目录
- 前言
- 一、图像预处理
- 二、轮廓提取
- 1.提取最外轮廓
- 2.提取矩形四个角点
- 3.将矩形角点排序
- 三、透视矫正
- 四、源码
前言
c/c++开发分享C++ OpenCV实战之图像透视矫正将使用opencv c++ 进行图像透视矫正。
一、图像预处理
原图如图所示。首先进行图像预处理。将图像进行灰度、滤波、二值化、形态学等操作,目的是为了下面的轮廓提取。在这里我还使用了形态学开、闭操作,目的是使整个二值图像连在一起。大家在做图像预处理时,可以根据图像特征自行处理。
mat gray; cvtcolor(src, gray, color_bgr2gray); mat gaussian; gaussianblur(gray, gaussian, size(3, 3), 0); mat thresh; threshold(gaussian, thresh, 0, 255, thresh_binary_inv | thresh_otsu); mat kernel = getstructuringelement(morph_rect, size(3, 3)); mat open; morphologyex(thresh, open, morph_open, kernel); mat kernel1 = getstructuringelement(morph_rect, size(7, 7)); mat close; morphologyex(open, close, morph_close, kernel1);
如图就是经过图像预处理得到的二值图像。
二、轮廓提取
1.提取最外轮廓
vector<vector<point>>contours; findcontours(close, contours, retr_external, chain_approx_simple);
使用findcontours、retr_external就可以提取出物体最外轮廓。
2.提取矩形四个角点
接下来将使用approxpolydp进行多边形轮廓拟合,目的是为了找到矩形的四个角点。关于approxpolydp api大家可以自行百度查看其用法。
vector<vector<point>>conpoly(contours.size()); vector<point>srcpts; for (int i = 0; i < contours.size(); i++) { double area = contourarea(contours[i]); if (area > 10000) { double peri = arclength(contours[i], true); approxpolydp(contours[i], conpoly[i], 0.02*peri, true); //获取矩形四个角点 srcpts = { conpoly[i][0],conpoly[i][1],conpoly[i][2],conpoly[i][3] }; } }
3.将矩形角点排序
由于我们之前使用的approxpolydp获取的角点是无序的,所以我们得确定各角点所在的位置。在这里我使用的算法是根据其角点所在图像位置特征确定左上、左下、右下、右上四个点。
int width = src.cols / 2; int height = src.rows / 2; int t_l, t_r, b_r, b_l; for (int i = 0; i < srcpts.size(); i++) { if (srcpts[i].x < width && srcpts[i].y < height) { t_l = i; } if (srcpts[i].x > width && srcpts[i].y < height) { t_r = i; } if (srcpts[i].x > width && srcpts[i].y > height) { b_r = i; } if (srcpts[i].x < width && srcpts[i].y > height) { b_l = i; } }
如图所示。至此已经完成了矩形四个角点的定位。接下来就可以使用透视变换进行图像矫正了。
三、透视矫正
在这里我们需要知道透视变换一个原理:
变换后,图像的长和宽应该变为:
长 = max(变换前左边长,变换前右边长)
宽 = max(变换前上边长,变换前下边长)
设变换后图像的左上角位置为原点位置。
double leftheight = eudis(srcpts[t_l], srcpts[b_l]) double rightheight = eudis(srcpts[t_r], srcpts[b_r]); double maxheight = max(leftheight, rightheight); double upwidth = eudis(srcpts[t_l], srcpts[t_r]); double downwidth = eudis(srcpts[b_l], srcpts[b_r]); double maxwidth = max(upwidth, downwidth);
确定变换后的长宽之后,就可以使用getperspectivetransform、warpperspective进行透视矫正了。
//这里使用的顺序是左上、右上、右下、左下顺时针顺序。srcaffinepts、dstaffinepts要一一对应 point2f srcaffinepts[4] = { point2f(srcpts[t_l]),point2f(srcpts[t_r]) ,point2f(srcpts[b_r]) ,point2f(srcpts[b_l]) }; point2f dstaffinepts[4] = { point2f(0,0),point2f(maxwidth,0),point2f(maxwidth,maxheight),point2f(0,maxheight) }; mat m = getperspectivetransform(srcaffinepts, dstaffinepts); mat dstimg; warpperspective(src, dstimg, m, point(maxwidth, maxheight));
这就是进行透视矫正之后的效果。
四、源码
#include<iostream> #include<opencv2/opencv.hpp> using namespace std; using namespace cv; double eudis(point pt1, point pt2) { return sqrt((pt2.x - pt1.x)*(pt2.x - pt1.x) + (pt2.y - pt1.y)*(pt2.y - pt1.y)); } int main() { mat src = imread("1.jpg"); if (src.empty()) { cout << "no image!" << endl; system("pause"); return -1; } mat gray; cvtcolor(src, gray, color_bgr2gray); mat gaussian; gaussianblur(gray, gaussian, size(3, 3), 0); mat thresh; threshold(gaussian, thresh, 0, 255, thresh_binary_inv | thresh_otsu); mat kernel = getstructuringelement(morph_rect, size(3, 3)); mat open; morphologyex(thresh, open, morph_open, kernel); mat kernel1 = getstructuringelement(morph_rect, size(7, 7)); mat close; morphologyex(open, close, morph_close, kernel1); vector<vector<point>>contours; findcontours(close, contours, retr_external, chain_approx_simple); vector<vector<point>>conpoly(contours.size()); vector<point>srcpts; for (int i = 0; i < contours.size(); i++) { double area = contourarea(contours[i]); if (area > 10000) { double peri = arclength(contours[i], true); approxpolydp(contours[i], conpoly[i], 0.02*peri, true); srcpts = { conpoly[i][0],conpoly[i][1],conpoly[i][2],conpoly[i][3] }; } } int width = src.cols / 2; int height = src.rows / 2; int t_l, t_r, b_r, b_l; for (int i = 0; i < srcpts.size(); i++) { if (srcpts[i].x < width && srcpts[i].y < height) { t_l = i; } if (srcpts[i].x > width && srcpts[i].y < height) { t_r = i; } if (srcpts[i].x > width && srcpts[i].y > height) { b_r = i; } if (srcpts[i].x < width && srcpts[i].y > height) { b_l = i; } } //circle(src, srcpts[t_l], 10, scalar(0, 0, 255), -1); //circle(src, srcpts[t_r], 10, scalar(0, 255, 255), -1); //circle(src, srcpts[b_r], 10, scalar(255, 0, 0), -1); //circle(src, srcpts[b_l], 10, scalar(0, 255, 0), -1); /* 变换后,图像的长和宽应该变为: 长 = max(变换前左边长,变换前右边长) 宽 = max(变换前上边长,变换前下边长) 设变换后图像的左上角位置为原点位置。 */ double leftheight = eudis(srcpts[t_l], srcpts[b_l]); double rightheight = eudis(srcpts[t_r], srcpts[b_r]); double maxheight = max(leftheight, rightheight); double upwidth = eudis(srcpts[t_l], srcpts[t_r]); double downwidth = eudis(srcpts[b_l], srcpts[b_r]); double maxwidth = max(upwidth, downwidth); point2f srcaffinepts[4] = { point2f(srcpts[t_l]),point2f(srcpts[t_r]) ,point2f(srcpts[b_r]) ,point2f(srcpts[b_l]) }; point2f dstaffinepts[4] = { point2f(0,0),point2f(maxwidth,0),point2f(maxwidth,maxheight),point2f(0,maxheight) }; mat m = getperspectivetransform(srcaffinepts, dstaffinepts); mat dstimg; warpperspective(src, dstimg, m, point(maxwidth, maxheight)); //imshow("dst", dstimg); imshow("src", src); waitkey(0); destroyallwindows(); system("pause"); return 0; }
总结
c/c++开发分享C++ OpenCV实战之图像透视矫正使用opencv c++ 进行图像透视矫正,关键步骤有以下几点。
1、图像预处理,获取二值图像。
2、将二值图像进行轮廓提取,定位矩形四个角点,并确定其位置。
3、确定图像变换后的长、宽。并将srcaffinepts、dstaffinepts一一对应之后进行透视变换。
到此这篇关于c++ opencv实战之图像透视矫正的文章就介绍到这了,更多相关c++ opencv图像透视矫正内容请搜索<计算机技术网(www.ctvol.com)!!>以前的文章或继续浏览下面的相关文章希望大家以后多多支持<计算机技术网(www.ctvol.com)!!>!
需要了解更多c/c++开发分享C++ OpenCV实战之图像透视矫正,都可以关注C/C++技术分享栏目—计算机技术网(www.ctvol.com)!
本文来自网络收集,不代表计算机技术网立场,如涉及侵权请联系管理员删除。
ctvol管理联系方式QQ:251552304
本文章地址:https://www.ctvol.com/c-cdevelopment/1038125.html