OpenCV-轮廓查找与对象测量

轮廓查找

cv2.findContours

在二值图像中查找轮廓

findContours(image, mode, method[, contours[, hierarchy[, offset]]]) -> contours, hierarchy
  • image:寻找轮廓的图像;
  • mode:表示轮廓的检索模式,有四种(本文介绍的都是新的cv2接口):
    • cv2.RETR_EXTERNAL:表示只检测外轮廓
    • cv2.RETR_LIST:检测的轮廓不建立等级关系
    • cv2.RETR_CCOMP :建立两个等级的轮廓,上面的一层为外边界,里面的一层为内孔的边界信息。如果内孔内还有一个连通物体,这个物体的边界也在顶层。
    • cv2.RETR_TREE:建立一个等级树结构的轮廓。
  • method:为轮廓的近似办法
    • cv2.CHAIN_APPROX_NONE 存储所有的轮廓点,相邻的两个点的像素位置差不超过1,即max(abs(x1-x2),abs(y2-y1))==1
    • cv2.CHAIN_APPROX_SIMPLE 压缩水平方向,垂直方向,对角线方向的元素,只保留该方向的终点坐标,例如一个矩形轮廓只需4个点来保存轮廓信息
    • cv2.CHAIN_APPROX_TC89_L1,CV_CHAIN_APPROX_TC89_KCOS 使用teh-Chinl chain 近似算法
    • CV_LINK_RUNS :通过连接为 1 的水平碎片使用完全不同的轮廓提取算法。仅有 CV_RETR_LIST 提取模式可以在本方法中应用
  • offset:每一个轮廓点的偏移量. 当轮廓是从图像 ROI 中提取出来的时候,使用偏移量有用,因为可以从整个图像上下文来对轮廓做分析
  • 返回值:
    • contours:一个列表,每一项都是一个轮廓, 不会存储轮廓所有的点,只存储能描述轮廓的点
    • hierarchy:一个ndarray, 元素数量和轮廓数量一样,每个轮廓contours[i]对应4个hierarchy元素hierarchy[i][0] ~hierarchy[i][3],分别表示后一个轮廓、前一个轮廓、父轮廓、内嵌轮廓的索引编号,如果没有对应项,则该值为负数

cv2.drawContours

绘制轮廓轮廓或填充轮廓

drawContours(image, contours, contourIdx, color[, thickness[, lineType[, hierarchy[, maxLevel[, offset]]]]]) -> image
  • image:指明在哪幅图像上绘制轮廓;image为三通道才能显示轮廓
  • contours:是轮廓本身,在Python中是一个list;
  • contourIdx:指定绘制轮廓list中的哪条轮廓,如果是-1,则绘制其中的所有轮廓。后面的参数很简单。
  • color:线的颜色
  • thickness表明轮廓线的宽度,如果是-1(cv2.FILLED),则为填充模式

示例

def canny(image):
    """canny边缘提取"""
    blurred = cv.GaussianBlur(image, (3, 3), 0)
    gray = cv.cvtColor(blurred, cv.COLOR_BGR2GRAY)

    grad_x = cv.Sobel(gray, cv.CV_16SC1, 1, 0)
    grad_y = cv.Sobel(gray, cv.CV_16SC1, 0, 1)

    # image:要检测的图像,threshold1:阈值1(最小值),threshold2:阈值2(最大值),使用此参数进行明显的边缘检测,
    # canny_output2 = cv.Canny(grad_x, grad_y, 30, 150)
    canny_output1 = cv.Canny(gray, 50, 150)  # 也可以直接传入gray
    return canny_output1


def contours(image):
    """轮廓查找"""
    binary = canny(image)
    contours, hierarchy = cv.findContours(binary, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE)

    for i, contour in enumerate(contours):
        # 函数 cv2.drawContours() 可以被用来绘制轮廓。它可以根据你提供的边界点绘制任何形状。
        # 它的第一个参数是原始图像,第二个参数是轮廓,一个 Python 列表。
        # 第三个参数是轮廓的索引(在绘制独立轮廓是很有用,当设 置为 -1 时绘制所有轮廓)。
        # 接下来的参数是轮廓的颜色和厚度等。
        cv.drawContours(image, contours, i, (0, 0, 255), 2)  # 2为像素大小,-1时填充轮廓
        print(i)
    cv.imshow("detect contours", image)
def image_contour(image):
    """轮廓查找并描点"""
    gray = cv.cvtColor(image, cv.COLOR_BGR2GRAY)
    ret, binary = cv.threshold(gray, 0, 255, cv.THRESH_BINARY_INV | cv.THRESH_OTSU)  # 图像二值化
    print("threshold value: %s" % ret)  # 输出阈值
    # cv.imshow("binary image", binary)

    contours, hierarchy = cv.findContours(binary, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE)
    for i, contour in enumerate(contours):
        cv.drawContours(image, contours, i, (0, 0, 255), 2)  # 用红色线条画出轮廓

        epsilon = 0.01 * cv.arcLength(contour, True)
        approx = cv.approxPolyDP(contour, epsilon, True)
        cv.drawContours(image, approx, -1, (255, 0, 0), 10)
    cv.imshow("contour_approx", image)

结果:
在这里插入图片描述

注意:

  1. 为了更加准确,要使用二值化图像。在寻找轮廓之前,要进行阈值化处理或者 Canny 边界检测
  2. 在Opencv4.0中 cv.findContours()的返回值以从三个变为二个

参考链接:

对象测量

cv2.contourArea

此函数利用格林公式计算轮廓的面积。对于具有自交点的轮廓,该函数几乎肯定会给出错误的结果。

contourArea(contour[, oriented]) -> retval
  • contour:输入二维的向量。
  • oriented:有方向的区域标志。
    • true:此函数依赖轮廓的方向(顺时针或逆时针)返回一个已标记区域的值。
    • false:默认值。意味着返回不带方向的绝对值

cv2.arcLength

计算轮廓周长或曲线长度

arcLength(curve, closed) -> retval
  • curve:二维点的输入向量
  • closed:指示曲线是否闭合的标志(闭合的(True))

cv2.boundingRect

用一个最小的矩形,把找到的形状包起来

boundingRect(array) -> retval

返回四个值,分别是x,y,w,h;

  • x,y是矩阵左上点的坐标
  • w,h是矩阵的宽和高

cv2.moments

计算多边形或栅格化形状的所有三阶矩

moments(array[, binaryImage]) -> retval
  • array:输入数组,可以是光栅图像(单通道,8-bit或浮点型二维数组),或者是一个二维数组(1 X N或N X 1),二维数组类型为Point或Point2f
  • binaryImage:默认值是false,如果为true,则所有非零的像素都会按值1对待,也就是说相当于对图像进行了二值化处理,阈值为1,此参数仅对图像有效

示例

def image_measure(image):
    """对象测量"""
    gray = cv.cvtColor(image, cv.COLOR_BGR2GRAY)
    ret, binary = cv.threshold(gray, 0, 255, cv.THRESH_BINARY_INV | cv.THRESH_OTSU)  # 图像二值化
    # print("threshold value: %s" % ret)
    # cv.imshow("binary image", binary)

    contours, hierarchy = cv.findContours(binary, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE)
    for i, contour in enumerate(contours):
        cv.drawContours(image, contours, i, (0, 255, 255), 1)  # 用黄色线条画出轮廓

        area = cv.contourArea(contour)  # 计算轮廓面积
        print("contour area:", area)

        # 轮廓周长,第二参数可以用来指定对象的形状是闭合的(True),还是打开的(一条曲线)。
        perimeter = cv.arcLength(contour, True)

        print("contour perimeter:", perimeter)

        x, y, w, h = cv.boundingRect(contour)  # 用矩形框出轮廓
        cv.rectangle(image, (x, y), (x + w, y + h), (0, 0, 255), 2)  # 画出矩形

        rate = min(w, h) / max(w, h)  # 计算矩阵宽高比
        print("rectangle rate", rate)
        
        mm = cv.moments(contour)  # 函数 cv2.moments() 会将计算得到的矩以一个字典的形式返回
        print(mm)
        
        # 计算出对象的重心
        cx = mm['m10'] / mm['m00']
        cy = mm['m01'] / mm['m00']
        
        cv.circle(image, (np.int(cx), np.int(cy)), 2, (0, 255, 255), -1)  # 用实心圆画出重心
        
    cv.imshow("measure_object", image)

结果:
在这里插入图片描述

参考链接:

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

咬着棒棒糖闯天下

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值