austin-distel-rxpThOwuVgE-unsplash.jpg

AI연구회

경남ICT협회 AI 연구 모임

자료실

How to Detect Small Objects(작은 물체를 감지하는 방법)

작은 물체 감지란 무엇입니까?

작은 물체 감지는 비디오 피드나 이미지에서 작은 물체를 정확하게 식별하는 것을 목표로 하는 컴퓨터 비전 문제입니다. 물체 자체가 반드시 작을 필요는 없습니다. 예를 들어, 작은 물체 감지는 항공 컴퓨터 비전에서 매우 중요하며, 각 개별 물체가 사진 크기에 비해 작더라도 물체를 정확하게 식별할 수 있어야 합니다.

컴퓨터 비전 파이프라인에는 작은 물체를 감지하기 위한 최적화를 할 수 있는 두 단계가 있습니다.

  1. 추론 시점(이미 훈련된 모델이 있고 작은 객체에 대한 성능을 높이고 싶은 경우 이상적임) 및
  2. 훈련하기 전에 올바른 전처리 단계를 추가하세요.

두 단계 모두 최적화하여 감지 성능을 개선할 수 있습니다.

이 가이드에서는 두 단계 모두에서 최적화를 수행하는 방법을 안내합니다.

공공 항공 해상 데이터세트 에서 드론이 위에서 본 작은 물체

작은 물체 문제는 왜 해결하기 어려운가?

작은 물체를 효과적으로 식별하는 방법에 대해 이야기하기 전에 대답해야 할 근본적인 질문이 하나 있습니다. 애초에 이미지나 비디오에서 작은 물체를 찾는 것이 왜 그렇게 어려운가요?

작은 물체 문제는 전 세계적으로 물체 감지 모델을 괴롭히고 있습니다. 구매하지 않습니까? 최신 최신 모델 YOLOv3 , EfficientDetYOLOv4 에 대한 COCO 평가 결과를 확인하세요 .

최신 모델을 보려면 AP_S, AP_M, AP_L을 확인하세요. 작은 물체는 어렵다! ( 인용하다 )

예를 들어 EfficientDet 에서 작은 물체의 평균 정밀도(mAP )는 12%에 불과하며, 큰 물체의 AP는 51%입니다. 거의 5배 정도 차이가 나네요!

그렇다면 작은 물체를 감지하는 것이 왜 그렇게 어려울까?

모든 것은 모델에 달려 있습니다. 객체 감지 모델은 합성곱 레이어에서 픽셀을 집계하여 특징을 형성합니다.

PP-YOLO 의 객체 감지를 위한 기능 집계

그리고 네트워크의 마지막에는 손실 함수를 기반으로 예측이 이루어지며, 이 손실 함수는 예측과 실제 결과의 차이를 기반으로 픽셀 전체에서 합산됩니다.

YOLO의 손실 함수

기준 진실 상자가 크지 않으면 학습이 진행되는 동안 신호가 작아집니다.

또한 작은 물체에는 데이터 라벨링 오류가 있을 가능성이 가장 높으며 식별이 생략될 수 있습니다.

경험적으로나 이론적으로 작은 물체는 단단합니다.

작은 물체를 감지하는 방법(추론 최적화)

번화한 거리, 도시의 드론 영상, 수평선 근처의 파도를 타는 서퍼 등 순진하게 실행되는 객체 감지 모델은 종종 좋지 않은 결과를 낳습니다. 주된 이유는 더 큰 물체에 대해 훈련된 모델이 작은 세부 사항을 놓치기 때문입니다.

yolov8s-640은 거의 아무것도 감지하지 못합니다!

이를 해결하려면 yolov8s-1280 과 같은 고해상도 이미지에서 학습된 모델 을 사용할 수 있습니다 . 그러나 이 문제에 대한 우리의 접근 방식 은 InferenceSlicer 입니다 .

이 글에서는 그 사용 방법을 설명하고 두 가지 최신 기능을 강조하겠습니다.

  • 오버랩 필터링 전략
  • 세분화 지원.

추론 슬라이서란 무엇입니까?

전체 장면에서 모델을 실행하는 대신 모델을 InferenceSlicer더 작은 부분(슬라이스)으로 분할하고 각 부분에서 모델을 실행한 다음 결과를 함께 연결합니다. 일반적으로 이는 SAHI 로 알려져 있습니다 .

사용은 InferenceSlicer간단합니다.

import supervision as sv
from inference import get_model

model = get_model(model_id="yolov8m-640")
image = cv2.imread(<SOURCE_IMAGE_PATH>)

def callback(image_slice: np.ndarray) -> sv.Detections:
    results = model.infer(image_slice)[0]
    return sv.Detections.from_inference(results)

slicer = sv.InferenceSlicer(callback=callback)
detections = slicer(image)

결과를 보려면 이미지에 주석을 달면 됩니다.

annotated_frame = sv.BoundingBoxAnnotator().annotate(
    scene=image.copy(),
    detections=detections
)

InferenceSlicer를 사용한 yolov8s-640의 성과가 훨씬 더 좋았습니다.

시간이 훨씬 오래 걸렸지만 모델은 물 속에 있는 모든 사람을 감지했습니다.

우리가 실행한 코드는 다음과 같습니다.

import supervision as sv
from inference import get_model
import cv2


image = cv2.imread("beach.jpg")
model = get_model("yolov8s-640")

def slicer_callback(slice: np.ndarray) -> sv.Detections:
    result = model.infer(slice)[0]
    detections = sv.Detections.from_inference(result)
    return detections

slicer = sv.InferenceSlicer(
    callback=slicer_callback,
    slice_wh=(512, 512),
    overlap_ratio_wh=(0.4, 0.4),
    overlap_filter_strategy=sv.OverlapFilter.NONE
)
detections = slicer(image)

annotated_frame = sv.BoundingBoxAnnotator().annotate(
    scene=image.copy(),
    detections=detections
)

이 모든 매개변수는 무엇입니까? 더 자세히 살펴보겠습니다.

  • slice_wh각 슬라이스의 크기를 설정할 수 있습니다. 이미지를 정확하게 나누지 않아도 걱정하지 마세요. InferenceSlicer슬라이스 위치를 자동으로 결정하지만 가끔 겹칩니다. slice_wh더 작은 값을 지정하면 더 많은 블록이 생성되어 추론이 더 느리지만 더 정확해집니다.
  • overlap_ratio_wh, 이전 매개변수와 무관하게 각 슬라이스에 약간의 오버랩을 추가합니다. 로 설정하면 (0, 0)가장자리 근처의 객체가 잘려 모델이 혼란스러워질 수 있습니다. 최소 20% 오버랩을 권장합니다 (0.2, 0.2). 값이 클수록 슬라이스가 더 많아집니다. 추론은 더 오래 걸리지만 더 정확해집니다.
  • callback각 조각에서 수행되는 작업을 정의합니다. np.ndarray이미지를 받아들이고, 일부 모델 로직을 수행하고, 하나의 객체를 반환하는 함수입니다 sv.Detections. 함수 입력은 생성되는 것과 유사한 BGR(청록색-적색)으로 이루어집니다 cv2.imread.
  • thread_workers여러 스레드를 사용할 수 있으므로 모델이 CPU에서 실행될 때 성능이 향상될 수 있습니다. GPU로 작업할 때는 이 값을 1. 우리는 병렬 구현을 위해 노력하고 있습니다. 필요한 것이 있으면 알려주십시오!
  • 마지막으로 중복되거나 겹치는 탐지를 제거하는 작업을 처리합니다 overlap_filter_strategy. iou_threshold더 자세히 살펴보겠습니다.

오버랩 필터링 전략

특성상 일부 모델은 여러 개의 중첩 감지를 생성합니다. 설정 overlap_ratio_wh도 기여합니다. 이전 해변 예에서는 575개의 탐지로 끝났지만 실제 개수는 280에 가깝습니다. 어떻게 도달합니까?

해변의 예에서는 겹치는 부분을 보기 어렵기 때문에 간단한 이미지를 분석해 보겠습니다. 로 다음을 감지했다고 가정합니다 overlap_filter_strategy = sv.OverlapFilter.NONE. 모든 탐지 항목을 볼 수 있지만 개선의 여지가 있습니다.

앞 차량과 밴에서 중복되는 영역이 여러 개 감지되었습니다.

기본적으로 비최대 억제InferenceSlicer (NMS)를 수행하여 일부 감지를 억제합니다. 요점은 상당한 중복이 있는 감지가 발견될 때마다 가장 높은 신뢰도를 가진 감지를 유지하고 다른 감지는 삭제한다는 것입니다. 매개변수를 설정하여 이를 제어할 수 있습니다. 값이 낮을수록 더 많은 감지가 삭제됩니다.InferenceSlieriou_threshold

관심이 있으시다면 Piotr가 NumPy를 사용한 Non-Max Suppression 에 대한 심층 분석을 작성했습니다 .

자동차에서 중복 감지는 삭제되었습니다! 하지만 밴에서도 하나 삭제되었습니다.

비최대 병합

에서는 supervision v0.21.0더 많은 필터링 전략을 도입했습니다. 을 설정하면 overlap_filter_strategy이제 필터링을 수행하지 않거나 NMM ( non-max-merge )을 수행할 수 있습니다.

설정하여 사용하실 수 있습니다 overlap_filter_strategy = sv.OverlapFilter.NON_MAX_MERGE.

Non-Max 병합은 Non-Max 억제와 매우 유사합니다. 먼저, IOU를 계산하고 임계값과 비교하여 어떤 기능이 크게 겹치는지 확인합니다. 그러나 가장 자신 있는 기능만 남기고 모두 버리는 대신 기능을 점진적으로 병합합니다. 알고리즘은 다음과 같습니다.

  1. 모든 기능의 IOU 계산
  2. 각각이 최소한 겹치는 기능 그룹을 찾습니다.iou_threshold
  3. 각 그룹의 경우 가장 확신이 강한 탐지부터 시작하여 다음으로 확신이 강한 탐지를 첫 번째 탐지에 병합합니다.
  4. IOU를 다시 계산하여 무한히 병합하지 않도록 합니다.
  5. 3단계로 돌아가서 추가 병합이 불가능할 때까지 계속합니다.
  6. 다른 그룹과 함께 이 과정을 반복하세요.

마지막으로, 감지된 객체를 둘러싼 상자가 표시됩니다.

자동차에서는 Non-max-merge가 비슷한 성능을 보였지만 밴에서는 더 나은 감지 성능을 보였습니다.

올바른 매개변수 선택

우리의 조언은 다음과 같습니다. 사용 사례와 다양한 InferenceSlicer매개변수를 실험해 보세요.


InferenceSlicer먼저, 모든 객체를 감지할 수 없는 표준 접근 방식인지 확인하세요 .

그렇지 않은 경우 InferenceSlicer기본 매개변수를 사용하여 시작하십시오. 계속해서 결과를 설정 slice_wh하고 overlap_ratio_wh미세 조정하세요.

마지막으로, 탐지 중복을 확인합니다. 대부분의 경우 기본값이 overlap_filter_strategy잘 작동합니다. 그렇지 않으면 .을 사용하여 실험합니다 . ! sv.OverlapFilter.NON_MAX_MERGE를 설정하는 것을 잊지 마세요 .iou_threshold

오버랩 처리 전략

세분화 지원

기사에서는 탐지와 상자에 대해 언급했지만 이후에는 supervision v0.21.0분할과 마스크를 사용하여 이를 빠르게 수행할 수 있습니다! 필요한 것은 분할 모델뿐입니다. 예 yolov8s-seg-640:

import supervision as sv
from inference import get_model

model = get_model(model_id="yolov8s-seg-640")
image = cv2.imread(<SOURCE_IMAGE_PATH>)

def callback(image_slice: np.ndarray) -> sv.Detections:
    results = model.infer(image_slice)[0]
    return sv.Detections.from_inference(results)

slicer = sv.InferenceSlicer(callback=callback)
detections = slicer(image)

마스크를 보려면 다른 주석 작성 도구를 사용해야 합니다!

annotated_frame = sv.MaskAnnotator().annotate(
    scene=image.copy(),
    detections=detections
)

AI 생성 이미지에 대한 실행은 다음과 같습니다.

InferenceSlicer의 결함에 주목하세요. 사람이 크면 시점에 가까워도 완전히 감지되지 않습니다.

보기는 어렵지만 InferenceSlicer로 생성된 해변 이미지의 분할은 다음과 같습니다.

yolov8s-seg-640을 사용하여 해변의 InferenceSlicer 출력을 매우 확대한 그림

Roboflow의 Inference Slicer는 이미지를 작은 세그먼트로 분할하고 각 부분에서 선택한 모델을 실행한 다음 결과를 하나로 묶습니다. 겹치는 결과가 있는 경우 Slicer는 overlap_filter_strategy선택한 항목에 따라 자동으로 처리합니다. 최근에는 세분화와도 작동합니다!

다음에 작은 물건을 다루는 데 어려움을 겪는다면, 한번 시도해 보세요!

작은 물체를 감지하는 방법(전처리)

이제 문제를 이해하고 해결 방법에 대해 논의할 준비가 되었습니다. 작은 객체에 대한 모델 성능을 향상하려면 다음 기술을 권장합니다.

 

팁 #1: 이미지 캡처 해상도를 높이세요

해상도, 해상도, 해상도... 그것은 모두 해상도 에 관한 것입니다 .

매우 작은 물체는 경계 상자 내에 단지 몇 개의 픽셀만 포함할 수 있습니다. 즉, 감지기가 작은 상자에서 형성할 수 있는 특징의 풍부함을 높이기 위해 이미지의 해상도를 높이는 것이 매우 중요합니다.

따라서 가능하면 최대한 높은 해상도의 이미지를 촬영하는 것이 좋습니다.

팁 #2: 모델의 입력 해상도 높이기

이미지가 더 높은 해상도 로 되면 모델의 입력 해상도를 확장할 수 있습니다. 경고: 이렇게 하면 훈련하는 데 더 오래 걸리는 대형 모델이 생성되고 배포를 시작할 때 추론 속도가 느려집니다. 성능과 속도의 적절한 균형을 찾기 위해 실험을 실행해야 할 수도 있습니다.

YOLOv4 훈련 튜토리얼 에서 설정 파일에서 이미지 크기를 변경하여 입력 해상도를 쉽게 확장할 수 있습니다 .

[net]
batch=64
subdivisions=36
width={YOUR RESOLUTION WIDTH HERE}
height={YOUR RESOLUTION HEIGHT HERE}
channels=3
momentum=0.949
decay=0.0005
angle=0
saturation = 1.5
exposure = 1.5
hue = .1

learning_rate=0.001
burn_in=1000
max_batches=6000
policy=steps
steps=4800.0,5400.0
scales=.1,.1

훈련 명령에서 이미지 크기 매개변수를 변경하여 YOLOv5를 훈련하는 방법에 대한 튜토리얼 에서 입력 해상도를 쉽게 조정할 수도 있습니다 .

!python train.py --img {YOUR RESOLUTON SIZE HERE} --batch 16 --epochs 10 --data '../data.yaml' --cfg ./models/custom_yolov5s.yaml --weights '' --name yolov5s_results  --cache

참고: 훈련 데이터의 최대 해상도까지만 개선된 결과를 볼 수 있습니다.

팁 #3: 전처리 중에 이미지 타일링

작은 이미지를 감지하는 또 다른 훌륭한 전략은 전처리 단계로 이미지를 타일링하는 것입니다. 타일링을 사용하면 작은 물체에 대한 감지기를 효과적으로 확대할 수 있지만 빠른 추론을 실행하는 데 필요한 작은 입력 해상도를 유지할 수 있습니다.

 

Roboflow 의 전처리 단계로 이미지 타일링

훈련 중에 타일링을 사용하는 경우 추론 시 이미지도 타일링해야 한다는 점을 기억하는 것이 중요합니다.

팁 #4: 추론 시 타일 이미지

훈련 중에 타일링을 사용한 경우 더 정확한 결과를 얻으려면 추론 중에도 타일링을 사용해야 합니다 . 추론 중에 객체가 훈련 중에 있던 크기와 비슷하도록 확대된 관점을 유지하고 싶기 때문입니다.

다음은 항공 사진을 통해 자동차를 감지하도록 훈련된 모델의 예입니다. 모델은 원본 이미지의 작은 크기와 큰 크기를 고려하여 자동차를 더 잘 인식하기 위해 타일링으로 훈련되었지만 추론 시 타일링을 사용하지 않으면 차량의 크기에 더 가깝기 때문에 자동차 대신 건물 및 기타 큰 형상을 감지하게 됩니다. 훈련 중에 감지하려고 시도한 개체입니다.

추론 시 타일링 없이 오류가 발생하기 쉬운 결과(제공: CHUTTERSNAP )

아래에서는 추론을 실행하기 전에 이미지에 타일링을 적용했습니다. 이를 통해 이미지의 일부를 확대하여 자동차를 더 크게 만들고 모델에서 쉽게 감지할 수 있습니다.

추론 시 타일링으로 결과 개선(제공: CHUTTERSNAP )

팁 #5: 이미지 확대를 사용하여 더 많은 데이터 생성

데이터 증대는 기본 데이터세트에서 새로운 이미지를 생성합니다. 이는 모델이 훈련 세트에 과적합되는 것을 방지하는 데 매우 유용할 수 있습니다 .

특히 작은 객체 감지에 유용한 증강에는 무작위 자르기 , 무작위 회전 , 모자이크 증강이 있습니다 .

팁 #6: 자동 학습 모델 앵커 사용

앵커 박스는 모델이 예측하는 것을 학습하는 전형적인 경계 박스입니다. 즉, 앵커 박스는 사전 설정될 수 있으며 때로는 훈련 데이터에 대해 최적이 아닐 수 있습니다. 이러한 박스를 현재 작업에 맞게 사용자 정의하는 것이 좋습니다. 다행히도 YOLOv5 모델 아키텍처는 사용자 정의 데이터를 기반으로 자동으로 이를 수행합니다. 해야 할 일은 훈련을 시작하는 것뿐입니다.

Analyzing anchors... anchors/target = 4.66, Best Possible Recall (BPR) = 0.9675. Attempting to generate improved anchors, please wait...
WARNING: Extremely small objects found. 35 of 1664 labels are < 3 pixels in width or height.
Running kmeans for 9 anchors on 1664 points...
thr=0.25: 0.9477 best possible recall, 4.95 anchors past thr
n=9, img_size=416, metric_all=0.317/0.665-mean/best, past_thr=0.465-mean: 18,24,  65,37,  35,68,  46,135,  152,54,  99,109,  66,218,  220,128,  169,228
Evolving anchors with Genetic Algorithm: fitness = 0.6825: 100%|██████████| 1000/1000 [00:00<00:00, 1081.71it/s]
thr=0.25: 0.9627 best possible recall, 5.32 anchors past thr
n=9, img_size=416, metric_all=0.338/0.688-mean/best, past_thr=0.476-mean: 13,20,  41,32,  26,55,  46,72,  122,57,  86,102,  58,152,  161,120,  165,204

팁 #7: 관련 없는 클래스 필터링

클래스 관리란 데이터 세트의 품질을 개선하는 중요한 기술입니다. 다른 클래스와 상당히 겹치는 클래스가 있는 경우 데이터 세트에서 이 클래스를 필터링해야 합니다. 그리고 데이터 세트의 작은 개체가 감지할 가치가 없다고 판단하여 제거하고 싶을 수도 있습니다. Roboflow Pro 의 일부인 고급 데이터 세트 상태 확인을 사용하면 이러한 모든 문제를 빠르게 식별할 수 있습니다 .

Roboflow의 온톨로지 관리 도구를 통해 클래스 생략 및 클래스 이름 변경이 모두 가능합니다 .

결론

작은 물체를 제대로 감지하는 것은 정말 어려운 일입니다. 이 글에서는 작은 물체 감지기를 개선하기 위한 몇 가지 전략을 논의했습니다. 즉, 다음과 같습니다.

 

(Linas Kondrackis가 작성한 게시물에서)

기업 홍보를 위한 확실한 방법
협회 홈페이지에 회사정보를 보강해 보세요.