物件檢測是迄今為止計算機視覺中最重要的應用領域。然而,小物體的檢測和大影象的推理仍然是實際使用中的主要問題,這是因為小目標物體有效特徵少,覆蓋範圍少。小目標物體的定義通常有兩種方式。一種是絕對尺度定義,即以物體的畫素尺寸來判斷是否為小目標,如在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
import sahi
# 列印sahi版本
print(sahi.__version__)
0.11.6
SAHI提供了封裝好的函數介面,以切分輸入影象和其標註資料。切分後的子圖及其標註資料可以用於識別,或者儲存為本地資料以供模型訓練。
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)
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資料集可以包含若干張圖片,但是以下程式碼範例中只包含一張圖片,方便演示。
展示資料集
# 展示影象
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)
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,
)
直接預測圖片
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.
SAHI提供多個工具函數以處理COCO資料集,具體使用可以閱讀sahi-docs-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")
切分資料集
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]
匯出為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]
目標檢測過程中,通過對高解析度小目標影象進行滑動視窗切片,能夠有效提高大解析度小目標影象的識別精度。但是滑動切片識別有需要注意的地方:
如果想了解其他的小目標識別方案,可以看看paddle家的paddledetection-smalldet。paddle提供了基於原圖和基於切圖的小目標識別方案,也提供了統計資料集尺寸分佈的程式碼(該統計程式碼對某些特定的資料集效果不好,具體原因看看程式碼)。推薦看看PaddleDetection的小目標識別方案,做的很不錯。