2018-01-31 11:28:08

▶ 영상에 로고 넣기


오늘은 영상에 로고 넣기를 해볼 것이다. 영상을 넣어줄 이미지와 로고는 각각 다음과 같다. 참고로 사진의 주인공은 천진대학교에 방문한 아빠..ㅎㅎ 로고는 천진대학교 로고이다. 




코드는 아래와 같은 내용으로 구성되어 있다. 


1. 로고를 넣을 영상 읽기

2. 로고 영상 읽기

3. 로고 영상 그레이 레벨로 읽기

4. 로고를 넣을 영상 및 로고 영상 사이즈 콘솔에 출력

5. 로고를 넣어줄 위치, 즉 관심영역(ROI) 설정 

6. 로고 흑백 영상을 마스크로 사용해서 로고를 ROI에 삽입


코드는 아래와 같다. 주석을 참고하자. 


#include <iostream>

#include <opencv2\core.hpp>

#include <opencv2\highgui.hpp>


int main()

{

cv::Mat father = cv::imread("father.jpg"); // 로고를 넣어줄 영상 읽기

cv::Mat logo = cv::imread("TJU_logo1.jpg"); // 로고 영상 읽기

cv::Mat logo_gray = cv::imread("TJU_logo1.jpg", CV_LOAD_IMAGE_GRAYSCALE); // 로고 영상 그레이 레벨로 읽기, 마스크로 사용하기 위해서


std::cout << "image size:"<< father.rows <<" x " << father.cols << ", logo size:" << logo.rows << " x " <<logo.cols << std::endl; // 로고 넣어줄 영상 및 로고 영상 사이즈 출력


cv::Mat imageROI(father, cv::Rect(father.cols - logo.cols, father.rows - logo.rows, logo.cols, logo.rows)); // 영상의 오른쪽 하단에서 영상 관심영역 (ROI) 정의 


cv::Mat mask(120 - logo_gray); // '120 - 로고 그레이 영상'을 마스크로 사용


logo.copyTo(imageROI, mask); // 마스크 값이 0이 아닌 위치에만 로고를 ROI에 삽입(로고의 흰 배경을 없애기 위한 방법)


cv::imshow("Image", father);  // 로고가 들어간 영상 전시

cv::waitKey(0);


return 0;

}


실행결과 아래와 같은 이미지가 출력된다. 로고가 영상 우측 하단에 삽입된 것을 확인할 수 있다. 원래 로고의 배경색이 흰색인데 흰색이 사라진 것에 주목하자. 



이미지 사이즈와 로고 사이즈는 아래와 같다. 




▶ 좀 더 알고 넘어갈 것들


1) 관심영역(ROI) 정의 관련


ROI는 region of interest의 약어로 관심영역을 뜻한다. 로고를 넣어줄 위치를 결정하기 위해서 ROI를 정의하는 것이 필요하다. 우리는 영상의 우측 하단에 로고를 넣어주기 위해서 관심 영역을 아래와 같이 코딩했다. 


cv::Mat imageROI(father, cv::Rect(father.cols - logo.cols, father.rows - logo.rows, logo.cols, logo.rows)); 


이 줄을 해석하면, father이라는 영상에서 직사각형(cv::Rect)의 ROI을 정의하는데, 그 직사각형의 왼쪽 상단 점의 위치는 father영상에서 (father영상의 가로 길이 - logo영상의 가로 길이, father영상의 세로 길이 - logo영상의 세로 길이)이고, 이 직사각형의 가로 길이는 logo의 가로 길이이고 세로 길이는 logo의 세로길이이다. 그니까 영상 우측 하단에 로고 크기 만큼의 ROI를 설정한 것이다. 



2) 마스크 설정 및 마스크를 활용한 로고 삽입 관련


아까 말했다시피 로고 영상의 배경색은 흰색이었다. 그래서 관심 영역을 설정한 후에 바로 거기에 로고를 삽입하면 그 배경색까지 그대로 삽입되어 버린다. 이런 식으로.. 



내 눈에는 별로 만족스럽지가 않다. (이게 더 마음에 드는 사람도 있겠지만.) 저 흰 배경을 없애주려면 마스크를 설정해주는 것이 필요하다. 


로고 영상을 그레이 스케일로도 읽은 이유가 여기에 있다. 그레이 스케일에서 흰색 배경은 255에 가까운 화소값들을 갖는다(참고로 검은색은 0에 가깝다). 지금 이 로고에서 흰 배경은 정확하게 255는 아니다. 


cv::Mat mask(120 - logo_gray);


그래서 위의 코드와 같이 120 - logo_gray을 해주면 흰 배경 부분은 다 0이 되어버리고, 나머지 푸른 색의 로고 부분만 0이 아닌 다른 숫자들을 갖게 된다. 로고 그레이 영상의 픽셀값들은 CV_8U, 즉 부호가 없는 8비트이기 때문이다. 120을 넘는 픽셀들은 모두 0이 되어버린다. 120은 몇차례 시행을 통해 괜찮은 값을 찾은 것이다. 로고에 따라 다른 수로 설정할 수 있다. 


logo.copyTo(imageROI, mask);


마스크를 이용해서 관심영역에 로고를 삽입하는데, 마스크의 값이 0이 아닌 위치에서만 로고가 삽입된다. 즉, 흰색 배경부분은 삽입되지 않는다. 




<참고자료>

[1] 로버트 라가니에 지음, 이문호 옮김, "OpenCV를 활용한 컴퓨터 비전 프로그래밍 3/e", 에이콘