您的位置:首页 > 运维架构

OpenCV学习+常用函数记录③:霍夫变换与轮廓提取

2020-11-01 18:52 771 查看

OpenCV 霍夫变换与轮廓提取

  • 4. 轮廓提取
  • 3. 霍夫变换

    首先放上霍夫变换官方文档:[霍夫直线变换官网文档]

    3.1 霍夫直线

    import cv2 as cv
    import matplotlib.pyplot as plt
    import numpy as np
    
    # 1. 将图片以灰度的方式读取进来
    img = cv.imread("../img/weiqi.jpg", cv.IMREAD_COLOR)
    gray_img = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
    
    # 2. 将图片转成二值图
    _, thresh_img = cv.threshold(gray_img, 0, 255, cv.THRESH_BINARY_INV | cv.THRESH_OTSU)
    
    # 3. 霍夫变换
    # 线段以像素为单位的距离精度,double类型的,推荐用1.0
    rho = 1
    # 线段以弧度为单位的角度精度,推荐用numpy.pi/180(弧度变换的步长)
    theta = np.pi / 180
    # 累加平面的阈值参数,int类型,超过设定阈值才被检测出线段,值越大,基本上意味着检出的线段越长,检出的线段个数越少。(一条直线至少包含十个像素点)
    threshold = 10
    # 线段以像素为单位的最小长度
    min_line_length = 25
    # 同一方向上两条线段判定为一条线段的最大允许间隔(断裂),超过了设定值,则把两条线段当成一条线段,值越大,允许线段上的断裂越大,越有可能检出潜在的直线段
    max_line_gap = 3
    
    lines = cv.HoughLinesP(thresh_img, rho, theta, threshold, minLineLength=min_line_length, maxLineGap=max_line_gap)
    
    dst_img = img.copy()
    
    for line in lines:
    x1, y1, x2, y2 = line[0]
    cv.line(dst_img, (x1, y1), (x2, y2), (0, 0, 255), 2)
    
    cv.imshow("src", img)
    cv<
    12bcb
    span class="token punctuation">.imshow("gray_img", gray_img)
    cv.imshow("thresh_img", thresh_img)
    cv.imshow("dst_img", dst_img)
    
    cv.waitKey(0)

    3.2 霍夫圆

    import cv2 as cv
    import numpy as np
    
    # 1. 将图片以灰度的方式读取进来
    img = cv.imread("../img/weiqi.jpg", cv.IMREAD_COLOR)
    gray_img = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
    
    # 2. 霍夫圆形检测
    def hough_circle(gray_img):
    # 定义检测图像中圆的方法。目前唯一实现的方法是cv2.HOUGH_GRADIENT
    method = cv.HOUGH_GRADIENT
    # 累加器分辨率与图像分辨率的反比。例如,如果dp = 1,则累加器具有与输入图像相同的分辨率。如果dp = 2,则累加器的宽度和高度都是一半。
    dp = 1
    # 检测到的圆的圆心之间最小距离。如果minDist太小,则可能导致检测到多个相邻的圆。如果minDist太大,则可能导致很多圆检测不到。
    minDist = 20
    # param1 Canny算法阈值上线
    # param2 cv2.HOUGH_GRADIENT方法的累加器阈值。阈值越小,检测到的圈子越多。
    # minRadius : 最小的半径,如果不确定,则不指定
    # maxRadius : 最大的半径,若不确定,则不指定
    circles = cv.HoughCircles(gray_img, method, dp, minDist=minDist, param1=70, param2=30, minRadius=0, maxRadius=20)
    
    dst_img = img.copy()
    for circle in circles[0, :]:
    # 圆心坐标,半径
    x, y, r = circle
    # 绘制圆心
    cv.circle(dst_img, (x, y), 2, (0, 255, 0), 1)
    # 绘制圆形
    cv.circle(dst_img, (x, y), r, (0, 0, 255), 2)
    
    cv.imshow("src", img)
    cv.imshow("result", dst_img)
    
    # 3. 调用函数,寻找霍夫圆
    hough_circle(gray_img)
    
    cv.waitKey(0)
    cv.destroyAllWindows()

    4. 轮廓提取

    • 基于图像边缘提取或二值化的基础寻找对象轮廓
    • 边缘提取的阈值会最终影响轮廓发现的结果
    • 主要API有以下两个
      findContours
      发现轮廓
    • drawContours
      绘制轮廓

    4.1 查找轮廓

    处理的图像, 轮廓列表, 继承关系 = cv.findContours(图像, 轮廓检索模式, 轮廓检索算法)
    
    # hierarchy[i][3],分别表示第i个轮廓的后一个轮廓、前一个轮廓、父轮廓、内嵌轮廓的索引编号

    轮廓检索模式:

    RETR_EXTERNAL
    只检测最外层轮廓
    RETR_LIST
    提取所有轮廓,并放置在list中,检测的轮廓不建立等级关系
    RETR_CCOMP
    提取所有轮廓,并将轮廓组织成双层结构(two-level hierarchy),顶层为连通域的外围边界,次层位内层边界
    RETR_TREE
    提取所有轮廓并重新建立网状轮廓结构

    轮廓检索算法:

    CHAIN_APPROX_NONE
    获取每个轮廓的每个像素,相邻的两个点的像素位置差不超过1
    CHAIN_APPROX_SIMPLE
    压缩水平方向,垂直方向,对角线方向的元素,只保留该方向的重点坐标,如果一个矩形轮廓只需4个点来保存轮廓信息
    CHAIN_APPROX_TC89_L1
    Teh-Chinl链逼近算法
    CHAIN_APPROX_TC89_KCOS
    Teh-Chinl链逼近算法

    4.2 绘制轮廓

    cv.drawContours(图像, 轮廓列表, 轮廓索引 如-1则绘制所有, 轮廓颜色, 轮廓的宽度)
    ((x,y),radius) = cv.minEnclosingCircle(contour)		# 绘制外切圆

    实现步骤:

    1. 读取图片
    2. 将图片转成一张灰色图片
    3. 对图片进行二值化处理
    4. 使用findContours查找轮廓
    5. 对轮廓进行处理
    import cv2 as cv
    
    # 1. 读取图片
    def read_rgb_img(img_name):
    rgb_img = cv.imread(img_name, cv.IMREAD_COLOR)
    cv.imshow("rgb img", rgb_img)
    return rgb_img
    
    # 2. 将图片转成一张灰色图片
    def convert_rgb2gray(img):
    gray_img = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
    return gray_img
    
    # 3. 对图片进行二值化处理
    def convert_gray2binary(img):
    # binary_img = cv.adaptiveThreshold(img, 255, cv.ADAPTIVE_THRESH_GAUSSIAN_C, cv.THRESH_BINARY, 5, 2)
    _, binary_img = cv.threshold(img, 0, 255, cv.THRESH_BINARY_INV | cv.THRESH_OTSU)
    return binary_img
    
    # 4. 使用findContours查找轮廓
    def getContours(img):
    _, contours, hierarchy = cv.findContours(img, cv.RETR_TREE, cv.CHAIN_APPROX_SIMPLE)
    print(contours, hierarchy)
    return contours
    
    # 5. 对轮廓进行处理
    def draw_contours(img, contours):
    index = -1                  			# 所有的轮廓
    thickness = 2              	 			# 轮廓的宽度
    color = (255, 125, 125)    				# 轮廓的颜色
    imgg = cv.drawContours(img, contours, index, color, thickness)
    cv.imshow('draw contours', imgg)		# 画出轮廓图
    for i, c in enumerate(contours):
    circle = cv.minEnclosingCircle(c)
    ((x, y), radius) = circle
    cv.circle(imgg, (int(x), int(y)), int(radius), (0, 0, 255), 2)
    
    if __name__ == '__main__':
    img_name = "../img/shape.jpg"
    
    rgb_img = read_rgb_img(img_name)
    gray_img = convert_rgb2gray(rgb_img)
    binary_imgage = convert_gray2binary(gray_img)
    contours = getContours(binary_imgage)
    draw_contours(rgb_img, contours)
    
    cv.imshow("gray_img", gray_img)					# 画出灰度图
    cv.imshow("binary_img", binary_imgage)			# 画出二值图
    cv.imshow('draw_contours_circle', rgb_img)		# 画出有外接圆的轮廓图
    cv.waitKey(0)
    cv.destroyAllWindows()
  • 内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
    标签: