{"id":123,"date":"2007-03-20T07:00:46","date_gmt":"2007-03-20T11:00:46","guid":{"rendered":"https:\/\/blogs.mathworks.com\/steve\/2007\/03\/20\/connected-component-labeling-part-3\/"},"modified":"2019-10-23T08:47:06","modified_gmt":"2019-10-23T12:47:06","slug":"connected-component-labeling-part-3","status":"publish","type":"post","link":"https:\/\/blogs.mathworks.com\/steve\/2007\/03\/20\/connected-component-labeling-part-3\/","title":{"rendered":"Connected component labeling &#8211; Part 3"},"content":{"rendered":"<div xmlns:mwsh=\"https:\/\/www.mathworks.com\/namespace\/mcode\/v1\/syntaxhighlight.dtd\" class=\"content\">\r\n   <p>Let's start looking at connected component labeling algorithms.  In this post I want to explain how you can think of pixel\r\n      neighborhood relationships in terms of a graph.  We'll look at how to represent and visualize a graph in MATLAB, as well as\r\n      how to compute the connected components of a graph.\r\n   <\/p>\r\n   <p>Here's our sample binary image:<\/p><pre style=\"background: #F9F7F3; padding: 10px; border: 1px solid rgb(200,200,200)\">bw = logical([ <span style=\"color: #0000FF\">...<\/span>\r\n    0 0 0 0 0 0 0\r\n    0 1 1 0 0 0 0\r\n    0 1 1 0 0 0 0\r\n    0 0 0 1 1 1 0\r\n    0 0 0 1 1 1 0\r\n    0 0 0 0 0 0 0 ])<\/pre><pre style=\"font-style:oblique\">\r\nbw =\r\n\r\n     0     0     0     0     0     0     0\r\n     0     1     1     0     0     0     0\r\n     0     1     1     0     0     0     0\r\n     0     0     0     1     1     1     0\r\n     0     0     0     1     1     1     0\r\n     0     0     0     0     0     0     0\r\n\r\n<\/pre><p>Each foreground pixel becomes a node in the graph.  Let's number the nodes.  Theoretically, the node ordering doesn't matter\r\n      very much, but for us it's convenient to use the same order as the <tt>find<\/tt> function:\r\n   <\/p><pre>0  0  0  0  0  0  0\r\n0  1  3  0  0  0  0\r\n0  2  4  0  0  0  0\r\n0  0  0  5  7  9  0\r\n0  0  0  6  8 10  0<\/pre><p>Next, make a list of which nodes in the graph are connected to each other.  Two nodes are connected if the corresponding pixels\r\n      are neighbors.  Using 4-connectivity, for example, node 1 is connected to nodes 2 and 3.  Node 4 is connected to nodes 2 and\r\n      3. Let's capture these pairwise connections in a matrix:\r\n   <\/p><pre style=\"background: #F9F7F3; padding: 10px; border: 1px solid rgb(200,200,200)\">pairs = [<span style=\"color: #0000FF\">...<\/span>\r\n    1 3; 1 2;\r\n    2 1; 2 4;\r\n    3 1; 3 4;\r\n    4 2; 4 3;\r\n    5 6; 5 7;\r\n    6 5; 6 8;\r\n    7 5; 7 8; 7 9;\r\n    8 6; 8 7; 8 10;\r\n    9 7; 9 10;\r\n    10 8; 10 9]<\/pre><pre style=\"font-style:oblique\">\r\npairs =\r\n\r\n     1     3\r\n     1     2\r\n     2     1\r\n     2     4\r\n     3     1\r\n     3     4\r\n     4     2\r\n     4     3\r\n     5     6\r\n     5     7\r\n     6     5\r\n     6     8\r\n     7     5\r\n     7     8\r\n     7     9\r\n     8     6\r\n     8     7\r\n     8    10\r\n     9     7\r\n     9    10\r\n    10     8\r\n    10     9\r\n\r\n<\/pre><p>From these pairs you can build up a graph representation called an <i>adjacency matrix<\/i>.  An adjacency matrix has one row and column for each graph node.  A nonzero element (p,q) means that there is a connection\r\n      between nodes p and q.  In other words, nodes p and q are adjacent.  You can build up an adjacency matrix from the list of\r\n      pairs by using <tt>accumarray<\/tt>, like this:\r\n   <\/p><pre style=\"background: #F9F7F3; padding: 10px; border: 1px solid rgb(200,200,200)\">A = accumarray(pairs, 1)<\/pre><pre style=\"font-style:oblique\">\r\nA =\r\n\r\n     0     1     1     0     0     0     0     0     0     0\r\n     1     0     0     1     0     0     0     0     0     0\r\n     1     0     0     1     0     0     0     0     0     0\r\n     0     1     1     0     0     0     0     0     0     0\r\n     0     0     0     0     0     1     1     0     0     0\r\n     0     0     0     0     1     0     0     1     0     0\r\n     0     0     0     0     1     0     0     1     1     0\r\n     0     0     0     0     0     1     1     0     0     1\r\n     0     0     0     0     0     0     1     0     0     1\r\n     0     0     0     0     0     0     0     1     1     0\r\n\r\n<\/pre><p>For graphs containing many nodes, you are better off constructing a sparse adjacency matrix, like this:<\/p><pre style=\"background: #F9F7F3; padding: 10px; border: 1px solid rgb(200,200,200)\">A = sparse(pairs(:,1), pairs(:,2), 1);\r\nspy(A)\r\ntitle(<span style=\"color: #A020F0\">'Spy plot of sparse adjacency matrix'<\/span>)<\/pre><img decoding=\"async\" vspace=\"5\" hspace=\"5\" src=\"https:\/\/blogs.mathworks.com\/images\/steve\/123\/bwlabel_part3_01.png\"> <p>MATLAB has a function called <tt>dmperm<\/tt>, which computes the Dulmage-Mendelsohn decomposition of a matrix. If the matrix is an adjacency matrix, <tt>dmperm<\/tt> can be used to compute the connected components of the corresponding graph. Here's how to do it.\r\n   <\/p>\r\n   <p>First, you have to put 1s on the diagonal of <tt>A<\/tt>:\r\n   <\/p><pre style=\"background: #F9F7F3; padding: 10px; border: 1px solid rgb(200,200,200)\">A(1:11:end) = 1;<\/pre>\r\n\r\n<p><em>[Note added June 29, 2007: Tim Davis pointed out this the above line is an inefficient way to get ones onto the diagonal of a sparse matrix.  Please see his <a href=\"https:\/\/blogs.mathworks.com\/steve\/2007\/03\/20\/connected-component-labeling-part-3\/#comments\">comments<\/a> for an explanation and for better ways to do it.]<\/em><\/p>\r\n<p>Next, call <tt>dmperm<\/tt>:\r\n   <\/p>\r\n\r\n<pre style=\"background: #F9F7F3; padding: 10px; border: 1px solid rgb(200,200,200)\">[p,q,r,s] = dmperm(A);<\/pre><p>The output <tt>p<\/tt> contains a permuted list of nodes:\r\n   <\/p><pre style=\"background: #F9F7F3; padding: 10px; border: 1px solid rgb(200,200,200)\">p<\/pre><pre style=\"font-style:oblique\">\r\np =\r\n\r\n     3     4     2     1    10     9     7     8     6     5\r\n\r\n<\/pre><p>And the output <tt>r<\/tt> tells you which nodes of <tt>p<\/tt> belong to the same connected component:\r\n   <\/p><pre style=\"background: #F9F7F3; padding: 10px; border: 1px solid rgb(200,200,200)\">r<\/pre><pre style=\"font-style:oblique\">\r\nr =\r\n\r\n     1     5    11\r\n\r\n<\/pre><p>Specifically, the first connected component contains these nodes:<\/p><pre style=\"background: #F9F7F3; padding: 10px; border: 1px solid rgb(200,200,200)\">p(r(1):r(2)-1)<\/pre><pre style=\"font-style:oblique\">\r\nans =\r\n\r\n     3     4     2     1\r\n\r\n<\/pre><p>The second connected component contains these nodes:<\/p><pre style=\"background: #F9F7F3; padding: 10px; border: 1px solid rgb(200,200,200)\">p(r(2):r(3)-1)<\/pre><pre style=\"font-style:oblique\">\r\nans =\r\n\r\n    10     9     7     8     6     5\r\n\r\n<\/pre><p>These two sets of nodes are the connected components of our original binary image.<\/p>\r\n   <p>Let's finish this example by using 8-connectivity instead of 4-connectivity.  Our list of pairs becomes:<\/p><pre style=\"background: #F9F7F3; padding: 10px; border: 1px solid rgb(200,200,200)\">pairs = [<span style=\"color: #0000FF\">...<\/span>\r\n    1 2; 1 3; 1 4;\r\n    2 1; 2 3; 2 4;\r\n    3 1; 3 2; 3 4;\r\n    4 1; 4 2; 4 3; 4 5;\r\n    5 4; 5 6; 5 7; 5 8;\r\n    6 5; 6 7; 6 8;\r\n    7 5; 7 6; 7 8; 7 9; 7 10;\r\n    8 5; 8 6; 8 7; 8 9; 8 10;\r\n    9 7; 9 8; 9 10;\r\n    10 7; 10 8; 10 9];<\/pre><p>Now repeat the steps of building the sparse adjacency matrix and calling <tt>dmperm<\/tt>:\r\n   <\/p><pre style=\"background: #F9F7F3; padding: 10px; border: 1px solid rgb(200,200,200)\">A = sparse(pairs(:,1), pairs(:,2), 1);\r\nA(1:11:end) = 1;\r\n[p,q,r,s] = dmperm(A);\r\nr<\/pre><pre style=\"font-style:oblique\">\r\nr =\r\n\r\n     1    11\r\n\r\n<\/pre>\r\n\r\n<p>\r\n<em>[Note added June 29, 2007: See Tim's <a href=\"https:\/\/blogs.mathworks.com\/steve\/2007\/03\/20\/connected-component-labeling-part-3\/#comments\">comment<\/a> about A(1:11:end) = 1.]<\/em>\r\n<\/p>\r\n\r\n<p>Now there's only one connected component:<\/p><pre style=\"background: #F9F7F3; padding: 10px; border: 1px solid rgb(200,200,200)\">p(r(1):r(2)-1)<\/pre><pre style=\"font-style:oblique\">\r\nans =\r\n\r\n    10     9     8     7     6     5     4     3     2     1\r\n\r\n<\/pre><p>Next time we'll look at computing connected components using a kind of \"flood fill\" approach.<\/p><script language=\"JavaScript\">\r\n<!--\r\n\r\n    function grabCode_ba0a2edc5ffa4d3e9cfc891868a8ed25() {\r\n        \/\/ Remember the title so we can use it in the new page\r\n        title = document.title;\r\n\r\n        \/\/ Break up these strings so that their presence\r\n        \/\/ in the Javascript doesn't mess up the search for\r\n        \/\/ the MATLAB code.\r\n        t1='ba0a2edc5ffa4d3e9cfc891868a8ed25 ' + '##### ' + 'SOURCE BEGIN' + ' #####';\r\n        t2='##### ' + 'SOURCE END' + ' #####' + ' ba0a2edc5ffa4d3e9cfc891868a8ed25';\r\n    \r\n        b=document.getElementsByTagName('body')[0];\r\n        i1=b.innerHTML.indexOf(t1)+t1.length;\r\n        i2=b.innerHTML.indexOf(t2);\r\n \r\n        code_string = b.innerHTML.substring(i1, i2);\r\n        code_string = code_string.replace(\/REPLACE_WITH_DASH_DASH\/g,'--');\r\n\r\n        \/\/ Use \/x3C\/g instead of the less-than character to avoid errors \r\n        \/\/ in the XML parser.\r\n        \/\/ Use '\\x26#60;' instead of '<' so that the XML parser\r\n        \/\/ doesn't go ahead and substitute the less-than character. \r\n        code_string = code_string.replace(\/\\x3C\/g, '\\x26#60;');\r\n\r\n        author = 'Steve Eddins';\r\n        copyright = 'Copyright 2007 The MathWorks, Inc.';\r\n\r\n        w = window.open();\r\n        d = w.document;\r\n        d.write('<pre>\\n');\r\n        d.write(code_string);\r\n\r\n        \/\/ Add author and copyright lines at the bottom if specified.\r\n        if ((author.length > 0) || (copyright.length > 0)) {\r\n            d.writeln('');\r\n            d.writeln('%%');\r\n            if (author.length > 0) {\r\n                d.writeln('% _' + author + '_');\r\n            }\r\n            if (copyright.length > 0) {\r\n                d.writeln('% _' + copyright + '_');\r\n            }\r\n        }\r\n\r\n        d.write('<\/pre>\\n');\r\n      \r\n      d.title = title + ' (MATLAB code)';\r\n      d.close();\r\n      }   \r\n      \r\n-->\r\n<\/script><p style=\"text-align: right; font-size: xx-small; font-weight:lighter;   font-style: italic; color: gray\"><br><a href=\"javascript:grabCode_ba0a2edc5ffa4d3e9cfc891868a8ed25()\"><span style=\"font-size: x-small;        font-style: italic;\">Get \r\n            the MATLAB code \r\n            <noscript>(requires JavaScript)<\/noscript><\/span><\/a><br><br>\r\n      Published with MATLAB&reg; 7.4<br><\/p>\r\n<\/div>\r\n<!--\r\nba0a2edc5ffa4d3e9cfc891868a8ed25 ##### SOURCE BEGIN #####\r\n%% Connected component labeling - part 3\r\n% Let's start looking at connected component labeling algorithms.  In this \r\n% post I want to explain how you can think of pixel neighborhood\r\n% relationships in terms of a graph.  We'll look at how to represent and \r\n% visualize a graph in MATLAB, as well as how to compute the connected\r\n% components of a graph.\r\n%\r\n% Here's our sample binary image:\r\n\r\nbw = logical([ ...\r\n    0 0 0 0 0 0 0\r\n    0 1 1 0 0 0 0\r\n    0 1 1 0 0 0 0\r\n    0 0 0 1 1 1 0\r\n    0 0 0 1 1 1 0\r\n    0 0 0 0 0 0 0 ])\r\n\r\n%%\r\n% Each foreground pixel becomes a node in the graph.  Let's number the \r\n% nodes.  Theoretically, the node ordering doesn't matter very much, but\r\n% for us it's convenient to use the same order as the |find| function:\r\n%\r\n%  0  0  0  0  0  0  0\r\n%  0  1  3  0  0  0  0\r\n%  0  2  4  0  0  0  0\r\n%  0  0  0  5  7  9  0\r\n%  0  0  0  6  8 10  0\r\n%\r\n% Next, make a list of which nodes in the graph are connected to each\r\n% other.  Two nodes are connected if the corresponding pixels are\r\n% neighbors.  Using 4-connectivity, for example, node 1 is connected to\r\n% nodes 2 and 3.  Node 4 is connected to nodes 2 and 3. Let's\r\n% capture these pairwise connections in a matrix:\r\n\r\npairs = [...\r\n    1 3; 1 2;\r\n    2 1; 2 4;\r\n    3 1; 3 4;\r\n    4 2; 4 3;\r\n    5 6; 5 7;\r\n    6 5; 6 8;\r\n    7 5; 7 8; 7 9;\r\n    8 6; 8 7; 8 10;\r\n    9 7; 9 10;\r\n    10 8; 10 9]\r\n\r\n\r\n%%\r\n% From these pairs you can build up a graph representation called an\r\n% _adjacency matrix_.  An adjacency matrix has one row and column for each\r\n% graph node.  A nonzero element (p,q) means that there is a connection\r\n% between nodes p and q.  In other words, nodes p and q are adjacent.  You\r\n% can build up an adjacency matrix from the list of pairs by using\r\n% |accumarray|, like this:\r\n\r\nA = accumarray(pairs, 1)\r\n\r\n%%\r\n% For graphs containing many nodes, you are better off constructing a\r\n% sparse adjacency matrix, like this:\r\n\r\nA = sparse(pairs(:,1), pairs(:,2), 1);\r\nspy(A)\r\ntitle('Spy plot of sparse adjacency matrix')\r\n\r\n%%\r\n% MATLAB has a function called |dmperm|, which computes the\r\n% Dulmage-Mendelsohn decomposition of a matrix. If the matrix is an\r\n% adjacency matrix, |dmperm| can be used to compute the connected\r\n% components of the corresponding graph. Here's how to do it.\r\n%\r\n% First, you have to put 1s on the diagonal of |A|:\r\n\r\nA(1:11:end) = 1;\r\n\r\n%%\r\n% Next, call |dmperm|:\r\n\r\n[p,q,r,s] = dmperm(A);\r\n\r\n%%\r\n% The output |p| contains a permuted list of nodes:\r\n\r\np\r\n\r\n%%\r\n% And the output |r| tells you which nodes of |p| belong to the same\r\n% connected component:\r\n\r\nr\r\n\r\n%%\r\n% Specifically, the first connected component contains these nodes:\r\n\r\np(r(1):r(2)-1)\r\n\r\n%%\r\n% The second connected component contains these nodes:\r\n\r\np(r(2):r(3)-1)\r\n\r\n%%\r\n% These two sets of nodes are the connected components of our original\r\n% binary image.\r\n%\r\n% Let's finish this example by using 8-connectivity instead of\r\n% 4-connectivity.  Our list of pairs becomes:\r\n\r\npairs = [...\r\n    1 2; 1 3; 1 4;\r\n    2 1; 2 3; 2 4;\r\n    3 1; 3 2; 3 4;\r\n    4 1; 4 2; 4 3; 4 5;\r\n    5 4; 5 6; 5 7; 5 8;\r\n    6 5; 6 7; 6 8;\r\n    7 5; 7 6; 7 8; 7 9; 7 10;\r\n    8 5; 8 6; 8 7; 8 9; 8 10;\r\n    9 7; 9 8; 9 10;\r\n    10 7; 10 8; 10 9];\r\n\r\n%%\r\n% Now repeat the steps of building the sparse adjacency matrix and calling\r\n% |dmperm|:\r\n\r\nA = sparse(pairs(:,1), pairs(:,2), 1);\r\nA(1:11:end) = 1;\r\n[p,q,r,s] = dmperm(A);\r\nr\r\n\r\n%%\r\n% Now there's only one connected component:\r\n\r\np(r(1):r(2)-1)\r\n\r\n%%\r\n% Next time we'll look at computing connected components using a kind of\r\n% \"flood fill\" approach.\r\n\r\n\r\n##### SOURCE END ##### ba0a2edc5ffa4d3e9cfc891868a8ed25\r\n-->","protected":false},"excerpt":{"rendered":"<p>\r\n   Let's start looking at connected component labeling algorithms.  In this post I want to explain how you can think of pixel\r\n      neighborhood relationships in terms of a graph.  We'll look at... <a class=\"read-more\" href=\"https:\/\/blogs.mathworks.com\/steve\/2007\/03\/20\/connected-component-labeling-part-3\/\">read more >><\/a><\/p>","protected":false},"author":42,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":[],"categories":[16],"tags":[336,342,330,338,340,52],"_links":{"self":[{"href":"https:\/\/blogs.mathworks.com\/steve\/wp-json\/wp\/v2\/posts\/123"}],"collection":[{"href":"https:\/\/blogs.mathworks.com\/steve\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blogs.mathworks.com\/steve\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blogs.mathworks.com\/steve\/wp-json\/wp\/v2\/users\/42"}],"replies":[{"embeddable":true,"href":"https:\/\/blogs.mathworks.com\/steve\/wp-json\/wp\/v2\/comments?post=123"}],"version-history":[{"count":1,"href":"https:\/\/blogs.mathworks.com\/steve\/wp-json\/wp\/v2\/posts\/123\/revisions"}],"predecessor-version":[{"id":3520,"href":"https:\/\/blogs.mathworks.com\/steve\/wp-json\/wp\/v2\/posts\/123\/revisions\/3520"}],"wp:attachment":[{"href":"https:\/\/blogs.mathworks.com\/steve\/wp-json\/wp\/v2\/media?parent=123"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blogs.mathworks.com\/steve\/wp-json\/wp\/v2\/categories?post=123"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blogs.mathworks.com\/steve\/wp-json\/wp\/v2\/tags?post=123"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}