本文将使用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 clo;morphologyex(open, clo, morph_clo, kernel1);
如图就是经过图像预处理得到的二值图像。
vector<vector<point>>contours;findcontours(clo, contours, retr_external, chain_approx_simple);
使用findcontours、retr_external就可以提取出物体最外轮廓。
接下来将使用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] };}}
由于我们之前使用的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 maxheig浓香型白酒ht = 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);
确定变换后的长宽之后,就可以使用getper2sinx的导数spectivetransform、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("pau");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 clo;morphologyex(open, clo, morph_clo, kernel1);vector<vector<point>>contours;findcontours(clo, 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("pau");return 0;}
总结
本文使用opencv c++ 进行图像透视矫正,关键步骤有以下几点。
1、图像预处理,获取二值图像。
2、将二值图像进行轮廓提取,定位矩形四个角点,并确定其位置。
3、确定图像变换后的长、宽。并将srcaffinepts、dstaffinepts一一对应之后进行透视变换。
到此这篇关于c++ opencv实战之图像透视矫正的文章就介绍到这了,更多相关c++ opencv图像透视矫正内容请搜索www.887551.com以前的文章或继续浏览下面的相关文章希望大家以后多多支持www.887551.com!
本文发布于:2023-04-04 13:38:58,感谢您对本站的认可!
本文链接:https://www.wtabcd.cn/fanwen/zuowen/2a7008a5aa812ad84e9e4935315bc758.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文word下载地址:C++ OpenCV实战之图像透视矫正.doc
本文 PDF 下载地址:C++ OpenCV实战之图像透视矫正.pdf
留言与评论(共有 0 条评论) |