{"id":207,"date":"2008-04-21T12:11:27","date_gmt":"2008-04-21T16:11:27","guid":{"rendered":"https:\/\/blogs.mathworks.com\/steve\/2008\/04\/21\/corresponding-labels\/"},"modified":"2019-10-28T09:29:49","modified_gmt":"2019-10-28T13:29:49","slug":"corresponding-labels","status":"publish","type":"post","link":"https:\/\/blogs.mathworks.com\/steve\/2008\/04\/21\/corresponding-labels\/","title":{"rendered":"Corresponding labeled objects in two images"},"content":{"rendered":"<div xmlns:mwsh=\"https:\/\/www.mathworks.com\/namespace\/mcode\/v1\/syntaxhighlight.dtd\" class=\"content\">\r\n   <p>Several questions I've seen about <tt>bwlabel<\/tt> are about finding the correspondences between object labels in two images.  In other words, if a particular pixel is in the\r\n      foreground in two binary images, is that pixel labeled the same in both images, or is it different?  In general, for foreground\r\n      pixels in the same locations, how do object labels in one binary image match up to object labels in the second?\r\n   <\/p>\r\n   <p>I'll show one method using the same small binary image that I've been using in my other recent <a href=\"https:\/\/blogs.mathworks.com\/steve\/category\/connected-components\/\">bwlabel posts<\/a>.\r\n   <\/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\/186\/scanned_page.png'<\/span>;\r\nbw = imread(url);\r\nbw = ~bw(1107:1194, 17:135);\r\nimshow(bw, <span style=\"color: #A020F0\">'InitialMagnification'<\/span>, <span style=\"color: #A020F0\">'fit'<\/span>)<\/pre><img decoding=\"async\" vspace=\"5\" hspace=\"5\" src=\"https:\/\/blogs.mathworks.com\/images\/steve\/2008\/bwlabel_correspondences_01.png\"> <p>Compute and display the labeled objects.<\/p><pre style=\"background: #F9F7F3; padding: 10px; border: 1px solid rgb(200,200,200)\">L1 = bwlabel(bw);\r\n\r\nI = im2uint8(bw);\r\nI(~bw) = 200;\r\nI(bw) = 240;\r\ns = regionprops(L1, <span style=\"color: #A020F0\">'extrema'<\/span>);\r\nimshow(I, <span style=\"color: #A020F0\">'InitialMagnification'<\/span>, <span style=\"color: #A020F0\">'fit'<\/span>)\r\nhold <span style=\"color: #A020F0\">on<\/span>\r\n<span style=\"color: #0000FF\">for<\/span> k = 1:numel(s)\r\n   e = s(k).Extrema;\r\n   text(e(1,1), e(1,2), sprintf(<span style=\"color: #A020F0\">'%d'<\/span>, k));\r\n<span style=\"color: #0000FF\">end<\/span>\r\nhold <span style=\"color: #A020F0\">off<\/span><\/pre><img decoding=\"async\" vspace=\"5\" hspace=\"5\" src=\"https:\/\/blogs.mathworks.com\/images\/steve\/2008\/bwlabel_correspondences_02.png\"> <p>Now let's try a morphological closing operation on this image.<\/p><pre style=\"background: #F9F7F3; padding: 10px; border: 1px solid rgb(200,200,200)\">bw2 = imclose(bw, ones(3,3));\r\nimshow(bw2, <span style=\"color: #A020F0\">'InitialMagnification'<\/span>, <span style=\"color: #A020F0\">'fit'<\/span>)<\/pre><img decoding=\"async\" vspace=\"5\" hspace=\"5\" src=\"https:\/\/blogs.mathworks.com\/images\/steve\/2008\/bwlabel_correspondences_03.png\"> <p>Compute and display the labeled objects in the second image.<\/p><pre style=\"background: #F9F7F3; padding: 10px; border: 1px solid rgb(200,200,200)\">L2 = bwlabel(bw2);\r\n\r\nI2 = im2uint8(bw2);\r\nI2(~bw2) = 200;\r\nI2(bw2) = 240;\r\ns2 = regionprops(L2, <span style=\"color: #A020F0\">'extrema'<\/span>);\r\nimshow(I2, <span style=\"color: #A020F0\">'InitialMagnification'<\/span>, <span style=\"color: #A020F0\">'fit'<\/span>)\r\nhold <span style=\"color: #A020F0\">on<\/span>\r\n<span style=\"color: #0000FF\">for<\/span> k = 1:numel(s2)\r\n   e2 = s2(k).Extrema;\r\n   text(e2(1,1), e2(1,2), sprintf(<span style=\"color: #A020F0\">'%d'<\/span>, k));\r\n<span style=\"color: #0000FF\">end<\/span>\r\nhold <span style=\"color: #A020F0\">off<\/span><\/pre><img decoding=\"async\" vspace=\"5\" hspace=\"5\" src=\"https:\/\/blogs.mathworks.com\/images\/steve\/2008\/bwlabel_correspondences_04.png\"> <p>Compare the two sets of labels visually.  You can see that the broken \"f\" character on the bottom line was labeled with 6\r\n      and 7 in the first image.  In the second image, the broken pieces have been merged and labeled with 4.\r\n   <\/p>\r\n   <p>On the first line of the first image, the \"s\" and \"t\" characters are distinct and are labeled with 2 and 4, respectively.\r\n       In the second image, they have been merged into one object that was labeled 2.\r\n   <\/p>\r\n   <p>Let's see how to compute all of the correspondences between the object labels in the two images.  First, compute the set of\r\n      pixels that belong to the foreground in both images.\r\n   <\/p><pre style=\"background: #F9F7F3; padding: 10px; border: 1px solid rgb(200,200,200)\">overlap = bw &amp; bw2;<\/pre><p>Next, compute the corresponding label pairs by using logical indexing into the two label matrices.<\/p><pre style=\"background: #F9F7F3; padding: 10px; border: 1px solid rgb(200,200,200)\">pairs = [L1(overlap), L2(overlap)];<\/pre><p>Eliminate the duplicates in the list of pairs.<\/p><pre style=\"background: #F9F7F3; padding: 10px; border: 1px solid rgb(200,200,200)\">pairs = unique(pairs, <span style=\"color: #A020F0\">'rows'<\/span>);<\/pre><p>Let's look at a few of the pairs to see how to interpret their meaning:<\/p><pre style=\"background: #F9F7F3; padding: 10px; border: 1px solid rgb(200,200,200)\">pairs(1:5, :)<\/pre><pre style=\"font-style:oblique\">\r\nans =\r\n\r\n     1     1\r\n     2     2\r\n     3     3\r\n     4     2\r\n     5     1\r\n\r\n<\/pre><p>Pixels belonging to objects 1 and 5 in the first image belong to a single object, labeled 1, in the second image.  Similarly,\r\n      pixels belonging to objects 2 and 4 in the first image belong to a single object, labeled 2, in the second image.  Pixels\r\n      labeled with a 3 in the first image are also labeled with a 3 in the second image.\r\n   <\/p>\r\n   <p>Depending on your application, you might want to form an adjacency graph, represented as a sparse matrix.<\/p><pre style=\"background: #F9F7F3; padding: 10px; border: 1px solid rgb(200,200,200)\">S = sparse(pairs(:,1), pairs(:,2), 1);\r\nspy(S)<\/pre><img decoding=\"async\" vspace=\"5\" hspace=\"5\" src=\"https:\/\/blogs.mathworks.com\/images\/steve\/2008\/bwlabel_correspondences_05.png\"> <p>One way to use the graph is to find all the object labels in image 1 that correspond to a given label in image 2. For example,\r\n      here are all the first-image objects corresponding to the object labeled with 6 in the second image:\r\n   <\/p><pre style=\"background: #F9F7F3; padding: 10px; border: 1px solid rgb(200,200,200)\">find(S(:, 6))<\/pre><pre style=\"font-style:oblique\">\r\nans =\r\n\r\n     9\r\n    10\r\n\r\n<\/pre><p>My other recent <tt>bwlabel<\/tt> posts were about <a href=\"https:\/\/blogs.mathworks.com\/steve\/2008\/03\/25\/bwlabel-search-order\/\">search order<\/a> and <a href=\"https:\/\/blogs.mathworks.com\/steve\/2008\/04\/14\/relabeling-a-label-matrix\/\">relabeling<\/a>. You can also look the archive of <a href=\"https:\/\/blogs.mathworks.com\/steve\/category\/connected-components\/\">all my posts about connected-component labeling<\/a>.\r\n   <\/p><script language=\"JavaScript\">\r\n<!--\r\n\r\n    function grabCode_d13ce95276724cc0b96f4b76df0c7125() {\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='d13ce95276724cc0b96f4b76df0c7125 ' + '##### ' + 'SOURCE BEGIN' + ' #####';\r\n        t2='##### ' + 'SOURCE END' + ' #####' + ' d13ce95276724cc0b96f4b76df0c7125';\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 2008 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_d13ce95276724cc0b96f4b76df0c7125()\"><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.6<br><\/p>\r\n<\/div>\r\n<!--\r\nd13ce95276724cc0b96f4b76df0c7125 ##### SOURCE BEGIN #####\r\n%%\r\n% Several questions I've seen about |bwlabel| are about finding the\r\n% correspondences between object labels in two images.  In other\r\n% words, if a particular pixel is in the foreground in two binary\r\n% images, is that pixel labeled the same in both images, or is it\r\n% different?  In general, for foreground pixels in the same\r\n% locations, how do object labels in one binary image match up to\r\n% object labels in the second?\r\n%\r\n% I'll show one method using the same small binary image that I've\r\n% been using in my other recent \r\n% <https:\/\/blogs.mathworks.com\/steve\/category\/connected-components\/ \r\n% bwlabel posts>.\r\n\r\nurl = 'https:\/\/blogs.mathworks.com\/images\/steve\/186\/scanned_page.png';\r\nbw = imread(url);\r\nbw = ~bw(1107:1194, 17:135);\r\nimshow(bw, 'InitialMagnification', 'fit')\r\n\r\n%%\r\n% Compute and display the labeled objects.\r\n\r\nL1 = bwlabel(bw);\r\n\r\nI = im2uint8(bw);\r\nI(~bw) = 200;\r\nI(bw) = 240;\r\ns = regionprops(L1, 'extrema');\r\nimshow(I, 'InitialMagnification', 'fit')\r\nhold on\r\nfor k = 1:numel(s)\r\n   e = s(k).Extrema;\r\n   text(e(1,1), e(1,2), sprintf('%d', k));\r\nend\r\nhold off\r\n\r\n%%\r\n% Now let's try a morphological closing operation on this image.\r\n\r\nbw2 = imclose(bw, ones(3,3));\r\nimshow(bw2, 'InitialMagnification', 'fit')\r\n\r\n%%\r\n% Compute and display the labeled objects in the second image.\r\nL2 = bwlabel(bw2);\r\n\r\nI2 = im2uint8(bw2);\r\nI2(~bw2) = 200;\r\nI2(bw2) = 240;\r\ns2 = regionprops(L2, 'extrema');\r\nimshow(I2, 'InitialMagnification', 'fit')\r\nhold on\r\nfor k = 1:numel(s2)\r\n   e2 = s2(k).Extrema;\r\n   text(e2(1,1), e2(1,2), sprintf('%d', k));\r\nend\r\nhold off\r\n\r\n%%\r\n% Compare the two sets of labels visually.  You can see that the\r\n% broken \"f\" character on the bottom line was labeled with 6 and 7\r\n% in the first image.  In the second image, the broken pieces have\r\n% been merged and labeled with 4.\r\n%\r\n% On the first line of the first image, the \"s\" and \"t\" characters\r\n% are distinct and are labeled with 2 and 4, respectively.  In the\r\n% second image, they have been merged into one object that was\r\n% labeled 2.\r\n%\r\n% Let's see how to compute all of the correspondences between the\r\n% object labels in the two images.  First, compute the set of pixels\r\n% that belong to the foreground in both images.\r\n\r\noverlap = bw & bw2;\r\n\r\n%%\r\n% Next, compute the corresponding label pairs by using logical\r\n% indexing into the two label matrices.\r\n\r\npairs = [L1(overlap), L2(overlap)];\r\n\r\n%%\r\n% Eliminate the duplicates in the list of pairs.\r\n\r\npairs = unique(pairs, 'rows');\r\n\r\n%%\r\n% Let's look at a few of the pairs to see how to interpret their\r\n% meaning:\r\n\r\npairs(1:5, :)\r\n\r\n%%\r\n% Pixels belonging to objects 1 and 5 in the first image belong to a\r\n% single object, labeled 1, in the second image.  Similarly, pixels\r\n% belonging to objects 2 and 4 in the first image belong to a single\r\n% object, labeled 2, in the second image.  Pixels labeled with a 3\r\n% in the first image are also labeled with a 3 in the second image.\r\n%\r\n% Depending on your application, you might want to form an adjacency\r\n% graph, represented as a sparse matrix.\r\n\r\nS = sparse(pairs(:,1), pairs(:,2), 1);\r\nspy(S)\r\n\r\n%%\r\n% One way to use the graph is to find all the object\r\n% labels in image 1 that correspond to a given label in image 2.\r\n% For example, here are all the first-image objects corresponding to\r\n% the object labeled with 6 in the second image:\r\n\r\nfind(S(:, 6))\r\n\r\n%%\r\n% My other recent |bwlabel| posts were about\r\n% <https:\/\/blogs.mathworks.com\/steve\/2008\/03\/25\/bwlabel-search-order\/\r\n% search order> and \r\n% <https:\/\/blogs.mathworks.com\/steve\/2008\/04\/14\/relabeling-a-label-matrix\/ \r\n% relabeling>.\r\n% You can also look the archive of \r\n% <https:\/\/blogs.mathworks.com\/steve\/category\/connected-components\/ \r\n% all my posts about\r\n% connected-component labeling>.\r\n##### SOURCE END ##### d13ce95276724cc0b96f4b76df0c7125\r\n-->","protected":false},"excerpt":{"rendered":"<p>\r\n   Several questions I've seen about bwlabel are about finding the correspondences between object labels in two images.  In other words, if a particular pixel is in the\r\n      foreground in two... <a class=\"read-more\" href=\"https:\/\/blogs.mathworks.com\/steve\/2008\/04\/21\/corresponding-labels\/\">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":[166,348,90,452,144,76,36,162,168,338,340,78,350],"_links":{"self":[{"href":"https:\/\/blogs.mathworks.com\/steve\/wp-json\/wp\/v2\/posts\/207"}],"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=207"}],"version-history":[{"count":1,"href":"https:\/\/blogs.mathworks.com\/steve\/wp-json\/wp\/v2\/posts\/207\/revisions"}],"predecessor-version":[{"id":3596,"href":"https:\/\/blogs.mathworks.com\/steve\/wp-json\/wp\/v2\/posts\/207\/revisions\/3596"}],"wp:attachment":[{"href":"https:\/\/blogs.mathworks.com\/steve\/wp-json\/wp\/v2\/media?parent=207"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blogs.mathworks.com\/steve\/wp-json\/wp\/v2\/categories?post=207"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blogs.mathworks.com\/steve\/wp-json\/wp\/v2\/tags?post=207"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}