尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

OPENCV4学习(40-56)

OPENCV4学习(40-56) 目录40.图像细化(需要扩展模块的库,目前环境不满足,结果为课程截图)thinning()图像细化(骨架提取)原理和形态学腐蚀的区别41.轮廓检测findContours()drawContours()42.轮廓信息统计contourArea()arcLength()43.轮廓外接多边形boundingRect()minAreaRect()approxPolyDP()44.凸包检测convexHull()凸包检测原理45.直线检测HoughLines()HoughLinesP()直线检测原理(Hough Transform 霍夫直线检测)霍夫变换核心思想霍夫直线检测的目的:46.点集拟合filLine()minEnclosingTriangle()minEnclosingCircle()47.二维码检测detect()decode()detectAndDecode()48.积分图像integral()积分图像(Integral Image)原理 目的原理任意矩形区域求和(最重要公式)OpenCV 接口目的是什么表格49.图像分割——漫水填充floodFill()漫水填充 floodFill 原理核心原理差值判断(关键)mask 掩码(非常重要)flags 参数三部分组成(位或组合)两种工作模式通俗例子应用场景floodFill vs connectedComponents常见坑一句话总结Scalar loDiff = Scalar(20, 20, 20); 说明含义判断条件(彩色图)如果是灰度图使用 floodFill完整调用示例调参理解坑一句话总结50.图像分割——分水岭法watershed()代码整体目的程序执行完整流程各个窗口含义重点易错点(写代码高频坑)分水岭算法 watershed 原理、API、目的、坑通俗原理(比喻:山地积水)51.Harris角点检测cornerHarris()drawKeypoints()​编辑52.Shi-Tomas角点检测goodFeaturesToTrack()53.亚像素级别角点位置优化cornerSubPix()54.ORB特征点create()ORB 特征点 Oriented FAST and Rotated BRIEF1、FAST 角点(关键点检测)2、rBRIEF 旋转 BRIEF(二进制描述子)APIORB 特征匹配一句话总结55.特征点匹配DMatch()match()knnMatch()radiusMatch()BFMatcher()drawMatches()56.RANSAC优化特征点匹配findHomography()40.图像细化(需要扩展模块的库,目前环境不满足,结果为课程截图)thinning()图像细化(骨架提取)原理细化:把二值图像中的前景物体,不断剥离边缘像素,压缩成单像素宽骨架,物体拓扑结构(连通、分支、拐点)保持不变,物体位置、大体形状不变,厚度变成 1 像素。 输入:二值图,一般:前景 = 白色 (255),背景 = 黑色 (0)。注意:细化≠轮廓提取。轮廓只是物体外圈;细化得到物体中间的骨架。和形态学腐蚀的区别操作特点腐蚀 erode整体均匀缩小物体,线条直接变细,会直接断开细线条,不保证单像素,会破坏拓扑细化thinning迭代剥边缘,维持连通拓扑,最终得到单像素骨架操作多次执行效果细化 thinning收敛后不再变化,线条保留单像素骨架,不会消失腐蚀 erode每调用一次物体就缩小一圈,细线条会直接消失腐蚀不能替代细化!多次腐蚀会直接把细线条腐蚀消失。#include opencv2\opencv.hpp #include opencv2\ximgproc.hpp //细化函数thining所在的头文件 #include iostream using namespace cv; using namespace std; int main() { //中文字进行细化 Mat img = imread("C:/opencv/LearnCV_black.png", IMREAD_ANYCOLOR); if (img.empty()) { cout "请确认图像文件名称是否正确" endl; return -1; } //英文字+实心圆和圆环细化 Mat words = Mat::zeros(100, 200, CV_8UC1); //创建一个黑色的背景图片 putText(words, "Learn", Point(30, 30), 2, 1, Scalar(255), 2); //添加英文 putText(words, "OpenCV 4", Point(30, 60), 2, 1, Scalar(255), 2); circle(words, Point(80, 75), 10, Scalar(255), -1); //添加实心圆 circle(words, Point(130, 75), 10, Scalar(255), 3); //添加圆环 //进行细化 Mat thin1, thin2; ximgproc::thinning(img, thin1, 0); //注意类名 ximgproc::thinning(words, thin2, 0); //显示处理结果 imshow("thin1", thin1); imshow("img", img); namedWindow("thin2", WINDOW_NORMAL); imshow("thin2", thin2); namedWindow("words", WINDOW_NORMAL); imshow("words", words); waitKey(0); return 0; }41.轮廓检测findContours()drawContours()#include opencv2\opencv.hpp #include iostream #include vector using namespace cv; using namespace std; int main() { system("color F0"); //更改输出界面颜色 Mat img = imread("C:/opencv/keys.jpg"); if (img.empty()) { cout "请确认图像文件名称是否正确" endl; return -1; } imshow("原图", img); Mat gray, binary; cvtColor(img, gray, COLOR_BGR2GRAY); //转化成灰度图 GaussianBlur(gray, gray, Size(13, 13), 4, 4); //平滑滤波 threshold(gray, binary, 170, 255, THRESH_BINARY | THRESH_OTSU); //自适应二值化 // 轮廓发现与绘制 vectorvectorPoint contours; //轮廓 vectorVec4i hierarchy; //存放轮廓结构变量 findContours(binary, contours, hierarchy, RETR_TREE, CHAIN_APPROX_SIMPLE, Point()); //绘制轮廓 for (int i = 0; i hierarchy.size(); i++) { cout hierarchy[i] endl; } for (int t = 0; t contours.size(); t++) { drawContours(img, contours, t, Scalar(0, 0, 255), 2, 8); imshow("轮廓检测结果", img); waitKey(0); } //输出轮廓结构描述子 return 0; }42.轮廓信息统计contourArea()arcLength()#include opencv2\opencv.hpp #include iostream #include vector using namespace cv; using namespace std; int main() { system("color F0"); //更改输出界面颜色 //用四个点表示三角形轮廓 vectorPoint contour; contour.push_back(Point2f(0, 0)); contour.push_back(Point2f(10, 0)); contour.push_back(Point2f(10, 10)); contour.push_back(Point2f(5, 5)); double area = contourArea(contour); cout "area =" area endl; double length0 = arcLength(contour, true); double length1 = arcLength(contour, false); cout "length0 =" length0 endl; cout "length1 =" length1 endl; cout "图像轮廓面积" endl; waitKey(0); Mat img = imread("C:/opencv/keys.jpg"); if (img.empty()) { cout "请确认图像文件名称是否正确" endl; return -1; } Mat gray, binary; cvtColor(img, gray, COLOR_BGR2GRAY); //转化成灰度图 GaussianBlur(gray, gray, Size(9, 9), 2, 2); //平滑滤波 threshold(gray, binary, 170, 255, THRESH_BINARY | THRESH_OTSU); //自适应二值化 // 轮廓检测 vectorvectorPoint contours; //轮廓 vectorVec4i hierarchy; //存放轮廓结构变量 findContours(binary, contours, hierarchy, RETR_TREE, CHAIN_APPROX_SIMPLE, Point()); //输出轮廓面积 for (int t = 0; t contours.size(); t++) { double area1 = contourArea(contours[t]); cout "第" t "轮廓面积=" area1 endl; } //输出轮廓长度 for (int t = 0; t contours.size(); t++) { double length2 = arcLength(contours[t], true); cout "第" t "个轮廓长度=" length2 endl; } return 0; }43.轮廓外接多边形boundingRect()minAreaRect()approxPolyDP()#include opencv2/opencv.hpp #include iostream #include vector using namespace cv; using namespace std; void drawapp(Mat result, Mat img2) { for (int i = 0; i result.rows; i++) { //最后一个坐标点与第一个坐标点连接 if (i == result.rows - 1) { Vec2i point1 = result.atVec2i(i); Vec2i point2 = result.atVec2i(0); line(img2, point1, point2, Scalar(0, 0, 255), 2, 8, 0); break; } Vec2i point1 = result.atVec2i(i); Vec2i point2 = result.atVec2i(i + 1); line(img2, point1, point2, Scalar(0, 0, 255), 2, 8, 0); } } int main() { Mat img = imread("C:/opencv/stuff.jpg"); if (img.empty()) { cout "请确认图像文件名称是否正确" endl; return -1; } Mat img1, img2; img.copyTo(img1); //深拷贝用来绘制最大外接矩形 img.copyTo(img2); //深拷贝用来绘制最小外接矩形 imshow("img", img); // 去噪声与二值化 Mat canny; Canny(img, canny, 80, 160, 3, false); imshow("", canny); //膨胀运算,将细小缝隙填补上 Mat kernel = getStructuringElement(0, Size(3, 3)); dilate(canny, canny, kernel); // 轮廓发现与绘制 vectorvectorPoint contours; vectorVec4i hierarchy; findContours(canny, contours, hierarchy, 0, 2, Point()); //寻找轮廓的外接矩形 for (int n = 0; n contours.size(); n++) { // 最大外接矩形 Rect rect = boundingRect(contours[n]); rectangle(img1, rect, Scalar(0, 0, 255), 2, 8, 0); // 最小外接矩形 RotatedRect rrect = minAreaRect(contours[n]); Point2f points[4]; rrect.points(points); //读取最小外接矩形的四个顶点 Point2f cpt = rrect.center; //最小外接矩形的中心 // 绘制旋转矩形与中心位置 for (int i = 0; i 4; i++) { if (i == 3) { line(img2, points[i], points[0], Scalar(0, 255, 0), 2, 8, 0); break; } line(img2, points[i], points[i + 1], Scalar(0, 255, 0), 2, 8, 0); } //绘制矩形的中心 circle(img2, cpt, 4, Scalar(255, 0, 0), -1, 8, 0); } //输出绘制外接矩形的结果 imshow("max", img1); imshow("min", img2); cout "下面是多边形拟合" endl; waitKey(0); Mat approx = imread("approx.png"); if (approx.empty()) { cout "请确认图像文件名称是否正确" endl; return -1; } // 边缘检测 Mat canny2; Canny(approx, canny2, 80, 160, 3, false); //膨胀运算 Mat kernel2 = getStructuringElement(0, Size(3, 3)); dilate(canny2, canny2, kernel2); // 轮廓发现与绘制 vectorvectorPoint contours2; vectorVec4i hierarchy2; findContours(canny2, contours2, hierarchy2, 0, 2, Point()); //绘制多边形 for (int t = 0; t contours2.size(); t++) { //用最小外接矩形求取轮廓中心 RotatedRect rrect = minAreaRect(contours2[t]); Point2f center = rrect.center; circle(approx, center, 2, Scalar(0, 255, 0), 2, 8, 0); Mat result; approxPolyDP(contours2[t], result, 4, true); //多边形拟合 drawapp(result, approx); cout "corners : " result.rows endl; //判断形状和绘制轮廓 if (result.rows == 3) { putText(approx, "triangle", center, 0, 1, Scalar(0, 255, 0), 1, 8); } if (result.rows == 4) { putText(approx, "rectangle", center, 0, 1, Scalar(0, 255, 0), 1, 8); } if (result.rows == 8) { putText(approx, "poly-8", center, 0, 1, Scalar(0, 255, 0), 1, 8); } if (result.rows 12) { putText(approx, "circle", center, 0, 1, Scalar(0, 255, 0), 1, 8); } } imshow("result", approx); waitKey(0); return 0; }44.凸包检测convexHull()凸包检测原理凸包 (Convex Hull):给一组二维点集,找到一个最小的凸多边形,把所有点全部包裹在多边形内部或者边上。 通俗比喻:拿一根橡皮筋,撑开套住所有点,松开橡皮筋收紧,橡皮筋形成的多边形就是凸包。输入:一组轮廓点(vectorPoint);输出:凸包顶点序列vectorPoint。#include opencv2/opencv.hpp #include iostream #include vector using namespace cv; using namespace std; int main() { Mat img = imread("C:/opencv/learnOpenCV/hand.png"); if (img.empty()) { cout "请确认图像文件名称是否正确" endl; return -1; } // 二值化 Mat gray, binary; cvtColor(img, gray, COLOR_BGR2GRAY); threshold(gray, binary, 105, 255, THRESH_BINARY); //开运算消除细小区域 Mat k = getStructuringElement(MORPH_RECT, Size(3, 3), Point(-1, -1)); morphologyEx(binary, binary, MORPH_OPEN, k); imshow("binary", binary); // 轮廓发现 vectorvectorPoint contours; vectorVec4i hierarchy; findContours(binary, contours, hierarchy, 0, 2, Point()); for (int n = 0; n contours.size(); n++) { //计算凸包 vectorPoint hull; convexHull(contours[n], hull); //绘制凸包 for (int i = 0; i hull.size(); i++) { //绘制凸包顶点 circle(img, hull[i], 4, Scalar(255, 0, 0), 2, 8, 0); //连接凸包 if (i == hull.size() - 1) { line(img, hull[i], hull[0], Scalar(0, 0, 255), 2, 8, 0); break; } line(img, hull[i], hull[i + 1], Scalar(0, 0, 255), 2, 8, 0); } } imshow("hull", img); waitKey(0); return 0; }45.直线检测HoughLines()HoughLinesP()直线检测原理(Hough Transform 霍夫直线检测)OpenCV 两个 API:标准霍夫变换:HoughLines(),输出极坐标直线参数概率霍夫变换:HoughLinesP(),输出线段的两个端点坐标(工程最常用)输入:一般是 Canny 边缘二值图,只有边缘白色 255,背景黑色 0。霍夫变换核心思想图像空间里的一条直线上的所有边缘点,映射到参数空间,会相交于同一个参数点。通过统计参数空间的累加器峰值,反找出图像中的直线。霍夫直线检测的目的:自动发现图像中存在的直线 / 线段,获取角度、位置、端点;多用于倾斜校正、车道线、工业零件直边检测、矩形物体定位。#include opencv2/opencv.hpp #include iostream using namespace cv; using namespace std; void drawLine(Mat img, //要标记直线的图像 vectorVec2f lines, //检测的直线数据 double rows, //原图像的行数(高) double cols, //原图像的列数(宽) Scalar scalar, //绘制直线的颜色 int n //绘制直线的线宽 ) { Point pt1, pt2; for (size_t i = 0; i lines.size(); i++) { float rho = lines[i][0]; //直线距离坐标原点的距离 float theta = lines[i][1]; //直线过坐标原点垂线与x轴夹角 double a = cos(theta); //夹角的余弦值 double b = sin(theta); //夹角的正弦值 double x0 = a*rho, y0 = b*rho; //直线与过坐标原点的垂线的交点 double length = max(rows, cols); //图像高宽的最大值 //计算直线上的一点 pt1.x = cvRound(x0 + length * (-b)); pt1.y = cvRound(y0 + length * (a)); //计算直线上另一点 pt2.x = cvRound(x0 - length * (-b)); pt2.y = cvRound(y0 - length * (a)); //两点绘制一条直线 line(img, pt1,
返回列表