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

如何在Python OpenCV中获取轮廓边界框的左上角坐标

解决机械臂坐标计算中纸张左上角坐标错误的问题

Hey there! Let's break down why your current top-left coordinate calculation is causing issues and fix it properly.

问题根源

你现在用中心x - 宽度/2,中心y - 高度/2的方式计算左上角,这个方法只适用于没有旋转的轴对齐矩形。但cv2.minAreaRect()返回的是一个旋转后的矩形,它的width和height是矩形自身的宽高,不一定对应图像坐标系的X/Y轴方向。直接这样计算自然会得到错误的坐标,甚至超出纸张范围。

正确解决方案

我们需要用cv2.boxPoints()把旋转矩形转换成四个角点的像素坐标,然后从这四个点里筛选出真正的左上角点(图像坐标系中,左上角是X最小且Y最小的点,因为图像Y轴向下)。

修改后的代码

下面是调整后的DefineBounds()方法,重点修改了左上角坐标的计算部分(记得先导入numpy:import numpy as np):

class Boundary(object):
    def __init__(self, image):
        self.frame = image
        self.DefineBounds()

    def DefineBounds(self):
        # 图像预处理:转灰度、模糊、边缘检测
        gray = cv2.cvtColor(self.frame, cv2.COLOR_BGR2GRAY)
        gray = cv2.GaussianBlur(gray, (5, 5), 0)
        edged = cv2.Canny(gray, 35, 125)

        # 寻找最大轮廓(假设是纸张)
        th, contours, hierarchy = cv2.findContours(edged.copy(), cv2.RETR_LIST, cv2.CHAIN_APPROX_NONE)
        c = max(contours, key=cv2.contourArea)

        # 绘制轮廓并显示
        cv2.drawContours(self.frame, c, -1, (0, 255, 0), 3)
        cv2.imshow("B and W", edged)
        cv2.imshow("capture", self.frame)
        cv2.waitKey(0)

        # 获取旋转矩形参数
        rect = cv2.minAreaRect(c)
        self.CenterBoundBox = rect[0]
        print("Center location of bounding box is {}".format(self.CenterBoundBox))
        
        # 获取旋转矩形的四个角点,转换为整数坐标
        box = cv2.boxPoints(rect)
        box = np.int0(box)
        
        # 筛选左上角点:X最小且Y最小的点(匹配图像坐标系)
        top_left = min(box, key=lambda p: (p[0], p[1]))
        self.TopLeftCoords = (top_left[0], top_left[1])
        x, y = self.TopLeftCoords
        print("X AND Y COORDINATES")
        print(x)
        print(y)

        # 绘制左上角标记与完整旋转矩形
        cv2.rectangle(self.frame, (x, y), (x+10, y+10), (0, 255, 0), 3)
        cv2.drawContours(self.frame, [box], 0, (255, 0, 0), 2)
        
        # 图像尺寸与像素转厘米计算
        self.OGImageHeight, self.OGImageWidth = self.frame.shape[:2]
        BboxWidth = rect[1][0]
        BboxHeight = rect[1][1]
        self.Px2CmWidth = BboxWidth / 21.5  # 对应纸张实际宽度21.5cm
        self.Px2CmHeight = BboxHeight / 18   # 对应纸张实际高度18cm
        print("Bbox dimensions {}  x  {}".format(BboxHeight, BboxWidth))
        print("Conversion values Px2Cm width {}, Px2Cm height {}".format(self.Px2CmWidth, self.Px2CmHeight))
        print("TopLeftCoords: {}".format(self.TopLeftCoords))

        cv2.imshow("BOX", self.frame)
        cv2.waitKey(0)

关键说明

  1. cv2.boxPoints()的作用:它会把minAreaRect返回的旋转矩形参数(中心、宽高、旋转角)转换成四个角点的像素坐标,这些坐标完全贴合图像坐标系,不会出现方向错位的问题。
  2. 筛选左上角点:通过min(box, key=lambda p: (p[0], p[1]))找到X最小、同时Y最小的点,这就是图像中纸张的真实左上角。
  3. 像素转厘米:你的转换逻辑是对的,只要确保21.5和18是纸张实际的宽高(厘米)即可。后续计算物体相对坐标时,用物体像素坐标减去左上角坐标,再除以转换系数就能得到厘米单位的坐标。

后续流程参考

得到正确的左上角坐标后,给机械臂传坐标的步骤就顺畅了:

  • 识别物体的像素坐标(比如中心或左上角)
  • 计算相对纸张的像素偏移:obj_rel_x = obj_x - self.TopLeftCoords[0],obj_rel_y = obj_y - self.TopLeftCoords[1]
  • 转换为厘米:obj_cm_x = obj_rel_x / self.Px2CmWidth,obj_cm_y = obj_rel_y / self.Px2CmHeight
  • 将厘米坐标传给机械臂即可

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.20 10:18:35