作为代码界的菜鸟,最近在尝试着用vs实现《数字图像处理与机器视觉》一书中有关图像处理的VC++代码。目前先从简单的图像几何变换做起,希望能记录自己的成长^_^
本篇是图像旋转变换的实现。
代码中实现的是顺时针变换,如果想要逆时针变换,可以直接把角度设为负值,也可以在旋转函数中进行相应改变,改变方法可参照代码注释中变换方程式。
缺点是这个方法虽然显示了转换后的完整图像,但是旋转后显示的图像跟原图像相比,尺寸有所变化,目前还不知道怎么解决,希望在以后能够解决这个问题。
代码如下:
#include <iostream>
#include <mat.h>//头文件中增加了math.h
#include <opencv2\core\core.hpp>
#include <opencv2\highgui\highgui.hpp>
#include <opencv2\imgproc\imgproc.hpp>
using namespace std;
using namespace cv;
/********************************************
void imgRotate(Mat img, Mat &dst, float ang)
功能: 以原点为中心的图像旋转
注: 图像左上顶点顺时针旋转x1=x0*cost+y0*sint;y1=x0*(-sint)+y0*cost
图像左上顶点逆时针旋转x1=x0*cost-y0*sint;y1=x0*sint+y0*cost;
参数: Mat img:原图像
Mat dst:转置后图像
float ang: 旋转的角度
返回值: 无
*********************************************/
void imgRotate(Mat img, Mat &dst, float ang)
{
float pi = 3.1415926;
int nH = img.rows;
int nW = img.cols;
ang = ang*pi / 180;
int i, j, u, v,minx=0,miny=0,maxx=0,maxy=0;
//这个循环是为了确定旋转变换后原图像各像素对应的坐标,进而确定目标图像的大小,进而显示全部图像
for (i = 0; i < nH; i++)
{
for (j = 0; j < nW; j++)
{
u = int(i*cos(ang) + j*sin(ang) + 0.5);
v = int(-i*sin(ang) + j*cos(ang) + 0.5);
if (minx>u)
minx = u;
if (maxx < u)
maxx = u;
if (miny>v)
miny = v;
if (maxy < v)
maxy = v;
}
}
int dH = abs(minx)+maxx;
int dW = abs(miny)+maxy;
dst.create(dH, dW, img.type());
//注意这个循环的起始和终止条件
//判断目标图像的像素经过逆变换后的像素坐标在不在原图像中来确定目标图像像素值
for (i = minx; i < maxx; i++)
{
for (j = miny; j < maxy; j++)
{
u = int(i*cos(ang) - j*sin(ang) + 0.5);
v = int(i*sin(ang) + j*cos(ang) + 0.5);
if (u>0 && u<nH&&v>0 && v < nW)
dst.at<Vec3b>(i+abs(minx), j+abs(miny)) = img.at<Vec3b>(u, v);//i和j都加上最小行和列值的绝对值是因为目标图像的像素坐标均为正值
else
dst.at<Vec3b>(i + abs(minx), j + abs(miny)) = 0;
}
}
}
int main()
{
Mat img = imread("1.jpg");
imshow("原图", img);
Mat dst;
//以图像左顶点为中心进行旋转变换
imgRotate(img, dst, 30);
cvNamedWindow("旋转变换",CV_WINDOW_FREERATIO);//这句是为了在显示结果图的时候可以自由控制结果图窗口的大小
imshow("旋转变换", dst);
waitKey(0);
return 0;
}
结果图如下:
顺时针30度旋转结果:
逆时针30度旋转结果(角度设为-30):