728x90
1. Object Detection 주요 데이터 세트 소개 및 Pascal VOC 데이터 세트의 이해
- Object Detection 과 segmentation 딥러닝 패키지는 주로 아래 3가지 데이터 세트 기반.
- Pascal VOC
- MS COCO
- Google Open Images
- 아래 갈 수록 더 세분화되어 많은 카테고리를 갖고 있다.
- Annotation?
- 바운딩박스의 위치, 이름, 이미지 사이즈 등 이미지에 대한 정보를 가지는 주석
- Pascal VOC의 경우 Annotation의 정보를 담은 xml 파일과 원본이미지 파일인 jpg 파일이 같은 이름을 갖는다.
2. MS COCO
- MS COCO는 Object detection에서 일반적으로 사용되는 데이터 셋
- train, val, test 셋을 따로 다운받을 수 있으며, 그에 대한 images 파일(파일명, 이미지크기 등), Annotation(bbox, category 등)은 모두 통합된 형태의 파일로서 존재한다.
- COCO는 이미지 한개에 여러 object 을 가지고 있으며 타 데이터셋에 비해 난이도가 높다.
3. OpenCV 개요
- 방대한 라이브러리 보유
- 주의점
- OpenCV는 OS 의 window frame 과 바로 인터페이스하여 사용할 수 있는 여러 기능 제공. 하지만 이들 기능을 사용하려면 window frame 생성이 가능한 GUI 개발 환경에서만 가능(window GUI, Linux X-windows 등). 따라서 주피터 노트북 기반에서는 사용시 오류 발생
- 즉, 아래와 같은 코드들은 주피터 노트북에서 실행 시 오류가 남. window 창을 생성할 환경이 안됨.
- ex) cv2.imshow, cv2.waitkey(), cv2.destroyAllWindows()
- 주피터 노트북은 이미지 배열(array) 시각화에 matplotlib 을 사용.
4. OpenCV 를 활용한 이미지 처리 실습
- skimage, PIL, opencv 등 여러가지 라이브러리로 이미지를 시각화할 수 있다.
- 그 중에서도 opencv는 여러 api를 제공하여 이미지, 영상처리에 특화됨.
- 자세한 건 아래 참조
5. OpenCV 를 활용한 영상 처리 실습
- 개요
- 기본적으로 VideoCapture(video파일위치) 클래스와 VideoWriter(write할 위치, 인코딩codec유형, fps, frame크기) 클래스가 핵심
- 전자로 input 하여 읽고, 후자로 output 한다고 생각하면 됨.
- fps 가 작으면 초당프레임이 작아지므로 딱딱 끊겨서 표현됨.
- 그리고 VideoWriter()을 이용해 지정하는 codec(DIVX, XVID, MJPG, X264, WMV1, WMV2) 로 영상을 인코딩할 수 있음.
- 참고로 리눅스 서버에서는 반드시 XVID 형태로만 인코딩 적용하고 write 시 동영상 명의 확장자는 반드시 .avi로만 해야함.
OpenCV의 이미지와 영상 처리
- Python에서 사용되는 여러 image라이브러리를 간단히 살펴보고 OpenCV와의 차이 이해
- OpenCV의 단일 이미지 처리 방식 이해
- OpenCV의 비디오 영상 처리 방식 이해
아래 예제는 GPU가 필요하지 않으며 코랩 커널을 GPU로 바꿀 필요가 없습니다.
- tensorflow와 keras 설치는 필요하지 않습니다.
- OpenCV와 기타 필요한 패키지는 이미 코랩에 설치 되어 있습니다.
실습 코드를 github에서 다운로드
# 현재 디렉토리는 /content이며 이 디렉토리를 기준으로 실습코드와 데이터를 다운로드 합니다.
!pwd
# 실습코드를 github에서 다운로드
!git clone https://github.com/chulminkw/DLCV.git
# DLCV 디렉토리가 Download되고 DLCV 밑에 Detection과 Segmentation 디렉토리가 있는 것을 확인
!ls -lia
!ls -lia DLCV
/content
Cloning into 'DLCV'...
remote: Enumerating objects: 75, done.[K
remote: Counting objects: 100% (75/75), done.[K
remote: Compressing objects: 100% (71/71), done.[K
remote: Total 234 (delta 32), reused 0 (delta 0), pack-reused 159[K
Receiving objects: 100% (234/234), 142.72 MiB | 22.96 MiB/s, done.
Resolving deltas: 100% (89/89), done.
total 20
4456463 drwxr-xr-x 1 root root 4096 Mar 7 16:14 .
4197035 drwxr-xr-x 1 root root 4096 Mar 7 16:13 ..
3670031 drwxr-xr-x 4 root root 4096 Mar 1 14:35 .config
4196981 drwxr-xr-x 7 root root 4096 Mar 7 16:14 DLCV
4456464 drwxr-xr-x 1 root root 4096 Mar 1 14:35 sample_data
total 11016
4196981 drwxr-xr-x 7 root root 4096 Mar 7 16:14 .
4456463 drwxr-xr-x 1 root root 4096 Mar 7 16:14 ..
4197178 drwxr-xr-x 2 root root 4096 Mar 7 16:14 colab_tf115_modify_files
4197181 drwxr-xr-x 6 root root 4096 Mar 7 16:14 data
4197064 drwxr-xr-x 8 root root 4096 Mar 7 16:14 Detection
4197049 -rw-r--r-- 1 root root 6567662 Mar 7 16:14 DLCV_Colab_SrcCode_20200905.zip
4196982 drwxr-xr-x 8 root root 4096 Mar 7 16:14 .git
4197215 -rw-r--r-- 1 root root 2063693 Mar 7 16:14 labelimg.pptx
4197216 -rw-r--r-- 1 root root 2612271 Mar 7 16:14 '구글클라우드 가입하기.pdf'
4197168 -rw-r--r-- 1 root root 142 Mar 7 16:14 README.md
4197169 drwxr-xr-x 3 root root 4096 Mar 7 16:14 Segmentation
OpenCV 이미지 처리 이해 및 타 패키지 비교
PIL 패키지를 이용하여 이미지 로드하기
import matplotlib.pyplot as plt
import os
%matplotlib inline
from PIL import Image
# PIL은 oepn()으로 image file을 읽어서 ImageFile객체로 생성.
# 코랩 버전은 상대 경로를 사용하지 않습니다. /content 디렉토리를 기준으로 절대 경로를 이용합니다.
# default_dir 은 /content/DLCV로 지정하고 os.path.join()으로 상세 파일/디렉토리를 지정합니다.
default_dir = '/content/DLCV'
pil_image = Image.open(os.path.join(default_dir, "data/image/beatles01.jpg"))
print('image type:', type(pil_image))
plt.figure(figsize=(10, 10))
plt.imshow(pil_image)
#plt.show()
image type: <class 'PIL.JpegImagePlugin.JpegImageFile'>
<matplotlib.image.AxesImage at 0x7f28f5fba3d0>
skimage(사이킷이미지)로 이미지 로드 하기
- skimage는 imread()를 이용하여 RGB 원본 이미지를 RGB 형태의 넘파이 배열로 반환함.
from skimage import io
#skimage는 imread()를 이용하여 image를 numpy 배열로 반환함.
sk_image = io.imread(os.path.join(default_dir, "data/image/beatles01.jpg"))
print('sk_image type:', type(sk_image), ' sk_image shape:', sk_image.shape)
# shape은 (행, 열, 채널) 이므로 행 = 세로, 열 = 가로길이가 된다.
plt.figure(figsize=(10, 10))
plt.imshow(sk_image)
#plt.show()
sk_image type: <class 'numpy.ndarray'> sk_image shape: (633, 806, 3)
<matplotlib.image.AxesImage at 0x7f28e9ef2b90>
OpenCV로 이미지 로드하기
- OpenCV는 imread()를 이용하여 원본 RGB 이미지를 BGR 형태의 넘파이 배열로 반환함.
- OpenCV의 imwrite()를 이용한다면 BGR 형태의 이미지 배열을 파일에 기록할 때 다시 RGB형태로 변환하므로 사용자는 RGB->BGR->RGB 변환에 신경쓰지 않아도 됨.
import cv2
cv2_image = cv2.imread(os.path.join(default_dir, "data/image/beatles01.jpg"))
# data/output 위치에 beatles02_cv.jpg 라는 이름으로 cv2_image 가 저장됨.
cv2.imwrite(os.path.join(default_dir, "data/output/beatles02_cv.jpg"), cv2_image)
print('cv_image type:', type(cv2_image), ' cv_image shape:', cv2_image.shape)
plt.figure(figsize=(10, 10))
# plt.imread 를 통해 array 뿐만아니라 이미지 파일도 읽을 수 있음.
# 즉, plt.imread 를 통해 이미지 파일을 저장하고 imshow 를 통해 시각화
# plt.imread 는 cv2.imread 와 다르게 RGB로 저장하므로 원본 그대로 표현 가능.
img = plt.imread(os.path.join(default_dir, "data/output/beatles02_cv.jpg"))
plt.imshow(img)
#plt.show()
cv_image type: <class 'numpy.ndarray'> cv_image shape: (633, 806, 3)
<matplotlib.image.AxesImage at 0x7f28e0c68810>
OpenCV의 imread()로 반환된 BGR 이미지 넘파이 배열을 그대로 시각화 하기
- OpenCV의 imread()는 RGB를 BGR로 변환하므로 원하지 않는 이미지가 출력됨
cv2_image = cv2.imread(os.path.join(default_dir, "data/image/beatles01.jpg"))
plt.figure(figsize=(10, 10))
plt.imshow(cv2_image)
plt.show()
)
sk_image = io.imread(os.path.join(default_dir, "data/image/beatles01.jpg"))
print(sk_image.shape)
# 만약 plt.imshow(sk_image[:,:,0]) 을 하면, 2차원 형태로 나오므로 흑백으로 나옴.
sk_image[:, :, 0]
(633, 806, 3)
array([[ 18, 17, 18, ..., 46, 38, 63],
[ 18, 18, 18, ..., 72, 41, 37],
[ 18, 18, 18, ..., 84, 56, 42],
...,
[225, 226, 228, ..., 231, 228, 229],
[225, 225, 226, ..., 229, 229, 227],
[225, 225, 224, ..., 227, 227, 227]], dtype=uint8)
cv2_image = cv2.imread(os.path.join(default_dir, "data/image/beatles01.jpg"))
print(type(cv2_image))
print(cv2_image.shape)
cv2_image[:, :, 0]
<class 'numpy.ndarray'>
(633, 806, 3)
array([[ 19, 19, 20, ..., 47, 39, 64],
[ 20, 20, 20, ..., 71, 40, 36],
[ 20, 20, 20, ..., 82, 54, 40],
...,
[198, 199, 201, ..., 190, 189, 188],
[198, 198, 199, ..., 188, 188, 186],
[199, 199, 198, ..., 186, 186, 186]], dtype=uint8)
cv2_image[:, :, 2]
array([[ 18, 18, 18, ..., 47, 39, 64],
[ 19, 19, 18, ..., 72, 41, 37],
[ 18, 18, 18, ..., 84, 56, 41],
...,
[225, 226, 228, ..., 231, 230, 229],
[225, 225, 226, ..., 229, 229, 227],
[225, 225, 224, ..., 227, 227, 227]], dtype=uint8)
cv2_image = cv2.imread(os.path.join(default_dir, "data/image/beatles01.jpg"))
draw_image = cv2.cvtColor(cv2_image, cv2.COLOR_BGR2RGB)
plt.figure(figsize=(10, 10))
plt.imshow(draw_image)
plt.show()
BGR 을 RGB 로 바꾸어야 하는 수고가 있음에도 불구하고 opencv를 사용하는 이유는 opencv가 여러가지 API 를 제공하며 여러 가속화 기능을 탑재하고 있어서 이미지, 영상 처리에 특화되어 있기 때문.
OpenCV 영상처리
- OpenCV는 간편하게 비디오 영상처리를 할 수 있는 API를 제공
- VideoCapture 객체는 Video Streaming을 Frame 별로 Capture하여 처리할 수 있는 기능 제공
- VideoWriter 객체는 VideoCapture로 읽어들인 Frame을 동영상으로 Write하는 기능 제공
# 코랩 버전은 아래 코드를 이용합니다.
# 코랩 버전은 용량 문제로 인해 Night and Day를 browser로 보여줄때 커널이 종료됩니다. 보다 작은 크기인 John Wick으로 대체
from IPython.display import HTML
from base64 import b64encode
mp4 = open('/content/DLCV/data/video/John_Wick_small.mp4','rb').read()
data_url = "data:video/mp4;base64," + b64encode(mp4).decode()
HTML("""
<video width=800 controls>
<source src="%s" type="video/mp4">
</video>
""" % data_url)
# 코랩 버전에서 위의 sample은 John wick이지만 실제 Video 처리는 강의와 동일하게 Night and Day로 수행.
import cv2
default_dir = '/content/DLCV'
video_input_path = os.path.join(default_dir, 'data/video/Night_Day_Chase.mp4')
# linux에서 video output의 확장자는 반드시 avi 로 설정 필요.
video_output_path = os.path.join(default_dir, 'data/output/Night_Day_Chase_output.avi')
cap = cv2.VideoCapture(video_input_path)
# Codec은 *'XVID'로 설정.
codec = cv2.VideoWriter_fourcc(*'XVID')
# VideoWriter 클래스의 vid_size 인자에는 int 자료형이 입력되어야 함.
# round 를 해주면 int 자료형을 반환함.
vid_size = (round(cap.get(cv2.CAP_PROP_FRAME_WIDTH)),round(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))) #(200, 400)
vid_fps = cap.get(cv2.CAP_PROP_FPS )
vid_writer = cv2.VideoWriter(video_output_path, codec, vid_fps, vid_size)
frame_cnt = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))
print('총 Frame 갯수:', frame_cnt, 'FPS:', round(vid_fps), 'Frame 크기:', vid_size)
총 Frame 갯수: 1383 FPS: 28 Frame 크기: (1216, 516)
아래 과정은 VideoCapture 를 통해 영상을 읽고 frame 마다 일정한 사각형을 그려주고 마지막에 VideoWriter 를 통해 output 하는 작업이다.
따라서 영상처리의 매커니즘은
- 영상을 읽고(VIdeoCapture)
- 처리하고(While True~)
- output하는 것이다(VideoWriter)
import time
green_color=(0, 255, 0)
red_color=(0, 0, 255)
start = time.time()
index=0
while True:
# cap.read() 는 처리할 프레임의 존재유무, 프레임 이미지 두가지를 반환
hasFrame, img_frame = cap.read()
if not hasFrame:
print('더 이상 처리할 frame이 없습니다.')
break
index += 1
print('frame :', index, '처리 완료')
cv2.rectangle(img_frame, (300, 100, 800, 400), color=green_color, thickness=2)
caption = "frame:{}".format(index)
cv2.putText(img_frame, caption, (300, 95), cv2.FONT_HERSHEY_SIMPLEX, 0.7, red_color, 1)
# write 을 하면서 RGB 로 되기 때문에 변환과정이 필요없음.
vid_writer.write(img_frame)
print('write 완료 시간:', round(time.time()-start,4))
# release 를 통해 open 된 비디오파일이나 영상장치를 닫는다.
# read 로 open 했으니 닫아주는 듯.
# 마지막에 그냥 해주는게 좋은 듯.
vid_writer.release()
cap.release()
frame : 1 처리 완료
frame : 2 처리 완료
frame : 3 처리 완료
frame : 4 처리 완료
....
frame : 1378 처리 완료
frame : 1379 처리 완료
frame : 1380 처리 완료
frame : 1381 처리 완료
frame : 1382 처리 완료
frame : 1383 처리 완료
더 이상 처리할 frame이 없습니다.
write 완료 시간: 15.0719
## colab 버전은 영상 파일을 google drive에서 download 해야 합니다. 이를 위해 google drive를 colab에 mount 수행.
import os, sys
from google.colab import drive
drive.mount('/content/gdrive')
코랩에서 등장한(?) 데이터는 google drive 로 옮겨야 실체화(?)된다. 즉, 나중에 download 할 수 있다.
이를 위해서는 mount를 하고 !cp(copy) [옮길파일] [My Drive/파일명] 을 실행한다.
## colab 버전은 Object Detection 적용된 영상 파일을 google drive에서 download 해야 합니다.
## My Drive 디렉토리 이름에 공란이 있으므로 ' '로 묶습니다.
# 이를 통해 이제 Night_Day 영상이 내 구글 드라이브에 저장됨.
!cp /content/DLCV/data/output/Night_Day_Chase_output.avi '/content/gdrive/My Drive/Night_Day_Chase_output.avi'
6. Object Detection과 Segmentation을 구현한 오픈소스, OpenCV, Tensorflow 기반의 다양한 패키지 소개
- 종류
- Keras, tensorflow 기반 패키지 : 쉽다.
- ex) keras-yolo3, keras-retina, mask r-cnn : 회사들에서 open 소스로 제공.
- opencv의 dnn 모듈 : 간편하게 object detection inference 가능. 학습 x, GPU 활용 어려움. 미리 학습된 모델 기반.
- tensorflow object detection api : 가장 많은 알고리즘 적용 가능. 어렵다.
- mobile 환경(연산능력이 약한 환경에서)에서의 object detection에 집중.
- 학습과정이 디게 복잡하고 version2와 1이 충돌. document 도 부족.
- Keras, tensorflow 기반 패키지 : 쉽다.
7. Deep Learning을 위한 GPU 이해 - CUDA와 cuDNN 소개 및 nvidia-smi 명령어 활용법
- CUDA란
- GPU 를 C 혹은 Python 과 같은 언어로 제어할 수 있게끔하는 기술.
- cuDNN 은 CUDA 의 딥러닝 라이브러리이다. 본래 GPU 는 그래픽카드의 용도였으므로 딥러닝 네트워크를 구성하고 학습시키기 위한 라이브러리를 출시한 것.
- 즉, tensorflow -> cuDNN -> CUDA 순으로 접근하고 종국적으로 GPU 를 제어한다.
- 참고로 리눅스에는 이런 것들이 다 안깔려있지만, 구글클라우드플랫폼에서 'Deeplearning on Linux' 로 가상환경을 구성했다면 다 깔려있음.
- nvidia-smi 를 통해 GPU 구동현황을 알 수 있으며, 이 명령어가 안된다면 CUDA 설치에 오류가 있는 것.
8. Object Detection 네트웍 개요 및 FPS/Resolution/성능 상관관계
- object detection 네트워크는 feature extractor, object detection network, region proposal 세가지로 구성된다.
- 첫번째는 우리가 아는 cnn을 통한 feature map을 만드는 것.
- 두번째는 feature map 을 기반으로 object detect 하는 것.
- 세번째는 selective search 와 같은 region proposal 을 활용하는 것.
- Image resolution(이미지의 크기)가 커지면 frame 의 선명도가 높아지므로 detection 성능은 좋아진다. 반면 배열의 크기가 커지므로 fps(초당 프레임처리 수)는 낮아짐.
- 두마리의 토끼를 잡을 수는 없으므로 상황에 맞는 모델을 선택해야 함.
질문과 비판은 언제나 환영입니다. 많이 꾸짖어주세요.
728x90
'(인프런)딥러닝 컴퓨터비전 완벽 가이드_권철민' 카테고리의 다른 글
[인프런] 2. Object Detection 의 이해 (0) | 2021.03.01 |
---|---|
[인프런] 1. 구글 클라우드 실습 환경 구축하기(+코랩) (0) | 2021.02.23 |