主要涉及兩個函數。
第一個,findHomography
計算多個二維點對之間的最優單映射變換矩陣 H(3行x3列) ,使用最小均方誤差或者RANSAC方法。函數功能:找到兩個平面之間的轉換矩陣。
Mat cv::findHomography ( InputArray srcPoints,
InputArray dstPoints,
int method = 0,
double ransacReprojThreshold = 3,
OutputArray mask = noArray(),
const int maxIters = 2000,
const double confidence = 0.995
)
參數詳解:
srcPoints | 源平面中點的座標矩陣,可以是CV_32FC2類型,也可以是vector<Point2f>類型 |
dstPoints | 目標平面中點的座標矩陣,可以是CV_32FC2類型,也可以是vector<Point2f>類型 |
method | 計算單應矩陣所使用的方法。不同的方法對應不同的參數,具體如下:
|
ransacReprojThreshold |
將點對視爲內點的最大允許重投影錯誤閾值(僅用於RANSAC和RHO方法)。如果 則點被認爲是個外點(即錯誤匹配點對)。若srcPoints和dstPoints是以像素爲單位的,則該參數通常設置在1到10的範圍內。 |
mask | 可選輸出掩碼矩陣,通常由魯棒算法(RANSAC或LMEDS)設置。 請注意,輸入掩碼矩陣是不需要設置的。 |
maxIters | RANSAC算法的最大迭代次數,默認值爲2000。 |
confidence | 可信度值,取值範圍爲0到1. |
第二個,warpPerspective
通過輸入變換矩陣得到透視圖片。
void cv::warpPerspective(InputArray src,
OutputArray dst,
InputArray M,
Size dsize,
int flags = INTER_LINEAR,
int borderMode = BORDER_CONSTANT,
const Scalar &borderValue = Scalar()
)
參數詳解:
src | 輸入圖片 |
dst | 輸出圖片 |
M | 輸入的透視變換矩陣,大小是3*3 |
dsize | 輸出圖片的大小 |
flags | 插值方法(INTER_LINEAR或INTER_NEAREST)與可選標誌WARP_INVERSE_MAP的組合,將M設置爲逆變換(𝚍𝚜𝚝→𝚜𝚛𝚌)。 |
borderMode | 邊界像素賦值操作(BORDER_CONSTANT or BORDER_REPLICATE),前者是定值,後者是複製周圍像素。 |
borderValue | 指定定值具體是那個值,默認是0 |
具體例子
透視變換同時獲取ROI,代碼如下:
#include<opencv2/opencv.hpp>
using namespace cv;
using namespace std;
struct callbackP
{
Mat src;
int clickTimes = 0; //在圖像上單擊次數
vector<Point2f> srcTri;
};
void onMouse(int event, int x, int y, int flags, void *utsc)
{
callbackP cp = *(callbackP*)utsc; // 先轉換類型,再取數據
if (event == EVENT_LBUTTONUP) //響應鼠標左鍵事件
{
circle((*(callbackP*)utsc).src, Point(x, y), 2, Scalar(0, 0, 255), 2); //標記選中點
imshow("wait ", (*(callbackP*)utsc).src);
(*(callbackP*)utsc).srcTri.push_back(Point2f(x, y));
cout << "x:" << x << " " << "y:" << y << endl;
(*(callbackP*)utsc).clickTimes++;
if ((*(callbackP*)utsc).clickTimes == 4)
{
cout << "按任意鍵繼續!" << endl;
}
}
}
int main(int argc, char *argv[])
{
vector<Point2f> dstTri(4);
Mat dst;
callbackP utsc;
utsc.src = imread("3.jpg");
namedWindow("src", WINDOW_AUTOSIZE);
imshow("src", utsc.src);
cout << "從需要透視變換區域的左上角開始,順時針依次點矩形的四個角!" << endl;
setMouseCallback("src", onMouse, (void*)&utsc); //類型轉換
waitKey();
if (utsc.clickTimes == 4)
{
dstTri[0].x = 0;
dstTri[0].y = 0;
dstTri[1].x = utsc.srcTri[1].x - utsc.srcTri[0].x;
dstTri[1].y = 0;
dstTri[2].x = utsc.srcTri[1].x - utsc.srcTri[0].x;
dstTri[2].y = utsc.srcTri[2].y - utsc.srcTri[1].y;
dstTri[3].x = 0;
dstTri[3].y = utsc.srcTri[2].y - utsc.srcTri[1].y;
//計算透視矩陣
Mat M = findHomography(utsc.srcTri, dstTri, RANSAC);
//圖像透視變換
warpPerspective(utsc.src, dst, M, Size((utsc.srcTri[1].x - utsc.srcTri[0].x), (utsc.srcTri[2].y - utsc.srcTri[1].y)));
imshow("output", dst);
imwrite("3p.jpg", dst);
cout << "透視變換矩陣:"<< M << endl;
waitKey();
}
else {
cout << "需要從左上角開始,順時針依次點矩形的四個角!" << endl;
cout << "現在點擊了" <<utsc.clickTimes << "次" <<endl;
}
return 0;
}
網上隨便找一張圖片,效果如下:注意,用鼠標描點時從左上角開始,順時針依次進行
只進行透視變換,代碼如下:
#include<opencv2/opencv.hpp>
using namespace cv;
using namespace std;
struct callbackP
{
Mat src;
int clickTimes = 0; //在圖像上單擊次數
vector<Point2f> srcTri;
};
void onMouse(int event, int x, int y, int flags, void *utsc)
{
callbackP cp = *(callbackP*)utsc; // 先轉換類型,再取數據
if (event == EVENT_LBUTTONUP) //響應鼠標左鍵事件
{
circle((*(callbackP*)utsc).src, Point(x, y), 2, Scalar(0, 0, 255), 2); //標記選中點
imshow("wait ", (*(callbackP*)utsc).src);
(*(callbackP*)utsc).srcTri.push_back(Point2f(x, y));
cout << "x:" << x << " " << "y:" << y << endl;
(*(callbackP*)utsc).clickTimes++;
if ((*(callbackP*)utsc).clickTimes == 4)
{
cout << "按任意鍵繼續!" << endl;
}
}
}
int main(int argc, char *argv[])
{
vector<Point2f> dstTri(4);
Mat dst;
callbackP utsc;
utsc.src = imread("3.jpg");
namedWindow("src", WINDOW_AUTOSIZE);
imshow("src", utsc.src);
cout << "從需要透視變換區域的左上角開始,順時針依次點矩形的四個角!" << endl;
setMouseCallback("src", onMouse, (void*)&utsc); //類型轉換
waitKey();
if (utsc.clickTimes == 4)
{
dstTri[0].x = utsc.srcTri[0].x;
dstTri[0].y = utsc.srcTri[0].y;
dstTri[1].x = utsc.srcTri[1].x;
dstTri[1].y = utsc.srcTri[0].y;
dstTri[2].x = utsc.srcTri[1].x;
dstTri[2].y = utsc.srcTri[2].y;
dstTri[3].x = utsc.srcTri[0].x;
dstTri[3].y = utsc.srcTri[2].y;
//計算透視矩陣
Mat M = findHomography(utsc.srcTri, dstTri, RANSAC);
//圖像透視變換
warpPerspective(utsc.src, dst, M, utsc.src.size());
imshow("output", dst);
imwrite("3pp.jpg", dst);
cout << "透視變換矩陣:"<< M << endl;
waitKey();
}
else {
cout << "需要從左上角開始,順時針依次點矩形的四個角!" << endl;
cout << "現在點擊了" <<utsc.clickTimes << "次" <<endl;
}
return 0;
}
效果圖:
參考博客:
https://blog.csdn.net/fengyeer20120/article/details/87798638