1544 字
8 分钟
OpenCV:霍夫变换

1. 介绍#

霍夫变换一种在图像中寻找直线、圆形以及其他简单形状的方法

最初的霍夫变换只能用于检测直线,经过发展后,霍夫变换不仅能够识别直线,还能识别其他简单的图形结构,常见的有 椭圆

霍夫直线变换用来在图像内寻找直线,可以用函数 cv2.HoughLines() 和函数 cv2.HoughLinesP() 实现;霍夫圆变换用来在图像内寻找圆,可以用函数 cv2.HoughCircles() 实现。

2. 霍夫直线变换#

2.1 基本原理#

  • 笛卡儿空间内的直线y = k·x + b霍夫空间内的点(k, b),互相对应。
  • 霍夫空间内的直线b = -x·k + y笛卡儿空间内点(x, y),互相对应。
  • 极坐标系内的一个点霍夫坐标系内的一条正弦曲线,互相对应。
  • 霍夫空间内,经过一个点的直线越多,说明其在笛卡儿空间映射的直线由越多的点所穿过的。
  • 霍夫变换选择直线基本思路是: 选择有尽可能多直线交汇的点

  • 在使用霍夫变换进行检测时,经常存在非常严重的误检测,于是出现了霍夫变换的改进版——概率霍夫变换
    • 改进1所接受直线的最小长度。如果有超过阈值个数的像素点构成了一条直线,但是这条直线很短,那么就不会接受该直线作为判断结果。
    • 改进2接受直线时允许的最大像素点间距。如果有超过阈值个数的像素点构成了一条直线,但是这组像素点之间的距离都很远,就不会接受该直线作为判断结果。

  • 在实际检测中,需要不断调整参数才能得到最优结果。

2.2 使用方法#

  • 通过函数cv2.HoughLines()实现霍夫直线变换
  • 函数原型lines = cv2.HoughLines( image, rho, theta, threshold )
  • 参数说明
    • image原始图像,必须是8位的、单通道二值图像
    • rho以像素为单位的距离r的精度,默认精度为1
    • theta角度𝜃的精度,默认精度为π/180,表示要搜索所有可能的角度
    • threshold阈值。值越小,判定出的直线就越多。
    • linesnumpy.ndarray类型数据。每个元素都是一对浮点数,表示检测到的直线的参数,即 (r, θ)
  • 使用函数cv2.HoughLines()检测到的是图像中的直线不是线段,检测到的直线是没有端点的。

  • 通过函数cv2.HoughLinesP()实现霍夫直线变换
  • 函数原型lines = cv2.HoughLinesP( image, rho, theta, threshold, minLineLength, maxLineGap )
  • 参数说明
    • image原始图像,必须是8位的、单通道二值图像
    • rho以像素为单位的距离r的精度,默认精度为1
    • theta角度𝜃的精度,默认精度为π/180,表示要搜索所有可能的角度
    • threshold阈值。值越小,判定出的直线就越多。
    • minLineLength:控制“接受直线的最小长度”的值,默认值为0。
    • maxLineGap:控制“接受共线线段之间的最小间隔”的值,即在一条线中两点的最大间隔,默认值为0。
    • linesnumpy.ndarray类型数据。每个元素都是一对浮点数,表示检测到的直线的参数,即 (x1, y1, x2, y2)

2.3 示例#

  • 霍夫直线变换
import cv2
import numpy as np
img = cv2.imread("board.png")
img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
cv2.imwrite("board_gray.png", img_gray)
val, img_edge = cv2.threshold(src=img_gray, thresh=127, maxval=255, type=cv2.THRESH_BINARY_INV)
cv2.imwrite("board_edge.png", img_edge)
lines = cv2.HoughLines(img_edge, 1, np.pi/4, 146)
D = max(img.shape[0], img.shape[1])
for line in lines:
rho, theta = line[0]
x = rho * np.cos(theta)
y = rho * np.sin(theta)
x1 = int(x - D * np.sin(theta))
y1 = int(y + D * np.cos(theta))
x2 = int(x + D * np.sin(theta))
y2 = int(y - D * np.cos(theta))
cv2.line(img, (x1,y1), (x2,y2), (0,0,255), 1)
cv2.imwrite("HoughLines.png", img)
  • 概率霍夫直线变换
import cv2
import numpy as np
img = cv2.imread("board.png")
img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
cv2.imwrite("board_gray.png", img_gray)
val, img_edge = cv2.threshold(src=img_gray, thresh=127, maxval=255, type=cv2.THRESH_BINARY_INV)
cv2.imwrite("board_edge.png", img_edge)
lines = cv2.HoughLinesP(img_edge, 1, np.pi/180, 120, minLineLength=150, maxLineGap=10)
for line in lines:
x1,y1,x2,y2 = line[0]
cv2.line(img, (x1,y1), (x2,y2), (0,0,255), 1)
cv2.imwrite("HoughLinesP.png", img)
原图灰度图像二值化图像
霍夫变换概率霍夫变换

3. 霍夫圆变换#

  • 只要是能够用一个参数方程表示的对象,都适合用霍夫变换来检测
  • 在霍夫圆变换中,需要考虑圆半径r圆心x坐标圆心y坐标共3 个参数。采用的策略是两轮筛选:第1轮筛选找出可能存在圆心位置,第2轮根据第1轮的结果筛选出半径大小
  • 霍夫圆变换也有用于决定是否接受圆的参数:圆心间的最小距离圆的最小半径圆的最大半径
  • 在实际检测中,需要不断调整参数才能得到最优结果。

3.1 使用方法#

  • 通过函数cv2.HoughCircles()实现霍夫圆变换

  • 函数原型circles = cv2.HoughCircles( image, method, dp, minDist, param1, param2, minRadius, maxRadius )

  • 参数说明

    • image原始图像,必须是8位的、单通道二值图像
    • method检测方法
    • dp累计器分辨率,用来指定图像分辨率圆心累加器分辨率的比例。
    • minDist圆心间的最小间距。如果存在圆心间距离小于该值的多个圆,则仅有一个会被检测出来。因此,如果该值太小,则会有多个临近的圆被检测出来;如果该值太大,则可能会在检测时漏掉一些圆。
    • param1对应Canny边缘检测器的高阈值。缺省时值为100。
    • param2值越大,检测到的圆越少; 值越小,检测到的圆越多。缺省时值为100。
  • minRadius圆半径的最小值小于该值的圆不会被检测出来。缺省值,默认为0。

    • maxRadius圆半径的最大值大于该值的圆不会被检测出来。缺省值,默认为0。
    • circlesnumpy.ndarray类型数据,由圆心坐标半径构成。

3.2 示例#

import cv2
import numpy as np
img = cv2.imread("chess.jpg")
img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
img_gray = cv2.medianBlur(img_gray, 3)
cv2.imwrite("chess_gray.png", img_gray)
circles = cv2.HoughCircles(img_gray, cv2.HOUGH_GRADIENT, 1, 180, param1=50, param2=30, minRadius=90, maxRadius=100)
circles = np.uint16(np.around(circles))
for i in circles[0,:]:
cv2.circle(img, (i[0],i[1]), 2, (255,255,255), 12)
cv2.circle(img, (i[0],i[1]), i[2], (0,255,255), 12)
cv2.imwrite("HoughCircles.png", img)
霍夫变换灰度图像霍夫圆变换
封面
示例歌曲
示例艺术家
封面
示例歌曲
示例艺术家
0:00 / 0:00