基于c++和opencv底层的图像旋转

图像旋转:本质上是对旋转后的图片中的每个像素计算在原图的位置。

在opencv包里有自带的旋转函数,当你知道倾斜角度theta时:

getRotationMatrix2D可得2X3的旋转变换矩阵 M,在用warpaffine函数可得倾斜后的图像dst。

很方便啊,为什么还要自己实现底层的图像旋转呢?因为有些地方你用这两个函数就会出现问题,比如说:

原图的size是MXN,且图像是完全填充的(因为如果有留白可能还不能将问题完全反映出来),现在你需要将它90°变换(为了形象说明),可是用前面两个API会产生什么结果呢?如下:

噢?有一部分看不见了…我们来看一下上面两个函数:

C++: Mat getRotationMatrix2D(Point2f center, double angle, double scale)

C++: void warpAffine(InputArray src, OutputArray dst, InputArray M, Size dsize, int ?ags=INTER_LINEAR, int borderMode=BORDER_CONSTANT, const Scalar& borderValue=Scalar())

一开始我以为是这两个参数的设置问题。一般来说,center是设置在源图像中心点进行翻转的,现在有一部分看不见了,是不是中心点的问题呢?我换个中心点可不可以呢?实验证明,分别设置左上、下;右上,下角点为中心点时,都会有部分图像显示不出来。我放弃center,改试dsize,改大一点,还是不行,只是显示和黑色面积分别更大了,显示的比例并没有改变什么。这时候就不必再试了,有这个功夫我还不如自己写个旋转函数呢。为什么会这样呢,因为原图的面积不够大啊,一旋转就出去了啊,所以依然不想自己写函数(不建议,因为写的函数代码很简单啊)的童鞋,用copyMakeborder函数在原图上添加边界再旋转吧。添加完边界后问题又来了:边界添加的小图像还是会旋出去。边界添加的大,图片本身就很小了(就像置身于一片苍茫的黑色的宇宙中,当然是夸张),接下来你要对原来的图片中的像素进行什么处理就更困难了,有点小了。必要时还得去边界,opencv里面好像可没有现成的去边界函数啊。

所以(前言说的太长),我们有必要自己写个简单方便的旋转函数。先给出旋转矩阵及其变换关系(别问我怎么来的,我是拿现成的老师教得,不过知道的朋友可以图解一下)

代码如下:

 1 Mat angleRectify(Mat img,float angle)
 2 {
 3     Mat retMat = Mat::zeros(550,850, CV_8UC3);
 4     float anglePI =(float) (angle * CV_PI / 180);
 5     int xSm, ySm;
 6     for(int i = 0; i < retMat.rows; i++)
 7         for(int j = 0; j < retMat.cols; j++)
 8         {
 9             xSm = (int)((i-retMat.rows/2)*cos(anglePI) - (j-retMat.cols/2)*sin(anglePI) + 0.5);
10             ySm = (int)((i-retMat.rows/2)*sin(anglePI) + (j-retMat.cols/2)*cos(anglePI) + 0.5);
11             xSm += img.rows / 2;
12             ySm += img.cols / 2;
13             if(xSm >= img.rows || ySm >= img.cols || xSm <= 0 || ySm <= 0){
14                 retMat.at<Vec3b>(i, j) = Vec3b(0, 0);
15             }
16             else{
17                 retMat.at<Vec3b>(i, j) = img.at<Vec3b>(xSm, ySm);
18             }
19         }
20
21     return retMat;
22 }

这里有几个问题需要说明:

1 本来需要变换后图片乘以 原图变换矩阵的逆矩阵 对应到原图中坐标。但是因为y轴方向向下,所以变换后图片乘以原图变换矩阵(无需逆矩阵)即可对应到原图中坐标

2 第9、10行需要 -retMat.rows/2和retMat.cols/2的原因在于,图像是以(retMat.cols/2,retMat.rows/2)为坐标原点旋转的,所以变换后图片中的每个像素点(i; j),需要平移到相对旋转中心的新坐标,即(i - Mat.rows/2; j - Mat.cols/2)。

  1. 第11,12行表示在计算完成之后,需要再次还原到相对左上角原点的旧坐标;
  2. 矩阵下标与原图变换矩阵相乘之前,需要将矩阵下标两值互换。相乘之后,需要再次互换下标值还原成矩阵下标。这句话是什么意思呢,我们可以看出,但是实际 xSm = (int)((i-retMat.rows/2)*cos(anglePI) - (j-retMat.cols/2)*sin(anglePI) + 0.5);  (i-retMat.rows/2)是我们认为的纵坐标。
  3. 旋转角度整数代表顺时针,负数代表逆时针(这点在opencv里的很多情况下都使用)
  4. 这里表示彩色图的旋转,Vec3b是彩色类型,如果是灰度图,将<>里的类型换成uchar并将retMat.at<Vec3b>(i, j) = Vec3b(0, 0); =>retMat.at<uchar>(i, j) = uchar(0);
  5. 如果是要旋转90°这种已知dst的size的情况下可以指定reMat的size从而不边界,其他类型还是会有边界的(但是比自己copyMakeBorder会小一些),因为你不知道reMat需要多大。

旋转45° 旋转90° 原图

文章参考:http://blog.csdn.net/ironyoung/article/details/41117039?utm_source=tuicool

时间: 2024-10-29 19:09:44

基于c++和opencv底层的图像旋转的相关文章

【图像处理】基于OpenCV底层实现的图片旋转

image processing 系列 [图像处理]直方图匹配 [图像处理]高斯滤波.中值滤波.均值滤波 图片旋转,本质上是对旋转后的图片中每一个像素点计算在原图的位置.然后照搬过来就好. (多说一句.假设计算出来在原图中的位置不是整数而是小数,由于像素点个数都是整数,就须要小数到整数的转换. 这个转换过程是有讲究的,须要用到插值:近期邻插值.双线性插值等等.这里我使用的是最简单的近期邻插值.即对小数四舍五入成整数.C/C++ 实现四舍五入见这里) 完整 github 代码:image-proc

用OpenCV实现Photoshop算法(一): 图像旋转

最近学习了OpenCV,于是想用它实现Photoshop的主要功能,用于照片处理. 对于一张照片,PS的一般处理步骤包括: 1, 旋转图片,校正位置. 2,剪切,调整大小,重新构图. 3,调整色阶.曲线,使图片曝光正确.对比适中. 4,调整对比度.饱和度 5,印章去掉不想要的东西,液化调整形体线条 6,对于人像图片,美肤.美白 7, 用色彩平衡.可选颜色等调整色调,形成照片调性 8,加一些光效 9,锐化 以后的一系列博文将采用OpenCV逐一实现Photoshop的算法和功能, 并用计算机视觉人

使用OpenCL+OpenCV实现图像旋转(一)

[题外话]近期申请了一个微信公众号:平凡程式人生.有兴趣的朋友可以关注,那里将会涉及更多更新OpenCL+OpenCV以及图像处理方面的文章. 最近在学习<OPENCL异构计算>,其中有一个实例是使用OpenCL实现图像旋转.这个实例中并没有涉及读取.保存.显示图像等操作,其中也存在一些小bug.在学习OpenCL之初,完整地实现这个实例还是很有意义的事情. 1.图像旋转原理 所谓图像旋转是指图像以某一点为中心旋转一定的角度,形成一幅新的图像的过程.这个点通常就是图像的中心. 由于是按照中心旋

【OpenCV】图像旋转详解,边缘用黑色填充

项目要用到图像旋转,OpenCV里面居然没有专门封装好的函数,只好自己写了.根据<learnning OpenCV>发现效果不是很理想,旋转后图像大小不变,可是图像却被裁减了. 例子如下: int main( int argc, char** argv ) { IplImage* src=cvLoadImage("C:\\Users\\Liu\\Desktop\\bridge.bmp",1); IplImage* dst = cvCloneImage( src ); int

图像处理 基于Visual C++编程 学习笔记 (4)图像旋转

图像旋转 imgrotation 根据输入的角度进行旋转变换 很简单,套公式. 遍历输出的图像的像素,去原图中找对应像素,超出边界置0 如果遍历原图像素,去构建输出图像像素则会有很多噪声,因为浮点数计算的误差 数据校验及数据转换 void CBMPDlg::OnRota() { // TODO: Add your control notification handler code here CDC *pDC = m_image1.GetDC(); CRect myRECT; m_image1.G

opencv-从图像旋转学习Mat数据访问

先看一个简单的例子 代码: // ConsoleApplication3_6_23.cpp : Defines the entry point for the console application. // #include "stdafx.h" #include<opencv2/opencv.hpp> #include<iostream> #include<vector> using namespace std; using namespace c

基于QT和OpenCV的人脸识别系统

1 系统方案设计 1.1 引言 人脸是一个常见而复杂的视觉模式,人脸所反映的视觉信息在人与人的交流和交往中有着重 要的作用和意义,对人脸进行处理和分析在视频监控.出入口控制.视频会议以及人机交互等领 域都有着广泛的应用前景,因此是模式识别和计算机视觉领域持续的研究热点. 本系统在 FriendlyARM Tiny6410 开发板基础上,利用 OpenCV 计算机视觉库和 QT 图形库,通 过普通的 USB 摄像头实现了自动人脸识别,准确率较高,方便易用. 1.2 系统总体架构 "人脸识别&quo

C/C++ BMP(24位真彩色)图像处理(4)------图像の旋转

历经一个多月,CSDN貌似终于好像把文章列表阅读量信息归零BUG给修好了,于是乎放篇做期末大作业时写的文章上来测测效果,可别又像上次一样一发文章就又坑爹了啊! 本篇谈的是图像的旋转,不算是什么新鲜的题目了.但是现在由于很多工具如MATLAB.OPENCV等都把算法写好给用户调用,导致大多用户只知其然不知其所以然,所以回顾一下也是好的. 图像的旋转,说到底就是每个像素点绕着某个圆心旋转一定角度.如果是写代码的话,旋转的角度和圆心应该是已知的条件,我们第一个思路是根据已知条件求取出图像经过旋转后的新

OpenCV &mdash;&mdash; 矩阵和图像操作

cvAbs , cvAbsDiff , cvAbsDiffS cvAdd , cvAddS , cvAddWeighted(可添加权重) #include <cv.h> #include <highgui.h> int main(int argc,char** argv) { IplImage *s1,*s2; s1=cvLoadImage("wukong.jpg",CV_LOAD_IMAGE_COLOR); s2=cvLoadImage("test.