在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;//nearest
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]);
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实现了模板图像的旋转匹配,此代码基于matchTemplate函数封装实现可以得知旋转角度的模板匹配(vs2013+opencv2.4.9) 2.带旋转的模板匹配的原理及算法实现(c++) 带旋转的模板匹配算法,能够匹配带旋转...
图像去雾算法opencv实现图像去雾算法opencv实现 暗原色的opencv实现
opencv实现图像的旋转 旋转后的图像保持不变,可以更改背景颜色,利用专门的封装好的函数cvWarpAffine来实现。
这是利用openCV实现图像旋转的C++程序源代码,在VC++ 6.0下编译成功的。
可以求出图像之间的旋转角,精度和图像大小成正比,利用频域做的,不是单纯的旋转0.1°,匹配一下,再转一下,再匹配一下。
opencv实现图像颜色增强算法。。。。 ,vs2013+opencv2.4.13 实现。
在二值图像处理特别是OCR识别与匹配中,都要通过对字符进行细化以便获得图像的骨架,通过zhang-suen细化算法获得图像,作为图像的特征之一,常用来作为识别或者模式匹配。此代码用C++实现了这一算法,配有注释,简洁...
为人师者慎下笔“,故此,本专栏亲自研究,实践,将调试过程中所遭所遇进行详细讲解,注意事项进行一一列举,希望能够帮助到各位初学OpenCV的小伙伴,避免走弯路,费时费力。 需opencv官网下载OpenCV-android-sdk将...
图像处理 图像处理_基于OpenCV实现的图像分割算法实现之AdaptiveThreshold
图像处理 图像处理_基于OpenCV实现的图像分割算法实现之Otsu
图像处理 图像处理_基于OpenCV实现的图像分割算法实现之RegionGrowing
基于opencv的图像匹配算法实现,主要包含了sift的实现,以及已知物体的识别
图像处理 图像处理_基于OpenCV实现的图像分割算法实现之watershed_demo
图像处理 图像处理_基于OpenCV实现的图像分割算法实现之Max_Entropy
利用OpenCvSharp实现感知哈希算法进行图片相似度对比及Stitcher类图像拼接生成全景图像 vs2015环境
opencv实现图像动态旋转 在visaual studio 2008环境下编程
课程设计-基于opencv传统图像处理算法实现物体尺寸测量系统c++源码(含详细注释+sln解决方案).zip课程设计-基于opencv传统图像处理算法实现物体尺寸测量系统c++源码(含详细注释+sln解决方案).zip课程设计-基于opencv...
基于opencv传统图像处理算法实现物体尺寸测量系统C++源码+项目说明+详细注释.zip 基于opencv传统图像处理算法实现物体尺寸测量系统C++源码+项目说明+详细注释.zip 基于opencv传统图像处理算法实现物体尺寸测量系统...
用opencv 2.4.9实现图像任意角度的旋转
openc 图片旋转 ;OpenCvSharp 图片旋转;C#图片旋转 左旋转90°、右旋转90°、旋转180°、垂直翻转、水平翻转