{"id":3835,"date":"2019-11-04T16:39:17","date_gmt":"2019-11-04T21:39:17","guid":{"rendered":"https:\/\/blogs.mathworks.com\/steve\/?p=3835"},"modified":"2022-11-08T17:50:15","modified_gmt":"2022-11-08T22:50:15","slug":"how-to-display-images-with-bilinear-interpolation-and-antialiasing","status":"publish","type":"post","link":"https:\/\/blogs.mathworks.com\/steve\/2019\/11\/04\/how-to-display-images-with-bilinear-interpolation-and-antialiasing\/","title":{"rendered":"How to display images with bilinear interpolation and antialiasing"},"content":{"rendered":"<div class=\"content\"><p><i>Note: this blog post describes an image display feature that is new in R2019b. You can download this release from<\/i> <a href=\"https:\/\/www.mathworks.com\/downloads\">https:\/\/www.mathworks.com\/downloads<\/a>.<\/p><p>This is my new favorite image:<\/p><p><img decoding=\"async\" vspace=\"5\" hspace=\"5\" src=\"https:\/\/blogs.mathworks.com\/steve\/files\/512px-Decimal_Clock_face_by_Pierre_Daniel_Destigny_1798-1805.jpg\" alt=\"\"> <\/p><p>But that's just a 512x512 version of it. Click <a href=\"https:\/\/blogs.mathworks.com\/steve\/files\/Decimal_Clock_face_by_Pierre_Daniel_Destigny_1798-1805.jpg\">here<\/a> for the full resolution (2048x2048) version. <i>Image credit: DeFacto [CC BY-SA 4.0 (<a href=\"https:\/\/creativecommons.org\/licenses\/by-sa\/4.0\">https:\/\/creativecommons.org\/licenses\/by-sa\/4.0<\/a>)]<\/i><\/p><p>This image caught my eye because I'm always looking for a good sample image to demonstrate <i>aliasing<\/i>. Also, I wanted to write a blog post about a new MATLAB image display feature in R2019b: bilinear interpolation and antialiasing.<\/p><p>Before I get into image display details, though, let's zoom into the center of the full-resolution image to see why it interests me.<\/p><pre class=\"codeinput\">url = <span class=\"string\">'https:\/\/blogs.mathworks.com\/steve\/files\/Decimal_Clock_face_by_Pierre_Daniel_Destigny_1798-1805.jpg'<\/span>;\r\nA = imread(url);\r\nA_cropped = A((-250:250) + 1024, (-250:250) + 1024, :);\r\nimshow(A_cropped)\r\n<\/pre><img decoding=\"async\" vspace=\"5\" hspace=\"5\" src=\"https:\/\/blogs.mathworks.com\/steve\/files\/image_display_interpolation_01.png\" alt=\"\"> <p>Next, I want to compute a pixel profile along a path that shows the high-frequency spatial variation. The code below shows the path in blue.<\/p><pre class=\"codeinput\">hold <span class=\"string\">on<\/span>\r\nx = [120 80];\r\ny = [106 188];\r\nplot(x,y,<span class=\"string\">'b'<\/span>,<span class=\"string\">'LineWidth'<\/span>,4)\r\nhold <span class=\"string\">off<\/span>\r\n<\/pre><img decoding=\"async\" vspace=\"5\" hspace=\"5\" src=\"https:\/\/blogs.mathworks.com\/steve\/files\/image_display_interpolation_02.png\" alt=\"\"> <p>And here's the pixel profile (converted to gray-scale) along that path.<\/p><pre class=\"codeinput\">close <span class=\"string\">all<\/span>\r\nc = improfile(A_cropped,x,y);\r\nc = rgb2gray(squeeze(c)\/255);\r\nh = plot(c(:,1));\r\nxlabel(<span class=\"string\">'Distance along the profile path'<\/span>)\r\nylabel(<span class=\"string\">'Gray-scale pixel value'<\/span>)\r\ndatatip(h,13,0.9614);\r\ndatatip(h,25,0.9271);\r\ndatatip(h,60,0.9282);\r\ndatatip(h,72,0.9133);\r\n<\/pre><img decoding=\"async\" vspace=\"5\" hspace=\"5\" src=\"https:\/\/blogs.mathworks.com\/steve\/files\/image_display_interpolation_03.png\" alt=\"\"> <p>I have placed a few datatips to show that the spatial periodicity along the path is about 4 pixel units. This is <i>very close<\/i> to the highest spatial frequency that can be represented with this pixel spacing. In other words, it is very close to what I would call <i>critically sampled<\/i>.<\/p><p>Why does this matter? Well, it means that if you shrink this image down just by using nearest-neighbor interpolation, which is the way MATLAB has always displayed images previously, you'll see some strange artifacts. Below, I'll use <tt>imshow<\/tt> to display the image at 25% magnification.<\/p><pre class=\"codeinput\">imshow(A_cropped,<span class=\"string\">'InitialMagnification'<\/span>,25)\r\n<\/pre><img decoding=\"async\" vspace=\"5\" hspace=\"5\" src=\"https:\/\/blogs.mathworks.com\/steve\/files\/image_display_interpolation_04.png\" alt=\"\"> <p>With R2019b, though, you can specify that you want an image to be displayed using bilinear interpolation. And, as explained in the documentation, when bilinear interpolation is specified, MATLAB also automatically applies an antialiasing technique.<\/p><pre class=\"codeinput\">imshow(A_cropped,<span class=\"string\">'InitialMagnification'<\/span>,25,<span class=\"string\">'Interpolation'<\/span>,<span class=\"string\">'bilinear'<\/span>)\r\n<\/pre><img decoding=\"async\" vspace=\"5\" hspace=\"5\" src=\"https:\/\/blogs.mathworks.com\/steve\/files\/image_display_interpolation_05.png\" alt=\"\"> <p>You can still see some spatial artifacts in this result, but they are significantly reduced.<\/p><p>Now let's examine the effect of specifying bilinear interpolation when you magnify an image instead of shrinking it. First, I'll crop out an even smaller piece of the original image.<\/p><pre class=\"codeinput\">B_cropped = A_cropped(50:150,115:215,:);\r\nimshow(B_cropped)\r\n<\/pre><img decoding=\"async\" vspace=\"5\" hspace=\"5\" src=\"https:\/\/blogs.mathworks.com\/steve\/files\/image_display_interpolation_06.png\" alt=\"\"> <p>Next, let's display it with 500% magnification, with and without the bilinear interpolation option.<\/p><pre class=\"codeinput\">imshow(B_cropped,<span class=\"string\">'InitialMagnification'<\/span>,500)\r\ntitle(<span class=\"string\">'500% magnification using nearest-neighbor interpolation'<\/span>)\r\n<\/pre><img decoding=\"async\" vspace=\"5\" hspace=\"5\" src=\"https:\/\/blogs.mathworks.com\/steve\/files\/image_display_interpolation_07.png\" alt=\"\"> <pre class=\"codeinput\">imshow(B_cropped,<span class=\"string\">'InitialMagnification'<\/span>,500,<span class=\"string\">'Interpolation'<\/span>,<span class=\"string\">'bilinear'<\/span>)\r\ntitle(<span class=\"string\">'500% magnification using bilinear interpolation'<\/span>)\r\n<\/pre><img decoding=\"async\" vspace=\"5\" hspace=\"5\" src=\"https:\/\/blogs.mathworks.com\/steve\/files\/image_display_interpolation_08.png\" alt=\"\"> <p>You can see the improved quality in the version using bilinear interpolation.<\/p><p>Note that the default is still nearest-neighbor interpolation. This was a choice that we discussed at some length. Ultimately, we decided to leave the default behavior unchanged, for two reasons:<\/p><div><ul><li>to avoid incompatibilities<\/li><li>for some image arrays, such as those containining segmentation labels or other kinds of categories, bilinear interpolation would not be appropriate<\/li><\/ul><\/div><p>If you already have MATLAB R2019b, give this image display option a try and let me know what you think in the comments.<\/p><script language=\"JavaScript\"> <!-- \r\n    function grabCode_4aa9838ed02f48f5ac530ea06ee26331() {\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='4aa9838ed02f48f5ac530ea06ee26331 ' + '##### ' + 'SOURCE BEGIN' + ' #####';\r\n        t2='##### ' + 'SOURCE END' + ' #####' + ' 4aa9838ed02f48f5ac530ea06ee26331';\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 2019 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_4aa9838ed02f48f5ac530ea06ee26331()\"><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; R2019b<br><\/p><\/div><!--\r\n4aa9838ed02f48f5ac530ea06ee26331 ##### SOURCE BEGIN #####\r\n%% How to display images with bilinear interpolation and antialiasing\r\n%\r\n% _Note: this blog post describes an image display feature that is new in\r\n% R2019b. You can download this release from_\r\n% https:\/\/mathworks.com\/downloads.\r\n%\r\n% This is my new favorite image:\r\n%\r\n% <<https:\/\/blogs.mathworks.com\/steve\/files\/512px-Decimal_Clock_face_by_Pierre_Daniel_Destigny_1798-1805.jpg>>\r\n%\r\n% But that's just a 512x512 version of it. Click\r\n% <https:\/\/blogs.mathworks.com\/steve\/files\/Decimal_Clock_face_by_Pierre_Daniel_Destigny_1798-1805.jpg\r\n% here> for the full resolution (2048x2048) version. _Image credit: DeFacto\r\n% [CC BY-SA 4.0 (https:\/\/creativecommons.org\/licenses\/by-sa\/4.0)]_ \r\n%\r\n% This image caught my eye because I'm always looking for a good sample\r\n% image to demonstrate _aliasing_. Also, I wanted to write a blog post\r\n% about a new MATLAB image display feature in R2019b: bilinear\r\n% interpolation and antialiasing.\r\n%\r\n% Before I get into image display details, though, let's zoom into the\r\n% center of the full-resolution image to see why it interests me.\r\n\r\nurl = 'https:\/\/blogs.mathworks.com\/steve\/files\/Decimal_Clock_face_by_Pierre_Daniel_Destigny_1798-1805.jpg';\r\nA = imread(url);\r\nA_cropped = A((-250:250) + 1024, (-250:250) + 1024, :);\r\nimshow(A_cropped)\r\n\r\n%%\r\n% Next, I want to compute a pixel profile along a path that shows the\r\n% high-frequency spatial variation. The code below shows the path in blue.\r\nhold on\r\nx = [120 80];\r\ny = [106 188];\r\nplot(x,y,'b','LineWidth',4)\r\nhold off\r\n\r\n%%\r\n% And here's the pixel profile (converted to gray-scale) along that path.\r\nclose all\r\nc = improfile(A_cropped,x,y);\r\nc = rgb2gray(squeeze(c)\/255);\r\nh = plot(c(:,1));\r\nxlabel('Distance along the profile path')\r\nylabel('Gray-scale pixel value')\r\ndatatip(h,13,0.9614);\r\ndatatip(h,25,0.9271);\r\ndatatip(h,60,0.9282);\r\ndatatip(h,72,0.9133);\r\n\r\n%%\r\n% I have placed a few datatips to show that the spatial periodicity along\r\n% the path is about 4 pixel units. This is _very close_ to the highest\r\n% spatial frequency that can be represented with this pixel spacing. In\r\n% other words, it is very close to what I would call _critically sampled_.\r\n%\r\n% Why does this matter? Well, it means that if you shrink this image down\r\n% just by using nearest-neighbor interpolation, which is the way MATLAB has\r\n% always displayed images previously, you'll see some strange artifacts.\r\n% Below, I'll use |imshow| to display the image at 25% magnification.\r\n\r\nimshow(A_cropped,'InitialMagnification',25)\r\n\r\n%%\r\n% With R2019b, though, you can specify that you want an image to be\r\n% displayed using bilinear interpolation. And, as explained in the\r\n% documentation, when bilinear interpolation is specified, MATLAB also\r\n% automatically applies an antialiasing technique.\r\n\r\nimshow(A_cropped,'InitialMagnification',25,'Interpolation','bilinear')\r\n\r\n%%\r\n% You can still see some spatial artifacts in this result, but they are\r\n% significantly reduced.\r\n%\r\n% Now let's examine the effect of specifying bilinear interpolation when\r\n% you magnify an image instead of shrinking it. First, I'll crop out an\r\n% even smaller piece of the original image.\r\n\r\nB_cropped = A_cropped(50:150,115:215,:);\r\nimshow(B_cropped)\r\n\r\n%%\r\n% Next, let's display it with 500% magnification, with and without the\r\n% bilinear interpolation option.\r\n\r\nimshow(B_cropped,'InitialMagnification',500)\r\ntitle('500% magnification using nearest-neighbor interpolation')\r\n\r\n%%\r\nimshow(B_cropped,'InitialMagnification',500,'Interpolation','bilinear')\r\ntitle('500% magnification using bilinear interpolation')\r\n\r\n%%\r\n% You can see the improved quality in the version using bilinear\r\n% interpolation.\r\n%\r\n% Note that the default is still nearest-neighbor interpolation. This was a\r\n% choice that we discussed at some length. Ultimately, we decided to leave\r\n% the default behavior unchanged, for two reasons:\r\n%\r\n% * to avoid incompatibilities\r\n% * for some image arrays, such as those containining segmentation labels\r\n% or other kinds of categories, bilinear interpolation would not be\r\n% appropriate\r\n%\r\n% If you already have MATLAB R2019b, give this image display option a try\r\n% and let me know what you think in the comments.\r\n\r\n##### SOURCE END ##### 4aa9838ed02f48f5ac530ea06ee26331\r\n-->","protected":false},"excerpt":{"rendered":"<div class=\"overview-image\"><img src=\"https:\/\/blogs.mathworks.com\/steve\/files\/image_display_interpolation_02.png\" class=\"img-responsive attachment-post-thumbnail size-post-thumbnail wp-post-image\" alt=\"\" decoding=\"async\" loading=\"lazy\" \/><\/div><p>Note: this blog post describes an image display feature that is new in R2019b. You can download this release from https:\/\/www.mathworks.com\/downloads.This is my new favorite image: But that's just a... <a class=\"read-more\" href=\"https:\/\/blogs.mathworks.com\/steve\/2019\/11\/04\/how-to-display-images-with-bilinear-interpolation-and-antialiasing\/\">read more >><\/a><\/p>","protected":false},"author":42,"featured_media":3851,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":[],"categories":[1],"tags":[278,1263,90,905,76,36,68,104,1127,52,94,96],"_links":{"self":[{"href":"https:\/\/blogs.mathworks.com\/steve\/wp-json\/wp\/v2\/posts\/3835"}],"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=3835"}],"version-history":[{"count":6,"href":"https:\/\/blogs.mathworks.com\/steve\/wp-json\/wp\/v2\/posts\/3835\/revisions"}],"predecessor-version":[{"id":5850,"href":"https:\/\/blogs.mathworks.com\/steve\/wp-json\/wp\/v2\/posts\/3835\/revisions\/5850"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/blogs.mathworks.com\/steve\/wp-json\/wp\/v2\/media\/3851"}],"wp:attachment":[{"href":"https:\/\/blogs.mathworks.com\/steve\/wp-json\/wp\/v2\/media?parent=3835"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blogs.mathworks.com\/steve\/wp-json\/wp\/v2\/categories?post=3835"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blogs.mathworks.com\/steve\/wp-json\/wp\/v2\/tags?post=3835"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}