2010-02-18 8 views
25

J'ai besoin de faire pivoter une image par un très petit angle, comme 1-5 degrés. Est-ce que OpenCV est un moyen simple de le faire? À la lecture de documents que je peux supposer que getAffineTransform() devraient être impliqués, mais il n'y a pas d'exemple direct de faire quelque chose comme:OpenCV: comment faire pivoter IplImage?

IplImage *rotateImage(IplImage *source, double angle); 

Répondre

42

Si vous utilisez OpenCV> 2.0, il est aussi facile que

using namespace cv; 

Mat rotateImage(const Mat& source, double angle) 
{ 
    Point2f src_center(source.cols/2.0F, source.rows/2.0F); 
    Mat rot_mat = getRotationMatrix2D(src_center, angle, 1.0); 
    Mat dst; 
    warpAffine(source, dst, rot_mat, source.size()); 
    return dst; 
} 

Note: angle est en degrés, radians pas.

Voir C++ documentation d'interface pour plus de détails et à s'y adapter que vous avez besoin:

4

Vérifiez ma réponse à un problème similaire:

Rotating an image in C/C++

Essentiellement, utilisez cvWarpAffine - J'ai décrit comment obtenir la matrice de transformation 2x3 à partir de l'angle de ma réponse précédente.

5

Edit: Pour voter vers le bas: S'il vous plaît commenter la raison vers le bas le vote d'une code essayé et testé?

#include "cv.h" 
#include "highgui.h" 
#include "math.h" 
int main(int argc, char** argv) 
{ 
    IplImage* src = cvLoadImage("lena.jpg", 1);  
    IplImage* dst = cvCloneImage(src); 

    int delta = 1; 
    int angle = 0; 
    int opt = 1; // 1: rotate & zoom 
       // 0: rotate only 
    double factor; 
    cvNamedWindow("src", 1); 
    cvShowImage("src", src); 

    for(;;) 
    { 
    float m[6]; 
    CvMat M = cvMat(2, 3, CV_32F, m); 
    int w = src->width; 
    int h = src->height; 

    if(opt) 
     factor = (cos(angle*CV_PI/180.) + 1.05) * 2; 
    else 
     factor = 1; 
    m[0] = (float)(factor*cos(-angle*2*CV_PI/180.)); 
    m[1] = (float)(factor*sin(-angle*2*CV_PI/180.)); 
    m[3] = -m[1]; 
    m[4] = m[0]; 
    m[2] = w*0.5f; 
    m[5] = h*0.5f; 

    cvGetQuadrangleSubPix(src, dst, &M); 
    cvNamedWindow("dst", 1); 
    cvShowImage("dst", dst); 
    if(cvWaitKey(1) == 27) 
     break; 
    angle =(int)(angle + delta) % 360; 
    }  
    return 0; 
} 

MISE À JOUR: Voir le code suivant pour rotation à l'aide warpaffine https://code.google.com/p/opencvjp-sample/source/browse/trunk/cpp/affine2_cpp.cpp?r=48

#include <cv.h> 
#include <highgui.h> 

using namespace cv; 

int 
main(int argc, char **argv) 
{ 
    // (1)load a specified file as a 3-channel color image, 
    // set its ROI, and allocate a destination image 
    const string imagename = argc > 1 ? argv[1] : "../image/building.png"; 
    Mat src_img = imread(imagename); 
    if(!src_img.data) 
    return -1; 
    Mat dst_img = src_img.clone(); 

    // (2)set ROI 
    Rect roi_rect(cvRound(src_img.cols*0.25), cvRound(src_img.rows*0.25), cvRound(src_img.cols*0.5), cvRound(src_img.rows*0.5)); 
    Mat src_roi(src_img, roi_rect); 
    Mat dst_roi(dst_img, roi_rect); 

    // (2)With specified three parameters (angle, rotation center, scale) 
    // calculate an affine transformation matrix by cv2DRotationMatrix 
    double angle = -45.0, scale = 1.0; 
    Point2d center(src_roi.cols*0.5, src_roi.rows*0.5); 
    const Mat affine_matrix = getRotationMatrix2D(center, angle, scale); 

    // (3)rotate the image by warpAffine taking the affine matrix 
    warpAffine(src_roi, dst_roi, affine_matrix, dst_roi.size(), INTER_LINEAR, BORDER_CONSTANT, Scalar::all(255)); 

    // (4)show source and destination images with a rectangle indicating ROI 
    rectangle(src_img, roi_rect.tl(), roi_rect.br(), Scalar(255,0,255), 2); 

    namedWindow("src", CV_WINDOW_AUTOSIZE); 
    namedWindow("dst", CV_WINDOW_AUTOSIZE); 
    imshow("src", src_img); 
    imshow("dst", dst_img); 
    waitKey(0); 

    return 0; 
} 
-1
IplImage* rotate(double angle, float centreX, float centreY, IplImage* src, bool crop) 
{ 
    int w=src->width; 
    int h=src->height; 

     CvPoint2D32f centre; 
     centre.x = centreX; 
     centre.y = centreY; 

     CvMat* warp_mat = cvCreateMat(2, 3, CV_32FC1); 

     cv2DRotationMatrix(centre, angle, 1.0, warp_mat); 

     double m11= cvmGet(warp_mat,0,0); 
     double m12= cvmGet(warp_mat,0,1); 
     double m13= cvmGet(warp_mat,0,2); 
     double m21= cvmGet(warp_mat,1,0); 
     double m22= cvmGet(warp_mat,1,1); 
     double m23= cvmGet(warp_mat,1,2); 
     double m31= 0; 
     double m32= 0; 
     double m33= 1; 
     double x=0; 
     double y=0; 
     double u0= (m11*x + m12*y + m13)/(m31*x + m32*y + m33); 
     double v0= (m21*x + m22*y + m23)/(m31*x + m32*y + m33); 
     x=w; 
     y=0; 
     double u1= (m11*x + m12*y + m13)/(m31*x + m32*y + m33); 
     double v1= (m21*x + m22*y + m23)/(m31*x + m32*y + m33); 
     x=0; 
     y=h; 
     double u2= (m11*x + m12*y + m13)/(m31*x + m32*y + m33); 
     double v2= (m21*x + m22*y + m23)/(m31*x + m32*y + m33); 
     x=w; 
     y=h; 
     double u3= (m11*x + m12*y + m13)/(m31*x + m32*y + m33); 
     double v3= (m21*x + m22*y + m23)/(m31*x + m32*y + m33); 

     int left= MAX(MAX(u0,u2),0); 
     int right= MIN(MIN(u1,u3),w); 
     int top= MAX(MAX(v0,v1),0); 
     int bottom= MIN(MIN(v2,v3),h); 

     ASSERT(left<right&&top<bottom); // throw message? 
     if (left<right&&top<bottom) 
     { 
      IplImage* dst= cvCreateImage(cvGetSize(src), IPL_DEPTH_8U, src->nChannels); 
      cvWarpAffine(src, dst, warp_mat/*, CV_INTER_LINEAR + CV_WARP_FILL_OUTLIERS, cvScalarAll(0)*/); 

      if (crop) // crop and resize to initial size 
      { 
       IplImage* dst_crop= cvCreateImage(cvSize(right-left, bottom-top), IPL_DEPTH_8U, src->nChannels); 
       cvSetImageROI(dst,cvRect(left,top,right-left,bottom-top)); 
       cvCopy(dst,dst_crop); 
       cvReleaseImage(&dst); 
       cvReleaseMat(&warp_mat); 
       //ver1 
       //return dst_crop; 
       // ver2 resize 
       IplImage* out= cvCreateImage(cvSize(w, h), IPL_DEPTH_8U, src->nChannels); 
       cvResize(dst_crop,out); 
       cvReleaseImage(&dst_crop); 
       return out; 
      } 
      else 
      { 
       /*cvLine(dst, cvPoint(left,top),cvPoint(left, bottom), cvScalar(0, 0, 255, 0) ,1,CV_AA); 
       cvLine(dst, cvPoint(right,top),cvPoint(right, bottom), cvScalar(0, 0, 255, 0) ,1,CV_AA); 
       cvLine(dst, cvPoint(left,top),cvPoint(right, top), cvScalar(0, 0, 255, 0) ,1,CV_AA); 
       cvLine(dst, cvPoint(left,bottom),cvPoint(right, bottom), cvScalar(0, 0, 255, 0) ,1,CV_AA);*/ 
       cvReleaseMat(&warp_mat); 
       return dst; 
      } 
     } 
     else 
     { 
      return NULL; //assert? 
     } 
} 
+0

Justifiez downvoting! "Il dit que la réponse n'est pas utile". Pourquoi pas? –

3

Mise à jour réponse complète pour OpenCV 2.4 et jusqu'à

// ROTATE p by R 
/** 
* Rotate p according to rotation matrix (from getRotationMatrix2D()) R 
* @param R  Rotation matrix from getRotationMatrix2D() 
* @param p  Point2f to rotate 
* @return  Returns rotated coordinates in a Point2f 
*/ 
Point2f rotPoint(const Mat &R, const Point2f &p) 
{ 
    Point2f rp; 
    rp.x = (float)(R.at<double>(0,0)*p.x + R.at<double>(0,1)*p.y + R.at<double>(0,2)); 
    rp.y = (float)(R.at<double>(1,0)*p.x + R.at<double>(1,1)*p.y + R.at<double>(1,2)); 
    return rp; 
} 

//COMPUTE THE SIZE NEEDED TO LOSSLESSLY STORE A ROTATED IMAGE 
/** 
* Return the size needed to contain bounding box bb when rotated by R 
* @param R  Rotation matrix from getRotationMatrix2D() 
* @param bb bounding box rectangle to be rotated by R 
* @return  Size of image(width,height) that will compleley contain bb when rotated by R 
*/ 
Size rotatedImageBB(const Mat &R, const Rect &bb) 
{ 
    //Rotate the rectangle coordinates 
    vector<Point2f> rp; 
    rp.push_back(rotPoint(R,Point2f(bb.x,bb.y))); 
    rp.push_back(rotPoint(R,Point2f(bb.x + bb.width,bb.y))); 
    rp.push_back(rotPoint(R,Point2f(bb.x + bb.width,bb.y+bb.height))); 
    rp.push_back(rotPoint(R,Point2f(bb.x,bb.y+bb.height))); 
    //Find float bounding box r 
    float x = rp[0].x; 
    float y = rp[0].y; 
    float left = x, right = x, up = y, down = y; 
    for(int i = 1; i<4; ++i) 
    { 
     x = rp[i].x; 
     y = rp[i].y; 
     if(left > x) left = x; 
     if(right < x) right = x; 
     if(up > y) up = y; 
     if(down < y) down = y; 
    } 
    int w = (int)(right - left + 0.5); 
    int h = (int)(down - up + 0.5); 
    return Size(w,h); 
} 

/** 
* Rotate region "fromroi" in image "fromI" a total of "angle" degrees and put it in "toI" if toI exists. 
* If toI doesn't exist, create it such that it will hold the entire rotated region. Return toI, rotated imge 
* This will put the rotated fromroi piece of fromI into the toI image 
* 
* @param fromI  Input image to be rotated 
* @param toI  Output image if provided, (else if &toI = 0, it will create a Mat fill it with the rotated image roi, and return it). 
* @param fromroi roi region in fromI to be rotated. 
* @param angle  Angle in degrees to rotate 
* @return   Rotated image (you can ignore if you passed in toI 
*/ 
Mat rotateImage(const Mat &fromI, Mat *toI, const Rect &fromroi, double angle) 
{ 
    //CHECK STUFF 
    // you should protect against bad parameters here ... omitted ... 

    //MAKE OR GET THE "toI" MATRIX 
    Point2f cx((float)fromroi.x + (float)fromroi.width/2.0,fromroi.y + 
       (float)fromroi.height/2.0); 
    Mat R = getRotationMatrix2D(cx,angle,1); 
    Mat rotI; 
    if(toI) 
     rotI = *toI; 
    else 
    { 
     Size rs = rotatedImageBB(R, fromroi); 
     rotI.create(rs,fromI.type()); 
    } 

    //ADJUST FOR SHIFTS 
    double wdiff = (double)((cx.x - rotI.cols/2.0)); 
    double hdiff = (double)((cx.y - rotI.rows/2.0)); 
    R.at<double>(0,2) -= wdiff; //Adjust the rotation point to the middle of the dst image 
    R.at<double>(1,2) -= hdiff; 

    //ROTATE 
    warpAffine(fromI, rotI, R, rotI.size(), INTER_CUBIC, BORDER_CONSTANT, Scalar::all(0)); 

    //& OUT 
    return(rotI); 
} 
Questions connexes