{"id":38,"date":"2006-02-28T07:00:49","date_gmt":"2006-02-28T12:00:49","guid":{"rendered":"https:\/\/blogs.mathworks.com\/steve\/?p=38"},"modified":"2019-10-21T17:47:21","modified_gmt":"2019-10-21T21:47:21","slug":"spatial-transformations-where-is-the-input-image","status":"publish","type":"post","link":"https:\/\/blogs.mathworks.com\/steve\/2006\/02\/28\/spatial-transformations-where-is-the-input-image\/","title":{"rendered":"Spatial transformations: Where is the input image?"},"content":{"rendered":"<div xmlns:mwsh=\"https:\/\/www.mathworks.com\/namespace\/mcode\/v1\/syntaxhighlight.dtd\" class=\"content\">\r\n   <introduction>\r\n      <p>We've talked about using Image Processing Toolbox functions to define an affine transformation and apply it to points.  Let's\r\n         begin to explore transforming images.\r\n      <\/p>\r\n      <p>First we have to answer a question that is often overlooked:  Where is the input image?  In other words, the input u-v space\r\n         is a plane.  Where does the image lie on the plane?\r\n      <\/p>\r\n   <\/introduction>\r\n   <h3>Contents<\/h3>\r\n   <div>\r\n      <ul>\r\n         <li><a href=\"#1\">Image location in the plane<\/a><\/li>\r\n         <li><a href=\"#2\">Rotation<\/a><\/li>\r\n         <li><a href=\"#3\">Scaling<\/a><\/li>\r\n      <\/ul>\r\n   <\/div>\r\n   <h3>Image location in the plane<a name=\"1\"><\/a><\/h3>\r\n   <p>With the default spatial coordinates for images in MATLAB, the center of the upper-left image pixel is at (1, 1).  Each pixel\r\n      is a square with unit area, so the corner of the upper-left image pixel is at (0.5, 0.5). A 4-by-4 image looks like this on\r\n      the plane:\r\n   <\/p><pre style=\"background: #F9F7F3; padding: 10px; border: 1px solid rgb(200,200,200)\">pixel_centers_x = [1 4 4 1 1];\r\npixel_centers_y = [1 1 4 4 1];\r\npixel_edges_x   = [0.5 4.5 4.5 0.5 0.5];\r\npixel_edges_y   = [0.5 0.5 4.5 4.5 0.5];\r\n\r\nplot(pixel_centers_x, pixel_centers_y);\r\nhold <span style=\"color: #A020F0\">on<\/span>\r\nplot(pixel_edges_x, pixel_edges_y, <span style=\"color: #A020F0\">':'<\/span>)\r\n\r\n<span style=\"color: #228B22\">% Plot axes lines<\/span>\r\nc = [.7 .7 .7];\r\nplot([-50 50], [0 0], <span style=\"color: #A020F0\">'color'<\/span>, c);\r\nplot([0 0], [-50 50], <span style=\"color: #A020F0\">'color'<\/span>, c);\r\n\r\naxis <span style=\"color: #A020F0\">ij<\/span>, axis <span style=\"color: #A020F0\">equal<\/span>\r\naxis([-5 5 -5 5]);\r\n\r\nlegend({<span style=\"color: #A020F0\">'Pixel centers'<\/span>, <span style=\"color: #A020F0\">'Pixel edges'<\/span>})\r\ntitle(<span style=\"color: #A020F0\">'Default image bounding rectangle location'<\/span>)\r\nxlabel(<span style=\"color: #A020F0\">'u'<\/span>)\r\nylabel(<span style=\"color: #A020F0\">'v'<\/span>)\r\nhold <span style=\"color: #A020F0\">off<\/span><\/pre><img decoding=\"async\" vspace=\"5\" hspace=\"5\" src=\"https:\/\/blogs.mathworks.com\/images\/steve\/38\/where_input_01.png\"> <h3>Rotation<a name=\"2\"><\/a><\/h3>\r\n   <p>A \"pure\" affine rotation rotates about the origin.  This means it can move an image into a completely different quadrant from\r\n      where it started.\r\n   <\/p><pre style=\"background: #F9F7F3; padding: 10px; border: 1px solid rgb(200,200,200)\">theta = 3*pi\/4;\r\nA1 = [ cos(theta)  sin(theta)  0\r\n      -sin(theta)  cos(theta)  0\r\n       0           0           1];\r\n\r\ntform1 = maketform(<span style=\"color: #A020F0\">'affine'<\/span>, A1);\r\n\r\n[pixel_centers_x1, pixel_centers_y1] = tformfwd(tform1, <span style=\"color: #0000FF\">...<\/span>\r\n   pixel_centers_x, pixel_centers_y);\r\n[pixel_edges_x1, pixel_edges_y1] = tformfwd(tform1, <span style=\"color: #0000FF\">...<\/span>\r\n   pixel_edges_x, pixel_edges_y);\r\n\r\nplot(pixel_centers_x1, pixel_centers_y1);\r\nhold <span style=\"color: #A020F0\">on<\/span>\r\nplot(pixel_edges_x1, pixel_edges_y1, <span style=\"color: #A020F0\">':'<\/span>)\r\n\r\n<span style=\"color: #228B22\">% Plot axes lines<\/span>\r\nc = [.7 .7 .7];\r\nplot([-50 50], [0 0], <span style=\"color: #A020F0\">'color'<\/span>, c);\r\nplot([0 0], [-50 50], <span style=\"color: #A020F0\">'color'<\/span>, c);\r\n\r\naxis <span style=\"color: #A020F0\">ij<\/span>, axis <span style=\"color: #A020F0\">equal<\/span>\r\naxis([-5 5 -5 5]);\r\n\r\nlegend({<span style=\"color: #A020F0\">'Pixel centers'<\/span>, <span style=\"color: #A020F0\">'Pixel edges'<\/span>})\r\ntitle(<span style=\"color: #A020F0\">'Rotated image'<\/span>)\r\nxlabel(<span style=\"color: #A020F0\">'x'<\/span>)\r\nylabel(<span style=\"color: #A020F0\">'y'<\/span>)\r\nhold <span style=\"color: #A020F0\">off<\/span><\/pre><img decoding=\"async\" vspace=\"5\" hspace=\"5\" src=\"https:\/\/blogs.mathworks.com\/images\/steve\/38\/where_input_02.png\"> <h3>Scaling<a name=\"3\"><\/a><\/h3>\r\n   <p>A \"pure\" affine scaling also operates with respect to the origin.  Since the image corner isn't exactly at the origin (by\r\n      default), scaling with a scale factor greater than 1 not only increases the size of the pixels, but it also moves the corner\r\n      of the image away from the origin.\r\n   <\/p><pre style=\"background: #F9F7F3; padding: 10px; border: 1px solid rgb(200,200,200)\">A2 = [ 3  0  0\r\n       0  3  0\r\n       0  0  1];\r\n\r\ntform2 = maketform(<span style=\"color: #A020F0\">'affine'<\/span>, A2);\r\n\r\n[pixel_centers_x2, pixel_centers_y2] = tformfwd(tform2, <span style=\"color: #0000FF\">...<\/span>\r\n   pixel_centers_x, pixel_centers_y);\r\n[pixel_edges_x2, pixel_edges_y2] = tformfwd(tform2, <span style=\"color: #0000FF\">...<\/span>\r\n   pixel_edges_x, pixel_edges_y);\r\n\r\nplot(pixel_centers_x2, pixel_centers_y2);\r\nhold <span style=\"color: #A020F0\">on<\/span>\r\nplot(pixel_edges_x2, pixel_edges_y2, <span style=\"color: #A020F0\">':'<\/span>)\r\n\r\n<span style=\"color: #228B22\">% Plot axes lines<\/span>\r\nc = [.7 .7 .7];\r\nplot([-50 50], [0 0], <span style=\"color: #A020F0\">'color'<\/span>, c);\r\nplot([0 0], [-50 50], <span style=\"color: #A020F0\">'color'<\/span>, c);\r\n\r\naxis <span style=\"color: #A020F0\">ij<\/span>, axis <span style=\"color: #A020F0\">equal<\/span>\r\naxis([-5 5 -5 5]);\r\n\r\nlegend({<span style=\"color: #A020F0\">'Pixel centers'<\/span>, <span style=\"color: #A020F0\">'Pixel edges'<\/span>})\r\ntitle(<span style=\"color: #A020F0\">'Scaled image'<\/span>)\r\nxlabel(<span style=\"color: #A020F0\">'x'<\/span>)\r\nylabel(<span style=\"color: #A020F0\">'y'<\/span>)\r\nhold <span style=\"color: #A020F0\">off<\/span><\/pre><img decoding=\"async\" vspace=\"5\" hspace=\"5\" src=\"https:\/\/blogs.mathworks.com\/images\/steve\/38\/where_input_03.png\"> <p>The center of the upper-left pixel is now at (3, 3), and the corner of the upper-left pixel is now at (1.5, 1.5).<\/p>\r\n   <p>When I discuss <tt>imtransform<\/tt>, I'll explain how it automatically takes care of these details so that most users don't have to worry about it. But if you\r\n      want to understand how things work, or if <tt>imtransform<\/tt>'s automatic procedure doesn't do exactly what you need, then you need to understand this information.\r\n   <\/p>\r\n <script language=\"JavaScript\"> \r\n<!--\r\n    function grabCode_38() {\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='38 ' + '##### ' + 'SOURCE BEGIN' + ' #####';\r\n        t2='##### ' + 'SOURCE END' + ' #####' + ' 38';\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        author = 'Steve Eddins';\r\n        copyright = 'Copyright 2006 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 author and copyright lines at the bottom if specified.\r\n        if ((author.length > 0) || (copyright.length > 0)) {\r\n            d.writeln('');\r\n            d.writeln('%%');\r\n            if (author.length > 0) {\r\n                d.writeln('% _' + author + '_');\r\n            }\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-->\r\n      <\/script>\r\n<noscript>\r\n<em>A JavaScript-enabled browser is required to use the \"Get the MATLAB code\" link.<\/em>\r\n<\/noscript>\r\n<p style=\"text-align: right; font-size: xx-small; font-weight:lighter;   font-style: italic; color: gray\"><br><a href=\"javascript:grabCode_38()\"><span style=\"font-size: x-small;        font-style: italic;\">Get \r\n            the MATLAB code<\/span><\/a><br><br>\r\n      Published with MATLAB&reg; 7.1<br><\/p>\r\n<\/div>\r\n<!--\r\n38 ##### SOURCE BEGIN #####\r\n%%\r\n% We've talked about using Image Processing Toolbox functions to define an\r\n% affine transformation and apply it to points.  Let's begin to explore\r\n% transforming images.\r\n%\r\n% First we have to answer a question that is often overlooked:  Where is\r\n% the input image?  In other words, the input u-v space is a plane.  Where\r\n% does the image lie on the plane?\r\n\r\n%% Image location in the plane\r\n% With the default spatial coordinates for images in MATLAB, the center of\r\n% the upper-left image pixel is at (1, 1).  Each pixel is a square with\r\n% unit area, so the corner of the upper-left image pixel is at (0.5, 0.5).\r\n% A 4-by-4 image looks like this on the plane:\r\n\r\npixel_centers_x = [1 4 4 1 1];\r\npixel_centers_y = [1 1 4 4 1];\r\npixel_edges_x   = [0.5 4.5 4.5 0.5 0.5];\r\npixel_edges_y   = [0.5 0.5 4.5 4.5 0.5];\r\n\r\nplot(pixel_centers_x, pixel_centers_y);\r\nhold on\r\nplot(pixel_edges_x, pixel_edges_y, ':')\r\n\r\n% Plot axes lines\r\nc = [.7 .7 .7];\r\nplot([-50 50], [0 0], 'color', c);\r\nplot([0 0], [-50 50], 'color', c);\r\n\r\naxis ij, axis equal\r\naxis([-5 5 -5 5]);\r\n\r\nlegend({'Pixel centers', 'Pixel edges'})\r\ntitle('Default image bounding rectangle location')\r\nxlabel('u')\r\nylabel('v')\r\nhold off\r\n\r\n%% Rotation\r\n% A \"pure\" affine rotation rotates about the origin.  This means it can\r\n% move an image into a completely different quadrant from where it started.\r\n\r\ntheta = 3*pi\/4;\r\nA1 = [ cos(theta)  sin(theta)  0\r\n      -sin(theta)  cos(theta)  0\r\n       0           0           1];\r\n\r\ntform1 = maketform('affine', A1);\r\n\r\n[pixel_centers_x1, pixel_centers_y1] = tformfwd(tform1, ...\r\n   pixel_centers_x, pixel_centers_y);\r\n[pixel_edges_x1, pixel_edges_y1] = tformfwd(tform1, ...\r\n   pixel_edges_x, pixel_edges_y);\r\n\r\nplot(pixel_centers_x1, pixel_centers_y1);\r\nhold on\r\nplot(pixel_edges_x1, pixel_edges_y1, ':')\r\n\r\n% Plot axes lines\r\nc = [.7 .7 .7];\r\nplot([-50 50], [0 0], 'color', c);\r\nplot([0 0], [-50 50], 'color', c);\r\n\r\naxis ij, axis equal\r\naxis([-5 5 -5 5]);\r\n\r\nlegend({'Pixel centers', 'Pixel edges'})\r\ntitle('Rotated image')\r\nxlabel('x')\r\nylabel('y')\r\nhold off\r\n\r\n%% Scaling\r\n% A \"pure\" affine scaling also operates with respect to the origin.  Since\r\n% the image corner isn't exactly at the origin (by default), scaling with a\r\n% scale factor greater than 1 not only increases the size of the pixels,\r\n% but it also moves the corner of the image away from the origin.\r\n\r\nA2 = [ 3  0  0\r\n       0  3  0\r\n       0  0  1];\r\n\r\ntform2 = maketform('affine', A2);\r\n\r\n[pixel_centers_x2, pixel_centers_y2] = tformfwd(tform2, ...\r\n   pixel_centers_x, pixel_centers_y);\r\n[pixel_edges_x2, pixel_edges_y2] = tformfwd(tform2, ...\r\n   pixel_edges_x, pixel_edges_y);\r\n\r\nplot(pixel_centers_x2, pixel_centers_y2);\r\nhold on\r\nplot(pixel_edges_x2, pixel_edges_y2, ':')\r\n\r\n% Plot axes lines\r\nc = [.7 .7 .7];\r\nplot([-50 50], [0 0], 'color', c);\r\nplot([0 0], [-50 50], 'color', c);\r\n\r\naxis ij, axis equal\r\naxis([-5 5 -5 5]);\r\n\r\nlegend({'Pixel centers', 'Pixel edges'})\r\ntitle('Scaled image')\r\nxlabel('x')\r\nylabel('y')\r\nhold off\r\n\r\n%%\r\n% The center of the upper-left pixel is now at (3, 3), and the corner of\r\n% the upper-left pixel is now at (1.5, 1.5).\r\n%\r\n% When I discuss |imtransform|, I'll explain how it automatically takes\r\n% care of these details so that most users don't have to worry about it.\r\n% But if you want to understand how things work, or if |imtransform|'s \r\n% automatic procedure doesn't do exactly what you need, then you need to \r\n% understand this information.\r\n\r\n\r\n##### SOURCE END ##### 38\r\n-->","protected":false},"excerpt":{"rendered":"<p>\r\n   \r\n      We've talked about using Image Processing Toolbox functions to define an affine transformation and apply it to points.  Let's\r\n         begin to explore transforming images.\r\n      \r\n ... <a class=\"read-more\" href=\"https:\/\/blogs.mathworks.com\/steve\/2006\/02\/28\/spatial-transformations-where-is-the-input-image\/\">read more >><\/a><\/p>","protected":false},"author":42,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":[],"categories":[10],"tags":[50,74,90,92,62,68,34,64,52,94,96],"_links":{"self":[{"href":"https:\/\/blogs.mathworks.com\/steve\/wp-json\/wp\/v2\/posts\/38"}],"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=38"}],"version-history":[{"count":1,"href":"https:\/\/blogs.mathworks.com\/steve\/wp-json\/wp\/v2\/posts\/38\/revisions"}],"predecessor-version":[{"id":3492,"href":"https:\/\/blogs.mathworks.com\/steve\/wp-json\/wp\/v2\/posts\/38\/revisions\/3492"}],"wp:attachment":[{"href":"https:\/\/blogs.mathworks.com\/steve\/wp-json\/wp\/v2\/media?parent=38"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blogs.mathworks.com\/steve\/wp-json\/wp\/v2\/categories?post=38"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blogs.mathworks.com\/steve\/wp-json\/wp\/v2\/tags?post=38"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}