{"id":825,"date":"2013-04-12T08:41:36","date_gmt":"2013-04-12T12:41:36","guid":{"rendered":"https:\/\/blogs.mathworks.com\/steve\/?p=825"},"modified":"2019-11-01T09:15:15","modified_gmt":"2019-11-01T13:15:15","slug":"revisiting-dctdemo-part-4","status":"publish","type":"post","link":"https:\/\/blogs.mathworks.com\/steve\/2013\/04\/12\/revisiting-dctdemo-part-4\/","title":{"rendered":"Revisiting dctdemo &#8211; part 4"},"content":{"rendered":"\r\n<div class=\"content\"><p>This is the fourth and last part of my plan (my evil plan?) to rewrite an Image Processing Toolbox example from 20 years ago using more modern MATLAB language features. I got the idea from Dave Garrison's <a href=\"https:\/\/www.mathworks.com\/company\/newsletters\/articles\/writing-apps-in-matlab.html\">recent article<\/a> on writing MATLAB apps.<\/p><p>Here's the old app I'm trying to reinvent:<\/p><p><img decoding=\"async\" vspace=\"5\" hspace=\"5\" src=\"https:\/\/blogs.mathworks.com\/images\/steve\/2013\/dctdemo-screen-shot.png\" alt=\"\"> <\/p><p>And here's what I had working <a href=\"https:\/\/blogs.mathworks.com\/steve\/2013\/03\/21\/revisiting-dctdemo-part-3\/\">last time<\/a>:<\/p><p><img decoding=\"async\" vspace=\"5\" hspace=\"5\" src=\"https:\/\/blogs.mathworks.com\/images\/steve\/2013\/dct-compression-example-v3.png\" alt=\"\"> <\/p><p>There are two things I want to wrap up before calling it good enough:<\/p><div><ul><li>Implement the display of the DCT coefficient mask (lower left of app)<\/li><li>Allow user to control the number of DCT coefficients by setting the <tt>NumDCTCoefficients<\/tt> property of the app.<\/li><\/ul><\/div><p>First let's get the DCT coefficient mask display working. Recall that last time I added a function to compute the reconstructed image, given the desired number of DCT coefficients. I'll add a second output argument to that function in order to return the DCT coefficient mask. Here's the code. The only changes are on the first line (to define the additional output argument) and the last three lines (to compute the mask).<\/p><pre>function [I2,mask] = reconstructImage(I,n)\r\n% Reconstruct the image from n of the DCT coefficients in each 8-by-8\r\n% block. Select the n coefficients with the largest variance across the\r\n% image. Second output argument is the 8-by-8 DCT coefficient mask.<\/pre><pre>% Compute 8-by-8 block DCTs.\r\nf = @(block) dct2(block.data);\r\nA = blockproc(I,[8 8],f);<\/pre><pre>% Compute DCT coefficient variances and decide\r\n% which to keep.\r\nB = im2col(A,[8 8],'distinct')';\r\nvars = var(B);\r\n[~,idx] = sort(vars,'descend');\r\nkeep = idx(1:n);<\/pre><pre>% Zero out the DCT coefficients we are not keeping.\r\nB2 = zeros(size(B));\r\nB2(:,keep) = B(:,keep);<\/pre><pre>% Reconstruct image using 8-by-8 block inverse\r\n% DCTs.\r\nC = col2im(B2',[8 8],size(I),'distinct');\r\nfinv = @(block) idct2(block.data);\r\nI2 = blockproc(C,[8 8],finv);<\/pre><pre>mask = false(8,8);\r\nmask(keep) = true;\r\nend<\/pre><p>Next I need some code to visualize the coefficient mask. I want to display it as image with gray lines drawn between the mask pixels. So I added a local function called <tt>displayCoefficientMask<\/tt>:<\/p><pre>function displayCoefficientMask(mask,ax)\r\nimshow(mask,'Parent',ax)\r\nfor k = 0.5:1.0:8.5\r\n    line('XData',[0.5 8.5], ...\r\n        'YData',[k k], ...\r\n        'Color',[0.6 0.6 0.6], ...\r\n        'LineWidth',2, ...\r\n        'Clipping','off', ...\r\n        'Parent',ax);\r\n    line('XData',[k k],...\r\n        'YData',[0.5 8.5],...\r\n        'Color',[0.6 0.6 0.6], ...\r\n        'LineWidth',2,...\r\n        'Clipping','off', ...\r\n        'Parent',ax);\r\nend\r\ntitle(ax,'DCT Coefficient Mask')\r\nend<\/pre><p>The last step is to call <tt>displayCoefficientMask<\/tt> from the <tt>update<\/tt> method (which gets called whenever the slider is moved). In the code below, I have modified the call to <tt>reconstructImage<\/tt> to use two output arguments in order to get the mask; I have assigned the various app properties; and I have added the call to <tt>displayCoefficientMask<\/tt> at the end.<\/p><pre>function update(app)\r\n% Update the computation\r\n[recon_image,mask] = reconstructImage(app.OriginalImage, ...\r\n    app.NumDCTCoefficients);<\/pre><pre>diff_image = imabsdiff(app.OriginalImage, recon_image);<\/pre><pre>% Update the app properties\r\napp.ReconstructedImage = recon_image;\r\napp.ErrorImage = diff_image;\r\napp.DCTCoefficientMask = mask;<\/pre><pre>% Update the display\r\nimshow(app.OriginalImage,'Parent',app.OriginalImageAxes);\r\ntitle(app.OriginalImageAxes,'Original Image');<\/pre><pre>imshow(recon_image,'Parent',app.ReconstructedImageAxes);\r\ntitle(app.ReconstructedImageAxes,'Reconstructed Image');<\/pre><pre>imshow(diff_image,[],'Parent',app.ErrorImageAxes);\r\ntitle(app.ErrorImageAxes,'Error Image');<\/pre><pre>displayCoefficientMask(mask,app.MaskAxes);<\/pre><pre>drawnow;\r\nend<\/pre><p>Here's the result with the DCT coefficient mask visualization included:<\/p><p><img decoding=\"async\" vspace=\"5\" hspace=\"5\" src=\"https:\/\/blogs.mathworks.com\/images\/steve\/2013\/dct-compression-example-v4.png\" alt=\"\"> <\/p><p>The last thing I want to do with this little app is to allow users to set the app's <tt>NumDCTCoefficients<\/tt> property from the command line and to have the app automatically update. To do this, I'll make a couple of changes to the <tt>NumDCTCoefficients<\/tt> property. First, I'll make it a <i>dependent<\/i> property. Instead of being stored independently, this property will be computed on-the-fly from slider setting whenever it is queried. That requires that I define a <a href=\"https:\/\/www.mathworks.com\/help\/matlab\/matlab_oop\/property-access-methods.html\"><i>property get method<\/i><\/a> that computes the property's value on demand. And last I'll need a <i>property set method<\/i> that defines what actions should be taken whenever the user sets the property.<\/p><p>Here's the modified <tt>property<\/tt> block that indicates that <tt>NumDCTCoefficients<\/tt> is a dependent property.<\/p><pre>properties (Dependent)\r\n    NumDCTCoefficients\r\nend<\/pre><p>And here are the get and set functions for <tt>NumDCTCoefficients<\/tt>. The get function computes the number on-the-fly based on the current slider position. The set function modifies the slider position and then calls the <tt>update<\/tt> method to recompute and redisplay everything.<\/p><pre>function value = get.NumDCTCoefficients(app)\r\n    value = round(get(app.Slider,'Value') * 64);\r\nend<\/pre><pre>function set.NumDCTCoefficients(app,num_coefficients)\r\n    set(app.Slider,'Value',num_coefficients\/64)\r\n    update(app);\r\nend<\/pre><p>Here's an example of this interaction.<\/p><pre class=\"codeinput\">app = dctCompressionExample_v5\r\n<\/pre><pre class=\"codeoutput\">\r\napp = \r\n\r\n  dctCompressionExample_v5 with properties:\r\n\r\n         OriginalImage: [240x240 double]\r\n    ReconstructedImage: [240x240 double]\r\n            ErrorImage: [240x240 double]\r\n    DCTCoefficientMask: [8x8 logical]\r\n    NumDCTCoefficients: 3\r\n\r\n<\/pre><img decoding=\"async\" vspace=\"5\" hspace=\"5\" src=\"https:\/\/blogs.mathworks.com\/images\/steve\/2013\/dctdemo_part4_01.png\" alt=\"\"> <p>I can see the DCT coefficient mask on the app, but I can also look at the <tt>DCTCoefficientMask<\/tt> property.<\/p><pre class=\"codeinput\">app.DCTCoefficientMask\r\n<\/pre><pre class=\"codeoutput\">\r\nans =\r\n\r\n     1     1     0     0     0     0     0     0\r\n     1     0     0     0     0     0     0     0\r\n     0     0     0     0     0     0     0     0\r\n     0     0     0     0     0     0     0     0\r\n     0     0     0     0     0     0     0     0\r\n     0     0     0     0     0     0     0     0\r\n     0     0     0     0     0     0     0     0\r\n     0     0     0     0     0     0     0     0\r\n\r\n<\/pre><p>And I can set the <tt>NumDCTCoefficients<\/tt> property, which causes the app to update.<\/p><pre class=\"codeinput\">app.NumDCTCoefficients = 1;\r\n<\/pre><img decoding=\"async\" vspace=\"5\" hspace=\"5\" src=\"https:\/\/blogs.mathworks.com\/images\/steve\/2013\/dctdemo_part4_02.png\" alt=\"\"> <p>OK, I think that's enough to get all the basic ideas. If you want to play around with the final version of the code for this blog post, you can download it from <a href=\"https:\/\/blogs.mathworks.com\/images\/steve\/2013\/dctCompressionExample_v5.m\">here<\/a>.<\/p><div><ul><li><a href=\"https:\/\/blogs.mathworks.com\/steve\/2013\/02\/08\/revisiting-dctdemo-part-1\/\">Revisiting dctdemo - part 1<\/a><\/li><li><a href=\"https:\/\/blogs.mathworks.com\/steve\/2013\/02\/21\/revisiting-dctdemo-part-2\/\">Revisiting dctdemo - part 2<\/a><\/li><li><a href=\"https:\/\/blogs.mathworks.com\/steve\/2013\/03\/21\/revisiting-dctdemo-part-3\/\">Revisiting dctdemo - part 3<\/a><\/li><li><a href=\"https:\/\/blogs.mathworks.com\/steve\/2013\/04\/12\/revisiting-dctdemo-part-4\/\">Revisiting dctdemo - part 4<\/a><\/li><\/ul><\/div><script language=\"JavaScript\"> <!-- \r\n    function grabCode_ca80ad834362412ca00fdfb72ba253d6() {\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='ca80ad834362412ca00fdfb72ba253d6 ' + '##### ' + 'SOURCE BEGIN' + ' #####';\r\n        t2='##### ' + 'SOURCE END' + ' #####' + ' ca80ad834362412ca00fdfb72ba253d6';\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 2013 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_ca80ad834362412ca00fdfb72ba253d6()\"><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; R2013a<br><\/p><p class=\"footer\"><br>\r\n      Published with MATLAB&reg; R2013a<br><\/p><\/div><!--\r\nca80ad834362412ca00fdfb72ba253d6 ##### SOURCE BEGIN #####\r\n%%\r\n% This is the fourth and last part of my plan (my evil plan?) to rewrite an\r\n% Image Processing Toolbox example from 20 years ago using more modern\r\n% MATLAB language features. I got the idea from Dave Garrison's\r\n% <https:\/\/www.mathworks.com\/company\/newsletters\/articles\/writing-apps-in-matlab.html\r\n% recent article> on writing MATLAB apps.\r\n%\r\n% Here's the old app I'm trying to reinvent:\r\n%\r\n% <<https:\/\/blogs.mathworks.com\/images\/steve\/2013\/dctdemo-screen-shot.png>>\r\n%\r\n% And here's what I had working <https:\/\/blogs.mathworks.com\/steve\/2013\/03\/21\/revisiting-dctdemo-part-3\/ \r\n% last time>:\r\n%\r\n% <<https:\/\/blogs.mathworks.com\/images\/steve\/2013\/dct-compression-example-v3.png>>\r\n%\r\n% There are two things I want to wrap up before calling it good enough:\r\n%\r\n% * Implement the display of the DCT coefficient mask (lower left of app)\r\n% * Allow user to control the number of DCT coefficients by setting the\r\n% |NumDCTCoefficients| property of the app.\r\n%\r\n% First let's get the DCT coefficient mask display working. Recall that\r\n% last time I added a function to compute the reconstructed image, given\r\n% the desired number of DCT coefficients. I'll add a second output argument\r\n% to that function in order to return the DCT coefficient mask. Here's the\r\n% code. The only changes are on the first line (to define the additional\r\n% output argument) and the last three lines (to compute the mask).\r\n%\r\n%  function [I2,mask] = reconstructImage(I,n)\r\n%  % Reconstruct the image from n of the DCT coefficients in each 8-by-8\r\n%  % block. Select the n coefficients with the largest variance across the\r\n%  % image. Second output argument is the 8-by-8 DCT coefficient mask.\r\n%  \r\n%  % Compute 8-by-8 block DCTs.\r\n%  f = @(block) dct2(block.data);\r\n%  A = blockproc(I,[8 8],f);\r\n%  \r\n%  % Compute DCT coefficient variances and decide\r\n%  % which to keep.\r\n%  B = im2col(A,[8 8],'distinct')';\r\n%  vars = var(B);\r\n%  [~,idx] = sort(vars,'descend');\r\n%  keep = idx(1:n);\r\n%  \r\n%  % Zero out the DCT coefficients we are not keeping.\r\n%  B2 = zeros(size(B));\r\n%  B2(:,keep) = B(:,keep);\r\n%  \r\n%  % Reconstruct image using 8-by-8 block inverse\r\n%  % DCTs.\r\n%  C = col2im(B2',[8 8],size(I),'distinct');\r\n%  finv = @(block) idct2(block.data);\r\n%  I2 = blockproc(C,[8 8],finv);\r\n%  \r\n%  mask = false(8,8);\r\n%  mask(keep) = true;\r\n%  end\r\n%\r\n% Next I need some code to visualize the coefficient mask. I want to\r\n% display it as image with gray lines drawn between the mask pixels. So I\r\n% added a local function called |displayCoefficientMask|:\r\n%\r\n%  function displayCoefficientMask(mask,ax)\r\n%  imshow(mask,'Parent',ax)\r\n%  for k = 0.5:1.0:8.5\r\n%      line('XData',[0.5 8.5], ...\r\n%          'YData',[k k], ...\r\n%          'Color',[0.6 0.6 0.6], ...\r\n%          'LineWidth',2, ...\r\n%          'Clipping','off', ...\r\n%          'Parent',ax);\r\n%      line('XData',[k k],...\r\n%          'YData',[0.5 8.5],...\r\n%          'Color',[0.6 0.6 0.6], ...\r\n%          'LineWidth',2,...\r\n%          'Clipping','off', ...\r\n%          'Parent',ax);\r\n%  end\r\n%  title(ax,'DCT Coefficient Mask')\r\n%  end\r\n%\r\n% The last step is to call |displayCoefficientMask| from the |update|\r\n% method (which gets called whenever the slider is moved). In the code\r\n% below, I have modified the call to |reconstructImage| to use two output\r\n% arguments in order to get the mask; I have assigned the various app\r\n% properties; and I have added the call to |displayCoefficientMask| at the\r\n% end.\r\n%\r\n%  function update(app)\r\n%  % Update the computation\r\n%  [recon_image,mask] = reconstructImage(app.OriginalImage, ...\r\n%      app.NumDCTCoefficients);\r\n%  \r\n%  diff_image = imabsdiff(app.OriginalImage, recon_image);\r\n%  \r\n%  % Update the app properties\r\n%  app.ReconstructedImage = recon_image;\r\n%  app.ErrorImage = diff_image;\r\n%  app.DCTCoefficientMask = mask;\r\n%  \r\n%  % Update the display\r\n%  imshow(app.OriginalImage,'Parent',app.OriginalImageAxes);\r\n%  title(app.OriginalImageAxes,'Original Image');\r\n%  \r\n%  imshow(recon_image,'Parent',app.ReconstructedImageAxes);\r\n%  title(app.ReconstructedImageAxes,'Reconstructed Image');\r\n%  \r\n%  imshow(diff_image,[],'Parent',app.ErrorImageAxes);\r\n%  title(app.ErrorImageAxes,'Error Image');\r\n%  \r\n%  displayCoefficientMask(mask,app.MaskAxes);\r\n%  \r\n%  drawnow;\r\n%  end\r\n%\r\n% Here's the result with the DCT coefficient mask visualization included:\r\n%\r\n% <<https:\/\/blogs.mathworks.com\/images\/steve\/2013\/dct-compression-example-v4.png>>\r\n%\r\n% The last thing I want to do with this little app is to allow users to set\r\n% the app's |NumDCTCoefficients| property from the command line and to have\r\n% the app automatically update. To do this, I'll make a couple of changes\r\n% to the |NumDCTCoefficients| property. First, I'll make it a _dependent_\r\n% property. Instead of being stored independently, this property will be\r\n% computed on-the-fly from slider setting whenever it is queried. That\r\n% requires that I define a \r\n% <https:\/\/www.mathworks.com\/help\/matlab\/matlab_oop\/property-access-methods.html \r\n% _property get method_> that computes the property's value on demand. And\r\n% last I'll need a _property set method_ that defines what actions should\r\n% be taken whenever the user sets the property.\r\n%\r\n% Here's the modified |property| block that indicates that\r\n% |NumDCTCoefficients| is a dependent property.\r\n%\r\n%  properties (Dependent)\r\n%      NumDCTCoefficients\r\n%  end\r\n%\r\n% And here are the get and set functions for |NumDCTCoefficients|. The get\r\n% function computes the number on-the-fly based on the current slider\r\n% position. The set function modifies the slider position and then calls\r\n% the |update| method to recompute and redisplay everything.\r\n%\r\n%  function value = get.NumDCTCoefficients(app)\r\n%      value = round(get(app.Slider,'Value') * 64);\r\n%  end\r\n%  \r\n%  function set.NumDCTCoefficients(app,num_coefficients)\r\n%      set(app.Slider,'Value',num_coefficients\/64)\r\n%      update(app);\r\n%  end\r\n%\r\n% Here's an example of this interaction.\r\n\r\napp = dctCompressionExample_v5\r\n\r\n%%\r\n% I can see the DCT coefficient mask on the app, but I can also look at the\r\n% |DCTCoefficientMask| property.\r\n\r\napp.DCTCoefficientMask\r\n\r\n%%\r\n% And I can set the |NumDCTCoefficients| property, which causes the app to\r\n% update.\r\n\r\napp.NumDCTCoefficients = 1;\r\n\r\n%%\r\n% OK, I think that's enough to get all the basic ideas. If you want to play\r\n% around with the final version of the code for this blog post, you can\r\n% download it from\r\n% <https:\/\/blogs.mathworks.com\/images\/steve\/2013\/dctCompressionExample_v5.m\r\n% here>.\r\n%\r\n% * <https:\/\/blogs.mathworks.com\/steve\/2013\/02\/08\/revisiting-dctdemo-part-1\/ Revisiting dctdemo - part 1>\r\n% * <https:\/\/blogs.mathworks.com\/steve\/2013\/02\/21\/revisiting-dctdemo-part-2\/ Revisiting dctdemo - part 2>\r\n% * <https:\/\/blogs.mathworks.com\/steve\/2013\/03\/21\/revisiting-dctdemo-part-3\/ Revisiting dctdemo - part 3>\r\n% * <https:\/\/blogs.mathworks.com\/steve\/2013\/04\/12\/revisiting-dctdemo-part-4\/ Revisiting dctdemo - part 4>\r\n\r\n##### SOURCE END ##### ca80ad834362412ca00fdfb72ba253d6\r\n-->","protected":false},"excerpt":{"rendered":"<div class=\"overview-image\"><img decoding=\"async\"  class=\"img-responsive\" src=\"https:\/\/blogs.mathworks.com\/images\/steve\/2013\/dctdemo_part4_02.png\" onError=\"this.style.display ='none';\" \/><\/div><p>\r\nThis is the fourth and last part of my plan (my evil plan?) to rewrite an Image Processing Toolbox example from 20 years ago using more modern MATLAB language features. I got the idea from Dave... <a class=\"read-more\" href=\"https:\/\/blogs.mathworks.com\/steve\/2013\/04\/12\/revisiting-dctdemo-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":[1],"tags":[711,989,204,981,102,991,987,993,36,747,188,190,484,52,100,432,130],"_links":{"self":[{"href":"https:\/\/blogs.mathworks.com\/steve\/wp-json\/wp\/v2\/posts\/825"}],"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=825"}],"version-history":[{"count":4,"href":"https:\/\/blogs.mathworks.com\/steve\/wp-json\/wp\/v2\/posts\/825\/revisions"}],"predecessor-version":[{"id":829,"href":"https:\/\/blogs.mathworks.com\/steve\/wp-json\/wp\/v2\/posts\/825\/revisions\/829"}],"wp:attachment":[{"href":"https:\/\/blogs.mathworks.com\/steve\/wp-json\/wp\/v2\/media?parent=825"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blogs.mathworks.com\/steve\/wp-json\/wp\/v2\/categories?post=825"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blogs.mathworks.com\/steve\/wp-json\/wp\/v2\/tags?post=825"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}