[深層学習] スライス支援ハイパー推論ライブラリ SAHI に基づく小さなターゲット認識の最適化

物体検出は、コンピューター ビジョンにおける最も重要な応用分野です。ただし、小さなオブジェクトの検出と大きな画像の推論は、実際の使用では依然として主な問題です。これは、効果的な機能が少なく、カバレッジが少ない小さなターゲットオブジェクトによるものです。小さなターゲット オブジェクトを定義するには、通常 2 つの方法があります。1つは絶対縮尺定義、つまりオブジェクトのピクセルサイズを使用して小さなオブジェクトかどうかを判断するもので、たとえばCOCOデータセットでは、32×32ピクセルより小さいサイズのオブジェクトは小さなオブジェクトと判断されます. もう一つは相対縮尺の定義で、画像に写る物体の割合から小さい物体かどうかを判断するもので、例えば国際光学工学会SPIEでは、物体の大きさが0.12以下の場合を定義しています。元の画像の%、小さなオブジェクトと判断できます。
SAHI: Slicing Aided Hyper Inference (Slicing Aided Super Reasoning) は、画像スライスによって小さなターゲットを検出します。SAHI 検出プロセスは、次のように説明できます。画像はスライディング ウィンドウを介していくつかの領域に分割され、各領域は個別に予測され、画像全体も推測されます。次に、各領域の予測結果を画像全体の予測結果と組み合わせ、最後に NMS (非最大値抑制) でフィルタリングします。認識プロセスは、次のように動的な図で表されます。

SAHI の正式な倉庫住所は、sahiです。SAHI の使用については、公式デモと公式ドキュメント: sahi-demoおよびsahi-docsを参照してください。SAHI の特定の作業パフォーマンスと原理について詳しく知りたい場合は、公式論文を読むことができます: Slicing Aided Hyper Inference and Fine-Tuning for Small Object Detection .
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 注釈ファイルのみがサポートされています)。

# 返回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, # 是否打印详细信息
) 

The source code of the slice_image function is located in sahi/slicing.py . このコードを段階的にデバッグして、どのように機能するかを確認できます. 主なロジックは次のとおりです:

  1. 抱き枕画像の画像オブジェクトを取得する

  2. 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
    
  3. 画像結果と注釈結果を保存し、SliceImageResult オブジェクトをラップして返す

次のコードは、1 つのイメージをスライスし、分割されたサブイメージをローカルに保存する方法を示しています。

元の画像を表示する

# 展示输入图片
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

png

分割画像

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)

png

1.1.2 COCO データセットのスライス

SAHI は、coco データセットをスライスするための slice_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にあります. このコードを段階的にデバッグして、どのように機能するかを確認できます. 主なロジックは次のとおりです:

  1. cocoファイルと画像情報を読む
  2. ループしてココ データセットの画像を読み取り、画像ごとに get_slice_bboxes 関数を呼び出して画像をセグメント化します。
  3. coco dict の結果を作成してファイルを保存する

次のコードは、coco データセットをスライスし、スライスしたサブグラフと注釈ファイルをローカルに保存する方法を示しています。coco データ セットには複数の画像を含めることができますが、デモンストレーションに便利なように、次のコード例には画像が 1 つだけ含まれています。

データセットを表示

# 展示图像
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>

png

データセットの分割

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)

png

1.2 画像予測

1.2.1 インターフェースの紹介

SHAI は、画像スライス予測のためのカプセル化インターフェイスを提供します. 具体的な関数インターフェイスは次のとおりです:

AutoDetectionModel クラス

SAHI は、AutoDetectionModel クラスの from_pretrained 関数に基づいてディープ ラーニング モデルを読み込みます。現在、YOLOv5 モデル、MMDetection モデル、Detectron2 モデル、HuggingFace オブジェクト検出モデルなどのディープ ラーニング モデル ライブラリをサポートしています.新しいモデル ライブラリをサポートする場合は、 sahi/modelsディレクトリ内のモデル ファイルを参照して、新しいモデル ライブラリを作成できます。モデル検出クラス。

モデル予測

  • get_prediction 関数に基づいてモデルを呼び出して、単一の画像を予測します。つまり、AutoDetectionModel クラスによって提供されるモデルを直接呼び出し、単一の画像を直接推測します。

  • get_sliced_prediction 関数に基づいて、予測は画像をセグメント化することによって行われます。get_sliced_prediction 関数では、最初に画像がセグメント化され、次に各サブ画像に対して個別にモデル推論が実行されます; 元の画像全体に対する推論が設定されている場合は、元の画像に対する推論の結果も統合されますモデルの精度を上げます。最後に、すべての予測結果に対して nms 統合が実行され、2 つの同様の予測フレームもマージされます。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 ソース コードのパラメーター インターフェイスを読み取るだけです。

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

png

スライス予測画像

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.

png

一枚の画像を直接認識するよりも、スライスすることでより小さな対象物を認識することができます。使用しているモデルは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.

png

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 のpaddle detection-smalldetを参照してくださいPaddle は、元の画像とカット画像に基づいて小さなターゲット認識スキームを提供し、統計データ セットのサイズ分布のコードも提供します (この統計コードは、特定のデータ セットではうまく機能しません。特定の理由については、コードを参照してください)。非常に優れた PaddleDetection の小さなターゲット認識ソリューションを確認することをお勧めします。

2 参考

おすすめ

転載: blog.csdn.net/LuohenYJ/article/details/128538834