日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

图像校正-仿射图像的畸变校正

發布時間:2024/1/18 编程问答 44 豆豆
生活随笔 收集整理的這篇文章主要介紹了 图像校正-仿射图像的畸变校正 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

仿射變換

原始平面經過仿射變換后,兩直線夾角會發生變化,產生畸變,如下圖
仿射變換的變換矩陣為:

可以簡寫為:

對偶于圓點(circular point)的圓錐曲線為:


如果直線 l 和 m 在原平面上垂直,那么有:

對于仿射變換的平面,可以推導出如下等式:

其中(l1’, l2’, l3’)、(m1’, m2’, m3’)分別為直線 l 和 m 的齊次坐標,令:

進而可以得到等式:

再令:

可以得到:

向量 s 具有兩個自由度,因此只需要兩個方程就能求解,進而需要找到兩對在原平面互相垂直的直線。求解出向量 s 后,矩陣 S 、 K 也都能對應求解,然后代入仿射變換矩陣中,對圖像平面進行逆變換,就能夠消除仿射畸變。

校正步驟

仿射畸變校正是在投影畸變校正的基礎上進行的,我的上一篇筆記記錄了投影畸變校正的一些方法(https://blog.csdn.net/qq_44226964/article/details/121549545?spm=1001.2014.3001.5501)。
首先在圖像上選取兩組垂直線,其中 a ⊥ b ,c ⊥ d ,每條直線上至少找兩個點以確定直線方程,如下圖所示:

在求出兩組垂直線的齊次坐標后,代入

中,建立二元一次方程組(可以令S22 = 1),解出向量 s 以及矩陣 S ,矩陣 K 使用 cholesky分解 的方法求解,最后得到仿射變換矩陣 Ha,求出 Ha 的逆矩陣后,就能對原圖像進行逆變換了。
最終結果如下圖,從上到下依次為 原圖、投影校正、仿射校正:

代碼

代碼中使用到的部分函數是投影校正里面的函數,在前面的文章中有,下面就沒有給出來了。

void RectifyAffine() {Mat src = imread("rectfing_projection.jpg", IMREAD_GRAYSCALE);IplImage* src2 = cvLoadImage("rectfing_projection.jpg");//使用鼠標獲取點的坐標//GetMouse(src2);//手動輸入上面獲取的8個點,每四個點確定一組垂直線Point3d points_3d_8[8] = { Point3d(23, 71, 1), Point3d(101, 126, 1) ,Point3d(101, 126, 1) ,Point3d(238, 76, 1),Point3d(50, 91, 1), Point3d(196, 91, 1), Point3d(141, 59, 1), Point3d(101, 126, 1) };//傳入點和圖像進行校正RectifyByOrthogonal( points_3d_8, src); }void RectifyByOrthogonal(Point3d points[8], Mat src) {//通過輸入的8個點得到4條連線vector<vector<float>> lines;int num_lines = 4;for (int i = 0; i < num_lines; i++){//獲取兩點連線GetLineFromPoints(points[2 * i], points[2 * i + 1], lines);}//使用兩組正交直線求解仿射變換矩陣(l1'm1', l1'm2'+l2'm1', l2'm2')s = 0//先求s=(s11,s12,s22)vector<vector<float>> coefficients;for (int i = 0; i < 2; i++){vector<float> coefficient;coefficient.push_back(lines[i * 2][0] * lines[i * 2 + 1][0]);coefficient.push_back(lines[i * 2][0] * lines[i * 2 + 1][1] + lines[i * 2][1] * lines[i * 2 + 1][0]);coefficient.push_back(lines[i * 2][1] * lines[i * 2 + 1][1]);coefficients.push_back(coefficient);}vector<float> s;ComputeEquationSet(coefficients, s);//計算K矩陣 S = KKT,使用Cholesky分解的方法vector<float> K;ComputeCholesky(s, K);//仿射變換矩陣Hafloat Ha[3][3] = { {1, 0, 0}, {0, 1, 0}, {0, 0, 1} };Ha[0][0] = 1 / K[0];Ha[0][1] = 0;Ha[1][0] = - K[2] / K[0];Ha[1][1] = 1;Mat image = Mat::zeros(src.rows, src.cols, CV_8UC1);GetRectifingImage1(Ha, src, image); }void ComputeEquationSet(vector<vector<float>> coefficients, vector<float> &result) {float a0 = coefficients[0][0];float b0 = coefficients[0][1];float c0 = coefficients[0][2];float a1 = coefficients[1][0];float b1 = coefficients[1][1];float c1 = coefficients[1][2];float s12 = (a0 * c1 - a1 * c0) / (a1 * b0 - a0 * b1);float s11 = -(b0 * s12 + c0) / a0;float s22 = 1;result.push_back(s11);result.push_back(s12);result.push_back(s22); }void ComputeCholesky(vector<float> s, vector<float> &K) {float s11 = s[0];float s12 = s[1];float s22 = s[2];float x11 = sqrt(s11);float x21 = s12 / s11 * x11;float x22 = sqrt(1 - x21 * x21);//歸一化x11 = x11 / x22;x21 = x21 / x22;x22 = 1;K.push_back(x11);K.push_back(0);K.push_back(x21);K.push_back(x22); }void GetRectifingImage1( float H[3][3], Mat& src, Mat dst) {Size size_src = src.size();for (int i = 0; i < size_src.height; i++){for (int j = 0; j < size_src.width; j++){float x3 = 1;int x1 = Round(j * H[0][0] / x3);int x2 = Round((j * H[1][0] + i) / x3);if (x1 < size_src.width && x1 >= 0 && x2 < size_src.height && x2 >= 0){dst.at<uint8_t>(x2, x1) = src.at<uint8_t>(i, j);}}}imshow("src1", src);imshow("dst", dst);waitKey(0);src = dst.clone(); }

總結

以上是生活随笔為你收集整理的图像校正-仿射图像的畸变校正的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。