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

163
0
2020年12月6日 09时15分

OpenCV 霍夫变换与轮廓提取

 

  • 3. 霍夫变换
    • 3.1 霍夫直线
    • 3.2 霍夫圆
  • 4. 轮廓提取
    • 4.1 查找轮廓
    • 4.2 绘制轮廓

 

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.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()

 

 

发表评论

后才能评论