perspective transform透视矩阵快速求法+矩形矫正
算了半天一直在思考如何快速把矩阵算出来,网上基本都是在说边长为1的正方形的变换方式=。= 不怎么用得上…… 公式推导推半天,计算还麻烦。。。。
++++++++++++++++++++++++++++++
对于透视变换:
其中我们在使用的时候最重要的是算出系数…………………… 这里我们按照i=1计算
找了半天找到了这一篇论文:http://www.ixueshu.com/document/027c165d22e18077318947a18e7f9386.html
里面提到我们可以将公式
改写成的模式。
那么根据矩形矫正前后的8个顶点可以得到公式:
那么只要计算中间8x8矩阵的逆,乘上变换后的uv矩阵,就可以求出所有待定系数。其中点的检测需要用到hough算法,点和点之间的对应我做了个交互,不然太麻烦了。。。。
矩阵求逆代码:其中N为8
1 #include <iostream> 2 using namespace std; 3 #define N 8 //测试矩阵维数定义 4 5 //按第一行展开计算|A| 6 double getA(double arcs[N][N], int n) 7 { 8 if (n == 1) 9 { 10 return arcs[0][0]; 11 } 12 double ans = 0; 13 double temp[N][N] = { 0.0 }; 14 int i, j, k; 15 for (i = 0; i<n; i++) 16 { 17 for (j = 0; j<n - 1; j++) 18 { 19 for (k = 0; k<n - 1; k++) 20 { 21 temp[j][k] = arcs[j + 1][(k >= i) ? k + 1 : k]; 22 23 } 24 } 25 double t = getA(temp, n - 1); 26 if (i % 2 == 0) 27 { 28 ans += arcs[0][i] * t; 29 } 30 else 31 { 32 ans -= arcs[0][i] * t; 33 } 34 } 35 return ans; 36 } 37 38 //计算每一行每一列的每个元素所对应的余子式,组成A* 39 void getAStart(double arcs[N][N], int n, double ans[N][N]) 40 { 41 if (n == 1) 42 { 43 ans[0][0] = 1; 44 return; 45 } 46 int i, j, k, t; 47 double temp[N][N]; 48 for (i = 0; i<n; i++) 49 { 50 for (j = 0; j<n; j++) 51 { 52 for (k = 0; k<n - 1; k++) 53 { 54 for (t = 0; t<n - 1; t++) 55 { 56 temp[k][t] = arcs[k >= i ? k + 1 : k][t >= j ? t + 1 : t]; 57 } 58 } 59 60 61 ans[j][i] = getA(temp, n - 1); //此处顺便进行了转置 62 if ((i + j) % 2 == 1) 63 { 64 ans[j][i] = -ans[j][i]; 65 } 66 } 67 } 68 } 69 70 //得到给定矩阵src的逆矩阵保存到des中。 71 bool GetMatrixInverse(double src[N][N], int n, double des[N][N]) 72 { 73 double flag = getA(src, n); 74 double t[N][N]; 75 if (0 == flag) 76 { 77 cout << "原矩阵行列式为0,无法求逆。请重新运行" << endl; 78 return false;//如果算出矩阵的行列式为0,则不往下进行 79 } 80 else 81 { 82 getAStart(src, n, t); 83 for (int i = 0; i<n; i++) 84 { 85 for (int j = 0; j<n; j++) 86 { 87 des[i][j] = t[i][j] / flag; 88 } 89 90 } 91 } 92 93 return true; 94 }
主函数内代码:(仅部分)
vector<pair<int, int>> P ,newPoint; //P 变换后标准A4的点 newPoint 变换前的点 计算时候计算变换后变换到变换前 //省略中间数值插入和输出图片构成 P.push_back(make_pair(0, 0)); P.push_back(make_pair((int)len1, 0)); P.push_back(make_pair((int)len1, (int)len2)); P.push_back(make_pair(0, (int)len2)); int uv[8] = { newPoint[0].first, newPoint[0].second, newPoint[1].first, newPoint[1].second, newPoint[2].first, newPoint[2].second, newPoint[3].first, newPoint[3].second }; double src[8][8] = { { P[0].first, P[0].second, 1, 0, 0, 0, -newPoint[0].first*P[0].first, -newPoint[0].first*P[0].second }, { 0, 0, 0, P[0].first, P[0].second, 1, -newPoint[0].second*P[0].first, -newPoint[0].second*P[0].second }, { P[1].first, P[1].second, 1, 0, 0, 0, -newPoint[1].first*P[1].first, -newPoint[1].first*P[1].second }, { 0, 0, 0, P[1].first, P[1].second, 1, -newPoint[1].second*P[1].first, -newPoint[1].second*P[1].second }, { P[2].first, P[2].second, 1, 0, 0, 0, -newPoint[2].first*P[2].first, -newPoint[2].first*P[2].second }, { 0, 0, 0, P[2].first, P[2].second, 1, -newPoint[2].second*P[2].first, -newPoint[2].second*P[2].second }, { P[3].first, P[3].second, 1, 0, 0, 0, -newPoint[3].first*P[3].first, -newPoint[3].first*P[3].second }, { 0, 0, 0, P[3].first, P[3].second, 1, -newPoint[3].second*P[3].first, -newPoint[3].second*P[3].second } }; double matrix_after[N][N]{}; bool flag = GetMatrixInverse(src, N, matrix_after); if (false == flag) { cout << "求不出系数" << endl; return; } cout << "逆矩阵:" << endl; for (int i = 0; i<8; i++) { for (int j = 0; j<8; j++) { cout << matrix_after[i][j] << " "; //cout << *(*(matrix_after+i)+j)<<" "; } cout << endl; } double xs[8]; for (int i = 0; i < 8; i++) { double sum = 0; for (int t = 0; t < 8; t++) { sum += matrix_after[i][t] * uv[t]; } xs[i] = sum; } //矩形矫正 没有用双线性插值 cimg_forXY(outputimg, x, y) { double px = xs[0] * x + xs[1] * y + xs[2]; double py = xs[3] * x + xs[4] * y + xs[5]; double p = xs[6] * x + xs[7] * y + 1; int u = px / p; int v = py / p; outputimg(x, y, 0) = paint(u, v, 0); outputimg(x, y, 1) = paint(u, v, 1); outputimg(x, y, 2) = paint(u, v, 2); }
以上~
基本实验了一下:
结果:
还可以吧。。。
SYSU 软工数媒 欢迎交流。。。
gayhub : https://github.com/azikk