如何在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)
关键说明
cv2.boxPoints()的作用:它会把minAreaRect返回的旋转矩形参数(中心、宽高、旋转角)转换成四个角点的像素坐标,这些坐标完全贴合图像坐标系,不会出现方向错位的问题。- 筛选左上角点:通过
min(box, key=lambda p: (p[0], p[1]))找到X最小、同时Y最小的点,这就是图像中纸张的真实左上角。 - 像素转厘米:你的转换逻辑是对的,只要确保
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
相关产品推荐
相关产品推荐

