python实现椭圆检测

最近在做一个跟测量有关的项目,进行椭圆检测用不到深度学习,仅仅是简单的图像处理,但是确实把我难到了。这里分享两个椭圆检测的思路。一个是通过openCV的椭圆检测器实现的,另一个是通过霍夫变化实现的。

有一说一,看到里面各种没见过的处理方法,我就好像挨了一巴掌,然后告诉我:你的视觉还没入门呢。

一、 完整的椭圆检测流程

拿到一张图片,我们首先需要进行预处理

1. 图像预处理

  • 灰度化:将彩色图像转换为灰度图像,简化处理过程。
  • 滤波:使用高斯滤波、中值滤波等方法去除图像噪声。
  • 边缘检测:应用Canny、Sobel等边缘检测算法来提取图像中的边缘信息。边缘是图像中物体轮廓的基础。

2. 轮廓检测

  • 轮廓查找 :使用OpenCV等库中的findContours函数来检测图像中的轮廓。
  • 轮廓筛选:根据轮廓的大小、形状等特征筛选出可能的椭圆轮廓。

3. 椭圆拟合

  • 最小二乘法拟合:对筛选出的轮廓,使用最小二乘法拟合椭圆。常用的方法有基于代数距离的最小二乘法(直接拟合椭圆方程)和基于几何距离的最小二乘法(如椭圆拟合的RANSAC算法)。
  • 椭圆检测器 :使用专门的椭圆检测器,如OpenCV中的fitEllipse函数,它可以直接在轮廓上拟合一个椭圆。

4. 验证和优化

  • 验证拟合结果:通过计算拟合椭圆的参数(如长短轴、中心点、旋转角度等)与图像中实际轮廓的匹配程度来验证拟合结果。
  • 优化参数:根据实际需求调整滤波、边缘检测、轮廓筛选等步骤的参数,以获得更好的识别效果。

二、 openCV的椭圆检测器操作示例

1. 图像预处理

js 复制代码
## 获取图像
imageSrc =  './images/droppy.png'
image = cv2.imread(imageSrc)

## 1. 灰度处理
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)



# 2. 边缘检测
edges = cv2.Canny(blurred, 50, 150)

## 侵蚀尺度设置
length = max(gray.shape)
# 膨胀和腐蚀可以帮助减少噪声和小轮廓
kernel = np.ones((int(length/20), int(length/20)), np.uint8)
edges = cv2.dilate(edges, kernel, iterations=1)
edges = cv2.erode(edges, kernel, iterations=1)

# 3. 轮廓追踪
_, contours, _ = cv2.findContours(edges, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)

这里为了更好的排除一些小的轮廓,又加了一步侵蚀,效果确实不错。

这是原图、灰度和边缘检测后的对比图。

这是轮廓追踪后的效果图

2. 筛选检测椭圆

对于轮廓需要进行椭圆拟合,然后筛选不合规的椭圆。我这里进行了两步筛选。

  1. 检查椭圆中心是否在图像内部
  2. 对椭圆按照面积进行排序,找到面积最大椭圆

检测长宽比,因为范围不好界定我给注释掉了,需要的可以加上。

js 复制代码
ellipses = []
for contour in contours:
    # 1. 检测椭圆
    ellipse = cv2.fitEllipse(contour)
    # 椭圆中心坐标;椭圆长轴和短轴的长度(直径);椭圆旋转角度
    center, axes, orientation = ellipse

    # 2. 检查椭圆中心是否在图像内部
    if 0 <= center[0] <= image.shape[0] and 0 <= center[1] <= image.shape[1]:
        # min_aspect_ratio = 0.7
        # max_aspect_ratio = 1.3
        # # 检测长宽比
        # if min_aspect_ratio <= aspect_ratio <= max_aspect_ratio:
        ellipses.append(ellipse)
        # cv2.ellipse(image, ellipse, (0, 255, 255), 2) # 绘制黄色
# 3.筛选椭圆
# 对椭圆按照面积进行排序,找到面积最大的圆
sorted_ellipses = sorted(ellipses, key=lambda item: item[1][0] * item[1][1], reverse=True)

selectedEllipse = sorted_ellipses[0]
cv2.ellipse(image, selectedEllipse, (0, 255, 0), 2)
cv2.imshow('Ellipse', image)
cv2.waitKey(0)
cv2.destroyAllWindows()

3. 结果图

绿色就是我们筛选出的椭圆,可以说是非常完美

三、霍夫变换检测操作示例

基本操作方式与上面基本相同

1. 加载图片,转换成灰度图并检测边缘

js 复制代码
from skimage import data,draw,color,transform,feature
import cv2

#1. 加载图片,转换成灰度图并检测边缘
image_rgb = data.coffee()[0:220, 160:420] #裁剪原图像,不然速度非常慢
image_gray = color.rgb2gray(image_rgb)
edges = feature.canny(image_gray, sigma=2.0, low_threshold=0.55, high_threshold=0.8)

2. 执行椭圆变换

js 复制代码
#2. 执行椭圆变换
result =transform.hough_ellipse(edges, accuracy=20, threshold=250,min_size=100, max_size=120)

3. 估计椭圆参数

js 复制代码
#3. 估计椭圆参数
result.sort(order='accumulator') #根据累加器排序
best = list(result[-1]) #排完序后取最后一个
yc, xc, a, b = [int(round(x)) for x in best[1:5]]
orientation = best[5]
selectedEllipse = ((xc,yc),(2*a,2*b),orientation)

4. 在原图上画出椭圆

js 复制代码
#4. 在原图上画出椭圆
cv2.ellipse(image_rgb, selectedEllipse, (0, 255, 0), 2)
cv2.imshow('Ellipse', image_rgb)
cv2.waitKey(0)
cv2.destroyAllWindows()

四、椭圆检测器和霍夫变换的优劣分析

  1. 椭圆检测器精度一般,速度较快。 他核心的原理是获得能够包围轮廓的最小椭圆,所以如果轮廓识别不精准,椭圆识别效果就会很差。

  2. 霍夫变换的精度很好,但是速度太慢,尤其是像素比较大的图片,会让你怀疑是不是程序卡死了。 霍夫变换更贴近我们想要识别的椭圆,但是需要注意对图片进行压缩。

相关推荐
秀儿还能再秀1 小时前
机器学习——简单线性回归、逻辑回归
笔记·python·学习·机器学习
阿_旭2 小时前
如何使用OpenCV和Python进行相机校准
python·opencv·相机校准·畸变校准
幸运的星竹2 小时前
使用pytest+openpyxl做接口自动化遇到的问题
python·自动化·pytest
kali-Myon3 小时前
ctfshow-web入门-SSTI(web361-web368)上
前端·python·学习·安全·web安全·web
B站计算机毕业设计超人3 小时前
计算机毕业设计Python+大模型农产品价格预测 ARIMA自回归模型 农产品可视化 农产品爬虫 机器学习 深度学习 大数据毕业设计 Django Flask
大数据·爬虫·python·深度学习·机器学习·课程设计·数据可视化
布鲁格若门4 小时前
AMD CPU下pytorch 多GPU运行卡死和死锁解决
人工智能·pytorch·python·nvidia
AI原吾4 小时前
探索 Python HTTP 的瑞士军刀:Requests 库
开发语言·python·http·requests
single_ffish4 小时前
XPath:网络爬虫中的数据提取利器
爬虫·python