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的运算警告,得到无效值。 - 功能逻辑不匹配:现有代码核心是车道线检测逻辑,仅实现了边缘线条拟合,没有黑色物体的轮廓检测、尺寸计算逻辑,和距离测量的需求不匹配。
解决方法
- 修复颜色空间转换错误,将
cv2.COLOR_RBG2HSV替换为cv2.COLOR_BGR2HSV。 - 新增黑色物体像素宽度计算逻辑,通过轮廓检测获取目标物体的外接矩形宽度,替代原有的随机像素值读取。
- 优化校准流程:校准阶段提示用户放入标定物体,成功检测到物体后再计算焦距,避免焦距为0的问题。
- 实时计算当前帧物体尺寸:每次循环都检测当前画面中黑色物体的宽度,作为距离计算的输入参数。
- 增加异常判断:未检测到物体、焦距为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
相关产品推荐
相关产品推荐

