Opencv学习笔记(八) 提取图像轮廓基础操作

经过两周opencv的学习,作者对opencv有了一些自己的理解和心得,总结出一套较为实用提取图像轮廓的方法。

操作步骤:

1、图像锐化。

图像锐化的目的是为了要增强图像中对比度,这样可以使提取轮廓的效果,让轮廓显现的更明显。

这里我们使用拉普拉斯算子遍历图像,预先定义矩阵:

Mat kernel = (Mat_(3, 3) << 1, 1, 1, 1, -8, 1, 1, 1, 1);

运用filter2D()函数 将我们定义好的矩阵遍历图像。再进行图像的运算Mat resultImg = src - src_lapl。(具体参考下面给出的代码)

Top:当Mat类型的图像数据类型不同时,可能需要运用到convertTo()函数来转换图像的深度和通道数。

这里给出convertTo()函数的基础用法:

src.convertTo(dst, type, scale, shift)

dst:目的矩阵;

type:需要的输出矩阵类型,或者更明确的,是输出矩阵的深度,如果是负值(常用-1)则输出矩阵和输入矩阵类型相同;

scale:比例因子;

shift:将输入数组元素按比例缩放后添加的值;

dst(i)=src(i)xscale+(shift,shift,…)

2、Canny()函数进行边缘检测。

前面的学习笔记已经详细介绍了Canny()函数的用法,这里我们不作展开。
只是需要注意的是,Canny函数参数的调参,由于处理的图像不同,读者参考一下代码使用时注意要自己调整参数。

3、findContours()函数提取轮廓

使用findContours()函数之前,一般要先定义一个放有vector容器的vector容器,子容器为Point,再定义一个放置四个int类型的vector容器。

vector<vector > contours;
vector hierarchy;

再使用findContours()函数提取轮廓

void findContours(
InputOutputArray image,
OutputArrayOfArrays contours,
OutputArray hierarchy,
int mode,
int method,
Point offset = Point());

关于该函数的参数,详细介绍可参考以下链接:

findContours()函数参数详细解释

4、drawContours()函数绘制轮廓

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表示目标图像;
contours表示输入的轮廓组,每一组轮廓由点vector构成;
contourIdx指明画第几个轮廓,如果该参数为负值,则画全部轮廓;
color为轮廓的颜色(Schlar类型);
thickness为轮廓的线宽,如果为负值或CV_FILLED表示填充轮廓内部;
lineType为线型;
InputArray hierarchy表示轮廓结构信息;

代码演示:

#include <opencv2\opencv.hpp>
#include<opencv2\imgproc\imgproc.hpp>
#include <iostream>
#include <math.h>
using namespace std;
using namespace cv;

int main()
{
 Mat src, gray_src, dest;
 src = imread("C:/Users/86159/Desktop/yasina.jpg");
 
 Mat src_lapl;                
 Mat kernel = (Mat_<float>(3, 3) << 1, 1, 1, 1, -8, 1, 1, 1, 1);        //定义拉普拉斯算子
 filter2D(src, src_lapl, CV_32F, kernel, Point(-1, -1), 0, BORDER_DEFAULT);
 src.convertTo(src, CV_32F);
 
 Mat resultImg = src - src_lapl;
 src.convertTo(src, CV_8UC3);
 src_lapl.convertTo(src_lapl, CV_8UC3);
 resultImg.convertTo(resultImg, CV_8UC3);
 
 Canny(resultImg, dest, 630, 1200, 3);
 
 Mat dst = Mat::zeros(src.size(), src.type());
 vector<vector<Point> > contours;
 vector<Vec4i> hierarchy;
 findContours(dest, contours, hierarchy, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE, Point(0, 0));                //提取轮廓
 
 for (int i = 0; i < contours.size(); i++)
 {
  drawContours(dst, contours, i, Scalar(255,255,255), 1, 4, hierarchy, 0, Point());                              //绘制轮廓
 }
 
 bitwise_not(dst, dst);                //图像取反
 
 namedWindow("原图", WINDOW_AUTOSIZE);
 moveWindow("原图", 50, 0);
 imshow("原图", src);
 namedWindow("效果图", WINDOW_AUTOSIZE);
 moveWindow("效果图", 693, 0);
 imshow("效果图", dst);
 
 waitKey(0);
 return 0;
}

效果展示:

在这里插入图片描述

希望对读者有所帮助,喜欢的话可以关注一下我的公众号,我会把学习笔记发在上面,大家可以一起共同学习!
在这里插入图片描述
Alt

发布了12 篇原创文章 · 获赞 9 · 访问量 3631

猜你喜欢

转载自blog.csdn.net/Rosen_er/article/details/104150887