{"id":275,"date":"2009-07-13T12:48:45","date_gmt":"2009-07-13T16:48:45","guid":{"rendered":"https:\/\/blogs.mathworks.com\/steve\/2009\/07\/13\/a-new-look-for-connected-component-labeling-in-r2009a-part-2\/"},"modified":"2019-10-28T15:38:36","modified_gmt":"2019-10-28T19:38:36","slug":"a-new-look-for-connected-component-labeling-in-r2009a-part-2","status":"publish","type":"post","link":"https:\/\/blogs.mathworks.com\/steve\/2009\/07\/13\/a-new-look-for-connected-component-labeling-in-r2009a-part-2\/","title":{"rendered":"A new look for connected component labeling in R2009a &#8211; Part 2"},"content":{"rendered":"<div xmlns:mwsh=\"https:\/\/www.mathworks.com\/namespace\/mcode\/v1\/syntaxhighlight.dtd\" class=\"content\">\r\n   <p><a href=\"https:\/\/blogs.mathworks.com\/steve\/2009\/07\/06\/a-new-look-for-connected-component-labeling-in-r2009a\/\">Last week<\/a> I wrote about our desire to reduce the memory used by <tt>bwlabel<\/tt>.  I also wrote about other issues we hoped to address:\r\n   <\/p>\r\n   <div>\r\n      <ul>\r\n         <li>The label matrix uses memory proportional to the total number of image pixels.  This seems unreasonable when you're working\r\n            with an image containing only a few object pixels.\r\n         <\/li>\r\n         <li>When <tt>bwlabel<\/tt> was used with <tt>regionprops<\/tt> (a frequent combination), some computational work was duplicated in both functions.\r\n         <\/li>\r\n         <li>Many users never use the label matrix directly.  They only compute it in order to pass it to <tt>regionprops<\/tt>.  That implies there may be a simpler, more usable interface design.\r\n         <\/li>\r\n      <\/ul>\r\n   <\/div>\r\n   <p>With so much code out there using <tt>bwlabel<\/tt> and <tt>regionprops<\/tt>, though, we did not want to introduce any compatibility problems.\r\n   <\/p>\r\n   <p>Our solution was to introduce two new functions in R2009a, <tt>bwconncomp<\/tt> and <tt>labelmatrix<\/tt>, as well as a couple of new syntaxes for the existing function <tt>regionprops<\/tt>.\r\n   <\/p>\r\n   <p>The new function <tt>bwconncomp<\/tt> finds the connected components of a binary image, just as <tt>bwlabel<\/tt> does. But it does not return the result as a label matrix.\r\n   <\/p><pre style=\"background: #F9F7F3; padding: 10px; border: 1px solid rgb(200,200,200)\">BW = [1     1     1     0     0     0     0     0\r\n      1     1     1     0     1     1     0     0\r\n      1     1     1     0     1     1     0     0\r\n      0     0     0     0     0     0     1     0\r\n      0     0     0     0     0     0     1     0\r\n      0     0     0     0     0     0     1     0\r\n      0     1     1     0     0     1     1     0\r\n      0     1     1     0     0     0     0     0];\r\n\r\ns = bwconncomp(BW)<\/pre><pre style=\"font-style:oblique\">\r\ns = \r\n\r\n    Connectivity: 8\r\n       ImageSize: [8 8]\r\n      NumObjects: 3\r\n    PixelIdxList: {[9x1 double]  [4x1 double]  [9x1 double]}\r\n\r\n<\/pre><p>As you can see, <tt>bwconncomp<\/tt> produces a structure.  The critical information for subsequent processing is the <tt>PixelIdxList<\/tt> field, which contains the linear indices of the pixels belonging to each object. For example, the 2nd object found comprises\r\n      four pixels with the following linear indices:\r\n   <\/p><pre style=\"background: #F9F7F3; padding: 10px; border: 1px solid rgb(200,200,200)\">s.PixelIdxList{2}<\/pre><pre style=\"font-style:oblique\">\r\nans =\r\n\r\n    15\r\n    16\r\n    23\r\n    24\r\n\r\n<\/pre><p>A key aspect of this design is that the amount of memory required is proportional to the number of object pixels, not the\r\n      number of image pixels. For a 1000-by-1000 image containing a single foreground pixel, the output data structure is nicely\r\n      compact:\r\n   <\/p><pre style=\"background: #F9F7F3; padding: 10px; border: 1px solid rgb(200,200,200)\">BW2 = false(1000, 1000);\r\nBW2(500, 500) = true;\r\ns2 = bwconncomp(BW2)<\/pre><pre style=\"font-style:oblique\">\r\ns2 = \r\n\r\n    Connectivity: 8\r\n       ImageSize: [1000 1000]\r\n      NumObjects: 1\r\n    PixelIdxList: {[499500]}\r\n\r\n<\/pre><pre style=\"background: #F9F7F3; padding: 10px; border: 1px solid rgb(200,200,200)\">whos <span style=\"color: #A020F0\">s2<\/span><\/pre><pre style=\"font-style:oblique\">  Name      Size            Bytes  Class     Attributes\r\n\r\n  s2        1x1               596  struct              \r\n\r\n<\/pre><p>You can compute the label matrix, if you really need it, using the new function <tt>labelmatrix<\/tt>.\r\n   <\/p><pre style=\"background: #F9F7F3; padding: 10px; border: 1px solid rgb(200,200,200)\">L2 = labelmatrix(s2);\r\nwhos <span style=\"color: #A020F0\">L2<\/span><\/pre><pre style=\"font-style:oblique\">  Name         Size                Bytes  Class    Attributes\r\n\r\n  L2        1000x1000            1000000  uint8              \r\n\r\n<\/pre><p>Notice that <tt>L2<\/tt> is a <tt>uint8<\/tt> matrix.  Unlike <tt>bwlabel<\/tt>, <tt>labelmatrix<\/tt> <b>does<\/b> adjust the output data type based on the number of objects.\r\n   <\/p>\r\n   <p>The last related change was to <tt>regionprops<\/tt>. As I mentioned before, we've noticed that this is a very common coding pattern:\r\n   <\/p><pre>  L = bwlabel(bw);\r\n  s = regionprops(L, ...);<\/pre><p>We've modified the syntax for <tt>regionprops<\/tt> so that you can now do this in a one step:\r\n   <\/p><pre>  s = regionprops(bw, ...);<\/pre><p>For example:<\/p><pre style=\"background: #F9F7F3; padding: 10px; border: 1px solid rgb(200,200,200)\">bw = imread(<span style=\"color: #A020F0\">'text.png'<\/span>);\r\ns = regionprops(bw, <span style=\"color: #A020F0\">'Centroid'<\/span>);<\/pre><p>These several new and modified functions, working together, nicely solve several design problems:<\/p>\r\n   <div>\r\n      <ul>\r\n         <li>Reducing memory use<\/li>\r\n         <li>Increasing speed (in many cases) by eliminating duplicate computation<\/li>\r\n         <li>Converting a two-step workflow to a one-step workflow<\/li>\r\n      <\/ul>\r\n   <\/div>\r\n   <p>We had one last concern, though. It takes code changes to benefit from these enhancements.  Users who aren't aware of the\r\n      new features and don't change their code will never benefit.  So what could we do to help users discover the new features?\r\n   <\/p>\r\n   <p>I'll comment about that next time.<\/p><script language=\"JavaScript\">\r\n<!--\r\n\r\n    function grabCode_3d5b15eb9e854d7495529c07058e00fc() {\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='3d5b15eb9e854d7495529c07058e00fc ' + '##### ' + 'SOURCE BEGIN' + ' #####';\r\n        t2='##### ' + 'SOURCE END' + ' #####' + ' 3d5b15eb9e854d7495529c07058e00fc';\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 = '';\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_3d5b15eb9e854d7495529c07058e00fc()\"><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.8<br><\/p>\r\n<\/div>\r\n<!--\r\n3d5b15eb9e854d7495529c07058e00fc ##### SOURCE BEGIN #####\r\n%%\r\n% <https:\/\/blogs.mathworks.com\/steve\/2009\/07\/06\/a-new-look-for-connected-component-labeling-in-r2009a\/ \r\n% Last week> I wrote about our desire to reduce the memory used by |bwlabel|.  I\r\n% also wrote about other issues we hoped to address:\r\n%\r\n% * The label matrix uses memory proportional to the\r\n% total number of image pixels.  This seems unreasonable when you're working\r\n% with an image containing only a few object pixels.\r\n% * When |bwlabel| was used with |regionprops| (a frequent combination), some \r\n% computational work was duplicated in both functions. \r\n% * Many users never use the label matrix directly.  They only compute it\r\n% in order to pass it to |regionprops|.  That implies there may be a simpler,\r\n% more usable interface design.\r\n%\r\n% With so much code out there using |bwlabel| and |regionprops|, though, we did\r\n% not want to introduce any compatibility problems.\r\n%\r\n% Our solution was to introduce two new functions in R2009a, |bwconncomp| and\r\n% |labelmatrix|, as well as a couple of new syntaxes for the existing function\r\n% |regionprops|.\r\n%\r\n% The new function |bwconncomp| finds the connected components of a binary\r\n% image, just as |bwlabel| does. But it does not return the result as a label\r\n% matrix.\r\n\r\nBW = [1     1     1     0     0     0     0     0\r\n      1     1     1     0     1     1     0     0\r\n      1     1     1     0     1     1     0     0\r\n      0     0     0     0     0     0     1     0\r\n      0     0     0     0     0     0     1     0\r\n      0     0     0     0     0     0     1     0\r\n      0     1     1     0     0     1     1     0\r\n      0     1     1     0     0     0     0     0];\r\n  \r\ns = bwconncomp(BW)\r\n\r\n%%\r\n% As you can see, |bwconncomp| produces a structure.  The critical information\r\n% for subsequent processing is the |PixelIdxList| field, which contains the\r\n% linear indices of the pixels belonging to each object. For example, the 2nd\r\n% object found comprises four pixels with the following linear indices:\r\n\r\ns.PixelIdxList{2}\r\n\r\n%%\r\n% A key aspect of this design is that the amount of memory required is\r\n% proportional to the number of object pixels, not the number of image pixels.\r\n% For a 1000-by-1000 image containing a single foreground pixel, the output data\r\n% structure is nicely compact:\r\n\r\nBW2 = false(1000, 1000);\r\nBW2(500, 500) = true;\r\ns2 = bwconncomp(BW2)\r\n\r\n%%\r\nwhos s2\r\n\r\n%%\r\n% You can compute the label matrix, if you really need it, using the new\r\n% function |labelmatrix|. \r\n\r\nL2 = labelmatrix(s2);\r\nwhos L2\r\n\r\n%%\r\n% Notice that |L2| is a |uint8| matrix.  Unlike |bwlabel|, |labelmatrix| *does*\r\n% adjust the output data type based on the number of objects. \r\n%\r\n% The last related change was to |regionprops|. As I mentioned before, we've\r\n% noticed that this is a very common coding pattern:\r\n%\r\n%    L = bwlabel(bw);\r\n%    s = regionprops(L, ...);\r\n%\r\n% We've modified the syntax for |regionprops| so that you can now do this in a\r\n% one step:\r\n%\r\n%    s = regionprops(bw, ...);\r\n%\r\n% For example:\r\n\r\nbw = imread('text.png');\r\ns = regionprops(bw, 'Centroid');\r\n\r\n%%\r\n% These several new and modified functions, working together, nicely solve\r\n% several design problems:\r\n%\r\n% * Reducing memory use\r\n% * Increasing speed (in many cases) by eliminating duplicate computation\r\n% * Converting a two-step workflow to a one-step workflow\r\n%\r\n% We had one last concern, though. It takes code changes to benefit from these\r\n% enhancements.  Users who aren't aware of the new features and don't change\r\n% their code will never benefit.  So what could we do to help users discover the\r\n% new features?\r\n%\r\n% I'll comment about that next time.\r\n\r\n##### SOURCE END ##### 3d5b15eb9e854d7495529c07058e00fc\r\n-->","protected":false},"excerpt":{"rendered":"<p>\r\n   Last week I wrote about our desire to reduce the memory used by bwlabel.  I also wrote about other issues we hoped to address:\r\n   \r\n   \r\n      \r\n         The... <a class=\"read-more\" href=\"https:\/\/blogs.mathworks.com\/steve\/2009\/07\/13\/a-new-look-for-connected-component-labeling-in-r2009a-part-2\/\">read more >><\/a><\/p>","protected":false},"author":42,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":[],"categories":[1],"tags":[561,166,102,76,563,168,100,306],"_links":{"self":[{"href":"https:\/\/blogs.mathworks.com\/steve\/wp-json\/wp\/v2\/posts\/275"}],"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=275"}],"version-history":[{"count":1,"href":"https:\/\/blogs.mathworks.com\/steve\/wp-json\/wp\/v2\/posts\/275\/revisions"}],"predecessor-version":[{"id":3641,"href":"https:\/\/blogs.mathworks.com\/steve\/wp-json\/wp\/v2\/posts\/275\/revisions\/3641"}],"wp:attachment":[{"href":"https:\/\/blogs.mathworks.com\/steve\/wp-json\/wp\/v2\/media?parent=275"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blogs.mathworks.com\/steve\/wp-json\/wp\/v2\/categories?post=275"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blogs.mathworks.com\/steve\/wp-json\/wp\/v2\/tags?post=275"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}