2013년 1월 6일 일요일

OpenCV #2-7 Example (관심 영역 정의)

 - 서로 다른 크기를 갖는 영상을 합칠 때 사용
 - cv::add 함수는 두 영상이 같아야 한다는 전제가 있었음.
 - 이번 경우에는 관심 영역 ROI(Region Of Interest)를 정의해 cv::add 함수에 적용할 수 있다.
 - 로고와 같은 크기를 갖는 ROI를 갖고 그대로 작업.
 - 영상 내 ROI의 위치가 결정되면 로고가 삽입된다.


  • Example
#include <iostream>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>

int main()
{
cv::Mat image = cv::imread("FlowerWar.jpeg");
cv::Mat logo = cv::imread("logo.jpg");

cv::namedWindow("Image");
cv::imshow("Image", image);

cv::namedWindow("Logo");
cv::imshow("Logo", logo);

cv::Mat imageROI = image(cv::Rect(410, 250, logo.cols, logo.rows));
// 영상 ROI 정의
// Rect는 사각형 영역 지정
// 410, 270은 각각 logo의 x좌표, y좌표 시작지점
// logo.cols, logo.rows는 로고의 끝지점
cv::addWeighted(imageROI, 1.0, logo, 0.3, 0., imageROI);
// 영상에 로고 붙이기
// imageROI = 1.0*imageROI + 0.3*logo + 0

cv::namedWindow("imageROI");
cv::imshow("imageROI", image);

cv::waitKey(0);

return 0;
}

  • Result

 - 로고의 컬러는 영상의 컬러에 더해지기 때문에(새추레이션 적용 - cv::saturate_cast 함수의 알고리즘이며 0미만을 0으로, 255이상을 255로 강제 변환하는 기법) 시각적인 결과는 항상 만족스럽지 못함.
 - 로고 영역이 있는 영상의 화소값을 로고 값으로 간단히 설정하는 것이 나을 수 있는데, 마스크를 사용해 로고를 ROI에 복사한다.

 - 소스
#include <iostream>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>

int main()
{
cv::Mat image = cv::imread("FlowerWar.jpeg");
cv::Mat logo = cv::imread("logo.jpg");

cv::Mat imageROI = image(cv::Rect(410, 250, logo.cols, logo.rows));
// 영상 ROI 정의
// Rect는 사각형 영역 지정
// 410, 270은 각각 logo의 x좌표, y좌표 시작지점
// logo.cols, logo.rows는 로고의 끝지점
cv::Mat mask = cv::imread("logo.jpg", 0);
// 마스크를 불러들이기 (그레이레벨 영상이어야 함)
logo.copyTo(imageROI, mask);
// 마스크를 ROI에 복사 (참조가 아닌 복사)

cv::namedWindow("imageROI");
cv::imshow("imageROI", image);

cv::waitKey(0);

return 0;
}

 - 결과

  • 예제 분석

 - ROI를 정의하는 한가지 방법은 cv::Rect 인스턴스를 사용하는 것.
 - cv::Rect(410, 250, logo.cols, logo.rows)에서 보듯 왼쪽 상단 모서리(생성자의 첫 두 가지 파라미터)의 위치와 사각형 크기(마지막 두 가지 파라미터인 너비와 높이)로 지정한 사각형 영역을 기술.

 - ROI는 행렬의 범위를 사용해 만들 수 있음 (cv::Range 구조체를 사용)
 - cv::Mat imageROI = image(cv::Range (250, 250+logo.rows), cv::Range (410, 410+logo.cols))

 - 소스
#include <iostream>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>

int main()
{
cv::Mat image = cv::imread("FlowerWar.jpeg");
cv::Mat logo = cv::imread("logo.jpg");

cv::Mat imageROI = image(cv::Range (250, 250+logo.rows), cv::Range (410, 410+logo.cols));
// cv::Range 구조체를 사용해서 영상 ROI 정의
cv::Mat mask = cv::imread("logo.jpg", 0);
logo.copyTo(imageROI, mask);

cv::namedWindow("imageROI");
cv::imshow("imageROI", image);
cv::waitKey(0);
return 0;
}

 - cv::Mat의 operator()는 다른 cv::Mat 인스턴스를 반환, 부분 시퀀스를 호출할 때 사용.
 - ROI에 임의 변환을 가하면 원본 영상의 일치되는 영역에 영향을 미친다. (영상과 ROI는 같은 영상 데이터를 공유)
 - ROI를 정의할 땐 복사하지 않으므로 상수 시간에 실행될 뿐 ROI 크기와 관계 없다.

 - 영상의 일부 행으로 만든 ROI를 정의할 경우 다음과 같이 사용해 호출
 - cv::Mat imageROI = image.rowRange(start, end);
 - 마찬가지로 영상의 일부 열로 만든 ROI라면 다음과 같다.
 - cv::Mat imageROI = image.colRange(start, end);
 - 시작과 마지막 첨자를 지정하면 단일 행 또는 단일 행 ROI를 정의한 것과 동일.

  • 참고문헌 : OpenCV 2 Computer Vision Application Programming Cookbook