OPENCV4学习(40-56)
2026/8/30 11:37:45 网站建设 项目流程

目录

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 BRIEF

1、FAST 角点(关键点检测)

2、rBRIEF 旋转 BRIEF(二进制描述子)

API

ORB 特征匹配

一句话总结

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); //自适应二值化 // 轮廓发现与绘制 vector<vector<Point>> contours; //轮廓 vector<Vec4i> 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"); //更改输出界面颜色 //用四个点表示三角形轮廓 vector<Point> 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); //自适应二值化 // 轮廓检测 vector<vector<Point>> contours; //轮廓 vector<Vec4i> 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.at<Vec2i>(i); Vec2i point2 = result.at<Vec2i>(0); line(img2, point1, point2, Scalar(0, 0, 255), 2, 8, 0); break; } Vec2i point1 = result.at<Vec2i>(i); Vec2i point2 = result.at<Vec2i>(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); // 轮廓发现与绘制 vector<vector<Point>> contours; vector<Vec4i> 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); // 轮廓发现与绘制 vector<vector<Point>> contours2; vector<Vec4i> 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):给一组二维点集,找到一个最小的凸多边形,把所有点全部包裹在多边形内部或者边上。 通俗比喻:拿一根橡皮筋,撑开套住所有点,松开橡皮筋收紧,橡皮筋形成的多边形就是凸包。

输入:一组轮廓点(vector<Point>);输出:凸包顶点序列vector<Point>

#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); // 轮廓发现 vector<vector<Point>> contours; vector<Vec4i> hierarchy; findContours(binary, contours, hierarchy, 0, 2, Point()); for (int n = 0; n < contours.size(); n++) { //计算凸包 vector<Point> 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:

  1. 标准霍夫变换:HoughLines(),输出极坐标直线参数
  2. 概率霍夫变换:HoughLinesP(),输出线段的两个端点坐标(工程最常用)

输入:一般是 Canny 边缘二值图,只有边缘白色 255,背景黑色 0。

霍夫变换核心思想

图像空间里的一条直线上的所有边缘点,映射到参数空间,会相交于同一个参数点。通过统计参数空间的累加器峰值,反找出图像中的直线。

霍夫直线检测的目的:

自动发现图像中存在的直线 / 线段,获取角度、位置、端点;多用于倾斜校正、车道线、工业零件直边检测、矩形物体定位

#include <opencv2/opencv.hpp> #include <iostream> using namespace cv; using namespace std; void drawLine(Mat &img, //要标记直线的图像 vector<Vec2f> 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,

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询