手撕图像仿射变换

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
// 功能: 采用双线性插值对图像进行尺寸变换
// 参数:
// Eigen::Matrix<int, 3, 2> srcPoint 原始图像中的三个不共面的点
// Eigen::Matrix<int, 3, 2> dstPoint 目标图像中的三个不共面的点
// cv::Mat srcImg 输入图像
// cv::Mat dstImg 输出图像
// 说明:
// 这里需要借助opencv读图像,所以函数的两个参数是opencv的格式
void warpAffine(Eigen::Matrix<int, 3, 2> srcPoint, Eigen::Matrix<int, 3, 2> dstPoint, cv::Mat srcImg, cv::Mat dstImg){
// Y = M x X
Eigen::Matrix<float, 3, 3> Y;
Eigen::Matrix<float, 3, 3> M;
Eigen::Matrix<float, 3, 3> X;

Y << dstPoint(0,0), dstPoint(1,0), dstPoint(2,0),
dstPoint(0,1), dstPoint(1,1), dstPoint(2,1),
1, 1, 1;

X << srcPoint(0,0), srcPoint(1,0), srcPoint(2,0),
srcPoint(0,1), srcPoint(1,1), srcPoint(2,1),
1, 1, 1;

M = Y * X.inverse(); // src -> dst

// apply transform
Eigen::Matrix<float, 3, 1> srcP;
Eigen::Matrix<float, 3, 1> dstP;
float x, y, tl, tr, dl, dr;
int x_, y_;
for(int row=0; row<dstImg.rows; row++){
for(int col=0; col<dstImg.cols; col++){
dstP << row, col, 1;
srcP = M * dstP;
x = srcP[0];
y = srcP[1];
x_ = int(x);
y_ = int(y);

cv::Vec3b val = (1-(x-x_))*(1-(y-y_))*srcImg.at<cv::Vec3b>(row, col) +
(1-(x-x_))*(y-y_)*srcImg.at<cv::Vec3b>(row, col+1) +
(x-x_)*(1-(y-y_))*srcImg.at<cv::Vec3b>(row+1, col) +
(x-x_)*(y-y_)*srcImg.at<cv::Vec3b>(row+1, col+1);

dstImg.at<cv::Vec3b>(row, col) = val;

}
}
}
0%