OpenCV机器视觉-霍夫变换

霍夫变换

霍夫直线变换

霍夫直线变换用来做直线检测

霍夫直线变换官网文档

绘制经过某点的所有直线的示例代码如下

import cv2 as cv
import matplotlib.pyplot as plt
import numpy as np


def draw_line():
    # 绘制一张黑图
    img = np.zeros((500, 500, 1), np.uint8)
    # 绘制一个点
    cv.line(img, (10, 10), (10, 10), (255), 1)
    cv.imshow("line", img)
    return img


def hough_lines(img):
    rho = 1;
    theta = np.pi / 180
    threshold = 0
    lines = cv.HoughLines(img, rho, theta, threshold)

    dst_img = img.copy()

    for line in lines[:, 0]:
        rho, theta = line
        a = np.cos(theta)
        b = np.sin(theta)
        x = a * rho
        y = b * rho

        x1 = int(np.round(x + 1000 * (-b)))
        y1 = int(np.round(y + 1000 * a))

        x2 = int(np.round(x - 1000 * (-b)))
        y2 = int(np.round(y - 1000 * a))

        cv.line(dst_img, (x1, y1), (x2, y2), (255, 0, 0), 1)

    cv.imshow("li", dst_img)


img = draw_line()
hough_lines(img)

cv.waitKey(0)
cv.destroyAllWindows()

案例:寻找棋盘中的直线

示例代码

import cv2 as cv
import matplotlib.pyplot as plt
import numpy as np

# 1. 将图片以灰度的方式读取进来
img = cv.imread("img/weiqi.jpg", cv.IMREAD_COLOR)
cv.imshow("src", img)

gray_img = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
# cv.imshow("gray",gray_img)
#
flag, thresh_img = cv.threshold(gray_img, 100, 255, cv.THRESH_BINARY_INV)
cv.imshow("thresh_img", thresh_img)

# 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("dst img", dst_img)

cv.waitKey(0)
cv.destroyAllWindows()

霍夫圆

一个圆可以由以下公式表示

OpenCV机器视觉-霍夫变换

其中

OpenCV机器视觉-霍夫变换

是圆心,r是半径。圆环需要3个参数来确定,所以进行圆环检测的累加器必须是三维的,这样效率就会很低,因此OpenCV使用了霍夫梯度法这个巧妙的方法,来使用边界的梯度信息,从而提升计算的效率。

使用步骤:

  1. 霍夫圆检测对噪声敏感,先对对象做中值滤波
  2. 检测边缘,先把可能的圆边缘过滤出来
  3. 根据边缘得到最大概率的圆心,进而得到最佳半径

OpenCV的Logo检测结果:

示例参数以及代码

import cv2
import numpy as np


def hough_circle(img):
    img_copy = img.copy()
    # 中值滤波降噪
    img_copy = cv2.GaussianBlur(img_copy, (3, 3), 0)
    img_copy = cv2.medianBlur(img_copy, 5)

    gray = cv2.cvtColor(img_copy, cv2.COLOR_BGR2GRAY)
    cv2.imshow("gray", gray)

    """
    @param 8-bit 单通道图片
    @param method 检测方法, 当前只有cv2.HOUGH_GRADIENT
    @param dp 累加器分辨率和图像分辨率的反比例, 例如:
        如果 dp=1 累加器和输入图像分辨率相同. 
        如果 dp=2 累加器宽高各为输入图像宽高的一半相同. 
    @param minDist 检测到圆的圆心之间的最小距离。
        如果参数太小,除了真实的一个之外,可能错误地检测到多个相邻的圆圈。
        如果参数太大,可能会遗漏一些圆
    @param param1 参数1。它是两个传递给Canny边缘检测器的较高阈值(较低的阈值是此值的一半)
    @param param2 参数2, 它是检测阶段圆心的累加器阈值。
    	它越小,会检测到更多的假圆圈。较大累加器值对应的圆圈将首先返回。
    @param minRadius 最小圆半径.
    @param maxRadius 最大圆半径. 
        如果<=0, 会使用图片最大像素值
        如果< 0, 直接返回圆心, 不计算半径
    """
    # ../images/coins.jpg
    circles = cv2.HoughCircles(gray, cv2.HOUGH_GRADIENT,
                               dp=1,
                               minDist=50,
                               param1=160,
                               param2=50,
                               minRadius=0,
                               maxRadius=100)

    circles = np.uint16(np.around(circles))
    for i in circles[0, :]:
        # draw the outer circle
        cv2.circle(img_copy, (i[0], i[1]), i[2], (0, 255, 0), 2)
        # draw the center of the circle
        cv2.circle(img_copy, (i[0], i[1]), 2, (0, 0, 255), 3)

    cv2.imshow("detected circles", img_copy)

案例:寻找棋盘中的棋子

示例代码

import cv2 as cv
import numpy as np

img = cv.imread("img/weiqi.jpg", cv.IMREAD_COLOR)
cv.imshow("src", img)
# 将图片转成灰色图片
gray_img = cv.cvtColor(img, cv.COLOR_BGR2GRAY)


# 霍夫圆形检测
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)

    for circle in circles[0, :]:
        # 圆心坐标,半径
        x, y, r = circle
        # 绘制圆心 必须强转成int类型
        cv.circle(img, (int(x), int(y)), 2, (0, 255, 0), 1)
        # 绘制圆形
        cv.circle(img, (int(x), int(y)), int(r), (0, 0, 255), 2)

    cv.imshow("result", img)


# 调用函数,寻找霍夫圆
hough_circle(gray_img)

cv.waitKey(0)
cv.destroyAllWindows()

文章出处登录后可见!

已经登录?立即刷新

共计人评分,平均

到目前为止还没有投票!成为第一位评论此文章。

(0)
青葱年少的头像青葱年少普通用户
上一篇 2022年5月19日
下一篇 2022年5月19日

相关推荐