python-opencv学习笔记(五):霍夫变换

霍夫变换原理

霍夫变换(Hough Transform)是图像处理中的一种特征提取技术,它通过一种投票算法检测具有特定形状的物体。Hough变换是图像处理中从图像中识别几何形状的基本方法之一。Hough变换的基本原理在于利用点与线的对偶性,将原始图像空间的给定的曲线通过曲线表达形式变为参数空间的一个点。这样就把原始图像中给定曲线的检测问题转化为寻找参数空间中的峰值问题。也即把检测整体特性转化为检测局部特性。比如直线、椭圆、圆、弧线等。

说起直线,我们会想到笛卡尔坐标系(即x-y坐标系)下的直线方程,细分之则有点斜式、截距式等, y = k x + b y=kx+b y=kx+b 是我们最熟悉的一种,但直线垂直于x轴时斜率 k k k不存在,这给我们带来许多不便之处。

这时笛卡尔坐标系就能转换为极坐标系: p = x c o s θ + y s i n θ p=xcos\theta + y sin\theta p=xcosθ+ysinθ,变形可得:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
如上图,假定在一个88的平面像素中有一条直线,并且从左上角(1,8)像素点开始分别计算θ为0°、45°、90°、135°、180°时的ρ,图中可以看出ρ分别为1、(9√2)/2、8、(7√2)/2、-1,并给这5个值分别记一票,同理计算像素点(3,6)点θ为0°、45°、90°、135°、180°时的ρ,再给计算出来的5个ρ值分别记一票,此时就会发现ρ = (9√2)/2的这个值已经记了两票了,以此类推,遍历完整个88的像素空间的时候ρ = (9√2)/2就记了5票, 别的ρ值的票数均小于5票,所以得到该直线在这个88的像素坐标中的极坐标方程为 (9√2)/2=xCos45°+y*Sin45°,到此该直线方程就求出来了。(PS:但实际中θ的取值不会跨度这么大,一般是PI/180)。

上述图文说明引用自Opencv学习笔记-----霍夫变换直线检测及原理理解

关于霍夫变换还有其它资料,可以看最后的参考与推荐。这里我就不再介绍了,我们直接来看opencv的代码。

cv2.HoughCircles

import cv2
import numpy as np


planets = cv2.imread('640.jpg')
gray_img = cv2.cvtColor(planets,cv2.COLOR_BGR2GRAY)
img = cv2.medianBlur(gray_img,5)
cimg = cv2.cvtColor(img,cv2.COLOR_GRAY2BGR)


circles = cv2.HoughCircles(img,cv2.HOUGH_GRADIENT,1,120,param1=100,param2=30,minRadius=0,maxRadius=0)
# circles = cv2.HoughCircles(img, cv2.HOUGH_GRADIENT, 1, cimg.shape[0]/64, param1=p1, param2=p2, minRadius=25, maxRadius=0)

circles = np.uint16(np.around(circles))

for i in circles[0,:]:
    #画出外圆
    cv2.circle(planets,(i[0],i[1]),i[2],(0,255,0),6)
    # 画出圆心
    cv2.circle(planets,(i[0],i[1]),2,(0,0,255),3)

cv2.imshow("HoughCirlces",planets)
cv2.imwrite("HoughCirlces.jpg",planets)
cv2.waitKey()
cv2.destroyAllWindows()

上面程序运行后可以得到下方的图像,上一半为原图。

在这里插入图片描述

其中关于cv2.HoughCircles参数解析为:

  1. 第一个参数,InputArray类型的image,输入图像,即源图像,需为8位的单通道二进制图像,可以将任意的源图载入进来后由函数修改成此格式后,再填在这里。
  2. 第二个参数,InputArray类型的lines,检测方法. 目前, 唯一被实现的方法是#HOUGH_GRADIENT
  3. 第三个参数,以像素为单位的距离精度。另一种形容方式是图像分辨率与累加器分辨率之比dp
  4. 第四个参数,直线搜索时的进步尺寸的单位minDist。被检测到的圆心的最小距离. 如果该参数很小, 除了一个正确的圆之外, 该圆的邻居也可能被错误地检测出来. 如果该参数很大, 一些圆将可能被错过
  5. 第五个参数,int类型的param1,第一个指定方法参数的参数. 在#HOUGH_GRADIENT的情况下,其为传递给Canny边缘检测的两个阈值中较高的阈值(较小的阈值为1/2)
  6. 第六个参数,param2有默认值0。在#HOUGH_GRADIENT的情况下, 它是检测阶段圆心的累加器阈值该值越小, 越多错误的圆将被检测出来. 在投票中获得高票的圆将被先返回.
  7. 第七个和第八个参数分别为最小圆圈半径和最大圆圈半径,如果maxRadius圆圈半径为0,那么将是最大的圆半径;如果小于0,则返回圆心位置。

而其中的circles:

  • circles[0][0]将返回x坐标;
  • circles[0][1]将返回y坐标;
  • circles[0][2]返回半径。

实例

霍夫圆变换可以根据需求自动调整:

import cv2
import numpy as np
import sys

def onTrackbarChange(max_slider):
    cimg = np.copy(img)

    p1 = max_slider
    p2 = max_slider * 0.4

    # Detect circles using HoughCircles transform
    circles = cv2.HoughCircles(gray, cv2.HOUGH_GRADIENT, 1, cimg.shape[0]/64, param1=p1, param2=p2, minRadius=25, maxRadius=50)

    # If at least 1 circle is detected
    if circles is not None:
        cir_len = circles.shape[1] # store length of circles found
        circles = np.uint16(np.around(circles))
        for i in circles[0, :]:
            # Draw the outer circle
            cv2.circle(cimg, (i[0], i[1]), i[2], (0, 255, 0), 2)
            # Draw the center of the circle
            cv2.circle(cimg, (i[0], i[1]), 2, (0, 0, 255), 3)
    else:
        cir_len = 0 # no circles detected
    
    # Display output image
    cv2.imshow('Image', cimg)    

    # Edge image for debugging
    edges = cv2.Canny(gray, p1, p2)
    cv2.imshow('Edges', edges)

    

    
if __name__ == "__main__":
    # Read image
    img = cv2.imread(r"brown-eyes.jpg", 1)

    # Convert to gray-scale
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

    # Create display windows
    cv2.namedWindow("Edges")
    cv2.namedWindow("Image")
    

    # Trackbar will be used for changing threshold for edge 
    initThresh = 105 
    maxThresh = 200 

    # Create trackbar
    cv2.createTrackbar("Threshold", "Image", initThresh, maxThresh, onTrackbarChange)
    onTrackbarChange(initThresh)
    
    while True:
        key = cv2.waitKey(1)
        if key == 27:
            break

    cv2.destroyAllWindows()

在这里插入图片描述
同样,还有线变换:

import cv2
import numpy as np
import sys

def onTrackbarChange(max_slider):
	global img
	global dst
	global gray

	dst = np.copy(img)

	th1 = max_slider 
	th2 = th1 * 0.4
	edges = cv2.Canny(img, th1, th2)
	
	# Apply probabilistic hough line transform
	lines = cv2.HoughLinesP(edges, 2, np.pi/180.0, 50, minLineLength=10, maxLineGap=100)

	# Draw lines on the detected points
	for line in lines:
		x1, y1, x2, y2 = line[0]
		cv2.line(dst, (x1, y1), (x2, y2), (0,0,255), 1)

	cv2.imshow("Result Image", dst)	
	cv2.imshow("Edges",edges)

if __name__ == "__main__":
	
	# Read image
	img = cv2.imread('lanes.jpg')
	
	# Create a copy for later usage
	dst = np.copy(img)

	# Convert image to gray
	gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

	# Create display windows
	cv2.namedWindow("Edges")
	cv2.namedWindow("Result Image")
	  

	# Initialize threshold value
	initThresh = 500

	# Maximum threshold value
	maxThresh = 1000

	cv2.createTrackbar("threshold", "Result Image", initThresh, maxThresh, onTrackbarChange)
	onTrackbarChange(initThresh)

	while True:
		key = cv2.waitKey(1)
		if key == 27:
			break

	cv2.destroyAllWindows()

在这里插入图片描述

参考与推荐:

[1]. 经典霍夫变换(Hough Transform)

[2]. Opencv学习笔记-----霍夫变换直线检测及原理理解

[3]. 【OpenCV学习笔记】之霍夫变换(Hough Transform)

[4]. 霍夫变换检测直线的公式推导以及基于opencv的源代码分析并实例实现

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

submarineas

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

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

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

打赏作者

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

抵扣说明:

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

余额充值