오늘은 Object Detection과 Segmentation에서 사용되는 데이터셋들과 해당 분야에서의 OpenCV에 대해서 정리해보고자 한다.
여러 Object Detection과 Segmentation 딥러닝 패키지가 아래 3개의 데이터셋들을 기반으로 pretrained되어 배포되어져 있다.
1) Pascal VOC
Pascal VOC는 XML Format으로 annotation이 저장되어져 있으며, 20개의 object 카테고리로 이루어져 있다.
2) MS COCO
MS COCO는 json Format으로 annotation이 저장되어져 있으며, 80개의 object 카테고리로 이루어져 있다.
3) Google Open Images
Google Open Images는 csv Format으로 annotation이 저장되어져 있으며, 600개의 object 카테고리로 이루어져 있다.
이미지의 detection 파일을 별도의 설명 파일로 제공하는 것.
Annotation은 object의 bounding box의 위치나 object의 이름 등을 특정 format으로 제공한다.
만약 원본 이미지에 bounding box를 시각화한다면, 너무 많은 노력이 들어간다. 그래서 image와 annotation을 함께 사용한다.
VOCdevkit
|
VOC 2012
|
Annotations - ImageSet - JPEGImages - SegmentationClass - SegmentationObject
Annotations : XML Format. 하나의 XML 파일 당 한 개 이미지에 대한 annotation 정보를 가지고 있음. 파일명은 이미지 파일명과 동일하게 매핑되어져 있다.
ImageSet : 어떤 이미지를 train, test, trainval에 사용할 것인지에 대한 매핑 정보를 개별 object별로 파일로 가지고 있다. 파일 리스트가 저장되어져 있다.
JPEGImages : Object Detection과 Segmentation에 사용될 원본 이미지가 jpg Format으로 저장되어져 있다.
SegmentationClass : Semantic Segmentation에 사용될 masking image가 저장되어져 있다.
SegmentationObject : Instance Segmentation에 사용될 masking image가 저장되어져 있다.
Element Tree를 이용하여 XML을 파싱한다.
import os
import random
VOC_ROOT_DIR = '/content/data/VOCdevkit/VOC2012/"
ANNO_DIR = os.path.join(VOC_ROOT_DIR, "Annotations")
IMAGE_DIR = os.path.join(VOC_ROOT_DIR, "JPEGImages")
xml_files = os.listdir(ANNO_DIR) #XML file list 가져오기
import os
import xml.etree.ElementTree as ET
#xml파일 하나 불러오기
xml_file = os.path.join(ANNO_DIR, '2007_000032.xml')
#XML 파일을 parsing하여 Element 생성
tree = ET.parse(xml_file) #tree가 만들어짐
root = tree.getroot() #root node를 찾는다
#image 관련 정보는 root의 자식으로 존재
image_name = root.find('filename').text #filename이라는 node를 찾고, 그 node의 text 구하기.
full_image_name = os.path.join(IMAGE_DIR, image_name)
image_size = root.find('size')
image_width = int(image_size.find('width').text)
image_height = int(image_size.find('height').text)
#파일내에 있는 모든 object Element를 찾음.
objects_list = []
for obj in root.findall('object'):
#object element의 자식 element에서 bndbox를 찾음.
xmlbox = obj.find('bndbox')
#bndbox element의 자식 element에서 xmin, ymin, xmax, ymax를 찾고, 이의 값(test)를 추출
x1 = int(xmlbox.find('xmin').text)
y1 = int(xmlbox.find('ymin').text)
x2 = int(xmlbox.find('xmax').text)
y2 = int(xmlbox.find('ymax').text)
bndbox_pos = (x1, y1, x2, y2)
class_name = obj.find('name').text
object_dict = {'class_name': class_name, 'bndbox_pos': bndbox_pos}
objects_list.append(object_dict)
import cv2
import os
import xml.etree.ElementTree as ET
xml_file = os.path.join(ANNO_DIR, '2007_000032.xml')
tree = ET.parse(xml_file)
root = tree.getroot()
image_name = root.find('filename').text
full_image_name = os.path.join(IMAGE_DIR, image_name)
img = cv2.imread(full_image_name)
#opencv의 rectangle()는 인자로 들어온 이미지 배열에 그대로 사각형을 그려주므로 별도의 이미지 배열에 그림 작업 수행.
draw_img = img.copy()
#opencv는 RGB가 아니라 BGR이므로 빨간색은 (0, 0, 255)
green_color = (0, 255, 0)
red_color = (0, 0, 255)
#파일내에 있는 모든 object Element를 찾음.
objects_list = []
for obj in root.findall('object'):
xmlbox = obj.find('bndbox')
left = int(xmlbox.find('xmin').text
top = int(xmlbox.find('ymin').text
right = int(xmlbox.find('xmax').text
bottom = int(xmlbox.find('ymax').text
class_name = obj.find('name').text
#draw_img 배열의 좌상단 우하단 좌표에 녹색 box로 표시
cv2.rectangle(draw_img, (left, top), (right, bottom), color = green_color, thickness = 1)
#draw_img 배열의 좌상단 좌표에 빨간색으로 class 표시
cv2.putText(draw_img, class_name, (left, top - 5), cv2.FONT_HERSHEY_SIMPLEX, 0.4, red_color, thickness = 1)
img_rgb = cv2.cvtColor(draw_img, cv2.COLOR_BGR2RGB)
plt.figure(figsize=(10, 10))
plt.imshow(img_rgb)
Object Detection에서 굉장히 일반화된 Dataset
80개의 Object Category
300k Image들과 1.5 Million개의 object들, 하나의 image에 평균 5개의 object들로 구성
Tensorflow object detection API 및 많은 오픈 소스 계열의 주요 패키지들은 COCO Dataset으로 Pretrained된 모델을 제공함
COCO Datasetdms 이미지 한 개에 여러 오브젝트들을 가지고 있으며, 타 데이터 세트에 비해 난이도가 높은 데이터를 제공한다.
이미지 파일들
학습용 파일, 검증용 파일, 테스트용 파일이 따로 존재.
이미지들은 모두 jpg format.
JSON Annotation 파일
JSON Format인 한 개의 파일로 구성됨
JSON 파일은 아래와 같은 대분류로 구성됨
info : COCO Dataset 생성 일자 등을 가지는 헤더 정보
license : 이미지 파일들의 라이선스에 대한 정보
images : 모든 이미지들의 id, 파일명, 이미지 너비와 높이 정보
annotations : 대상 image 밒 object id. Segmentation, bounding box, 픽셀 영역 등의 상세 정보.
categories : 80개 오브젝트 카테고리에 대한 id, 이름, group등을 가짐.
PIL (Python Image Library)
Scikit Image
OpenCV
imread()를 이용한 이미지 로딩
OpenCV에서 이미지를 로딩할 때 imread 함수를 사용한다. imread 함수는 파일을 읽어 Numpy Array로 변환한다.
OpenCV에서 imread를 이용할 때 주의할 점은 이미지를 RGB 형태가 아닌 GBR 형태로 읽는다는 것이다.
import cv2
import matplotlib.pyplot as plt
img_array = cv2.imread('파일명')
plt.imshow(img_array)
cvtColor()를 이용하여 BGR을 RGB로 변환
OpenCV에서 imread함수를 이용하여 로딩된 이미지 배열은 BGR 배열이기 때문에 cvtColor 함수를 이용하여 RGB로 변환해주어야 한다.
import cv2
import matplotlib.pyplot as plt
img_array = cv2.imread('파일명')
rgb_img_array = cv2.cvtColor(img_array, cv2.COLOR_BGR2RGB)
plt.imshow(rgb_img_array)
imwrite()를 이용하여 파일에 쓰기
OpenCV에서 메모리에 있는 이미지 배열을 파일에 저장하려면 imwrite 함수를 이용한다. imwrite함수는 이미지 배열을 RGB 형태로 저장한다.
import cv2
import matplotlib.pyplot as plt
img_array = cv2.imread('파일명')
cv2.imwrite('출력파일명', img_array)
OpenCV 영상 처리 개요
OpenCV의 VideoCapture 클래스는 동영상을 개별 Frame으로 하나씩 읽어들이는 기능을 제공한다.
VideoWriter은 Videocapture으로 읽어들인 개별 Frame을 동영상 파일로 Write를 수행한다.
VideoCapture 개요
cap = cv2.VideoCapture(video_input_path)
#영상 frame 너비
cap.get(cv2.CAP_PROP_FRAME_WIDTH)
#영상 frame 높이
cap.get(cv2.CAP_PROP_FRAME_HEIGHT)
#영상 FPS
cap.get(cv2.CAP_PROP_FPS)
while True:
hasFrame, img_frame = cap.read()
if not hasFrame:
print('더 이상 처리할 frame이 없습니다.')
break
VideoWriter 개요
cap = cv2.VideoCapture(video_input_path)
codec = cv2.VideoWriter_fourcc(*'XVID')
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)
vid_writer = cv2.VideoWriter(video_output_path, codec, vid_fps, vid_size)
import cv2
video_input_path = 불러올 영상 경로
video_output_path = 영상 저장 경로
cap = cv2.VideoCapture(video_input_path)
codec = cv2.VideoWriter_fourcc(*'XVID') #codec은 *'XVID'로 설정
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)
vid_writer = cv2.VideoWriter(video_output_path, codec, vid_fps, vid_size)
frame_cnt = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))
OpenCV 영상처리 실습코드
import time
green_color = (0, 255, 0)
red_color = (0, 0, 255)
start = time.time()
index = 0
while True:
hasFrame, img_frame = cap.read()
if not hasFrame:
print('더 이상 처리할 frame이 없습니다.')
break
index += 1
print('frame :', index, '처리 완료')
cv2.rectangle(img_frame, (사각형의 좌표), color = green_color, thickness = 2)
caption = 'frame:{}'.format(index)
cv2.putText(img_frame, caption, (글자 위치 좌표), cv2.FONT_HERSHEY_SIMPLEX, 0.7, red_color, 1)
vid_writer.write(img_frame)
print('write 완료 시간:', round(time.time()-start, 4))
vid_writer.release()
cap.release()