圖像旋轉后的還原圖像坐標


需求:對每一個新圖像中的像素進行遍歷。計算像素點在原圖像中相應的位置。


因為在求邊界時。假定圖像進行順時針旋轉,因此此處進行反推新像素位置在原圖像中的相應位置時。須要用逆時針計算。

順時針計算方法是:

X = xcos(theta) + y sin(theta)
Y = ycos(theta) – x sin(theta)

逆時針計算方法是:
X= x cos(theta) – ysin(theta)
Y = xsin(theta) + ycos(theta)
而圖像的坐標軸與尋常所用的坐標軸不同。


也就是說。圖像的旋轉順時針和逆時針的坐標變換公式與常見坐標的變換公式相反:

逆時針計算方法是:

X = xcos(theta) + y sin(theta)
Y = y cos(theta) – x sin(theta)
順時針計算方法是:
X= x cos(theta) – ysin(theta)
Y = xsin(theta) + ycos(theta)
邊界xmin,xmax,ymin。ymax的計算方法:

void bound(int x, int y, float ca, float sa, int *xmin, int *xmax, int *ymin, int *ymax)
/* int x,y;
 float ca,sa;
 int *xmin,*xmax,*ymin,*ymax;*/
{  
    int rx,ry;
     // 以左上角為中心逆時針旋轉
    rx = (int)floor(ca*(float)x+sa*(float)y);
    ry = (int)floor(-sa*(float)x+ca*(float)y);

    if (rx<*xmin) *xmin=rx; if (rx>*xmax) *xmax=rx;
    if (ry<*ymin) *ymin=ry; if (ry>*ymax) *ymax=ry;
}
計算出邊界來之后,就能夠用下式子計算出新圖像的高度和寬度。

xmin = xmax = ymin = ymax = 0;
     bound(nx-1,0,ca,sa,&xmin,&xmax,&ymin,&ymax);
     bound(0,ny-1,ca,sa,&xmin,&xmax,&ymin,&ymax);
     bound(nx-1,ny-1,ca,sa,&xmin,&xmax,&ymin,&ymax);
 
     sx = xmax-xmin+1;
     sy = ymax-ymin+1;
然后就能夠利用cvWarpAffine( src, rotImage, &M,CV_INTER_LINEAR+CV_WARP_FILL_OUTLIERS,cvScalarAll(0) )進行旋轉。

事實上,方法cvWarpAffine看起來的效果。貌似是依照圖像左上角旋轉,然后。平移矩陣a13,a23得到的。即:

 xp = ca * x + sa * y - xtrans;
 yp = ca * y – sa * x - ytrans;
M矩陣為:
m[0] = ca;
m[1] = sa;
m[2] =-(float)xmin;
m[3] =-m[1];
m[4] = m[0];
m[5] =-(float)ymin;
上文中提到的都是從原圖計算旋轉后新圖的問題。

如何進行復原。首先,須要找出原圖像的原點。

此處就是原圖像左上角的點,在新圖像中的位置。

旋轉超過90°和不超過須要分開處理。

void compensate_affine_coor1(int *x0, int *y0, int w1, int h1, float t1, float t2, float Rtheta)
{
     // 逆時針旋轉時的復原
     float x_ori, y_ori;   
     float x_tmp, y_tmp;
 
     float x1 = *x0;
     float y1 = *y0;

     Rtheta = Rtheta*CV_PI/180;
     if ( Rtheta <= CV_PI/2 ) {
         x_ori = 0;
         y_ori = w1 * sin(Rtheta) / t1;
     }
     else {
         x_ori = -w1 * cos(Rtheta) / t2;
         y_ori = ( w1 * sin(Rtheta) + h1 * sin(Rtheta-CV_PI/2) ) / t1;
     }

     float sin_Rtheta = sin(Rtheta);
     float cos_Rtheta = cos(Rtheta); 

     /* project the coordinates of im1 to original image before tilt-rotation transform */
     /* Get the coordinates with respect to the 'origin' of the original image before transform */
     x1 = x1 - x_ori;
     y1 = y1 - y_ori;

     /* Invert tilt */
     x1 = x1 * t2;
     y1 = y1 * t1;

     /* Invert rotation (Note that the y direction (vertical) is inverse to the usual concention. Hence Rtheta instead of -Rtheta to inverse the rotation.) */
     x_tmp = cos_Rtheta*x1 - sin_Rtheta*y1;
     y_tmp = sin_Rtheta*x1 + cos_Rtheta*y1; 

     x1 = x_tmp+1;
     y1 = y_tmp+1;     
 
     *x0 = x1;
     *y0 = y1;
}
旋轉不超過90度時。


因此。O`的x_ori = 0; y_ori = w1 * sin(Rtheta) / t1;

假設超過90度時,


x_ori = -w1 * cos(Rtheta) / t2;
y_ori = ( w1 * sin(Rtheta) + h1 * sin(Rtheta-CV_PI/2) ) / t1; 
首先將所須要還原的坐標點平移,使之變為相對於O`點的坐標。然后,以O`點,即原來的O點按相反的方向旋轉theta角度。注意。w1和h1是旋轉前新圖像的高寬,而不是旋轉后新圖像的高和寬。


關於Image Engineering& Computer Vision很多其它討論與交流。敬請關注本博客和新浪微博songzi_tea


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM