opencv 图像翻转、旋转转自:/watkinsong/article/details/91896491.图像左右翻转、翻转90度opencv中并没有直接封装图像旋转任意角度的函数,一般我们可以使用仿射变换获得旋转后的图像,这时候可以进行任意角度的旋转,但是如果我们需要将图像旋转90度,例如只是对图像进行左右翻转,或者旋转90度将图像放倒,那么如果还使用仿射变换,显得有些不是很简单,有点过于复杂。
实际上可以使用求转置矩阵的方式将图像旋转90度,然后可以沿着指定的坐标轴对旋转后的图像进行翻转变化。
使用transpose(src, dst);对目标图像进行转置变换,可以将垂直的图像变为水平放置。
然后使用flip()函数对图像进行翻转。
整个过程非常简单,可以看下下面的代码就非常清晰的了解了。
// ImageFlip.cpp : Defines the entry point for the console application.//#include "stdafx.h"#include "opencv/cv.h"#include "opencv/highgui.h"#include "stdio.h"#include "iostream"using namespace cv;using namespace std;int _tmain(int argc, _TCHAR* argv[]) {Mat src = imread("lena.jpg");Mat dst;transpose(src, dst);Mat dst2;flip(dst, dst2, 1); // flip by y axis Mat dst3;flip(dst, dst3, 0); // flip by x axis Mat dst4;flip(dst, dst4, -1); // flip by both axises imshow("src", src);imshow("dst", dst);imshow("dst2", dst2);imshow("dst3", dst3);imshow("dst4", dst4); cvWaitKey();return 0;}实验结果:原始图像:转置以后:flip(dst, dst2, 1); // flip by y axis2、任意角度旋转、同时缩放(输出图像大小与输入图像大小相同,容易造成图像不全)下面这份代码用于实现对图像的缩放与旋转。
OpenCV版本:2.4.2// 图像旋转与缩放// Author:// Blog:/icvpr#include <iostream>#include <vector>#include <opencv2/opencv.hpp>int main(int argc, char** argv){cv::Mat image = cv::imread("../test.jpg");if (image.empty()){std::cout<<"read imagefailure"<<std::endl;return -1;}cv::Point2f center = cv::Point2f(image.cols / 2, image.rows / 2); // 旋转中心double angle = 30; // 旋转角度double scale = 0.5; // 缩放尺度cv::Mat rotateMat;rotateMat = cv::getRotationMatrix2D(center, angle, scale);cv::Mat rotateImg;cv::warpAffine(image, rotateImg, rotateMat, image.size());cv::imwrite("../rotate.jpg", rotateImg);return 0;} // 图像旋转与缩放// Author:// Blog:/icvpr #include<iostream>#include <vector>#include <opencv2/opencv.hpp>int main(int argc, char** argv){ cv::Mat image = cv::imread("../test.jpg");if (image.empty()){std::cout<<"read image failure"<<std::endl;return -1;} cv::Point2f center = cv::Point2f(image.cols / 2, image.rows / 2); // 旋转中心double angle = 30; // 旋转角度double scale = 0.5; // 缩放尺度cv::Mat rotateMat;rotateMat = cv::getRotationMatrix2D(center, angle, scale); cv::Mat rotateImg;cv::warpAffine(image, rotateImg, rotateMat,image.size()); cv::imwrite("../rotate.jpg", rotateImg);return 0;}原图:缩放:旋转:旋转+缩放3.图像旋转、缩放(缩放后图像完整的进行显示)旋转变换公式的推导:如下图,在2维坐标上,有一点p(x, y) , 直线op的长度为r, 直线op和x轴的正向的夹角为a。
直线op围绕原点做逆时针方向b度的旋转,到达p’(s,t) 则有s = r cos(a + b) = r cos(a)cos(b) – r sin(a)sin(b)(1.1)t = r sin(a + b) = r sin(a)cos(b) + r cos(a) sin(b) (1.2) 其中x =r cos(a) , y = r sin(a)代入(1.1), (1.2) ,s = x cos(b) – y sin(b)(1.3)t = x sin(b) + y cos(b) (1.4)用行列式表示如下用到的一些OpenCV中的函数:(1) CvMat*cv2DRotationMatrix(CvPoint2D32f center, double angle, doublescale, CvMat*map_matrix);Mat getRotationMatrix2D(Point2f center, doubleangle, double scale);说明:计算旋转加缩放的仿射矩阵参数:center:旋转中心angle:旋转度数,正值表示逆时针旋转。
scale:各方向同性的缩放尺度map_matrix:输出参数,仿射变换矩阵,浮点型2*3矩阵返回值:仿射变换矩阵注意:默认的变换是以相反的顺序进行的,即从目标到源。
对于目标图像中的任一点(x,y),先计算出它在源图像中的坐标,再将此点的像素值拷贝到目标图像中,所以计算出的变换矩阵是从目标到源的变换矩阵。
例如逆时针旋转30度,不做缩放,计算出的变换矩阵为:(2) void cvWarpAffine(const CvArr* src,CvArr* dst, const CvMat*map_matrix,intflags=CV_INTER_LINEAR+CV_WARP_FILL_OUTLIERS, CvScalar fillval=cvScalarAll(0));void warpAffine(InputArray src, OutputArray dst, InputArray M,Sizedsize, int flags=INTER_LINEAR,int borderMode = BORDER_CONSTANT,constScalar& borderValue=Scalar() );说明:对图像做仿射变换参数:M:输入参数,2*3的仿射变换矩阵dsize:输出图像的尺寸flags:差值方法,若设置WARP_INVERSE_MAP标识,指明M是目的到源的变换。
borderMode:边界处理方法注意:当设置标志位WARP_INVERSE_MAP时,目标图像的计算公式为:否则,先调用invertAffineTransform()计算出M的逆仿射变换M’,然后将M’带入以上公式进行变换。
[cpp] viewplaincopy print?#include<iostream>#include<opencv2/imgproc/imgproc.hpp>#include<opencv2/highgui/highgui.hpp>using namespace std;using namespace cv;#define SCALE 0.5 //缩放比例int main(){Mat src = imread("pic3.png");Mat dst;//输出图像int angle = 30;//旋转角度(正值表示逆时针旋转)int length;//输出图像的宽度或高度//为了保证无论如何旋转都能放下,输出图像的长和宽都设为输入图像对角线长度乘以SCALE//但如果是缩小(SCALE<=1),这样会导致临时图像中放不下原图,所以对于所有缩小的情况,输出图像和临时图像的长宽都设为原图的对角线长度if(SCALE <= 1)length = sqrt(src.cols*src.cols +src.rows*src.rows);elselength = sqrt(src.cols*src.cols + src.rows*src.rows) * SCALE;//建立临时图像,长宽都是源图像的对角线长度,将源图像复制到临时图像的中心后再变换Mat tempImg(length,length,src.type());//临时图像,大小和输出图像一样大int ROI_x = length/2 - src.cols/2;//ROI矩形左上角的x 坐标int ROI_y = length/2 - src.rows/2;//ROI矩形左上角的y 坐标Rect ROIRect(ROI_x,ROI_y,src.cols,src.rows);//ROI 矩形Mat tempImgROI2(tempImg,ROIRect);//tempImg的中间部分src.copyTo(tempImgROI2);//将原图复制到tempImg的中心Point2f center(length/2,length/2);//旋转中心Mat M = getRotationMatrix2D(center,angle,SCALE);//计算旋转的仿射变换矩阵//输出看看算出的矩阵是什么cout<<"变换矩阵:"<<endl;cout<<M.at<double>(0,0)<<","<<M.at<d ouble>(0,1)<<","<<M.at<double>(0,2)<< ;","<<endl;cout<<M.at<double>(1,0)<<","<<M.at<double>(1,1)<<","<<M.at<double>(1,2)<< ;","<<endl;warpAffine(tempImg,dst,M,Size(length,length));//仿射变换//显示imshow("src",src);imshow("tempImg",tempImg);imshow("dst",dst);waitKey(0);return 0;} #include<iostream>#include<opencv2/imgproc/imgproc.hpp>#include<opencv2/highgui/highgui.hpp>using namespace std;using namespace cv;#define SCALE 0.5 //缩放比例int main(){Mat src = imread("pic3.png");Mat dst;//输出图像int angle = 30;//旋转角度(正值表示逆时针旋转) int length;//输出图像的宽度或高度//为了保证无论如何旋转都能放下,输出图像的长和宽都设为输入图像对角线长度乘以SCALE//但如果是缩小(SCALE<=1),这样会导致临时图像中放不下原图,所以对于所有缩小的情况,输出图像和临时图像的长宽都设为原图的对角线长度if(SCALE <= 1)length = sqrt(src.cols*src.cols +src.rows*src.rows);elselength = sqrt(src.cols*src.cols + src.rows*src.rows) * SCALE;//建立临时图像,长宽都是源图像的对角线长度,将源图像复制到临时图像的中心后再变换Mat tempImg(length,length,src.type());//临时图像,大小和输出图像一样大int ROI_x = length/2 - src.cols/2;//ROI矩形左上角的x 坐标int ROI_y = length/2 - src.rows/2;//ROI矩形左上角的y 坐标Rect ROIRect(ROI_x,ROI_y,src.cols,src.rows);//ROI矩形Mat tempImgROI2(tempImg,ROIRect);//tempImg的中间部分src.copyTo(tempImgROI2);//将原图复制到tempImg的中心Point2f center(length/2,length/2);//旋转中心Mat M = getRotationMatrix2D(center,angle,SCALE);//计算旋转的仿射变换矩阵//输出看看算出的矩阵是什么cout<<"变换矩阵:"<<endl;cout<<M.at<double>(0,0)<<","<<M.at<d ouble>(0,1)<<","<<M.at<double>(0,2)<< ;","<<endl;cout<<M.at<double>(1,0)<<","<<M.at<d ouble>(1,1)<<","<<M.at<double>(1,2)<< ;","<<endl;warpAffine(tempImg,dst,M,Size(length,length));//仿射变换//显示imshow("src",src);imshow("tempImg",tempImg);imshow("dst",dst); waitKey(0);return 0;}效果图:原图临时图像1结果1临时图像2结果2。