{"id":63,"date":"2006-06-13T08:06:53","date_gmt":"2006-06-13T12:06:53","guid":{"rendered":"https:\/\/blogs.mathworks.com\/steve\/?p=63"},"modified":"2019-10-22T12:29:30","modified_gmt":"2019-10-22T16:29:30","slug":"spatial-transformations-findbounds","status":"publish","type":"post","link":"https:\/\/blogs.mathworks.com\/steve\/2006\/06\/13\/spatial-transformations-findbounds\/","title":{"rendered":"Spatial transformations: findbounds"},"content":{"rendered":"<div xmlns:mwsh=\"https:\/\/www.mathworks.com\/namespace\/mcode\/v1\/syntaxhighlight.dtd\" class=\"content\">\r\n   <p>I've written <a href=\"https:\/\/blogs.mathworks.com\/steve\/?p=55\">previously<\/a> about how Image Processing Toolbox uses inverse mapping to implement spatial transforms. In this method, you set up a grid\r\n      in output space.  For each pixel in the output space grid, you use the inverse transform to determine the corresponding input\r\n      space location, and you interpolate to get the input image pixel value at that point.\r\n   <\/p>\r\n   <p>I've <a href=\"https:\/\/blogs.mathworks.com\/steve\/?p=58\">also written<\/a> about the question of where to establish the grid in output space.  If you don't somehow pay attention to the specific transformation,\r\n      you might choose a grid that's too small:\r\n   <\/p>\r\n   <p><img decoding=\"async\" vspace=\"5\" hspace=\"5\" src=\"https:\/\/blogs.mathworks.com\/images\/steve\/58\/output_image_example_1.png\"> <\/p>\r\n   <p>Or your grid might be too big:<\/p>\r\n   <p><img decoding=\"async\" vspace=\"5\" hspace=\"5\" src=\"https:\/\/blogs.mathworks.com\/images\/steve\/58\/output_image_example_2.png\"> <\/p>\r\n   <p>Or your grid might be in the wrong place completely:<\/p>\r\n   <p><img decoding=\"async\" vspace=\"5\" hspace=\"5\" src=\"https:\/\/blogs.mathworks.com\/images\/steve\/58\/output_image_example_3.png\"> <\/p>\r\n   <p>To avoid these problems (and to avoid the tech support calls!), the function <tt>imtransform<\/tt> uses the function <tt>findbounds<\/tt> to determine automatically where to place the output grid and how big it should be.\r\n   <\/p>\r\n   <p><tt>findbounds<\/tt> first creates a grid of points.  These points are located in input space at each corner of the image, as well as in between\r\n      each corner and in the middle.  It looks like this:\r\n   <\/p><pre style=\"background: #F9F7F3; padding: 10px; border: 1px solid rgb(200,200,200)\">I = imread(<span style=\"color: #A020F0\">'rice.png'<\/span>);\r\nh = imshow(I);\r\nset(h,<span style=\"color: #A020F0\">'AlphaData'<\/span>,0.3);\r\naxis <span style=\"color: #A020F0\">on<\/span>, grid <span style=\"color: #A020F0\">on<\/span>\r\nin_points = [ <span style=\"color: #0000FF\">...<\/span>\r\n    0.5000    0.5000\r\n    0.5000  256.5000\r\n  256.5000    0.5000\r\n  256.5000  256.5000\r\n    0.5000  128.5000\r\n  128.5000    0.5000\r\n  128.5000  128.5000\r\n  128.5000  256.5000\r\n  256.5000  128.5000];\r\nhold <span style=\"color: #A020F0\">on<\/span>\r\nplot(in_points(:,1), in_points(:,2), <span style=\"color: #A020F0\">'.'<\/span>, <span style=\"color: #A020F0\">'MarkerSize'<\/span>, 18)\r\nhold <span style=\"color: #A020F0\">off<\/span><\/pre><img decoding=\"async\" vspace=\"5\" hspace=\"5\" src=\"https:\/\/blogs.mathworks.com\/images\/steve\/63\/findbounds_example_01.png\"> <p><tt>findbounds<\/tt> then calls <tt>tformfwd<\/tt> to transform these points into output space.  (For this example I'm going to construct an affine tform struct that combines\r\n      scaling, rotation, shear, and a large translation.)\r\n   <\/p><pre style=\"background: #F9F7F3; padding: 10px; border: 1px solid rgb(200,200,200)\">tform = maketform(<span style=\"color: #A020F0\">'affine'<\/span>, <span style=\"color: #0000FF\">...<\/span>\r\n    [1.1067 -0.2341 0; 0.5872 1.1769 0; 1000 -300 1]);\r\nout_points = tformfwd(tform, in_points)<\/pre><pre style=\"font-style:oblique\">\r\nout_points =\r\n\r\n  1.0e+003 *\r\n\r\n    1.0008   -0.2995\r\n    1.1512    0.0018\r\n    1.2842   -0.3595\r\n    1.4345   -0.0582\r\n    1.0760   -0.1489\r\n    1.1425   -0.3295\r\n    1.2177   -0.1789\r\n    1.2928   -0.0282\r\n    1.3593   -0.2088\r\n\r\n<\/pre><pre style=\"background: #F9F7F3; padding: 10px; border: 1px solid rgb(200,200,200)\">plot(out_points(:,1), out_points(:,2), <span style=\"color: #A020F0\">'.'<\/span>, <span style=\"color: #A020F0\">'MarkerSize'<\/span>, 18)\r\naxis <span style=\"color: #A020F0\">ij<\/span>, axis <span style=\"color: #A020F0\">image<\/span>\r\ngrid <span style=\"color: #A020F0\">on<\/span><\/pre><img decoding=\"async\" vspace=\"5\" hspace=\"5\" src=\"https:\/\/blogs.mathworks.com\/images\/steve\/63\/findbounds_example_02.png\"> <p>The bounding box of the points in output space tells us where to put the output space grid.<\/p>\r\n   <p>When you call <tt>imtransform<\/tt>, you can use optional output arguments to determine where the image is located in output space.\r\n   <\/p><pre style=\"background: #F9F7F3; padding: 10px; border: 1px solid rgb(200,200,200)\">[J,XData,YData] = imtransform(I, tform);\r\nXData<\/pre><pre style=\"font-style:oblique\">\r\nXData =\r\n\r\n  1.0e+003 *\r\n\r\n    1.0017    1.4337\r\n\r\n<\/pre><pre style=\"background: #F9F7F3; padding: 10px; border: 1px solid rgb(200,200,200)\">YData<\/pre><pre style=\"font-style:oblique\">\r\nYData =\r\n\r\n -358.7527    1.2473\r\n\r\n<\/pre><p>You can use this information together with <tt>imshow<\/tt> to place the image in the right place on an axes that contains other X-Y data.\r\n   <\/p><pre style=\"background: #F9F7F3; padding: 10px; border: 1px solid rgb(200,200,200)\">h = imshow(J,<span style=\"color: #A020F0\">'XData'<\/span>,XData,<span style=\"color: #A020F0\">'YData'<\/span>,YData);\r\nset(h,<span style=\"color: #A020F0\">'AlphaData'<\/span>,0.3)\r\nhold <span style=\"color: #A020F0\">on<\/span>\r\nplot(out_points(:,1), out_points(:,2), <span style=\"color: #A020F0\">'.'<\/span>, <span style=\"color: #A020F0\">'MarkerSize'<\/span>, 18)\r\naxis <span style=\"color: #A020F0\">on<\/span>\r\ngrid <span style=\"color: #A020F0\">on<\/span>\r\nhold <span style=\"color: #A020F0\">off<\/span>\r\naxis <span style=\"color: #A020F0\">ij<\/span>, axis <span style=\"color: #A020F0\">image<\/span><\/pre><img decoding=\"async\" vspace=\"5\" hspace=\"5\" src=\"https:\/\/blogs.mathworks.com\/images\/steve\/63\/findbounds_example_03.png\"> <p>So that's the method <tt>imtransform<\/tt> uses to determine where the output image should be in output space.\r\n   <\/p>\r\n   <p>In a future posting I'll cover two more topics related to <tt>findbounds<\/tt> and <tt>imtransform<\/tt>:\r\n   <\/p>\r\n   <div>\r\n      <ul>\r\n         <li>What to do when there's no forward transform in the tform structure<\/li>\r\n         <li>The special problem of pure translation<\/li>\r\n      <\/ul>\r\n   <\/div>\r\n<script language=\"JavaScript\"> \r\n<!--\r\n    function grabCode_63() {\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='63 ' + '##### ' + 'SOURCE BEGIN' + ' #####';\r\n        t2='##### ' + 'SOURCE END' + ' #####' + ' 63';\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_63()\"><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.2<br><\/p>\r\n<\/div>\r\n<!--\r\n63 ##### SOURCE BEGIN #####\r\n%%\r\n% I've written <https:\/\/blogs.mathworks.com\/steve\/?p=55 previously> \r\n% about how Image Processing Toolbox uses inverse\r\n% mapping to implement spatial transforms. In this method, you set up a\r\n% grid in output space.  For each pixel in the output space grid, you use\r\n% the inverse transform to determine the corresponding input space\r\n% location, and you interpolate to get the input image pixel value at that\r\n% point.\r\n%\r\n% I've <https:\/\/blogs.mathworks.com\/steve\/?p=58 also written> about the \r\n% question of where to establish the grid in\r\n% output space.  If you don't somehow pay attention to the specific\r\n% transformation, you might choose a grid that's too small:\r\n%\r\n% <<https:\/\/blogs.mathworks.com\/images\/steve\/58\/output_image_example_1.png>>\r\n%\r\n% Or your grid might be too big:\r\n%\r\n% <<https:\/\/blogs.mathworks.com\/images\/steve\/58\/output_image_example_2.png>>\r\n%\r\n% Or your grid might be in the wrong place completely:\r\n%\r\n% <<https:\/\/blogs.mathworks.com\/images\/steve\/58\/output_image_example_3.png>>\r\n%\r\n% To avoid these problems (and to avoid the tech support calls!), the\r\n% function <https:\/\/www.mathworks.com\/help\/images\/index.htmlimtransform.html \r\n% |imtransform|> uses the function \r\n% <https:\/\/www.mathworks.com\/help\/images\/index.htmlfindbounds.html \r\n% |findbounds|> to determine\r\n% automatically where to place the output grid and how big it should be.\r\n%\r\n% |findbounds| first creates a grid of points.  These points are located in\r\n% input space at each corner of the image, as well as in between each corner\r\n% and in the middle.  It looks like this:\r\n\r\nI = imread('rice.png');\r\nh = imshow(I);\r\nset(h,'AlphaData',0.3);\r\naxis on, grid on\r\nin_points = [ ...\r\n    0.5000    0.5000\r\n    0.5000  256.5000\r\n  256.5000    0.5000\r\n  256.5000  256.5000\r\n    0.5000  128.5000\r\n  128.5000    0.5000\r\n  128.5000  128.5000\r\n  128.5000  256.5000\r\n  256.5000  128.5000];\r\nhold on\r\nplot(in_points(:,1), in_points(:,2), '.', 'MarkerSize', 18)\r\nhold off\r\n\r\n%%\r\n% |findbounds| then calls |tformfwd| to transform these points into output\r\n% space.  (For this example\r\n% I'm going to construct an affine tform struct that combines scaling,\r\n% rotation, shear, and a large translation.)\r\n\r\ntform = maketform('affine', ...\r\n    [1.1067 -0.2341 0; 0.5872 1.1769 0; 1000 -300 1]);\r\nout_points = tformfwd(tform, in_points)\r\n\r\n%%\r\n\r\nplot(out_points(:,1), out_points(:,2), '.', 'MarkerSize', 18)\r\naxis ij, axis image\r\ngrid on\r\n\r\n%%\r\n% The bounding box of the points in output space tells us where to put the\r\n% output space grid.\r\n%\r\n% When you call |imtransform|, you can use optional output arguments to\r\n% determine where the image is located in output space.  \r\n\r\n[J,XData,YData] = imtransform(I, tform);\r\nXData\r\n\r\n%%\r\n\r\nYData\r\n\r\n%%\r\n% You can use this information together with |imshow| to place the image in\r\n% the right place on an axes that contains other X-Y data.\r\n\r\nh = imshow(J,'XData',XData,'YData',YData);\r\nset(h,'AlphaData',0.3)\r\nhold on\r\nplot(out_points(:,1), out_points(:,2), '.', 'MarkerSize', 18)\r\naxis on\r\ngrid on\r\nhold off\r\naxis ij, axis image\r\n\r\n%%\r\n% So that's the method |imtransform| uses to determine where the output image\r\n% should be in output space.\r\n%\r\n% In a future posting I'll cover two more topics related to |findbounds|\r\n% and |imtransform|:\r\n%\r\n% * What to do when there's no forward transform in the tform structure\r\n% * The special problem of pure translation\r\n##### SOURCE END ##### 63\r\n-->","protected":false},"excerpt":{"rendered":"<p>\r\n   I've written previously about how Image Processing Toolbox uses inverse mapping to implement spatial transforms. In this method, you set up a grid\r\n      in output space.  For each pixel in the... <a class=\"read-more\" href=\"https:\/\/blogs.mathworks.com\/steve\/2006\/06\/13\/spatial-transformations-findbounds\/\">read more >><\/a><\/p>","protected":false},"author":42,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":[],"categories":[10],"tags":[50,42,70,76,36,44,62,68,64],"_links":{"self":[{"href":"https:\/\/blogs.mathworks.com\/steve\/wp-json\/wp\/v2\/posts\/63"}],"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=63"}],"version-history":[{"count":1,"href":"https:\/\/blogs.mathworks.com\/steve\/wp-json\/wp\/v2\/posts\/63\/revisions"}],"predecessor-version":[{"id":2189,"href":"https:\/\/blogs.mathworks.com\/steve\/wp-json\/wp\/v2\/posts\/63\/revisions\/2189"}],"wp:attachment":[{"href":"https:\/\/blogs.mathworks.com\/steve\/wp-json\/wp\/v2\/media?parent=63"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blogs.mathworks.com\/steve\/wp-json\/wp\/v2\/categories?post=63"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blogs.mathworks.com\/steve\/wp-json\/wp\/v2\/tags?post=63"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}