这次实验是要设计一个可以让图形进行绕任意中心任意角度旋转的函数WarpAffine,其核心大概就是使用双线性差值进行重采样。
在数学上,双线性插值是有两个变量的插值函数的线性插值扩展,其核心思想是在两个方向分别进行一次线性插值。
在代码中实现双线性插值要注意原图像和目标图像的原点均旋转左上角,然后根据插值公式计算目标图像每点像素,得到结果大致如下:
简单来说,就是使用
int x=(i+0.5)*m/a-0.5
int y=(j+0.5)*n/b-0.5
来代替
int x=i*m/a
int y=j*n/b
除了双线性插值之外,还需要的就是图像旋转操作了。我在做图像旋转时,首先新创建了和原图像大小相等的新图像,还有指定旋转中心,然后使用getRotationMatrix2D方法来获取旋转矩阵(2*3矩阵)。
在getRotatePoint()函数里,使用了这样一个for循环来完成所需功能:
得到结果如图所示:
改变旋转中心和旋转角度:
在完成图像旋转的操作之后,我又想更方便的、不需要在命令行界面手动输入旋转中心和旋转角度的操作,于是想到了上个实验中使用的滑动条语句,便把对旋转角度和旋转中心的设定都放到了滑动条中,可以实现在图像窗口中完成任意角度和中心的选择。
同时也欢迎各位关注我的公众号 南木的下午茶
———————————————————————————————————
图片和代码请自取
#include "stdafx.h"
#include <iostream>
#include<vector>
#include<algorithm>
#include <opencv2\opencv.hpp>
#include <opencv2\highgui\highgui.hpp>
using namespace std;
using namespace cv;
#define pi 3.1415926
vector<cv::Point2i> Rotate(cv::Mat srcImage, vector<cv::Point2i> Points, const cv::Point rotate_center, const double angle) {
vector<cv::Point2i> dstPoints;
int x1 = 0, y1 = 0;
int row = srcImage.rows;
for (size_t i = 0; i < Points.size(); i++)
{
x1 = Points.at(i).x;
y1 = row - Points.at(i).y;
int x2 = rotate_center.x;
int y2 = row - rotate_center.y;
int x = cvRound((x1 - x2)*cos(pi / 180.0 * angle) - (y1 - y2)*sin(pi / 180.0 * angle) + x2);
int y = cvRound((x1 - x2)*sin(pi / 180.0 * angle) + (y1 - y2)*cos(pi / 180.0 * angle) + y2);
y = row - y;
dstPoints.push_back(Point2i(x, y));
}
return dstPoints;
}
int main() {
Mat src = imread("../res/图片1.jpg");
Point2i point(100, 100);
vector<cv::Point2i> Points;
Points.push_back(point);
cv::circle(src, point, 2, cv::Scalar(255, 0, 0), 2);
cv::imshow("src image ", src);
cv::Mat dst;
//旋转角度
double angle ;
//旋转中心
int m,n;
cout << "请输入旋转角度、旋转中心x轴坐标、旋转中心y轴坐标:" << endl;
cin >> angle >> m >> n;
//输出图像的尺寸与原图一样
cv::Size dst_sz(src.cols, src.rows);
//指定旋转中心
cv::Point2f center(src.cols / m, src.rows / n);
//获取旋转矩阵(2x3矩阵)
cv::Mat rot_mat = cv::getRotationMatrix2D(center, angle, 1.0);
cv::Scalar borderColor = Scalar(0, 238, 0);
cv::warpAffine(src, dst, rot_mat, dst_sz, INTER_LINEAR, BORDER_CONSTANT, borderColor);
//cv::warpAffine(src, dst, rot_mat, dst_sz, INTER_LINEAR, BORDER_REPLICATE);
vector<cv::Point2i> dstPoints = Rotate(dst, Points, center, angle);
cv::circle(dst, dstPoints.at(0), 5, cv::Scalar(0, 0, 255), 2);
cv::imshow("Rotation Image", dst);
waitKey(0);
return 0;
}