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

相关推荐
彭祥.4 小时前
Jetson边缘计算主板:Ubuntu 环境配置 CUDA 与 cudNN 推理环境 + OpenCV 与 C++ 进行目标分类
c++·opencv·分类
烛阴4 小时前
简单入门Python装饰器
前端·python
好开心啊没烦恼4 小时前
Python 数据分析:numpy,说人话,说说数组维度。听故事学知识点怎么这么容易?
开发语言·人工智能·python·数据挖掘·数据分析·numpy
面朝大海,春不暖,花不开4 小时前
使用 Python 实现 ETL 流程:从文本文件提取到数据处理的全面指南
python·etl·原型模式
Tony沈哲5 小时前
macOS 上为 Compose Desktop 构建跨架构图像处理 dylib:OpenCV + libraw + libheif 实践指南
opencv·算法
2301_805054565 小时前
Python训练营打卡Day59(2025.7.3)
开发语言·python
万千思绪6 小时前
【PyCharm 2025.1.2配置debug】
ide·python·pycharm
微风粼粼7 小时前
程序员在线接单
java·jvm·后端·python·eclipse·tomcat·dubbo
云天徽上8 小时前
【PaddleOCR】OCR表格识别数据集介绍,包含PubTabNet、好未来表格识别、WTW中文场景表格等数据,持续更新中......
python·ocr·文字识别·表格识别·paddleocr·pp-ocrv5
你怎么知道我是队长8 小时前
python-input内置函数
开发语言·python