728x90
반응형

# 성능 평가

Metrics - IOU (Intersection over Union)

=> 모델이 예측한 결과와 실측(Gound Truth) box가 얼마나 정확하게 겹치는가를 나타내는 지표

 

생성된 전체 면적 중에 예측이 맞은 면적을 구하는 것이기 때문에 1에 가까울수록 좋다

pascal voc 0.5, ms coco competition 0.5 ~ 0.95

 

# 입력인자로 후보 박스와 실제 박스를 받아서 IOU를 계산하는 함수 생성

import numpy as np 

def compute_iou(cand_box, gt_box):
    # cand_box ss에서 추천한 box, gt_box 실제 box
    # Calculate intersection areas : 쉽게 구하는 방법
    x1 = np.maximum(cand_box[0], gt_box[0])
    y1 = np.maximum(cand_box[1], gt_box[1])
    x2 = np.minimum(cand_box[2], gt_box[2])
    y2 = np.minimum(cand_box[3], gt_box[3])
    
    intersection = np.maximum(x2 - x1, 0) * np.maximum(y2 - y1, 0)
    
    cand_box_area = (cand_box[2] - cand_box[0]) * (cand_box[3] - cand_box[1])
    gt_box_area = (gt_box[2] - gt_box[0]) * (gt_box[3] - gt_box[1])
    union = cand_box_area + gt_box_area - intersection
    
    iou = intersection / union
    return iou

# gt_box 생성

import cv2
import matplotlib.pyplot as plt
%matplotlib inline

# 실제 box(Ground Truth)의 좌표를 아래와 같다고 가정. 
gt_box = [60, 15, 320, 420]


img = cv2.imread('./data/audrey01.jpg')
img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)

red = (255, 0 , 0)
img_rgb = cv2.rectangle(img_rgb, (gt_box[0], gt_box[1]), (gt_box[2], gt_box[3]), color=red, thickness=2)

plt.figure(figsize=(8, 8))
plt.imshow(img_rgb)
plt.show()

사람이 입력한 gt_box 정보

# 예측하기

import selectivesearch

#selectivesearch.selective_search()는 이미지의 Region Proposal정보를 반환 
img = cv2.imread('./data/audrey01.jpg')
img_rgb2 = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
_, regions = selectivesearch.selective_search(img_rgb2, scale=100, min_size=2000)

print(type(regions), len(regions))
#<class 'list'> 41

# 평가하기

cand_rects = [cand['rect'] for cand in regions]
for index, cand_box in enumerate(cand_rects):
    # 전처리
    cand_box = list(cand_box)
    cand_box[2] += cand_box[0]
    cand_box[3] += cand_box[1]
    
    # 평가하기
    iou = compute_iou(cand_box, gt_box)
    print('index:', index, "iou:", iou)
    
# index: 0 iou: 0.06157293686705451
# index: 1 iou: 0.07156308851224105
# index: 2 iou: 0.2033654637255666
# index: 3 iou: 0.04298195631528965
# index: 4 iou: 0.14541310541310543
# index: 5 iou: 0.10112060778727446
# index: 6 iou: 0.11806905615946989
# index: 7 iou: 0.1420163334272036
# index: 8 iou: 0.035204259342190375
# index: 9 iou: 0.004256894317971497
# index: 10 iou: 0.5184766640298338
# index: 11 iou: 0.04465579710144928
# index: 12 iou: 0.0853656220322887
# index: 13 iou: 0.015722240419259743
# index: 14 iou: 0.037833068643021
# index: 15 iou: 0.22523535071077264
# index: 16 iou: 0.0
# index: 17 iou: 0.053941120607787274
# index: 18 iou: 0.05154006626579948
# index: 19 iou: 0.05660327592118798
# index: 20 iou: 0.01165009904393209
# index: 21 iou: 0.18588082901554404
# index: 22 iou: 0.19555555555555557
# index: 23 iou: 0.5409250175192712
# index: 24 iou: 0.205679012345679
# index: 25 iou: 0.042245111210628454
# index: 26 iou: 0.34848824374009246
# index: 27 iou: 0.18588082901554404
# index: 28 iou: 0.10952135872362326
# index: 29 iou: 0.29560078245307364
# index: 30 iou: 0.045470015655843715
# index: 31 iou: 0.3126506582607083
# index: 32 iou: 0.4934902582553282
# index: 33 iou: 0.5490037131949166
# index: 34 iou: 0.1018867924528302
# index: 35 iou: 0.31513409961685823
# index: 36 iou: 0.3423913043478261
# index: 37 iou: 0.6341234282410753
# index: 38 iou: 0.6270619201314865
# index: 39 iou: 0.6270619201314865
# index: 40 iou: 0.6270619201314865

 

 

# 수정 반영하기

# cand['size'] > 5000인 box들만
cand_rects = [cand['rect'] for cand in regions if cand['size'] > 5000]
cand_rects.sort()

# 다시로드
img = cv2.imread('./data/audrey01.jpg')
img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
print('img shape:', img.shape)

# 추천 box
green_rgb = (125, 255, 51)
cand_rects = [cand['rect'] for cand in regions if cand['size'] > 3000]
gt_box = [60, 15, 320, 420]
img_rgb = cv2.rectangle(img_rgb, (gt_box[0], gt_box[1]), (gt_box[2], gt_box[3]), color=red, thickness=2)

for index, cand_box in enumerate(cand_rects):
    # 전처리
    cand_box = list(cand_box)
    cand_box[2] += cand_box[0]
    cand_box[3] += cand_box[1]
    # 평가
    iou = compute_iou(cand_box, gt_box)
    
    # 성능이 좋은 box만
    if iou > 0.5:
        print('index:', index, "iou:", iou, 'rectangle:',(cand_box[0], cand_box[1], cand_box[2], cand_box[3]) )
        cv2.rectangle(img_rgb, (cand_box[0], cand_box[1]), (cand_box[2], cand_box[3]), color=green_rgb, thickness=1)
        text = "{}: {:.2f}".format(index, iou)
        cv2.putText(img_rgb, text, (cand_box[0]+ 100, cand_box[1]+10), cv2.FONT_HERSHEY_SIMPLEX, 0.4, color=green_rgb, thickness=1)
    
plt.figure(figsize=(12, 12))
plt.imshow(img_rgb)
plt.show()

# img shape: (450, 375, 3)
# index: 8 iou: 0.5184766640298338 rectangle: (72, 171, 324, 393)
# index: 18 iou: 0.5409250175192712 rectangle: (72, 171, 326, 449)
# index: 28 iou: 0.5490037131949166 rectangle: (0, 97, 374, 449)
# index: 32 iou: 0.6341234282410753 rectangle: (0, 0, 374, 444)
# index: 33 iou: 0.6270619201314865 rectangle: (0, 0, 374, 449)
# index: 34 iou: 0.6270619201314865 rectangle: (0, 0, 374, 449)
# index: 35 iou: 0.6270619201314865 rectangle: (0, 0, 374, 449)

반응형
728x90
반응형

# selective search 설치

!pip install selectivesearch0

 

# 오드리 햅번 이미지 가져오기

!mkdir /content/data
!wget -O /content/data/audrey01.jpg https://raw.githubusercontent.com/chulminkw/DLCV/master/data/image/audrey01.jpg

# 데이터 로드

import selectivesearch
import cv2
import matplotlib.pyplot as plt
import os
%matplotlib inline

### 오드리헵번 이미지를 cv2로 로드하고 matplotlib으로 시각화 
img = cv2.imread('./data/audrey01.jpg')
# cvtColor : RGB로 바꿈
img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
print('img shape:', img.shape)

plt.figure(figsize=(8, 8))
plt.imshow(img_rgb)
plt.show()

사람 눈엔 직관적으로 사진이지만, 컴퓨터에겐 그래프이다.

# selective_search에 사진을 넣고 region 탐색

import selectivesearch 

#selectivesearch.selective_search()는 이미지의 Region Proposal정보를 반환 
# selectivesearch.selective_search(img file, scale=오브젝트 추천 크기, min_size=오브젝트 최소 크기)
_, regions = selectivesearch.selective_search(img_rgb, scale=100, min_size=2000)
# 튜플 생략, regions


print(type(regions), len(regions))
# <class 'list'> 41
# 41개의 공간

#반환된 Region Proposal(후보 영역)에 대한 정보 보기.

반환된 regions 변수는 리스트 타입으로 세부 원소로 딕셔너리를 가지고 있음. 개별 딕셔너리내 KEY값별 의미

- rect 키값은 x,y 시작 좌표와 너비, 높이 값을 가지며 이 값이 Detected Object 후보를 나타내는 Bounding box 정보임.

- rect: 시작점, 시작점, widths, heights

- size는 segment로 select된 Object의 크기

- labels는 해당 rect로 지정된 Bounding Box내에 있는 오브젝트들의 고유 ID

- [7, 11] 7번과 11번을 합쳐야겠다

- 아래로 내려갈 수록 너비와 높이 값이 큰 Bounding box이며 하나의 Bounding box에 여러개의 오브젝트가 있을 확률이 커짐.

regions
[{'labels': [0.0], 'rect': (0, 0, 107, 167), 'size': 11166},
 {'labels': [1.0], 'rect': (15, 0, 129, 110), 'size': 8771},
 {'labels': [2.0], 'rect': (121, 0, 253, 133), 'size': 17442},
 {'labels': [3.0], 'rect': (134, 17, 73, 62), 'size': 2713},
 {'labels': [4.0], 'rect': (166, 23, 87, 176), 'size': 8639},
 {'labels': [5.0], 'rect': (136, 53, 88, 121), 'size': 4617},
 {'labels': [6.0], 'rect': (232, 79, 117, 147), 'size': 7701},
 {'labels': [7.0], 'rect': (50, 91, 133, 123), 'size': 7042},
 {'labels': [8.0], 'rect': (305, 97, 69, 283), 'size': 11373},
 {'labels': [9.0], 'rect': (0, 161, 70, 46), 'size': 2363},
 {'labels': [10.0], 'rect': (72, 171, 252, 222), 'size': 34467},
 {'labels': [11.0], 'rect': (0, 181, 118, 85), 'size': 5270},
 {'labels': [12.0], 'rect': (106, 210, 89, 101), 'size': 2868},
 {'labels': [13.0], 'rect': (302, 228, 66, 96), 'size': 2531},
 {'labels': [14.0], 'rect': (0, 253, 92, 134), 'size': 7207},
 {'labels': [15.0], 'rect': (153, 270, 173, 179), 'size': 10360},
 {'labels': [16.0], 'rect': (0, 305, 47, 139), 'size': 4994},
 {'labels': [17.0], 'rect': (104, 312, 80, 71), 'size': 3595},
 {'labels': [18.0], 'rect': (84, 360, 91, 67), 'size': 2762},
 {'labels': [19.0], 'rect': (0, 362, 171, 87), 'size': 7705},
 {'labels': [20.0], 'rect': (297, 364, 77, 85), 'size': 5164},
 {'labels': [7.0, 11.0], 'rect': (0, 91, 183, 175), 'size': 12312},
 {'labels': [4.0, 5.0], 'rect': (136, 23, 117, 176), 'size': 13256},
 {'labels': [10.0, 15.0], 'rect': (72, 171, 254, 278), 'size': 44827},
 {'labels': [4.0, 5.0, 3.0], 'rect': (134, 17, 119, 182), 'size': 15969},
 {'labels': [8.0, 13.0], 'rect': (302, 97, 72, 283), 'size': 13904},
 {'labels': [2.0, 6.0], 'rect': (121, 0, 253, 226), 'size': 25143},
 {'labels': [7.0, 11.0, 9.0], 'rect': (0, 91, 183, 175), 'size': 14675},
 {'labels': [0.0, 1.0], 'rect': (0, 0, 144, 167), 'size': 19937},
 {'labels': [0.0, 1.0, 4.0, 5.0, 3.0], 'rect': (0, 0, 253, 199), 'size': 35906},
 {'labels': [14.0, 16.0], 'rect': (0, 253, 92, 191), 'size': 12201},
 {'labels': [14.0, 16.0, 7.0, 11.0, 9.0], 'rect': (0, 91, 183, 353), 'size': 26876},
 {'labels': [10.0, 15.0, 19.0], 'rect': (0, 171, 326, 278), 'size': 52532},
 {'labels': [10.0, 15.0, 19.0, 8.0, 13.0], 'rect': (0, 97, 374, 352), 'size': 66436},
 {'labels': [17.0, 18.0], 'rect': (84, 312, 100, 115), 'size': 6357},
 {'labels': [17.0, 18.0, 14.0, 16.0, 7.0, 11.0, 9.0], 'rect': (0, 91, 184, 353), 'size': 33233},
 {'labels': [17.0, 18.0, 14.0, 16.0, 7.0, 11.0, 9.0, 12.0], 'rect': (0, 91, 195, 353), 'size': 36101},
 {'labels': [17.0, 18.0, 14.0, 16.0, 7.0, 11.0, 9.0, 12.0, 2.0, 6.0], 'rect': (0, 0, 374, 444), 'size': 61244},
 {'labels': [17.0, 18.0, 14.0, 16.0, 7.0, 11.0, 9.0, 12.0, 2.0, 6.0, 10.0, 15.0, 19.0, 8.0, 13.0],
  'rect': (0, 0, 374, 449), 'size': 127680},
 {'labels': [17.0, 18.0, 14.0, 16.0, 7.0, 11.0, 9.0, 12.0, 2.0, 6.0, 10.0, 15.0, 19.0, 8.0, 13.0, 20.0],
  'rect': (0, 0, 374, 449), 'size': 132844},
 {'labels': [17.0, 18.0, 14.0, 16.0, 7.0, 11.0, 9.0, 12.0, 2.0, 6.0, 10.0, 15.0, 19.0, 8.0, 13.0, 20.0, 0.0, 1.0, 4.0, 5.0, 3.0],
  'rect': (0, 0, 374, 449), 'size': 168750}]

# bounding box를 시각화 하기

# opencv의 rectangle()을 이용하여 시각화
# rectangle()은 이미지와 좌상단 좌표, 우하단 좌표, box컬러색, 두께등을 인자로 입력하면 원본 이미지에 box를 그려줌. 

# bounding box 섹상 지정
green_rgb = (125, 255, 51)
# 노트북형태라 메모리 꼬일것 때문에 copy
img_rgb_copy = img_rgb.copy()
for rect in cand_rects:
    
    # tuple bounding box 좌표 찍기
    left = rect[0]
    top = rect[1]
    # rect[2], rect[3]은 절대적인 수치(너비와 높이)이므로 우하단 좌표를 구하기 위해 좌상단 좌표에 각각을 더함. 
    right = left + rect[2]
    bottom = top + rect[3]

    # bounding box 표시하기
    img_rgb_copy = cv2.rectangle(img_rgb_copy, (left, top), (right, bottom), color=green_rgb, thickness=2)
    
plt.figure(figsize=(8, 8))
plt.imshow(img_rgb_copy)
plt.show()

너무 많은 bounding box

# bounding box의 크기가 큰 후보만 추출

# 크기가 10000이상인 애만
cand_rects = [cand['rect'] for cand in regions if cand['size'] > 10000]

green_rgb = (125, 255, 51)
img_rgb_copy = img_rgb.copy()
for rect in cand_rects:
    
    left = rect[0]
    top = rect[1]
    # rect[2], rect[3]은 너비와 높이이므로 우하단 좌표를 구하기 위해 좌상단 좌표에 각각을 더함. 
    right = left + rect[2]
    bottom = top + rect[3]
    
    img_rgb_copy = cv2.rectangle(img_rgb_copy, (left, top), (right, bottom), color=green_rgb, thickness=2)
    
plt.figure(figsize=(8, 8))
plt.imshow(img_rgb_copy)
plt.show()

반응형
728x90
반응형

object detection은 localization과 같은 방법을 동일하게 적용하면 문제가 생길 수 있음

 

이미지안에 이미지 안에 비슷한 object가 여러개 있으면 Feature Extraction Layer를 통과한 feature map이 생성되고 그러면 사이즈도 줄어들고 추상화된다.

feature map에서 추출하고 regression을 통해서 발견한 이미지 특성을 다른 곳에서 또 발견하면 모델이 위치좌표를 찍는 것에 엉뚱한 좌표를 찍는 문제가 생긴다.

 

이미지 내에서 좌표를 찍는 것이 detection 영역의 문제의식이다.

특정영역을 한정하고 찾고, 한정하고 찾는 것이 정확도가 높았다. 위치를 옮기면서 찾는 것이 슬라이딩 방식이다.

 

1) sliding window

window를 이동시키면서 detection하는 방식

- 다양한 형태의 window를 슬라이딩

- window scale은 고정하고 scale을 변경한 여러 이미지를 사용하는 방식

: 초기 기법이고, 오브젝트 없는 영역도 무조건 슬라이딩 하여야 하며, 여러형태의 window와 여러 scale이미지를 스캔하여 검출해야해서, 수행시간이 오래 걸리고, 검출 성능이 상대적으로 낮음

- region proposal 기법 등장으로 활용도는 떨어졌지만 OD 발전의 기술토대 제공

 

 

2) Region Proposal

 

이미지는 밝기, 색상, 윤곽선으로 구분이 됨, 이 특성을 이용해서 object가 있을만한 후보영역을 찾는다

- selective search

차이점을 segmentation을 함

빠른 detection과 높은 recall 예측 성능을 동시에 만족하는 알고리즘

color, Texture, size, shape에 따라 유사한 region을 계층적 그룹핑 방법으로 계산함

-> 각 기준에 의해 조금이라도 건덕지가 있으면 영역을 나눠버리고 마스킹을 해서 후보군을 만듬

=> 그리고 비슷한 애들은 중복, 비슷한 특성 등 찾아서 계층적 그룹핑, 합쳐버림

경계선은 edge detector,

 

selective search는 최초에는 pixel intensity 기반한 graph-based segment기법에 따라 over segmentation을 수행

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

반응형
728x90
반응형

원본이미지에 1개의 object가 있는 경우

 

image classification과 똑같은 순서이고 

예를 들어 (224, 224) 라고 하고

VGG16과 같은 back bone 즉, Feature Extrator에 이미지를 입력하게 된다.

backbone의 역할은 이미지 내에서 중요한  피처를 추출하는 것이다.

 

그것을 통해서 최종적으로 feature map이 만들어짐

가령 feature map은 (7, 7)이 되어 size는 작아지는데, 대신 채널 수는 늘어나게 됨 (7, 7, 512) 

원본이미지 대비 축약된, 추상화된 이미지가 생성된다.

 

그리고 보통 img와 label을 maping시키고, 학습을 해놓음

그리고 softmax 함수로 class score를 매겼을 때 {car : 0.8, cat : 0.1, dog : 0.1 } 이러면 car이 된다.

 

3000개 img들로 각각 1000장씩 학습을 시키고

layer [ Dense layer, softmax 함수, fully connected ]로 학습시킴

=> img classification 원리

 

 

annotation 파일에 object, bounding box 좌표(xmin, ymin), (xmin, ymin)가 입력이 되어있다.

혹은 yolo는 center 좌표로 지정하기도 함. 

object localization 은 여기서 bounding box regression이 또 있음.

각각 label을 각각 좌표에 예측을 해봄

 

feature map은 map당 object가 딱 하나니깐 map에 이런 특성이 나오면 해당 bounding box regression을 적용한다.

그러면 잘나옴

 

그리고 object를 학습시키고, 가중치를 부여하면서, 여러 각도, 여러 이미지를 통해서 학습시킨다.

이 feature가 있으면 maping을 한다가 됨.

yolo의 경우 예측결과가 class confidence score이 있음

 

object detection으로 2개 이상의 object를 검출하면 거기에 문제가 생김

문제가 유사하게 적용했는데 각각 좌표가 이상한 곳에 찍힘

inference가 이상한 곳에 찍힘.

1000장의 이미지가 있으면 각각 학습시키면서 feature 특징은 학습했는데 feature 좌표를 획득하는데 문제가 생긴다.

예를 들어 중간값으로 좌표를 찍는 식으로

 

object가 있을 만한 위치를 먼저 찾아주고, 그 위치의 object를 탐색하는 방식이 보통 방식임

=> Region proposal

대충 가이드라인은 나눠줘야 번잡하지 않다.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

반응형
728x90
반응형

1. object detection의 주요 구성 요소

 

1) 영역 추정

Region Propsosal

bounding box를 예측

object 위치를 추정 : regression, bounding box 내 object가 뭔지 인지하는게 : classification

초기엔 딥러닝이 알아서 찾아주지 않을까 했는데, 예측 성능이 형편없더라

loss도 커지고, 성능도 낮았다.

object가 있을만한 위치를 제대로 알려줘야 한다. 정확히 매칭을 시켜주기 위해,

있을만한 영역에 대한 힌트를 주어야한다 => 영역 추정

 

2) Detection을 위한 Deep Learning 네트웍 구성

- Feature Extraction + Classification

: back born 

작은 object를 만듬, resNet

 

- Feature Pyramid Network 

: neck

만들어낸 object를 체계적으로 구성함

 

- Network Prediction + classification + regression

: head

object를 classification 함

 

3) etc

- IOU

- NMS : 어떤 처리를 하는지

- mAP

- Anchor Box

 

 

2. 왜 어려운가?

1) classification과 regression을 동시에 수행

보통은 단일식을 이용하는데, 동시에 수행하고, 동시에 성능, loss 가 좋아야 함.

 

2) 다양한 크기와 유형의 오브젝트가 섞임

크기가 크고 작고, 길고 뭉뚝하고, 다양한 오브젝트모양

feature map을 detect 해야함

 

3) 중요한 detect 시간

시간도 중요함, 예를 들어 cctv, 자율주행 등 알고리즘 딜레마가 있음

수행시간 vs 성능

 

4) 명확하지 않은 이미지

작은 object, background를 잘못 detecting 하는 경우

 

5) 데이터 세트의 부족

annotation을 만들어 줘야함, 생성하기가 상대적으로 어려움

 

 

 

반응형
728x90
반응형

object detection은 2012년을 기점으로 딥러닝 기반으로 발전을 했다.

1) classification 을 시도

이미지 내에서 분류

feature map을 만듬

 

2) Localization

하나의 이미지에서 하나의 object를 bounding box로 찾음

 

3) Object Detection

여러개의 object들의 위치를 bounding box로 지정해서 찾음

 

4) Segmentation

Detection 보다 더 발전된 형태로 pixel 레벨 Detection 수행

 

* Localization과 Detection은 해당 object위치를 bounding box로 찾고, bounding box 내 오브젝트를 판별한다

* Localization과 Detection은 bounding box regression(box의 좌표값을 예측)과 classification 두개의 문제가 합쳐져 있다.

* Localization에 비해 Detection은 두개 이상의 object를 이미지의 임의 위치에서 찾아야 해서 상대적으로  Localization보다 여러가지 문제가 있다.

 

 

Object Detection History

one-stage detector와 two-stage detector가 있는데

two-stage detector는 object를 미리 예측한 후에 디텍터를 실행한다.

성능이 좋지만 느림, 실시간 적용 힘듬

 

one-stage detector는 ssd, retina-net 등 성능은 강력했지만 inference가 떨어졌다. 그러나 yolo에서는 inference도 향상시킨 모델을 만든다.

반응형

+ Recent posts