์ ์ ์ด ์์ด์ ์ด์ด์ ์ฐ๋๊ฑธ ๊น๋จน์๋ค์.. ์ด์ฌํ ์จ๋ณด๊ฒ ์ต๋๋ค ใ
# ํ์ฌ ๋๋ ํ ๋ฆฌ๋ /content์ด๋ฉฐ ์ด ๋๋ ํ ๋ฆฌ๋ฅผ ๊ธฐ์ค์ผ๋ก ์ค์ต์ฝ๋์ ๋ฐ์ดํฐ๋ฅผ ๋ค์ด๋ก๋ ํฉ๋๋ค.
!pwd
!rm -rf DLCV
!git clone https://github.com/chulminkw/DLCV.git
# DLCV ๋๋ ํ ๋ฆฌ๊ฐ Download๋๊ณ DLCV ๋ฐ์ Detection๊ณผ Segmentation ๋๋ ํ ๋ฆฌ๊ฐ ์๋ ๊ฒ์ ํ์ธ
!ls -lia
!ls -lia DLCV
OpenCV Darknet YOLO๋ฅผ ์ด์ฉํ์ฌ image & ์์ Object Detection
- ์ฌ๊ธฐ์ YOLO์ tiny-yolo๋ฅผ ์ด์ฉํ์ฌ Object Detection์ ํด๋ณด๊ฒ ์ต๋๋ค.
import cv2
import matplotlib.pyplot as plt
import os
%matplotlib inline
# ์ฝ๋ฉ ๋ฒ์ ์ default_dir ์ /content/DLCV๋ก ์ง์ ํ๊ณ os.path.join()์ผ๋ก ์์ธ ํ์ผ/๋๋ ํ ๋ฆฌ๋ฅผ ์ง์ ํฉ๋๋ค.
default_dir = '/content/DLCV'
img = cv2.imread(os.path.join(default_dir, 'data/image/beatles01.jpg'))
img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
print('image shape:', img.shape)
plt.figure(figsize=(12, 12))
plt.imshow(img_rgb)
image shape: (633, 806, 3)
<matplotlib.image.AxesImage at 0x7cb8db20ff10>
๋ฐ์ดํฐ์ ์ ํ์ธํ, Darknet Yolo์ฌ์ดํธ์์ coco๋ก ํ์ต๋ Inference๋ชจ๋ธ์ ํ๊ฒฝํ์ผ์ ๋ค์ด๋ก๋ ๋ฐ์ ํ ์ด๋ฅผ ์ด์ฉํด OpenCV์์ Inference ๋ชจ๋ธ์ ์์ฑํด ๋ณด๊ฒ ์ต๋๋ค.
- https://pjreddie.com/darknet/yolo/ ์ ๋ค์ด๋ก๋ URL ์์.
- pretrained ๋ชจ๋ธ์ wget https://pjreddie.com/media/files/yolov3.weights ์์ ๋ค์ด๋ก๋
- pretrained ๋ชจ๋ธ์ ์ํ ํ๊ฒฝ ํ์ผ์ https://raw.githubusercontent.com/pjreddie/darknet/master/cfg/yolov3.cfg ์์ ๋ค์ด๋ก๋
- wget https://github.com/pjreddie/darknet/blob/master/cfg/yolov3.cfg?raw=true -O ./yolov3.cfg
- readNetFromDarknet(configํ์ผ, weightํ์ผ)๋ก configํ์ผ ์ธ์๊ฐ weightํ์ผ ์ธ์๋ณด๋ค ๋จผ์ ์ด. ์ฃผ์ ํ์.
- tiny yolo์ pretrained๋ weightํ์ผ์ wget https://pjreddie.com/media/files/yolov3-tiny.weights ์์ download ๊ฐ๋ฅ.
- config ํ์ผ์ wget https://github.com/pjreddie/darknet/blob/master/cfg/yolov3-tiny.cfg?raw=true -O ./yolov3-tiny.cfg ๋ก ๋ค์ด๋ก๋.
!rm -rf /content/DLCV/Detection/yolo//pretrained
!mkdir /content/DLCV/Detection/yolo/pretrained
# pretrained ๋๋ ํ ๋ฆฌ๊ฐ ์์ฑ๋์๋์ง ํ์ธ ํฉ๋๋ค.
%cd /content/DLCV/Detection/yolo
!ls
### coco ๋ฐ์ดํฐ ์ธํธ๋ก pretrained ๋ yolo weight ํ์ผ๊ณผ config ํ์ผ ๋ค์ด๋ก๋
%cd /content/DLCV/Detection/yolo/pretrained
!echo "##### downloading pretrained yolo/tiny-yolo weight file and config file"
!wget https://pjreddie.com/media/files/yolov3.weights
!wget https://github.com/pjreddie/darknet/blob/master/cfg/yolov3.cfg?raw=true -O ./yolov3.cfg
!wget https://pjreddie.com/media/files/yolov3-tiny.weights
!wget wget https://github.com/pjreddie/darknet/blob/master/cfg/yolov3-tiny.cfg?raw=true -O ./yolov3-tiny.cfg
!echo "##### check out pretrained yolo files"
!ls /content/DLCV/Detection/yolo/pretrained
readNetFromDarknet(config weightํ์ผ)์ ์ด์ฉํ์ฌ yolo inference network ๋ชจ๋ธ๋ก๋ฉ
import os
#CUR_DIR = os.path.abspath('.')
# ์ฝ๋ฉ ๋ฒ์ ์ ์๋ ์ฝ๋ ์ฌ์ฉ
CUR_DIR = '/content/DLCV/Detection/yolo'
weights_path = os.path.join(CUR_DIR, 'pretrained/yolov3.weights')
config_path = os.path.join(CUR_DIR, 'pretrained/yolov3.cfg')
#config ํ์ผ ์ธ์๊ฐ ๋จผ์ ์ด.
cv_net_yolo = cv2.dnn.readNetFromDarknet(config_path, weights_path)
COCO Class id์ Class๋ช Mapping
labels_to_names_seq๋ class id๊ฐ 0~79๊น์ง์ ๋๋ค.
- OpenCV DNN Darknet YOLO Model์ Loadํฉ๋๋ค.
labels_to_names_seq = {0:'person',1:'bicycle',2:'car',3:'motorbike',4:'aeroplane',5:'bus',6:'train',7:'truck',8:'boat',9:'traffic light',10:'fire hydrant',
11:'stop sign',12:'parking meter',13:'bench',14:'bird',15:'cat',16:'dog',17:'horse',18:'sheep',19:'cow',20:'elephant',
21:'bear',22:'zebra',23:'giraffe',24:'backpack',25:'umbrella',26:'handbag',27:'tie',28:'suitcase',29:'frisbee',30:'skis',
31:'snowboard',32:'sports ball',33:'kite',34:'baseball bat',35:'baseball glove',36:'skateboard',37:'surfboard',38:'tennis racket',39:'bottle',40:'wine glass',
41:'cup',42:'fork',43:'knife',44:'spoon',45:'bowl',46:'banana',47:'apple',48:'sandwich',49:'orange',50:'broccoli',
51:'carrot',52:'hot dog',53:'pizza',54:'donut',55:'cake',56:'chair',57:'sofa',58:'pottedplant',59:'bed',60:'diningtable',
61:'toilet',62:'tvmonitor',63:'laptop',64:'mouse',65:'remote',66:'keyboard',67:'cell phone',68:'microwave',69:'oven',70:'toaster',
71:'sink',72:'refrigerator',73:'book',74:'clock',75:'vase',76:'scissors',77:'teddy bear',78:'hair drier',79:'toothbrush' }
labels_to_names = {1:'person',2:'bicycle',3:'car',4:'motorcycle',5:'airplane',6:'bus',7:'train',8:'truck',9:'boat',10:'traffic light',
11:'fire hydrant',12:'street sign',13:'stop sign',14:'parking meter',15:'bench',16:'bird',17:'cat',18:'dog',19:'horse',20:'sheep',
21:'cow',22:'elephant',23:'bear',24:'zebra',25:'giraffe',26:'hat',27:'backpack',28:'umbrella',29:'shoe',30:'eye glasses',
31:'handbag',32:'tie',33:'suitcase',34:'frisbee',35:'skis',36:'snowboard',37:'sports ball',38:'kite',39:'baseball bat',40:'baseball glove',
41:'skateboard',42:'surfboard',43:'tennis racket',44:'bottle',45:'plate',46:'wine glass',47:'cup',48:'fork',49:'knife',50:'spoon',
51:'bowl',52:'banana',53:'apple',54:'sandwich',55:'orange',56:'broccoli',57:'carrot',58:'hot dog',59:'pizza',60:'donut',
61:'cake',62:'chair',63:'couch',64:'potted plant',65:'bed',66:'mirror',67:'dining table',68:'window',69:'desk',70:'toilet',
71:'door',72:'tv',73:'laptop',74:'mouse',75:'remote',76:'keyboard',77:'cell phone',78:'microwave',79:'oven',80:'toaster',
81:'sink',82:'refrigerator',83:'blender',84:'book',85:'clock',86:'vase',87:'scissors',88:'teddy bear',89:'hair drier',90:'toothbrush',
91:'hair brush'}
3๊ฐ์ Scale Output Layer์์ ๊ฒฐ๊ณผ ๋ฐ์ดํฐ ์ถ์ถ
# YOLO ๋คํธ์ํฌ์์ ๋ชจ๋ ๋ ์ด์ด ์ด๋ฆ์ ๊ฐ์ ธ์ด
layer_names = cv_net_yolo.getLayerNames()
# ์ถ๋ ฅ ๋ ์ด์ด์ ์ธ๋ฑ์ค๋ฅผ ๊ธฐ๋ฐ์ผ๋ก YOLOv3์ ์ถ๋ ฅ ๋ ์ด์ด ์ด๋ฆ์ ์ถ์ถ
outlayer_names = [layer_names[i - 1] for i in cv_net_yolo.getUnconnectedOutLayers()]
# ์ถ๋ ฅ ๋ ์ด์ด ์ด๋ฆ์ ์ถ๋ ฅ (13x13, 26x26, 52x52 grid์์ ํ์ง๋ ๊ฒฐ๊ณผ๋ฅผ ์ ๊ณตํ๋ ๋ ์ด์ด๋ค)
print('output_layer name:', outlayer_names)
# ๋ก๋ฉ๋ YOLOv3 ๋ชจ๋ธ์ 416x416 ํฌ๊ธฐ๋ฅผ ์
๋ ฅ์ผ๋ก ์ฌ์ฉํจ.
# ์ด๋ฏธ์ง๋ฅผ 416x416์ผ๋ก ํฌ๊ธฐ ๋ณ๊ฒฝํ๊ณ BGR ์ฑ๋์ RGB๋ก ๋ณํํ์ฌ ๋คํธ์ํฌ์ ์
๋ ฅํ๊ธฐ ์ํ blob ์์ฑ
cv_net_yolo.setInput(cv2.dnn.blobFromImage(
img, # ์๋ณธ ์ด๋ฏธ์ง
scalefactor=1/255.0, # ํฝ์
๊ฐ์ 0~1 ๋ฒ์๋ก ์ ๊ทํ (255๋ก ๋๋)
size=(416, 416), # YOLOv3์ ์
๋ ฅ ํฌ๊ธฐ (416x416)
swapRB=True, # BGR ์ฑ๋์ RGB๋ก ๋ณํ
crop=False # ์ด๋ฏธ์ง๋ฅผ ์๋ฅด์ง ์๊ณ ๊ทธ๋๋ก ์ฌ์ฉ
))
# YOLO ๋คํธ์ํฌ์์ ์ง์ ํ ์ถ๋ ฅ ๋ ์ด์ด๋ค์์ ๊ฐ์ฒด ํ์ง๋ฅผ ์ํํ๊ณ ๊ฒฐ๊ณผ๋ฅผ ๋ฐํ
cv_outs = cv_net_yolo.forward(outlayer_names)
# ํ์ง๋ ๊ฐ์ฒด์ ๊ฒฝ๊ณ ์์(Bounding Box)๋ฅผ ๊ทธ๋ฆฌ๊ธฐ ์ํ ์์ (๋
น์)
green_color = (0, 255, 0)
# ๊ฒฝ๊ณ ์์ ์์ ํ์๋ ์บก์
(๊ฐ์ฒด ์ด๋ฆ ๋ฐ ํ๋ฅ )์ ์ํ ๊ธ์์ (๋นจ๊ฐ์)
red_color = (0, 0, 255)
# Result: output_layer name: ['yolo_82', 'yolo_94', 'yolo_106']
YOLO ๋คํธ์ํฌ์์ ์ถ๋ ฅ ๋ ์ด์ด ์ด๋ฆ์ ์ถ์ถ
- cv_net_yolo.getLayerNames(): ๋คํธ์ํฌ์ ๋ชจ๋ ๋ ์ด์ด ์ด๋ฆ์ ๊ฐ์ ธ์ต๋๋ค. YOLOv3 ๋ชจ๋ธ์ ์ฌ๋ฌ ๋ ์ด์ด๋ก ๊ตฌ์ฑ๋์ด ์๊ณ , ๊ฐ ๋ ์ด์ด๋ CNN(Convolutional Neural Network) ๊ณ์ธต์ ๋๋ค.
- cv_net_yolo.getUnconnectedOutLayers(): ๋คํธ์ํฌ์์ ์ถ๋ ฅ ๋ ์ด์ด์ ์ธ๋ฑ์ค๋ฅผ ๋ฐํํฉ๋๋ค. YOLOv3์์๋ 3๊ฐ์ ์ถ๋ ฅ ๋ ์ด์ด(13x13, 26x26, 52x52 grid)๊ฐ ์กด์ฌํ๋ฉฐ, ์ด ๋ ์ด์ด๋ค์์ ๊ฐ์ฒด ํ์ง๋ฅผ ์ํํฉ๋๋ค.
- outlayer_names: YOLO ๋ชจ๋ธ์์ ์ถ๋ ฅ ๋ ์ด์ด๋ค๋ง ์ถ์ถํ ๋ฆฌ์คํธ์ ๋๋ค. ํ์ง ๊ฒฐ๊ณผ๋ฅผ ์ด ๋ ์ด์ด๋ค์์ ์ป์ต๋๋ค.
YOLOv3 ๋ชจ๋ธ์ ์ ๋ ฅ ์ด๋ฏธ์ง ์ค์
cv2.dnn.blobFromImage: ์ด๋ฏธ์ง๋ฅผ ๋คํธ์ํฌ์ ์ ๋ ฅํ ์ ์๋ ํ์(blob)์ผ๋ก ๋ณํํ๋ ํจ์์ ๋๋ค. ์ด ๊ณผ์ ์์ ์ฌ๋ฌ ์ค์ ์ด ์ด๋ฃจ์ด์ง๋๋ค:
- scalefactor=1/255.0: ์ด๋ฏธ์ง์ ํฝ์ ๊ฐ์ 255๋ก ๋๋์ด 0~1 ๋ฒ์๋ก ์ ๊ทํํฉ๋๋ค. ์ด ๊ณผ์ ์ ํตํด YOLO ๋ชจ๋ธ์ด ํ์ตํ ๋ฐ์ดํฐ์ ์ ๋ ฅ๊ฐ์ ๋ง์ถฅ๋๋ค.
- size=(416, 416): ์ ๋ ฅ ์ด๋ฏธ์ง์ ํฌ๊ธฐ๋ฅผ 416x416 ํฝ์ ๋ก ๋ฆฌ์ฌ์ด์ฆํฉ๋๋ค. YOLOv3๋ 416x416 ํฌ๊ธฐ์ ์ด๋ฏธ์ง๋ฅผ ํ์ตํ๊ธฐ ๋๋ฌธ์, ์ ๋ ฅ ํฌ๊ธฐ๋ฅผ ๋ง์ถ์ด์ผ ํฉ๋๋ค.
- swapRB=True: OpenCV๋ ๊ธฐ๋ณธ์ ์ผ๋ก BGR ํ์์ ์ด๋ฏธ์ง๋ฅผ ์ฌ์ฉํ์ง๋ง, YOLO๋ RGB ํ์์ ์ฌ์ฉํฉ๋๋ค. ๋ฐ๋ผ์ BGR์์ RGB๋ก ์ฑ๋์ ๋ณํํฉ๋๋ค.
- crop=False: ์ด๋ฏธ์ง๋ฅผ ์๋ฅด์ง ์๊ณ ๊ทธ๋๋ก ์ฌ์ฉํฉ๋๋ค.
Object Detection ์ํ
- cv_net_yolo.forward(outlayer_names): YOLO ๋คํธ์ํฌ์ ์ถ๋ ฅ ๋ ์ด์ด์์ ๊ฐ์ฒด ํ์ง ๊ฒฐ๊ณผ๋ฅผ ์ป์ต๋๋ค. outlayer_names๋ ์์์ ๊ตฌํ ์ถ๋ ฅ ๋ ์ด์ด๋ค์ด๋ฉฐ, ์ฌ๊ธฐ์ ๊ฐ ๊ฐ์ฒด์ ์์น, ํฌ๊ธฐ, ๊ทธ๋ฆฌ๊ณ ๊ฐ์ฒด ๋ถ๋ฅ์ ๋ํ ์ ๋ณด๋ฅผ ์ถ์ถํฉ๋๋ค.
- cv_outs: YOLOv3๊ฐ ์ถ์ถํ ๊ฐ์ฒด ํ์ง ๊ฒฐ๊ณผ๊ฐ ์ ์ฅ๋ฉ๋๋ค.
output_layer name: ['yolo_82', 'yolo_94', 'yolo_106']
3๊ฐ์ Scale Output Layer์์ Object Detection ์ ๋ณด๋ฅผ ๋ชจ๋ ์์ง
Center, Width, Height ์ขํ๋ ๋ชจ๋ ์ข์๋จ, ์ฐํ๋จ ์ขํ๋ก ๋ณ๊ฒฝํฉ๋๋ค.
import numpy as np
# ์๋ณธ ์ด๋ฏธ์ง๋ฅผ YOLO ๋คํธ์ํฌ์ ์
๋ ฅํ ๋๋ (416, 416)์ผ๋ก ํฌ๊ธฐ๋ฅผ ์กฐ์ ํจ.
# ๋คํธ์ํฌ๊ฐ ์์ธกํ bounding box ์ขํ๋ ์ด ํฌ๊ธฐ ๊ธฐ์ค์ผ๋ก ๊ณ์ฐ๋๋ฏ๋ก, ์๋ณธ ์ด๋ฏธ์ง ํฌ๊ธฐ์ ๋ง์ถ๊ธฐ ์ํด ์๋ณธ ์ด๋ฏธ์ง์ shape ์ ๋ณด ํ์.
rows = img.shape[0] # ์๋ณธ ์ด๋ฏธ์ง์ ๋์ด
cols = img.shape[1] # ์๋ณธ ์ด๋ฏธ์ง์ ๋๋น
# Confidence(์ ๋ขฐ๋)์ NMS(Non-Maximum Suppression) ์๊ณ๊ฐ ์ค์
conf_threshold = 0.5 # confidence threshold (ํ์ง๋ ๊ฐ์ฒด์ ์ ๋ขฐ๋ ์ต์๊ฐ)
nms_threshold = 0.4 # Non-Maximum Suppression threshold (์ค๋ณต๋ ๋ฐ์ค๋ฅผ ์ ๊ฑฐํ๊ธฐ ์ํ ์๊ณ๊ฐ)
# ํ์ง๋ ๊ฐ์ฒด์ ๋ํ ์ ๋ณด๋ฅผ ์ ์ฅํ ๋ฆฌ์คํธ
class_ids = [] # ํด๋์ค ID๋ฅผ ์ ์ฅํ๋ ๋ฆฌ์คํธ
confidences = [] # ์ ๋ขฐ๋๋ฅผ ์ ์ฅํ๋ ๋ฆฌ์คํธ
boxes = [] # bounding box ์ขํ๋ฅผ ์ ์ฅํ๋ ๋ฆฌ์คํธ
# YOLO ๋คํธ์ํฌ์์ ๋ฐํ๋ 3๊ฐ์ output layer์ ๋ํด ํ์ง๋ ๊ฐ์ฒด ์ ๋ณด๋ฅผ ์ถ์ถํ๊ณ ์๊ฐํ
for ix, output in enumerate(cv_outs):
print('output shape:', output.shape) # ๊ฐ output layer์ shape ์ถ๋ ฅ (ํ์ง๋ ๊ฐ์ฒด์ ์์ ์์ฑ ํฌ๊ธฐ)
# ๊ฐ output layer์์ ํ์ง๋ ๊ฐ์ฒด๋ณ๋ก ์ ๋ณด๋ฅผ ์ถ์ถ
for jx, detection in enumerate(output):
# detection ๋ฐฐ์ด์ 6๋ฒ์งธ ์์๋ถํฐ๋ ํด๋์ค๋ณ ์ ์(class score)๋ค์ด ์ ์ฅ๋์ด ์์ (์์ 5๊ฐ๋ bounding box ์ ๋ณด)
scores = detection[5:]
# ๊ฐ์ฅ ๋์ ์ ์๋ฅผ ๊ฐ์ง ์ธ๋ฑ์ค(class ID)๋ฅผ ์ฐพ์
class_id = np.argmax(scores)
# ํด๋น ํด๋์ค์ confidence(์ ๋ขฐ๋) ๊ฐ์ ์ถ์ถ
confidence = scores[class_id]
# confidence๊ฐ conf_threshold๋ณด๋ค ๋์ ๊ฐ์ฒด๋ง ์ฒ๋ฆฌ (ํ์ง ์ ๋ขฐ๋๊ฐ ๋ฎ์ ๊ฐ์ฒด๋ ๋ฌด์)
if confidence > conf_threshold:
print('ix:', ix, 'jx:', jx, 'class_id', class_id, 'confidence:', confidence)
# detection ๋ฐฐ์ด์ ์๋ถ๋ถ์ ์ค์ฌ ์ขํ(x, y)์ ๋๋น(width), ๋์ด(height)๋ฅผ ํฌํจํจ
# YOLO๋ ์ข์๋จ์ด๋ ์ฐํ๋จ ์ขํ๊ฐ ์๋๋ผ ์ค์ฌ ์ขํ์ ํฌ๊ธฐ๋ฅผ ๋ฐํํจ
# ์ด ๊ฐ์ ์๋ณธ ์ด๋ฏธ์ง์ ๋ง๊ฒ ๋น์จ๋ก ๋ณํํ์ฌ ์ข์๋จ๊ณผ ์ฐํ๋จ ์ขํ๋ฅผ ๊ณ์ฐ
center_x = int(detection[0] * cols) # ํ์ง๋ ๊ฐ์ฒด์ ์ค์ฌ x ์ขํ (์๋ณธ ์ด๋ฏธ์ง ํฌ๊ธฐ์ ๋ง๊ฒ ์กฐ์ )
center_y = int(detection[1] * rows) # ํ์ง๋ ๊ฐ์ฒด์ ์ค์ฌ y ์ขํ (์๋ณธ ์ด๋ฏธ์ง ํฌ๊ธฐ์ ๋ง๊ฒ ์กฐ์ )
width = int(detection[2] * cols) # ํ์ง๋ ๊ฐ์ฒด์ ๋๋น (์๋ณธ ์ด๋ฏธ์ง ํฌ๊ธฐ์ ๋ง๊ฒ ์กฐ์ )
height = int(detection[3] * rows) # ํ์ง๋ ๊ฐ์ฒด์ ๋์ด (์๋ณธ ์ด๋ฏธ์ง ํฌ๊ธฐ์ ๋ง๊ฒ ์กฐ์ )
# ์ข์๋จ ์ขํ ๊ณ์ฐ (์ค์ฌ ์ขํ์์ ๋๋น์ ๋์ด์ ์ ๋ฐ์ ๋นผ์ ๊ตฌํจ)
left = int(center_x - width / 2)
top = int(center_y - height / 2)
# ํ์ง๋ ๊ฐ์ฒด์ class ID, confidence, bounding box ์ขํ ์ ๋ณด๋ฅผ ์ ์ฅ
class_ids.append(class_id) # ํ์ง๋ ๊ฐ์ฒด์ ํด๋์ค ID ์ ์ฅ
confidences.append(float(confidence)) # ํ์ง๋ ๊ฐ์ฒด์ ์ ๋ขฐ๋ ์ ์ฅ
boxes.append([left, top, width, height]) # ํ์ง๋ ๊ฐ์ฒด์ bounding box ์ขํ ์ ์ฅ
output shape: (507, 85) ix: 0 jx: 316 class_id 0 confidence: 0.8499539 ix: 0 jx: 319 class_id 0 confidence: 0.9317015 ix: 0 jx: 325 class_id 0 confidence: 0.7301026 ix: 0 jx: 328 class_id 0 confidence: 0.9623244 ix: 0 jx: 334 class_id 0 confidence: 0.9984485 ix: 0 jx: 337 class_id 0 confidence: 0.9833524 ix: 0 jx: 343 class_id 0 confidence: 0.9978433 ix: 0 jx: 346 class_id 0 confidence: 0.63752526 output shape: (2028, 85) ix: 1 jx: 831 class_id 2 confidence: 0.81699777 ix: 1 jx: 832 class_id 2 confidence: 0.7153828 ix: 1 jx: 877 class_id 2 confidence: 0.78542227 ix: 1 jx: 955 class_id 2 confidence: 0.8472696 ix: 1 jx: 1199 class_id 0 confidence: 0.7259762 ix: 1 jx: 1202 class_id 0 confidence: 0.9635838 ix: 1 jx: 1259 class_id 0 confidence: 0.97018635 ix: 1 jx: 1262 class_id 0 confidence: 0.9877816 ix: 1 jx: 1277 class_id 0 confidence: 0.9924558 ix: 1 jx: 1280 class_id 0 confidence: 0.99840033 ix: 1 jx: 1295 class_id 0 confidence: 0.6916557 ix: 1 jx: 1313 class_id 0 confidence: 0.9205802 ix: 1 jx: 1337 class_id 0 confidence: 0.5387825 ix: 1 jx: 1340 class_id 0 confidence: 0.6424068 ix: 1 jx: 1373 class_id 0 confidence: 0.57844293 ix: 1 jx: 1391 class_id 0 confidence: 0.89902174 output shape: (8112, 85) ix: 2 jx: 2883 class_id 2 confidence: 0.9077373 ix: 2 jx: 2886 class_id 2 confidence: 0.63324577 ix: 2 jx: 2892 class_id 2 confidence: 0.6575013 ix: 2 jx: 3039 class_id 2 confidence: 0.8036038 ix: 2 jx: 3048 class_id 2 confidence: 0.94120145 ix: 2 jx: 3051 class_id 2 confidence: 0.61540514 ix: 2 jx: 3184 class_id 2 confidence: 0.95041007 ix: 2 jx: 3185 class_id 2 confidence: 0.8492525 ix: 2 jx: 3214 class_id 2 confidence: 0.9064125 ix: 2 jx: 3373 class_id 2 confidence: 0.68997973 ix: 2 jx: 3394 class_id 0 confidence: 0.7640699
- scores = detection[5:]: detection ๋ฐฐ์ด์์ ์ฒซ 5๊ฐ ์์๋ bounding box ์ ๋ณด์ด๊ณ , ๊ทธ ์ดํ๊ฐ ํด๋์ค๋ณ ์ ์์ ๋๋ค.
- CoCO Dataset์ผ๋ก Pre-Trained๋ Model์์ BoundingBox ์ ๋ณด๋ฅผ ์ถ์ถ์
- Bounding Box ์ ๋ณด๋ฅผ 4๊ฐ์ Box ์ขํ, 1๊ฐ์ Object Score, ๊ทธ๋ฆฌ๊ณ 80๊ฐ์ Class score(Coco๋ 80๊ฐ์ Object Category์)๋ก ๊ตฌ์ฑ๋ ์ด 85๊ฐ์ ์ ๋ณด ๊ตฌ์ฑ์์ ์ ๋ณด ์ถ์ถ์ด ํ์ํฉ๋๋ค.
- Class id์ class score๋ ์ด 80๊ฐ vector์์ ๊ฐ์ฅ ๋์ ๊ฐ์ ๊ฐ์ง๋ ์์น ์ธ๋ฑ์ค์ ๊ทธ ๊ฐ์ ๋๋ค.
NMS๋ฅผ ์ด์ฉํ์ฌ ๊ฐ Output layer์์ Detected๋ Object์ ๊ฒน์น๋ Bounding box ์ ์ธ
NMS Filtering ์ด๋ผ๊ณ ๋ ํฉ๋๋ค.
conf_threshold = 0.5
nms_threshold = 0.4
idxs = cv2.dnn.NMSBoxes(boxes, confidences, conf_threshold, nms_threshold)
print(idxs)
# Result: [ 4 17 6 15 30 28 24 32 11 8 34 33 25 29]
- NMSBoxes๋ ์์์ ๊ตฌํ list boxes ์ ๋๋ค.
NMS๋ก ์ต์ข filtering๋ idxs๋ฅผ ์ด์ฉํ์ฌ boxes, classes, confidences์์ ํด๋นํ๋ Object์ ๋ณด ์ถ์ถ & ์๊ฐํ
# ์๋ณธ ์ด๋ฏธ์ง๋ฅผ ๋ณต์ฌํ์ฌ ์ฌ๊ฐํ์ ๊ทธ๋ฆด ์ด๋ฏธ์ง ๋ฐฐ์ด ์์ฑ
draw_img = img.copy()
# NMS๋ก ํํฐ๋ง๋ ๊ฐ์ฒด๊ฐ ์์ ๊ฒฝ์ฐ์๋ง ์ฒ๋ฆฌ
if len(idxs) > 0:
# ํํฐ๋ง๋ ๊ฐ์ฒด๋ค์ ์ธ๋ฑ์ค๋ฅผ ํ๋์ฉ ์ฒ๋ฆฌ
for i in idxs.flatten():
box = boxes[i] # bounding box ์ขํ ์ถ์ถ
left = box[0] # ์ข์๋จ x ์ขํ
top = box[1] # ์ข์๋จ y ์ขํ
width = box[2] # ๋ฐ์ค์ ๋๋น
height = box[3] # ๋ฐ์ค์ ๋์ด
# ํด๋์ค๋ช
๊ณผ ์ ๋ขฐ๋๋ฅผ ํ
์คํธ๋ก ์์ฑ
caption = "{}: {:.4f}".format(labels_to_names_seq[class_ids[i]], confidences[i])
# bounding box ๊ทธ๋ฆฌ๊ธฐ
cv2.rectangle(draw_img, (int(left), int(top)), (int(left + width), int(top + height)), color=green_color, thickness=2)
# ํด๋์ค๋ช
๊ณผ ์ ๋ขฐ๋ ํ
์คํธ ๊ทธ๋ฆฌ๊ธฐ
cv2.putText(draw_img, caption, (int(left), int(top - 5)), cv2.FONT_HERSHEY_SIMPLEX, 0.5, red_color, 1)
# ํด๋์ค๋ช
๊ณผ ์ ๋ขฐ๋๋ฅผ ์ฝ์์ ์ถ๋ ฅ
print(caption)
# BGR ์ด๋ฏธ์ง๋ฅผ RGB๋ก ๋ณํํ์ฌ ์๊ฐํ
img_rgb = cv2.cvtColor(draw_img, cv2.COLOR_BGR2RGB)
# ์ด๋ฏธ์ง ํฌ๊ธฐ์ ์๊ฐํ
plt.figure(figsize=(12, 12))
plt.imshow(img_rgb)
person: 0.9984
person: 0.9984
person: 0.9978
person: 0.9878
car: 0.9504
car: 0.9412
car: 0.9077
car: 0.9064
car: 0.8473
car: 0.8170
person: 0.7641
car: 0.6900
car: 0.6332
car: 0.6154
<matplotlib.image.AxesImage at 0x7c3250be2f20>
์ด๋ฏธ์ง ๋ณต์ฌ ๋ฐ ์ด๊ธฐํ
- draw_img = img.copy()๋ ์๋ณธ ์ด๋ฏธ์ง๋ฅผ ๋ณต์ฌํ์ฌ ์๋ก์ด ๋ฐฐ์ด์ ์์ฑํฉ๋๋ค. OpenCV์ rectangle() ํจ์๋ ์ธ์๋ก ๋๊ฒจ์ค ์ด๋ฏธ์ง์ ๋ฐ๋ก ์ฌ๊ฐํ์ ๊ทธ๋ฆฌ๊ธฐ ๋๋ฌธ์, ์๋ณธ ์ด๋ฏธ์ง๋ฅผ ๋ณด์กดํ๋ ค๊ณ ๋ณต์ฌ๋ณธ์ ๋ง๋ญ๋๋ค.
NMS ํํฐ๋ง๋ ๊ฐ์ฒด ์ฒ๋ฆฌ
- Non-Maximum Suppression(NMS)์ ์ฌ๋ฌ ๊ฐ์ฒด ํ์ง ๊ฒฐ๊ณผ ์ค์์ ๊ฐ์ฅ ์ ๋ขฐ๋๊ฐ ๋์ ๊ฒ์ ์ ํํ๊ณ , ๋ค๋ฅธ ์ค๋ณต๋ bounding box๋ฅผ ์ ๊ฑฐํ๋ ๊ธฐ๋ฒ์ ๋๋ค. NMS ๊ฒฐ๊ณผ๋ก idxs ๋ฆฌ์คํธ์๋ ํํฐ๋ง๋ ๊ฐ์ฒด๋ค์ ์ธ๋ฑ์ค๋ง ๋จ์ต๋๋ค.
- if len(idxs) > 0:๋ ํ์ง๋ ๊ฐ์ฒด๊ฐ ์๋ ๊ฒฝ์ฐ์๋ง ์ฒ๋ฆฌํ๋๋ก ํฉ๋๋ค.
Bounding Box์ ํด๋์ค๋ช , ์ ๋ขฐ๋ ํ์
- for i in idxs.flatten():๋ ํํฐ๋ง๋ ์ธ๋ฑ์ค๋ฅผ ํ๋์ฉ ๋ฐ๋ณต ์ฒ๋ฆฌํฉ๋๋ค. flatten() ํจ์๋ 2์ฐจ์ ๋ฐฐ์ด์ 1์ฐจ์ ๋ฐฐ์ด๋ก ๋ณํํ์ฌ ๋ฐ๋ณตํ ์ ์๋๋ก ๋์์ค๋๋ค.
- boxes[i]๋ฅผ ํตํด ํ์ง๋ ๊ฐ์ฒด์ bounding box ์ขํ๋ฅผ ๊ฐ์ ธ์ค๊ณ , ์ด ์ขํ๋ ์ข์๋จ x, ์ข์๋จ y, ๋๋น, ๋์ด๋ฅผ ํฌํจํฉ๋๋ค.
- caption์ ํ์ง๋ ๊ฐ์ฒด์ ํด๋์ค๋ช ๊ณผ ์ ๋ขฐ๋๋ฅผ ํฌํจํ ๋ฌธ์์ด๋ก, ์ด๋ฅผ ์ด๋ฏธ์ง์ ํ์ํ๊ธฐ ์ํด ์ฌ์ฉํฉ๋๋ค.
Bounding Box ๊ทธ๋ฆฌ๊ธฐ
- cv2.rectangle() ํจ์๋ ์ด๋ฏธ์ง ์์ ์ฌ๊ฐํ์ ๊ทธ๋ฆฌ๋ ํจ์์ ๋๋ค. ์ข์๋จ ์ขํ์ ์ฐํ๋จ ์ขํ๋ฅผ ์ ๋ ฅ์ผ๋ก ๋ฐ์ ๊ฒฝ๊ณ ์์๋ฅผ ๊ทธ๋ฆฝ๋๋ค. ๊ฒฝ๊ณ ์์์ ์์์ green_color๋ก ์ค์ ๋์ด ์๊ณ , ๋๊ป๋ 2์ ๋๋ค.
ํ ์คํธ(ํด๋์ค๋ช , ์ ๋ขฐ๋)ํ์
- cv2.putText() ํจ์๋ ์ด๋ฏธ์ง์ ํ ์คํธ๋ฅผ ์ฝ์ ํฉ๋๋ค. ํ ์คํธ๋ ๊ฐ์ฒด์ ํด๋์ค๋ช ๊ณผ ์ ๋ขฐ๋๋ฅผ ํฌํจํ๊ณ ์์ผ๋ฉฐ, ํ ์คํธ ์์น๋ bounding box์ ์ข์๋จ ์ขํ ์์ ํ์๋ฉ๋๋ค. ๊ธ๊ผด์ OpenCV์ FONT_HERSHEY_SIMPLEX๊ฐ ์ฌ์ฉ๋๊ณ , ๊ธ์ ํฌ๊ธฐ์ ์์์ด ์ค์ ๋ฉ๋๋ค.
BGR์์ RGB๋ก ๋ณํ ๋ฐ ์๊ฐํ
- OpenCV๋ BGR ํ์์ ์ด๋ฏธ์ง๋ฅผ ์ฌ์ฉํ์ง๋ง, matplotlib์์๋ RGB ํ์์ ์ด๋ฏธ์ง๋ฅผ ์ฌ์ฉํฉ๋๋ค. ๋ฐ๋ผ์ cv2.cvtColor()๋ฅผ ์ฌ์ฉํ์ฌ BGR ์ด๋ฏธ์ง๋ฅผ RGB๋ก ๋ณํํ ํ, plt.imshow()๋ฅผ ํตํด ์ด๋ฏธ์ง๋ฅผ ํ๋ฉด์ ํ์ํฉ๋๋ค.
์ด๋ฏธ์ง ํฌ๊ธฐ ์กฐ์ ๋ฐ ์ถ๋ ฅ
- plt.figure(figsize=(12, 12))๋ ์ถ๋ ฅ๋ ์ด๋ฏธ์ง์ ํฌ๊ธฐ๋ฅผ ์ค์ ํ๋ฉฐ, 12x12์ธ์น๋ก ์ค์ ํฉ๋๋ค. plt.imshow(img_rgb)๋ฅผ ์ฌ์ฉํด ์ด๋ฏธ์ง ๊ฒฐ๊ณผ๋ฅผ ์๊ฐ์ ์ผ๋ก ํ์ํฉ๋๋ค.
๋จ์ผ image๋ฅผ YOLO๋ก detectํ๋ get_detected_img ํจ์ ์์ฑ
def get_detected_img(cv_net, img_array, conf_threshold, nms_threshold, use_copied_array=True, is_print=True):
# ์๋ณธ ์ด๋ฏธ์ง๋ฅผ ๋คํธ์์ ์
๋ ฅ์์๋ (416, 416)๋ก resize ํจ.
# ์ดํ ๊ฒฐ๊ณผ๊ฐ ์ถ๋ ฅ๋๋ฉด resize๋ ์ด๋ฏธ์ง ๊ธฐ๋ฐ์ผ๋ก bounding box ์์น๊ฐ ์์ธก ๋๋ฏ๋ก ์ด๋ฅผ ๋ค์ ์๋ณตํ๊ธฐ ์ํด ์๋ณธ ์ด๋ฏธ์ง shape์ ๋ณด ํ์
rows = img_array.shape[0]
cols = img_array.shape[1]
draw_img = None
if use_copied_array:
draw_img = img_array.copy()
else:
draw_img = img_array
#์ ์ฒด Darknet layer์์ 13x13 grid, 26x26, 52x52 grid์์ detect๋ Output layer๋ง filtering
layer_names = cv_net.getLayerNames()
try:
output_layers = cv_net.getUnconnectedOutLayers()
# ์ธ๋ฑ์ค ๋ฆฌ์คํธ์ ์ ์ ๋ฆฌ์คํธ ๋ชจ๋ ์ฒ๋ฆฌ
outlayer_names = [layer_names[i - 1] if isinstance(i, list) else layer_names[i - 1] for i in output_layers]
except:
# ์์ ๋ฐฉ๋ฒ์ด ์คํจํ๋ฉด ์ด ๋์ ๋ฐฉ๋ฒ์ ์๋
output_layers = cv_net.getUnconnectedOutLayers().flatten()
outlayer_names = [layer_names[i - 1] for i in output_layers]
# ๋ก๋ฉํ ๋ชจ๋ธ์ Yolov3 416 x 416 ๋ชจ๋ธ์. ์๋ณธ ์ด๋ฏธ์ง ๋ฐฐ์ด์ ์ฌ์ด์ฆ (416, 416)์ผ๋ก, BGR์ RGB๋ก ๋ณํํ์ฌ ๋ฐฐ์ด ์
๋ ฅ
cv_net.setInput(cv2.dnn.blobFromImage(img_array, scalefactor=1/255.0, size=(416, 416), swapRB=True, crop=False))
start = time.time()
# Object Detection ์ํํ์ฌ ๊ฒฐ๊ณผ๋ฅผ cvOut์ผ๋ก ๋ฐํ
cv_outs = cv_net.forward(outlayer_names)
layerOutputs = cv_net.forward(outlayer_names)
# bounding box์ ํ
๋๋ฆฌ์ caption ๊ธ์์ ์ง์
green_color=(0, 255, 0)
red_color=(0, 0, 255)
class_ids = []
confidences = []
boxes = []
# 3๊ฐ์ ๊ฐ๋ณ output layer๋ณ๋ก Detect๋ Object๋ค์ ๋ํด์ Detection ์ ๋ณด ์ถ์ถ ๋ฐ ์๊ฐํ
for ix, output in enumerate(cv_outs):
# Detected๋ Object๋ณ iteration
for jx, detection in enumerate(output):
scores = detection[5:]
class_id = np.argmax(scores)
confidence = scores[class_id]
# confidence๊ฐ ์ง์ ๋ conf_threshold๋ณด๋ค ์์ ๊ฐ์ ์ ์ธ
if confidence > conf_threshold:
#print('ix:', ix, 'jx:', jx, 'class_id', class_id, 'confidence:', confidence)
# detection์ scale๋ ์ข์๋จ, ์ฐํ๋จ ์ขํ๋ฅผ ๋ฐํํ๋ ๊ฒ์ด ์๋๋ผ, detection object์ ์ค์ฌ์ขํ์ ๋๋น/๋์ด๋ฅผ ๋ฐํ
# ์๋ณธ ์ด๋ฏธ์ง์ ๋ง๊ฒ scale ์ ์ฉ ๋ฐ ์ข์๋จ, ์ฐํ๋จ ์ขํ ๊ณ์ฐ
center_x = int(detection[0] * cols)
center_y = int(detection[1] * rows)
width = int(detection[2] * cols)
height = int(detection[3] * rows)
left = int(center_x - width / 2)
top = int(center_y - height / 2)
# 3๊ฐ์ ๊ฐ๋ณ output layer๋ณ๋ก Detect๋ Object๋ค์ ๋ํ class id, confidence, ์ขํ์ ๋ณด๋ฅผ ๋ชจ๋ ์์ง
class_ids.append(class_id)
confidences.append(float(confidence))
boxes.append([left, top, width, height])
# NMS๋ก ์ต์ข
filtering๋ idxs๋ฅผ ์ด์ฉํ์ฌ boxes, classes, confidences์์ ํด๋นํ๋ Object์ ๋ณด๋ฅผ ์ถ์ถํ๊ณ ์๊ฐํ.
idxs = cv2.dnn.NMSBoxes(boxes, confidences, conf_threshold, nms_threshold)
if len(idxs) > 0:
for i in idxs.flatten():
box = boxes[i]
left = box[0]
top = box[1]
width = box[2]
height = box[3]
# labels_to_names ๋์
๋๋ฆฌ๋ก class_id๊ฐ์ ํด๋์ค๋ช
์ผ๋ก ๋ณ๊ฒฝ. opencv์์๋ class_id + 1๋ก ๋งคํํด์ผํจ.
caption = "{}: {:.4f}".format(labels_to_names_seq[class_ids[i]], confidences[i])
#cv2.rectangle()์ ์ธ์๋ก ๋ค์ด์จ draw_img์ ์ฌ๊ฐํ์ ๊ทธ๋ฆผ. ์์น ์ธ์๋ ๋ฐ๋์ ์ ์ํ.
cv2.rectangle(draw_img, (int(left), int(top)), (int(left+width), int(top+height)), color=green_color, thickness=2)
cv2.putText(draw_img, caption, (int(left), int(top - 5)), cv2.FONT_HERSHEY_SIMPLEX, 0.5, red_color, 1)
if is_print:
print('Detection ์ํ์๊ฐ:',round(time.time() - start, 2),"์ด")
return draw_img
- ์
๋ ฅ ์ด๋ฏธ์ง ํฌ๊ธฐ ํ์ธ ๋ฐ ๋ณต์ฌ๋ณธ ์์ฑ:
- ํจ์๊ฐ ์ ๋ ฅ์ผ๋ก ๋ฐ๋ img_array์ ํฌ๊ธฐ ์ ๋ณด๋ฅผ ํ์ธํ์ฌ rows์ cols์ ์ ์ฅํฉ๋๋ค. ์ด๋ ๋์ค์ ๋คํธ์ํฌ๊ฐ ์์ธกํ bounding box ์ขํ๋ฅผ ์๋ ์ด๋ฏธ์ง ํฌ๊ธฐ๋ก ๋ณํํ๋ ๋ฐ ์ฌ์ฉ๋ฉ๋๋ค.
- use_copied_array ํ๋๊ทธ์ ๋ฐ๋ผ ์๋ณธ ์ด๋ฏธ์ง๋ฅผ ๊ทธ๋๋ก ์ฌ์ฉํ ์ง, ์๋๋ฉด ๋ณต์ฌ๋ณธ์ ์ฌ์ฉํ ์ง ๊ฒฐ์ ํฉ๋๋ค. ๋ณต์ฌ๋ณธ์ ์ฌ์ฉํ๋ ์ด์ ๋ ์๋ณธ ์ด๋ฏธ์ง๋ฅผ ๋ณด์กดํ๊ธฐ ์ํจ์ ๋๋ค.
- ์ถ๋ ฅ ๋ ์ด์ด ํํฐ๋ง:
- YOLO ๋ชจ๋ธ์ ๋ชจ๋ ๋ ์ด์ด ์ด๋ฆ์ ๊ฐ์ ธ์ค๊ณ , getUnconnectedOutLayers() ํจ์๋ฅผ ์ฌ์ฉํ์ฌ ์ถ๋ ฅ ๋ ์ด์ด๋ค๋ง ํํฐ๋งํฉ๋๋ค. YOLOv3๋ 3๊ฐ์ ์ถ๋ ฅ ๋ ์ด์ด๋ฅผ ๊ฐ์ง๊ณ ์์ผ๋ฉฐ, ๊ฐ ๋ ์ด์ด๋ ๋ค๋ฅธ ํฌ๊ธฐ์ ๊ทธ๋ฆฌ๋(13x13, 26x26, 52x52)์์ ๊ฐ์ฒด๋ฅผ ํ์งํฉ๋๋ค.
- ์ด๋ฏธ์ง ์ ์ฒ๋ฆฌ ๋ฐ ๋คํธ์ํฌ ์
๋ ฅ:
- ์ด๋ฏธ์ง๋ฅผ YOLOv3 ๋ชจ๋ธ์ด ์๊ตฌํ๋ ํฌ๊ธฐ(416x416)๋ก ๋ฆฌ์ฌ์ด์ฆํ๊ณ , OpenCV์ ๊ธฐ๋ณธ BGR ํ์์์ YOLO๊ฐ ์๊ตฌํ๋ RGB ํ์์ผ๋ก ๋ณํํฉ๋๋ค. ์ด๋ฅผ cv2.dnn.blobFromImage() ํจ์๋ฅผ ์ฌ์ฉํ์ฌ ์ฒ๋ฆฌํ ํ, ๋คํธ์ํฌ์ ์ ๋ ฅํฉ๋๋ค.
- ๊ฐ์ฒด ํ์ง ์ํ:
- cv_net.forward() ํจ์๋ ๋คํธ์ํฌ์ ์ถ๋ ฅ ๋ ์ด์ด์์ ๊ฐ์ฒด ํ์ง ๊ฒฐ๊ณผ๋ฅผ ๋ฐํํฉ๋๋ค. ๊ฒฐ๊ณผ์๋ ๊ฐ ๊ฐ์ฒด์ ์ค์ฌ ์ขํ, ๋๋น, ๋์ด, ์ ๋ขฐ๋ ๋ฐ ํด๋์ค๋ณ ์ ์ ์ ๋ณด๊ฐ ํฌํจ๋์ด ์์ต๋๋ค.
- ํ์ง ๊ฒฐ๊ณผ ์ฒ๋ฆฌ:
- ํ์ง๋ ๊ฐ์ฒด๋ค์ ์ ๋ขฐ๋์ ํด๋์ค ID๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ์ ํจํ ๊ฐ์ฒด๋ง ํํฐ๋งํฉ๋๋ค. ์ ๋ขฐ๋๊ฐ ์ง์ ๋ ์๊ณ๊ฐ(conf_threshold)๋ณด๋ค ๋์ ๊ฐ์ฒด๋ง ์ ํจํ ๊ฐ์ฒด๋ก ๊ฐ์ฃผํฉ๋๋ค.
- ๊ฐ ํ์ง ๊ฒฐ๊ณผ์์ ๊ฐ์ฒด์ ์ค์ฌ ์ขํ์ ํฌ๊ธฐ ์ ๋ณด๋ฅผ ์๋ณธ ์ด๋ฏธ์ง ํฌ๊ธฐ๋ก ๋ณํํ์ฌ bounding box ์ขํ๋ฅผ ๊ณ์ฐํฉ๋๋ค.
- Non-Maximum Suppression (NMS):
- Non-Maximum Suppression(NMS)์ ์ฌ์ฉํ์ฌ ์ค๋ณต๋ bounding box๋ฅผ ์ ๊ฑฐํฉ๋๋ค. NMS๋ ์ฌ๋ฌ bounding box๊ฐ ๊ฒน์น ๋, ์ ๋ขฐ๋๊ฐ ๊ฐ์ฅ ๋์ ๋ฐ์ค๋ฅผ ๋จ๊ธฐ๊ณ ๋๋จธ์ง๋ฅผ ์ ๊ฑฐํ๋ ๊ธฐ๋ฒ์ ๋๋ค.
- Bounding Box์ ํ
์คํธ ์๊ฐํ:
- NMS๋ก ํํฐ๋ง๋ ๊ฐ์ฒด๋ค์ ๋ํด bounding box๋ฅผ ๊ทธ๋ฆฌ๊ณ , ํ์ง๋ ๊ฐ์ฒด์ ํด๋์ค๋ช ๊ณผ ์ ๋ขฐ๋๋ฅผ ์ด๋ฏธ์ง์ ํ ์คํธ๋ก ํ์ํฉ๋๋ค. cv2.rectangle() ํจ์๋ bounding box๋ฅผ ๊ทธ๋ฆฌ๋ ์ญํ ์ ํ๊ณ , cv2.putText()๋ ํ ์คํธ๋ฅผ ์ด๋ฏธ์ง์ ์ฝ์ ํฉ๋๋ค.
- ํ์ง ์๊ฐ ์ถ๋ ฅ ๋ฐ ๊ฒฐ๊ณผ ๋ฐํ:
- ํ์ง์ ๊ฑธ๋ฆฐ ์๊ฐ์ ์ถ๋ ฅํ๊ณ , bounding box์ ํด๋์ค๋ช ์ด ๊ทธ๋ ค์ง ์ด๋ฏธ์ง๋ฅผ ๋ฐํํฉ๋๋ค.
import cv2
import matplotlib.pyplot as plt
%matplotlib inline
import numpy as np
import time
# image ๋ก๋
default_dir = '/content/DLCV'
img = cv2.imread(os.path.join(default_dir, 'data/image/beatles01.jpg'))
#coco dataset ํด๋์ค๋ช
๋งคํ
import os
#๊ฐ๊ธ์ ์ ๋ ๊ฒฝ๋ก ์ฌ์ฉ.
#CUR_DIR = os.path.abspath('.')
# ์ฝ๋ฉ ๋ฒ์ ์ ์๋ ์ฝ๋ ์ฌ์ฉ
CUR_DIR = '/content/DLCV/Detection/yolo'
weights_path = os.path.join(CUR_DIR, 'pretrained/yolov3.weights')
config_path = os.path.join(CUR_DIR, 'pretrained/yolov3.cfg')
# tensorflow inference ๋ชจ๋ธ ๋ก๋ฉ
cv_net_yolo = cv2.dnn.readNetFromDarknet(config_path, weights_path)
conf_threshold = 0.5
nms_threshold = 0.4
# Object Detetion ์ํ ํ ์๊ฐํ
draw_img = get_detected_img(cv_net_yolo, img, conf_threshold=conf_threshold, nms_threshold=nms_threshold, use_copied_array=True, is_print=True)
img_rgb = cv2.cvtColor(draw_img, cv2.COLOR_BGR2RGB)
plt.figure(figsize=(12, 12))
plt.imshow(img_rgb)
Detection ์ํ์๊ฐ: 4.44 ์ด
<matplotlib.image.AxesImage at 0x7c3250b01c60>
- SSD์ ๋นํด์ ๋๋ฆฌ์ง๋ง Object Detection ์ฑ๋ฅ์ ์ข์๊ฑธ ์ ์ ์์ต๋๋ค.
Video(์์) Object Detection
def do_detected_video(cv_net, input_path, output_path, conf_threshold, nms_threshold, is_print):
# ์
๋ ฅ ๋น๋์ค ํ์ผ์ ์ฝ๊ธฐ ์ํด VideoCapture ๊ฐ์ฒด ์์ฑ
cap = cv2.VideoCapture(input_path)
# ๋น๋์ค ์ฝ๋ฑ ์ค์ (XVID ์ฌ์ฉ)
codec = cv2.VideoWriter_fourcc(*'XVID')
# ์
๋ ฅ ๋น๋์ค์ ํฌ๊ธฐ์ FPS๋ฅผ ๊ฐ์ ธ์ด
vid_size = (round(cap.get(cv2.CAP_PROP_FRAME_WIDTH)), round(cap.get(cv2.CAP_PROP_FRAME_HEIGHT)))
vid_fps = cap.get(cv2.CAP_PROP_FPS)
# ์ถ๋ ฅ ๋น๋์ค ํ์ผ์ ์ ์ฅํ๊ธฐ ์ํ VideoWriter ๊ฐ์ฒด ์์ฑ
vid_writer = cv2.VideoWriter(output_path, codec, vid_fps, vid_size)
# ๋น๋์ค์ ์ด ํ๋ ์ ์ ๊ฐ์ ธ์ค๊ธฐ
frame_cnt = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))
print('์ด Frame ๊ฐฏ์:', frame_cnt)
# Bounding box์ ํ
์คํธ์ ์์ ์ค์
green_color = (0, 255, 0) # Bounding box ์์ (๋
น์)
red_color = (0, 0, 255) # ํ
์คํธ ์์ (๋นจ๊ฐ์)
# ๋น๋์ค์ ๋ชจ๋ ํ๋ ์์ ํ๋์ฉ ์ฒ๋ฆฌ
while True:
hasFrame, img_frame = cap.read() # ๋น๋์ค์ ํ ํ๋ ์์ ์ฝ์ด์ด
if not hasFrame:
print('๋ ์ด์ ์ฒ๋ฆฌํ frame์ด ์์ต๋๋ค.')
break # ํ๋ ์์ ๋ชจ๋ ์ฒ๋ฆฌํ๋ฉด ์ข
๋ฃ
# YOLOv3๋ฅผ ์ฌ์ฉํ์ฌ ๊ฐ์ฒด ํ์ง ์ํ
returned_frame = get_detected_img(cv_net, img_frame, conf_threshold=conf_threshold, nms_threshold=nms_threshold, \
use_copied_array=False, is_print=is_print)
# ํ์ง ๊ฒฐ๊ณผ๊ฐ ํฌํจ๋ ํ๋ ์์ ์ถ๋ ฅ ๋น๋์ค์ ์ ์ฅ
vid_writer.write(returned_frame)
# ๋น๋์ค ํ์ผ ์ ์ฅ์ ๋ง๋ฌด๋ฆฌ
vid_writer.release()
cap.release()
default_dir = '/content/DLCV'
do_detected_video(cv_net_yolo, os.path.join(default_dir, 'data/video/John_Wick_small.mp4'),
os.path.join(default_dir, 'data/output/John_Wick_small_yolo01.avi'), conf_threshold,
nms_threshold, True)
- ์
๋ ฅ ๋น๋์ค ๋ก๋:
- cv2.VideoCapture(input_path)๋ฅผ ์ฌ์ฉํ์ฌ ์ง์ ๋ ๋น๋์ค ํ์ผ์ ์ฝ์ต๋๋ค.
- ๋น๋์ค ์ถ๋ ฅ ์ค์ :
- cv2.VideoWriter๋ฅผ ์ฌ์ฉํ์ฌ ์ถ๋ ฅ ๋น๋์ค ํ์ผ์ ์์ฑํฉ๋๋ค. ์ ๋ ฅ ๋น๋์ค์ ํด์๋(vid_size)์ FPS(vid_fps)๋ฅผ ๊ทธ๋๋ก ์ฌ์ฉํฉ๋๋ค.
- ํ๋ ์ ๋ฐ๋ณต ์ฒ๋ฆฌ:
- cap.read()๋ฅผ ํตํด ๋น๋์ค์์ ํ๋ ์์ ํ๋์ฉ ์ฝ์ต๋๋ค.
- ๊ฐ ํ๋ ์์ ๋ํด get_detected_img() ํจ์๋ฅผ ํธ์ถํ์ฌ YOLOv3๋ฅผ ์ฌ์ฉํ ๊ฐ์ฒด ํ์ง๋ฅผ ์ํํฉ๋๋ค.
- ํ์ง๋ ๊ฐ์ฒด๊ฐ ํฌํจ๋ ํ๋ ์์ ์ถ๋ ฅ ๋น๋์ค ํ์ผ์ ์ ์ฅํฉ๋๋ค.
- ์ข
๋ฃ ์ฒ๋ฆฌ:
- ๋ ์ด์ ์ฒ๋ฆฌํ ํ๋ ์์ด ์์ผ๋ฉด ๋ฃจํ๋ฅผ ์ข ๋ฃํ๊ณ , ๋น๋์ค ํ์ผ์ ์ ์ฅํ ํ ์์์ ํด์ ํฉ๋๋ค.
ํ๋ผ๋ฏธํฐ ์ค๋ช
- cv_net: YOLOv3 ๋คํธ์ํฌ (๋ชจ๋ธ).
- input_path: ์ ๋ ฅ ๋น๋์ค ํ์ผ ๊ฒฝ๋ก.
- output_path: ๊ฒฐ๊ณผ๋ฅผ ์ ์ฅํ ์ถ๋ ฅ ๋น๋์ค ํ์ผ ๊ฒฝ๋ก.
- conf_threshold: ํ์ง ์ ๋ขฐ๋ ์๊ณ๊ฐ.
- nms_threshold: Non-Maximum Suppression ์๊ณ๊ฐ.
- is_print: ํ์ง ๊ฒฐ๊ณผ ์ถ๋ ฅ ์ฌ๋ถ (ํ์ง ์ ๋ณด๋ฅผ ์ถ๋ ฅํ ์ง ์ฌ๋ถ ๊ฒฐ์ ).
## Object Detection ์ ์ฉ๋ ์์ ํ์ผ์ google drive์์ download ํด์ผ ํฉ๋๋ค. ์ด๋ฅผ ์ํด google drive๋ฅผ colab์ mount ์ํ.
import os, sys
from google.colab import drive
drive.mount('/content/gdrive')
## Object Detection ์ ์ฉ๋ ์์ ํ์ผ์ google drive์์ download ํด์ผ ํฉ๋๋ค.
## My Drive ๋๋ ํ ๋ฆฌ ์ด๋ฆ์ ๊ณต๋์ด ์์ผ๋ฏ๋ก ' '๋ก ๋ฌถ์ต๋๋ค.
!cp /content/DLCV/data/output/John_Wick_small_yolo01.avi '/content/gdrive/My Drive/John_Wick_small_yolo01.avi'
Tiny YOLO๋ก Object Detection ์ํ
tiny YOLO๋ ์ผ๋ฐ YOLO๋ณด๋ค๋ ์ฑ๋ฅ์ด ๋จ์ด์ง๋ค๋ ํน์ง์ด ์์ต๋๋ค.
- tiny yolo์ pretrained๋ weightํ์ผ์ wget https://pjreddie.com/media/files/yolov3-tiny.weights ์์ download ๊ฐ๋ฅ.
- config ํ์ผ์ wget https://github.com/pjreddie/darknet/blob/master/cfg/yolov3-tiny.cfg?raw=true -O ./yolov3-tiny.cfg ๋ก ๋ค์ด๋ก๋
import cv2
import matplotlib.pyplot as plt
%matplotlib inline
import numpy as np
import os
import time
# image ๋ก๋
default_dir = '/content/DLCV'
img = cv2.imread(os.path.join(default_dir, 'data/image/beatles01.jpg'))
#coco dataset ํด๋์ค๋ช
๋งคํ
import os
#๊ฐ๊ธ์ ์ ๋ ๊ฒฝ๋ก ์ฌ์ฉ.
#CUR_DIR = os.path.abspath('.')
# ์ฝ๋ฉ ๋ฒ์ ์ ์๋ ์ฝ๋ ์ฌ์ฉ
CUR_DIR = '/content/DLCV/Detection/yolo'
weights_path = os.path.join(CUR_DIR, 'pretrained/yolov3-tiny.weights')
config_path = os.path.join(CUR_DIR, 'pretrained/yolov3-tiny.cfg')
# tensorflow inference ๋ชจ๋ธ ๋ก๋ฉ
cv_net_yolo = cv2.dnn.readNetFromDarknet(config_path, weights_path)
#tiny yolo์ ๊ฒฝ์ฐ confidence๊ฐ ์ผ๋ฐ์ ์ผ๋ก ๋ฎ์.
conf_threshold = 0.3
nms_threshold = 0.4
# Object Detetion ์ํ ํ ์๊ฐํ
draw_img = get_detected_img(cv_net_yolo, img, conf_threshold=conf_threshold, nms_threshold=nms_threshold, use_copied_array=True, is_print=True)
img_rgb = cv2.cvtColor(draw_img, cv2.COLOR_BGR2RGB)
plt.figure(figsize=(12, 12))
plt.imshow(img_rgb)
Tiny YOLO๋ก ์์ Detection
default_dir = '/content/DLCV'
do_detected_video(cv_net_yolo, os.path.join(default_dir, 'data/video/John_Wick_small.mp4'),
os.path.join(default_dir, 'data/output/John_Wick_small_tiny_yolo01.avi'), conf_threshold,
nms_threshold, True)
## Object Detection ์ ์ฉ๋ ์์ ํ์ผ์ google drive์์ download ํด์ผ ํฉ๋๋ค.
## My Drive ๋๋ ํ ๋ฆฌ ์ด๋ฆ์ ๊ณต๋์ด ์์ผ๋ฏ๋ก ' '๋ก ๋ฌถ์ต๋๋ค.
!cp /content/DLCV/data/output/John_Wick_small_tiny_yolo01.avi '/content/gdrive/My Drive/John_Wick_small_tiny_yolo01.avi'
'๐ Computer Vision' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
[CV] Object Detection Model Training์ ์ ์์ฌํญ (0) | 2024.10.08 |
---|---|
[CV] Keras ๊ธฐ๋ฐ YOLO Open Source Package & Object Detection (0) | 2024.10.07 |
[CV] OpenCV์์ YOLO๋ฅผ ์ด์ฉํ Object Detection Part.1 (0) | 2024.07.15 |
[CV] YOLO (You Only Look Once) (0) | 2024.07.14 |
[CV] OpenCV DNN ํจํค์ง & SSD ๊ธฐ๋ฐ Object Detection ์ํ (0) | 2024.07.10 |