在OpenCV中,目前并没有现成的函数直接用来实现图像旋转,它是用仿射变换函数cv::warpAffine来实现的,此函数目前支持4种插值算法,最近邻、双线性、双三次、兰索斯插值,如果传进去的参数为基于像素区域关系插值算法(INTER_AREA),则按双线性插值。

通常使用2*3矩阵来表示仿射变换:

其中,T相当于变换前的原始图像,x,y为变换后的图像坐标。

对于cv::getRotationMatrix2D函数的实现公式为:

其中scale为缩放因子(x、y方向保持一致),angle为旋转角度(弧长),centerx,centery为旋转中心。

以lena.jpg图像旋转45度为例:

采用最近邻插值算法的实现代码为:

 cv::Mat matSrc = cv::imread("lena.jpg", 2 | 4);if (matSrc.empty()) return;const double degree = 45;double angle = degree * CV_PI / 180.;double alpha = cos(angle);double beta = sin(angle);int iWidth = matSrc.cols;int iHeight = matSrc.rows;int iNewWidth = cvRound(iWidth * fabs(alpha) + iHeight * fabs(beta));int iNewHeight = cvRound(iHeight * fabs(alpha) + iWidth * fabs(beta));double m[6];m[0] = alpha;m[1] = beta;m[2] = (1 - alpha) * iWidth / 2. - beta * iHeight / 2.;m[3] = -m[1];m[4] = m[0];m[5] = beta * iWidth / 2. + (1 - alpha) * iHeight / 2.;cv::Mat M = cv::Mat(2, 3, CV_64F, m);cv::Mat matDst1 = cv::Mat(cv::Size(iNewWidth, iNewHeight), matSrc.type(), cv::Scalar::all(0));double D = m[0]*m[4] - m[1]*m[3];D = D != 0 ? 1./D : 0;double A11 = m[4]*D, A22 = m[0]*D;m[0] = A11; m[1] *= -D;m[3] *= -D; m[4] = A22;double b1 = -m[0]*m[2] - m[1]*m[5];double b2 = -m[3]*m[2] - m[4]*m[5];m[2] = b1; m[5] = b2;int round_delta = 512;//nearestfor (int y=0; y<iNewHeight; ++y){for (int x=0; x<iNewWidth; ++x){//int tmpx = cvFloor(m[0] * x + m[1] * y + m[2]);//int tmpy = cvFloor(m[3] * x + m[4] * y + m[5]);int adelta = cv::saturate_cast<int>(m[0] * x * 1024);int bdelta = cv::saturate_cast<int>(m[3] * x * 1024);int X0 = cv::saturate_cast<int>((m[1] * y + m[2]) * 1024) + round_delta;int Y0 = cv::saturate_cast<int>((m[4] * y + m[5]) * 1024) + round_delta;int X = (X0 + adelta) >> 10;int Y = (Y0 + bdelta) >> 10;if ((unsigned)X < iWidth && (unsigned)Y < iHeight){matDst1.at<cv::Vec3b>(y, x) = matSrc.at<cv::Vec3b>(Y, X);}}}cv::imwrite("rotate_nearest_1.jpg", matDst1);M = cv::getRotationMatrix2D(cv::Point2f(iWidth / 2., iHeight / 2.), degree, 1);cv::Mat matDst2;cv::warpAffine(matSrc, matDst2, M, cv::Size(iNewWidth, iNewHeight), 0, 0, 0);cv::imwrite("rotate_nearest_2.jpg", matDst2);

采用双线性插值算法的实现代码为:

 cv::Mat matSrc = cv::imread("lena.jpg", 2 | 4);if (matSrc.empty()) return;const double degree = 45;double angle = degree * CV_PI / 180.;double alpha = cos(angle);double beta = sin(angle);int iWidth = matSrc.cols;int iHeight = matSrc.rows;int iNewWidth = cvRound(iWidth * fabs(alpha) + iHeight * fabs(beta));int iNewHeight = cvRound(iHeight * fabs(alpha) + iWidth * fabs(beta));double m[6];m[0] = alpha;m[1] = beta;m[2] = (1 - alpha) * iWidth / 2. - beta * iHeight / 2.;m[3] = -m[1];m[4] = m[0];m[5] = beta * iWidth / 2. + (1 - alpha) * iHeight / 2.;cv::Mat M = cv::Mat(2, 3, CV_64F, m);cv::Mat matDst1 = cv::Mat(cv::Size(iNewWidth, iNewHeight), matSrc.type(), cv::Scalar::all(0));double D = m[0]*m[4] - m[1]*m[3];D = D != 0 ? 1./D : 0;double A11 = m[4]*D, A22 = m[0]*D;m[0] = A11; m[1] *= -D;m[3] *= -D; m[4] = A22;double b1 = -m[0]*m[2] - m[1]*m[5];double b2 = -m[3]*m[2] - m[4]*m[5];m[2] = b1; m[5] = b2;for (int y=0; y<iNewHeight; ++y){for (int x=0; x<iNewWidth; ++x){//int tmpx = cvFloor(m[0] * x + m[1] * y + m[2]);//int tmpy = cvFloor(m[3] * x + m[4] * y + m[5]);float fx = m[0] * x + m[1] * y + m[2];float fy = m[3] * x + m[4] * y + m[5];int sy  = cvFloor(fy);fy -= sy;//sy = std::min(sy, iHeight-2);//sy = std::max(0, sy);if (sy < 0 || sy >= iHeight) continue;short cbufy[2];cbufy[0] = cv::saturate_cast<short>((1.f - fy) * 2048);cbufy[1] = 2048 - cbufy[0];int sx = cvFloor(fx);fx -= sx;//if (sx < 0) {// fx = 0, sx = 0;//}//if (sx >= iWidth - 1) {// fx = 0, sx = iWidth - 2;//}if (sx < 0 || sx >= iWidth) continue;short cbufx[2];cbufx[0] = cv::saturate_cast<short>((1.f - fx) * 2048);cbufx[1] = 2048 - cbufx[0];for (int k=0; k<matSrc.channels(); ++k){if (sy == iHeight - 1 || sx == iWidth - 1) {continue;} else {matDst1.at<cv::Vec3b>(y, x)[k] = (matSrc.at<cv::Vec3b>(sy, sx)[k] * cbufx[0] * cbufy[0] +matSrc.at<cv::Vec3b>(sy+1, sx)[k] * cbufx[0] * cbufy[1] +matSrc.at<cv::Vec3b>(sy, sx+1)[k] * cbufx[1] * cbufy[0] +matSrc.at<cv::Vec3b>(sy+1, sx+1)[k] * cbufx[1] * cbufy[1]) >> 22;}}}}cv::imwrite("rotate_bilinear_1.jpg", matDst1);M = cv::getRotationMatrix2D(cv::Point2f(iWidth / 2., iHeight / 2.), degree, 1);cv::Mat matDst2;cv::warpAffine(matSrc, matDst2, M, cv::Size(iNewWidth, iNewHeight), 1, 0, 0);cv::imwrite("rotate_bilinear_2.jpg", matDst2);

其它插值算法的实现代码与双线性类似,可参考 http://blog.csdn.net/fengbingchun/article/details/17335477

OpenCV中图像旋转(warpAffine)算法的实现过程相关推荐

  1. Opencv:图像旋转,cv2.getRotationMatrix2D 和 cv2.warpAffine 函数

    学习记录如何使用opencv实现对图像的旋转操作. 1 cv2.getRotationMatrix2D(center, angle, scale) 图像的旋转矩阵一般为: 但是单纯的这个矩阵是在原点处 ...

  2. OpenCV中图像特征提取与描述

    目录 图像特征提取与描述 图像的特征 Harris和Shi-Tomas算法 Harris角点检测 Shi-Tomasi角点检测 小结 SIFT/SURF算法 SIFT原理 基本流程 尺度空间极值检测 ...

  3. 应用OpenCV进行图像旋转和平移

    简 介: 本文中,你了解了了如何通过OpenCV完成对于图像的旋转和平移.我们首先通过 getRotationMatrix2D() 获取2D旋转矩阵,然后完成了对于图像的旋转.具体是通过warpAff ...

  4. Opencv 基础(四):使用OpenCV进行图像旋转和平移

    如今,图像编辑变得越来越流行,因为手机有内置的功能,可以让你裁剪.旋转和更多的操作你的图像. 这篇文章中,我们将探索和学习这些图像编辑技术.具体来说,我们将学习如何: 旋转图像 移动图像 基本图像变换 ...

  5. 计算机LCG/PCG/MWC/XorShift等PRNG算法,以及V8中Math.random()、webkit中crypto等随机算法的实现

    计算机LCG/PCG/MWC/XorShift等PRNG算法,以及V8中Math.random().webkit中crypto等随机算法的实现 本文篇幅较长,如想直接看 js 的随机数实现可定位本文E ...

  6. OpenCV中图像以Mat类型保存时各通道数据在内存中的组织形式及python代码访问各通道数据的简要方式...

    OpenCV中图像以Mat类型保存时各通道数据在内存中的组织形式及python代码访问各通道数据的简要方式 以最简单的4 x 5三通道图像为例,其在内存中Mat类型的数据组织形式如下: 每一行的每一列 ...

  7. OpenCV中图像的BGR格式 Img对象的属性说明

    1. 图像的BGR格式说明 OpenCV中图像读入的数据格式是numpy的ndarray数据格式.是BGR格式,取值范围是[0,255]. 如下图所示,分为三个维度: 第一维度:Height 高度,对 ...

  8. OpenCV中图像轮廓检测

    OpenCV中图像轮廓检测 通过之前的Canny方法可以得到图像的边界,但是我们无法得到边界的数学信息.所以就有了今天的图像轮廓检测. 在OpenCV中图像轮廓检测的API: findContours ...

  9. OPENCV中图像数据结构及其转化

    OPENCV中图像数据结构及其转化 1. IplImage 它是openCV库中表示图像的结构体. 初始化: cvLoadImage(),cvCreateImage() 访问元素:[行指针] b = ...

最新文章

  1. 2018-3-22论文一种新型的智能算法--狼群算法(笔记三)算法的步骤+收敛性分析
  2. Windows Sockets2 详解2——堵塞与非堵塞模式
  3. linux环境变量恢复,linux环境变量设置错误后的恢复方法(转)
  4. android 判断横竖屏的方法
  5. nstruts2.0发布前奏---浅谈struts和依赖注入在项目中的应用
  6. 见良:学习多媒体主要靠实践
  7. jmp连mysql_令人迷惑的ATT的jmp:直接跳转和间接跳转 [转]
  8. php5.4.41 绿色_编译安装PHP5.4.41
  9. Java基础题笔记1
  10. 物联网和工业互联网场景下的边缘计算
  11. 面向现代化应用,火山引擎云原生究竟提供了哪些能力?
  12. pet缩聚流程图_PET生产工艺流程分解.ppt
  13. java feign请求pathvariable_8、服务发现amp;服务消费者Feign
  14. 分页组件extremeComponents的使用
  15. layui编辑器上传图片
  16. 推流至Wowza服务器要注意的问题
  17. 计算机网络--物理层(全)
  18. pyhton第五章 字典与集合 课后习题
  19. C语言 基于循环结构的程序设计(PTA)
  20. 怎么查看笔记本内存条型号_怎么看电脑内存条型号 电脑内存条型号查看方法【详解】...

热门文章

  1. linux下比较文件并输出,Linux使用diff命令比较文件找出文件之间相同的部分
  2. 固定旋转_旋转压片机如何正确更换冲模?
  3. OpenCV——图像的平移旋转
  4. Mastering Algorithms with C中文版附带源码说明
  5. c4d中的3D插图制作视频教程 Skillshare – 3D Illustration in Cinema 4D
  6. UE4创建第一人称射击游戏学习教程
  7. C++中 public,protected, private 访问标号小结
  8. BitCask 持久化hash存储引擎 原理介绍
  9. 递归/分治:归并排序
  10. MQTT topic匹配规则