在使用opencv处理图像的时候,在获取ROI区域这一步用的最多的就是找到指定区域,一般是根据轮廓提取,我们可以通过opencv中的findContours()
函数来查找图片中的轮廓,但是会发现找到的轮廓相当之多,如何在这些轮廓中准确定位道自己需要的轮廓呢?下面介绍几种方法:
前导知识
1. 查找轮廓
findContours() ps:点击函数名可以直接跳转到官方文档哦!
void cv::findContours(InputOutputArray image,
OutputArrayOfArrays contours,
OutputArray hierarchy,
int mode,
int method,
Point offset = Point()
)
Python:
cv.findContours(image, mode, method[, contours[, hierarchy[, offset]]])->image, contours, hierarchy
#include <opencv2/imgproc.hpp>
在二值图像中查找轮廓
参数 | 说明 |
---|---|
image | 输入的源图像 |
contours | 查找到的所有的轮廓的集合 |
hierarchy | 维护了每个轮廓的拓扑结构(层级关系),和contours同型 |
mode | 轮廓检索模式 |
method | 轮廓近似方法 |
offest | 每个轮廓点移动的偏移量 |
Examples:
vector<vector<Point> > contours;
vector<Vec4i> hierarchy;
cv::findContours( img, contours, hierarchy, RETR_TREE, CHAIN_APPROX_SIMPLE);
2. 绘制轮廓
drawContours()ps:点击函数名可以直接跳转到官方文档哦!
void cv::drawContours ( InputOutputArray image,
InputArrayOfArrays contours,
int contourIdx,
const Scalar & color,
int thickness = 1,
int lineType = LINE_8,
InputArray hierarchy = noArray(),
int maxLevel = INT_MAX,
Point offset = Point()
)
Python:
cv.drawContours(image, contours, contourIdx, color[, thickness[, lineType[, hierarchy[, maxLevel[, offset]]]]])->image
#include <opencv2/imgproc.hpp>
绘制轮廓线或者填充轮廓
参数 | 说明 |
---|---|
image | 输入的源图像 |
contours | 保存了所有轮廓的集合 |
contourIdx | 待绘制的轮廓序号 |
color | 绘制的轮廓线的颜色 |
thickness | 轮廓线的粗细 |
lineType | 轮廓线线型 |
hierarchy | 维护了所有轮廓的拓扑结构 |
maxLevel | 最大嵌套层级 |
offset | 轮廓线的偏移量 |
Examples:
vector<vector<Point> > contours;
vector<Vec4i> hierarchy;
findContours(imgDilate, contours, hierarchy, RETR_TREE, CHAIN_APPROX_SIMPLE );
for (int idx = 0; idx < contours.size(); idx++)
{
Scalar color(rand() & 255, rand() & 255, rand() & 255);
drawContours(img, contours, idx, color, 2, LINE_8, hierarchy, 3);
}
imshow("img",img);
正文
1. 根据面积筛选
使用contourArea()
可以计算得到一个轮廓的面积(这里的面积的单位应该是平方像素),然后和最小面积比较,得到筛选后的轮廓。
Examples:
// 计算轮廓面积
double area = contourArea(contours[idx]);
// 预设最小轮廓面积为1000,<=1000的轮廓被筛除,>1000的轮廓被放入finalContours中以返回
if(area > minArea){
finalContours.push_back(contours[idx]);
}
2. 根据拐点个数筛选多边形轮廓
如果要在一堆多边形轮廓中筛选出四边形轮廓,则可以首先根据拐点的个数进行筛选,使用approxPolyDP()
获取轮廓拐点。
Examples:
// 获取轮廓拐点,拐点坐标保存在approx中,精度为轮廓周长的0.02倍
approxPolyDP(contours[idx],approx,0.02*arcLength(contours[idx],true), true);
// 预设要筛选的拐点数目approxNum=4
if (approx.size() == approxNum) {
finalContours.push_back(contours[idx]);
}
3. 根据嵌套层级筛选
以上面的二值图像为例,如果当通过拐点、面积筛选的方法筛选之后,发现白线的内侧和外侧轮廓都被画了出来,如果只要外轮廓,则可以根据hierarchy
来进行筛选。
approxPolyDP(contours[idx], approx, 0.02 * arcLength(contours[idx], true), true);
// 根据拐点数量筛选
if (approx.size() == approxNum) {
// 筛除具有父轮廓的轮廓
if (hierarchy[idx][3] < 0) {
dstContours.push_back(contours[idx]);
dstApproxs.push_back(approx);
}
}
参考文献
杂项