contrib/mul/vimt/vimt_rotate.h
Go to the documentation of this file.
00001 // This is mul/vimt/vimt_rotate.h
00002 #ifndef vimt_rotate_h_
00003 #define vimt_rotate_h_
00004 //:
00005 // \file
00006 // \brief Rotate an image, using the resampling functions
00007 // \author Tim Cootes
00008 //
00009 // A front end to the resampling functions that allows
00010 // an image to be rotated by any angle theta
00011 
00012 #include <vimt/vimt_image_2d_of.h>
00013 #include <vil/vil_resample_bilin.h>
00014 #include <vnl/vnl_math.h>
00015 #include <vcl_cmath.h> // for vcl_fmod()
00016 #include <vcl_cassert.h>
00017 
00018 //: Calculate theta in range 0 to x
00019 inline double calc_theta_mod(double theta, double x)
00020 {
00021   if (x<0) x=-x;
00022   double theta_x = vcl_fmod(theta,x);
00023   if (theta_x<0)
00024     theta_x += x;
00025   return theta_x;
00026 }
00027 
00028 //: Rotate image by angle theta
00029 // On exit, dest is sized to completely include rotated source.
00030 // Its world2im() transformation includes that of the src and
00031 // the rotation (ie world frame is preserved).
00032 // Note that this currently assumes square pixels.
00033 // So dest_image.world2im()=rotation*src_image.world2im()
00034 //  \relatesalso vil_image_view
00035 template <class sType, class dType>
00036 inline void vimt_rotate(const vimt_image_2d_of<sType>& src_image,
00037                         vimt_image_2d_of<dType>& dest_image,
00038                         double theta_deg)
00039 {
00040   if (theta_deg==0.0)
00041   {
00042     dest_image=src_image;
00043     return;
00044   }
00045 
00046   // nb if theta = 0, 90, 180 or 270 should employ a simpler + faster method
00047   // of rotating the image!  But at least, in those cases, d[xy][12] are 0 or 1.
00048 
00049   double theta_90= calc_theta_mod( theta_deg, 90.0 );
00050   double theta_360= calc_theta_mod( theta_deg, 360.0 );
00051 
00052   // calculate dimensions of rotated image
00053   // a---b
00054   // |   |
00055   // c---d
00056   int src_ni = src_image.image().ni();
00057   int src_nj = src_image.image().nj();
00058   double c= vcl_cos(theta_90*vnl_math::pi_over_180);
00059   double s= vcl_sin(theta_90*vnl_math::pi_over_180);
00060 
00061   // calc corners of grid to sample (in original image frame)
00062   double ai= -src_nj*s*c;
00063   double aj=  src_nj*s*s;
00064   double bi=  src_ni*c*c;
00065   double bj= -src_ni*s*c;
00066   double ci=  src_ni*s*s;
00067   double cj=  src_nj-bj;
00068   double di=  src_ni-ai;
00069   double dj=  src_nj*c*c;
00070 
00071   // size of destination image
00072   int l1= int( src_nj*s+ src_ni*c );
00073   int l2= int( src_nj*c+ src_ni*s );
00074 
00075   // set up directions for sampling src image
00076   // nb varies every 90 degrees ( ie different corner at top of image!)
00077   double dx1, dy1, dx2, dy2, x0, y0;
00078   int n1,n2;
00079 
00080   assert(theta_360>= 0.0 && theta_360 < 360.0);
00081 
00082   if ( theta_360< 90.0 )
00083   {
00084     dx1= (bi-ai)/l1;
00085     dy1= (bj-aj)/l1;
00086     dx2= (ci-ai)/l2;
00087     dy2= (cj-aj)/l2;
00088     x0 = ai;
00089     y0 = aj;
00090     n1 = l1;
00091     n2 = l2;
00092   }
00093   else if (theta_360< 180.0 )
00094   {
00095     dx1= (ai-ci)/l2;
00096     dy1= (aj-cj)/l2;
00097     dx2= (di-ci)/l1;
00098     dy2= (dj-cj)/l1;
00099     x0 = ci;
00100     y0 = cj;
00101     n1 = l2;
00102     n2 = l1;
00103   }
00104   else if (theta_360< 270.0 )
00105   {
00106     dx1= (ci-di)/l1;
00107     dy1= (cj-dj)/l1;
00108     dx2= (bi-di)/l2;
00109     dy2= (bj-dj)/l2;
00110     x0 = di;
00111     y0 = dj;
00112     n1 = l1;
00113     n2 = l2;
00114   }
00115   else // if (theta_360< 360.0 )
00116   {
00117     dx1= (di-bi)/l2;
00118     dy1= (dj-bj)/l2;
00119     dx2= (ai-bi)/l1;
00120     dy2= (aj-bj)/l1;
00121     x0 = bi;
00122     y0 = bj;
00123     n1 = l2;
00124     n2 = l1;
00125   }
00126 
00127   vil_resample_bilin(src_image.image(), dest_image.image(),
00128                      x0, y0, dx1, dy1, dx2, dy2, n1, n2 );
00129 
00130   // Set up rotation transformation (giving image to rotated frame)
00131   vimt_transform_2d rot;
00132   rot.set_similarity(vgl_point_2d<double>(dx1,dy1),
00133                      vgl_point_2d<double>(x0,y0));
00134   vimt_transform_2d im2w = src_image.world2im().inverse()*rot;
00135   dest_image.set_world2im(im2w.inverse());
00136 }
00137 
00138 #endif // vimt_rotate_h_