图像识别入门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(CvSizesize,intdepth,intchannels);

函数说明:

第一个参数表示图像的大小。

第二个参数表示图像的深度,可以为IPL_DEPTH_8U,IPL_DEPTH_16U等等。

第三个参数表示图像的通道数。

#include

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

#include

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;

}

运行结果:

  • 发表于:
  • 原文链接https://kuaibao.qq.com/s/20190106G005Q000?refer=cp_1026
  • 腾讯「云+社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。

扫码关注云+社区

领取腾讯云代金券