opencv 图像各方向旋转
1. 简介
计算机图形学中的应用非常广泛的变换是一种称为仿射变换的特殊变换,在仿射变换中的基本变换包括平移、旋转、缩放、剪切这几种。本文以及接下来的几篇文章重点介绍一下关于旋转的变换,包括二维旋转变换、三维旋转变换以及它的一些表达方式(旋转矩阵、四元数、欧拉角等)。
2. 绕原点二维旋转
首先要明确旋转在二维中是绕着某一个点进行旋转,三维中是绕着某一个轴进行旋转。二维旋转中最简单的场景是绕着坐标原点进行的旋转,如下图所示:
如图所示点v 绕 原点旋转θθ 角,得到点v’,假设 v点的坐标是(x, y) ,那么可以推导得到 v’点的坐标(x’, y’)(设原点到v的距离是r,原点到v点的向量与x轴的夹角是ϕϕ )
尽管图示中仅仅表示的是旋转一个锐角θθ的情形,但是我们推导中使用的是三角函数的基本定义来计算坐标的,因此当旋转的角度是任意角度(例如大于180度,导致v’点进入到第四象限)结论仍然是成立的。
旋转和平移 代码1
Rx 可以通过 getRotationMatrix2D 得到
Point center(face_img.cols/2, face_img.rows/2);
//cv::Mat rot_mat = cv::getRotationMatrix2D(center, -1 * arctan, 1.0);
cv::Mat Rx(2, 3, CV_32FC1);
double theta_r = roll * 3.1415926 / 180; /** 3.1415926 / 180*/
float cos_theta = cos(theta_r);
float sin_theta = sin(theta_r);
Rx.at<float>(0, 0) = cos_theta;
Rx.at<float>(0, 1) = -sin_theta;
Rx.at<float>(0, 2) = (1-cos_theta)*center.x + center.y * sin_theta;
Rx.at<float>(1, 0) = sin_theta;
Rx.at<float>(1, 1) = cos_theta;
Rx.at<float>(1, 2) = (1-cos_theta) * center.y - center.x* sin_theta;
//std::cout << rot_mat << std::endl;
cv::Mat rotated_ROI;
cv::warpAffine(face_img, rotated_ROI, Rx, face_img.size(), cv::INTER_LINEAR, cv::BORDER_CONSTANT, cv::Scalar::all(0));
3. 绕任意点的二维旋转
绕原点的旋转是二维旋转最基本的情况,当我们需要进行绕任意点旋转时,我们可以把这种情况转换到绕原点的旋转,思路如下:
1. 首先将旋转点移动到原点处
2. 执行如2所描述的绕原点的旋转
3. 再将旋转点移回到原来的位置
旋转和平移 代码2
Point center(face_img.cols/2, face_img.rows/2);
//cv::Mat rot_mat = cv::getRotationMatrix2D(center, -1 * arctan, 1.0);
cv::Mat Rx(3, 3, CV_32FC1);
double theta_r = roll * 3.1415926 / 180; /** 3.1415926 / 180*/
float cos_theta = cos(theta_r);
float sin_theta = sin(theta_r);
Rx.at<float>(0, 0) = cos_theta;
Rx.at<float>(0, 1) = -sin_theta;
Rx.at<float>(0, 2) = (1-cos_theta)*center.x + center.y * sin_theta;
Rx.at<float>(1, 0) = sin_theta;
Rx.at<float>(1, 1) = cos_theta;
Rx.at<float>(1, 2) = (1-cos_theta) * center.y - center.x* sin_theta;
Rx.at<float>(2, 0) = 0;
Rx.at<float>(2, 1) = 0;
Rx.at<float>(2, 2) = 1;
//std::cout << rot_mat << std::endl;
cv::Mat rotated_ROI;
//cv::warpAffine(face_img, rotated_ROI, rot_mat, face_img.size(), cv::INTER_LINEAR, cv::BORDER_CONSTANT, cv::Scalar::all(0));
warpPerspective(face_img, rotated_ROI, Rx, cv::Size(face_img.cols, face_img.rows));
cv::imshow("roll face", rotated_ROI);
绕X 轴 Y轴 Z轴旋转的结果
void warp_perspect_3_angle(cv::Mat face, float roll, float yaw, float pitch) {
cv::Mat face_img = face.clone();
int imgHeight = face_img.rows;
int imgWidth = face_img.cols;
float alpha, beta, gamma;
alpha = pitch * 3.1415926 / 180;
beta = yaw* 3.1415926 / 180;
gamma = roll * 3.1415926 / 180;
Mat Rot = Mat::eye(3, 3, CV_32FC1);
Rot.at<float>(0, 0) = cos(beta) * cos(gamma);
Rot.at<float>(0, 1) = cos(beta) * sin(gamma);
Rot.at<float>(0, 2) = -sin(beta);
Rot.at<float>(1, 0) = sin(alpha) * sin(beta) * cos(gamma) - cos(alpha) * sin(gamma);
Rot.at<float>(1, 1) = sin(alpha) * sin(beta) * sin(gamma) + cos(alpha) * cos(gamma);
Rot.at<float>(1, 2) = sin(alpha) * cos(beta);
Rot.at<float>(2, 0) = cos(alpha) * sin(beta) * cos(gamma) + sin(alpha) * sin(gamma);
Rot.at<float>(2, 1) = cos(alpha) * sin(beta) * sin(gamma) - sin(alpha) * cos(gamma);
Rot.at<float>(2, 2) = cos(alpha) * cos(beta);
Mat invRot;
invert(Rot, invRot, DECOMP_SVD);
float fx = imgWidth/2;
float fy = imgHeight/2;
float cx = imgWidth / 2;
float cy = imgHeight / 2;
Mat point3D = Mat::zeros(3, 1, CV_32FC1);
Mat oldPoint3D = Mat::zeros(3, 1, CV_32FC1);
Mat dstImg = face_img.clone();
dstImg.setTo(0);
uchar* pImgData = (uchar*)face_img.data;
uchar* pDstData = (uchar*)dstImg.data;
for (int j = 0; j < imgHeight; j++)
{
for (int i = 0; i < imgWidth; i++)
{
float X = (i - cx) / fx;
float Y = (j - cy) / fy;
float Z = 1;
point3D.at<float>(0, 0) = X;
point3D.at<float>(1, 0) = Y;
point3D.at<float>(2, 0) = Z;
//求旋转前坐标点
oldPoint3D = invRot*point3D;
float oldX = oldPoint3D.at<float>(0, 0);
float oldY = oldPoint3D.at<float>(1, 0);
float oldZ = oldPoint3D.at<float>(2, 0);
//重投影到二维平面
if (oldZ > 1e-3)
{
float u = ((fx*oldX + cx*oldZ) / oldZ);
float v = ((fy*oldY + cy*oldZ) / oldZ);
int u0 = floor(u);
int v0 = floor(v);
int u1 = u0 + 1;
int v1 = v0 + 1;
if (u0 >= 0 && v0 >= 0 && u1 < imgWidth && v1 < imgHeight)
{
float dx = u - u0;
float dy = v - v0;
float weight1 = (1 - dx)*(1 - dy);
float weight2 = dx*(1 - dy);
float weight3 = (1 - dx)*dy;
float weight4 = dx*dy;
pDstData[j*imgWidth * 3 + i * 3 + 0] = weight1*pImgData[v0*imgWidth * 3 + u0 * 3 + 0] +
weight2*pImgData[v0*imgWidth * 3 + u1 * 3 + 0] +
weight3*pImgData[v1*imgWidth * 3 + u0 * 3 + 0] +
weight4*pImgData[v1*imgWidth * 3 + u1 * 3 + 0];
pDstData[j*imgWidth * 3 + i * 3 + 1] = weight1*pImgData[v0*imgWidth * 3 + u0 * 3 + 1] +
weight2*pImgData[v0*imgWidth * 3 + u1 * 3 + 1] +
weight3*pImgData[v1*imgWidth * 3 + u0 * 3 + 1] +
weight4*pImgData[v1*imgWidth * 3 + u1 * 3 + 1];
pDstData[j*imgWidth * 3 + i * 3 + 2] = weight1*pImgData[v0*imgWidth * 3 + u0 * 3 + 2] +
weight2*pImgData[v0*imgWidth * 3 + u1 * 3 + 2] +
weight3*pImgData[v1*imgWidth * 3 + u0 * 3 + 2] +
weight4*pImgData[v1*imgWidth * 3 + u1 * 3 + 2];
}
}
}
}
imshow("show", dstImg);
---------------------
opencv 图像各方向旋转的更多相关文章
- [opencv] 图像几何变换:旋转,缩放,斜切
几何变换 几何变换可以看成图像中物体(或像素)空间位置改变,或者说是像素的移动. 几何运算需要空间变换和灰度级差值两个步骤的算法,像素通过变换映射到新的坐标位置,新的位置可能是在几个像素之间,即不一定 ...
- OpenCV:OpenCV图像旋转的代码
OpenCV图像旋转的代码 cv::transpose( bfM, bfM ) 前提:使用两个矩阵Mat型进行下标操作是不行的,耗费的时间太长了.直接使用两个指针对拷贝才是王道.不知道和OpenCV比 ...
- OpenCV 图像旋转实现
1 旋转矩形 首先建议阅读图像旋转算法原理-旋转矩阵,这篇博客可以让你很好地理解图像中的每一个点是如何进行旋转操作的.其中涉及到了图像原点与笛卡尔坐标原点之间的相互转换以及点旋转的一些公式推导. 这里 ...
- 关于OpenCV图像操作的默认参数问题
本系列文章由 @yhl_leo 出品,转载请注明出处. 文章链接: http://blog.csdn.net/yhl_leo/article/details/51559490 在使用OpenCV以及其 ...
- OpenCV图像金字塔:高斯金字塔、拉普拉斯金字塔与图片尺寸缩放
这篇已经写得很好,真心给作者点个赞.题目都是直接转过来的,直接去看吧. Reference Link : http://blog.csdn.net/poem_qianmo/article/detail ...
- 【OpenCV新手教程之十三】OpenCV图像金字塔:高斯金字塔、拉普拉斯金字塔与图片尺寸缩放
本系列文章由@浅墨_毛星云 出品,转载请注明出处. 文章链接:http://blog.csdn.net/poem_qianmo/article/details/26157633 作者:毛星云(浅墨) ...
- 学习 opencv---(12)OpenCV 图像金字塔:高斯金字塔,拉普拉斯金字塔与图片尺寸缩放
在这篇文章里,我们一起学习下 图像金字塔 的一些基本概念,如何使用OpenCV函数pyrUp和pyrDown 对图像进行向上和向下采样,以及了解专门用于缩放图像尺寸的resize函数的用法.此博文一共 ...
- [cocos2d-x] 让精灵响应触摸 并把方向旋转到相对应的角度
在cocos2d-x里面 想要把一个精灵从原位置移动到用户所触摸到的点 , 并且把精灵的方向旋转相对应的弧度,可以参考一下我的做法 我这里的精灵是用一条鱼, 用户触摸后鱼就移动到所触摸的点, 并且移 ...
- Opencv 图像叠加 添加水印
Opencv 图像叠加 添加水印 C++: void Mat::copyTo(OutputArray m) const C++: void Mat::copyTo(OutputArray m, Inp ...
随机推荐
- apache在windows下的命令安装与报错解决
1.在windows下能够通过执行apache的exe文件就能够,但当我们打包的时候,就须要命令来安装apache.apache在windows下用命令下的安装为: apache.exe -k ins ...
- user agent stylesheet 解决方法
写了一个写了一个页面字体一直是加粗.原来是 strong,b{ user agent stylesheet font-weight:bold; } 引起的 解决方法:又一次定义 strong,b{ f ...
- ios12--简易购物车
Assets.xcassets图片是拖到右边里面去的. // // ViewController.m // 03-综合练习 // #import "ViewController.h" ...
- Android横竖屏切换不重新调用onCreate()
再次感叹Android的碎片化!!!! 设置AndroidManifest.xml中Activity的android:configChanges=”keyboardHidden|orientation ...
- E20170627-hm
confirmation n. 证实; 证明; 确认,
- 八大排序算法(Python)
一.插入排序 介绍 插入排序的基本操作就是将一个数据插入到已经排好序的有序数据中,从而得到一个新的.个数加一的有序数据. 算法适用于少量数据的排序,时间复杂度为O(n^2). 插入 ...
- JavaScript(JS)的简单使用
一.什么是JS(Javascript)? Javascript是一种脚本语言,被广泛用于Web应用开发,常用来为网页添加各式各样的功能,为用户提供更加流畅的浏览效果. Javascript严格区分大小 ...
- C语言过时了?为什么还要推荐每一位程序员都来学一下C语言?
互联网蓬勃发展的时代,有一类人做出了巨大的贡献,这一群人被大家称之为程序员,怎样才能成为一名优秀的程序员呢,为什么每一个程序员都需要学习C语言呢? 就让我来跟大家分享分享: 在学习C/C++或者想 ...
- JavaScript--innerHTML 属性
innerHTML 属性用于获取或替换 HTML 元素的内容. 语法: Object.innerHTML 注意: 1.Object是获取的元素对象,如通过document.getElementById ...
- IMP-00058 ORA-12638:身份证明检索失败
需要将oracle的tns关掉 1.打开 oracle 的Net Manage 地址:开始 -> 程序 -> Oracle -> Configuration and Migratio ...