{"id":877,"date":"2013-09-05T13:28:02","date_gmt":"2013-09-05T17:28:02","guid":{"rendered":"https:\/\/blogs.mathworks.com\/steve\/?p=877"},"modified":"2019-11-01T09:24:42","modified_gmt":"2019-11-01T13:24:42","slug":"defining-and-filling-holes-on-the-border-of-an-image","status":"publish","type":"post","link":"https:\/\/blogs.mathworks.com\/steve\/2013\/09\/05\/defining-and-filling-holes-on-the-border-of-an-image\/","title":{"rendered":"Defining and filling holes on the border of an image"},"content":{"rendered":"<div class=\"content\"><p>Blog reader Alex <a href=\"https:\/\/blogs.mathworks.com\/steve\/2013\/08\/28\/introduction-to-spatial-referencing\/#comment-26888\">asked a question<\/a> this week about filling holes in this binary image.<\/p><pre class=\"codeinput\">url = <span class=\"string\">'https:\/\/blogs.mathworks.com\/images\/steve\/2013\/eye-heart-matlab.png'<\/span>;\r\nbw = imread(url);\r\nimshow(bw)\r\n<\/pre><img decoding=\"async\" vspace=\"5\" hspace=\"5\" src=\"https:\/\/blogs.mathworks.com\/images\/steve\/2013\/eye_heart_matlab_01.png\" alt=\"\"> <p>Alex tried <tt>imfill<\/tt> but it didn't give him exactly what he was looking for.<\/p><pre class=\"codeinput\">bw2 = imfill(bw,<span class=\"string\">'holes'<\/span>);\r\nimshow(bw2)\r\ntitle(<span class=\"string\">'Filling holes (first attempt)'<\/span>)\r\n<\/pre><img decoding=\"async\" vspace=\"5\" hspace=\"5\" src=\"https:\/\/blogs.mathworks.com\/images\/steve\/2013\/eye_heart_matlab_02.png\" alt=\"\"> <p>Alex asked how he could fill the objects that are touching the border. At this point, MathWorker <a href=\"https:\/\/www.mathworks.com\/matlabcentral\/fileexchange\/authors\/204413\">Sean de Wolski<\/a> jumped in and pointed out the problem wasn't well defined; there are multiple interpretations and possible solutions.<\/p><p>It might not be obvious from Alex's image that this is the case, so let me illustrate with a different example. This image has one object, and it touches the border in a way that divides the background into two regions. Topologically, this object is the same as each of the five \"unfilled\" objects in Alex's image.<\/p><pre class=\"codeinput\">bw_eye = imdilate(eye(200),ones(5,5));\r\nimshow(bw_eye)\r\n<\/pre><img decoding=\"async\" vspace=\"5\" hspace=\"5\" src=\"https:\/\/blogs.mathworks.com\/images\/steve\/2013\/eye_heart_matlab_03.png\" alt=\"\"> <p><tt>imfill<\/tt> doesn't do anything to this image:<\/p><pre class=\"codeinput\">imshow(imfill(bw_eye,<span class=\"string\">'holes'<\/span>))\r\ntitle(<span class=\"string\">'Output of imfill'<\/span>)\r\n<\/pre><img decoding=\"async\" vspace=\"5\" hspace=\"5\" src=\"https:\/\/blogs.mathworks.com\/images\/steve\/2013\/eye_heart_matlab_04.png\" alt=\"\"> <p>What does it mean to \"fill\" this object? Would you expect the upper-right portion of the background to be filled, or the lower-right? This is the point Sean was making.<\/p><p>Well, I stared at Alex's image for a while, trying to come up with a formulation of the problem that would be better defined and that would do what Alex expects.<\/p><p>I think I've hit upon a reasonable formulation. It's not the only one, however, and I'd be interested in what ideas other readers have about this.<\/p><p>Here's my idea: Fill objects against two adjacent borders at a time. By \"fill against a border\", I mean pad that border with white pixels, do the fill, and then remove the padding.<\/p><p>Let's go back to Alex's image and \"fill against\" the left and the top border. The following call to <tt>padarray<\/tt> adds a column of white pixels on the left and a row of white pixels on the top.<\/p><pre class=\"codeinput\">bw_a = padarray(bw,[1 1],1,<span class=\"string\">'pre'<\/span>);\r\nbw_a_filled = imfill(bw_a,<span class=\"string\">'holes'<\/span>);\r\nbw_a_filled = bw_a_filled(2:end,2:end);\r\nimshow(bw_a_filled)\r\n<\/pre><img decoding=\"async\" vspace=\"5\" hspace=\"5\" src=\"https:\/\/blogs.mathworks.com\/images\/steve\/2013\/eye_heart_matlab_05.png\" alt=\"\"> <p>Now fill against the top and the right border.<\/p><pre class=\"codeinput\">bw_b = padarray(padarray(bw,[1 0],1,<span class=\"string\">'pre'<\/span>),[0 1],1,<span class=\"string\">'post'<\/span>);\r\nbw_b_filled = imfill(bw_b,<span class=\"string\">'holes'<\/span>);\r\nbw_b_filled = bw_b_filled(2:end,1:end-1);\r\nimshow(bw_b_filled);\r\n<\/pre><img decoding=\"async\" vspace=\"5\" hspace=\"5\" src=\"https:\/\/blogs.mathworks.com\/images\/steve\/2013\/eye_heart_matlab_06.png\" alt=\"\"> <p>Next, fill against the right and bottom borders.<\/p><pre class=\"codeinput\">bw_c = padarray(bw,[1 1],1,<span class=\"string\">'post'<\/span>);\r\nbw_c_filled = imfill(bw_c,<span class=\"string\">'holes'<\/span>);\r\nbw_c_filled = bw_c_filled(1:end-1,1:end-1);\r\nimshow(bw_c_filled)\r\n<\/pre><img decoding=\"async\" vspace=\"5\" hspace=\"5\" src=\"https:\/\/blogs.mathworks.com\/images\/steve\/2013\/eye_heart_matlab_07.png\" alt=\"\"> <p>Finally, fill against the bottom and left borders. (I wouldn't expect this to have any effect on this particular image.)<\/p><pre class=\"codeinput\">bw_d = padarray(padarray(bw,[1 0],1,<span class=\"string\">'post'<\/span>),[0 1],1,<span class=\"string\">'pre'<\/span>);\r\nbw_d_filled = imfill(bw_d,<span class=\"string\">'holes'<\/span>);\r\nbw_d_filled = bw_d_filled(1:end-1,2:end);\r\nimshow(bw_d_filled)\r\n<\/pre><img decoding=\"async\" vspace=\"5\" hspace=\"5\" src=\"https:\/\/blogs.mathworks.com\/images\/steve\/2013\/eye_heart_matlab_08.png\" alt=\"\"> <p>The last step is then to \"logical OR\" all these images together.<\/p><pre class=\"codeinput\">bw_filled = bw_a_filled | bw_b_filled | bw_c_filled | bw_d_filled;\r\nimshow(bw_filled)\r\ntitle(<span class=\"string\">'Final filled result'<\/span>)\r\n<\/pre><img decoding=\"async\" vspace=\"5\" hspace=\"5\" src=\"https:\/\/blogs.mathworks.com\/images\/steve\/2013\/eye_heart_matlab_09.png\" alt=\"\"> <p>Readers, please post your thoughts about this problem. It wouldn't surprise me at all to learn of other useful ways to think about it and other implementation methods.<\/p><p>Alex, I hope you find this useful.<\/p><script language=\"JavaScript\"> <!-- \r\n    function grabCode_61de625da3934c33ac6692800e75c5c2() {\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='61de625da3934c33ac6692800e75c5c2 ' + '##### ' + 'SOURCE BEGIN' + ' #####';\r\n        t2='##### ' + 'SOURCE END' + ' #####' + ' 61de625da3934c33ac6692800e75c5c2';\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        copyright = 'Copyright 2013 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 copyright line at the bottom if specified.\r\n        if (copyright.length > 0) {\r\n            d.writeln('');\r\n            d.writeln('%%');\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     --> <\/script><p style=\"text-align: right; font-size: xx-small; font-weight:lighter;   font-style: italic; color: gray\"><br><a href=\"javascript:grabCode_61de625da3934c33ac6692800e75c5c2()\"><span style=\"font-size: x-small;        font-style: italic;\">Get \r\n      the MATLAB code <noscript>(requires JavaScript)<\/noscript><\/span><\/a><br><br>\r\n      Published with MATLAB&reg; R2013a<br><\/p><p class=\"footer\"><br>\r\n      Published with MATLAB&reg; R2013a<br><\/p><\/div><!--\r\n61de625da3934c33ac6692800e75c5c2 ##### SOURCE BEGIN #####\r\n%%\r\n% Blog reader Alex\r\n% <https:\/\/blogs.mathworks.com\/steve\/2013\/08\/28\/introduction-to-spatial-referencing\/#comment-26888\r\n% asked a question> this week about filling holes in this binary image.\r\n\r\nurl = 'https:\/\/blogs.mathworks.com\/images\/steve\/2013\/eye-heart-matlab.png';\r\nbw = imread(url);\r\nimshow(bw)\r\n\r\n%%\r\n% Alex tried |imfill| but it didn't give him exactly what he was looking\r\n% for.\r\n\r\nbw2 = imfill(bw,'holes');\r\nimshow(bw2)\r\ntitle('Filling holes (first attempt)')\r\n\r\n%%\r\n% Alex asked how he could fill the objects that are touching the border. At\r\n% this point, MathWorker\r\n% <https:\/\/www.mathworks.com\/matlabcentral\/fileexchange\/authors\/204413 \r\n% Sean de Wolski> jumped in a pointed out the problem\r\n% wasn't well defined; there are multiple interpretations and possible\r\n% solutions.\r\n%\r\n% It might not obvious from Alex's image that this is the case, so let me\r\n% illustrate with a different example. This image has one object, and it\r\n% touches the border in a way that divides the background into two regions.\r\n% Topologically, this object is the same as each of the five \"unfilled\"\r\n% objects in Alex's image.\r\n\r\nbw_eye = imdilate(eye(200),ones(5,5));\r\nimshow(bw_eye)\r\n\r\n%%\r\n% |imfill| doesn't do anything to this image:\r\n\r\nimshow(imfill(bw_eye,'holes'))\r\ntitle('Output of imfill')\r\n\r\n%%\r\n% What does it mean to \"fill\" this object? Would you expect the upper-right\r\n% portion of the background to be filled, or the lower-right? This is the\r\n% point Sean was making.\r\n%\r\n% Well, I stared at Alex's image for a while, trying to come up with a\r\n% formulation of the problem that would be better defined and that would do\r\n% what Alex expects.\r\n%\r\n% I think I've hit upon a reasonable formulation. It's not the only one,\r\n% however, and I'd be interested in what ideas other readers have about\r\n% this.\r\n%\r\n% Here's my idea: Fill objects against two adjacent borders at a time. By\r\n% \"fill against a border\", I mean pad that border with white pixels, do the\r\n% fill, and then remove the padding.\r\n%\r\n% Let's go back to Alex's image and \"fill against\" the left and the top\r\n% border. The following call to |padarray| adds a column of white pixels on\r\n% the left and a row of white pixels on the top.\r\n\r\nbw_a = padarray(bw,[1 1],1,'pre');\r\nbw_a_filled = imfill(bw_a,'holes');\r\nbw_a_filled = bw_a_filled(2:end,2:end);\r\nimshow(bw_a_filled)\r\n\r\n%%\r\n% Now fill against the top and the right border.\r\n\r\nbw_b = padarray(padarray(bw,[1 0],1,'pre'),[0 1],1,'post');\r\nbw_b_filled = imfill(bw_b,'holes');\r\nbw_b_filled = bw_b_filled(2:end,1:end-1);\r\nimshow(bw_b_filled);\r\n\r\n%%\r\n% Next, fill against the right and bottom borders.\r\n\r\nbw_c = padarray(bw,[1 1],1,'post');\r\nbw_c_filled = imfill(bw_c,'holes');\r\nbw_c_filled = bw_c_filled(1:end-1,1:end-1);\r\nimshow(bw_c_filled)\r\n\r\n%%\r\n% Finally, fill against the bottom and left borders. (I wouldn't expect\r\n% this to have any effect on this particular image.)\r\n\r\nbw_d = padarray(padarray(bw,[1 0],1,'post'),[0 1],1,'pre');\r\nbw_d_filled = imfill(bw_d,'holes');\r\nbw_d_filled = bw_d_filled(1:end-1,2:end);\r\nimshow(bw_d_filled)\r\n\r\n%%\r\n% The last step is then to \"logical OR\" all these images together.\r\n\r\nbw_filled = bw_a_filled | bw_b_filled | bw_c_filled | bw_d_filled;\r\nimshow(bw_filled)\r\ntitle('Final filled result')\r\n\r\n%%\r\n% Readers, please post your thoughts about this problem. It wouldn't\r\n% surprise me at all to learn of other useful ways to think about it and\r\n% other implementation methods.\r\n%\r\n% Alex, I hope you find this useful.\r\n\r\n\r\n##### SOURCE END ##### 61de625da3934c33ac6692800e75c5c2\r\n-->","protected":false},"excerpt":{"rendered":"<div class=\"overview-image\"><img decoding=\"async\"  class=\"img-responsive\" src=\"https:\/\/blogs.mathworks.com\/images\/steve\/2013\/eye_heart_matlab_09.png\" onError=\"this.style.display ='none';\" \/><\/div><p>Blog reader Alex asked a question this week about filling holes in this binary image.url = 'https:\/\/blogs.mathworks.com\/images\/steve\/2013\/eye-heart-matlab.png';\r\nbw = imread(url);\r\nimshow(bw)\r\n Alex... <a class=\"read-more\" href=\"https:\/\/blogs.mathworks.com\/steve\/2013\/09\/05\/defining-and-filling-holes-on-the-border-of-an-image\/\">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":[300,124,136,76,36,288,344,52],"_links":{"self":[{"href":"https:\/\/blogs.mathworks.com\/steve\/wp-json\/wp\/v2\/posts\/877"}],"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=877"}],"version-history":[{"count":9,"href":"https:\/\/blogs.mathworks.com\/steve\/wp-json\/wp\/v2\/posts\/877\/revisions"}],"predecessor-version":[{"id":3819,"href":"https:\/\/blogs.mathworks.com\/steve\/wp-json\/wp\/v2\/posts\/877\/revisions\/3819"}],"wp:attachment":[{"href":"https:\/\/blogs.mathworks.com\/steve\/wp-json\/wp\/v2\/media?parent=877"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blogs.mathworks.com\/steve\/wp-json\/wp\/v2\/categories?post=877"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blogs.mathworks.com\/steve\/wp-json\/wp\/v2\/tags?post=877"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}