본문 바로가기
컴퓨터비전

Region Proposal(영역 추정) - Selective Search 기법

by 차분한 공돌이 2024. 2. 14.

Region Proposal(영역 추정) 개념과 목적

앞서 살펴본 Sliding Window 기법은 모든 영역에 대해서 classification&bbox regression 을 실행하기 때문에 계산량이 많다는 문제가 발생한다. 

 

이를 해결(목적)하기 위해 "전체 이미지에서 Object가 있을 만한 후보 영역"을 찾은 후, 이 구역에 대해서만

classification&bbox regression 을 실행하는 방식(개념)이 Region Proposal(영역 추정) 이다.

 

이러한 Region Proposal의 대표 방법 중 하나가 Selective Search이다.

 

Selective Search 과정

1. 원본 이미지를 최초 segmentation 진행(Over Segmentation)

2. 개별 segment된 모든 부분들을 Bounding box로 만들어서 Region Proposal 리스트로 추가

3. 이전 단계의 segment된 부분들을 컬러, 무늬(Texture),크기(Size),형태(Shape)에 따라 유사도가 비슷한 segment들을 그룹핑함 ->1번 스탭 진행

4. 3반복하며 최종 Region Proposal 도출 후 해당 영역에 classification & bbox regression 진행

 

 

Selective Search 실습 및 시각화

실습은 구글 colab에서 실시

 

selective search 설치

 

!pip install selectivesearch

 

디렉토리 생성 및 이미지 가져와서 저장

 

!mkdir /content/data  #디렉토리 생성 
!wget -O /content/data/audrey01.jpg 
https://raw.githubusercontent.com/chulminkw/DLCV/master/data/image/audrey01.jpg #해당 이미지를 디렉토리 밑에 해당 이름으로 저장
 

cv2 이용하여 이미지 반환 후 matplotlib으로 시각화

 

import selectivesearch
import cv2 #이미지 및 비디오 처리, 컴퓨터 비전 작업 등을 위한 강력한 도구가 포함
import matplotlib.pyplot as plt
import os #운영 체제와 상호 작용하기 위한 함수를 제공
%matplotlib inline

### 오드리헵번 이미지를 cv2로 로드하고 matplotlib으로 시각화
img = cv2.imread('./data/audrey01.jpg') #지정된 경로의 이미지 파일이 읽혀져서 OpenCV에서 사용할 수 있는 형식인 Numpy 배열로 반환
img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) #cv2.imread()로 이미지 가져오면 BGR 형태이고, matplotlib으로 이미지 표시하려면 RGB형태여야 해서 바꿔주는 것

print('img shape:', img.shape)

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

 

 

selective search 이용하여 object가 있을만한 위치 구하기

 

import selectivesearch

#selectivesearch.selective_search()는 이미지의 Region Proposal정보를 반환
_, regions = selectivesearch.selective_search(img_rgb, scale=100, min_size=2000) #regions : object가 있을 만한 위치

print(type(regions), len(regions))  #41이 나왔다는 건 이미지에서 object 추정 구역이 41개 라는 것

 

 

regions 값 살펴보기

 

regions

 

 

[{'rect': (0, 0, 107, 167), 'size': 11166, 'labels': [0.0]},
 {'rect': (15, 0, 129, 110), 'size': 8771, 'labels': [1.0]},
 {'rect': (121, 0, 253, 133), 'size': 17442, 'labels': [2.0]},
 {'rect': (134, 17, 73, 62), 'size': 2713, 'labels': [3.0]},
 {'rect': (166, 23, 87, 176), 'size': 8639, 'labels': [4.0]},
 {'rect': (136, 53, 88, 121), 'size': 4617, 'labels': [5.0]},
 {'rect': (232, 79, 117, 147), 'size': 7701, 'labels': [6.0]},
 {'rect': (50, 91, 133, 123), 'size': 7042, 'labels': [7.0]},
 {'rect': (305, 97, 69, 283), 'size': 11373, 'labels': [8.0]},
 {'rect': (0, 161, 70, 46), 'size': 2363, 'labels': [9.0]},
 {'rect': (72, 171, 252, 222), 'size': 34467, 'labels': [10.0]},
 {'rect': (0, 181, 118, 85), 'size': 5270, 'labels': [11.0]},
 {'rect': (106, 210, 89, 101), 'size': 2868, 'labels': [12.0]},
 {'rect': (302, 228, 66, 96), 'size': 2531, 'labels': [13.0]},
 {'rect': (0, 253, 92, 134), 'size': 7207, 'labels': [14.0]},
 {'rect': (153, 270, 173, 179), 'size': 10360, 'labels': [15.0]},
 {'rect': (0, 305, 47, 139), 'size': 4994, 'labels': [16.0]},
 {'rect': (104, 312, 80, 71), 'size': 3595, 'labels': [17.0]},
 {'rect': (84, 360, 91, 67), 'size': 2762, 'labels': [18.0]},
 {'rect': (0, 362, 171, 87), 'size': 7705, 'labels': [19.0]},
 {'rect': (297, 364, 77, 85), 'size': 5164, 'labels': [20.0]},
 {'rect': (0, 91, 183, 175), 'size': 12312, 'labels': [7.0, 11.0]},

 

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

<개별 딕셔너리내 KEY값별 의미>

rect 키값은 x,y 시작 좌표와 너비, 높이 값을 가지며 이 값이 Detected Object 후보를 나타내는 Bounding box임.
size는 segment로 select된 Object의 크기
labels는 해당 rect로 지정된 Bounding Box내에 있는 오브젝트들의 고유 ID

 

{'rect': (0, 91, 183, 175), 'size': 12312, 'labels': [7.0, 11.0]} : 이 바운딩 박스 안에 object가 2개 포함됨을 의미

 

bounding box를 이미지 위에 시각화 하기

 

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

green_rgb = (125, 255, 51) #bbox의 색깔   
img_rgb_copy = img_rgb.copy() #메모리 꼬이는 거 방지   
for rect in cand_rects:                     
    #만약 rect : (0,0,107,167) 이라면
    left = rect[0] #0  
    top = rect[1]  #0      
    # rect[2], rect[3]은 너비와 높이이므로 우하단 좌표를 구하기 위해 좌상단 좌표에 각각을 더함.
    right = left + rect[2] #0 + 107
    bottom = top + rect[3] #0 + 167    

    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()

 

 

 

크기가  10000 이상인 bounding box 선별하여 시각화

 

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()

 

 

 

bounding box의 개수가 줄어들었다.

 

Reference