写在前面:最近在做yolov5封装成一个接口,然后将数据提供给前端展示。在展示的时候一张照片里可能有多个相同的标签,这样数据就不好进行匹配,所以针对这个问题,下面将会详细描述。
目录
一、问题详情
检测图片如下,前端需要:检测图片+额外数据
如果是下图,那么生成的数据为:{'image1':['person':0.59,'person':0.88,'tie':0.66,'tie':029]}
如果你对返回的数据进行修改:{'image1':['person-01':0.59,'person-02':0.88,'tie-01':0.66,'tie-02':029]},那么这样和图片就不对应了!!!
二、解决办法
图片输出效果如下,给前端返回数据结果为,这样就一一对应了:
{'image1':['person-01':0.59,'person-02':0.88,'tie-01':0.66,'tie-02':029]}
我的解决思路请看第三部分,如果还想进行更多的图片操作,我感觉这篇博客可以为你打开思路:
三、解决过程
可以为每一个特定的标签添加一个计数器,并在每次遇到该标签时,都更新这个计数器。修改代码的地点在delect.py中的if save_img or save_crop or view_img:部分。
label_counter
是一个defaultdict
,当我们尝试访问一个不存在的键时,它会返回0,并创建一个新的键。因此,label_counter[label_name] += 1
会将对应标签的计数器加一,即使这是第一次遇到这个标签。
然后,我们用f'{label_name}-{label_counter[label_name]:02d}'
生成了标签和编号。:02d
表示我们想要一个至少两位数的整数,如果数字不足两位,则用0填充。所以1
会变成01
,2
会变成02
,依此类推。
# 增加对应的计数器
label_counter[label_name] += 1
label = None if hide_labels else (f'{label_name}-{label_counter[label_name]:02d}' if hide_conf else f'{label_name}-{label_counter[label_name]:02d} {conf:.2f}')
这样就可以是不是对计数的原理有所了解了,接下来就是改变图片上的label,这里使用opencv。
x1, y1, x2, y2 = map(int, xyxy) # 转换为整数类型
cv2.putText(im0s, label, (x1, y1 - 5), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 255, 255), 2)
使用cv2.putText()
在图片上绘制文本。它的参数是:图片,文本,文本的左下角的位置,字体,字体的大小,颜色,线条的宽度。
注意:xyxy
是一个包含了矩形框的四个坐标的列表,[x1, y1, x2, y2]
。你可能需要根据你的具体情况来决定标签的位置。在这个示例中,默认标签放在矩形框的左上角。
还有就是,需要对xyxy进行类型转换,在OpenCV中,图像的坐标是以整数表示的,但是xyxy
中的坐标可能是浮点数,因此需要将它们转换为整数。要不然你可能会遇到这个问题:
Traceback (most recent call last):
File "D:\python\item\bird_identification\birds_app\demo.py", line 35, in <module>
print(f"测试输出:{detector.detect()}")
File "D:\python\item\bird_identification\birds_app\yolov5_master\detect.py", line 280, in detect
run(self.weights, self.source, self.data, self.imgsz, self.conf_thres,
File "C:\Users\liuyu\AppData\Roaming\Python\Python39\site-packages\torch\utils\_contextlib.py", line 115, in decorate_context
return func(*args, **kwargs)
File "D:\python\item\bird_identification\birds_app\yolov5_master\detect.py", line 150, in run
cv2.putText(im0s, label, (xyxy[0], xyxy[1] - 5), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 255, 255), 2)
cv2.error: OpenCV(4.5.5) :-1: error: (-5:Bad argument) in function 'putText'
> Overload resolution failed:
> - Can't parse 'org'. Sequence item with index 0 has a wrong type
> - Can't parse 'org'. Sequence item with index 0 has a wrong type
完整代码如下
#导包
from collections import defaultdict
#定义一个收集的集合
detected_objects = {}
@smart_inference_mode()
def run(
weights=ROOT / 'yolov5s.pt', # model path or triton URL
source=ROOT / 'data/images', # file/dir/URL/glob/screen/0(webcam)
data=ROOT / 'data/coco128.yaml', # dataset.yaml path
imgsz=(640, 640), # inference size (height, width)
#省略源代码。。。。。
detected_objects[path] = []
label_counter = defaultdict(int)
# Write results
for *xyxy, conf, cls in reversed(det):
if save_txt: # Write to file
xywh = (xyxy2xywh(torch.tensor(xyxy).view(1, 4)) / gn).view(-1).tolist() # normalized xywh
line = (cls, *xywh, conf) if save_conf else (cls, *xywh) # label format
with open(f'{txt_path}.txt', 'a') as f:
f.write(('%g ' * len(line)).rstrip() % line + '\n')
if save_img or save_crop or view_img: # Add bbox to image
c = int(cls) # integer class
# label = None if hide_labels else (names[c] if hide_conf else f'{names[c]} {conf:.2f}')
label_name = names[c]
# 增加对应的计数器
label_counter[label_name] += 1
label = None if hide_labels else (
f'{label_name}-{label_counter[label_name]:02d}' if hide_conf else f'{label_name}-{label_counter[label_name]:02d} {conf:.2f}')
# 在图片上绘制标签和编号
x1, y1, x2, y2 = map(int, xyxy)
cv2.putText(im0s, label, (x1, y1 - 5), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 255, 255), 2)
annotator.box_label(xyxy, label, color=colors(c, True))
detected_objects[path].append(label)
if save_crop:
save_one_box(xyxy, imc, file=save_dir / 'crops' / names[c] / f'{p.stem}.jpg', BGR=True)
# 省略源代码。。。
项目内代码展示:
PS:我用的是yolov5-6版本的!本文主要介绍的是标签编号,至于封装部署有空再慢慢更新吧!打工人没啥更新的动力了,要是更了,你可以看看我的yolo专栏。哈哈,在此记录一下心得!