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

OpenCV测量摄像头黑色物体距离出现RuntimeWarning错误如何解决

问题背景

开发目标为测量摄像头采集画面中黑色物体的距离,代码运行时出现计算警告,距离测量功能无法正常工作。

原始代码

import cv2
import numpy as np

def make_coordinates(image, line_parameters):
    slope, intercept = line_parameters
    y1 = image.shape[0]
    y2 = int(y1*(3/5))
    x1 = int((y1 - intercept)/slope)
    x2 = int((y2 - intercept)/slope)
    return np.array([x1, y1, x2, y2])
def average_slope_intercept(image, lines):
    left_fit = []
    right_fit = []
    if lines is not None:
        for line in lines:
            x1, y1, x2, y2 = line.reshape(4)
            parameters = np.polyfit((x1, x2), (y1, y2), 1)
            slope = parameters[0]
            intercept = parameters[1]
            if slope < 0:
                left_fit.append((slope, intercept))
            else:
                right_fit.append((slope, intercept))
        left_fit_average = np.average(left_fit, axis=0)
        #right_fit_average = np.average(right_fit, axis=0)
        print(left_fit_average, 'left')
        #print(right_fit_average, 'right')
        left_line = make_coordinates(image, left_fit_average)
        #right_line = make_coordinates(image, right_fit_average)
        return np.array([left_line])


def distance_to_camera(knownWidth, focalLength, perWidth):
    return (knownWidth * focalLength) / perWidth
# 计算图像中物体或标记到摄像头距离的第一步是校准并计算焦距,因此需要提前明确:
# 初始化已知物体到摄像头的距离
KNOWN_DISTANCE = 24.0
# 初始化已知物体的宽度
KNOWN_WIDTH = 11.0

def canny(img):
    hsv = cv2.cvtColor(img, cv2.COLOR_RBG2HSV)
    black_lower = np.array([0, 0, 0])
    black_upper = np.array([180, 255, 30])
    black_mask = cv2.inRange(hsv, black_lower, black_upper)
    kernel = 5
    blur = cv2.GaussianBlur(black_mask, (kernel, kernel),0)
    canny = cv2.Canny(blur, 50, 150)
    return canny

def display_lines(img, lines):
    line_image = np.zeros_like(img)
    if lines is not None:
        for line in lines:
            for x1, y1, x2, y2 in line:
                cv2.line(line_image, (x1, y1), (x2, y2), (255, 0, 0), 10)
    return line_image


def region_of_interest(canny):
    height = canny.shape[0]
    width = canny.shape[1]
    mask = np.zeros_like(canny)

    square = np.array([[(635,478),(0,478),(281,200)]
                       ])
    cv2.fillPoly(mask, square, 255)
    masked_image = cv2.bitwise_and(canny, mask)
    return masked_image

cap = cv2.VideoCapture(0)
_,c_image = cap.read()
marker = canny(c_image)
focalLength = (marker [1][0] * KNOWN_DISTANCE) / KNOWN_WIDTH
print('focalLength', focalLength)
while True:
    _, frame = cap.read()
    canny_image = canny(frame)
    cropped_canny = region_of_interest(canny_image)
    lines = cv2.HoughLinesP(cropped_canny, 2, np.pi / 180, 100, np.array([]), minLineLength=40, maxLineGap=5)
    averaged_lines = average_slope_intercept(frame, lines)
    line_image = display_lines(frame, averaged_lines)
    combo_image = cv2.addWeighted(frame, 0.8, line_image, 1, 1)
    CM = distance_to_camera(KNOWN_WIDTH, focalLength, marker[1][0])
    cv2.imshow("result", combo_image)
    cv2.putText(frame, "%.2fft" % CM,
                (frame.shape[1] - 200, frame.shape[0] - 20), cv2.FONT_HERSHEY_SIMPLEX,
                2.0, (0, 255, 0), 3)
    if cv2.waitKey(1) & 0xFF == ord('q'):
        break
cap.release()
cv2.destroyAllWindows()

错误日志

>>> %Run mesafe.py
focalLength 0.0
[-3.89346104e-01  4.41339935e+02] left
mesafe.py:18: RuntimeWarning: invalid value encountered in double_scalars
  return (knownWidth * focalLength) / perWidth
[-3.90163497e-01  4.41415626e+02] left
[-3.85150497e-01  4.40625233e+02] left
[-3.93702170e-01  4.43145302e+02] left
错误原因分析
  • 颜色空间转换参数错误:OpenCV默认读取图像的格式为BGR,代码中误写为cv2.COLOR_RBG2HSV,会导致黑色物体掩膜提取不准。
  • 焦距计算逻辑完全错误:canny()返回的是边缘二值图,像素值只有0(非边缘)和255(边缘)两种,代码直接取marker[1][0](第二行第一列的像素灰度值)计算焦距,从日志看该值为0,导致焦距计算结果为0。
  • 距离计算的输入参数错误:循环计算距离时,仍然使用校准阶段的固定marker[1][0]作为物体像素宽度,没有实时读取当前帧的物体尺寸,且该值为0时会触发除以0的运算警告,得到无效值。
  • 功能逻辑不匹配:现有代码核心是车道线检测逻辑,仅实现了边缘线条拟合,没有黑色物体的轮廓检测、尺寸计算逻辑,和距离测量的需求不匹配。
解决方法
  1. 修复颜色空间转换错误,将cv2.COLOR_RBG2HSV替换为cv2.COLOR_BGR2HSV。
  2. 新增黑色物体像素宽度计算逻辑,通过轮廓检测获取目标物体的外接矩形宽度,替代原有的随机像素值读取。
  3. 优化校准流程:校准阶段提示用户放入标定物体,成功检测到物体后再计算焦距,避免焦距为0的问题。
  4. 实时计算当前帧物体尺寸:每次循环都检测当前画面中黑色物体的宽度,作为距离计算的输入参数。
  5. 增加异常判断:未检测到物体、焦距为0时跳过距离计算,避免无效运算和警告。

核心修改代码示例

# 新增:获取黑色物体的像素宽度
def get_black_object_width(img):
    hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
    black_lower = np.array([0, 0, 0])
    black_upper = np.array([180, 255, 30])
    black_mask = cv2.inRange(hsv, black_lower, black_upper)
    # 形态学去噪
    kernel = np.ones((5,5), np.uint8)
    black_mask = cv2.morphologyEx(black_mask, cv2.MORPH_OPEN, kernel)
    contours, _ = cv2.findContours(black_mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
    if contours:
        # 取面积最大的轮廓作为目标物体
        max_contour = max(contours, key=cv2.contourArea)
        _, _, w, _ = cv2.boundingRect(max_contour)
        return w
    return 0

# 修改:校准焦距流程
cap = cv2.VideoCapture(0)
focalLength = 0
# 校准阶段
while True:
    _, c_image = cap.read()
    cali_width = get_black_object_width(c_image)
    if cali_width > 0:
        focalLength = (cali_width * KNOWN_DISTANCE) / KNOWN_WIDTH
        print('校准完成,焦距:', focalLength)
        break
    cv2.putText(c_image, "请将标定物体放入视野", (50,50), cv2.FONT_HERSHEY_SIMPLEX, 1, (0,0,255), 2)
    cv2.imshow("校准", c_image)
    if cv2.waitKey(1) & 0xFF == ord('q'):
        cap.release()
        cv2.destroyAllWindows()
        exit()
cv2.destroyWindow("校准")

# 修改:主循环逻辑
while True:
    _, frame = cap.read()
    # 原有车道线检测逻辑可根据需求保留或删除
    canny_image = canny(frame)
    cropped_canny = region_of_interest(canny_image)
    lines = cv2.HoughLinesP(cropped_canny, 2, np.pi / 180, 100, np.array([]), minLineLength=40, maxLineGap=5)
    averaged_lines = average_slope_intercept(frame, lines)
    line_image = display_lines(frame, averaged_lines)
    combo_image = cv2.addWeighted(frame, 0.8, line_image, 1, 1)
    
    # 新增距离计算逻辑
    current_width = get_black_object_width(frame)
    if current_width > 0 and focalLength > 0:
        CM = distance_to_camera(KNOWN_WIDTH, focalLength, current_width)
        cv2.putText(combo_image, f"{CM:.2f}in",
                    (frame.shape[1] - 200, frame.shape[0] - 20), cv2.FONT_HERSHEY_SIMPLEX,
                    1.0, (0, 255, 0), 3)
    else:
        cv2.putText(combo_image, "未检测到目标",
                    (frame.shape[1] - 200, frame.shape[0] - 20), cv2.FONT_HERSHEY_SIMPLEX,
                    1.0, (0, 0, 255), 3)
    
    cv2.imshow("result", combo_image)
    if cv2.waitKey(1) & 0xFF == ord('q'):
        break
cap.release()
cv2.destroyAllWindows()

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.23 17:45:02