You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用OpenCV与NumPy poly1d测量物体尺寸的曲线拟合异常问题

电线杆高度测量多项式拟合异常问题

问题背景

我想用NumPy生成拟合曲线,通过图像中标尺的已知点预测未知点的高度测量值。此前用其他图像测试时,Excel的多项式拟合完全正常,工作中同类软件也能正常使用,但更换新的校准图像后,测量结果偏差极大——尝试测量18'11"(最低导线)的高度时,输出数值瞬间变成数万。

已知条件

  • 电线杆前的标尺刻度(从下到上):
    • 3'6" → 42英寸
    • 6'6" → 78英寸
    • 9'8" → 116英寸
    • 13' → 156英寸
  • 图像已通过OpenCV的undistort完成相机畸变校正

现有代码

核心拟合逻辑代码

dist = self.firstClick - y
self.yData.append(dist)

if len(self.yData) > 4:
    print(self.poly(dist))

if len(self.yData) == 4:
    array = np.array(self.xData)
    array = np.expand_dims(array, axis=0)
    
    print(self.xData)
    print(self.yData)
    
    array = np.append(array, [self.yData], axis=0)
    print(array)
    x = array[:,0]
    y = array[:,1]
    
    self.poly = np.poly1d(np.polyfit(x, y, 2))
    poly1d = np.poly1d(self.poly)
    xp = np.linspace(-2, 20, 1)
    _ = plt.plot(x, y, '.', xp, self.poly(xp), '-', xp, self.poly(xp), '--')
    plt.ylim(0,200)
    plt.show()

图像显示与缩放代码

self.img = cv2.imread(imagePath, cv2.IMREAD_ANYCOLOR)
self.scale_percent = 30

self.width = int(self.img.shape[1] * self.scale_percent/100)
self.height = int(self.img.shape[0] * self.scale_percent/100)

dsize = (self.width, self.height)

self.output = cv2.resize(self.img, dsize)

img = self.output

cv2.imshow('image', img)

cv2.setMouseCallback('image', self.click_event)

cv2.waitKey()

数值校准代码

if self.firstClick == 0:
    self.firstClick = y
    cv2.putText(self.output, "Pole Base", (x, y), font, 1, (255, 255, 0), 2)
    cv2.imshow('image', self.output)
    
elif self.firstClick != 0 and self.secondClick == 0:
    self.secondClick = y
    print("The difference in first and second clicks is", self.firstClick - self.secondClick)
    first = self.firstClick - self.secondClick
    inch = first/42
    foot = inch*12
    self.foot = foot
    print("One foot is currently: ", foot)
    self.firstLine = 3.5*12
    self.secondLine = 6.5*12
    self.thirdLine = 9.67*12
    self.fourthLine = 13*12

    self.xData = np.array([self.firstLine, self.secondLine, self.thirdLine, self.fourthLine])
    self.yData.append(self.firstLine)

    print(self.firstLine)
    print(self.secondLine)
    print(self.thirdLine)
    print(self.fourthLine)

问题根源分析

  1. 数据对应关系完全错误:拟合时x = array[:,0]和y = array[:,1]取的是xData的前两个元素,完全没有用到yData的像素距离值,相当于用错误的数据集做拟合。
  2. 拟合因果颠倒:需要用像素距离预测实际高度,但现有代码用实际高度作为x,像素距离作为y拟合,预测时输入像素距离会导致数值爆炸。
  3. yData初始化错误:校准代码中把实际高度值self.firstLine加入yData,但后续yData应该存储像素距离,导致数据类型混合,拟合基础错误。
  4. 绘图参数无效:xp = np.linspace(-2, 20, 1)只生成1个点,无法验证拟合曲线是否合理。

修正方案

1. 修正yData初始化

在校准代码中删除self.yData.append(self.firstLine),改为在点击标尺的四个刻度点时,依次将对应的像素距离(dist = self.firstClick - y)加入yData。

2. 修正核心拟合逻辑

dist = self.firstClick - y
self.yData.append(dist)

# 收集完4个标尺点后执行拟合
if len(self.yData) == 4:
    print("实际高度(英寸):", self.xData)
    print("像素距离:", self.yData)
    
    # 用像素距离预测实际高度,x为像素距离,y为实际高度
    self.poly = np.poly1d(np.polyfit(self.yData, self.xData, 2))
    
    # 生成合理的绘图区间,覆盖已知点及可能的未知点范围
    xp = np.linspace(0, max(self.yData)*1.5, 100)
    plt.plot(self.yData, self.xData, '.', xp, self.poly(xp), '-')
    plt.xlabel("像素距离")
    plt.ylabel("实际高度(英寸)")
    plt.ylim(0, 250) # 覆盖18'11"=227英寸的测量需求
    plt.show()

# 预测未知点高度
if len(self.yData) > 4:
    predicted_inch = self.poly(dist)
    predicted_foot = predicted_inch / 12
    print(f"预测高度: {predicted_foot:.2f} 英尺 ({predicted_inch:.2f} 英寸)")

3. 额外注意事项

  • 确保点击标尺四个刻度点时,yData中存储的是每个刻度到电线杆底部的像素距离,xData对应每个刻度的实际高度(42、78、116、156英寸)。
  • 若二次多项式拟合仍有偏差,可以尝试一次多项式(线性拟合),因为图像经过畸变校正后,高度与像素距离大概率呈线性关系。

内容的提问来源于stack exchange,提问作者ABloode

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.18 05:35:23