旋转Opencv矩阵90度、180度、270度

40

我正在从网络摄像头捕捉图像,并且需要将其旋转90度。我找到了以下这些函数:

  1. getRotationMatrix2D - 创建旋转矩阵(无论它是什么)
  2. transform - 通过旋转矩阵将一个矩阵转换为另一个矩阵

但是,我只得到了黑色区域。这是我的代码:

   if(rotate_button.click%4>0) {
       double angle = (rotate_button.click%4)*90;  //button increments its click by 1 per click
       Mat transform_m = getRotationMatrix2D(Point(cam_frame_width/2, cam_frame_height/2), angle, 1);  //Creating rotation matrix
       Mat current_frame;
       transform(cam_frame, current_frame, transform_m);  //Transforming captured image into a new one
       cam_frame = Mat((int)current_frame.cols,(int)current_frame.rows, cam_frame_type) = Scalar(0,128,0);  //resizing captured matrix, so I can copy the resized one on it
       current_frame.copyTo(cam_frame);  //Copy resized to original
   }

只输出黑屏。


7
这个问题涉及C++,而另一个问题则依赖于Java接口。一些答案使用了C++接口,但这并不足以将此问题标记为重复。 - Antonio
4个回答

138
上面的回答过于复杂,会占用你的CPU。你的问题不是任意旋转,而是“通过90、180、270度旋转Opencv矩阵”。
更新于2017年6月30日:
OpenCV支持此功能,但未记录文档:https://github.com/opencv/opencv/blob/master/modules/core/include/opencv2/core.hpp#L1041
void rotate(InputArray src, OutputArray dst, int rotateCode);

使用

enum RotateFlags {
    ROTATE_90_CLOCKWISE = 0, //Rotate 90 degrees clockwise
    ROTATE_180 = 1, //Rotate 180 degrees clockwise
    ROTATE_90_COUNTERCLOCKWISE = 2, //Rotate 270 degrees clockwise
};

原始答案和任意角度旋转:

您也可以使用翻转和转置操作来实现此功能,例如对于90度顺时针旋转:

transpose(matSRC, matROT);  
flip(matROT, matROT,1); //transpose+flip(1)=CW

等等其他指令自己想出来(思考=学习),通过从文档中介绍的转置和翻转操作形式来介绍自己。

void rot90(cv::Mat &matImage, int rotflag){
  //1=CW, 2=CCW, 3=180
  if (rotflag == 1){
    transpose(matImage, matImage);  
    flip(matImage, matImage,1); //transpose+flip(1)=CW
  } else if (rotflag == 2) {
    transpose(matImage, matImage);  
    flip(matImage, matImage,0); //transpose+flip(0)=CCW     
  } else if (rotflag ==3){
    flip(matImage, matImage,-1);    //flip(-1)=180          
  } else if (rotflag != 0){ //if not 0,1,2,3:
    cout  << "Unknown rotation flag(" << rotflag << ")" << endl;
  }
}

所以你要这样调用它,并注意矩阵是通过引用传递的。

cv::Mat matImage;
//Load in sensible data
rot90(matImage,3); //Rotate it

//Note if you want to keep an original unrotated version of 
// your matrix as well, just do this
cv::Mat matImage;
//Load in sensible data
cv::Mat matRotated = matImage.clone();
rot90(matImage,3); //Rotate it
任意角度旋转 顺便提一下,以下是如何进行任意角度旋转的方法,我预计这种方法会比普通旋转昂贵50倍。请注意,这种旋转方式会包含黑色填充,并且边缘将被旋转到图像原始大小之外。
void rotate(cv::Mat& src, double angle, cv::Mat& dst){
    cv::Point2f ptCp(src.cols*0.5, src.rows*0.5);
    cv::Mat M = cv::getRotationMatrix2D(ptCp, angle, 1.0);
    cv::warpAffine(src, dst, M, src.size(), cv::INTER_CUBIC); //Nearest is too rough, 
}

对于一个旋转角度为10.5度的调用,显然是:

cv::Mat matImage, matRotated;
//Load in data
rotate(matImage, 10.5, matRotated);

我觉得非常了不起的是,这些极为基础的功能并不是OpenCV的一部分,而OpenCV确实有一些本地的东西,比如人脸检测(性能可疑,不太稳定)。令人惊叹。
干杯!

2
这应该是针对此特定问题的被接受的答案。 - marcman
@TimZaman:实际上它似乎在OpenCV中,尽管我只能在源代码中找到它,而不是在文档中:https://github.com/opencv/opencv/blob/master/modules/core/include/opencv2/core.hpp#L1025。请参见core.hpp中的`void rotate(InputArray src, OutputArray dst, int rotateCode)`。 - tdp2110
1
@TimZaman:另外,我不确定这一点,但你可能需要小心处理方式,确保你从同一个Mat中读取和写入。OpenCV可能会自动处理,但也有可能不会。 - tdp2110
2
@tdp2110 原地修改没问题。感谢您的建议!已更新答案。 - TimZaman
可以确认 cv2.rotate(img, 1) 在 Python 上可行。 - Derek 朕會功夫
显示剩余3条评论

33

使用warpAffine函数:

尝试:

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());

dst 是最终图像


12
这个答案适用于任意旋转,但问题是需要进行90度(模)旋转。也就是说,你的仿射变换可能要比转置和翻转的组合计算密集度高几十倍(请参见下面我的答案)。 - TimZaman
1
糟糕!Affine将插值并使用大量浮点算术运算。而且,它甚至不是所要求的欧几里得刚体变换。翻转将更加有效。 - Vlad
1
即使使用warpAffine旋转360度,图像仍会模糊。您可以添加flags=cv2.INTER_NEAREST来减少一些模糊,但仍然会有明显的退化。 - user3064538

9
@Abhishek Thakur的答案仅适用于将图像旋转180度。它无法处理90度的旋转,因为:
  • 提供给getRotationMatrix2D的旋转中心不正确,以及
  • 传递给warpAffline的输出矩阵大小不正确。

以下是将图像旋转90度的代码:

Mat src = imread("image.jpg");
Mat dst;

double angle = 90;  // or 270
Size src_sz = src.size();
Size dst_sz(src_sz.height, src_sz.width); 

int len = std::max(src.cols, src.rows); 
Point2f center(len/2., len/2.);
Mat rot_mat = cv::getRotationMatrix2D(center, angle, 1.0);
warpAffine(src, dst, rot_mat, dst_sz);

编辑: 另一种方法 旋转图像90度、180度或270度需要进行矩阵转置,然后再进行翻转。这种方法可能更快。


这个答案相比上面明显简单的解决方案过于复杂。编辑提到了一个链接,使用了简单的解决方案但是在循环中,因此比我已经给出的答案更慢。 - TimZaman

0
上述代码运行良好,但由于矩阵计算和warpAffine插值使用浮点数,导致图像引入数值误差。
对于90度增量旋转,我更喜欢使用以下Python/ OpenCV Python代码:
由于Python中的OpenCV图像是2d Numpy数组。
90度:
theImage = numpy.rot90( theImage, 1 )
270度:
theImage = numpy.rot90( theImage, 3 )
注意:我仅在形状为(X,Y)的灰度图像上进行了测试。如果您有颜色(或其他多分离)图像,则可能需要先调整其形状,以确保旋转沿正确的轴进行。

4
这不是正确的语言。 - TimZaman

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接