对具有小目标的图像进行过采样,并通过复制多个小目标对其进行扩充。然而,这种增强需要分割注释,因此,它与目标检测数据集不兼容。有方法可以从原始图像中截取放大区域,从中学习到更丰富的小目标特征。额外的特征对检测性能有积极的贡献,但要扩大的区域的选择带来了计算负担。
也有研究提出了一种用于小目标检测的全卷积网络,该网络包含了一种早期的视觉注意力机制,用来选择最有希望的包含小目标及其上下文的区域。还有研究提出了一种基于切片的技术,但其实现并不通用,仅适用于特定的目标检测器。也有研究提出了一种新型的小型行人检测网络(JCS-Net),该网络将分类任务和超分辨率任务整合在一个统一的框架中。
有学者提出了一种利用生成式对抗网络(GAN)从模糊的小人脸直接生成清晰的高分辨率人脸的算法。然而,由于这些技术提出了新的检测器体系结构,它们需要从头开始用大型数据集进行预训练,这是昂贵的。
在推理过程中,应用切片间25%的重叠,会增加小/中物体AP和整体AP,但略微降低大物体AP。增加是由切片预测的额外小目标真阳性引起,减少是由匹配大GT框的切片预测的假阳性引起。小目标检测AP以SF最佳,SI次之,大目标检测AP以SF最佳,FI次之,证实了FI对大目标检测的贡献。
检测小目标和远程目标检测是监控应用中的一个主要挑战。这些物体由图像中少量的像素表示,缺乏足够的细节,使得传统的检测器难以检测。在这项工作中,提出了一个名为切片辅助超推理(SAHI)的开源框架,该框架为小目标检测提供了一个通用的切片辅助推理和微调管道。所提出的技术是通用的,因为它可以应用在任何可用的目标检测器之上,而不需要进行任何微调。
利用Visdrone和xView空中目标检测数据集上的目标检测Baseline的实验评估表明,该推理方法可将FCOS、VFNet和TOOD检测器的目标检测AP分别提高6.8%、5.1%和5.3%。此外,通过切片辅助微调可以进一步提高检测精度,从而按相同的顺序累计增加了12.7%、13.4%和14.5%的AP。
所提出的技术已与Detectron2、MMDetection和YOLOv5模型完成集成。
开源地址:https://github.com/obss/sahi
def slice_image(
image: Union[str, Image.Image],
coco_annotation_list: Optional[CocoAnnotation] = None,
output_file_name: Optional[str] = None,
output_dir: Optional[str] = None,
slice_height: int = 512,
slice_width: int = 512,
overlap_height_ratio: float = 0.2,
overlap_width_ratio: float = 0.2,
min_area_ratio: float = 0.1,
out_ext: Optional[str] = None,
verbose: bool = False,
) -> SliceImageResult:
# define verboseprint
verboselog = logger.info if verbose else lambda *a, **k: None
def _export_single_slice(image: np.ndarray, output_dir: str, slice_file_name: str):
image_pil = read_image_as_pil(image)
slice_file_path = str(Path(output_dir) / slice_file_name)
# export sliced image
image_pil.save(slice_file_path)
verboselog("sliced image path: " + slice_file_path)
# create outdir if not present
if output_dir is not None:
Path(output_dir).mkdir(parents=True, exist_ok=True)
# read image
image_pil = read_image_as_pil(image)
verboselog("image.shape: " + str(image_pil.size))
image_width, image_height = image_pil.size
if not (image_width != 0 and image_height != 0):
raise RuntimeError(f"invalid image size: {image_pil.size} for 'slice_image'.")
slice_bboxes = get_slice_bboxes(
image_height=image_height,
image_width=image_width,
slice_height=slice_height,
slice_width=slice_width,
overlap_height_ratio=overlap_height_ratio,
overlap_width_ratio=overlap_width_ratio,
)
t0 = time.time()
n_ims = 0
# init images and annotations lists
sliced_image_result = SliceImageResult(original_image_size=[image_height, image_width], image_dir=output_dir)
# iterate over slices
for slice_bbox in slice_bboxes:
n_ims += 1
# extract image
image_pil_slice = image_pil.crop(slice_bbox)
# process annotations if coco_annotations is given
if coco_annotation_list is not None:
sliced_coco_annotation_list = process_coco_annotations(coco_annotation_list, slice_bbox, min_area_ratio)
# set image file suffixes
slice_suffixes = "_".join(map(str, slice_bbox))
if out_ext:
suffix = out_ext
else:
try:
suffix = Path(image_pil.filename).suffix
except AttributeError:
suffix = ".jpg"
# set image file name and path
slice_file_name = f"{output_file_name}_{slice_suffixes}{suffix}"
# create coco image
slice_width = slice_bbox[2] - slice_bbox[0]
slice_height = slice_bbox[3] - slice_bbox[1]
coco_image = CocoImage(file_name=slice_file_name, height=slice_height, width=slice_width)
# append coco annotations (if present) to coco image
if coco_annotation_list:
for coco_annotation in sliced_coco_annotation_list:
coco_image.add_annotation(coco_annotation)
# create sliced image and append to sliced_image_result
sliced_image = SlicedImage(image=np.asarray(image_pil_slice), coco_image=coco_image, starting_pixel=[slice_bbox[0], slice_bbox[1]],)
sliced_image_result.add_sliced_image(sliced_image)
# export slices if output directory is provided
if output_file_name and output_dir:
conc_exec = concurrent.futures.ThreadPoolExecutor(max_workers=MAX_WORKERS)
conc_exec.map(_export_single_slice, sliced_image_result.images, [output_dir] * len(sliced_image_result), sliced_image_result.filenames,)
verboselog("Num slices: " + str(n_ims) + " slice_height: " + str(slice_height) + " slice_width: " + str(slice_width),)
return sliced_image_result