{"id":338,"date":"2010-08-16T17:10:54","date_gmt":"2010-08-16T21:10:54","guid":{"rendered":"https:\/\/blogs.mathworks.com\/steve\/2010\/08\/16\/isotropic-dilation-using-the-distance-transform\/"},"modified":"2019-10-29T13:33:04","modified_gmt":"2019-10-29T17:33:04","slug":"isotropic-dilation-using-the-distance-transform","status":"publish","type":"post","link":"https:\/\/blogs.mathworks.com\/steve\/2010\/08\/16\/isotropic-dilation-using-the-distance-transform\/","title":{"rendered":"Isotropic dilation using the distance transform"},"content":{"rendered":"<div xmlns:mwsh=\"https:\/\/www.mathworks.com\/namespace\/mcode\/v1\/syntaxhighlight.dtd\" class=\"content\">\r\n   <p><a href=\"https:\/\/www.mathworks.com\/matlabcentral\/fileexchange\/authors\/911\">Brett<\/a> recently asked me about an image processing problem. One step in the problem involved finding out which pixels are within\r\n      a certain distance of the foreground in a binary image. We experimented with a few methods, and I want to share the results\r\n      with you. In particular, I want to show you a useful technique called <i>isotropic dilation<\/i> that can be achieved using the distance transform.\r\n   <\/p>\r\n   <p>Let's start with a small 400-by-400 test image that has only a single foreground pixel in the center.<\/p><pre style=\"background: #F9F7F3; padding: 10px; border: 1px solid rgb(200,200,200)\">bw = false(400, 400);\r\nbw(200, 200) = 1;\r\nimshow(bw)<\/pre><img decoding=\"async\" vspace=\"5\" hspace=\"5\" src=\"https:\/\/blogs.mathworks.com\/images\/steve\/2010\/isotropic_dilation_01.png\"> <p>Suppose we want to know which pixels are within 25 units of the foreground pixel? One common technique is to perform dilation\r\n      with a disk.\r\n   <\/p><pre style=\"background: #F9F7F3; padding: 10px; border: 1px solid rgb(200,200,200)\">se = strel(<span style=\"color: #A020F0\">'disk'<\/span>, 25);\r\nbw2 = imdilate(bw, se);<\/pre><p>This has a problem, though. If you read the documentation for <tt>strel<\/tt> carefully, you'll see that by default it computes a structuring element that is an <b>approximation<\/b> of a disk. You can see the effect of the approximation by looking at the output of the dilation:\r\n   <\/p><pre style=\"background: #F9F7F3; padding: 10px; border: 1px solid rgb(200,200,200)\">imshow(bw2)<\/pre><img decoding=\"async\" vspace=\"5\" hspace=\"5\" src=\"https:\/\/blogs.mathworks.com\/images\/steve\/2010\/isotropic_dilation_02.png\"> <p>You can avoid the approximation by passing in 0 as a third input argument to <tt>strel<\/tt>:\r\n   <\/p><pre style=\"background: #F9F7F3; padding: 10px; border: 1px solid rgb(200,200,200)\">se2 = strel(<span style=\"color: #A020F0\">'disk'<\/span>, 25, 0);\r\nbw3 = imdilate(bw, se2);\r\nimshow(bw3)<\/pre><img decoding=\"async\" vspace=\"5\" hspace=\"5\" src=\"https:\/\/blogs.mathworks.com\/images\/steve\/2010\/isotropic_dilation_03.png\"> <p>So why does <tt>strel<\/tt> use a disk approximation by default? Because it's usually a lot faster. Let's check it out on a larger test image (750-by-1500)\r\n      with a lot of pixels in the foreground.\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\/2010\/binary_benchmark.png'<\/span>;\r\nbw2 = imread(url);\r\nimshow(bw2, <span style=\"color: #A020F0\">'InitialMagnification'<\/span>, 25)<\/pre><img decoding=\"async\" vspace=\"5\" hspace=\"5\" src=\"https:\/\/blogs.mathworks.com\/images\/steve\/2010\/isotropic_dilation_04.png\"> <pre style=\"background: #F9F7F3; padding: 10px; border: 1px solid rgb(200,200,200)\">f = @() imdilate(bw2, se)\r\ntime_with_approximate_disk = timeit(f)<\/pre><pre style=\"font-style:oblique\">\r\nf = \r\n\r\n    @()imdilate(bw2,se)\r\n\r\n\r\ntime_with_approximate_disk =\r\n\r\n    0.0292\r\n\r\n<\/pre><pre style=\"background: #F9F7F3; padding: 10px; border: 1px solid rgb(200,200,200)\">g = @() imdilate(bw2, se2)\r\ntime_with_exact_disk = timeit(g)<\/pre><pre style=\"font-style:oblique\">\r\ng = \r\n\r\n    @()imdilate(bw2,se2)\r\n\r\n\r\ntime_with_exact_disk =\r\n\r\n    1.4536\r\n\r\n<\/pre>\r\n   <p>An alternative to using <tt>imdilate<\/tt> is to use <tt>bwdist<\/tt> to compute the distance transform and then threshold the result. The distance transform computes, for each pixel, the distance\r\n      between that pixel and the nearest foreground pixel.  Here's how it would work:\r\n   <\/p><pre style=\"background: #F9F7F3; padding: 10px; border: 1px solid rgb(200,200,200)\">bw4 = bwdist(bw) &lt;= 25;\r\nimshow(bw4)<\/pre><img decoding=\"async\" vspace=\"5\" hspace=\"5\" src=\"https:\/\/blogs.mathworks.com\/images\/steve\/2010\/isotropic_dilation_05.png\"> <p>The function <tt>bwdist<\/tt> uses a fast algorithm, so this works a lot faster than <tt>imdilate<\/tt> with an exact disk.\r\n   <\/p><pre style=\"background: #F9F7F3; padding: 10px; border: 1px solid rgb(200,200,200)\">h = @() bwdist(bw2) &lt;= 25;\r\ntime_using_distance_transform = timeit(h)<\/pre><pre style=\"font-style:oblique\">\r\ntime_using_distance_transform =\r\n\r\n    0.0687\r\n\r\n<\/pre><p>This technique of thresholding the distance transform is sometimes called <i>isotropic dilation<\/i>.\r\n   <\/p>\r\n   <p>Have you made creative use of the distance transform in your work? Then post a comment here.<\/p><script language=\"JavaScript\">\r\n<!--\r\n\r\n    function grabCode_9259cdda5e1b40cf9546a63b5be4d529() {\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='9259cdda5e1b40cf9546a63b5be4d529 ' + '##### ' + 'SOURCE BEGIN' + ' #####';\r\n        t2='##### ' + 'SOURCE END' + ' #####' + ' 9259cdda5e1b40cf9546a63b5be4d529';\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_9259cdda5e1b40cf9546a63b5be4d529()\"><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\n9259cdda5e1b40cf9546a63b5be4d529 ##### SOURCE BEGIN #####\r\n%%\r\n% <https:\/\/www.mathworks.com\/matlabcentral\/fileexchange\/authors\/911 Brett>\r\n% recently asked me about an image processing problem. One step \r\n% in the problem involved finding out which pixels are within a certain\r\n% distance of the foreground in a binary image. We experimented with a few\r\n% methods, and I want to share the results with you. In particular, I want\r\n% to show you a useful technique called _isotropic dilation_ that can be\r\n% achieved using the distance transform.\r\n%\r\n% Let's start with a small 400-by-400 test image that has only a single\r\n% foreground pixel in the center.\r\n\r\nbw = false(400, 400);\r\nbw(200, 200) = 1;\r\nimshow(bw)\r\n\r\n%%\r\n% Suppose we want to know which pixels are within 25 units of the\r\n% foreground pixel? One common technique is to perform dilation with a\r\n% disk.\r\n\r\nse = strel('disk', 25);\r\nbw2 = imdilate(bw, se);\r\n\r\n%%\r\n% This has a problem, though. If you read the documentation for |strel|\r\n% carefully, you'll see that by default it computes a structuring element\r\n% that is an *approximation* of a disk. You can see the effect of the\r\n% approximation by looking at the output of the dilation:\r\n\r\nimshow(bw2)\r\n\r\n%%\r\n% You can avoid the approximation by passing in 0 as a third input\r\n% argument to |strel|:\r\n\r\nse2 = strel('disk', 25, 0);\r\nbw3 = imdilate(bw, se2);\r\nimshow(bw3)\r\n\r\n%%\r\n% So why does |strel| use a disk approximation by default? Because it's\r\n% usually a lot faster. Let's check it out on a larger test image\r\n% (750-by-1500) with a \r\n% lot of pixels in the foreground.\r\n\r\nurl = 'https:\/\/blogs.mathworks.com\/images\/steve\/2010\/binary_benchmark.png';\r\nbw2 = imread(url);\r\nimshow(bw2, 'InitialMagnification', 25)\r\n\r\n%%\r\n\r\nf = @() imdilate(bw2, se)\r\ntime_with_approximate_disk = timeit(f)\r\n\r\n%%\r\n\r\ng = @() imdilate(bw2, se2)\r\ntime_with_exact_disk = timeit(g)\r\n\r\n%%\r\n% (You can download |timeit| from the \r\n% <https:\/\/www.mathworks.com\/matlabcentral\/fileexchange\/18798-timeit-benchmarking-function \r\n% MATLAB Central File Exchange>.)\r\n\r\n%%\r\n% An alternative to using |imdilate| is to use |bwdist| to compute the\r\n% distance transform and then threshold the result. The distance transform\r\n% computes, for each pixel, the distance between that pixel and the nearest\r\n% foreground pixel.  Here's how it would work:\r\n\r\nbw4 = bwdist(bw) <= 25;\r\nimshow(bw4)\r\n\r\n%%\r\n% The function |bwdist| uses a fast algorithm, so this works a lot faster\r\n% than |imdilate| with an exact disk.\r\n\r\nh = @() bwdist(bw2) <= 25;\r\ntime_using_distance_transform = timeit(h)\r\n\r\n%%\r\n% This technique of thresholding the distance transform is sometimes\r\n% called _isotropic dilation_.\r\n%\r\n% Have you made creative use of the distance transform in your work? Then\r\n% post a comment here.\r\n##### SOURCE END ##### 9259cdda5e1b40cf9546a63b5be4d529\r\n-->","protected":false},"excerpt":{"rendered":"<p>\r\n   Brett recently asked me about an image processing problem. One step in the problem involved finding out which pixels are within\r\n      a certain distance of the foreground in a binary image. We... <a class=\"read-more\" href=\"https:\/\/blogs.mathworks.com\/steve\/2010\/08\/16\/isotropic-dilation-using-the-distance-transform\/\">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":[456,102,124,76,36,106,474],"_links":{"self":[{"href":"https:\/\/blogs.mathworks.com\/steve\/wp-json\/wp\/v2\/posts\/338"}],"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=338"}],"version-history":[{"count":1,"href":"https:\/\/blogs.mathworks.com\/steve\/wp-json\/wp\/v2\/posts\/338\/revisions"}],"predecessor-version":[{"id":2635,"href":"https:\/\/blogs.mathworks.com\/steve\/wp-json\/wp\/v2\/posts\/338\/revisions\/2635"}],"wp:attachment":[{"href":"https:\/\/blogs.mathworks.com\/steve\/wp-json\/wp\/v2\/media?parent=338"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blogs.mathworks.com\/steve\/wp-json\/wp\/v2\/categories?post=338"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blogs.mathworks.com\/steve\/wp-json\/wp\/v2\/tags?post=338"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}