图像识别入门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 sizeintdepthintchannels);

  • 函数说明:

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

  • 第二个参数表示图像的深度,可以为IPL_DEPTH_8UIPL_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 图像的缩放和旋转的主要内容,如果未能解决你的问题,请参考以下文章

如何通过平移、旋转和/或缩放调整来匹配两个分割蒙版

为啥我们必须将手势识别器的旋转/缩放设置回 0/1?

图片处理-opencv-3.图像缩放、旋转、翻转、平移

图像识别算法及案例

如何使 MODI 无法识别旋转图像?

OpenCV新手入门,如何用它平移缩放和旋转图片