如何用OpenCV检测车轮图像中的椭圆以实现位姿估计
如何从车轮轮廓中提取有效椭圆点并计算椭圆参数
你已经通过阈值和轮廓检测定位到了车轮的最大轮廓,但冗余点的问题确实会影响椭圆参数的计算。这里有两个直接有效的解决方案,既能过滤冗余点,又能准确得到椭圆的位姿参数:
方案一:轮廓近似过滤冗余点
先通过多边形近似简化原始轮廓,去掉轮胎花纹、噪声带来的冗余点,再用简化后的轮廓拟合椭圆。
方案二:直接对原始轮廓做椭圆拟合(更推荐)
OpenCV的cv2.fitEllipse()函数本身就具备从点集中拟合最优椭圆的能力,它会自动忽略轮廓中的冗余噪声点,直接输出椭圆的关键参数,非常适合你的车轮位姿估计需求。
修改后的完整代码
import sys import numpy as np import matplotlib.pyplot as plt import cv2 from skimage import img_as_ubyte # 测试图片路径 filenames = [ 'back_wheel.png', 'backwheel1.png', 'backwheel2.png', 'backwheel3.png', 'frontwheel1.png', 'frontwheel2.png' ] def getWheel0(filename): image_rgb_orig = cv2.imread(filename) if image_rgb_orig is None: print(f"无法读取图片: {filename}") return image_rgb = image_rgb_orig.copy() print('Original Dimensions : ', image_rgb.shape) # 统一缩放图片,方便处理 width = 350 height = int(width * image_rgb.shape[0]/image_rgb.shape[1]) dim = (width, height) image_rgb = cv2.resize(image_rgb, dim, interpolation=cv2.INTER_AREA) image_gray = cv2.cvtColor(image_rgb, cv2.COLOR_BGR2GRAY) # 直方图均衡化增强对比度 equ = cv2.equalizeHist(image_gray) norm_image = cv2.normalize(equ, None, alpha=0, beta=1, norm_type=cv2.NORM_MINMAX) # 阈值处理得到二值图 ret, th = cv2.threshold(norm_image, 0.2, 1.0, cv2.THRESH_TOZERO_INV) th = img_as_ubyte(th) # 转换为8位格式,方便轮廓检测 # 寻找轮廓(只提取最外层轮廓) contours, hierarchy = cv2.findContours(th, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) # 筛选最大面积的轮廓 big_contour = None max_area = 0 for cnt in contours: area = cv2.contourArea(cnt) if area > max_area: max_area = area big_contour = cnt if big_contour is None: print(f"未找到有效轮廓: {filename}") return # ------------------- 核心处理部分 ------------------- # 方法1:轮廓近似(可选,用于过滤冗余点) epsilon = 0.005 * cv2.arcLength(big_contour, True) approx_contour = cv2.approxPolyDP(big_contour, epsilon, True) # 方法2:直接拟合椭圆(推荐) ellipse = cv2.fitEllipse(big_contour) # 提取椭圆参数:(中心(x,y), (长轴长度, 短轴长度), 旋转角度) ell_center, ell_axes, ell_angle = ellipse # 在图像上绘制结果 result = image_rgb.copy() # 绘制原始最大轮廓(细绿色线) cv2.drawContours(result, [big_contour], -1, (0, 255, 0), 1) # 绘制近似后的轮廓(细蓝色线,可选) cv2.drawContours(result, [approx_contour], -1, (255, 0, 0), 1) # 绘制拟合的椭圆(粗红色线) cv2.ellipse(result, ellipse, (0, 0, 255), 2) # 打印椭圆参数,用于位姿估计 print(f"\n图片 {filename} 的椭圆参数:") print(f"中心坐标: {round(ell_center[0],2)}, {round(ell_center[1],2)}") print(f"长轴/短轴: {round(ell_axes[0],2)}, {round(ell_axes[1],2)}") print(f"旋转角度: {round(ell_angle,2)}°") # 显示结果 fig2, (ax1, ax2, ax3) = plt.subplots(ncols=3, nrows=1, figsize=(12, 4), sharex=True, sharey=True) ax1.set_title('Original Image') ax1.imshow(cv2.cvtColor(image_rgb_orig, cv2.COLOR_BGR2RGB)) ax2.set_title('Thresholded Image') ax2.imshow(th, cmap='gray') ax3.set_title('Ellipse Fitting Result') ax3.imshow(cv2.cvtColor(result, cv2.COLOR_BGR2RGB)) plt.show() # 处理所有测试图片 for fname in filenames: getWheel0(fname)
关键代码解释
轮廓近似:
cv2.arcLength()计算轮廓的周长,epsilon是近似精度,值越小保留的细节越多,值越大简化程度越高。你可以根据实际图片调整0.005这个系数,找到最适合的简化效果。- 近似后的轮廓点数量大幅减少,轮胎花纹、边缘噪声带来的冗余点会被过滤掉。
椭圆拟合:
cv2.fitEllipse()直接接收原始轮廓点集,基于最小二乘法拟合出最优椭圆,返回的元组包含所有位姿相关参数:ell_center:椭圆中心坐标,对应车轮的中心位置ell_axes:长轴和短轴的长度,结合相机内参就能计算车轮的实际尺寸ell_angle:椭圆的旋转角度,对应车轮的姿态角
- 这个函数会自动忽略轮廓中的噪声点,拟合结果稳定可靠,完全满足位姿估计的需求。
阈值优化:
- 把原来的固定阈值改成了适配归一化图像的
0.2,1.0,避免因为不同图片亮度差异导致检测失败,鲁棒性更强。
- 把原来的固定阈值改成了适配归一化图像的
运行方式
保存修改后的代码为tire.py,然后在终端运行:
python tire.py
你会看到每张图片的原始图、阈值图和拟合结果图,同时控制台会输出每个车轮的椭圆参数,直接用于位姿估计即可。
内容的提问来源于stack exchange,提问作者user2996950
相关产品推荐
相关产品推荐

