이미지 연산 (+, -)

본 글은 이미지 간 덧셈과 뺄셈에 대해 다룬다. C++로 작성한 OpenCV 코드를 활용한다.


오버랩

먼저 이미지 간 덧셈에 대해 살펴보자. 두 이미지($X$)를 더하면 이미지가 겹쳐진 형태로 표현된다. 하지만 단순히 더하면 값이 범위를 넘어서면서 정보가 손실된다. 이미지 픽셀은 0 ~ 255 범위를 가지기 때문에 255를 넘는 정보는 모두 255로 표현된다. 참고로 정보가 손실된다는 표현이 이해되지 않는다면 saturate에 대해 읽어보자.

따라서 값이 커지는 것을 막기 위해 가중합(weighted sum)을 사용한다.

$$X = \sum{X_i \cdot w_i} + b$$

예를 들어, 이미지 $X_1$와 $X_2$를 더한다면 $0.5X_1 + 0.5X_2$를 할 수 있다. $X_1$ 이미지를 강조하고 싶다면 $X_1$에 곱해지는 가중치를 늘리면 된다.

$b$는 작은 편향 값으로 이미지 특성에 따라 조절할 수 있다. 잘 모르겠다면 명도 조절에 대해 읽어보자.

OpenCV는 값을 더할 때 + 연산자와 addWeighted를 사용한다. 두 방법 모두 saturate(포화) 연산을 지원하기 때문에 쉽게 사용할 수 있다.

using namespace cv;

Mat img1 = imread("man1.jpg");
Mat img2 = imread("man2.jpg");

Mat dst;
// dst = img1 * 0.5 + img2 * 0.5 + 0;
addWeighted(img1, 0.5, img2, 0.5, 0, dst);

imshow("dst", dst);

img1, img2, dst

위 예시는 각 이미지에 0.5의 가중치를 주고, 편향은 0으로 사용하지 않았다.


틀린 그림 찾기

이번에는 뺄셈을 이용해 두 이미지의 차를 구해보자. 두 이미지를 빼면 비슷한 부분은 어둡게, 다른 부분은 밝게 나타난다. 회색조 이미지를 예로 들면, 255와 245의 차는 10으로 검정에 가깝게 표현되지만 255와 20의 차는 235로 흰색에 가깝게 표현된다. 

$$X = | X_1 - X_0 |$$

단순히 두 이미지를 빼고 절댓값을 구한다. - 연산자와 absdiff 모두 saturate(포화) 연산을 지원한다.

using namespace cv;

Mat img1 = imread("desk1.jpg");
Mat img2 = imread("desk2.jpg");

Mat dst;
// dst = abs(img1 - img2);
absdiff(img1, img2, dst);

imshow("diff", dst);

img1, img2, dst

이걸로 틀린 그림 찾기를 풀면 재밌을 것 같다.