{"id":715,"date":"2012-12-04T07:00:54","date_gmt":"2012-12-04T12:00:54","guid":{"rendered":"https:\/\/blogs.mathworks.com\/steve\/?p=715"},"modified":"2019-11-01T09:07:34","modified_gmt":"2019-11-01T13:07:34","slug":"image-effects-part-4","status":"publish","type":"post","link":"https:\/\/blogs.mathworks.com\/steve\/2012\/12\/04\/image-effects-part-4\/","title":{"rendered":"Don\u2019t Photoshop it\u2026MATLAB it! Image Effects with MATLAB (Part 4)"},"content":{"rendered":"<div class=\"content\"><!--introduction--><p><i>I'd like to welcome back guest blogger <a href=\"https:\/\/www.mathworks.com\/matlabcentral\/fileexchange\/authors\/911\">Brett Shoelson<\/a> for the continuation of his series of posts on implementing image special effects in MATLAB. Brett, a contributor for the <a href=\"https:\/\/blogs.mathworks.com\/pick\/\">File Exchange Pick of the Week blog<\/a>, has been doing image processing with MATLAB for almost 20 years now.<\/i><\/p>\r\n\r\n<p>\r\n<a href=\"https:\/\/blogs.mathworks.com\/steve\/2012\/11\/13\/image-effects-part-1\/\">[Part 1]<\/a> \r\n<a href=\"https:\/\/blogs.mathworks.com\/steve\/2012\/11\/20\/image-effects-part-2\/\">[Part 2]<\/a>\r\n<a href=\"https:\/\/blogs.mathworks.com\/steve\/2012\/11\/27\/image-effects-part-3\/\">[Part 3]<\/a>\r\n<a href=\"https:\/\/blogs.mathworks.com\/steve\/2012\/12\/04\/image-effects-part-4\/\">[Part 4]<\/a>\r\n<\/p>\r\n\r\n<!--\/introduction--><h3>Contents<\/h3><div><ul><li><a href=\"#565e6a04-a287-4754-b4f9-af219aa8016c\">Out Standing in the Field<\/a><\/li><li><a href=\"#2ce8418c-d279-4ac8-9c1b-ab315c44b3d1\">Segmenting by Color<\/a><\/li><li><a href=\"#f8f98f7a-90d2-449f-8f1f-0c3587d5ccfc\">Now to Use the Segmented Zebra<\/a><\/li><li><a href=\"#80a54d09-4262-412a-b544-a61fb27f9843\">Thanks, a Note on Image Segmentation, and a Challenge<\/a><\/li><\/ul><\/div><p><img decoding=\"async\" vspace=\"5\" hspace=\"5\" src=\"https:\/\/blogs.mathworks.com\/pick\/files\/zebrainpastelfield.png\" alt=\"\"> <\/p><h4>Out Standing in the Field<a name=\"565e6a04-a287-4754-b4f9-af219aa8016c\"><\/a><\/h4><p>In the three previous entries in this guest series (<a href=\"https:\/\/blogs.mathworks.com\/steve\/?p=701\">part 1<\/a>, <a href=\"https:\/\/blogs.mathworks.com\/steve\/?p=704\">part 2<\/a>, <a href=\"https:\/\/blogs.mathworks.com\/steve\/?p=707\">part 3<\/a>) I've worked my way through some approaches to creating special image effects with MATLAB. I started easy, and increased the difficulty level as I progressed. In this fourth post, I'm going to create the zebra image above. You might guess that doing so will entail segmenting the zebra--certainly the most difficult part of this problem.<\/p><p>I previously wrote that I can <i>usually<\/i> get a good segmentation mask working in on or more grayscale representations of a color image. While I stand by that statement, I will also say that sometimes color <i>does<\/i> provide good information with which to create a segmentation mask. In fact, I'm going to use color to segment the zebra in this image, and then use the manual masking approach (using the <a href=\"https:\/\/www.mathworks.com\/help\/images\/ref\/imfreehand.html\"><tt>imfreehand<\/tt><\/a>- mediated approach I used in the previous post) to fine-tune the mask.<\/p><h4>Segmenting by Color<a name=\"2ce8418c-d279-4ac8-9c1b-ab315c44b3d1\"><\/a><\/h4><p>There are several approaches to segmenting using color information. If I wanted to create a mask of a single user-selected color, for instance, I could use <a href=\"https:\/\/www.mathworks.com\/help\/images\/ref\/impixelregion.html\"><tt>impixelregion<\/tt><\/a> to explore colors in a region, or I could invoke <a href=\"https:\/\/www.mathworks.com\/help\/images\/ref\/impixel.html\"><tt>impixel<\/tt><\/a> to click-select color samples.<\/p><pre class=\"language-matlab\"><span class=\"comment\">%Note that the |im2double| conversion conveniently scales the intensities to [0,1]<\/span>\r\nURL = <span class=\"string\">'https:\/\/blogs.mathworks.com\/pick\/files\/ZebraInField.jpg'<\/span>;\r\nimg = im2double(imread(URL));\r\nfigure, imshow(img);\r\nimpixelregion\r\n<\/pre><p><img decoding=\"async\" vspace=\"5\" hspace=\"5\" src=\"https:\/\/blogs.mathworks.com\/pick\/files\/impixelregion.png\" alt=\"\"> <\/p><p><tt>impixelregion<\/tt> provides a convenient tool for exploring the RGB (or grayscale) values underneath a small rectangle; as you drag that rectangle over your image, the intensity values are updated and displayed in a separate figure. In this image, for instance, we might recognize that the grass has an RGB intensity of roughly [0.75 0.65 0.5]. By specifying a \"tolerance\" of 0.05 (i.e., 5 percent of the color range) we can readily create a mask of \"not-zebra\" by selecting all pixels that have those approximate red, green, and blue values:<\/p><pre class=\"language-matlab\">targetColor = [0.75 0.65 0.5];\r\ntolerance = 0.05;\r\nmask =<span class=\"keyword\">...<\/span>\r\n  img(:,:,1) &gt;= targetColor(1) - tolerance &amp; <span class=\"keyword\">...<\/span>\r\n  img(:,:,1) &lt;= targetColor(1) + tolerance &amp; <span class=\"keyword\">...<\/span>\r\n  img(:,:,2) &gt;= targetColor(2) - tolerance &amp; <span class=\"keyword\">...<\/span>\r\n  img(:,:,2) &lt;= targetColor(2) + tolerance &amp; <span class=\"keyword\">...<\/span>\r\n  img(:,:,3) &gt;= targetColor(3) - tolerance &amp; <span class=\"keyword\">...<\/span>\r\n  img(:,:,3) &lt;= targetColor(3) + tolerance;\r\nfigure,imshow(mask);title(<span class=\"string\">'Not Zebra?'<\/span>)\r\n<\/pre><p><img decoding=\"async\" vspace=\"5\" hspace=\"5\" src=\"https:\/\/blogs.mathworks.com\/pick\/files\/SegmentingZebra1.png\" alt=\"\"> <\/p><p>Recognize here that each of those constraints on the binary variable \"mask\" is simply an additional logical AND that I'm applying. I could easily provide different tolerances for ranges above and below each of R, G, and B. (<a href=\"https:\/\/www.mathworks.com\/matlabcentral\/fileexchange\/38484-segmenttool--an-interactive-gui-for-segmenting-images\">A GUI<\/a> with sliders might facilitate that interaction!) I could also create additional masks in a similar manner and combine them, using the logical OR operation, until I achieved the desired segmentation.<\/p><p>Instead of going down that path, though, I'd like to demonstrate another useful approach to color segmentation. In this approach, rather than manually selecting colors on which to base the segmentation mask, I'm going to let MATLAB do the work. The function <a href=\"https:\/\/www.mathworks.com\/help\/matlab\/ref\/rgb2ind.html\"><tt>rgb2ind<\/tt><\/a> quantizes an image into a user-specified number of colors. Each of those \"quantum levels\" can be used to create a unique mask of the image. For instance, here I quantize the zebra into 16 colors and display the binary mask that each index represents:<\/p><pre class=\"language-matlab\">nColors = 16;\r\nX = rgb2ind(img,16);\r\n<span class=\"comment\">% (X ranges from 0 to nColors-1)<\/span>\r\n<span class=\"keyword\">for<\/span> ii = 0:nColors-1\r\n    subplot(4,4,ii+1)\r\n    imshow(ismember(X,ii));\r\n    title(sprintf(<span class=\"string\">'X = %d'<\/span>,ii));\r\n<span class=\"keyword\">end<\/span>\r\n<\/pre><p><img decoding=\"async\" vspace=\"5\" hspace=\"5\" src=\"https:\/\/blogs.mathworks.com\/pick\/files\/SegmentingZebra2.png\" alt=\"\"> <\/p><p>Now at a glance I can construct a segmentation mask of the zebra, selecting only the indices that have a significant component within the area of interest:<\/p><pre class=\"language-matlab\">mask = ismember(X,[0,2,4,5,7,10:12,14,15]);\r\nfigure,imshow(mask)\r\n<\/pre><p><img decoding=\"async\" vspace=\"5\" hspace=\"5\" src=\"https:\/\/blogs.mathworks.com\/pick\/files\/SegmentingZebra3.png\" alt=\"\"> <\/p><p>Clearly, there's a tradeoff between including more indices to \"solidify\" the zebra mask, and increasing the amount of background \"noise\" included in the segmentation. I like this as a starting point, so I'm going to use this and start refining:<\/p><pre class=\"language-matlab\">mask = bwareaopen(mask,100); <span class=\"comment\">%Remove small blobs<\/span>\r\nmask = imfill(mask,<span class=\"string\">'holes'<\/span>); <span class=\"comment\">%Morphologically fill holes<\/span>\r\nfigure,imshow(mask)\r\n<\/pre><p><img decoding=\"async\" vspace=\"5\" hspace=\"5\" src=\"https:\/\/blogs.mathworks.com\/pick\/files\/SegmentingZebra4.png\" alt=\"\"> <\/p><p>Normally, I would use <a href=\"https:\/\/www.mathworks.com\/help\/images\/ref\/imclearborder.html\"><tt>imclearborder<\/tt><\/a> to remove the large white region at the top of the image, and then, using <a href=\"https:\/\/www.mathworks.com\/help\/images\/ref\/regionprops.html\"><tt>regionprops<\/tt><\/a>, determine the areas of each connected blob. The documentation for <tt>regionprops<\/tt> shows how one could easily use that information to eliminate all but the largest object in the resulting image. (That would presumably leave only the zebra.) But in this case, that would also eliminate all the small isolated regions around the zebra's legs, and I would like to keep those. So instead, I'm going to quickly encircle the zebra using <tt>imfreehand<\/tt>, and use the resulting mask to eliminate all peripheral blobs.<\/p><pre class=\"language-matlab\">manualMask = imfreehand;\r\n<\/pre><p><img decoding=\"async\" vspace=\"5\" hspace=\"5\" src=\"https:\/\/blogs.mathworks.com\/pick\/files\/SegmentingZebra5.png\" alt=\"\"> <\/p><pre class=\"language-matlab\">posns = getPosition(manualMask);\r\n[m,n,~] = size(mask);\r\nincludeMask = poly2mask(posns(:,1),posns(:,2),m,n);\r\nmask = mask &amp; includeMask;\r\nmask = imdilate(mask,strel(<span class=\"string\">'disk'<\/span>,2)); <span class=\"comment\">%Slight tweak here<\/span>\r\nimshow(mask);\r\n<\/pre><p><img decoding=\"async\" vspace=\"5\" hspace=\"5\" src=\"https:\/\/blogs.mathworks.com\/pick\/files\/SegmentingZebra6.png\" alt=\"\"> <\/p><h4>Now to Use the Segmented Zebra<a name=\"f8f98f7a-90d2-449f-8f1f-0c3587d5ccfc\"><\/a><\/h4><p>Yes! I like that mask, and can do a lot with it. Conveniently, the function <a href=\"https:\/\/www.mathworks.com\/help\/images\/ref\/roifilt2.html\"><tt>roifilt2<\/tt><\/a> allows me to operate on only a masked portion of an image. That function, though, only works on 2-D images--not on RGB images. However, when it makes sense to do so, I can modify the red, green, and blue planes indendently, and reconstruct the RGB image using <tt>cat<\/tt>. For instance:<\/p><pre class=\"language-matlab\">processImage{1} = @(x) imadjust(x,[0.05; 0.16],[1.00; 0.11], 1.20); <span class=\"comment\">%Red plane<\/span>\r\nprocessImage{2} = @(x) imadjust(x,[0.10; 0.83],[0.00; 1.00], 1.00); <span class=\"comment\">%Green plane<\/span>\r\nprocessImage{3} = @(x) imadjust(x,[0.00; 0.22],[1.00; 0.00], 1.10); <span class=\"comment\">%Blue plane<\/span>\r\nr = roifilt2(img(:,:,1),mask,processImage{1});\r\ng = roifilt2(img(:,:,2),mask,processImage{2});\r\nb = roifilt2(img(:,:,3),mask,processImage{3});\r\nenhancedImg = cat(3,r,g,b);\r\nfigure,imshow(enhancedImg)\r\n<\/pre><p><img decoding=\"async\" vspace=\"5\" hspace=\"5\" src=\"https:\/\/blogs.mathworks.com\/pick\/files\/greenpinkzebra.png\" alt=\"\"> <\/p><p>Creating the \"normal\" zebra in the pastel field is a <i>bit<\/i> trickier, since I can't do a decorrelation stretch plane-by-plane. So instead, I'm going to create the \"pastel effect\" using <tt>decorrstretch<\/tt>, and then reset the values <i>underneath the masked zebra<\/i> back to their original values.<\/p><pre class=\"language-matlab\">imgEnhanced = decorrstretch(img); <span class=\"comment\">%Operating on the original image<\/span>\r\n<span class=\"comment\">% Now reset the red plane to the masked value of the original image<\/span>\r\nr = imgEnhanced(:,:,1); <span class=\"comment\">% Get the enhanced red plane<\/span>\r\ntmp = img(:,:,1); <span class=\"comment\">% Get the original red plane<\/span>\r\n<span class=\"comment\">%Replace the enhanced red under the mask with the original red:<\/span>\r\nr(mask) = tmp(mask);\r\n<span class=\"comment\">% Same for green<\/span>\r\ng = imgEnhanced(:,:,2);\r\ntmp = img(:,:,2);\r\ng(mask) = tmp(mask);\r\n<span class=\"comment\">% And blue<\/span>\r\nb = imgEnhanced(:,:,3);\r\ntmp = img(:,:,3);\r\nb(mask) = tmp(mask);\r\n<span class=\"comment\">% Now reconstruct the enhanced image<\/span>\r\nimgEnhanced = cat(3,r,g,b);\r\n<span class=\"comment\">% And tweak it with imadjust to intensify colors<\/span>\r\nimgEnhanced = imadjust(imgEnhanced,[0.1; 0.8],[0.00; 1.00], 1.00);\r\n<span class=\"comment\">%figure, imshow(imgEnhanced); title('Voila!')<\/span>\r\n<span class=\"comment\">%(This reproduces the zebra at the top of this post!)<\/span>\r\n<\/pre><h4>Thanks, a Note on Image Segmentation, and a Challenge<a name=\"80a54d09-4262-412a-b544-a61fb27f9843\"><\/a><\/h4><p>If you are a regular reader of \"Steve on Image Processing,\" then you'll know that I've commandeered Steve's blog for the past several weeks to present my vision of using MATLAB to create special image effects. I'd like to thank Steve for hosting this guest series; I always enjoy reading Steve's blog, and I'm very pleased to contribute to it.<\/p><p>In the course of this guest series, I shared <a href=\"https:\/\/www.mathworks.com\/matlabcentral\/fileexchange\/index?utf8=%E2%9C%93&amp;term=morphtool+or+imadjustgui\">my GUIs<\/a> for adjusting image intensities and for trying out different morphological operations and structuring elements. I previously mentioned that segmentation is often the most difficult part of an image processing problem. So, in the spirit of the coming holidays, here's one more GUI that I'd like to share with you: <a href=\"https:\/\/www.mathworks.com\/matlabcentral\/fileexchange\/38484-segmenttool--an-interactive-gui-for-segmenting-images\">SegmentTool<\/a> provides an interactive environment for segmenting images. It currently includes tabs for edge detection, thresholding, Hough transforms, using regional and extended minima and maxima, and color-based segmentation. Take it for a test drive and let me know what you think, or what else you'd like to see incorporated.<\/p><p><img decoding=\"async\" vspace=\"5\" hspace=\"5\" src=\"https:\/\/blogs.mathworks.com\/pick\/files\/SegmentTool.png\" alt=\"\"> <\/p><p>This post concludes this guest series, but doesn't nearly exhaust the creative ways in which one can manipulate images using MATLAB and the Image Processing Toolbox. So I'd like to close with a challenge:<\/p><div><ul><li>What Effects Can <i>You<\/i> Create with MATLAB? * Share your own cool image effects with us! Show us how, using only MATLAB (and MathWorks Toolboxes, of course) you can create cool image effects. I will catalog, and share on the MATLAB Central File Exchange, useful or fun approaches to creating special effects with images.<\/li><\/ul><\/div><p>Note that it's not just the altered images that I want; please include the code (or at least, pseudo-code, with detail sufficient to allow other users to reproduce the effect). I'll gladly send some swag to anyone who shares an effect that gets included in the special effects gallery. Send your code to me at <a href=\"mailto:brett.shoelson@mathworks.com\">brett.shoelson@mathworks.com<\/a>.<\/p><p>Happy MATLABbing!<\/p><p>All images copyright Brett Shoelson; used with permission.<\/p><script language=\"JavaScript\"> <!-- \r\n    function grabCode_c4fe66f244b14bb6b7e8d341a1ba25f0() {\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='c4fe66f244b14bb6b7e8d341a1ba25f0 ' + '##### ' + 'SOURCE BEGIN' + ' #####';\r\n        t2='##### ' + 'SOURCE END' + ' #####' + ' c4fe66f244b14bb6b7e8d341a1ba25f0';\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 2012 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_c4fe66f244b14bb6b7e8d341a1ba25f0()\"><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; R2012b<br><\/p><p class=\"footer\"><br>\r\n      Published with MATLAB&reg; R2012b<br><\/p><\/div><!--\r\nc4fe66f244b14bb6b7e8d341a1ba25f0 ##### SOURCE BEGIN #####\r\n%% Don't Photoshop it...MATLAB it! Image Effects with MATLAB (Part 4)\r\n%\r\n% _I'd like to welcome back guest blogger\r\n% <https:\/\/www.mathworks.com\/matlabcentral\/fileexchange\/authors\/911 Brett\r\n% Shoelson> for the continuation of his series of posts on implementing\r\n% image special effects in MATLAB. Brett, a contributor for the\r\n% <https:\/\/blogs.mathworks.com\/pick\/ File Exchange Pick of the Week blog>,\r\n% has been doing image processing with MATLAB for almost 20 years now._\r\n%%\r\n% \r\n% <<https:\/\/blogs.mathworks.com\/pick\/files\/zebrainpastelfield.png>>\r\n% \r\n\r\n%% Out Standing in the Field\r\n% In the three previous entries in this guest series\r\n% (<https:\/\/blogs.mathworks.com\/steve\/?p=701 part 1>,\r\n% <https:\/\/blogs.mathworks.com\/steve\/?p=704 part 2>,\r\n% <https:\/\/blogs.mathworks.com\/steve\/?p=707 part 3>) I've worked my way\r\n% through some approaches to creating special image effects with MATLAB. I\r\n% started easy, and increased the difficulty level as I progressed. In this\r\n% fourth post, I'm going to create the zebra image above. You might guess\r\n% that doing so will entail segmenting the zebraREPLACE_WITH_DASH_DASHcertainly the most\r\n% difficult part of this problem.\r\n\r\n%%\r\n% I previously wrote that I can _usually_ get a good segmentation mask\r\n% working in on or more grayscale representations of a color image. While I\r\n% stand by that statement, I will also say that sometimes color _does_\r\n% provide good information with which to create a segmentation mask. In\r\n% fact, I'm going to use color to segment the zebra in this image, and then\r\n% use the manual masking approach (using the\r\n% <https:\/\/www.mathworks.com\/help\/images\/ref\/imfreehand.html |imfreehand|>-\r\n% mediated approach I used in the previous post) to fine-tune\r\n% the mask.\r\n\r\n%% Segmenting by Color\r\n% There are several approaches to segmenting using color information. If\r\n% I wanted to create a mask of a single user-selected color, for instance, \r\n% I could use\r\n% <https:\/\/www.mathworks.com\/help\/images\/ref\/impixelregion.html |impixelregion|> \r\n% to explore colors in a region, or I could invoke \r\n% <https:\/\/www.mathworks.com\/help\/images\/ref\/impixel.html |impixel|> \r\n% to click-select color samples. \r\n%\r\n%   %Note that the |im2double| conversion conveniently scales the intensities to [0,1]\r\n%   URL = 'https:\/\/blogs.mathworks.com\/pick\/files\/ZebraInField.jpg';\r\n%   img = im2double(imread(URL)); \r\n%   figure, imshow(img);\r\n%   impixelregion\r\n\r\n%% \r\n% <<https:\/\/blogs.mathworks.com\/pick\/files\/impixelregion.png>>\r\n% \r\n\r\n%%\r\n% |impixelregion| provides a convenient tool for exploring the RGB (or\r\n% grayscale) values underneath a small rectangle; as you drag that\r\n% rectangle over your image, the intensity values are updated and displayed\r\n% in a separate figure. In this image, for instance, we might recognize\r\n% that the grass has an RGB intensity of roughly [0.75 0.65 0.5]. By\r\n% specifying a \"tolerance\" of 0.05 (i.e., 5 percent of the color range) we can readily create a mask of \"not-zebra\"\r\n% by selecting all pixels that have those approximate red, green, and blue\r\n% values:\r\n%\r\n%   targetColor = [0.75 0.65 0.5];\r\n%   tolerance = 0.05;\r\n%   mask =...\r\n%     img(:,:,1) >= targetColor(1) - tolerance & ...\r\n%     img(:,:,1) <= targetColor(1) + tolerance & ...\r\n%     img(:,:,2) >= targetColor(2) - tolerance & ...\r\n%     img(:,:,2) <= targetColor(2) + tolerance & ...\r\n%     img(:,:,3) >= targetColor(3) - tolerance & ...\r\n%     img(:,:,3) <= targetColor(3) + tolerance;\r\n%   figure,imshow(mask);title('Not Zebra?')\r\n%%\r\n% \r\n% <<https:\/\/blogs.mathworks.com\/pick\/files\/SegmentingZebra1.png>>\r\n% \r\n%%\r\n% Recognize here that each of those constraints on the binary variable\r\n% \"mask\" is simply an additional logical AND that I'm applying. I could\r\n% easily provide different tolerances for ranges above and below each of R,\r\n% G, and B. (<https:\/\/www.mathworks.com\/matlabcentral\/fileexchange\/38484-segmenttool--an-interactive-gui-for-segmenting-images A GUI>\r\n% with sliders might facilitate that interaction!) I could\r\n% also create additional masks in a similar manner and combine them, using\r\n% the logical OR operation, until I achieved the desired segmentation.\r\n\r\n%%\r\n% Instead of going down that path, though, I'd like to demonstrate another\r\n% useful approach to color segmentation. In this approach, rather than\r\n% manually selecting colors on which to base the segmentation mask, I'm\r\n% going to let MATLAB do the work. The function\r\n% <https:\/\/www.mathworks.com\/help\/matlab\/ref\/rgb2ind.html |rgb2ind|>\r\n% quantizes an image into a user-specified number of colors. Each of those\r\n% \"quantum levels\" can be used to create a unique mask of the image. For\r\n% instance, here I quantize the zebra into 16 colors and display the binary\r\n% mask that each index represents:\r\n%\r\n%   nColors = 16;\r\n%   X = rgb2ind(img,16);\r\n%   % (X ranges from 0 to nColors-1)\r\n%   for ii = 0:nColors-1\r\n%       subplot(4,4,ii+1)\r\n%       imshow(ismember(X,ii));\r\n%       title(sprintf('X = %d',ii));\r\n%   end\r\n\r\n%%\r\n% \r\n% <<https:\/\/blogs.mathworks.com\/pick\/files\/SegmentingZebra2.png>>\r\n% \r\n\r\n%% \r\n% Now at a glance I can construct a segmentation mask of the zebra, selecting\r\n% only the indices that have a significant component within the area of interest:\r\n% \r\n%   mask = ismember(X,[0,2,4,5,7,10:12,14,15]);\r\n%   figure,imshow(mask)\r\n%%\r\n% \r\n% <<https:\/\/blogs.mathworks.com\/pick\/files\/SegmentingZebra3.png>>\r\n% \r\n\r\n%%\r\n% Clearly, there's a tradeoff between including more indices to \"solidify\"\r\n% the zebra mask, and increasing the amount of background \"noise\" included\r\n% in the segmentation. I like this as a starting point, so I'm going to use\r\n% this and start refining:\r\n%\r\n%   mask = bwareaopen(mask,100); %Remove small blobs\r\n%   mask = imfill(mask,'holes'); %Morphologically fill holes\r\n%   figure,imshow(mask)\r\n\r\n%%\r\n% \r\n% <<https:\/\/blogs.mathworks.com\/pick\/files\/SegmentingZebra4.png>>\r\n% \r\n\r\n%% \r\n% Normally, I would use\r\n% <https:\/\/www.mathworks.com\/help\/images\/ref\/imclearborder.html |imclearborder|> \r\n% to remove the large white region at the top of the image, and then,\r\n% using <https:\/\/www.mathworks.com\/help\/images\/ref\/regionprops.html |regionprops|>,\r\n% determine the areas of each connected blob. The documentation for\r\n% |regionprops| shows how one could easily use that information to \r\n% eliminate all but the largest object in the resulting image. (That\r\n% would presumably leave only the zebra.) But in this case, that would also\r\n% eliminate all the small isolated regions around the zebra's legs, and I\r\n% would like to keep those. So instead, I'm going to quickly encircle the\r\n% zebra using |imfreehand|, and use the resulting mask to eliminate all\r\n% peripheral blobs.\r\n%\r\n%   manualMask = imfreehand;\r\n\r\n%%\r\n% \r\n% <<https:\/\/blogs.mathworks.com\/pick\/files\/SegmentingZebra5.png>>\r\n% \r\n\r\n%%\r\n%   posns = getPosition(manualMask);\r\n%   [m,n,~] = size(mask);\r\n%   includeMask = poly2mask(posns(:,1),posns(:,2),m,n);\r\n%   mask = mask & includeMask;\r\n%   mask = imdilate(mask,strel('disk',2)); %Slight tweak here\r\n%   imshow(mask);\r\n\r\n%%\r\n% \r\n% <<https:\/\/blogs.mathworks.com\/pick\/files\/SegmentingZebra6.png>>\r\n% \r\n\r\n%% Now to Use the Segmented Zebra\r\n% Yes! I like that mask, and can do a lot with it. Conveniently, the\r\n% function <https:\/\/www.mathworks.com\/help\/images\/ref\/roifilt2.html\r\n% |roifilt2|> allows me to operate on only a masked portion of an image.\r\n% That function, though, only works on 2-D imagesREPLACE_WITH_DASH_DASHnot on RGB images.\r\n% However, when it makes sense to do so, I can modify the red, green, and\r\n% blue planes indendently, and reconstruct the RGB image using |cat|. For\r\n% instance:\r\n%\r\n%   processImage{1} = @(x) imadjust(x,[0.05; 0.16],[1.00; 0.11], 1.20); %Red plane\r\n%   processImage{2} = @(x) imadjust(x,[0.10; 0.83],[0.00; 1.00], 1.00); %Green plane\r\n%   processImage{3} = @(x) imadjust(x,[0.00; 0.22],[1.00; 0.00], 1.10); %Blue plane\r\n%   r = roifilt2(img(:,:,1),mask,processImage{1});\r\n%   g = roifilt2(img(:,:,2),mask,processImage{2});\r\n%   b = roifilt2(img(:,:,3),mask,processImage{3});\r\n%   enhancedImg = cat(3,r,g,b);\r\n%   figure,imshow(enhancedImg)\r\n\r\n%%\r\n% \r\n% <<https:\/\/blogs.mathworks.com\/pick\/files\/greenpinkzebra.png>>\r\n% \r\n\r\n%%\r\n% Creating the \"normal\" zebra in the pastel field is a _bit_ trickier,\r\n% since I can't do a decorrelation stretch plane-by-plane. So instead, I'm\r\n% going to create the \"pastel effect\" using |decorrstretch|, and then reset\r\n% the values _underneath the masked zebra_ back to their original values.\r\n%\r\n%   imgEnhanced = decorrstretch(img); %Operating on the original image\r\n%   % Now reset the red plane to the masked value of the original image\r\n%   r = imgEnhanced(:,:,1); % Get the enhanced red plane\r\n%   tmp = img(:,:,1); % Get the original red plane\r\n%   %Replace the enhanced red under the mask with the original red:\r\n%   r(mask) = tmp(mask); \r\n%   % Same for green\r\n%   g = imgEnhanced(:,:,2);\r\n%   tmp = img(:,:,2);\r\n%   g(mask) = tmp(mask);\r\n%   % And blue\r\n%   b = imgEnhanced(:,:,3);\r\n%   tmp = img(:,:,3);\r\n%   b(mask) = tmp(mask);\r\n%   % Now reconstruct the enhanced image\r\n%   imgEnhanced = cat(3,r,g,b);\r\n%   % And tweak it with imadjust to intensify colors\r\n%   imgEnhanced = imadjust(imgEnhanced,[0.1; 0.8],[0.00; 1.00], 1.00);\r\n%   %figure, imshow(imgEnhanced); title('Voila!')\r\n%   %(This reproduces the zebra at the top of this post!)\r\n\r\n%% Thanks, a Note on Image Segmentation, and a Challenge\r\n% If you are a regular reader of \"Steve on Image Processing,\" then you'll\r\n% know that I've commandeered Steve's blog for the past several weeks to\r\n% present my vision of using MATLAB to create special image effects. I'd\r\n% like to thank Steve for hosting this guest series; I always enjoy reading\r\n% Steve's blog, and I'm very pleased to contribute to it.\r\n\r\n%% \r\n% In the course of this guest series, I shared\r\n% <https:\/\/www.mathworks.com\/matlabcentral\/fileexchange\/index?utf8=%E2%9C%93&term=morphtool+or+imadjustgui my GUIs>\r\n% for adjusting image intensities and for trying out different\r\n% morphological operations and structuring elements. I previously mentioned\r\n% that segmentation is often the most difficult part of an image processing\r\n% problem. So, in the spirit of the coming holidays, here's one more GUI\r\n% that I'd like to share with you:\r\n% <https:\/\/www.mathworks.com\/matlabcentral\/fileexchange\/38484-segmenttool--an-interactive-gui-for-segmenting-images SegmentTool>\r\n% provides an interactive environment for segmenting images. It currently\r\n% includes tabs for edge detection, thresholding, Hough transforms, using\r\n% regional and extended minima and maxima, and color-based segmentation.\r\n% Take it for a test drive and let me know what you think, or what else\r\n% you'd like to see incorporated.\r\n\r\n%%\r\n% \r\n% <<https:\/\/blogs.mathworks.com\/pick\/files\/SegmentTool.png>>\r\n% \r\n\r\n%%\r\n% This post concludes this guest series, but doesn't nearly exhaust the\r\n% creative ways in which one can manipulate images using MATLAB and the\r\n% Image Processing Toolbox. So I'd like to close with a challenge:\r\n% \r\n% * What Effects Can _You_ Create with MATLAB? *\r\n% Share your own cool image effects with us! Show us how, using only MATLAB\r\n% (and MathWorks Toolboxes, of course) you can create cool image effects. I\r\n% will catalog, and share on the MATLAB Central File Exchange, useful or\r\n% fun approaches to creating special effects with images. \r\n\r\n%%\r\n% Note that it's not just the altered images that I want; please include\r\n% the code (or at least, pseudo-code, with detail sufficient to allow other\r\n% users to reproduce the effect). I'll gladly send some swag to anyone who\r\n% shares an effect that gets included in the special effects gallery. Send\r\n% your code to me at brett.shoelson@mathworks.com.\r\n\r\n%% \r\n% Happy MATLABbing!\r\n\r\n%%\r\n% All images copyright Brett Shoelson; used with permission.\r\n##### SOURCE END ##### c4fe66f244b14bb6b7e8d341a1ba25f0\r\n-->","protected":false},"excerpt":{"rendered":"<!--introduction--><p><i>I'd like to welcome back guest blogger <a href=\"https:\/\/www.mathworks.com\/matlabcentral\/fileexchange\/authors\/911\">Brett Shoelson<\/a> for the continuation of his series of posts on implementing image special effects in MATLAB. Brett, a contributor for the <a href=\"https:\/\/blogs.mathworks.com\/pick\/\">File Exchange Pick of the Week blog<\/a>, has been doing image processing with MATLAB for almost 20 years now.<\/i>... <a class=\"read-more\" href=\"https:\/\/blogs.mathworks.com\/steve\/2012\/12\/04\/image-effects-part-4\/\">read more >><\/a><\/p>","protected":false},"author":42,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":[],"categories":[22],"tags":[138,46,537,725,727,390,949,124,136,416,959,76,36,422,296,627,709,190,270,106,72,52],"_links":{"self":[{"href":"https:\/\/blogs.mathworks.com\/steve\/wp-json\/wp\/v2\/posts\/715"}],"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=715"}],"version-history":[{"count":11,"href":"https:\/\/blogs.mathworks.com\/steve\/wp-json\/wp\/v2\/posts\/715\/revisions"}],"predecessor-version":[{"id":3805,"href":"https:\/\/blogs.mathworks.com\/steve\/wp-json\/wp\/v2\/posts\/715\/revisions\/3805"}],"wp:attachment":[{"href":"https:\/\/blogs.mathworks.com\/steve\/wp-json\/wp\/v2\/media?parent=715"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blogs.mathworks.com\/steve\/wp-json\/wp\/v2\/categories?post=715"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blogs.mathworks.com\/steve\/wp-json\/wp\/v2\/tags?post=715"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}