[深度学习] 基于切片辅助超推理库SAHI优化小目标识别
对象检测是迄今为止计算机视觉中最重要的应用领域。然而,小物体的检测和大图像的推理仍然是实际使用中的主要问题,这是因为小目标物体有效特征少,覆盖范围少。小目标物体的定义通常有两种方式。一种是绝对尺度定义,即以物体的像素尺寸来判断是否为小目标,如在COCO数据集中,尺寸小于32×32像素的目标被判定为小目标。另外一种是相对尺度定义,即以物体在图像中的占比面积比例来判断是否为小目标,例如国际光学工程学会SPIE定义,若目标尺寸小于原图的0.12%则可以判定成小目标。
SAHI: Slicing Aided Hyper Inference(切片辅助超推理)通过图像切片的方式来检测小目标。SAHI检测过程可以描述为:通过滑动窗口将图像切分成若干区域,各个区域分别进行预测,同时也对整张图片进行推理。然后将各个区域的预测结果和整张图片的预测结果合并,最后用NMS(非极大值抑制)进行过滤。用动图表示该识别过程如下:
SAHI的官方仓库地址为:sahi。关于SAHI的使用可以阅读官方demo和官方文档:sahi-demo和sahi-docs。如果想进一步了解SAHI具体工作性能和原理,可以阅读官方发表的论文:Slicing Aided Hyper Inference and Fine-Tuning for Small Object Detection。
SAHI安装指令如下:
pip install sahi
本文所有算法展示效果和代码见:
github: Python-Study-Notes
1 SAHI使用
import sahi
# 打印sahi版本
print(sahi.__version__)
0.11.6
1.1 图像切片
SAHI提供了封装好的函数接口,以切分输入图像和其标注数据。切分后的子图及其标注数据可以用于识别,或者保存为本地数据以供模型训练。
1.1.1 单张图像切片
SAHI提供slice_image函数以切分单张图片及其标注文件(仅支持coco标注文件),slice_image函数接口介绍如下:
# 返回SAHI的图像分片结果类SliceImageResult
def slice_image(
image: Union[str, Image.Image], # 单张图像地址或单个pillow image对象,必填参数
coco_annotation_list: Optional[CocoAnnotation] = None, # coco标注文件
output_file_name: Optional[str] = None, # 输出文件名前缀
output_dir: Optional[str] = None, # 输出文件地址
slice_height: int = None, # 子图切分高度
slice_width: int = None, # 子图切分宽度
overlap_height_ratio: float = None, # 子图高度间的重叠率
overlap_width_ratio: float = None, # 子图宽度间的重叠率
auto_slice_resolution: bool = True, # 如果没有设置slice_height和slice_width,则自动确定slice_height、slice_width、overlap_height_ratio、overlap_width_ratio
min_area_ratio: float = 0.1, # 子图中标注框小于原始标注框占比,则放弃该标注框
out_ext: Optional[str] = None, # 图像后缀格式
verbose: bool = False, # 是否打印详细信息
)
slice_image函数源代码位于sahi/slicing.py中,这段代码可以单步调试看看怎么运行的,主要逻辑如下:
获得pillow image图像对象
调用get_slice_bboxes函数切分图像
- 获得切分参数
if slice_height and slice_width:
# 计算重叠像素
y_overlap = int(overlap_height_ratio * slice_height)
x_overlap = int(overlap_width_ratio * slice_width)
elif auto_slice_resolution:
x_overlap, y_overlap, slice_width, slice_height = get_auto_slice_params(height=image_height, width=image_width)
- 循环切分图像
# 行循环
while y_max < image_height:
# 设置起始切分坐标
x_min = x_max = 0
y_max = y_min + slice_height
# 列循环
while x_max < image_width:
x_max = x_min + slice_width
# 如果图像不够切分,框往左或往上移动
if y_max > image_height or x_max > image_width:
xmax = min(image_width, x_max)
ymax = min(image_height, y_max)
xmin = max(0, xmax - slice_width)
ymin = max(0, ymax - slice_height)
slice_bboxes.append([xmin, ymin, xmax, ymax])
else:
slice_bboxes.append([x_min, y_min, x_max, y_max])
# 下一次切分从本次切分图像x_max-x_overlap开始
x_min = x_max - x_overlap
y_min = y_max - y_overlap
保存图片结果和标注结果,并包装返回SliceImageResult对象
以下代码演示了对单张图片进行切片,并将切分后的子图保存到本地。
展示原图
# 展示输入图片
from PIL import Image
# 图像地址:https://github.com/obss/sahi/tree/main/demo/demo_data
image_path = "image/small-vehicles1.jpeg"
img = Image.open(image_path).convert('RGB')
img
切分图片
from sahi.slicing import slice_image
# 输出文件名前缀
output_file_name = "slice"
# 输出文件夹
output_dir = "result"
# 切分图像
slice_image_result = slice_image(
image=image_path,
output_file_name=output_file_name,
output_dir=output_dir,
slice_height=256,
slice_width=256,
overlap_height_ratio=0.2,
overlap_width_ratio=0.2,
verbose=False,
)
print("原图宽{},高{}".format(slice_image_result.original_image_width, slice_image_result.original_image_height))
# 切分后的子图以形式:图像前缀_所在原图顶点坐标来保存文件
print("切分子图{}张".format(len(slice_image_result.filenames)))
原图宽1068,高580
切分子图15张
展示切分后的子图
import matplotlib.pyplot as plt
from PIL import Image
import math
import os
axarr_row = 3
axarr_col = math.ceil(len(slice_image_result.filenames)/axarr_row)
f, axarr = plt.subplots(axarr_row, axarr_col, figsize=(14,7))
for index, file in enumerate(slice_image_result.filenames):
img = Image.open(os.path.join(slice_image_result.image_dir,file))
axarr[int(index/axarr_col), int(index%axarr_col)].imshow(img)
1.1.2 COCO数据集切片
SAHI提供slice_coco函数以切分coco数据集(仅支持coco数据集)。slice_coco函数接口介绍如下:
# 返回切片后的coco标注字典文件,coco文件保存地址
def slice_coco(
coco_annotation_file_path: str, # coco标注文件
image_dir: str, # coco图像集地址
output_coco_annotation_file_name: str, # 输出coco标注集文件名,不需要加文件类型后缀
output_dir: Optional[str] = None, # 输出文件地址
ignore_negative_samples: bool = False, # 是否忽略没有标注框的子图
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, # 如果没有设置slice_height和slice_width,则自动确定slice_height、slice_width、overlap_height_ratio、overlap_width_ratio
out_ext: Optional[str] = None, # 保存图像的扩展
verbose: bool = False, # 是否打印详细信息
)
slice_coco函数源代码位于sahi/slicing.py中,这段代码可以单步调试看看怎么做的,主要逻辑如下:
- 读取coco文件和图片信息
- 循环读取coco数据集的图片,每张图片调用get_slice_bboxes函数切分图像
- 创建coco dict结果并保存文件
以下代码演示了对coco数据集进行切片,并将切分后的子图和标注文件保存到本地。coco数据集可以包含若干张图片,但是以下代码示例中只包含一张图片,方便演示。
展示数据集
# 展示图像
from PIL import Image, ImageDraw
from sahi.utils.file import load_json
import matplotlib.pyplot as plt
import os
# coco图像集地址
image_path = "image"
# coco标注文件
coco_annotation_file_path="image/terrain2_coco.json"
# 加载数据集
coco_dict = load_json(coco_annotation_file_path)
f, axarr = plt.subplots(1, 1, figsize=(8, 8))
# 读取图像
img_ind = 0
img = Image.open(os.path.join(image_path,coco_dict["images"][img_ind]["file_name"])).convert('RGBA')
# 绘制标注框
for ann_ind in range(len(coco_dict["annotations"])):
xywh = coco_dict["annotations"][ann_ind]["bbox"]
xyxy = [xywh[0], xywh[1], xywh[0] + xywh[2], xywh[1] + xywh[3]]
ImageDraw.Draw(img, 'RGBA').rectangle(xyxy, width=5)
axarr.imshow(img)
<matplotlib.image.AxesImage at 0x210a7583250>
切分数据集
from sahi.slicing import slice_coco
# 保存的coco数据集标注文件名
output_coco_annotation_file_name="sliced"
# 输出文件夹
output_dir = "result"
# 切分数据集
coco_dict, coco_path = slice_coco(
coco_annotation_file_path=coco_annotation_file_path,
image_dir=image_path,
output_coco_annotation_file_name=output_coco_annotation_file_name,
ignore_negative_samples=False,
output_dir=output_dir,
slice_height=320,
slice_width=320,
overlap_height_ratio=0.2,
overlap_width_ratio=0.2,
min_area_ratio=0.2,
verbose=False
)
print("切分子图{}张".format(len(coco_dict['images'])))
print("获得标注框{}个".format(len(coco_dict['annotations'])))
indexing coco dataset annotations...
Loading coco annotations: 100%|█████████████████████████████████████████████████████████| 1/1 [00:00<00:00, 334.21it/s]
100%|████████████████████████████████████████████████████████████████████████████████████| 1/1 [00:00<00:00, 11.80it/s]
切分子图12张
获得标注框18个
展示切分后的子图和标注框
axarr_row = 3
axarr_col = math.ceil(len(coco_dict['images']) / axarr_row)
f, axarr = plt.subplots(axarr_row, axarr_col, figsize=(10, 7))
for index, img in enumerate(coco_dict['images']):
img = Image.open(os.path.join(output_dir, img["file_name"]))
for ann_ind in range(len(coco_dict["annotations"])):
# 搜索与当前图像匹配的边界框
if coco_dict["annotations"][ann_ind]["image_id"] == coco_dict["images"][index]["id"]:
xywh = coco_dict["annotations"][ann_ind]["bbox"]
xyxy = [xywh[0], xywh[1], xywh[0] + xywh[2], xywh[1] + xywh[3]]
# 绘图
ImageDraw.Draw(img, 'RGBA').rectangle(xyxy, width=5)
axarr[int(index / axarr_col), int(index % axarr_col)].imshow(img)
1.2 图像预测
1.2.1 接口介绍
SHAI提供了图像切片预测的封装接口,具体的函数接口如下:
AutoDetectionModel类
SAHI基于AutoDetectionModel类的from_pretrained函数加载深度学习模型。目前支持YOLOv5 models, MMDetection models, Detectron2 models和HuggingFace object detection models等深度学习模型库,如果想支持新的模型库,可以参考sahi/models目录下的模型文件,新建模型检测类。
模型预测
基于get_prediction函数调用模型预测单张图片,也就是直接调用AutoDetectionModel类提供的模型,直接推理单张图片。
基于get_sliced_prediction函数以切分图片的方式进行预测。在get_sliced_prediction函数内部会先切分图片,然后对每个子图单独进行模型推理;如果设置了对整张原图进行推理,那么也会整合原图推理的结果以增加模型精度。最后对所有的预测结果进行nms整合,相近的两个预测框也会进行合并。get_sliced_prediction函数接口如下:
def get_sliced_prediction(
image,
detection_model=None,
slice_height: int = None,
slice_width: int = None,
overlap_height_ratio: float = 0.2,
overlap_width_ratio: float = 0.2,
perform_standard_pred: bool = True, # 是否单独对原图进行识别
postprocess_type: str = "GREEDYNMM", # 合并结果的方式,可选'NMM', 'GRREDYNMM', 'NMS'
postprocess_match_metric: str = "IOS", # NMS匹配方式IOU或者IOS
postprocess_match_threshold: float = 0.5, # 匹配置信度
postprocess_class_agnostic: bool = False, # 在合并结果时,是否将不同类别的检测框放在一起处理
verbose: int = 1,
merge_buffer_length: int = None, # 低配设备使用,以加快处理
auto_slice_resolution: bool = True,
)
- 基于predict函数进行批处理,predict函数进一步封装了识别代码,如果想使用该函数,阅读predict源代码参数接口即可。
1.2.2 应用实例
直接预测图片
from sahi import AutoDetectionModel
from sahi.predict import get_prediction
# 初始化检测模型,缺少yolov5代码,pip install yolov5即可
detection_model = AutoDetectionModel.from_pretrained(
model_type='yolov5', # 模型类型
model_path='./yolov5n.pt', # 模型文件路径
confidence_threshold=0.3, # 检测阈值
device="cpu", # or 'cuda:0'
);
image = 'image/small-vehicles1.jpeg'
# 获得模型直接预测结果
result = get_prediction(image, detection_model)
# result是SAHI的PredictionResult对象,可获得推理时间,检测图像,检测图像尺寸,检测结果
# 查看标注框,可以用于保存为其他格式
for pred in result.object_prediction_list:
bbox = pred.bbox # 标注框BoundingBox对象,可以获得边界框的坐标、面积
category = pred.category # 类别Category对象,可获得类别id和类别名
score = pred.score.value # 预测置信度
# 保存文件结果
export_dir = "result"
file_name = "res"
result.export_visuals(export_dir=export_dir, file_name=file_name)
# 展示结果
from PIL import Image
import os
image_path = os.path.join(export_dir,file_name+'.png')
img = Image.open(image_path).convert('RGB')
img
切片预测图片
from sahi import AutoDetectionModel
from sahi.predict import get_sliced_prediction
# 初始化检测模型
detection_model = AutoDetectionModel.from_pretrained(
model_type='yolov5',
model_path='yolov5n.pt',
confidence_threshold=0.3,
device="cpu", # or 'cuda:0'
)
image = 'image/small-vehicles1.jpeg'
result = get_sliced_prediction(
image,
detection_model,
slice_height = 256,
slice_width = 256,
overlap_height_ratio = 0.2,
overlap_width_ratio = 0.2,
perform_standard_pred = True,
)
# result是SAHI的PredictionResult对象,可获得推理时间,检测图像,检测图像尺寸,检测结果
# 查看标注框,可以用于保存为其他格式
for pred in result.object_prediction_list:
bbox = pred.bbox # 标注框BoundingBox对象,可以获得边界框的坐标、面积
category = pred.category # 类别Category对象,可获得类别id和类别名
score = pred.score.value # 预测置信度
# 保存文件结果
export_dir = "result"
file_name = "res"
result.export_visuals(export_dir=export_dir, file_name=file_name)
# 结果导出为coco标注形式
coco_anno = result.to_coco_annotations()
# 结果导出为coco预测形式
coco_pred = result.to_coco_predictions()
# 展示结果
from PIL import Image
import os
image_path = os.path.join(export_dir,file_name+'.png')
img = Image.open(image_path).convert('RGB')
img
Performing prediction on 15 number of slices.
相对单张图片直接识别,通过切片的方式能够识别到更多的小目标。由于使用的模型是yolov5n,可以看到一些识别结果不正确,比如同一辆车在不同子图被分别识别为卡车或汽车,一种好的解决办法是将postprocess_class_agnostic参数设置为True,将不同类别的检测框放在一起进行合并,同时降低 postprocess_match_threshold以滤除结果。
image = 'image/small-vehicles1.jpeg'
result = get_sliced_prediction(
image,
detection_model,
slice_height = 256,
slice_width = 256,
overlap_height_ratio = 0.2,
overlap_width_ratio = 0.2,
perform_standard_pred = True,
postprocess_match_threshold = 0.2,
postprocess_class_agnostic = True,
)
# 保存文件结果
export_dir = "result"
file_name = "res"
result.export_visuals(export_dir=export_dir, file_name=file_name)
# 展示结果
from PIL import Image
import os
image_path = os.path.join(export_dir,file_name+'.png')
img = Image.open(image_path).convert('RGB')
img
Performing prediction on 15 number of slices.
1.3 SAHI工具函数
SAHI提供多个工具函数以处理COCO数据集,具体使用可以阅读sahi-docs-coco。
1.3.1 coco数据集制作与精度分析
以下代码创建了coco标注数据,并保存到本地
from sahi.utils.file import save_json
from sahi.utils.coco import Coco, CocoCategory, CocoImage, CocoAnnotation,CocoPrediction
# 创建coco对象
coco = Coco()
# 添加类
coco.add_category(CocoCategory(id=0, name='human'))
coco.add_category(CocoCategory(id=1, name='vehicle'))
# 循环遍历图像
for i in range(3):
# 创建单个图像
coco_image = CocoImage(
file_name="image{}.jpg".format(i), height=1080, width=1920)
# 添加图像对应的标注
coco_image.add_annotation(
CocoAnnotation(
# [x_min, y_min, width, height]
bbox=[0, 0, 200, 200],
category_id=0,
category_name='human'
)
)
coco_image.add_annotation(
CocoAnnotation(
bbox=[200, 100, 300, 300],
category_id=1,
category_name='vehicle'
)
)
# 添加图像预测数据
coco_image.add_prediction(
CocoPrediction(
score=0.864434,
bbox=[0, 0, 150, 150],
category_id=0,
category_name='human'
)
)
coco_image.add_prediction(
CocoPrediction(
score=0.653424,
bbox=[200, 100, 250, 200],
category_id=1,
category_name='vehicle'
)
)
# 将图像添加到coco对象
coco.add_image(coco_image)
# 提取json标注数据,不会保存图像预测结果
coco_json = coco.json
# 将json标注数据保存为json本地文件
save_json(coco_json, "coco_dataset.json")
# 提取预测结果json文件,并保存到本地
predictions_array = coco.prediction_array
save_json(predictions_array, "coco_predictions.json")
当我们获得了预测数据,我们可以基于pycocotools工具分析预测数据的精度,pycocotools是目标检测必备工具,官方仓库地址为cocoapi,结果分析代码如下:
# 需要单独安装pycocotools
from pycocotools.cocoeval import COCOeval
from pycocotools.coco import COCO
coco_ground_truth = COCO(annotation_file="coco_dataset.json")
coco_predictions = coco_ground_truth.loadRes("coco_predictions.json")
coco_evaluator = COCOeval(coco_ground_truth, coco_predictions, "bbox")
# 进行匹配计算
coco_evaluator.evaluate()
# 进行结果的累加
coco_evaluator.accumulate()
# 输出结果
coco_evaluator.summarize()
loading annotations into memory...
Done (t=0.00s)
creating index...
index created!
Loading and preparing results...
DONE (t=0.00s)
creating index...
index created!
Running per image evaluation...
Evaluate annotation type *bbox*
DONE (t=0.00s).
Accumulating evaluation results...
DONE (t=0.01s).
Average Precision (AP) @[ IoU=0.50:0.95 | area= all | maxDets=100 ] = 0.200
Average Precision (AP) @[ IoU=0.50 | area= all | maxDets=100 ] = 1.000
Average Precision (AP) @[ IoU=0.75 | area= all | maxDets=100 ] = 0.000
Average Precision (AP) @[ IoU=0.50:0.95 | area= small | maxDets=100 ] = -1.000
Average Precision (AP) @[ IoU=0.50:0.95 | area=medium | maxDets=100 ] = -1.000
Average Precision (AP) @[ IoU=0.50:0.95 | area= large | maxDets=100 ] = 0.200
Average Recall (AR) @[ IoU=0.50:0.95 | area= all | maxDets= 1 ] = 0.200
Average Recall (AR) @[ IoU=0.50:0.95 | area= all | maxDets= 10 ] = 0.200
Average Recall (AR) @[ IoU=0.50:0.95 | area= all | maxDets=100 ] = 0.200
Average Recall (AR) @[ IoU=0.50:0.95 | area= small | maxDets=100 ] = -1.000
Average Recall (AR) @[ IoU=0.50:0.95 | area=medium | maxDets=100 ] = -1.000
Average Recall (AR) @[ IoU=0.50:0.95 | area= large | maxDets=100 ] = 0.200
统计数据集标注信息
from sahi.utils.coco import Coco
coco = Coco.from_coco_dict_or_path("coco_dataset.json")
# 获得数据集状态,指标说明看字段名就能懂
stats = coco.stats
stats
indexing coco dataset annotations...
Loading coco annotations: 100%|████████████████████████████████████████████████████████| 3/3 [00:00<00:00, 1504.59it/s]
{'num_images': 3,
'num_annotations': 6,
'num_categories': 2,
'num_negative_images': 0,
'num_images_per_category': {'human': 3, 'vehicle': 3},
'num_annotations_per_category': {'human': 3, 'vehicle': 3},
'min_num_annotations_in_image': 2,
'max_num_annotations_in_image': 2,
'avg_num_annotations_in_image': 2.0,
'min_annotation_area': 40000,
'max_annotation_area': 90000,
'avg_annotation_area': 65000.0,
'min_annotation_area_per_category': {'human': 40000, 'vehicle': 90000},
'max_annotation_area_per_category': {'human': 40000, 'vehicle': 90000}}
预测结果过滤
from sahi.utils.file import save_json
from sahi.utils.coco import remove_invalid_coco_results
# 去除预测结果中的无效边界框,如边界框坐标为负的结果
coco_results = remove_invalid_coco_results("coco_predictions.json")
save_json(coco_results, "fixed_coco_result.json")
# 根据数据集实际标注信息,进一步去除边界框坐标超过图像长宽的结果
coco_results = remove_invalid_coco_results("coco_predictions.json", "coco_dataset.json")
1.3.2 coco数据集处理
切分数据集
from sahi.utils.coco import Coco
# 指定coco文件
coco_path = "coco_dataset.json"
# 初始coco对象
coco = Coco.from_coco_dict_or_path(coco_path)
# 拆分数据集为训练集和验证集,训练集图像占比0.85
result = coco.split_coco_as_train_val(
train_split_rate=0.85
)
# 保存训练集和验证集
save_json(result["train_coco"].json, "train_split.json")
save_json(result["val_coco"].json, "val_split.json")
indexing coco dataset annotations...
Loading coco annotations: 100%|████████████████████████████████████████████████████████| 3/3 [00:00<00:00, 3005.95it/s]
修改标注类别
from sahi.utils.coco import Coco
from sahi.utils.file import save_json
coco = Coco.from_coco_dict_or_path("coco_dataset.json")
print("标注类别:{}".format(coco.category_mapping))
# 修改数据集类别
# 将标注中human类的索引改为3,将原先vehicle类的标注删除
# 新加big_vehicle类和car类
desired_name2id = {
"big_vehicle": 1,
"car": 2,
"human": 3
}
# 更新标注类别
coco.update_categories(desired_name2id)
print("修改后标注类别:{}".format(coco.category_mapping))
# 保存结果
save_json(coco.json, "updated_coco.json")
indexing coco dataset annotations...
Loading coco annotations: 100%|████████████████████████████████████████████████████████| 3/3 [00:00<00:00, 1002.78it/s]
标注类别:{0: 'human', 1: 'vehicle'}
修改后标注类别:{1: 'big_vehicle', 2: 'car', 3: 'human'}
按照标注框面积过滤数据集
from sahi.utils.coco import Coco
from sahi.utils.file import save_json
# 打开标注数据
coco = Coco.from_coco_dict_or_path("coco_dataset.json")
# 过滤包含标注框面积小于min的图像
area_filtered_coco = coco.get_area_filtered_coco(min=50000)
# 过滤标注框面积不在[min,max]的图像
area_filtered_coco = coco.get_area_filtered_coco(min=50, max=80000)
# 筛选同时符合多个类别面积要求的图像
intervals_per_category = {
"human": {"min": 20, "max": 30000},
"vehicle": {"min": 50, "max": 90000},
}
area_filtered_coco = coco.get_area_filtered_coco(intervals_per_category=intervals_per_category)
# 导出数据
save_json(area_filtered_coco.json, "area_filtered_coco.json")
indexing coco dataset annotations...
Loading coco annotations: 100%|████████████████████████████████████████████████████████| 3/3 [00:00<00:00, 1503.69it/s]
过滤无标注的图片
from sahi.utils.coco import Coco
from sahi.utils.file import save_json
# 去除无标注框的图片
coco = Coco.from_coco_dict_or_path("coco_dataset.json", ignore_negative_samples=True)
# 导出数据
# save_json(coco.json, "coco_ignore_negative.json")
indexing coco dataset annotations...
Loading coco annotations: 100%|████████████████████████████████████████████████████████| 3/3 [00:00<00:00, 3007.39it/s]
裁剪标注框
from sahi.utils.coco import Coco
from sahi.utils.file import save_json
coco_path = "coco_dataset.json"
# 将溢出边界框剪裁为图像宽度和高度
coco = Coco.from_coco_dict_or_path(coco_path, clip_bboxes_to_img_dims=True)
# 对已有coco对象,将溢出边界框剪裁为图像宽度和高度
coco = coco.get_coco_with_clipped_bboxes()
save_json(coco.json, "coco.json")
indexing coco dataset annotations...
Loading coco annotations: 100%|████████████████████████████████████████████████████████| 3/3 [00:00<00:00, 1007.04it/s]
合并coco数据集
# from sahi.utils.coco import Coco
# from sahi.utils.file import save_json
# coco_1 = Coco.from_coco_dict_or_path("coco1.json", image_dir="images_1/")
# coco_2 = Coco.from_coco_dict_or_path("coco2.json", image_dir="images_2/")
# # 合并数据集
# coco_1.merge(coco_2)
# # 保存
# save_json(coco_1.json, "merged_coco.json")
下采样数据集
from sahi.utils.coco import Coco
from sahi.utils.file import save_json
coco_path = "coco_dataset.json"
coco = Coco.from_coco_dict_or_path(coco_path)
# 用1/10的图像创建Coco对象
# subsample_ratio表示每10张图像取1张图像
subsampled_coco = coco.get_subsampled_coco(subsample_ratio=10)
# 仅对包含标注框为category_id的图像进行下采样,category_i=-1时表示负样本
subsampled_coco = coco.get_subsampled_coco(subsample_ratio=10, category_id=0)
# 保存数据集
save_json(subsampled_coco.json, "subsampled_coco.json")
indexing coco dataset annotations...
Loading coco annotations: 100%|████████████████████████████████████████████████████████| 3/3 [00:00<00:00, 1512.19it/s]
上采样数据集
from sahi.utils.coco import Coco
from sahi.utils.file import save_json
coco_path = "coco_dataset.json"
coco = Coco.from_coco_dict_or_path(coco_path)
# 每个样本重复10次
upsampled_coco = coco.get_upsampled_coco(upsample_ratio=10)
# 仅对包含标注框为category_id的图像进行采样,category_i=-1时表示负样本
subsampled_coco = coco.get_upsampled_coco(upsample_ratio=10, category_id=0)
# 导出数据集
save_json(upsampled_coco.json, "upsampled_coco.json")
indexing coco dataset annotations...
Loading coco annotations: 100%|████████████████████████████████████████████████████████| 3/3 [00:00<00:00, 1503.51it/s]
1.3.3 coco数据集转换
导出为yolov5格式并分割数据集
from sahi.utils.coco import Coco
# 注意image_dir路径
coco = Coco.from_coco_dict_or_path("coco_dataset.json", image_dir="images/")
# 导出为yolov5数据集格式,train_split_rate设置训练集数据比例
# coco.export_as_yolov5(
# output_dir="output/",
# train_split_rate=0.85
# )
indexing coco dataset annotations...
Loading coco annotations: 100%|████████████████████████████████████████████████████████| 3/3 [00:00<00:00, 1002.22it/s]
将训练集和验证集导出为yolov5格式
from sahi.utils.coco import Coco, export_coco_as_yolov5
# 注意image_dir路径
train_coco = Coco.from_coco_dict_or_path("train_split.json", image_dir="images/")
val_coco = Coco.from_coco_dict_or_path("val_split.json", image_dir="images/")
# 导出数据集
# data_yml_path = export_coco_as_yolov5(
# output_dir="output",
# train_coco=train_coco,
# val_coco=val_coco
# )
indexing coco dataset annotations...
Loading coco annotations: 100%|████████████████████████████████████████████████████████| 2/2 [00:00<00:00, 1002.34it/s]
indexing coco dataset annotations...
Loading coco annotations: 100%|████████████████████████████████████████████████████████| 1/1 [00:00<00:00, 1003.42it/s]
1.4 总结
目标检测过程中,通过对高分辨率小目标图像进行滑动窗口切片,能够有效提高大分辨率小目标图像的识别精度。但是滑动切片识别有需要注意的地方:
- 需要图像数据集是否符合通用的高分辨小目标图像标准,如果对普通数据集进行切片识别容易拆分已有目标物体,这样做浪费推理时间也会导致最终检测结果精度不高。
- 滑动切片对识别模型的精度有一定的要求,一般来说模型越大精度越高,但是切片识别所花费的推理时间也越长。所以需要平衡模型精度和模型推理时间,而且也要确定滑动切片的尺度。
- 滑动切片识别在识别目标类别较少的任务中,识别精度更高,因为后处理能过滤很多重复识别检测框。
如果想了解其他的小目标识别方案,可以看看paddle家的paddledetection-smalldet。paddle提供了基于原图和基于切图的小目标识别方案,也提供了统计数据集尺寸分布的代码(该统计代码对某些特定的数据集效果不好,具体原因看看代码)。推荐看看PaddleDetection的小目标识别方案,做的很不错。
2 参考
- sahi
- sahi-demo
- sahi-docs
- Slicing Aided Hyper Inference and Fine-Tuning for Small Object Detection
- sahi/slicing.py
- sahi/models
- sahi-docs-coco
- cocoapi
- paddledetection-smalldet
[深度学习] 基于切片辅助超推理库SAHI优化小目标识别的更多相关文章
- 深度学习|基于LSTM网络的黄金期货价格预测--转载
深度学习|基于LSTM网络的黄金期货价格预测 前些天看到一位大佬的深度学习的推文,内容很适用于实战,争得原作者转载同意后,转发给大家.之后会介绍LSTM的理论知识. 我把code先放在我github上 ...
- 机器学习 —— 深度学习 —— 基于DAGNN的MNIST NET
DAGNN 是Directed acyclic graph neural network 缩写,也就有向图非循环神经网络.我使用的是由MatConvNet 提供的DAGNN API.选择这套API作为 ...
- 如何使用网格搜索来优化深度学习模型中的超参数(Keras)
https://machinelearningmastery.com/grid-search-hyperparameters-deep-learning-models-python-keras/ Ov ...
- 原 Nginx网络架构实战学习笔记(七):nginx性能优化小总结
文章目录 优化思路: 优化过程 Php-mysql的优化 Nginx+phjp+mysql+nginx 压力测试: 模拟 前0-10万是热数据, 10-20万是冷门数据 请求热数据 0-10,请求9次 ...
- 使用 PyTorch Lightning 将深度学习管道速度提高 10 倍
前言 本文介绍了如何使用 PyTorch Lightning 构建高效且快速的深度学习管道,主要包括有为什么优化深度学习管道很重要.使用 PyTorch Lightning 加快实验周期的六种 ...
- 30个深度学习库:按Python、C++、Java、JavaScript、R等10种语言分类
30个深度学习库:按Python.C++.Java.JavaScript.R等10种语言分类 包括 Python.C++.Java.JavaScript.R.Haskell等在内的一系列编程语言的深度 ...
- 深度学习遥感影像(哨兵2A/B)超分辨率
这段时间,用到了哨兵影像,遇到了一个问题,就是哨兵影像,它的RGB/NIR波段是10米分辨率的,但是其他波段是20米和60米的,这就需要pansharpening了,所以我们需要设计一种算法来进行解决 ...
- AI在汽车中的应用:实用深度学习
https://mp.weixin.qq.com/s/NIza8E5clC18eMF_4GMwDw 深度学习的“深度”层面源于输入层和输出层之间实现的隐含层数目,隐含层利用数学方法处理(筛选/卷积)各 ...
- 深度学习新星:GAN的基本原理、应用和走向
深度学习新星:GAN的基本原理.应用和走向 (本文转自雷锋网,转载已获取授权,未经允许禁止转载)原文链接:http://www.leiphone.com/news/201701/Kq6FvnjgbKK ...
- (转) 机器学习很有趣Part6:怎样使用深度学习进行语音识别
本文转自:http://www.jiqizhixin.com/article/2321 机器学习很有趣Part6:怎样使用深度学习进行语音识别 2017-02-19 13:20:47 机器学习 ...
随机推荐
- <三>从编译器角度理解C++代码编译和链接原理
1代码 点击查看代码 **sum.cpp** int gdata=10; int sum(int a,int b){ return a+b; } **main.cpp** extern int gda ...
- MyBatis(介绍和环境配置)
ORM(Object Relational Mapping) 设计模式,思想 对象关系映射,是一种数据持久化技术.它在对象模型和关系型数据库之间建立起对应关系,并且提供了一种机制,通过JavaBea ...
- selenium4-定位单个页面元素
在操作各项页面元素之前,先介绍下如何通过Python代码来找到这些元素.WebDriver提供了18种元素定位方法,共分为两类(定位当个元素.定位组元素),本节先举例详细介绍下selenium4-定位 ...
- 14.MongoDB系列之配置分片
1. 启动服务器 1.1 启动配置服务器 配置服务器是集群的大脑,保存着关于每个服务器包含哪些数据的所有元数据,因此,必须首先创建配置服务器. 由于资源限制,在同一机器上启动三个进程 # mkdir ...
- 项目实战:在线报价采购系统(React +SpreadJS+Echarts)
小伙伴们对采购系统肯定不陌生,小到出差路费.部门物资采购:大到生产计划.原料成本预估都会涉及到该系统. 管理人员可以通过采购系统减少管理成本,说是管理利器毫不过分,对于采购的效率提升也有极大帮助. 但 ...
- raid 5搭建部署
raid 5搭建部署 软raid与备份 1.用四块磁盘做实验,三块盘搭建raid阵列组,有一块当作备份可以使用raid 5来搭建三块磁盘的阵列组 创建命令如下: [root@xiaohaoge ~]# ...
- HTML躬行记(3)——WebRTC视频通话
WebRTC 在创建点对点(P2P)的连接之前,会先通过信令服务器交换两端的 SDP 和 ICE Candidate,取两者的交集,决定最终的音视频参数.传输协议.NAT 打洞方式等信息. 在完成媒体 ...
- 基于JESD204B和PCIe DMA的多通道数据采集和回放系统
基于JESD204B和PCIe DMA的多通道数据采集和回放系统 在主机端PCIe驱动的控制和调度下,数据采集与回放系统可以同时完成对多个JESD204B接口AD数据的采集以及JESD204B接口DA ...
- 23种设计模式之自定义Spring框架(五)
7,自定义Spring框架 7.1 spring使用回顾 自定义spring框架前,先回顾一下spring框架的使用,从而分析spring的核心,并对核心功能进行模拟. 数据访问层.定义UserDao ...
- Redis可视化管理工具-RedisDesktopManager
Windows客户端,访问Redis数据库并执行一些基本操作. 链接:https://pan.baidu.com/s/1OuGqIfbpGwglC-642rECbQ 提取码:m6uo