opencv 查找并绘制轮廓

一个轮廓一般对应一系列的点, 也就是图像中的一条曲线。其表示方法可能根据不同的情况而有所不同。 在opencv中可以用findContours()函数从二值图像查找轮廓

findContours()函数用于在二值图像中寻找轮廓

◆ findContours() [1/2]

void cv::findContours(InputArray image,
  OutputArrayOfArrays contours,
  OutputArray hierarchy,
  int mode,
  int method,
  Point offset = Point() 
 )  
Python:
 contours, hierarchy=cv.findContours(image, mode, method[, contours[, hierarchy[, offset]]])

Parameters

imageSource, an 8-bit single-channel image. Non-zero pixels are treated as 1's. Zero pixels remain 0's, so the image is treated as binary . You can use compareinRangethreshold , adaptiveThresholdCanny, and others to create a binary image out of a grayscale or color one. If mode equals to RETR_CCOMP or RETR_FLOODFILL, the input can also be a 32-bit integer image of labels (CV_32SC1).
contoursDetected contours. Each contour is stored as a vector of points (e.g. std::vector<std::vector<cv::Point> >).
hierarchy可选的输出向量(例如std::vector),包含关于图像拓扑的信息。它有和轮廓一样多的元素。对于每个i-th等值线[i],将元素层次[i][0]、层次[i][1]、层次[i][2]、层次[i][3]分别设置为同一层次下一个等值线、前一个等值线、第一子等值线和父等值线的元素层次[i] b[3]索引为0。如果轮廓i没有下一个轮廓、上一个轮廓、父轮廓或嵌套轮廓,则对应的hierarchy[i]元素为负数。
modeContour retrieval mode, see RetrievalModes
methodContour approximation method, see ContourApproximationModes
offsetOptional offset by which every contour point is shifted. This is useful if the contours are extracted from the image ROI and then they should be analyzed in the whole image context.

 

 

◆ ContourApproximationModes

enum cv::ContourApproximationModes

#include <opencv2/imgproc.hpp>

the contour approximation algorithm

Enumerator
CHAIN_APPROX_NONE 

Python: cv.CHAIN_APPROX_NONE

stores absolutely all the contour points. That is, any 2 subsequent points (x1,y1) and (x2,y2) of the contour will be either horizontal, vertical or diagonal neighbors, that is, max(abs(x1-x2),abs(y2-y1))==1.

CHAIN_APPROX_SIMPLE 

Python: cv.CHAIN_APPROX_SIMPLE

compresses horizontal, vertical, and diagonal segments and leaves only their end points. For example, an up-right rectangular contour is encoded with 4 points.

CHAIN_APPROX_TC89_L1 

Python: cv.CHAIN_APPROX_TC89_L1

applies one of the flavors of the Teh-Chin chain approximation algorithm [224]

CHAIN_APPROX_TC89_KCOS 

Python: cv.CHAIN_APPROX_TC89_KCOS

applies one of the flavors of the Teh-Chin chain approximation algorithm [224]

我们使用cv.findContours()寻找轮廓时,参数2表示轮廓的检索方式(RetrievalModes),当我们传入的是cv.RETR_TREE,它表示什么意思呢?另外,函数返回值hierarchy有什么用途呢?下面我们就来研究下这两个问题

理解轮廓层级

图中总共有8条轮廓,2和2a分别表示外层和里层的轮廓,3和3a也是一样。从图中看得出来:

如果我们打印出cv.findContours()函数的返回值hierarchy,会发现它是一个包含4个值的数组:[Next, Previous, First Child, Parent]
Next:与当前轮廓处于同一层级的下一条轮廓
举例来说,前面图中跟0处于同一层级的下一条轮廓是1,所以Next=1;同理,对轮廓1来说,Next=2;那么对于轮廓2呢?没有与它同一层级的下一条轮廓了,此时Next=-1。
Previous:与当前轮廓处于同一层级的上一条轮廓
跟前面一样,对于轮廓1来说,Previous=0;对于轮廓2,Previous=1;对于轮廓2a,没有上一条轮廓了,所以Previous=-1。
First Child:当前轮廓的第一条子轮廓
比如对于轮廓2,第一条子轮廓就是轮廓2a,所以First Child=2a;对轮廓3,First Child=3a。
Parent:当前轮廓的父轮廓
比如2a的父轮廓是2,Parent=2;轮廓2没有父轮廓,所以Parent=-1。

OpenCV中找到的轮廓序号跟前面讲的不同

现在既然我们了解了轮廓层级的概念,那么类似cv.RETR_TREE的轮廓寻找方式又是啥意思呢?

 

轮廓寻找方式

OpenCV中有四种轮廓寻找方式RetrievalModes,下面分别来看下:

◆ RetrievalModes

enum cv::RetrievalModes

#include <opencv2/imgproc.hpp>

轮廓检索算法的模式

Enumerator
RETR_EXTERNAL 

Python: cv.RETR_EXTERNAL

retrieves only the extreme outer contours. It sets hierarchy[i][2]=hierarchy[i][3]=-1 for all the contours.

RETR_LIST 

Python: cv.RETR_LIST

retrieves all of the contours without establishing any hierarchical relationships.

RETR_CCOMP 

Python: cv.RETR_CCOMP

retrieves all of the contours and organizes them into a two-level hierarchy. At the top level, there are external boundaries of the components. At the second level, there are boundaries of the holes. If there is another contour inside a hole of a connected component, it is still put at the top level.

RETR_TREE 

Python: cv.RETR_TREE

retrieves all of the contours and reconstructs a full hierarchy of nested contours.

RETR_FLOODFILL 

Python: cv.RETR_FLOODFILL

1. RETR_LIST

这是最简单的一种寻找方式,它不建立轮廓间的子属关系,也就是所有轮廓都属于同一层级。这样,hierarchy中的后两个值[First Child, Parent]都为-1。比如同样的图,我们使用cv.RETR_LIST来寻找轮廓:

contours, hierarchy = cv2.findContours(thresh, cv2.RETR_LIST, 2)
print(hierarchy)
# 结果如下
[[[ 1 -1 -1 -1]
  [ 2  0 -1 -1]
  [ 3  1 -1 -1]
  [ 4  2 -1 -1]
  [ 5  3 -1 -1]
  [ 6  4 -1 -1]
  [ 7  5 -1 -1]
  [-1  6 -1 -1]]]

 因为没有从属关系,所以轮廓0的下一条是1,1的下一条是2……

如果你不需要轮廓层级信息的话,cv.RETR_LIST更推荐使用,因为性能更好

2. RETR_TREE

cv.RETR_TREE就是之前我们一直在使用的方式,它会完整建立轮廓的层级从属关系,前面已经详细说明过了。

3. RETR_EXTERNAL

这种方式只寻找最高层级的轮廓,也就是它只会找到前面我们所说的3条0级轮廓:

实验讲解 RETR_EXTERNAL

contours, hierarchy = cv.findContours(thresh, cv.RETR_EXTERNAL, 2)
print(len(contours), hierarchy, sep='\n')
# 结果如下
3
[[[ 1 -1 -1 -1]
  [ 2  0 -1 -1]
  [-1  1 -1 -1]]]

实验结果

4. RETR_CCOMP

相比之下cv.RETR_CCOMP比较难理解,它把所有的轮廓只分为2个层级,不是外层的就是里层的。结合代码和图片,我们来理解下:

实验讲解 RETR_CCOMP

 

contours, hierarchy = cv.findContours(thresh, cv.RETR_CCOMP, 2)
print(hierarchy)
# 结果如下
[[[ 1 -1 -1 -1]
  [ 2  0 -1 -1]
  [ 4  1  3 -1]
  [-1 -1 -1  2]
  [ 6  2  5 -1]
  [-1 -1 -1  4]
  [ 7  4 -1 -1]
  [-1  6 -1 -1]]]

实验结果

使用这个参数找到的轮廓序号与之前不同。
图中括号里面1代表外层轮廓,2代表里层轮廓。比如说对于轮廓2,Next就是4,Previous是1,它有里层的轮廓3,所以First Child=3,但因为只有两个层级,它本身就是外层轮廓,所以Parent=-1。大家可以针对其他的轮廓自己验证一下。 

绘制轮廓线drawContours()

◆ drawContours()

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:
 image=cv.drawContours(image, contours, contourIdx, color[, thickness[, lineType[, hierarchy[, maxLevel[, offset]]]]])

绘制轮廓、轮廓或填充轮廓 

如果thickness≥0,则绘制图像中的轮廓轮廓;如果thickness<0,则填充轮廓轮廓所限定的区域。

Parameters

image目标 图像.
contours所有的输入轮廓。每个轮廓被存储为一个点 vector.
contourIdx表示要绘制的轮廓线的参数。如果它是负的,所有的轮廓线都画出来.
color轮廓线的颜色.
thickness绘制轮廓线所用的线的厚度。如果它是负的(例如,thickness=FILLED),轮廓内部被绘制.
lineType线连通度. 参见 LineTypes
hierarchy关于层次结构的可选信息。只有当你想只画一些轮廓线时才需要它 (see maxLevel ).
maxLevel绘制轮廓的最大水平。如果为0,则只绘制指定的轮廓线。如果是1,函数绘制轮廓线和所有嵌套轮廓线。如果是2,函数绘制轮廓,所有嵌套的轮廓,所有嵌套到嵌套的轮廓,以此类推。只有在有层次结构可用时才考虑此参数。
offset可选的轮廓位移参数。将所有绘制的轮廓按指定的偏移量移动=(dx,dy) .

 

◆ LineTypes

enum cv::LineTypes

#include <opencv2/imgproc.hpp>

types of line

Enumerator
FILLED 

Python: cv.FILLED

 
LINE_4 

Python: cv.LINE_4

4-connected line

LINE_8 

Python: cv.LINE_8

8-connected line

LINE_AA 

Python: cv.LINE_AA

antialiased line

参考:https://www.cnblogs.com/wojianxin/p/12602490.html

          opencv4文档

 

轮廓线查找python实现例子: 

def myFindContours():
    """轮廓查找实验示例"""
    img=cv2.imread('GSYT01.JPG') #载入图像
    gray=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY) #转8位灰度图
    himg=cv2.equalizeHist(gray)   #直方图均匀化
    cv2.imshow('原图', img)
    h=img.shape[0]
    w=img.shape[1]
    dstImg=np.zeros((h,w),np.float32) #初始化结果图
    edge = cv2.Canny(himg, 100, 254)  # 边缘提取
    cv2.imshow('边缘', edge)
    ret, binary = cv2.threshold(himg, 200, 255, cv2.THRESH_BINARY) #阈值化。
    #binary=binary>200
    contours, hierarchy=cv2.findContours(edge,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE) #寻找轮廓线

    himg=cv2.cvtColor(himg,cv2.COLOR_GRAY2BGR)

    for contour in contours:
#        x, y, w, h = cv2.boundingRect(contour)
#        area = cv2.contourArea(contour)
        B=nr.randint(1,255)
        G=nr.randint(1,255)
        R=nr.randint(1,255)

        cv2.drawContours(himg, [contour], -1, (B, G, R), 2)

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值