这两天在看YOLOv1的代码,看到这边博客给了代码
传送门:动手学习深度学习pytorch版——从零开始实现YOLOv1
其中有个地方需要用到cv2.rectangle()函数来给图像进行框选
这个函数中的pt1和pt2参数指的就是要框选的图像的左上角点和右下角点,这大家也都知道了
但是当时只有中心宽高(xywh)格式的坐标数据,所以我们需要把它转换成xyxy格式(左上角点和右下角点)的坐标数据
代码先前已经做的工作是,遍历了图片,获取它的xml数据,从而获得的宽高、xyxy格式的变量,然后再通过convert()函数对数据进行归一化
def convert(size, bbox):
"""
将bbox的左上角点、右下角点坐标的格式,转换为bbox中心点 + bbox的w,h的格式,并进行归一化
size: [weight, height]
bbox: [Xmin, Ymin, Xmax, Ymax]
即:xyxy(左上右下) ——> xywh(中心宽高)
xyxy(左上右下):左上角的xy坐标和右下角的xy坐标
xywh(中心宽高):边界框中心点的xy坐标和图片的宽度和高度
"""
dw = 1. / size[0]
dh = 1. / size[1]
x = (bbox[0] + bbox[2]) / 2.0
y = (bbox[1] + bbox[3]) / 2.0
w = bbox[2] - bbox[0]
h = bbox[3] - bbox[1]
x = x * dw
y = y * dh
w = w * dw
h = h * dh
return (x, y, w, h)
但是后来我只想检验一张图片,所以再根据路径读取xml数据有点麻烦,代码中有两行关于pt1和pt2的计算公式,是怎么来的呢,下面我笨拙地推导一下(目前还没理解到其他好理解的方式能直接写出这个公式,因为我是直接推导了一遍,才看明白这个公式是啥意思)
show_labels_img("2011_000002")
def show_labels_img(imgname):
"""imgname是输入图像的名称,无下标"""
img = cv2.imread(STATIC_DATASET_PATH + "/JPEGImages/" + imgname + ".jpg") # 用于读取图片文件
h, w = img.shape[:2]
# label = []
'''
1) ./是当前目录
2) ../是父级目录
3) /是根目录
'''
with open(STATIC_DATASET_PATH + "/labels/" + imgname + ".txt", "r") as labels:
for label in labels:
label = label.split(" ")
# label: [类、x、y、w、h(中心宽高)]
label = [float(x.strip()) for x in label]
# 根据convert()推导pt1和pt2的公式
pt1 = (int(label[1] * w - label[3] * w / 2), int(label[2] * h - label[4] * h / 2)) # 矩形的左上角
print(pt1)
pt2 = (int(label[1] * w + label[3] * w / 2), int(label[2] * h + label[4] * h / 2)) # 矩形的右下角
print(pt2)
# 图像、文字内容、坐标、字体样式、字体大小、颜色、粗细
cv2.putText(img, GL_CLASSES[int(label[0])], pt1, cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 0, 255))
'''
pt1: x1, y1(矩形的左上角)
pt2: x2, y2(矩形的右下角)
color:B G R
'''
cv2.rectangle(img, pt1, pt2, (0, 0, 255), 2)
cv2.imshow("img", img)
cv2.waitKey(0) # 持续显示图片直到有按键被按下,用鼠标选中图片显示窗口,按下键盘任意键即可关闭该窗口()必须要有这一行,否则无法显示图片
推导过程如下: