{"id":1471,"date":"2015-10-20T14:38:06","date_gmt":"2015-10-20T18:38:06","guid":{"rendered":"https:\/\/blogs.mathworks.com\/steve\/?p=1471"},"modified":"2019-11-01T12:12:35","modified_gmt":"2019-11-01T16:12:35","slug":"image-resizing-geometry","status":"publish","type":"post","link":"https:\/\/blogs.mathworks.com\/steve\/2015\/10\/20\/image-resizing-geometry\/","title":{"rendered":"Image resizing geometry"},"content":{"rendered":"<div class=\"content\"><p>This question landed in my inbox recently:<\/p><p><i>I have a 721x1441 matrix, <tt>T<\/tt>, of temperature values. The x-axis goes from 0 to 360 degrees in steps of 0.25 degrees. The y-axis goes from -90 to 90 degrees, also in steps of 0.25 degrees.<\/i><\/p><p><i>If I call <tt>imresize(T,0.25)<\/tt> to shrink the image by a factor of 4, what is the geometry of the result in terms of degrees? Is it 0:360 along the x-axis and -90:90 along the y-axis?<\/i><\/p><p>This is a really good question that I would be worth exploring in a blog post. I've personally wrestled enough with image resizing over years to know that there's more than one way to precisely interpret the phrase \"shrink by a factor of 4.\" So let me show you exactly what's happening with <tt>imresize<\/tt>.<\/p><p>Suppose you have an 8-by-8 image, and you want to shrink it by a factor of 4. I think that most people would expect the output image to be 2-by-2. And that's what <tt>imresize<\/tt> produces. The diagram below illustrates the mapping between a region in the input image and the corresponding region in the output image. The 4-pixel by 4-pixel outlined square region on the left geometrically maps exactly to the 1-pixel by 1-pixel square region on the right.<\/p><p><img decoding=\"async\" vspace=\"5\" hspace=\"5\" src=\"https:\/\/blogs.mathworks.com\/steve\/files\/8x8-to-2x2.jpg\" alt=\"\"> <\/p><p>Let's get more specific about the coordinate mapping by looking at just one dimension. I'll use the symbol $u$ to represent the input-space coordinate and $x$ to represent the output-space coordinate. Here's what the geometrical mapping looks like when shrinking by a factor of 4:<\/p><p><img decoding=\"async\" vspace=\"5\" hspace=\"5\" src=\"https:\/\/blogs.mathworks.com\/steve\/files\/shrink-by-4-geometry.jpg\" alt=\"\"> <\/p><p>In the diagram above, we can see that $x=0.5$ maps to $u=0.5$ and $x=1.5$ maps to $u=4.5$.<\/p><p>For a general scale factor $s$, here's the equation:<\/p><p>$$u = \\frac{x}{s} + \\frac{1}{2}\\left(1 - \\frac{1}{s}\\right)$$<\/p><p>This equation appears directly in the code. Look for this line in imresize.m<\/p><pre>u = x\/scale + 0.5 * (1 - 1\/scale);<\/pre><p>The output of <tt>imresize(T,0.25)<\/tt> is 181-by-361, so it has 361 columns. So, in ordinary pixel coordinates, we have an x-axis with values 1:361. How do those values correspond to degrees?<\/p><p>To answer that question, first convert from output-space coordinates to input-space coordinates.<\/p><pre class=\"codeinput\">x = 1:361;\r\nscale = 0.25;\r\nu = x\/scale + 0.5*(1 - 1\/scale);\r\n<\/pre><p>Look at the first few and last few values of <tt>u<\/tt>.<\/p><pre class=\"codeinput\">u(1:5)\r\n<\/pre><pre class=\"codeoutput\">\r\nans =\r\n\r\n    2.5000    6.5000   10.5000   14.5000   18.5000\r\n\r\n<\/pre><pre class=\"codeinput\">u(end-4:end)\r\n<\/pre><pre class=\"codeoutput\">\r\nans =\r\n\r\n   1.0e+03 *\r\n\r\n    1.4265    1.4305    1.4345    1.4385    1.4425\r\n\r\n<\/pre><p>We know that $u=1$ maps to 0 degrees and $u=1441$ maps to 360 degrees. The equation for that mapping is $d_u = (u-1)\/4$. That gives us the degree values for each column of the output image:<\/p><pre class=\"codeinput\">d_u = (u-1)\/4;\r\n<\/pre><pre class=\"codeinput\">d_u(1:5)\r\n<\/pre><pre class=\"codeoutput\">\r\nans =\r\n\r\n    0.3750    1.3750    2.3750    3.3750    4.3750\r\n\r\n<\/pre><pre class=\"codeinput\">d_u(end-4:end)\r\n<\/pre><pre class=\"codeoutput\">\r\nans =\r\n\r\n  356.3750  357.3750  358.3750  359.3750  360.3750\r\n\r\n<\/pre><p>Now let's repeat the process for the vertical coordinates. I'll use $y$ as the vertical output-space symbol and $v$ as the vertical input-space symbol. The mapping from $v$ to degrees is $d_v = v\/4 - 90.25$.<\/p><pre class=\"codeinput\">y = 1:181;\r\nv = y\/scale + 0.5*(1 - 1\/scale);\r\nd_v = v\/4 - 90.25;\r\n<\/pre><pre class=\"codeinput\">d_v(1:5)\r\n<\/pre><pre class=\"codeoutput\">\r\nans =\r\n\r\n  -89.6250  -88.6250  -87.6250  -86.6250  -85.6250\r\n\r\n<\/pre><pre class=\"codeinput\">d_v(end-4:end)\r\n<\/pre><pre class=\"codeoutput\">\r\nans =\r\n\r\n   86.3750   87.3750   88.3750   89.3750   90.3750\r\n\r\n<\/pre><p>So the answer to the original question is: _Each pixel is one degree wide, and the upper left pixel is centered at (0.375 degrees, -89.625 degrees).<\/p><p>You can use the <tt>'XData'<\/tt> and <tt>'YData'<\/tt> parameters when you call <tt>imshow<\/tt> to incorporate this information. I'll illustrate with a 181-by-361 image of random values.<\/p><pre class=\"codeinput\">I = rand(181,361);\r\nimshow(I,<span class=\"string\">'XData'<\/span>,d_u([1 end]),<span class=\"string\">'YData'<\/span>,d_v([1 end]),<span class=\"keyword\">...<\/span>\r\n   <span class=\"string\">'InitialMagnification'<\/span>,<span class=\"string\">'fit'<\/span>)\r\naxis <span class=\"string\">on<\/span>\r\nax = gca;\r\nax.XTick = d_u(1:10:end);\r\nax.YTick = d_v(1:10:end);\r\naxis([0 24.5 -90 -78.5])\r\n<\/pre><img decoding=\"async\" vspace=\"5\" hspace=\"5\" src=\"https:\/\/blogs.mathworks.com\/steve\/files\/imresize_geometry_01.png\" alt=\"\"> <p>I have suggested to the development team that they make this kind of computation easier in the future, possibly by using the spatial referencing objects that have recently been introduced in the Image Processing Toolbox.<\/p><script language=\"JavaScript\"> <!-- \r\n    function grabCode_ee331bde900e4ba89f440f0c55438435() {\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='ee331bde900e4ba89f440f0c55438435 ' + '##### ' + 'SOURCE BEGIN' + ' #####';\r\n        t2='##### ' + 'SOURCE END' + ' #####' + ' ee331bde900e4ba89f440f0c55438435';\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 2015 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_ee331bde900e4ba89f440f0c55438435()\"><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; R2015b<br><\/p><\/div><!--\r\nee331bde900e4ba89f440f0c55438435 ##### SOURCE BEGIN #####\r\n%%\r\n% This question landed in my inbox recently:\r\n%\r\n% _I have a 721x1441 matrix, |T|, of temperature values. The x-axis\r\n% goes from 0 to 360 degrees in steps of 0.25 degrees. The y-axis\r\n% goes from -90 to 90 degrees, also in steps of 0.25 degrees._\r\n%\r\n% _If I call |imresize(T,0.25)| to shrink the image by a factor of\r\n% 4, what is the geometry of the result in terms of degrees? Is it\r\n% 0:360 along the x-axis and -90:90 along the y-axis?_\r\n%\r\n% This is a really good question that I would be worth exploring in\r\n% a blog post. I've personally wrestled enough with image resizing\r\n% over years to know that there's more than one way to precisely\r\n% interpret the phrase \"shrink by a factor of 4.\" So let me show you\r\n% exactly what's happening with |imresize|.\r\n%\r\n% Suppose you have an 8-by-8 image, and you want to shrink it by a\r\n% factor of 4. I think that most people would expect the output\r\n% image to be 2-by-2. And that's what |imresize| produces. The\r\n% diagram below illustrates the mapping between a region in the\r\n% input image and the corresponding region in the output image. The\r\n% 4-pixel by 4-pixel outlined square region on the left\r\n% geometrically maps exactly to the 1-pixel by 1-pixel square region\r\n% on the right.\r\n%\r\n% <<https:\/\/blogs.mathworks.com\/steve\/files\/8x8-to-2x2.jpg>>\r\n%\r\n% Let's get more specific about the coordinate mapping by looking at\r\n% just one dimension. I'll use the symbol $u$ to represent the\r\n% input-space coordinate and $x$ to represent the output-space\r\n% coordinate. Here's what the geometrical mapping looks like when\r\n% shrinking by a factor of 4:\r\n%\r\n% <<https:\/\/blogs.mathworks.com\/steve\/files\/shrink-by-4-geometry.jpg>>\r\n%\r\n% In the diagram above, we can see that $x=0.5$ maps to $u=0.5$ and\r\n% $x=1.5$ maps to $u=4.5$.\r\n%\r\n% For a general scale factor $s$, here's the equation:\r\n%\r\n% $$u = \\frac{x}{s} + \\frac{1}{2}\\left(1 - \\frac{1}{s}\\right)$$\r\n%\r\n% This equation appears directly in the code. Look for this line in\r\n% imresize.m\r\n%\r\n%  u = x\/scale + 0.5 * (1 - 1\/scale);\r\n%\r\n% The output of |imresize(T,0.25)| is 181-by-361, so it has 361\r\n% columns. So, in ordinary pixel coordinates, we have an x-axis with\r\n% values 1:361. How do those values correspond to degrees?\r\n%\r\n% To answer that question, first convert from output-space\r\n% coordinates to input-space coordinates.\r\n\r\nx = 1:361;\r\nscale = 0.25;\r\nu = x\/scale + 0.5*(1 - 1\/scale);\r\n\r\n%%\r\n% Look at the first few and last few values of |u|.\r\nu(1:5)\r\n\r\n%%\r\nu(end-4:end)\r\n\r\n%%\r\n% We know that $u=1$ maps to 0 degrees and $u=1441$ maps to 360\r\n% degrees. The equation for that mapping is $d_u = (u-1)\/4$. That gives\r\n% us the degree values for each column of the output image:\r\n\r\nd_u = (u-1)\/4;\r\n\r\n%%\r\nd_u(1:5)\r\n\r\n%%\r\nd_u(end-4:end)\r\n\r\n%%\r\n% Now let's repeat the process for the vertical coordinates. I'll\r\n% use $y$ as the vertical output-space symbol and $v$ as the\r\n% vertical input-space symbol. The mapping from $v$ to degrees is\r\n% $d_v = v\/4 - 90.25$.\r\n\r\ny = 1:181;\r\nv = y\/scale + 0.5*(1 - 1\/scale);\r\nd_v = v\/4 - 90.25;\r\n\r\n%%\r\nd_v(1:5)\r\n\r\n%%\r\nd_v(end-4:end)\r\n\r\n%%\r\n% So the answer to the original question is: _Each pixel is one\r\n% degree wide, and the upper left pixel is centered at (0.375\r\n% degrees, -89.625 degrees).\r\n\r\n%%\r\n% You can use the |'XData'| and |'YData'| parameters when you call\r\n% |imshow| to incorporate this information. I'll illustrate with a\r\n% 181-by-361 image of random values.\r\n\r\nI = rand(181,361);\r\nimshow(I,'XData',d_u([1 end]),'YData',d_v([1 end]),...\r\n   'InitialMagnification','fit')\r\naxis on\r\nax = gca;\r\nax.XTick = d_u(1:10:end);\r\nax.YTick = d_v(1:10:end);\r\naxis([0 24.5 -90 -78.5])\r\n\r\n%%\r\n% I have suggested to the development team that they make this kind\r\n% of computation easier in the future, possibly by using the spatial\r\n% referencing objects that have recently been introduced in the\r\n% Image Processing Toolbox.\r\n##### SOURCE END ##### ee331bde900e4ba89f440f0c55438435\r\n-->","protected":false},"excerpt":{"rendered":"<div class=\"overview-image\"><img src=\"https:\/\/blogs.mathworks.com\/steve\/files\/shrink-by-4-geometry.jpg\" class=\"img-responsive attachment-post-thumbnail size-post-thumbnail wp-post-image\" alt=\"\" decoding=\"async\" loading=\"lazy\" \/><\/div><p>This question landed in my inbox recently:I have a 721x1441 matrix, T, of temperature values. The x-axis goes from 0 to 360 degrees in steps of 0.25 degrees. The y-axis goes from -90 to 90 degrees,... <a class=\"read-more\" href=\"https:\/\/blogs.mathworks.com\/steve\/2015\/10\/20\/image-resizing-geometry\/\">read more >><\/a><\/p>","protected":false},"author":42,"featured_media":1470,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":[],"categories":[1],"tags":[50,80,156,36,460],"_links":{"self":[{"href":"https:\/\/blogs.mathworks.com\/steve\/wp-json\/wp\/v2\/posts\/1471"}],"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=1471"}],"version-history":[{"count":1,"href":"https:\/\/blogs.mathworks.com\/steve\/wp-json\/wp\/v2\/posts\/1471\/revisions"}],"predecessor-version":[{"id":1472,"href":"https:\/\/blogs.mathworks.com\/steve\/wp-json\/wp\/v2\/posts\/1471\/revisions\/1472"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/blogs.mathworks.com\/steve\/wp-json\/wp\/v2\/media\/1470"}],"wp:attachment":[{"href":"https:\/\/blogs.mathworks.com\/steve\/wp-json\/wp\/v2\/media?parent=1471"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blogs.mathworks.com\/steve\/wp-json\/wp\/v2\/categories?post=1471"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blogs.mathworks.com\/steve\/wp-json\/wp\/v2\/tags?post=1471"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}