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

如何使用OpenCV计算盒子相对桌面中点的像素距离?

计算桌面与棕色盒子中点的像素距离

需求

编写OpenCV程序,计算桌面中点(红点)与棕色盒子中点(蓝点)之间的像素距离。最初计划通过cv2.findContours识别两者边界,获取中点后用dist.euclidean计算距离,但遇到干扰问题。

现有问题

当前代码会识别出电线、反光等无关轮廓,即使添加面积过滤条件也无法有效排除这些干扰,导致无法准确获取桌面和盒子的轮廓。

现有代码

初始轮廓检测代码

cv2.namedWindow("Object detector", cv2.WINDOW_NORMAL)    
image = cv2.imread(PATH_TO_IMAGE)

cv2.resizeWindow('Object detector', 800, 600)

im_bw = cv2.cvtColor(image, cv2.COLOR_RGB2GRAY)

kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (1,2))
morphology_img = cv2.morphologyEx(im_bw, cv2.MORPH_OPEN, kernel,iterations=1)

edged = cv2.Canny(morphology_img, 50, 100)
edged = cv2.dilate(edged, None, iterations=1)

cnts= cv2.findContours(edged.copy(),cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)
cnts = imutils.grab_contours(cnts)
(cnts, _) = contours.sort_contours(cnts)

cv2.drawContours(image, cnts, -1, (0,255,0), 3)

orig = image.copy()

cv2.imshow('Object detector', image)

cv2.waitKey(0)
cv2.destroyAllWindows()

轮廓过滤代码

for (i, c) in enumerate(cnts):
    # if the contour is not sufficiently large, ignore it
    if cv2.contourArea(c) < 50000:
        continue
    else:        
        box = cv2.minAreaRect(c)
        box = cv2.cv.BoxPoints(box) if imutils.is_cv2() else cv2.boxPoints(box)
        box = np.array(box, dtype="int")
        cv2.drawContours(image, [box.astype("int")], -1, (0, 255, 0), 1)
        (tl, tr, br, bl) = box
        (tltrX, tltrY) = midpoint(tl, tr)
        (blbrX, blbrY) = midpoint(bl, br)
        (tlblX, tlblY) = midpoint(tl, bl)
        (trbrX, trbrY) = midpoint(tr, br)        
        # compute the Euclidean distance between the midpoints
        dA = dist.euclidean((tltrX, tltrY), (blbrX, blbrY))
        dB = dist.euclidean((tlblX, tlblY), (trbrX, trbrY))
        cv2.putText(image, "{:.1f}".format(dA),
        (int(tltrX - 15), int(tltrY - 10)), cv2.FONT_HERSHEY_SIMPLEX,
        0.65, (255, 255, 255), 2)
        cv2.putText(image, "{:.1f}".format(dB),
        (int(trbrX + 10), int(trbrY)), cv2.FONT_HERSHEY_SIMPLEX,
        0.65, (255, 255, 255), 2)

解决方案

核心思路是用颜色分割替代灰度边缘检测,结合形状过滤精准提取目标轮廓,避免无关干扰:

关键步骤

  1. 颜色分割提取盒子:利用棕色在HSV空间的特征范围,生成掩码精准定位盒子区域,排除非棕色的干扰。
  2. 形态学去噪:通过闭运算填充盒子内部空洞,消除小噪声点。
  3. 形状过滤:除了面积,还通过矩形度(轮廓面积与最小外接矩形面积的比值)过滤非矩形的干扰轮廓(如电线、反光)。
  4. 桌面中点简化计算:若桌面占满图像,直接取图像中心;若桌面未完全占屏,可通过浅色区域提取最大轮廓计算中心。

完整代码示例

import cv2
import numpy as np
from scipy.spatial import distance as dist

def midpoint(ptA, ptB):
    return ((ptA[0] + ptB[0]) * 0.5, (ptA[1] + ptB[1]) * 0.5)

# 替换为你的图像路径
PATH_TO_IMAGE = "your_image_path.jpg"
image = cv2.imread(PATH_TO_IMAGE)
cv2.namedWindow("Result", cv2.WINDOW_NORMAL)
cv2.resizeWindow("Result", 800, 600)
orig = image.copy()

# 1. 提取棕色盒子区域
hsv = cv2.cvtColor(image, cv2.COLOR_BGR2HSV)
# 棕色的HSV范围(可根据实际图像微调)
lower_brown = np.array([10, 100, 20])
upper_brown = np.array([20, 255, 200])
brown_mask = cv2.inRange(hsv, lower_brown, upper_brown)

# 形态学闭运算,填充盒子内部空洞,去除小噪声
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (5, 5))
brown_mask = cv2.morphologyEx(brown_mask, cv2.MORPH_CLOSE, kernel, iterations=2)

# 查找盒子轮廓并过滤
box_cnts = cv2.findContours(brown_mask.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)[0]
box_center = None
for c in box_cnts:
    area = cv2.contourArea(c)
    # 过滤小轮廓,同时检查矩形度
    if area > 1000:
        rect = cv2.minAreaRect(c)
        box = cv2.boxPoints(rect)
        box = np.int0(box)
        # 计算矩形度:轮廓面积 / 最小外接矩形面积,接近1说明是规整矩形
        rect_area = rect[1][0] * rect[1][1]
        solidity = area / rect_area
        if solidity > 0.8:
            # 获取盒子中点
            box_center = (int(rect[0][0]), int(rect[0][1]))
            cv2.drawContours(orig, [box], 0, (255, 0, 0), 2)
            cv2.circle(orig, box_center, 5, (255, 0, 0), -1)
            break

# 2. 获取桌面中点
# 方法1:若桌面占满图像,直接取图像中心
desktop_center = (image.shape[1] // 2, image.shape[0] // 2)
# 方法2:若桌面未完全占屏,提取浅色区域的最大轮廓计算中心
# hsv_lower = np.array([0, 0, 200])
# hsv_upper = np.array([180, 50, 255])
# desktop_mask = cv2.inRange(hsv, hsv_lower, hsv_upper)
# desktop_cnts = cv2.findContours(desktop_mask.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)[0]
# desktop_cnt = max(desktop_cnts, key=cv2.contourArea)
# desktop_moments = cv2.moments(desktop_cnt)
# desktop_center = (int(desktop_moments["m10"] / desktop_moments["m00"]), int(desktop_moments["m01"] / desktop_moments["m00"]))

cv2.circle(orig, desktop_center, 5, (0, 0, 255), -1)

# 3. 计算并显示距离
if box_center is not None:
    pixel_distance = dist.euclidean(desktop_center, box_center)
    cv2.line(orig, desktop_center, box_center, (255, 0, 255), 2)
    cv2.putText(orig, f"像素距离: {pixel_distance:.1f} px", (50, 50), 
                cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2)

cv2.imshow("Result", orig)
cv2.waitKey(0)
cv2.destroyAllWindows()

注意事项

  • 若棕色盒子的颜色与示例不同,需调整lower_brown和upper_brown的HSV数值(可通过OpenCV的颜色拾取工具获取)。
  • 矩形度阈值0.8可根据实际情况微调,确保只保留盒子轮廓。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.24 21:15:33