1、常见的OpenCV的读图问题:

1.1、读取图片的方法:

注意:opencv c++是支持中文的,python不支持中文。
img = cv2.imdecode(np.fromfile(img_path, dtype=np.uint8), 1)
img = cv2.imdecode(np.fromfile(img_path, dtype=np.uint8), -1) # 读入完整图片,见下面解释
img = cv2.imdecode(np.fromfile(img_path, dtype=np.uint8), 0) # 读成灰度
img = cv2.imdecode(np.fromfile(img_path, dtype=np.uint8), 1) # 读成彩图
其中:img_path为读取图片路径及图片名,可以包含中文

1.2、保存图片的方法:

cv2.imencode(‘.jpg’, src)[1].tofile(save_path)

2、目标检测的 bounding box 的表示方法:

2.1、边框种类:

  • bounding box的表示方法有很多种类,常见的表示的方法如:1)Pascal Voc;2)COCO;3)YOLO;
  • 如图所示的bounding box的可视化image.png

图-1,bounding box的示意图

2.2、Pascal Voc 表示方法:

  • bounding box涉及的信息,(x_min, y_min, x_max, y_max), 其中x_min和y_min表示左上角的坐标,其中x_max和 y_max表示右下角的坐标。如图-1所示【98,345,420,462】

    2.3、COCO 表示方法:

  • bounding box涉及的信息,(x_min, y_min, w, h), 其中x_min和y_min表示左上角的坐标,其中w和h表示宽度和高度。如图-1所示【98,345,322,117】

    2.4、yolo 表示方法:

  • bounding box涉及的信息,(x_center, y_center, w, h), 这4个值是经过数据规范化(normalized )的。其中x_center, y_center表示边框的中心位置, 其中w, h分别表示边框的宽度和高度,

  • 示例:边框的宽度是322,高度是117

    • 不规范化是[(98 + (322 / 2)), (345 + (117 / 2)), 322, 117]=[259, 403.5, 322, 117]
    • 规范化方法是[259 / 640, 403.5 / 480, 322 / 640, 117 / 480]
    • 最终结果是[0.4046875, 0.840625, 0.503125, 0.24375]

      3、yolo系列的数据处理问题:

      3.1、开源数据处理代码:

      已开源 yolov5-tools 工具源码链接

      3.2、开源数据widerface边框存储格式:

  • widerface 的 bounding box 的涉及的信息,(x,y,w,h),其中x和y是用来表示边框的左上角的坐标,w和h为表示边框的宽度和高度;

  • 关于 widerface 标注文件的读取,可以参考开源代码,注意代码不需要做任何的修改。具体的源码链接:widerface 的数据集的处理方案

    3.3、yolov5的边框存储格式:

  • bounding box的涉及的信息,(x_center, y_center, w, h) ,注意这四个值是经过数据的规范化的即为normalize。其中x_center, y_center表示bounding box的中心位置,w和h表示边框的宽度和高度

  • 如示例说明:
    • 边框的宽度为:322;高度为:117;整张图片的宽度为:640;高度为:480;
    • 未经过规范化:【259,403.5,322,117】
    • 经过规范化:【259/640,403.5/480,322/640,117/480】
    • 最终的结果为:【0.4046875,0.840625,0.503125,0.24375】
  • yolov5 的 bounding box 的详述表示方法,详细的工具代码见链接:已开源 yolov5-tools 工具源码链接

    4、数据转换后的错误的检查:

    4.1、可视化的形式展示标注的结果,单张图片的可视化代码所示:

    ```python import numpy as np import cv2 import torch

label_path = ‘./coco128/labels/train2017/000000000094.txt’ image_path = ‘./coco128/images/train2017/000000000094.jpg’

坐标转换,原始存储的是YOLOv5格式

Convert nx4 boxes from [x, y, w, h] normalized to [x1, y1, x2, y2] where xy1=top-left, xy2=bottom-right

def xywhn2xyxy(x, w=640, h=640, padw=0, padh=0):

  1. y = x.clone() if isinstance(x, torch.Tensor) else np.copy(x)
  2. y[:, 0] = w * (x[:, 0] - x[:, 2] / 2) + padw # top left x
  3. y[:, 1] = h * (x[:, 1] - x[:, 3] / 2) + padh # top left y
  4. y[:, 2] = w * (x[:, 0] + x[:, 2] / 2) + padw # bottom right x
  5. y[:, 3] = h * (x[:, 1] + x[:, 3] / 2) + padh # bottom right y
  6. return y

读取labels

with open(label_path, ‘r’) as f: lb = np.array([x.split() for x in f.read().strip().splitlines()], dtype=np.float32) # labels print(lb)

读取图像文件

img = cv2.imread(str(image_path)) h, w = img.shape[:2] lb[:, 1:] = xywhn2xyxy(lb[:, 1:], w, h, 0, 0)#反归一化 print(lb)

绘图

for _, x in enumerate(lb): class_label = int(x[0]) # class

  1. cv2.rectangle(img,(x[1],x[2]),(x[3],x[4]),(0, 255, 0) )
  2. cv2.putText(img,str(class_label), (int(x[1]), int(x[2] - 2)),fontFace = cv2.FONT_HERSHEY_SIMPLEX,fontScale=1,color=(0, 0, 255),thickness=2)

cv2.imshow(‘show’, img) cv2.waitKey(0)#按键结束 cv2.destroyAllWindows()

  1. <a name="Lccdb"></a>
  2. ## 4.2、文件夹式全图片的可视化代码所示:
  3. ```python
  4. import numpy as np
  5. import cv2
  6. import torch
  7. source_directory_img_path="../images/train"
  8. source_directory_label_path="../labels/train"
  9. target_directory_path= "../check"
  10. #坐标转换,原始存储的是YOLOv5格式
  11. # Convert nx4 boxes from [x, y, w, h] normalized to [x1, y1, x2, y2] where xy1=top-left, xy2=bottom-right
  12. def xywhn2xyxy(x, w=640, h=640, padw=0, padh=0):
  13. y = x.clone() if isinstance(x, torch.Tensor) else np.copy(x)
  14. y[:, 0] = w * (x[:, 0] - x[:, 2] / 2) + padw # top left x
  15. y[:, 1] = h * (x[:, 1] - x[:, 3] / 2) + padh # top left y
  16. y[:, 2] = w * (x[:, 0] + x[:, 2] / 2) + padw # bottom right x
  17. y[:, 3] = h * (x[:, 1] + x[:, 3] / 2) + padh # bottom right y
  18. return y
  19. import os
  20. def draw_label(image_path,label_path):
  21. with open(label_path, 'r') as f:
  22. lb = np.array([x.split() for x in f.read().strip().splitlines()], dtype=np.float32) # labels
  23. #print(lb)
  24. # 读取图像文件
  25. img = cv2.imread(str(image_path))
  26. h, w = img.shape[:2]
  27. lb[:, 1:] = xywhn2xyxy(lb[:, 1:], w, h, 0, 0) # 反归一化
  28. #print(lb)
  29. # 绘图
  30. for _, x in enumerate(lb):
  31. class_label = int(x[0]) # class
  32. cv2.rectangle(img, (x[1], x[2]), (x[3], x[4]), (0, 255, 0))
  33. cv2.putText(img, str(class_label), (int(x[1]), int(x[2] - 2)), fontFace=cv2.FONT_HERSHEY_SIMPLEX, fontScale=1,
  34. color=(0, 0, 255), thickness=2)
  35. return img
  36. if __name__ == '__main__':
  37. for root, dirs, files in os.walk(source_directory_img_path):
  38. for f in files:
  39. file_name = f.split('.')[0]+".txt"
  40. image_path = os.path.join(source_directory_img_path, f)
  41. label_path =os.path.join(source_directory_label_path, file_name)
  42. target =os.path.join(target_directory_path, f)
  43. img= draw_label(image_path, label_path)
  44. print(target)
  45. cv2.imwrite(target, img);

5、yolov5-tools的工具的使用方法:

示例:coco2yolo

1)打开general_json2yolo.py

  1. if __name__ == '__main__':
  2. source = 'coco'
  3. if source == 'coco':
  4. convert_coco_json('../../Downloads/coco/annotations/')
  5. 改成自己的COCO文件所在目录

2)执行 python general_json2yolo.py

  1. 生成结果如下:
  2. ├── new_dir
  3. │ ├── images
  4. │ └── labels
  5. │ └── train2017
  6. labels中的train2017存储是标注文本,例如000000000009.txt

3)可以把COCO的训练图像文件放到

  1. ├── new_dir
  2. ├── images
  3. │ └── train2017
  4. 注意:此处与coco128的目录结构一模一样