首页 最新 热门 推荐

  • 首页
  • 最新
  • 热门
  • 推荐

python-opencv 边缘检测、直线检测、圆检测

  • 25-02-18 13:41
  • 2713
  • 7013
blog.csdn.net

文章目录

    • Canny算法
    • 霍夫变换-直线检测
    • 霍夫变换-圆形检测

Canny算法

除了将目标与背景分离开来,边缘检测也同样是一种图像分割方法,从分割结果来看,adaptiveThreshold函数显然就采取了类似边缘检测的划分方案。

Canny在1986年提出了一种边缘检测算法,因其卓越的性能和准确性而广泛应用于各种图像分析领域。opencv中提供了这种算法,其操作步骤如下

  1. 高斯滤波:采用 5 × 5 5\times5 5×5的高斯滤波,对图像进行平滑,以降低灰度波动,使边缘更加明显。
  2. 梯度计算:用Sobel核函数对图像滤波,得到两个方向的一阶导数 G x , G y G_x, G_y Gx​,Gy​,从而得到图像的梯度 G x 2 + G y 2 \sqrt{G_x^2+G_y^2} Gx2​+Gy2​ ​以及辐角 tan ⁡ − 1 G y G x \tan^{-1}\frac{G_y}{G_x} tan−1Gx​Gy​​
  3. 非极大值抑制:即抑制那些不是局部最大值的梯度值,即一个像素点,只有其梯度幅度大于周围像素点时,才被认为是边缘点。
  4. 双阈值处理:通过高阈值 t 2 t_2 t2​和低阈值 t 1 t_1 t1​来进一步判断边缘,某点若梯度幅度大于 t 2 t_2 t2​,则被认为是边缘点;若处于 t 2 t_2 t2​和 t 1 t_1 t1​之间,则被认为是潜在的边缘点。
  5. 边缘跟踪和连接:最后,算法跟踪由边缘像素点组成的线,并连接它们以形成完整的边缘。

令 t 1 = 100 , t 2 = 200 t_1=100,t_2=200 t1​=100,t2​=200,则Canny算法的边缘检测结果如下

在这里插入图片描述

实现代码如下。

imgs = {}
imgs['Original'] = ascent().astype(np.uint8)
imgs['edges'] = cv2.Canny(img,100,200)

for i,key in enumerate(imgs, 1):
    plt.subplot(1,2,i)
    plt.imshow(imgs[key],cmap = 'gray')
    plt.title(key)
    plt.axis('off')

plt.show()
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

【Canny】即为Canny边缘检测函数,其输入参数分别是待检测图像和阈值 t 1 , t 2 t_1, t_2 t1​,t2​。

霍夫变换-直线检测

在获取图像边缘后,可能会对边缘的形状产生兴趣。1962年,Hough提出一种直线和圆的识别方案,思路是将图像中的点映射到一个参数空间,这个空间中涵盖了某个几何形状的所有参数,这个变换便被称作霍夫变换(Hough Transform, HT)。

Python中提供了基于HT的直线检测函数,可实现如下效果。

在这里插入图片描述

代码为

img = ascent().astype(np.uint8)
m, n = img.shape

edges = cv2.Canny(img, 50, 150, apertureSize = 3)
lines = cv2.HoughLines(edges,1.1,np.pi/180,200)
  • 1
  • 2
  • 3
  • 4
  • 5

【HoughLines】就是HT直线检测函数,其输入的四个参数分别是待检测图像、以像素为单位的距离精度 p r p_r pr​、以弧度为单位的角度精度 p θ p_\theta pθ​以及累加平面的阈值参数。 p r , p θ p_r, p_\theta pr​,pθ​这两个值设得越大,则会检查出越多的直线。

其检测检测结果由 ( ρ , θ ) (\rho, \theta) (ρ,θ)来表示,其中 ρ \rho ρ表示直线与坐标原点 ( 0 , 0 ) (0,0) (0,0)的距离, θ \theta θ是直线的垂线与 x x x轴的夹角。从而直线方程可表示为点法式

x cos ⁡ θ + y sin ⁡ θ − ρ = 0 x\cos\theta+y\sin\theta-\rho=0 xcosθ+ysinθ−ρ=0

对于尺寸为 m m m行 n n n列的图像来说,四个边框分别是 x = 0 , x = n , y = 0 , y = m x=0, x=n, y=0, y=m x=0,x=n,y=0,y=m,记 c = cos ⁡ θ , s = sin ⁡ θ c=\cos\theta, s=\sin\theta c=cosθ,s=sinθ,则直线与四个边框的交点分别为

( 0 , ρ s ) ( n , ρ − n c s ) ( ρ c , 0 ) ( ρ − m s c , m ) (0,ρs)(n,ρ−ncs)(ρc,0)(ρ−msc,m) (0,sρ​)(cρ​,0)​(n,sρ−nc​)(cρ−ms​,m)​

从而绘图代码如下

fig, ax = plt.subplots(1,2)

ax[0].imshow(img, cmap='gray')
for line in lines:
    rho,theta = line[0]
    c = np.cos(theta)
    s = np.sin(theta)
    xs = [0, n, rho/c, (rho-m*s)/c]
    ys = [rho/s, (rho-n*c)/s, 0, m]
    i1, i2 = np.argsort(xs)[1:3]
    ax[0].plot([xs[i1], xs[i2]], [ys[i1], ys[i2]], ls='--')
    ax[1].plot([xs[i1], xs[i2]], [ys[i1], ys[i2]], ls='--')

plt.grid()
plt.show()
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

霍夫变换-圆形检测

opencv中提供了基于霍夫变换的圆形检测方法,可实现下图所示的检测结果。

在这里插入图片描述

其实现代码如下。

path = 'coins.png'

coins = {}
img = cv2.imread(path, cv2.IMREAD_COLOR)
gray = cv2.cv2tColor(img, cv2.COLOR_BGR2GRAY)

coins['gray'] = cv2.medianBlur(gray, 25)
coins['edge'] = cv2.Canny(coins['gray'],100,200)

rows = gray.shape[0]
circles = cv2.HoughCircles(coins['gray'], cv2.HOUGH_GRADIENT,
        1, 150, param1=100, param2=30,
        minRadius=1, maxRadius=300)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

【HoughCircles】是opencv提供的基于霍夫变换的圆形检测工具。

函数参数说明:

  • image: 待检测灰度图像。
  • method: 检测圆的方法。
  • dp: 霍夫变换的分辨率,值越大,检测的圆越少,但越准确。
  • minDist: 圆心之间的最小距离。
  • param1: 边缘检测时使用Canny算子的高阈值,低阈值是高阈值的一半。
  • param2: 用于圆心检测的参数。
  • minRadius, maxRadius: 圆半径的最小值和最大值。

其中,opencv通提供了四种检测圆的方法,其method参数可选值如下

  • 【cv2.HOUGH_GRADIENT】霍夫梯度法,通过计算图像中的梯度来确定圆心的可能位置,然后对这些位置进行投票,以确定真实的圆心。这种方法的问题是对噪声敏感。
  • 【cv2.HOUGH_GRADIENT_ALT】霍夫梯度法的另一种实现。
  • 【cv2.HOUGH_PROBABILISTIC】概率霍夫变换,与霍夫梯度法的区别是,并不通过全局投票来确定圆心,而检查一些候选点是否符合圆的方程,它通常会产生较少的假阳性结果,但可能检测不到某些圆。
  • 【cv2.HOUGH_MULTI_SCALE】多尺度霍夫变换,将在不同尺度上应用霍夫变换,对缩放、旋转和倾斜变化具有更好的鲁棒性。和其他方法相比,该方法可能会检测到更多的圆,但也更吃计算资源。

绘图代码如下。

coins['circles'] = img
for i,key in enumerate(coins,1):
    ax = plt.subplot(1,3,i)
    plt.title(key)
    plt.imshow(coins[key])
    plt.axis('off')

th = np.deg2rad(np.arange(361))
for x,y,r in circles[0]:
    xs = x + r*np.cos(th)
    ys = y + r*np.sin(th)
    plt.scatter(x, y, marker='*', color='red')
    plt.plot(xs, ys, color='red')

plt.show()
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
注:本文转载自blog.csdn.net的微小冷的文章"https://tinycool.blog.csdn.net/article/details/139230108"。版权归原作者所有,此博客不拥有其著作权,亦不承担相应法律责任。如有侵权,请联系我们删除。
复制链接
复制链接
相关推荐
发表评论
登录后才能发表评论和回复 注册

/ 登录

评论记录:

未查询到任何数据!
回复评论:

分类栏目

后端 (14832) 前端 (14280) 移动开发 (3760) 编程语言 (3851) Java (3904) Python (3298) 人工智能 (10119) AIGC (2810) 大数据 (3499) 数据库 (3945) 数据结构与算法 (3757) 音视频 (2669) 云原生 (3145) 云平台 (2965) 前沿技术 (2993) 开源 (2160) 小程序 (2860) 运维 (2533) 服务器 (2698) 操作系统 (2325) 硬件开发 (2492) 嵌入式 (2955) 微软技术 (2769) 软件工程 (2056) 测试 (2865) 网络空间安全 (2948) 网络与通信 (2797) 用户体验设计 (2592) 学习和成长 (2593) 搜索 (2744) 开发工具 (7108) 游戏 (2829) HarmonyOS (2935) 区块链 (2782) 数学 (3112) 3C硬件 (2759) 资讯 (2909) Android (4709) iOS (1850) 代码人生 (3043) 阅读 (2841)

热门文章

101
推荐
关于我们 隐私政策 免责声明 联系我们
Copyright © 2020-2025 蚁人论坛 (iYenn.com) All Rights Reserved.
Scroll to Top