文章目录

  • 图像轮廓与图像分割修复(opencv3编程入门第八章)第一节 查找并绘制轮廓
  • 两个库函数的使用
  • 示例代码1
  • 示例代码2


图像轮廓与图像分割修复(opencv3编程入门第八章)第一节 查找并绘制轮廓

两个库函数的使用

  1. 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(感兴趣区域)图像中找出的轮廓,并要在整个图像中进行分析时,这个参数便可以派上用场。
  1. 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;
}

结果展示:

opencv 内轮廓拟合圆_opencv


opencv 内轮廓拟合圆_opencv_02


opencv 内轮廓拟合圆_opencv_03


不好意思发现截屏把歌词弄进去了。

示例代码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以下,否则程序会出错

opencv 内轮廓拟合圆_opencv 内轮廓拟合圆_04


opencv 内轮廓拟合圆_findContour_05