▶ 영상 재매핑 처리
오늘은 영상의 화소를 옮겨 영상의 모습을 변경하는 방법에 대해 공부해보자. 화소의 값을 바꾸지 않고 화소의 위치를 새로운 위치에 재매핑 할 것이다. 두 가지를 해볼 것인데 하나는 영상에 물결 효과를 넣는 것이고, 또 다른 하나는 영상을 좌우반전시키는 것이다.
1. 원본 영상 읽기 및 띄우기
2. 원본 영상에 물결 효과 넣기 - cv::remap 함수
3. 원본 영상을 좌우반전시키기 - cv::remap 함수
코드는 아래와 같다.
#include <iostream>
#include <opencv2\core.hpp>
#include <opencv2\highgui.hpp>
#include <opencv2\imgproc.hpp> //cv::remap 함수 사용을 위해 필요
void wave(const cv::Mat &image, cv::Mat &result); // 물결 효과 함수
void flip(const cv::Mat &image, cv::Mat &result); // 좌우반전 함수
int main()
{
cv::Mat before = cv::imread("cathedral.jpg");
cv::imshow("before", before);
cv::Mat after1;
after1.create(before.rows, before.cols, before.type());
wave(before, after1); // 물결 효과
cv::imshow("after1", after1);
cv::Mat after2;
after2.create(before.rows, before.cols, before.type());
flip(before, after2); // 좌우반전
cv::imshow("after2", after2);
cv::waitKey(0);
return 0;
}
void wave(const cv::Mat &image, cv::Mat &result) // 물결 효과 함수
{
// 맵 역할
cv::Mat srcX(image.rows, image.cols, CV_32F);
cv::Mat srcY(image.rows, image.cols, CV_32F);
// 매핑 생성
for (int i = 0; i < image.rows; i++)
{
for (int j = 0; j < image.cols; j++)
{
// 화소 (i, j)의 새로운 위치
srcX.at<float>(i, j) = j; // 열은 그대로 유지
srcY.at<float>(i, j) = i + 10 * sin(j / 10.0); // 원래 있는 i행의 화소를 바로 사인 곡선에 따라 옮김
}
}
// 매핑 적용
cv::remap(image, result, srcX, srcY, cv::INTER_LINEAR);
}
void flip(const cv::Mat &image, cv::Mat &result) // 좌우 반전 함수
{
// 맵 역할
cv::Mat srcX(image.rows, image.cols, CV_32F);
cv::Mat srcY(image.rows, image.cols, CV_32F);
// 매핑 생성
for (int i = 0; i < image.rows; i++)
{
for (int j = 0; j < image.cols; j++)
{
// 화소 (i, j)의 새로운 위치
srcX.at<float>(i, j) = image.cols-j-1; // 열은 좌우가 바뀜 ex) 1번째 열은 마지막 열로, 2번째 열은 (마지막-1)열로,..., 마지막 열은 1번째 열로.
srcY.at<float>(i, j) = i; // 행은 그대로 유지
}
}
// 매핑 적용
cv::remap(image, result, srcX, srcY, cv::INTER_LINEAR);
}
원본 이미지와 결과 이미지들을 살펴보자. 원본 이미지, 물결 효과가 첨가된 이미지, 좌우반전된 이미지 순이다.
▶ 좀 더 알고 넘어갈 것들
1) cv::remap 함수
cv::remap 함수를 사용하기 위해서는 재매핑처리를 위한 x맵과 y맵을 먼저 정의해야 한다. (참고로 cv::remap 함수를 사용하기 위해서는
#include <opencv2\imgproc.hpp>
가 헤더 부분에 선언되어 있어야 한다.) 물결 효과보다는 좌우반전의 경우가 좀 더 간단하니 좌우반전의 코드 부분으로 재매핑처리에 대해서 이해해보자.
// 맵 역할
cv::Mat srcX(image.rows, image.cols, CV_32F);
cv::Mat srcY(image.rows, image.cols, CV_32F);
// 매핑 생성
for (int i = 0; i < image.rows; i++)
{
for (int j = 0; j < image.cols; j++)
{
// 화소 (i, j)의 새로운 위치
srcX.at<float>(i, j) = image.cols-j-1; // 열은 좌우가 바뀜.
srcY.at<float>(i, j) = i; // 행은 그대로 유지
}
}
좌우반전을 위해 행들은 그대로 유지시키고 열들만 변경시켜준다. 첫번째 열은 마지막 열로, 두번째 열은 마지막 하나 전 열로,..., 마지막 열은 첫번째 열로.
x맵과 y맵을 정의한 후에는 매핑을 적용해준다.
// 매핑 적용
cv::remap(image, result, srcX, srcY, cv::INTER_LINEAR);
이전 포스팅 http://bskyvision.com/291에서도 영상의 좌우반전을 소개했었다. 이때는 opencv 라이브러리 내의 cv::flip 함수를 사용했었다.
2) 물결 효과
이미지에 물결 효과를 어떻게 줬는지 좀 더 살펴보자.
// 매핑 생성
for (int i = 0; i < image.rows; i++)
{
for (int j = 0; j < image.cols; j++)
{
// 화소 (i, j)의 새로운 위치
srcX.at<float>(i, j) = j; // 열은 그대로 유지
srcY.at<float>(i, j) = i + 10 * sin(j / 10.0); // 원래 있는 i행의 화소를 바로 사인 곡선에 따라 옮김
}
}
우선 열들은 그대로 유지한다. 그리고 행들은 사인 함수를 이용해서 j의 값에 따라 위 아래로 변동이 있게 만들어 준다. 현재 행의 위치에서 사인 함수 앞에 곱해져 있는 10픽셀 만큼 위 아래로 왔다갔다 하게 될 것이다.
<참고자료>
[1] 로버트 라가니에 지음, 이문호 옮김, "OpenCV를 활용한 컴퓨터 비전 프로그래밍 3/e", 에이콘
'Dev > C, C++' 카테고리의 다른 글
[opencv와 C++로 컴퓨터 비전] 두 개의 영상 가중합하기 (0) | 2018.03.19 |
---|---|
[opencv와 C++로 컴퓨터 비전] 영상 선명하게 만들기 (0) | 2018.03.07 |
[opencv와 C++로 컴퓨터 비전] 영상 내 컬러 개수 감소 (0) | 2018.02.15 |
제가 심심풀이로 만든 저격수 훈련 게임: '아임스나이퍼' (은근 중독성 있음) (18) | 2018.02.06 |
[opencv와 C++로 컴퓨터 비전] 예쁜 타이머 만들기 (타이머 종료시 음악 재생) (6) | 2018.02.02 |
[opencv와 C++로 컴퓨터 비전] 영상에 소금-후추 잡음(salt-and-pepper noise) 넣기 (2) | 2018.02.01 |
[opencv와 C++로 컴퓨터 비전] 영상 위에 로고 넣기 (0) | 2018.01.31 |
[opencv와 C++로 컴퓨터 비전] 영상 위에 그림 그리기 및 글쓰기 (0) | 2018.01.30 |