图像轮廓——findContours和drawContours、逼近多边形approxPolyDP

一、图像轮廓

图像轮廓是指将边缘连接起来形成的一个整体,用于后续计算。

# 轮廓发现:基于阈值化
def contours_demo(image):
    # dst = cv.GaussianBlur(image,(3,3),0)
    # gray = cv.cvtColor(dst, cv.COLOR_RGB2GRAY)
    # ret, binary = cv.threshold(gray, 0, 255, cv.THRESH_BINARY | cv.THRESH_OTSU)
    # cv.imshow('binary image', binary)
    binary = edge_demo(image)
    # findContours:发现轮廓;
    """
    findContours(image, mode, method, contours=None, hierarchy=None, offset=None)
        image:8位单通道图像,所有非零值被处理为1,所有零值保持不变
        mode:轮廓检索模式,如RETR_EXTERNAL只检测外轮廓
        method:轮廓的近似方法,如CHAIN_APPROX_SIMPLE压缩水平方向、垂直方向、对角线方向的元素,只保留该方向上的终点坐标。
        contours:检测到的轮廓。每条轮廓线存储为一个点的向量
        hierarchy:可选输出向量(如std::vector),包含图像拓扑信息。它有和等高线的数量一样多
        [1,-1,-1,-1]:1表示第一个轮廓;第2位-1表示前一个轮廓不存在;第3位-1表示不存在子轮廓;第4位-1表示不存在父轮廓
        offset:每个轮廓点移动的可选偏移量。这是有用的从图像感兴趣区域提取轮廓线,然后在整个图像环境中进行分析。
    """
    contours, heriachy = cv.findContours(binary, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE)
    for i, contour in enumerate(contours):
        # drawContours:绘制轮廓;contours:所有的轮廓;-1:像素,把轮廓全部填充
        """
        drawContours(image, contours, contourIdx, color, thickness=None, lineType=None, hierarchy=None, maxLevel=None, offset=None)
            image:待绘制轮廓的图像
            contours:需要绘制的轮廓
            contourIdx:需要绘制的边缘索引。一个整数或零表示绘制对应索引号的轮廓,负数表示绘制全部轮廓
            color:绘制的颜色,用BGR格式表示
            thickness:可选,表示绘制轮廓时所用画笔的粗细,-1表示绘制实心轮廓
            lineType:可选,表示绘制轮廓时所用的线型
            hierarchy:对应函数cv.findContours所输出的层次信息
            maxLevel:控制所绘制轮廓层次的深度。非零整数表示绘制最高层及以下的相同数量层级的轮廓
            offset:偏移参数,使轮廓偏移到不同位置展示出来
        """
        cv.drawContours(image, contours, i, (0, 0, 255), 2)
        print(i)
    cv.imshow('detect_contours', image)

在这里插入图片描述

二、对象测量

1、moments函数
在这里插入图片描述
(1)cv.moments所返回的特征值能够用来比较两个轮廓是否相似。零阶矩“m00”表示一个轮廓的面积。

(2)中心矩通过减去均值获取平移不变性,从而忽略两个对象的位置关系,帮助比较不同位置上两个对象的一致性。

(3)归一化中心矩通过除以物体总尺寸获得缩放不变性,其提取的属性值具有平移不变性和缩放不变性,得以比较。

2、逼近多边形

原理:首先从轮廓中找到距离最远的两个点,将两点相连。接着,在轮廓上找到一个离当前直线最远的点,将该点与原有直线连成一个封闭的多边形,得到一个三角形。不断迭代,直到轮廓上所有的点到当前多边形的距离都小于函数approxPolyDP的epsilon的值。
在这里插入图片描述

# 轮廓分析:计算每个轮廓的弧长与面积,像素单位
def measure_object(image):
    gray = cv.cvtColor(image, cv.COLOR_RGB2GRAY)
    ret, binary = cv.threshold(gray, 0, 255, cv.THRESH_BINARY | cv.THRESH_OTSU)
    cv.imshow('binary image', binary)
    dst = cv.cvtColor(binary, cv.COLOR_GRAY2RGB)
    contours, hireachy = cv.findContours(binary, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE)
    for i, contour in enumerate(contours):
        # contourArea:计算轮廓的面积
        area = cv.contourArea(contour)
        print('contour area : %s'%area)
        # boundingRect:绘制轮廓的矩形边界,返回矩形边界的左上角顶点坐标值及矩形边界的宽度和高度。
        x, y, w, h = cv.boundingRect(contour)
        # 宽、高比=宽度/高度
        rate = min(w, h) / max(w, h)
        print('rectangle rate : %s'% rate)
        # moments:获取轮廓特征
        mm = cv.moments(contour)
        print(type(mm))
        # 得到矩形中心位置
        cx = mm['m10'] / mm['m00']
        cy = mm['m01'] / mm['m00']
        # 对每个轮廓在原来的位置上绘制,绘制中心点
        cv.circle(image, (np.int_(cx), np.int_(cy)), 3, (0, 255, 255), -1)
        # 对每个轮廓绘制外接矩形
        cv.rectangle(image, (x, y), (x + w, y + h), (0, 0, 255), 2)
        cv.imshow('rectangle image', image)
        # approxPolyDP:获取轮廓的多边形拟合结果;epsilon4:越小越折线越逼近真实形状;closed:是否为闭合区域
        """
        approxPolyDP(curve, epsilon, closed, approxCurve=None)
            curve:轮廓
            epsilon:精度,原始轮廓的边界点与逼近多边形边界之间的最大距离
            closed:true表示多边形是封闭的,false表示多边形是不封闭的
            approxCurve:逼近多边形的点集
        """
        approxCurve = cv.approxPolyDP(contour, 4, True)  # 4才能区别出三边形和四边形
        print(approxCurve.shape)
        # 轮廓拟合
       	if approxCurve.shape[0] == 4:
            cv.drawContours(dst, contours, i, (0, 255, 0), 2)
        if approxCurve.shape[0] == 7:
            cv.drawContours(dst, contours, i, (0, 0, 255), 2)
        if approxCurve.shape[0] == 11:
            cv.drawContours(dst, contours, i, (0, 165, 255), 2)
        if approxCurve.shape[0] == 15:
            cv.drawContours(dst, contours, i, (128, 0, 128), 2)
        if approxCurve.shape[0] == 16:
            cv.drawContours(dst, contours, i, (255, 0, 0), 2)
        if approxCurve.shape[0] == 21:
            cv.drawContours(dst, contours, i, (128, 128, 0), 2)
    cv.imshow('measure_object', dst)  # dst:注意返回值


>>contour area : 7950.5
	rectangle rate : 0.992
	<class 'dict'>
	(4, 1, 2)
	
	contour area : 16218.5
	rectangle rate : 0.5625
	<class 'dict'>
	(11, 1, 2)
	
	contour area : 17186.5
	rectangle rate : 1.0
	<class 'dict'>
	(7, 1, 2)
	
	contour area : 19246.5
	rectangle rate : 0.9875776397515528
	<class 'dict'>
	(21, 1, 2)
	
	contour area : 18078.0
	rectangle rate : 0.9934640522875817
	<class 'dict'>
	(15, 1, 2)
	
	contour area : 20040.0
	rectangle rate : 0.9937888198757764
	<class 'dict'>
	(16, 1, 2)

在这里插入图片描述
在这里插入图片描述

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值