{"id":2062,"date":"2016-07-25T11:01:44","date_gmt":"2016-07-25T15:01:44","guid":{"rendered":"https:\/\/blogs.mathworks.com\/steve\/?p=2062"},"modified":"2019-11-01T16:44:02","modified_gmt":"2019-11-01T20:44:02","slug":"adaptive-thresholding-for-binarization","status":"publish","type":"post","link":"https:\/\/blogs.mathworks.com\/steve\/2016\/07\/25\/adaptive-thresholding-for-binarization\/","title":{"rendered":"Adaptive thresholding for binarization"},"content":{"rendered":"<div class=\"content\"><p>Despite recent appearances on the blog, I still exist! It's just been a little crazier than usual for the last month or so.<\/p><p><b>Anyway<\/b> ... I'm back, and I'm going to try to wrap things up about image binarization. In my <a href=\"https:\/\/blogs.mathworks.com\/steve\/2016\/06\/14\/image-binarization-otsus-method\/\">14-Jun-2016 post<\/a>, I discussed the algorithm underlying <a href=\"https:\/\/www.mathworks.com\/help\/images\/ref\/imbinarize.html\"><tt>imbinarize<\/tt><\/a> for the global thresholding case. Today I'm going to talk about the algorithm for the adaptive thresholding case.<\/p><p>Here's an image suffering from an extreme case of nonuniform illumination.<\/p><pre class=\"codeinput\">I = imread(<span class=\"string\">'printedtext.png'<\/span>);\r\nimshow(I)\r\n<\/pre><img decoding=\"async\" vspace=\"5\" hspace=\"5\" src=\"https:\/\/blogs.mathworks.com\/steve\/files\/bradley_method_01.png\" alt=\"\"> <p>Here is the binarization using a global threshold.<\/p><pre class=\"codeinput\">bw1 = imbinarize(I);\r\nimshow(bw1)\r\ntitle(<span class=\"string\">'Global threshold'<\/span>)\r\n<\/pre><img decoding=\"async\" vspace=\"5\" hspace=\"5\" src=\"https:\/\/blogs.mathworks.com\/steve\/files\/bradley_method_02.png\" alt=\"\"> <p>And here is the binarization using an adaptive threshold. Note that we have to tell the function that the foreground pixels (representing text characters) are darker than the background pixels (the white paper).<\/p><pre class=\"codeinput\">bw2 = imbinarize(I,<span class=\"string\">'adaptive'<\/span>,<span class=\"string\">'ForegroundPolarity'<\/span>,<span class=\"string\">'dark'<\/span>);\r\nimshow(bw2)\r\ntitle(<span class=\"string\">'Adaptive threshold'<\/span>)\r\n<\/pre><img decoding=\"async\" vspace=\"5\" hspace=\"5\" src=\"https:\/\/blogs.mathworks.com\/steve\/files\/bradley_method_03.png\" alt=\"\"> <p>The algorithm used by |imbinarize(I,'adaptive',...) is sometimes called Bradley's method, for the paper by D. Bradley and G. Roth, \"Adaptive Thresholding Using Integral Image,\" Journal of Graphics Tools, vol. 12, issue 2, pp. 13-21, 2007.<\/p><p>This method uses a large-neighborhood mean filter. If the input image pixel is more than a certain percentage greater than the mean filter, then it is set to white.<\/p><p>To perform large-neighborhood mean filtering (also called <i>box filtering<\/i>) efficiently, the implementation uses something called an <i>integral image<\/i>. With this technique, time required to perform mean filtering depends only on the number of image pixels. The time is independent of the neighborhood size. Maybe I'll discuss integral images and box filtering in a future post. In the meantime, you can look at <a href=\"https:\/\/www.mathworks.com\/help\/images\/ref\/integralimage.html\"><tt>integralImage<\/tt><\/a> and <a href=\"https:\/\/www.mathworks.com\/help\/images\/ref\/imboxfilt.html\"><tt>imboxfilt<\/tt><\/a>.<\/p><p>So how big is the mean filter neighborhood? Well, there's no fixed rule. This is another one of those magic numbers that bedevil image processing. The function <tt>imbinarize<\/tt> uses a square neighborhood that is about 1\/8 of the smallest image dimension. This is just a heuristic rule that works reasonably well for a variety of images.<\/p><p>The function <tt>imbinarize<\/tt> does everything for you in one step. It computes the adaptive threshold image and then applies it to produce a binary output image. If you want the adaptive threshold image itself, or if you want more control over the how the adaptive threshold image is computed, then you can use <a href=\"https:\/\/www.mathworks.com\/help\/images\/ref\/adaptthresh.html\"><tt>adaptthresh<\/tt><\/a>.<\/p><p>Here is the adaptive threshold image for the printed text example shown above.<\/p><pre class=\"codeinput\">T = adaptthresh(I,<span class=\"string\">'ForegroundPolarity'<\/span>,<span class=\"string\">'dark'<\/span>);\r\nimshow(T)\r\ntitle(<span class=\"string\">'Adaptive threshold image'<\/span>)\r\n<\/pre><img decoding=\"async\" vspace=\"5\" hspace=\"5\" src=\"https:\/\/blogs.mathworks.com\/steve\/files\/bradley_method_04.png\" alt=\"\"> <p>When you use <tt>adaptthresh<\/tt>, you can control the neighborhood size directly. You can also specify other local background measurement methods, including median filtering and Gaussian filter.<\/p><p><b>Wrapping Up<\/b><\/p><p>With the new set of Image Processing Toolbox interfaces, using <tt>imbinarize<\/tt> as your one-step solution for both global and adaptive thresholding. Gain finer control over algorithm details, if you need to, by using the underlying functions <tt>otsuthresh<\/tt> and <tt>adaptthresh<\/tt>. The older functions, <tt>im2bw<\/tt> and <tt>graythresh<\/tt>, still exist for compatibility, but we encourage you to use the new functions in your new code.<\/p><script language=\"JavaScript\"> <!-- \r\n    function grabCode_fe9ea6458a2b48c3892cb04123763a2a() {\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='fe9ea6458a2b48c3892cb04123763a2a ' + '##### ' + 'SOURCE BEGIN' + ' #####';\r\n        t2='##### ' + 'SOURCE END' + ' #####' + ' fe9ea6458a2b48c3892cb04123763a2a';\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 2016 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_fe9ea6458a2b48c3892cb04123763a2a()\"><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; R2016a<br><\/p><\/div><!--\r\nfe9ea6458a2b48c3892cb04123763a2a ##### SOURCE BEGIN #####\r\n%%\r\n% Despite recent appearances on blog, I still exist! It's just been a\r\n% little crazier than usual for the last month or so.\r\n%\r\n% *Anyway* ... I'm back, and I'm going to try to wrap things up about image\r\n% binarization. In my\r\n% <https:\/\/blogs.mathworks.com\/steve\/2016\/06\/14\/image-binarization-otsus-method\/\r\n% 14-Jun-2016 post>, I discussed the algorithm underlying\r\n% <https:\/\/www.mathworks.com\/help\/images\/ref\/imbinarize.html |imbinarize|>\r\n% for the global thresholding case. Today I'm going to talk about the\r\n% algorithm for the adaptive thresholding case.\r\n%\r\n% Here's an image suffering from an extreme case of nonuniform\r\n% illumination.\r\n\r\nI = imread('printedtext.png');\r\nimshow(I)\r\n\r\n%%\r\n% Here is the binarization using a global threshold.\r\n\r\nbw1 = imbinarize(I);\r\nimshow(bw1)\r\ntitle('Global threshold')\r\n\r\n%%\r\n% And here is the binarization using an adaptive threshold. Note that we\r\n% have to tell the function that the foreground pixels (representing text\r\n% characters) are darker than the background pixels (the white paper).\r\n\r\nbw2 = imbinarize(I,'adaptive','ForegroundPolarity','dark');\r\nimshow(bw2)\r\ntitle('Adaptive threshold')\r\n\r\n%%\r\n% The algorithm used by |imbinarize(I,'adaptive',...) is sometimes called\r\n% Bradley's method, for the paper by D. Bradley and G. Roth, \"Adaptive\r\n% Thresholding Using Integral Image,\" Journal of Graphics Tools, vol. 12,\r\n% issue 2, pp. 13-21, 2007.\r\n%\r\n% This method uses a large-neighborhood mean filter. If the input image\r\n% pixel is more than a certain percentage greater than the mean filter,\r\n% then it is set to white.\r\n%\r\n% To perform large-neighborhood mean filtering (also called _box filtering_)\r\n% efficiently, the implementation uses something called an _integral\r\n% image_. With this technique, time required to perform mean filtering\r\n% depends only on the number of image pixels. The time is independent of\r\n% the neighborhood size. Maybe I'll discuss integral images and box\r\n% filtering in a future post. In the meantime, you can look at\r\n% <https:\/\/www.mathworks.com\/help\/images\/ref\/integralimage.html\r\n% |integralImage|> and\r\n% <https:\/\/www.mathworks.com\/help\/images\/ref\/imboxfilt.html |imboxfilt|>.\r\n%\r\n% So how big is the mean filter neighborhood? Well, there's no fixed rule.\r\n% This is another one of those magic numbers that bedevil image processing.\r\n% The function |imbinarize| uses a square neighborhood that is about 1\/8 of\r\n% the smallest image dimension. This is just a heuristic rule that works\r\n% reasonably well for a variety of images.\r\n%\r\n% The function |imbinarize| does everything for you in one step. It\r\n% computes the adaptive threshold image and then applies it to produce a\r\n% binary output image. If you want the adaptive threshold image itself, or\r\n% if you want more control over the how the adaptive threshold image is\r\n% computed, then you can use\r\n% <https:\/\/www.mathworks.com\/help\/images\/ref\/adaptthresh.html\r\n% |adaptthresh|>.\r\n%\r\n% Here is the adaptive threshold image for the printed text example shown\r\n% above.\r\n\r\nT = adaptthresh(I,'ForegroundPolarity','dark');\r\nimshow(T)\r\ntitle('Adaptive threshold image')\r\n\r\n%%\r\n% When you use |adaptthresh|, you can control the neighborhood\r\n% size directly. You can also specify other local background measurement\r\n% methods, including median filtering and Gaussian filter.\r\n%\r\n% *Wrapping Up*\r\n%\r\n% With the new set of Image Processing Toolbox interfaces, using\r\n% |imbinarize| as your one-step solution for both global and adaptive\r\n% thresholding. Gain finer control over algorithm details, if you need to,\r\n% by using the underlying functions |otsuthresh| and |adaptthresh|. The\r\n% older functions, |im2bw| and |graythresh|, still exist for compatibility,\r\n% but we encourage you to use the new functions in your new code.\r\n##### SOURCE END ##### fe9ea6458a2b48c3892cb04123763a2a\r\n-->","protected":false},"excerpt":{"rendered":"<div class=\"overview-image\"><img src=\"https:\/\/blogs.mathworks.com\/steve\/files\/bradley_method_02.png\" class=\"img-responsive attachment-post-thumbnail size-post-thumbnail wp-post-image\" alt=\"\" decoding=\"async\" loading=\"lazy\" \/><\/div><p>Despite recent appearances on the blog, I still exist! It's just been a little crazier than usual for the last month or so.Anyway ... I'm back, and I'm going to try to wrap things up about image... <a class=\"read-more\" href=\"https:\/\/blogs.mathworks.com\/steve\/2016\/07\/25\/adaptive-thresholding-for-binarization\/\">read more >><\/a><\/p>","protected":false},"author":42,"featured_media":2065,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":[],"categories":[1],"tags":[1159,82,84,1155,76,36,52],"_links":{"self":[{"href":"https:\/\/blogs.mathworks.com\/steve\/wp-json\/wp\/v2\/posts\/2062"}],"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=2062"}],"version-history":[{"count":3,"href":"https:\/\/blogs.mathworks.com\/steve\/wp-json\/wp\/v2\/posts\/2062\/revisions"}],"predecessor-version":[{"id":2069,"href":"https:\/\/blogs.mathworks.com\/steve\/wp-json\/wp\/v2\/posts\/2062\/revisions\/2069"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/blogs.mathworks.com\/steve\/wp-json\/wp\/v2\/media\/2065"}],"wp:attachment":[{"href":"https:\/\/blogs.mathworks.com\/steve\/wp-json\/wp\/v2\/media?parent=2062"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blogs.mathworks.com\/steve\/wp-json\/wp\/v2\/categories?post=2062"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blogs.mathworks.com\/steve\/wp-json\/wp\/v2\/tags?post=2062"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}