目录
2.1.1、cv::findContours(src, contours, hierarchy, retrivalMode, approxiMode, offSet);
2.1.2、cv::Canny(src, edges, lowThreshold, highThreshold, kernel_size, useL2Gradient);
2.2.1、cv::blur(src,blurImg,size,anchor,borderType);
2.2.2、cv::threshold(src,binaryImg, thresh, maxVal, threshType);
2.2.3、drawContours(drawing, contours, index, color, lineThickness, lineType, hierarchy, maxLevel);
1、图像找轮廓和边简介
进行图像处理任务时,图像内部形状的边缘信息往往包含了大量的细节,比如圆形,只要能找到圆形的轮廓我们就能判断出来这个形状是圆,而且能据此计算出圆心、半径、面积等其他感兴趣的数据。后续的尺寸测量、目标检测等任务中也常常会用到找轮廓、找边的算法。
2、OpenCV中找轮廓找边用到的方法
2.1、重要的Opencv函数
2.1.1、cv::findContours(src, contours, hierarchy, retrivalMode, approxiMode, offSet);
findContours参数列表
参数名 | 说明 |
---|---|
src | 灰度图像(8UC1),一般是二值化后的图像 |
contours | 用于存放找到的轮廓点 |
hierarchy | 用于存储轮廓之间的层次关系 |
retrivalMode | 轮廓提取方式,可以选择最外层或者多层轮廓等 |
approxiMode | 轮廓计算方式 |
offSet | 轮廓点偏移量 |
2.1.2、cv::Canny(src, edges, lowThreshold, highThreshold, kernel_size, useL2Gradient);
Canny参数列表
参数名 | 说明 |
---|---|
src | 灰度图像(8UC1) |
edges | 用于保存边缘信息的图像,该处理后续使用的图像 |
lowThreshold | 低阈值,低于此值都不作为边界 |
highThreshold | 高阈值,高于此值都作为边界 |
kernel_size | 卷积核大小 |
useL2Gradient | 使用L2范数提高计算精度 |
2.2、例程中使用到的其他方法
2.2.1、cv::blur(src,blurImg,size,anchor,borderType);
blur参数列表
参数名 | 说明 |
---|---|
src | 输入图像 |
blurImg | 模糊操作后的效果图象 |
size | 卷积核大小 |
anchor | 锚点,一般都是卷积核中间对应的位置 |
borderType | 运算时边界补充值类型 |
2.2.2、cv::threshold(src,binaryImg, thresh, maxVal, threshType);
threshold参数
2.2.3、drawContours(drawing, contours, index, color, lineThickness, lineType, hierarchy, maxLevel);
drawContours参数
参数名 | 说明 |
---|---|
drawing | 要绘制轮廓点的图像 |
contours | 用来绘制轮廓的点集 |
index | 要绘制的点集(子集)的索引 |
color | 绘制轮廓的颜色 |
lineThickness | 绘制轮廓的线宽 |
lineType | 线的形式,默认8连通域 |
hierarchy | 轮廓之间的层次关系,一般由findContours方法提供 |
maxLevel | 绘图等级 |
3、代码和运行效果
3.1、示例代码
#include <iostream>
#include <opencv2/opencv.hpp>
using namespace std;
int main()
{
//读取图像
//cv::Mat src = cv::imread("C:\\Users\\111\\Desktop\\IMG_20240731_222630.jpg",cv::IMREAD_GRAYSCALE);// cv::IMREAD_GRAYSCALE:读取图像的灰度图
//创建测试灰度图
cv::Mat src = cv::Mat::zeros(400, 400, CV_8UC1);// 创建一个空白的黑色图像,大小为400x400,类型为8位无符号整型(即灰度图)
cv::Point center = cv::Point(200, 200);// 将要绘制圆的圆心
int radius = 100;// 设置圆的半径
cv::Scalar colorSrc = cv::Scalar(255, 255, 255);// 设置绘图颜色(这里是白色)
int thickness = -1;// 绘制线的宽度,默认是1,这里设置-1表示填充整个圆内部
cv::LineTypes lineTypeSrc = cv::LINE_8;// 线的形式,默认8连通域
int shift = 0;// 调整中心点坐标和半径值中的小数位数,默认是0:不调整,随数字增大,圆的中心坐标值减小,半径减小
cv::circle(src, center, radius, colorSrc, thickness, lineTypeSrc,shift);// 绘制一个白色的圆 =cv::circle(src, center, radius, colorSrc, thickness)
// 显示图像
cv::namedWindow("Img", cv::WINDOW_NORMAL);// cv::WINDOW_NORMAL:可调整大小或者用来将图像由全屏显示切换为常规大小
cv::imshow("Img", src);
cv::waitKey();
//图像模糊
cv::Mat blurImg;
cv::Size size = cv::Size(5,5);// 卷积核大小,越大模糊效果越明显,可以横向和纵向设置不同值
cv::Point anchor = cv::Point(-1,-1);// 卷积运算后结果作为哪个位置的值,默认(-1,-1)表示卷积核中心位置
cv::BorderTypes borderType = cv::BORDER_DEFAULT;// 图像边缘的点计算卷积时需拓展边缘外的点,该值决定补充点像素值规律,默认以边缘为对称轴补充图像内的像素
cv::blur(src,blurImg,size,anchor,borderType);// =cv::blur(src,blurImg,size)
//图像二值化
cv::Mat binaryImg;
double thresh = 150;// 阈值,以该值为分界线,高于该值的像素值都设为maxVal,低于此值都设为0
double maxVal = 255;// 最大像素值,高于阈值的像素值设为此值
cv::ThresholdTypes threshType = cv::THRESH_BINARY;// 阈值分割的操作方式,全局阈值、自动阈值、三角阈值等
cv::threshold(blurImg,binaryImg, thresh, maxVal, threshType);// 根据阈值分割方式选择可以选择使用或不适用返回值
//找轮廓
vector<vector<cv::Point>> contours;// 用于接收轮廓点数据,注意是二维数组,根据实际情况选择使用全部或部分数据
vector<cv::Vec4i> hierarchy; // 用于存储轮廓之间的层次关系,如果不需要可以忽略
cv::RetrievalModes retrivalMode = cv::RETR_EXTERNAL;// 轮廓提取方式,根据需要选择最外层或者多层轮廓
cv::ContourApproximationModes approxiMode = cv::CHAIN_APPROX_SIMPLE;// 轮廓计算方式,如果你需要轮廓的精确表示,可以使用CHAIN_APPROX_NONE
cv::Point offSet = cv::Point();// 偏移量,计算的点会根据该点进行偏移,默认不偏移
cv::findContours(binaryImg, contours, hierarchy, retrivalMode, approxiMode, offSet);// =cv::findContours(binaryImg, contours, retrivalMode, approxiMode)
//绘制轮廓
cv::Mat drawing = cv::Mat::zeros(src.size(), CV_8UC1); // 创建一个与原图同样大小的黑色画布,保持8UC1(灰度图)
cv::Scalar color = cv::Scalar(255, 255, 255); // 白色
int lineThickness = 1;// 线宽,默认值1
cv::LineTypes lineType = cv::LINE_8;// 线的形式,默认8连通域
int maxLevel = 0;// 绘图等级,越大绘的越多
for (int i = 0; i < contours.size(); i++) {
cv::drawContours(drawing, contours, i, color, lineThickness, lineType, hierarchy, maxLevel);//绘制第i组轮廓点
}// 如果绘制全部轮廓点:drawContours(drawing, contours, -1, color);
cv::namedWindow("Contours", cv::WINDOW_NORMAL);
cv::imshow("Contours", drawing);
cv::waitKey();
// canny算子找边
cv::Mat edges;
double lowThreshold = 50;// 低阈值,低于此值都不作为边界
double highThreshold = 150;// 高阈值,高于此值都作为边界;高低阈值之间看是否相连
int kernel_size = 3;// 卷积核大小,sobel矩阵大小,默认3
bool useL2Gradient = false;// 是否需要使用L2范数提高梯度计算精度,默认false
cv::Canny(src, edges, lowThreshold, highThreshold, kernel_size, useL2Gradient);// =cv::Canny(src, edges, lowThreshold, highThreshold)
cv::namedWindow("Edges", cv::WINDOW_NORMAL);
cv::imshow("Edges", edges);
cv::waitKey();
}
3.2、运行结果
图像从左到右依次是原图,轮廓图,边缘图
从运行结果来看,其实找轮廓和直接canny找边效果差不多,但是找轮廓方法使用更广泛,毕竟可以直接拿到轮廓点数据,而且操作方式方法更多,运用更灵活。