{"id":224,"date":"2008-09-03T14:16:08","date_gmt":"2008-09-03T18:16:08","guid":{"rendered":"https:\/\/blogs.mathworks.com\/steve\/2008\/09\/03\/dilation-algorithmsintroduction\/"},"modified":"2019-10-28T09:40:35","modified_gmt":"2019-10-28T13:40:35","slug":"dilation-algorithms-introduction","status":"publish","type":"post","link":"https:\/\/blogs.mathworks.com\/steve\/2008\/09\/03\/dilation-algorithms-introduction\/","title":{"rendered":"Dilation algorithms&mdash;Introduction"},"content":{"rendered":"<div xmlns:mwsh=\"https:\/\/www.mathworks.com\/namespace\/mcode\/v1\/syntaxhighlight.dtd\" class=\"content\">\r\n<p><em>Post updated on September 4 based on feedback from Cris Luengo's comment.<\/em><\/p>\r\n\r\n   <p>Today I'm starting a new series covering some of the concepts underlying algorithms for performing morphological dilation\r\n      (and erosion, which is very similar). Most of the time, when people talk about image dilation, they mean the form of dilation\r\n      that is a local maximum operation on the neighbors of each pixel.  For example, here's how to compute the local maximum, for\r\n      each image pixel, with that pixel and its eight neighbors:\r\n   <\/p><pre style=\"background: #F9F7F3; padding: 10px; border: 1px solid rgb(200,200,200)\">A = magic(5)<\/pre><pre style=\"font-style:oblique\">\r\nA =\r\n\r\n    17    24     1     8    15\r\n    23     5     7    14    16\r\n     4     6    13    20    22\r\n    10    12    19    21     3\r\n    11    18    25     2     9\r\n\r\n<\/pre><pre style=\"background: #F9F7F3; padding: 10px; border: 1px solid rgb(200,200,200)\">se = ones(3,3)<\/pre><pre style=\"font-style:oblique\">\r\nse =\r\n\r\n     1     1     1\r\n     1     1     1\r\n     1     1     1\r\n\r\n<\/pre><pre style=\"background: #F9F7F3; padding: 10px; border: 1px solid rgb(200,200,200)\">B = imdilate(A, se)<\/pre><pre style=\"font-style:oblique\">\r\nB =\r\n\r\n    24    24    24    16    16\r\n    24    24    24    22    22\r\n    23    23    21    22    22\r\n    18    25    25    25    22\r\n    18    25    25    25    21\r\n\r\n<\/pre><p>The set of neighborhood pixels involved in the max operator forms a shape called the <i>structuring element<\/i>. The structuring element doesn't have to be square, as above.  Here is dilation with a short, 3-pixel line:\r\n   <\/p><pre style=\"background: #F9F7F3; padding: 10px; border: 1px solid rgb(200,200,200)\">se = [1 1 1];\r\nB2 = imdilate(A, se)<\/pre><pre style=\"font-style:oblique\">\r\nB2 =\r\n\r\n    24    24    24    15    15\r\n    23    23    14    16    16\r\n     6    13    20    22    22\r\n    12    19    21    21    21\r\n    18    25    25    25     9\r\n\r\n<\/pre><p>Let's consider how long it should take to compute dilation. Suppose an image has P pixels, and the structuring element contains\r\n      Q neighbors.  Computing the output for a particular pixel involves both Q memory reads and Q comparisons.  Therefore we might\r\n      expect the computation time to be proportional to Q.\r\n   <\/p>\r\n   <p>We can try to verify that behavior using square structuring elements of varying sizes.  \r\n   <\/p><pre style=\"background: #F9F7F3; padding: 10px; border: 1px solid rgb(200,200,200)\"><span style=\"color: #228B22\">% Read in a small sample image and replicate it to make a 1k-by-1k<\/span>\r\n<span style=\"color: #228B22\">% test image.<\/span>\r\nI = repmat(imread(<span style=\"color: #A020F0\">'rice.png'<\/span>), 4, 4);\r\n\r\n<span style=\"color: #228B22\">% Measure dilation times using a set of square structuring elements<\/span>\r\n<span style=\"color: #228B22\">% ranging in size from 5-by-5 to 97-by-97.<\/span>\r\nw = 5:4:97;\r\n\r\n<span style=\"color: #228B22\">% The number of neighbors, Q, in each structuring element will be<\/span>\r\n<span style=\"color: #228B22\">% w^2.  We are guessing that the running time will be proportional<\/span>\r\n<span style=\"color: #228B22\">% to Q.<\/span>\r\nQ = w.^2;\r\n\r\n<span style=\"color: #228B22\">% Initialize vector containing recorded times.<\/span>\r\ntimes = [];\r\n\r\n<span style=\"color: #0000FF\">for<\/span> wk = w\r\n    <span style=\"color: #228B22\">% Not that many MATLAB users are familiar with the for-loop<\/span>\r\n    <span style=\"color: #228B22\">% construct above.  I'll send a MATLAB t-shirt to the first<\/span>\r\n    <span style=\"color: #228B22\">% person who adds a comment to this post with a brief, clear,<\/span>\r\n    <span style=\"color: #228B22\">% and correct explanation.<\/span>\r\n\r\n    se = strel(ones(wk, wk));\r\n    f = @() imdilate(I, se);\r\n    times(end+1) = timeit(f);\r\n<span style=\"color: #0000FF\">end<\/span>\r\n\r\nplot(Q, times)\r\nylim([0 1.5*max(times)])<\/pre><img decoding=\"async\" vspace=\"5\" hspace=\"5\" src=\"https:\/\/blogs.mathworks.com\/images\/steve\/2008\/dilation_1_01.png\"> <p>That plot looks almost constant, with maybe just a hint of an increase with Q.<\/p>\r\n   <p>So is <tt>imdilate<\/tt> somehow computing dilation faster than expected?\r\n   <\/p>\r\n   <p>That's the subject of this series.  We'll start digging in deeper next time.<\/p><script language=\"JavaScript\">\r\n<!--\r\n\r\n    function grabCode_ead61fc63e6d42a9867f9472df238bbc() {\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='ead61fc63e6d42a9867f9472df238bbc ' + '##### ' + 'SOURCE BEGIN' + ' #####';\r\n        t2='##### ' + 'SOURCE END' + ' #####' + ' ead61fc63e6d42a9867f9472df238bbc';\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_ead61fc63e6d42a9867f9472df238bbc()\"><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\nead61fc63e6d42a9867f9472df238bbc ##### SOURCE BEGIN #####\r\n%%\r\n% Today I'm starting a new series covering some of the concepts\r\n% underlying algorithms for performing morphological dilation (and\r\n% erosion, which is very similar). Most of the time, when people\r\n% talk about image dilation, they mean the form of dilation that is\r\n% a local maximum operation on the neighbors of each pixel.  For\r\n% example, here's how to compute the local maximum, for each image\r\n% pixel, with that pixel and its eight neighbors:\r\n\r\nA = magic(5)\r\n\r\n%%\r\nse = ones(3,3)\r\n\r\n%%\r\nB = imdilate(A, se)\r\n\r\n%%\r\n% The set of neighborhood pixels involved in the max operator forms\r\n% a shape called the _structuring element_. The structuring element\r\n% doesn't have to be square, as above.  Here is dilation with a\r\n% short, 3-pixel line:\r\n\r\nse = [1 1 1];\r\nB2 = imdilate(A, se)\r\n\r\n%%\r\n% Let's consider how long it should take to compute dilation.\r\n% Suppose an image has P pixels, and the structuring element\r\n% contains Q neighbors.  Computing the output for a particular pixel\r\n% involves both Q memory reads and Q comparisons.  Therefore we\r\n% might expect the computation time to be proportional to Q.\r\n%\r\n% We can try to verify that behavior using square structuring\r\n% elements of varying sizes.  (I'll be using my |timeit| function,\r\n% which you can \r\n% <https:\/\/www.mathworks.com\/matlabcentral\/fileexchange\/loadFile.do?objectId=18798&objectType=file \r\n% download from the MATLAB Central File Exchange>.)\r\n\r\n% Read in a small sample image and replicate it to make a 1k-by-1k\r\n% test image.\r\nI = repmat(imread('rice.png'), 4, 4);\r\n\r\n% Measure dilation times using a set of square structuring elements\r\n% ranging in size from 5-by-5 to 97-by-97.\r\nw = 5:4:97;\r\n\r\n% The number of neighbors, Q, in each structuring element will be\r\n% w^2.  We are guessing that the running time will be proportional\r\n% to Q.\r\nQ = w.^2;\r\n\r\n% Initialize vector containing recorded times.\r\ntimes = [];\r\n\r\nfor wk = w\r\n    % Not that many MATLAB users are familiar with the for-loop\r\n    % construct above.  I'll send a MATLAB t-shirt to the first\r\n    % person who adds a comment to this post with a brief, clear,\r\n    % and correct explanation.\r\n    \r\n    se = strel(ones(wk, wk));\r\n    f = @() imdilate(I, se);\r\n    times(end+1) = timeit(f);\r\nend\r\n\r\nplot(Q, times)\r\nylim([0 1.5*max(times)])\r\n\r\n%%\r\n% That plot looks almost constant, with maybe just a hint of an\r\n% increase with Q. \r\n%\r\n% So is |imdilate| somehow computing dilation faster than expected?\r\n%\r\n% That's the subject of this series.  We'll start digging in deeper\r\n% next time.\r\n##### SOURCE END ##### ead61fc63e6d42a9867f9472df238bbc\r\n-->","protected":false},"excerpt":{"rendered":"<p>\r\nPost updated on September 4 based on feedback from Cris Luengo's comment.\r\n\r\n   Today I'm starting a new series covering some of the concepts underlying algorithms for performing morphological... <a class=\"read-more\" href=\"https:\/\/blogs.mathworks.com\/steve\/2008\/09\/03\/dilation-algorithms-introduction\/\">read more >><\/a><\/p>","protected":false},"author":42,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":[],"categories":[18],"tags":[124,76,54,288,68,116,106,474,298],"_links":{"self":[{"href":"https:\/\/blogs.mathworks.com\/steve\/wp-json\/wp\/v2\/posts\/224"}],"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=224"}],"version-history":[{"count":1,"href":"https:\/\/blogs.mathworks.com\/steve\/wp-json\/wp\/v2\/posts\/224\/revisions"}],"predecessor-version":[{"id":2647,"href":"https:\/\/blogs.mathworks.com\/steve\/wp-json\/wp\/v2\/posts\/224\/revisions\/2647"}],"wp:attachment":[{"href":"https:\/\/blogs.mathworks.com\/steve\/wp-json\/wp\/v2\/media?parent=224"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blogs.mathworks.com\/steve\/wp-json\/wp\/v2\/categories?post=224"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blogs.mathworks.com\/steve\/wp-json\/wp\/v2\/tags?post=224"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}