OpenCV: how to rotate IplImage?

前端 未结 5 1308
礼貌的吻别
礼貌的吻别 2020-11-29 08:27

I need to rotate an image by very small angle, like 1-5 degrees. Does OpenCV provide simple way of doing that? From reading docs i can assume that getAf

相关标签:
5条回答
  • 2020-11-29 08:42

    Edit: To down voter: Please comment the reason for down voting a tried and tested code?

    #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;
    }
    

    UPDATE: See the following code for rotation using 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;
    }
    
    0 讨论(0)
  • 2020-11-29 08:42
    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 讨论(0)
  • 2020-11-29 08:45

    Updating full answer for OpenCV 2.4 and up

    // 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);
    }
    
    0 讨论(0)
  • 2020-11-29 08:48

    Check my answer to a similar problem:

    Rotating an image in C/C++

    Essentially, use cvWarpAffine - I've described how to get the 2x3 transformation matrix from the angle in my previous answer.

    0 讨论(0)
  • 2020-11-29 09:03

    If you use OpenCV > 2.0 it is as easy as

    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 is in degrees, not radians.

    See the C++ interface documentation for more details and adapt as you need:

    • getRotationMatrix
    • warpAffine
    0 讨论(0)
提交回复
热议问题