{"id":2975,"date":"2018-05-21T17:28:14","date_gmt":"2018-05-21T21:28:14","guid":{"rendered":"https:\/\/blogs.mathworks.com\/steve\/?p=2975"},"modified":"2019-11-01T22:31:43","modified_gmt":"2019-11-02T02:31:43","slug":"superpixel-posterization","status":"publish","type":"post","link":"https:\/\/blogs.mathworks.com\/steve\/2018\/05\/21\/superpixel-posterization\/","title":{"rendered":"Superpixel Posterization"},"content":{"rendered":"<p>Today's blog post was inspired by an example written by my friend and Image Processing Toolbox developer, Alex Taylor. A few years back, Alex tinkered with using toolbox algorithms to achieve a pseudo-artistic \"posterization\" effect, like this: <\/p><pre class=\"matlab-code\" id=\"matlabcode\" style=\"background-color: #F7F7F7;font-family: monospace;font-weight:normal;border-style: solid; border-width: 1px ;border-color:#E9E9E9;padding-top:5px;padding-bottom:5px;line-height:150%;\">imshow(<span style=\"color:rgb(160, 32, 240);\">'eddins-horn-1000.png'<\/span>)\r\n<\/pre><img decoding=\"async\" src=\"https:\/\/blogs.mathworks.com\/steve\/files\/paintByNumbersSuperpixels_1.png\"><p>I thought the technique was cool and worth showing. I also noticed that the example uses several Image Processing Toolbox functions that haven't been in the product very long, including: <\/p>\r\n      <ul type=\"square\">\r\n         <p> <inline style=\"font-family: monospace, monospace; font-size: inherit;\">rgb2lab<\/inline> <\/p>\r\n         <p> <inline style=\"font-family: monospace, monospace; font-size: inherit;\">lab2rgb<\/inline> <\/p>\r\n         <p> <inline style=\"font-family: monospace, monospace; font-size: inherit;\">imoverlay<\/inline> <\/p>\r\n         <p> <inline style=\"font-family: monospace, monospace; font-size: inherit;\">boundarymask<\/inline> <\/p>\r\n         <p> <inline style=\"font-family: monospace, monospace; font-size: inherit;\">superpixels<\/inline> <\/p>\r\n      <\/ul>\r\n      <p>So I realized this would be a good chance to introduce you to some recent toolbox additions that you might not know about.<\/p>\r\n      <h3>rgb2lab and lab2rgb<\/h3>\r\n      <p>The two functions <inline style=\"font-family: monospace, monospace; font-size: inherit;\">rgb2lab<\/inline> and <inline style=\"font-family: monospace, monospace; font-size: inherit;\">lab2rgb<\/inline> were introduced in R2014b. They convert between an RGB space and the CIE L*a*b* space. You could perform this conversion previously using the functions <inline style=\"font-family: monospace, monospace; font-size: inherit;\">makecform<\/inline> and <inline style=\"font-family: monospace, monospace; font-size: inherit;\">applycform<\/inline>, but it was awkward. These functions support both <em>sRGB<\/em> and <em>Adobe RGB (1998)<\/em>. <\/p>\r\n      <p>I have mentioned these functions in a couple of previous blog posts, including <a href=\"https:\/\/blogs.mathworks.com\/steve\/2015\/04\/03\/displaying-a-color-gamut-surface\/\">\"Displaying a color gamut surface\"<\/a> and <a href=\"https:\/\/blogs.mathworks.com\/steve\/2015\/08\/11\/out-of-gamut-colors\/\">\"Out-of-gamut colors.\"<\/a><\/p>\r\n      <h3>boundarymask<\/h3>\r\n      <p>The function <inline style=\"font-family: monospace, monospace; font-size: inherit;\">boundarymask<\/inline>, added in R2016a, produces a binary image whose foreground pixels delineate either the boundaries between adjacent labels, if you give it a label matrix, or the boundaries between the foreground and background, if you give it a binary image. Here's an example. <\/p><pre class=\"matlab-code\" id=\"matlabcode\" style=\"background-color: #F7F7F7;font-family: monospace;font-weight:normal;border-style: solid; border-width: 1px ;border-color:#E9E9E9;padding-top:5px;padding-bottom:5px;line-height:150%;\">I = imread(<span style=\"color:rgb(160, 32, 240);\">'rice.png'<\/span>);\r\nbw = imbinarize(I,<span style=\"color:rgb(160, 32, 240);\">'adaptive'<\/span>);\r\nmask = boundarymask(bw);\r\nsubplot(1,2,1)\r\nimshow(I)\r\ntitle(<span style=\"color:rgb(160, 32, 240);\">'Original image'<\/span>)\r\nsubplot(1,2,2)\r\nimshow(mask)\r\ntitle(<span style=\"color:rgb(160, 32, 240);\">'Boundary mask'<\/span>)\r\n<\/pre><img decoding=\"async\" src=\"https:\/\/blogs.mathworks.com\/steve\/files\/paintByNumbersSuperpixels_2.png\"><h3>imoverlay<\/h3>\r\n      <p>The function <inline style=\"font-family: monospace, monospace; font-size: inherit;\">imoverlay<\/inline>, added in R2016a, is useful for highlighting a subset of pixel locations in an image. A good example would be to show the boundary mask computed above on top of the original image. <\/p><pre class=\"matlab-code\" id=\"matlabcode\" style=\"background-color: #F7F7F7;font-family: monospace;font-weight:normal;border-style: solid; border-width: 1px ;border-color:#E9E9E9;padding-top:5px;padding-bottom:5px;line-height:150%;\">I_overlay = imoverlay(I,mask,<span style=\"color:rgb(160, 32, 240);\">'yellow'<\/span>);\r\nimshow(I_overlay)\r\n<\/pre><img decoding=\"async\" src=\"https:\/\/blogs.mathworks.com\/steve\/files\/paintByNumbersSuperpixels_3.png\"><p>In my first year of writing this blog (2006), I wrote my own function with this name and submitted it to the File Exchange. Now that the Image Processing Toolbox has its own version, I'll probably remove mine from the File Exchange soon. <\/p>\r\n      <h3>superpixels<\/h3>\r\n      <p>A \"superpixel\" is simply a group of connected pixels that have similar colors. Computing superpixels has found a regular place in a variety of image analysis and computer vision tasks. The Image Processing Toolbox function <inline style=\"font-family: monospace, monospace; font-size: inherit;\">superpixels<\/inline>, introduced in R2016a, computes these groups. Here's an example that computes the superpixels and then uses both <inline style=\"font-family: monospace, monospace; font-size: inherit;\">boundarymask<\/inline> and <inline style=\"font-family: monospace, monospace; font-size: inherit;\">imoverlay<\/inline> to visualize them. <\/p><pre class=\"matlab-code\" id=\"matlabcode\" style=\"background-color: #F7F7F7;font-family: monospace;font-weight:normal;border-style: solid; border-width: 1px ;border-color:#E9E9E9;padding-top:5px;padding-bottom:5px;line-height:150%;\">A = imread(<span style=\"color:rgb(160, 32, 240);\">'kobi.png'<\/span>);\r\nL = superpixels(A,1500);\r\nmask = boundarymask(L);\r\nB = imoverlay(A,mask,<span style=\"color:rgb(160, 32, 240);\">'cyan'<\/span>);\r\nclf\r\nimshow(B)\r\n<\/pre><img decoding=\"async\" src=\"https:\/\/blogs.mathworks.com\/steve\/files\/paintByNumbersSuperpixels_4.png\"><h3>Superpixel Posterization<\/h3>\r\n      <p>The superpixel posterization method, as implemented by Alex, starts by using <inline style=\"font-family: monospace, monospace; font-size: inherit;\">superpixels<\/inline> to compute clusters of like pixels. <\/p>\r\n      <p>Here's how it works.<\/p><pre class=\"matlab-code\" id=\"matlabcode\" style=\"background-color: #F7F7F7;font-family: monospace;font-weight:normal;border-style: solid; border-width: 1px ;border-color:#E9E9E9;padding-top:5px;padding-bottom:5px;line-height:150%;\">A = imread(<span style=\"color:rgb(160, 32, 240);\">'eddins-horn.png'<\/span>);\r\nimshow(A)\r\ntitle(<span style=\"color:rgb(160, 32, 240);\">'Original image'<\/span>)\r\n<\/pre><img decoding=\"async\" src=\"https:\/\/blogs.mathworks.com\/steve\/files\/paintByNumbersSuperpixels_5.png\"><p>Next, compute and visualize the superpixel clusters.<\/p><pre class=\"matlab-code\" id=\"matlabcode\" style=\"background-color: #F7F7F7;font-family: monospace;font-weight:normal;border-style: solid; border-width: 1px ;border-color:#E9E9E9;padding-top:5px;padding-bottom:5px;line-height:150%;\">[L,N] = superpixels(A,1000);\r\nBW = boundarymask(L);\r\nimshow(imoverlay(A,BW,<span style=\"color:rgb(160, 32, 240);\">'cyan'<\/span>))\r\n<\/pre><img decoding=\"async\" src=\"https:\/\/blogs.mathworks.com\/steve\/files\/paintByNumbersSuperpixels_6.png\"><p>In the next step, I want to replace the pixels in each superpixel cluster with the mean of the cluster's colors. But I want to compute the mean in L*a*b* space, so I start by converting from RGB to L*a*b*. <\/p><pre class=\"matlab-code\" id=\"matlabcode\" style=\"background-color: #F7F7F7;font-family: monospace;font-weight:normal;border-style: solid; border-width: 1px ;border-color:#E9E9E9;padding-top:5px;padding-bottom:5px;line-height:150%;\">Alab = rgb2lab(A);\r\n<\/pre><p>I'll use the function <inline style=\"font-family: monospace, monospace; font-size: inherit;\">label2idx<\/inline> to compute the indices of the pixels in each superpixel cluster. That will let me access the red, green, and blue component values using linear indexing. <\/p><pre class=\"matlab-code\" id=\"matlabcode\" style=\"background-color: #F7F7F7;font-family: monospace;font-weight:normal;border-style: solid; border-width: 1px ;border-color:#E9E9E9;padding-top:5px;padding-bottom:5px;line-height:150%;\">pixel_idx = label2idx(L);\r\n<\/pre><p>For each of the <inline style=\"font-family: monospace, monospace; font-size: inherit;\">N<\/inline> superpixel clusters, use linear indexing to access the red, green, and blue components, compute the corresponding means, and insert those mean values into the corresponding pixel positions in the L*a*b* output image. <\/p><pre class=\"matlab-code\" id=\"matlabcode\" style=\"background-color: #F7F7F7;font-family: monospace;font-weight:normal;border-style: solid; border-width: 1px ;border-color:#E9E9E9;padding-top:5px;padding-bottom:5px;line-height:150%;\">Aplab = Alab;\r\nLn = numel(L);\r\n<span style=\"color:rgb(0, 0, 255);\">for<\/span> k = 1:N\r\n    idx = pixel_idx{k};\r\n    Aplab(idx) = mean(Alab(idx));\r\n    Aplab(idx+Ln) = mean(Alab(idx+Ln));\r\n    Aplab(idx+2*Ln) = mean(Alab(idx+2*Ln));\r\n<span style=\"color:rgb(0, 0, 255);\">end<\/span>\r\n<\/pre><p>Finally, convert back to RGB space.<\/p><pre class=\"matlab-code\" id=\"matlabcode\" style=\"background-color: #F7F7F7;font-family: monospace;font-weight:normal;border-style: solid; border-width: 1px ;border-color:#E9E9E9;padding-top:5px;padding-bottom:5px;line-height:150%;\">Ap = lab2rgb(Aplab);\r\nimshow(Ap)\r\n<\/pre><img decoding=\"async\" src=\"https:\/\/blogs.mathworks.com\/steve\/files\/paintByNumbersSuperpixels_7.png\">","protected":false},"excerpt":{"rendered":"<div class=\"overview-image\"><img decoding=\"async\"  class=\"img-responsive\" src=\"https:\/\/blogs.mathworks.com\/steve\/files\/paintByNumbersSuperpixels_7.png\" onError=\"this.style.display ='none';\" \/><\/div><p>Today's blog post was inspired by an example written by my friend and Image Processing Toolbox developer, Alex Taylor. A few years back, Alex tinkered with using toolbox algorithms to achieve a... <a class=\"read-more\" href=\"https:\/\/blogs.mathworks.com\/steve\/2018\/05\/21\/superpixel-posterization\/\">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":[1217,178,1155,737,76,36,1115,1221,308,162,1113,72,1219,52],"_links":{"self":[{"href":"https:\/\/blogs.mathworks.com\/steve\/wp-json\/wp\/v2\/posts\/2975"}],"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=2975"}],"version-history":[{"count":1,"href":"https:\/\/blogs.mathworks.com\/steve\/wp-json\/wp\/v2\/posts\/2975\/revisions"}],"predecessor-version":[{"id":2977,"href":"https:\/\/blogs.mathworks.com\/steve\/wp-json\/wp\/v2\/posts\/2975\/revisions\/2977"}],"wp:attachment":[{"href":"https:\/\/blogs.mathworks.com\/steve\/wp-json\/wp\/v2\/media?parent=2975"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blogs.mathworks.com\/steve\/wp-json\/wp\/v2\/categories?post=2975"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blogs.mathworks.com\/steve\/wp-json\/wp\/v2\/tags?post=2975"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}