{"id":340,"date":"2010-09-07T17:21:43","date_gmt":"2010-09-07T21:21:43","guid":{"rendered":"https:\/\/blogs.mathworks.com\/steve\/2010\/09\/07\/almost-connected-component-labeling\/"},"modified":"2019-10-29T13:34:02","modified_gmt":"2019-10-29T17:34:02","slug":"almost-connected-component-labeling","status":"publish","type":"post","link":"https:\/\/blogs.mathworks.com\/steve\/2010\/09\/07\/almost-connected-component-labeling\/","title":{"rendered":"Almost-connected-component labeling"},"content":{"rendered":"<div xmlns:mwsh=\"https:\/\/www.mathworks.com\/namespace\/mcode\/v1\/syntaxhighlight.dtd\" class=\"content\">\r\n   <p>In a <a href=\"https:\/\/blogs.mathworks.com\/steve\/2010\/08\/16\/isotropic-dilation-using-the-distance-transform\/\">recent post<\/a> I demonstrated the use of <tt>bwdist<\/tt> (binary image Euclidean distance transform) to perform isotropic dilation. This was inspired by something that <a href=\"https:\/\/www.mathworks.com\/matlabcentral\/fileexchange\/authors\/911\">Brett<\/a> asked me about.\r\n   <\/p>\r\n   <p>Last night Brett <a href=\"https:\/\/blogs.mathworks.com\/steve\/2010\/08\/16\/isotropic-dilation-using-the-distance-transform\/#comment-23438\">posted a comment<\/a> explaining a little bit more about what he was doing. I'm going to coin a term for what Brett described: <i>almost-connected-component labeling<\/i>.\r\n   <\/p>\r\n   <p>I'll illustrate with a simple synthetic image containing a number of circular blobs.<\/p><pre style=\"background: #F9F7F3; padding: 10px; border: 1px solid rgb(200,200,200)\">url = <span style=\"color: #A020F0\">'https:\/\/blogs.mathworks.com\/images\/steve\/2010\/blobs_in_clumps.png'<\/span>;\r\nbw = imread(url);\r\nimshow(bw)<\/pre><img decoding=\"async\" vspace=\"5\" hspace=\"5\" src=\"https:\/\/blogs.mathworks.com\/images\/steve\/2010\/almost_connected_component_labeling_01.png\"> <p>Now let's label the connected components in <tt>bw<\/tt>.\r\n   <\/p><pre style=\"background: #F9F7F3; padding: 10px; border: 1px solid rgb(200,200,200)\">cc = bwconncomp(bw)<\/pre><pre style=\"font-style:oblique\">\r\ncc = \r\n\r\n    Connectivity: 8\r\n       ImageSize: [337 313]\r\n      NumObjects: 23\r\n    PixelIdxList: {1x23 cell}\r\n\r\n<\/pre><p>You can see that there are 23 distinct objects detected. The function <tt>label2rgb<\/tt> is useful for visualizing connected components. You use it by converting the output of <tt>bwconncomp<\/tt> to a label matrix using <tt>labelmatrix<\/tt> and then passing the result to <tt>label2rgb<\/tt>.\r\n   <\/p><pre style=\"background: #F9F7F3; padding: 10px; border: 1px solid rgb(200,200,200)\">L = labelmatrix(cc);\r\nrgb = label2rgb(L, <span style=\"color: #A020F0\">'jet'<\/span>, [.7 .7 .7], <span style=\"color: #A020F0\">'shuffle'<\/span>);\r\nimshow(rgb)<\/pre><img decoding=\"async\" vspace=\"5\" hspace=\"5\" src=\"https:\/\/blogs.mathworks.com\/images\/steve\/2010\/almost_connected_component_labeling_02.png\"> <p>Brett's question was this: How can we label and measure the three clumps instead of the smaller circles? (The clumps were\r\n      cell clusters in Brett's problem.) The answer is to combine an isotropic dilation step with connected component labeling.\r\n   <\/p>\r\n   <p>Let's say that two circles are \"almost connected\" if they are within 25 pixel units of distance from each other. So start\r\n      with an isotropic dilation step:\r\n   <\/p><pre style=\"background: #F9F7F3; padding: 10px; border: 1px solid rgb(200,200,200)\">bw2 = bwdist(bw) &lt;= 12.5;\r\nimshow(bw2)<\/pre><img decoding=\"async\" vspace=\"5\" hspace=\"5\" src=\"https:\/\/blogs.mathworks.com\/images\/steve\/2010\/almost_connected_component_labeling_03.png\"> <p>Now we can perform connected component labeling on <tt>bw2<\/tt>:\r\n   <\/p><pre style=\"background: #F9F7F3; padding: 10px; border: 1px solid rgb(200,200,200)\">L2 = labelmatrix(bwconncomp(bw2));\r\nrgb2 = label2rgb(L2, <span style=\"color: #A020F0\">'jet'<\/span>, [.7 .7 .7], <span style=\"color: #A020F0\">'shuffle'<\/span>);\r\nimshow(rgb2)<\/pre><img decoding=\"async\" vspace=\"5\" hspace=\"5\" src=\"https:\/\/blogs.mathworks.com\/images\/steve\/2010\/almost_connected_component_labeling_04.png\"> <p>We have the three clumps now, but they are too \"fat.\" That is, they have too many pixels in them because of the isotropic\r\n      dilation step.  So if, for example, we measure the area of each clump using <tt>regionprops<\/tt>:\r\n   <\/p><pre style=\"background: #F9F7F3; padding: 10px; border: 1px solid rgb(200,200,200)\">s = regionprops(L2, <span style=\"color: #A020F0\">'Area'<\/span>);\r\n[s.Area]<\/pre><pre style=\"font-style:oblique\">\r\nans =\r\n\r\n       14418       11023        6341\r\n\r\n<\/pre><p>we get a distorted area measurement. What if we want to perform measurements only on the pixels in the original clumps?<\/p>\r\n   <p>A nice application of <a href=\"https:\/\/blogs.mathworks.com\/steve\/2008\/01\/28\/logical-indexing\/\">logical indexing<\/a> will modify <tt>L2<\/tt> to get rid of the added pixels. The following line sets to 0 all elements of <tt>L2<\/tt> corresponding to background pixels in <tt>bw<\/tt>.\r\n   <\/p><pre style=\"background: #F9F7F3; padding: 10px; border: 1px solid rgb(200,200,200)\">L2(~bw) = 0;\r\nimshow(label2rgb(L2, <span style=\"color: #A020F0\">'jet'<\/span>, [.7 .7 .7], <span style=\"color: #A020F0\">'shuffle'<\/span>))<\/pre><img decoding=\"async\" vspace=\"5\" hspace=\"5\" src=\"https:\/\/blogs.mathworks.com\/images\/steve\/2010\/almost_connected_component_labeling_05.png\"> <pre style=\"background: #F9F7F3; padding: 10px; border: 1px solid rgb(200,200,200)\">s = regionprops(L2, <span style=\"color: #A020F0\">'Area'<\/span>);\r\n[s.Area]<\/pre><pre style=\"font-style:oblique\">\r\nans =\r\n\r\n        4827        3510        2208\r\n\r\n<\/pre><p>Do you have an application for \"almost-connected-component labeling\"? Post your comment here.<\/p>\r\n   <p>PS. Hey, in case you didn't notice, the <a href=\"https:\/\/www.mathworks.com\/products\/new_products\/latest_features.html\">R2010b release<\/a> is out. I'll post something about it soon.\r\n   <\/p><script language=\"JavaScript\">\r\n<!--\r\n\r\n    function grabCode_3201921a69dd4730a21c9a75305683ec() {\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='3201921a69dd4730a21c9a75305683ec ' + '##### ' + 'SOURCE BEGIN' + ' #####';\r\n        t2='##### ' + 'SOURCE END' + ' #####' + ' 3201921a69dd4730a21c9a75305683ec';\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 2010 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_3201921a69dd4730a21c9a75305683ec()\"><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.10<br><\/p>\r\n<\/div>\r\n<!--\r\n3201921a69dd4730a21c9a75305683ec ##### SOURCE BEGIN #####\r\n%%\r\n% In a \r\n% <https:\/\/blogs.mathworks.com\/steve\/2010\/08\/16\/isotropic-dilation-using-the-distance-transform\/ \r\n% recent post> I demonstrated the use of |bwdist| (binary image\r\n% Euclidean distance transform) to perform isotropic dilation. This was\r\n% inspired by something that \r\n% <https:\/\/www.mathworks.com\/matlabcentral\/fileexchange\/authors\/911 Brett>\r\n% asked me about. \r\n%\r\n% Last night Brett \r\n% <https:\/\/blogs.mathworks.com\/steve\/2010\/08\/16\/isotropic-dilation-using-the-distance-transform\/#comment-23438 posted a comment> explaining a little bit more about \r\n% what he was doing. I'm going to coin a term for what Brett described:\r\n% _almost-connected-component labeling_.\r\n%\r\n% I'll illustrate with a simple synthetic image containing a number of\r\n% circular blobs.\r\n\r\nurl = 'https:\/\/blogs.mathworks.com\/images\/steve\/2010\/blobs_in_clumps.png';\r\nbw = imread(url);\r\nimshow(bw)\r\n\r\n%%\r\n% Now let's label the connected components in |bw|.\r\n\r\ncc = bwconncomp(bw)\r\n\r\n%%\r\n% You can see that there are 23 distinct objects detected. The function\r\n% |label2rgb| is useful for visualizing connected components. You use it by\r\n% converting the output of |bwconncomp| to a label matrix using\r\n% |labelmatrix| and then passing the result to |label2rgb|.\r\n\r\nL = labelmatrix(cc);\r\nrgb = label2rgb(L, 'jet', [.7 .7 .7], 'shuffle');\r\nimshow(rgb)\r\n\r\n%%\r\n% Brett's question was this: How can we label and measure the three clumps\r\n% instead of the smaller circles? (The clumps were cell clusters in Brett's\r\n% problem.) The answer is to combine an isotropic dilation step with\r\n% connected component labeling.\r\n%\r\n% Let's say that two circles are \"almost connected\" if they are within 25\r\n% pixel units of distance from each other. So start with an isotropic\r\n% dilation step:\r\n\r\nbw2 = bwdist(bw) <= 12.5;\r\nimshow(bw2)\r\n\r\n%%\r\n% Now we can perform connected component labeling on |bw2|:\r\n\r\nL2 = labelmatrix(bwconncomp(bw2));\r\nrgb2 = label2rgb(L2, 'jet', [.7 .7 .7], 'shuffle');\r\nimshow(rgb2)\r\n\r\n%%\r\n% We have the three clumps now, but they are too \"fat.\" That is, they have\r\n% too many pixels in them because of the isotropic dilation step.  So if,\r\n% for example, we measure the area of each clump using |regionprops|:\r\n\r\ns = regionprops(L2, 'Area');\r\n[s.Area]\r\n\r\n%%\r\n% we get a distorted area measurement. What if\r\n% we want to perform measurements only on the pixels in the original\r\n% clumps? \r\n%\r\n% A nice application of \r\n% <https:\/\/blogs.mathworks.com\/steve\/2008\/01\/28\/logical-indexing\/ logical indexing> \r\n% will modify |L2| to get rid of the\r\n% added pixels. The following line sets to 0 all elements of |L2|\r\n% corresponding to background pixels in |bw|.\r\n\r\nL2(~bw) = 0;\r\nimshow(label2rgb(L2, 'jet', [.7 .7 .7], 'shuffle'))\r\n\r\n%%\r\n\r\ns = regionprops(L2, 'Area');\r\n[s.Area]\r\n\r\n%%\r\n% Do you have an application for \"almost-connected-component labeling\"?\r\n% Post your comment here.\r\n%\r\n% PS. Hey, in case you didn't notice, the \r\n% <https:\/\/www.mathworks.com\/products\/new_products\/latest_features.html\r\n% R2010b release> is out. I'll post \r\n% something about it soon.\r\n##### SOURCE END ##### 3201921a69dd4730a21c9a75305683ec\r\n-->","protected":false},"excerpt":{"rendered":"<p>\r\n   In a recent post I demonstrated the use of bwdist (binary image Euclidean distance transform) to perform isotropic dilation. This was inspired by something that Brett asked me about.\r\n   \r\n  ... <a class=\"read-more\" href=\"https:\/\/blogs.mathworks.com\/steve\/2010\/09\/07\/almost-connected-component-labeling\/\">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":[561,456,76,36,152,563,168],"_links":{"self":[{"href":"https:\/\/blogs.mathworks.com\/steve\/wp-json\/wp\/v2\/posts\/340"}],"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=340"}],"version-history":[{"count":1,"href":"https:\/\/blogs.mathworks.com\/steve\/wp-json\/wp\/v2\/posts\/340\/revisions"}],"predecessor-version":[{"id":3693,"href":"https:\/\/blogs.mathworks.com\/steve\/wp-json\/wp\/v2\/posts\/340\/revisions\/3693"}],"wp:attachment":[{"href":"https:\/\/blogs.mathworks.com\/steve\/wp-json\/wp\/v2\/media?parent=340"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blogs.mathworks.com\/steve\/wp-json\/wp\/v2\/categories?post=340"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blogs.mathworks.com\/steve\/wp-json\/wp\/v2\/tags?post=340"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}