우선 Saliency map이란
영상(사진)을 어떤 기준에 따라 분석하기 쉽도록 단순하게 변환하는 것을 말합니다.
쉽게 이야기하면, 한 사진에서 유독 두드러지게 다른 부분이 있다는 가정하에 그 차이를 명확하게 보이도록 하는 것인데... 대표적인 예시로 배경과 물체의 구분이 있습니다. 보통 그 기준으로 평균값을 사용합니다.
파이썬에 경우 opencv에 Saliency map이 존재합니다. 이 함수가 완벽하지는 않지만 꽤 쓸 만 한편이에요. 단 픽셀의 수가 많을수록 -당연하겠지만- 시간이 꽤 걸리는 편입니다. 요즘 나오는 스마트폰 사진을 노트북으로 처리했을 때 거진 2-3초가량이 걸렸어요. 사실 제 컴퓨터가 느려서 그런 거 같기는 한데...(LG 노트북 사용 중)
많이 쓰는 Saliency map의 방식이 궁금한 사람은 위키피디아의 정리를 참고해봐도 좋을것같습니다.
# import the necessary packages
import cv2
import numpy as np
import os
def step1_getarea(image) :
"""
step1-물체의 주변부 찾기
:param image: 물체를 찾을 사진의 이미지
:return res : 찾아낸 물체 사진
"""
#원본 이미지 사진 크기 재조정 할일이 있을 경우 사용
imageHeight, imageWidth = image.shape[:2]
resizeImage = image
# 우리 코드의 핵심 cv2를 이용해 Saliencymap을 계산
saliency = cv2.saliency.StaticSaliencyFineGrained_create()
(success, saliencyMap) = saliency.computeSaliency(resizeImage)
saliencyMap = (saliencyMap * 255).astype("uint8") # 0-1사이의 값을 0-255의 값으로 변환
cv2.imwrite(os.path.join(os.getcwd(),"sailencyMap.jpg"),saliencyMap) #비교를 위해 저장
# the saliency map에 추가적으로 threshold 과정을 넣어준다.
threshMap = cv2.threshold(saliencyMap.astype("uint8"), 0, 255,
cv2.THRESH_BINARY | cv2.THRESH_OTSU)[1]
cv2.imwrite(os.path.join(os.getcwd(),"thresholdMap.jpg"),threshMap) #비교를 위해 저장
# 이진화 이미지의 윤곽선을 검색
# cv2.findContours(이진화 이미지, 검색 방법, 근사화 방법) return 윤곽선, 계층 구조
contours, hierachy = cv2.findContours(threshMap, cv2.RETR_LIST, cv2.CHAIN_APPROX_NONE)
area, output = 0, contours[0]
#가장 큰 윤곽선을 찾는 과정
for cnt in contours:
if (area < cv2.contourArea(cnt)):
area = cv2.contourArea(cnt)
output = cnt
# 근사치 구하기
epsilon = 0.02 * cv2.arcLength(output, True)
approx = cv2.approxPolyDP(output, epsilon, True)
#찾은 물체의 근사치 좌표 구하기
x, y, w, h = cv2.boundingRect(approx)
rx = x
ry = y
if (x > 30):
rx = x - 30
if (y > 100):
ry = y - 100
#사진 자르기
dst = resizeImage[ry:y + h + 100,rx:x + w + 100] # NOTE: its img[y: y + h, x: x + w] and *not* img[x: x + w, y: y + h]]
return dst
위 코드는 파이썬의 opencv를 이용한 Saliency map의 간단한 예제입니다. 사실 위의 코드로 처리하기 어려운 여러 예외상황들이 있습니다. 완벽한 영상처리라는 건 정말 어려운 일이에요.
드에서 몇단계를 더 지나서 최종적으로 아래의 사진을 얻어내는 게 제 코드의 목표였습니다. 물체와 배경의 분리가 간단해 보이는 첫 단계이지만 사실 실제로 해보니 그렇게 간단하기만 한 일은 아니었어요.
요즘 AI 및 머신러닝 같은 부분들이 유행한 지 시간이 좀 지났는데, 그런 부분들이 영상처리에서 큰 활약을 하고 있죠. 슬금슬금 공부해두면 좋을 거 같습니다.
'IT' 카테고리의 다른 글
[JavaScript] let과 var 그리고 const의 차이점 (0) | 2021.05.11 |
---|---|
[VI] 리눅스환경 vi, vim에서 ^M 제거 하기 (0) | 2021.05.07 |
[shell] 파일에서 테이블 리스트 읽어 행의 수(row수)를 세는 shell script만들어보기 (0) | 2021.05.03 |
구글의 텐서플로우 자격증 시험 후기 (0) | 2021.02.12 |
[Linux] 리눅스 주요 명령어 (0) | 2020.09.02 |