最近读了一些代码,不同的开源框架采用画图方式不一样,就学习了一下。
目标检测普遍的正矩形(hbb)其实就是四边形的一个特例,以下的代码都是以绘制四边形的检测结果为例。
opencv
def draw_box_cv(img, boxes, labels, scores):
img = img + np.array([103.939, 116.779, 123.68])
boxes = boxes.astype(np.int64)
labels = labels.astype(np.int32)
img = np.array(img, np.float32)
img = np.array(img*255/np.max(img), np.uint8)
num_of_object = 0
for i, box in enumerate(boxes):
x_c, y_c, w, h, theta = box[0], box[1], box[2], box[3], box[4]
label = labels[i]
if label != 0:
num_of_object += 1
color = (np.random.randint(255), np.random.randint(255), np.random.randint(255))
rect = ((x_c, y_c), (w, h), theta)
#根据四边形的中心x_c, y_c,w,h以及偏移角度theta,恢复出四个点点的坐标
rect = cv2.boxPoints(rect)
rect = np.int0(rect) #转为int
cv2.drawContours(img, [rect], -1, color, 3) #在图中根据rect绘制
category = LABEl_NAME_MAP[label] #类别
if scores is not None:
cv2.rectangle(img,
pt1=(x_c, y_c),
pt2=(x_c + 120, y_c + 15),
color=color,
thickness=-1)
cv2.putText(img,
text=category+": "+str(scores[i]),
org=(x_c, y_c+10),
fontFace=1,
fontScale=1,
thickness=2,
color=(color[1], color[2], color[0]))
else:
cv2.rectangle(img,
pt1=(x_c, y_c),
pt2=(x_c + 40, y_c + 15),
color=color,
thickness=-1)
cv2.putText(img,
text=category,
org=(x_c, y_c + 10),
fontFace=1,
fontScale=1,
thickness=2,
color=(color[1], color[2], color[0]))
cv2.putText(img,
text=str(num_of_object),
org=((img.shape[1]) // 2, (img.shape[0]) // 2),
fontFace=3,
fontScale=1,
color=(255, 0, 0))
return img
cv2实际上用起来是最方便的了,但是唯一的缺点就是我要写检测结果的标注text的时候,不能写中文,如果写出来的画都变成问号了。因此就尝试了用PIL
PIL
def draw_box_cv(img, imgname, boxes, labels, scores):
img = img + np.array([103.939, 116.779, 123.68])
boxes = boxes.astype(np.int64)
labels = labels.astype(np.int32)
img = np.array(img, np.float32)
img = np.array(img*255/np.max(img), np.uint8)
num_of_object = 0
img_PIL = Image.fromarray(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))#由于读取图片用到的函数是cv2,所以读入的图片是BGR的格式,因此要转变成RGB
draw = ImageDraw.Draw(img_PIL) #创建pil的画笔
font = ImageFont.truetype("/usr/share/fonts/truetype/sim/simhei.ttf", 20) # 参数1:字体文件路径,参数2:字体大小
for i, box in enumerate(boxes):
x_c, y_c, w, h, theta = box[0], box[1], box[2], box[3], box[4]
label = labels[i]
if label != 0:
num_of_object += 1
color = (np.random.randint(255), np.random.randint(255), np.random.randint(255))
rect = ((x_c, y_c), (w, h), theta)
rect = cv2.boxPoints(rect)
rect = np.int0(rect)
draw.polygon([(rect[0,0],rect[0,1]),#制检测的方框
(rect[1,0],rect[1,1]),
(rect[2,0],rect[2,1]),
(rect[3,0],rect[3,1])], outline=color)
category = LABEl_NAME_MAP[label] #类别
if scores is not None:
outlines = '{:s} {:.3f}'.format(category, scores[i])
outlines = outlines.decode('utf-8') #一定要有这句话!
draw.text((x_c, y_c+10), outlines ,color=(color[1], color[2], color[0]),font = font)
else:
outlines = category.decode('utf-8') #一定要有这句话!
draw.text((x_c, y_c+10), outlines,color=(color[1], color[2], color[0]),font = font)
ext = os.path.splitext(imgname)[-1]
img_name = os.path.splitext(imgname)[0]
outname = img_name + '_fpn' + ext
img_PIL.save(cfgs.INFERENCE_SAVE_PATH + '/'+ outname)
PIL的优点就是可以写中文的标注了,但是缺点就是画四边形的时候不能改变线宽,以至于画出来非常细,很影响观看。(如果是要绘制矩形的检测结果,是可以改变线宽的)
matplotlib
def draw_box_cv(img, imgname, gt, savepath, boxes, labels, scores):
img = img + np.array([103.939, 116.779, 123.68])
boxes = boxes.astype(np.int64)
labels = labels.astype(np.int32)
img = np.array(img, np.float32)
img = np.array(img*255/np.max(img), np.uint8)
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)#由于读取图片用到的函数是cv2,所以读入的图片是BGR的格式,因此要转变成RGB
num_of_object = 0
dpi=100 #一般300dpi就比较清晰了
fig = plt.figure(frameon=False)
fig.set_size_inches(img.shape[1]/dpi, img.shape[0]/dpi)
ax = plt.Axes(fig, [0., 0., 1., 1.])
ax.axis('off')
fig.add_axes(ax)
ax.imshow(img)
for i, box in enumerate(boxes):
x_c, y_c, w, h, theta = box[0], box[1], box[2], box[3], box[4]
label = labels[i]
if label != 0:
num_of_object += 1
color = (rand(), rand(), rand())
rect = ((x_c, y_c), (w, h), theta)
rect = cv2.boxPoints(rect) #根据上面的((x_c, y_c), (w, h), theta)变换成四个点的坐标
rect = np.int0(rect)
rect = mpathes.Polygon(rect,fill=False,
edgecolor=color, linewidth=2.0) #画多边行,不填充,线的宽度为2.5
ax.add_patch(rect)
category = LABEl_NAME_MAP[label]
if scores is not None:
ax.text(x_c, y_c+10,
'{:s} {:.3f}'.format(category, scores[i]),
bbox=dict(facecolor='blue', alpha=0.3),#在写标注的位置会绘制一个据带填充的矩形框,其透明度为alpha
fontsize=14, color='red')
else:
ax.text(x_c, y_c+10,
'{:s}'.format(category),
bbox=dict(facecolor='blue', alpha=0.3),
fontsize=14, color='red')
ext = os.path.splitext(imgname)[-1]
img_name = os.path.splitext(imgname)[0]
if gt == True:
outname = img_name + '_gt' + ext
else:
outname = img_name + '_fpn' + ext
fig.savefig(savepath + '/'+ outname)
plt.close('all')
matplotlib的优点就是可以写中文的标注,但是需要配置一下:windows及ubuntu下解决matplotlib显示中文文本为方框的问题
缺点就是保存的图片可能会有白色的边框