项目开发时发现部分代码可能需要重复调用。这部分代码可以写到同一个utils文件中,减低其他代码的冗余性。

一、Bbox面积计算

  1. def compute_area(boxes):
  2. '''
  3. Args
  4. boxes: (N,4) ndarray of float. y1,x1,y2,x2
  5. '''
  6. import numpy as np
  7. areas = np.zeros((len(boxes), dtype=np.float64)
  8. for i in range(len(boxes)):
  9. areas[i] = (boxes[i, 2] - boxes[i,0]) * (boxes[i, 3] - boxes[i, 1])
  10. return areas

二、Bbox中心点计算

  1. def get_center(boxes):
  2. '''
  3. Args
  4. boxes: (N,4) ndarray of float. x1,y1,x2,y2
  5. '''
  6. centers = [((boxes[0] + boxes[2]) / 2, (boxes[1] + boxes[3]) / 2) for box in boxes]
  7. return centers

三、Bbox之间的交并比计算

  1. def compute_overlap(boxes1, boxes2):
  2. """
  3. Args
  4. a: (N, 4) ndarray of float
  5. b: (K, 4) ndarray of float
  6. """
  7. import numpy as np
  8. for k in range(K):
  9. box_area = (
  10. (boxes2[k, 2] - boxes2[k, 0]) *
  11. (boxes2[k, 3] - boxes2[k, 1])
  12. )
  13. for n in range(N):
  14. iw = (
  15. min(boxes1[n, 2], boxes2[k, 2]) -
  16. max(boxes1[n, 0], boxes2[k, 0])
  17. )
  18. if iw > 0:
  19. ih = (
  20. min(boxes1[n, 3], boxes2[k, 3]) -
  21. max(boxes1[n, 1], boxes2[k, 1])
  22. )
  23. if ih > 0:
  24. ua = np.float64(
  25. (boxes1[n, 2] - boxes1[n, 0]) *
  26. (boxes1[n, 3] - boxes1[n, 1]) +
  27. box_area - iw * ih
  28. )
  29. overlaps[n, k] = iw * ih / ua
  30. return overlaps
  1. def compute_iou(boxes_a, boxes_b):
  2. """
  3. numpy 计算IoU
  4. :param boxes_a: [N,4]
  5. :param boxes_b: [M,4]
  6. :return: IoU [N,M]
  7. """
  8. import numpy as np
  9. # 扩维
  10. boxes_a = np.expand_dims(boxes_a, axis=1) # (N,1,4)
  11. boxes_b = np.expand_dims(boxes_b, axis=0) # (1,M,4)
  12. # 分别计算高度和宽度的交集
  13. overlap_h = np.maximum(0.0, np.minimum(boxes_a[..., 2], boxes_b[..., 2]) - np.maximum(boxes_a[..., 0], boxes_b[..., 0])) # (N,M)
  14. overlap_w = np.maximum(0.0, np.minimum(boxes_a[..., 3], boxes_b[..., 3]) - np.maximum(boxes_a[..., 1], boxes_b[..., 1])) # (N,M)
  15. # 通过点乘(对应元素相乘)计算交集
  16. overlap = overlap_w * overlap_h
  17. # 计算面积
  18. area_a = (boxes_a[..., 2] - boxes_a[..., 0]) * (boxes_a[..., 3] - boxes_a[..., 1])
  19. area_b = (boxes_b[..., 2] - boxes_b[..., 0]) * (boxes_b[..., 3] - boxes_b[..., 1])
  20. # 交并比
  21. iou = overlap / (area_a + area_b - overlap)
  22. return iou

四、将图像格式转化至模型输入的格式

  1. def load_image_into_numpy_array(image_path):
  2. """
  3. :param image_path:
  4. :return:
  5. """
  6. import cv2
  7. import Image
  8. import numpy as np
  9. image = Image.open(image_path).convert('RGB')
  10. # 注意cv2的图像通道顺序是BGR,而TensorFlow、pytorch支持的图像通道顺序是RGB。
  11. image = cv2.resize(np.array(image), (300, 300)).astype(np.uint8)
  12. return image

五、检测结果过滤

  1. def filter_detect_boxes(boxes, scores, classes, min_score, max_boxes):
  2. """
  3. :param boxes:
  4. :param scores:
  5. :param classes:
  6. :param min_score:最小得分阈值
  7. :param max_boxes:单帧最大Bbox检测数量
  8. :return:
  9. """
  10. idx = scores >= min_score
  11. boxes = boxes[idx]
  12. classes = classes[idx]
  13. scores = scores[idx]
  14. return boxes[:max_boxes], scores[:max_boxes], classes[:max_boxes]

六、多线程推理

  1. import multiprocessing
  2. print("start to detect ......")
  3. processes = []
  4. for i in range(12): # 线程数,可以按照待检测图像或视频数量做一个自适应调整。
  5. images = [image_path for idx, image_path in enumerate(TEST_IMAGE_PATHS) if idx % 12 == i]
  6. p = multiprocessing.Process(target=save_result, args=(images, boxes_path, classes_path, vis_output_path))
  7. # p = multiprocessing.Process(target=函数名, args=(前面指定函数所对应的参数,含images这个待检测的图像列表))
  8. p.start()
  9. processes.append(p)
  10. # 等待执行完成
  11. for p in processes:
  12. p.join()

七、基于多帧上检测结果的平滑过滤

  1. window_detect = [] # 需要写在循环外面
  2. # 数据处理过程略
  3. boxes, scores, classes = inference_and_filter(image)
  4. window_detect.append(classes) # 或者boxes, scores
  5. if len(window_detect) == window_size:
  6. # 进行逻辑处理,如过滤偶尔误报、利用滑窗均值代表当前帧的score检测结果等
  7. window_detect.pop(0)

零、其他

  • 针对region of interest进行检测的结果,可以通过坐标转化直接放到原图上可视化。
  • 针对形变后的region of interest进行检测的结果,可以先通过相同形变的逆过程将结果返回至roi区域,最后再放到原图上可视化。