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

歡迎訪問 生活随笔!

生活随笔

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

编程问答

图像透视变换应用

發布時間:2024/1/1 编程问答 36 豆豆
生活随笔 收集整理的這篇文章主要介紹了 图像透视变换应用 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

簡介

透視變換是將成像投影到一個新的視平面,也稱作投影映射。投影變換是三維空間上的非線性變換,可看做是仿射變換的更一般形式,簡單講即通過一個3x3的變換矩陣將原圖投影到一個新的視平面(Viewing Plane),在視覺上的直觀表現就是產生或消除了遠近感。

OpenCV透視變換的透視變換

1、warpPerspective

利用透視矩陣對圖像進行透視變換

  • 說明
    OpenCV提供了warpPerspective( )函數來實現圖片的透視變換,只需要輸入梯形四個頂點的坐標和目標畫布四個角的坐標,即可自動完成轉換。核心代碼只有兩行:首先讀取兩個坐標數組,計算變換矩陣;然后根據變換矩陣對原圖進行透視變換,并輸出到目標畫布。

    函數warpPerspective使用指定的矩陣轉換源圖像:
    dst(x,y)=src(M11x+M12y+M13M31x+M32y+M33,M21x+M22y+M23M31x+M32y+M33)\texttt{dst} (x,y) = \texttt{src} \left ( \frac{M_{11} x + M_{12} y + M_{13}}{M_{31} x + M_{32} y + M_{33}} , \frac{M_{21} x + M_{22} y + M_{23}}{M_{31} x + M_{32} y + M_{33}} \right ) dst(x,y)=src(M31?x+M32?y+M33?M11?x+M12?y+M13??,M31?x+M32?y+M33?M21?x+M22?y+M23??)
    當設置標志WARP_INVERSE_MAP時。否則,首先使用invert反轉轉換,然后將其放在上面的公式中,而不是M中。

  • 聲明

    void warpPerspective(InputArray src,OutputArray dst,InputArray M,Size dsize,int flags=INTER_LINEAR,int borderMode= BORDER_CONSTANT,const Scalar &borderValue=Scalar() )
  • 參數

    src輸入圖像
    dst輸出圖像,其大小為dsize,并且類型與src相同。
    M3×3的轉換矩陣。
    dsize輸出圖像的尺寸大小。
    flags插值方法(INTER_LINEAR或INTER_NEAREST)與可選標志WARP_INVERSE_MAP的組合,設置M為逆變換(dst→src\texttt{dst}\rightarrow\texttt{src}dstsrc)。
    borderMode邊界補償方式,BORDER_CONSTANT 或者BORDER_REPLICATE
    borderValue邊界補償大小,常值,默認為0。

關于變換矩陣M,OpenCV提供兩種方法計算:

1.1、findHomography–計算透視矩陣

通過輸入和輸出圖像中兩組點計算透視矩陣

  • 說明
    查找兩個平面之間的透視轉換。
    通過變換前、后兩個平面的點尋找出一個單應性變換矩陣H:

    使得反投影誤差:
    ∑i(xi′?h11xi+h12yi+h13h31xi+h32yi+h33)2+(yi′?h21xi+h22yi+h23h31xi+h32yi+h33)2\sum _i \left ( x'_i- \frac{h_{11} x_i + h_{12} y_i + h_{13}}{h_{31} x_i + h_{32} y_i + h_{33}} \right )^2+ \left ( y'_i- \frac{h_{21} x_i + h_{22} y_i + h_{23}}{h_{31} x_i + h_{32} y_i + h_{33}} \right )^2i?(xi??h31?xi?+h32?yi?+h33?h11?xi?+h12?yi?+h13??)2+(yi??h31?xi?+h32?yi?+h33?h21?xi?+h22?yi?+h23??)2被最小化。

    如果參數方法設置為默認值0,則該函數使用所有點對通過簡單的最小二乘方案計算初始單應性估計。

    但是,如果不是所有的點對(srcPointsisrcPoints_isrcPointsi?, dstPointsidstPoints_idstPointsi?)都適合嚴格的透視圖轉換(也就是說,存在一些異常值),那么這個初始估計就會很差。在這種情況下,您可以使用三種健壯方法中的一種。RANSAC方法,LMeDS和 RHO嘗試許多不同的隨機對應點對的子集(四雙,共線雙被丟棄),估計單應性矩陣使用這個子集和一個簡單的最小二乘算法,然后計算計算單應性的質量/善良的數量(這是內圍層RANSAC或至少值重新投影誤差LMeDS)。然后使用最佳子集生成單應矩陣的初始估計inliers/outliers的掩碼。

    無論采用何種方法,無論是否健壯,都可以使用Levenberg-Marquardt方法進一步精簡計算出的單應性矩陣(僅在穩健方法中使用inliers),以進一步降低重投影誤差。

    RANSAC和RHO的方法幾乎可以處理任何異常值比率,但是需要一個閾值來區分異常值和異常值。LMeDS方法不需要任何閾值,但是只有在有超過50%的內部值時,它才能正確運行。最后,如果沒有異常值并且噪聲很小,請使用默認方法(method= 0)。

  • 聲明

    Mat findHomography( InputArray srcPoints, InputArray dstPoints,int method = 0, double ransacReprojThreshold = 3,OutputArray mask=noArray(), const int maxIters = 2000,const double confidence = 0.995 );Mat findHomography(InputArray srcPoints, InputArray dstPoints,OutputArray mask, int method = 0, double ransacReprojThreshold =3 );
  • 參數

    srcPoint原始平面中點的坐標,其類型為CV_32FC2或vector 的矩陣。
    dstPoint目標平面中點的坐標,類型為CV_32FC2的矩陣或vector 。
    method用于計算單應矩陣的方法。
    ransacReprojThreshold
    mask通過可靠的方法(RANSAC或LMEDS)設置的可選輸出掩碼。請注意,輸入掩碼值將被忽略。
    maxItersRANSAC的最大迭代次數。
    confidence置信度,介于0和1之間。
    method取值
    • 0: 使用所有點的常規方法,即最小二乘法
    • RANSAC: 基于RANSAC的魯棒方法
    • LMEDS: 最小中值穩健方法
    • RHO: 基于PROSAC穩健的方法
1.2、getPerspectiveTransform–根據四對對應點計算透視變換

通過原圖和變換后圖像的4個對應點(即對應的四邊形)計算出透視變換矩陣。

  • 說明
    The function calculates the 3×3 matrix of a perspective transform so that:

  • 聲明

    Mat cv::getPerspectiveTransform ( InputArray src,InputArray dst,int solveMethod = DECOMP_LU ) Mat cv::getPerspectiveTransform ( const Point2f src[],const Point2f dst[],int solveMethod = DECOMP_LU )
  • 參數

    src源圖像中四邊形頂點的坐標。
    dst目標圖像中相應四邊形頂點的坐標。
    solveMethod傳遞給cv :: solve(DecompTypes)的方法。
2、perspectiveTransform–點的透視變換

利用透視矩陣對點進行透視變換。

  • 說明
    執行向量的透視矩陣轉換。

    函數cv :: perspectiveTransform通過將src的每個元素視為2D或3D向量來對其進行轉換,其方式如下:

    這里顯示了3D矢量變換。在2D矢量變換的情況下,將省略z分量。

    該函數轉換2D或3D向量的稀疏集合。如果要使用透視變換來變換圖像,請使用warpPerspective。如果存在反問題,也就是說,您想從幾對對應點中計算出最可能的透視變換,則可以使用getPerspectiveTransform或findHomography。

  • 聲明

    void perspectiveTransform( InputArray src,OutputArray dst,InputArray m )
  • 參數

    src輸入兩通道或三通道浮點數組;每個元素都是要轉換的2D / 3D向量。
    dst與src具有相同大小和類型的輸出數組。
    m3x3或4x4浮點轉換矩陣。

應用

?簡單變換

void onMouse(int event, int x, int y, int flags, void* utsc) {if (event==EVENT_LBUTTONUP){//畫出源圖像中需要透視到四邊形中的4個待轉換點circle(src2, Point(x, y), 2, Scalar(0, 0, 255), 2);imshow("wait", src2);//記錄原圖中待轉換的點坐標srcTri[clickTimes].x = x;srcTri[clickTimes].y = y;clickTimes++;cout << "The" << clickTimes << " point: [ " << srcTri[clickTimes - 1].x << "," << srcTri[clickTimes - 1].y << "]" << endl;}if (clickTimes == 4) {//將原圖像中的四個點轉換到目的圖形的對應四個點上//第一個點——左上角dstTri[0].x = 0;dstTri[0].y = 0;//第二個點——右上角dstTri[1].x = 480;dstTri[1].y = 0;//第三個點——右下角dstTri[2].x = 480;dstTri[2].y = 600;//第四個點——左下角dstTri[3].x = 0;dstTri[3].y = 600;//通過原圖像和目標圖像中4個對應點求出透視矩陣Mat m = findHomography(srcTri, dstTri, RANSAC);warpPerspective(src, dst, m, Size(480, 600));imshow("dst", dst);} }int main() {src = imread("D:/test/m.png");src2 = src.clone();namedWindow("src", WINDOW_AUTOSIZE);imshow("src", src2);setMouseCallback("src", onMouse);waitKey(0);return 0; }



注意:需要注意透視變換中點與點的對應順序,應該順時針方向進行點的轉換。

?復雜的透視變換
可以結合第一個應用的方式,使用點擊事件進行獲取需要在目標圖片上轉換的具體坐標。

void warpPerspectiveTest() {//1 讀取廣告圖Mat src = imread("D:/test/src.jpg");imshow("src", src);//2 讀取廣告牌背景圖Mat bg = imread("D:/test/bg.jpg");Mat bg_temp = bg.clone();imshow("bg", bg);//3 透視變換4對坐標確定vector<Point2f> srcTri(4), dstTri(4);//3.1 源圖的四個坐標srcTri[0].x = 0;srcTri[0].y = 0;srcTri[1].x = src.cols-1;srcTri[1].y = 0;srcTri[2].x = src.cols-1;srcTri[2].y = src.rows-1;srcTri[3].x = 0;srcTri[3].y = src.rows-1;//3.2 目標圖片的四個坐標//用畫圖工具測試的4個點的像素坐標dstTri[0].x = 218;dstTri[0].y = 31;dstTri[1].x = 392;dstTri[1].y = 182;dstTri[2].x = 399;dstTri[2].y = 258;dstTri[3].x = 218;dstTri[3].y = 194;//4 求出透視變換的矩陣//Mat m=getPerspectiveTransform(srcTri, dstTri);Mat m = findHomography(srcTri, dstTri);//5 進行透視變換warpPerspective(src, bg_temp, m, bg.size());imshow("bg_temp", bg_temp);//fillConvexPoly(InputOutputArray img, const Point * pts, int npts,// const Scalar & color, int lineType = LINE_8,// int shift = 0);Point pt[4];for (size_t i = 0; i < 4; i++){pt[i] = dstTri[i];}//6 在目標圖像中去除多邊形區域,并合并fillConvexPoly(bg, pt, 4,Scalar(0));Mat dst;add(bg,bg_temp , dst);imshow("dst", dst); }





?自動檢測源映射坐標
上面都是手動或者自己輸入的變換源坐標,下面讓計算機自己檢測需要的4個坐標。
步驟:

  • 圖片預處理
    1.1 灰度
    1.2 二值化分割
    1.3 去噪聲
    1.4 閉操作
  • 尋找輪廓
  • 霍夫直線檢測
  • 定位邊沿輪廓直線
  • 直線方程
  • 直線交點
  • 透視矩陣
  • 透視變換
  • void warpPerspectiveTest2() {Mat src = imread("D:/test/kak.png");imshow("src", src);//1. 圖片預處理//1.1 灰度化Mat gray_src;cvtColor(src, gray_src, COLOR_BGR2GRAY);//1.2 去噪聲blur(gray_src, gray_src, Size(3, 3));//1.3 二值化Mat binary_src;threshold(gray_src, binary_src, 0, 255, THRESH_BINARY_INV|THRESH_OTSU);imshow("binary_src", binary_src);//1.4 閉操作Mat closed_src;Mat kernel = getStructuringElement(MORPH_RECT, Size(3, 3));morphologyEx(binary_src, closed_src, MORPH_CLOSE,kernel );imshow("closed_src", closed_src);//2. 尋找輪廓vector<vector<Point>> contours;Mat draw = Mat::zeros(src.size(), src.type());//注意尋找輪廓的方法,只尋找最外圍的輪廓findContours(closed_src, contours, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE);//2.1 遍歷每一個輪廓for (size_t i = 0; i < contours.size(); i++){Rect rect = boundingRect(contours[i]);if (rect.width < src.cols / 2 && rect.height < src.rows / 2)continue;//2.2 畫出篩選后的輪廓drawContours(draw, contours, i, Scalar(0, 0, 255),3);}imshow("draw", draw);//3. 霍夫直線檢測--為了匹配四個邊vector<Vec4i> lines;cvtColor(draw, draw, COLOR_BGR2GRAY);//Each line is represented by a 4-element vector,(x1, y1, x2, y2), where (x1,y1)and(x2, y2)are the ending points of each detected//3.1 找出所有的直線HoughLinesP(draw, lines, 1, CV_PI / 180, src.rows / 2, src.rows / 2, 0);Mat draw2 = Mat::zeros(src.size(), src.type());for (int j = 0; j < lines.size(); j++) {Vec4i ln = lines[j];//3.2 畫出所有的直線line(draw2, Point(ln[0], ln[1]), Point(ln[2], ln[3]), Scalar(0, 255, 0), 2);}cout << "lines.size=" << lines.size() << endl;imshow("draw2", draw2);//4. 定位邊沿輪廓直線Vec4i topLine, bottomLine, leftLine, rightLine;for (size_t i = 0; i < lines.size(); i++){Vec4i ln = lines[i];//4.1找最左側的直線,確定左側直線的兩個點的橫坐標在圖像中心的左側區域if (ln[0] < src.cols / 2 && ln[2] < src.cols / 2) {leftLine = ln;}//4.2找頂部的直線,確定頂部直線的兩個點的縱坐標在圖像中心的上方區域內if (ln[1] < src.rows / 2 && ln[3] < src.rows / 2) {topLine = ln;}//4.3找最右側的直線,確定右側直線的兩個點的橫坐標在圖像中心的右側區域if (ln[0] > src.cols / 2 && ln[2] > src.cols / 2) {rightLine = ln;}//4.4找底部的直線,確定底部直線的兩個點的縱坐標在圖像中心的下方區域內if (ln[1] > src.rows / 2 && ln[3] > src.rows / 2) {bottomLine = ln;}}cout << "leftLine:p1(x,y)=" << leftLine[0] << "," << leftLine[1] << " " << "p2(x,y)=" << leftLine[2] << "," << leftLine[3] << endl;cout << "topLine:p1(x,y)=" << topLine[0] << "," << topLine[1] << " " << "p2(x,y)=" << topLine[2] << "," << topLine[3] << endl;cout << "rightLine:p1(x,y)=" << rightLine[0] << "," << rightLine[1] << " " << "p2(x,y)=" << rightLine[2] << "," << rightLine[3] << endl;cout << "bottomLine:p1(x,y)=" << bottomLine[0] << "," << bottomLine[1] << " " << "p2(x,y)=" << bottomLine[2] << "," << bottomLine[3] << endl;//5. 直線方程//5.1求出左側直線的方程 y=kx+b: k=(y2-y1)/(x2-x1) b=y-kx double kl = double(leftLine[3] - leftLine[1]) / double(leftLine[2] - leftLine[0]);double bl = double(leftLine[1] - kl * leftLine[0]);//5.2求出頂側直線的方程 double kt = double(topLine[3] - topLine[1]) / double(topLine[2] - topLine[0]);double bt = double(topLine[1] - kt * topLine[0]);//5.3求出右側直線的方程 double kr = double(rightLine[3] - rightLine[1]) / double(rightLine[2] - rightLine[0]);double br = double(rightLine[1] - kr * rightLine[0]);//5.4求出底部直線的方程 double kb = double(bottomLine[3] - bottomLine[1]) / double(bottomLine[2] - bottomLine[0]);double bb = double(bottomLine[1] - kb * bottomLine[0]);//6. 直線交點Point p1, p2, p3, p4;//6.1左側直線和頂部直線的交點: x=(b2-b1)/(k1-k2) y=k1*x+b1p1.x = int((bt - bl) / (kl - kt));p1.y = int(kl * p1.x + bl);//6.2頂部直線和右側直線的交點p2.x = int((br - bt) / (kt - kr));p2.y = int(kt * p2.x + bt);//6.3右側直線和底部直線的交點p3.x = int((bb - br) / (kr - kb));p3.y = int(kr * p3.x + br);//6.4底部直線和左側直線的交點p4.x = int((bl - bb) / (kb - kl));p4.y = int(kb * p4.x + bb);cout << "左上角:[" << p1.x << "," << p1.y <<"]"<< endl;cout << "右上角:[" << p2.x << "," << p2.y <<"]"<< endl;cout << "右下角:[" << p3.x << "," << p3.y <<"]"<< endl;cout << "左下角:[" << p4.x << "," << p4.y <<"]"<< endl;//6.5畫出交點circle(draw2, p1, 2, Scalar(0, 0, 255));circle(draw2, p2, 2, Scalar(0, 0, 255));circle(draw2, p3, 2, Scalar(0, 0, 255));circle(draw2, p4, 2, Scalar(0, 0, 255));imshow("draw2-point", draw2);//7. 透視矩陣 //將檢測出來的4個點變換到新的對應的4個點坐標//7.1源圖像的四個待映射的點vector<Point2f> srcTri(4);srcTri[0] = p1;srcTri[1] = p2;srcTri[2] = p3;srcTri[3] = p4;//7.2目標圖像中相對應的點vector<Point2f> dstTri(4);dstTri[0] = Point(0, 0);dstTri[1] = Point(src.cols, 0);dstTri[2] = Point(src.cols, src.rows);dstTri[3] = Point(0, src.rows);//7.3獲取透視變換的矩陣Mat m_FindH=findHomography(srcTri, dstTri);Mat m_getPT=getPerspectiveTransform(srcTri, dstTri);//8 透視變換Mat dst_findH = Mat::zeros(src.size(), src.type());Mat dst_getPT = Mat::zeros(src.size(), src.type());warpPerspective(src, dst_findH, m_FindH, src.size());warpPerspective(src, dst_getPT, m_FindH, src.size());imshow("dst_findH", dst_findH);imshow("dst_getPT", dst_getPT);}









    學習:
    【OpenCV3.3】通過透視變換矯正變形圖像

    Opencv日常之Homography

    【OpenCV】透視變換 Perspective Transformation(續)

    【圖像處理】透視變換 Perspective Transformation

    圖像透視變換原理及實現

    詳解 OpenCV 透視變換原理 及 實例

    【圖像處理】透視變換 Perspective Transformation

    opencv學習筆記五十:透視變換綜合實例

    總結

    以上是生活随笔為你收集整理的图像透视变换应用的全部內容,希望文章能夠幫你解決所遇到的問題。

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