文章目录
- 图像轮廓与图像分割修复(opencv3编程入门第八章)第一节 查找并绘制轮廓
- 两个库函数的使用
- 示例代码1
- 示例代码2
图像轮廓与图像分割修复(opencv3编程入门第八章)第一节 查找并绘制轮廓
两个库函数的使用
- void findContours(InputOutputArray image, OutputArrayOfArrays contours, OutputArray hierarchy, int mode, int method, Point offset=Point())
- 第一个参数:InputArray类型的image,输入图像,必须是二值图像。我们可以用compare()、imrange()、threshold()、adaptivethreshold()、canny()等函数由灰度图或者彩色图创建二值图像。
- 第二个参数:此参数类型可以使用vector<vector<Point>>类型,用于存放监测到的轮廓, 每一个轮廓被储存为一个点构成的容器。contour[i]表示第i个轮廓。
- 第三个参数:可以使用vector<Vec4i>类型。该容器的元素为4维int类型的向量。向量中的4个元素分别存放当前轮廓contour[i]的后一个轮廓编号、前一个轮廓编号、父轮廓编号、内嵌轮廓编号。
- 第四个参数:int类型,轮廓检索模式,取值如下表所示
标识符 | 含义 |
RETR_EXTERNAL | 只检测外层轮廓 |
RETR_LIST | 检测所有轮廓,轮廓间不建立等级关系 |
RETE_CCOMP | 检测所有轮廓,并且将其组织为双层结构,顶层为连通域的外围边界,次层为孔的内层边界 |
RETE_TREE | 提取所有轮廓,并建立网状的轮廓结构 \ |
- 第五个参数:int类型,轮廓的近似方法,取值如下表
标识符 | 含义 |
CHAIN_APPROX_NONE | 获取每个轮廓的每个像素,相邻的两个像素位置差不超过1 |
CHAIN_APPROX_SIMPLE | 压缩水平方向,垂直方向、对角线方向的元素,只保留该方向的终点坐标,例如一个矩形轮廓只需要4个点 |
CHAIN_APPROX_TC89_L1, CHAIN_APPROX_TC89_KCOS | 使用teh-Chinl链逼近算法 |
- 第六个参数:Point类型的偏移量,每个轮廓点的可选偏移量。对于ROI(感兴趣区域)图像中找出的轮廓,并要在整个图像中进行分析时,这个参数便可以派上用场。
- void drawContours(InputOutputArray image, InputArrayOfArrays contours, int contourIdx, const Scalar& color, int thickness=1, int lineType=8, InputArray hierarchy=noArray(), int maxLevel=INT_MAX, Point offset=Point() )
- 第一个参数:image表示目标图像,Mat类型即可。
- 第二个参数:contours表示输入的轮廓组,每一组轮廓由点vector构成,可以使用vector<vector<Point>>类型。
- 第三个参数:contourIdx指明画第几个轮廓,如果该参数为负值,则画全部轮廓,
- 第四个参数:color为轮廓的颜色,Scalar类型。
- 第五个参数:thickness为轮廓的线宽,如果为负值或CV_FILLED表示填充轮廓内部。
- 第六个参数:lineType为线型,取值类型如下表:
取值 | 含义 |
8(默认值) | 8连通型 |
4 | 4连通型 |
LINE_AA | 抗锯齿线型 |
- 第七个参数:可选的轮廓结构信息,
- 第八个参数:为maxLevel,绘制轮廓的最大等级
- 第九个参数:Point类型的偏移量。
示例代码1
#include <opencv2/opencv.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
using namespace cv;
using namespace std;
int main()
{
//以灰度值模式载入原始图像
Mat srcImage = imread("1.jpg", 0);
imshow("original image", srcImage);
//初始化结果图
Mat dstImage = Mat::zeros(srcImage.rows, srcImage.cols, CV_8UC3);
//src取大于阈值119的那部分
srcImage = srcImage > 100;
imshow("阈值处理后的原始图", srcImage);
//定义轮廓和层次结构
vector<vector<Point>> contours;
vector<Vec4i> hierarchy; //该容器内放了4维int向量
//查找轮廓
findContours(srcImage, contours, hierarchy, RETR_CCOMP, CHAIN_APPROX_SIMPLE);
//遍历所有顶层的轮廓,以随机颜色绘制出每个连接组件的颜色
int index = 0;
for(; index >= 0; index = hierarchy[index][0])
{
Scalar color(rand() & 255, rand() & 255, rand() & 255);
drawContours(dstImage, contours, index, color, FILLED, 8, hierarchy);
}
imshow("轮廓图", dstImage);
waitKey(0);
return 0;
}
结果展示:
不好意思发现截屏把歌词弄进去了。
示例代码2
#include <opencv2/opencv.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <iostream>
using namespace cv;
using namespace std;
#define WINDOW_NAME1 "【原始图窗口】"
#define WINDOW_NAME2 "【轮廓图】"
//全局变量声明
Mat g_srcImage, g_grayImage, g_cannyMat_output;
int g_nThresh{ 50 }, g_nThresh_max{ 255 };
RNG g_rng(12345);
vector<vector<Point>> g_vContour;
vector<Vec4i> g_vHierarchy;
//全局函数声明
static void ShowHelpText();
void on_threshChange(int, void*);
int main()
{
g_srcImage = imread("1.jpg", 1);
if(!g_srcImage.data)
{
cout << "读取图片错误" << endl;
return false;
}
//转成灰度图并模糊化降噪
cvtColor(g_srcImage, g_grayImage, COLOR_BGR2GRAY);
blur(g_grayImage, g_grayImage, Size(3, 3));
//创建窗口
namedWindow(WINDOW_NAME1, WINDOW_KEEPRATIO);
imshow(WINDOW_NAME1, g_srcImage);
//创建滚动条并初始化
createTrackbar("canny阈值", WINDOW_NAME1, &g_nThresh, g_nThresh_max, on_threshChange);
on_threshChange(0, 0);
waitKey(0);
return 0;
}
//回调函数
void on_threshChange(int, void*)
{
//用canny算子检测边缘
Canny(g_grayImage, g_cannyMat_output, g_nThresh, g_nThresh * 2, 3);
//寻找轮廓
findContours(g_cannyMat_output, g_vContour, g_vHierarchy, RETR_TREE, CHAIN_APPROX_SIMPLE, Point(0, 0));
//绘制轮廓
Mat drawing = Mat::zeros(g_cannyMat_output.size(), CV_8UC3);
for(int i=0; i < g_vContour.size(); i++)
{
Scalar color = Scalar(g_rng.uniform(0, 255), g_rng.uniform(0, 255), g_rng.uniform(0, 255));
drawContours(drawing, g_vContour, i, color, 2, 8, g_vHierarchy, 0, Point());
}
namedWindow(WINDOW_NAME2, WINDOW_KEEPRATIO);
imshow(WINDOW_NAME2, drawing);
}
结果展示:
不要把阈值调到50以下,否则程序会出错