图像识别入门3 图像的缩放和旋转
Posted 神马学习
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了图像识别入门3 图像的缩放和旋转相关的知识,希望对你有一定的参考价值。
我们很多时候得到图像,图像本身就需要进一步处理才能进行下一步工作,常遇到的比如图片太大,位置不正,这样我们就需要图像的缩放旋转。
首先说图像的缩放:
用cvResize实现图像缩放:
voidcvResize(
const CvArr* src,
CvArr* dst,
intinterpolation=CV_INTER_LINEAR
);
函数说明:
第一个参数表示输入图像。
第二个参数表示输出图像。
第三个参数表示插值方法
CV_INTER_NN - 最近邻插值,
CV_INTER_LINEAR - 双线性插值 (缺省使用)
CV_INTER_AREA - 使用象素关系重采样。当图像缩小时候,该方法可以避免波纹出现。当图像放大时,类似于 CV_INTER_NN 方法..
CV_INTER_CUBIC - 立方插值.
IplImage* cvCreateImage(CvSize size, intdepth, intchannels);
函数说明:
第一个参数表示图像的大小。
第二个参数表示图像的深度,可以为IPL_DEPTH_8U,IPL_DEPTH_16U等等。
第三个参数表示图像的通道数。
#include <opencv2/opencv.hpp>
using namespace std;
//隐藏控制台窗口
#pragma comment(linker, "/subsystem:\"windows\" /entry:\"mainCRTStartup\"")
int main()
{
const char *pstrImageName = "D:\\abc\\1.jpg";
const char *pstrSaveImageName = "1缩放图.jpg";
const char *pstrWindowsSrcTitle = "原图 ";
const char *pstrWindowsDstTitle = "缩放图 ";
double fScale = 0.5; //缩放倍数
CvSize czSize; //目标图像尺寸
//从文件中读取图像
IplImage *pSrcImage = cvLoadImage(pstrImageName, CV_LOAD_IMAGE_UNCHANGED);
IplImage *pDstImage = NULL;
//计算目标图像大小
czSize.width = pSrcImage->width * fScale;
czSize.height = pSrcImage->height * fScale;
//创建图像并缩放
pDstImage = cvCreateImage(czSize, pSrcImage->depth, pSrcImage->nChannels);
cvResize(pSrcImage, pDstImage, CV_INTER_AREA);
//创建窗口
cvNamedWindow(pstrWindowsSrcTitle, CV_WINDOW_AUTOSIZE);
cvNamedWindow(pstrWindowsDstTitle, CV_WINDOW_AUTOSIZE);
//在指定窗口中显示图像
cvShowImage(pstrWindowsSrcTitle, pSrcImage);
cvShowImage(pstrWindowsDstTitle, pDstImage);
//等待按键事件
cvWaitKey();
//保存图片
cvSaveImage(pstrSaveImageName, pDstImage);
cvDestroyWindow(pstrWindowsSrcTitle);
cvDestroyWindow(pstrWindowsDstTitle);
cvReleaseImage(&pSrcImage);
cvReleaseImage(&pDstImage);
return 0;
}
运行结果:
而且这样缩放有个好处,倍数设置多大,清晰度基本可以保证的。
然后说说图像的旋转:
旋转一般是指将图像围绕某一指定点旋转一定的角度,图像旋转后会有一部分图像转出显示区域,可以截图那部分,也可以改变图像的尺寸使得图像显示完全。所谓图像旋转是指图像以某一点为中心旋转一定的角度,形成一幅新的图像的过程。这个点通常就是图像的中心。由于是按照中心旋转,所以有这样一个属性:旋转前和旋转后的点离中心的位置不变。根据这个属性,可以得到旋转后的点的坐标与原坐标的对应关系。原图像的坐标一般是以左上角为原点的,我们先把坐标转换为以图像中心为原点。假设原图像的宽为w,高为h,(x0,y0)为原坐标内的一点,转换坐标后的点为(x1,y1)。可以得到:
X0’ = x0 -w/2; y1’ =-y0 + h/2;
在新的坐标系下,假设点(x0,y0)距离原点的距离为r,点与原点之间的连线与x轴的夹角为b,旋转的角度为a,旋转后的点为(x1,y1)。
x0=r*cosb; y0=r*sinb
x1 = r*cos(b-a)= r*cosb*cosa+r*sinb*sina=x0*cosa+y0*sina;
y1=r*sin(b-a)=r*sinb*cosa-r*cosb*sina=-x0*sina+y0*cosa;
得到了转换后的坐标,我们只需要把这些坐标再转换为原坐标系即可。
x1’ = x1+w/2= x0*cosa+y0*sina+w/2
y1’=-y1+h/2=-(-x0*sina+y0*cosa)+h/2=x0*sina-y0*cosa+h/2
此处的x0/y0是新的坐标系中的值,转换为原坐标系为:
x1'= x0*cosa+y0*sina+w/2=(x00-w/2)*consa+(-y00+h/2)*sina+w/2
y1'=x0*sina-y0*cosa+h/2=(x00-w/2)*sina-(-y00+h/2)*cosa+h/2
=(y00-h/2)*cosa+( x00-w/2)*sina+h/2
在OpenCV中,目前并没有现成的函数直接用来实现图像旋转,它是用仿射变换函数cv::warpAffine来实现的,此函数目前支持4种插值算法,最近邻、双线性、双三次、兰索斯插值,如果传进去的参数为基于像素区域关系插值算法(INTER_AREA),则按双线性插值。
一 旋转角度坐标的计算
1.如果O点为圆心,则点P绕点O旋转redian弧度之后,点P的坐标变换为点Q的计算公式为:
Q.x=P.x*cos(redian)-P.y*sin(redian)
Q.y=P.x*sin(redian)+P.y*cos(redian)
redian表示的为弧度
弧度与角度的变换公式为:
redian=pi*180/angle
2. 如果O点不是圆心,则点P绕点O旋转redian弧度之后,点P的坐标变换为Q的计算公式如下:
Q.x=(P.x-O.x)*cos(redian)-(P.y-O.y)*sin(redian)+O.x
Q.y=(P.x-O.x)*sin(redian)+(P.y-O.y)*cos(redian)+O.y
二 旋转任意角度的步骤
1.首先默认旋转45度时,所扩展的图像最大,即为根号2倍的长或宽的最大值,将图像填充到可能达到的最大
2 使用getRotationMatrix2D函数求取旋转矩阵,使用warpAffine函数旋转矩阵
3 求旋转之后包括图像的最大的矩形
4 删除多余的黑色边框
#include <iostream>
#include<opencv2/opencv.hpp>
using namespace cv;
void rotate_arbitrarily_angle(Mat &src, Mat &dst, float angle)
{
float radian = (float)(angle / 180.0 * CV_PI);
//填充图像
int maxBorder = (int)(max(src.cols, src.rows)* 1.414); //即为sqrt(2)*max
int dx = (maxBorder - src.cols) / 2;
int dy = (maxBorder - src.rows) / 2;
copyMakeBorder(src, dst, dy, dy, dx, dx, BORDER_CONSTANT);
//旋转
Point2f center((float)(dst.cols / 2), (float)(dst.rows / 2));
Mat affine_matrix = getRotationMatrix2D(center, angle, 1.0);//求得旋转矩阵
warpAffine(dst, dst, affine_matrix, dst.size());
//计算图像旋转之后包含图像的最大的矩形
float sinVal = abs(sin(radian));
float cosVal = abs(cos(radian));
Size targetSize((int)(src.cols * cosVal + src.rows * sinVal),
(int)(src.cols * sinVal + src.rows * cosVal));
//剪掉多余边框
int x = (dst.cols - targetSize.width) / 2;
int y = (dst.rows - targetSize.height) / 2;
Rect rect(x, y, targetSize.width, targetSize.height);
dst = Mat(dst, rect);
}
int main() {
cv::Mat src = cv::imread("D:\\abc\\1.jpg");
cv::Mat dst;
rotate_arbitrarily_angle(src, dst, 30);
cv::imshow("src", src);
cv::imshow("dst", dst);
cv::waitKey(0);
return 0;
}
运行结果:
以上是关于图像识别入门3 图像的缩放和旋转的主要内容,如果未能解决你的问题,请参考以下文章