영상의 산술 및 논리 연산

덧셈 연산

  • 두 영상의 같은 위치에 존재하는 픽셀 값을 더하여 결과 영상의 픽셀 값으로 설정
  • 덧셈의 결과가 255보다 클 경우 픽셀 값을 255로 설정하는 포화 연산을 진행함

image

  • 많은 결과 픽셀들이 두 픽셀의 합으로 인해 완전한 흰색인 255로 표현된 것을 확인할 수 있음

image

void add(InputArray src1, InputArray src2, OutputArray dst, InputArray mask = noArray(), int dtype = -1);
  • src1 : 첫 번째 입력 행렬 또는 스칼라
  • src2 : 두 번째 입력 행렬 또는 스칼라
  • dst : 출력 행렬, dst의 깊이는 src1, src2의 깊이와 같거나 또는 dtype 인자에 의해 결정됨
  • mask : 마스크 영상, mask 행렬 원소 값이 0이 아닌 위치에서만 연산을 수행함
  • dtype : 출력 행렬의 깊이

가중치 합

  • 두 영상의 같은 위치에 존재하는 픽셀 값에 대하여 가중합을 계산하여 결과 영상의 픽셀 값으로 설정
  • 보통 알파와 베타의 합이 1이 되도록 설정함
    • 알파와 베타의 합이 1일 경우에는 saturate안의 값이 0~255 사이의 값이 나오므로 포화 연산까지 안감

image

image

void addWeighted(InputArray src1, double alpha, InputArray src2, double beta, double gamma, OutputArray dst, int dtype = -1);
  • src1 : 첫 번째 입력 행렬
  • alpha : src1 행렬의 가중치
  • src2 : 두 번째 입력 행렬
  • beta : src2 행렬의 가중치
  • gamma : 가중합 결과에 추가적으로 더할 값

image

  • dst : 출력 행렬, 입력 행렬과 같은 크기, 같은 채널 수
  • dtype : 출력 행렬의 깊이

평균 연산

  • 가중치 알파와 베타를 둘 다 0.5로 설정

image

image

평균 연산의 응용

  • 잡음 제거
    • 같은 장면을 여러분 촬영하면 같은 부분에 대하여 다른 값들이 들어가는 경우가 있는데 (어떤 값은 + a, 어떤 값은 -a) 이렇게 들어가는 잡음의 합은 전체적으로 평균이 0으로 동작함
    • 같은 장면을 여러분 촬영해서 노이즈 없는 선명한 영상을 얻을 수 있음

image

  • 아래 사진 같은 경우 건물 아래에 사람과 차들이 많이 돌아다니지만 사람과 차들이 움직이는 어떤 패턴이 긴 시간으로 보면 노이즈로 해당됨
    • 위에 나와있는 건물은 전혀 움직이지 않으므로 건물만 촬영되고 사람과 차는 나타나지 않는 사진으로 결과를 도출할 수 있음

image

뺄셈 연산

  • 두 영상의 같은 위치에 존재하는 픽셀 값에 대하여 뺄셈 연산을 수행하여 결과 영상의 픽셀 값으로 설정
  • 뺄셈 결과가 0보다 작으면 픽셀 값을 0으로 설정하는 포화 연산을 진행함
  • 덧셈 연산과 달리 뺄셈 연산은 영상의 순서에 따라 결과가 달라짐

image

image

void substract(InputArray src1, InputArray src2, OutputArray dst, InputArray mask = noArray(), int dtype =-1);
  • src1 : 첫 번째 입력 행렬 또는 스칼라
  • src2 : 두 번째 입력 행렬 또는 스칼라
  • dst : 출력 행렬, dst의 깊이는 src1, src2의 깊이와 같거나 또는 dtype 인자에 의해 결정됨
  • mask : 마스크 영상, mask 행렬 원소 값이 0이 아닌 위치에서만 연산을 수행함
  • dtype : 출력 행렬의 깊이

차이 연산

  • 두 입력 연산에 대하여 뺄셈 연산을 수행한 후, 그 절댓값을 이용하여 결과 영상을 생성하는 연산
  • 뺄셈 연산과 달리 입력 영상 순서에 영향을 주지 않음

image

  • 영상의 다른 부분(변화된 부분)을 찾기 위해 많이 사용됨
    • 변화가 있는 부분에 대해서만 0보다 큰 값이 나타나고 나머진 0의 값으로 나타남

image

void absdiff(InputArray src1, InputArray src2, OutputArray dst);
  • src1 : 첫 번째 입력 행렬 또는 스칼라
  • src2 : 두 번째 입력 행렬 또는 스칼라
  • dst : 출력 행렬(차영상), 입력 행렬과 같은 크기, 같은 채널 수

image

예제 코드

#include <iostream>
#include "opencv2/opencv.hpp"

using namespace std;
using namespace cv;

int main()
{
	Mat src1 = imread("lenna256.bmp", IMREAD_GRAYSCALE);
	Mat src2 = imread("square.bmp", IMREAD_GRAYSCALE);

	if (src1.empty() || src2.empty()) {
		cerr << "Image load failed!" << endl;
		return -1;
	}

	if (src1.size() != src2.size() || src1.type() != src2.type()) {
		cerr << "The images are different in size or type!" << endl;
		return -1;
	}

	imshow("src1", src1);
	imshow("src2", src2);

	Mat dst1, dst2, dst3, dst4;

	add(src1, src2, dst1); // 덧셈 연산
	addWeighted(src1, 0.5, src2, 0.5, 0, dst2); // 알파와 베타값이 0.5이므로 평균
	subtract(src1, src2, dst3); // 뺄셈 연산
	absdiff(src1, src2, dst4); // 차이 연산

	imshow("dst1", dst1);
	imshow("dst2", dst2);
	imshow("dst3", dst3);
	imshow("dst4", dst4); 
	waitKey();
}
  • 실행결과
    • src2의 검정색은 0이고 하얀색 부분이 255 이므로 src1 와 더하면 흰색은 무조건 255 이상의 값이 되므로 포화 연산 되고 검정색 부분은 0이므로 기존 src1과 같은 값이 나오게 됨
    • dst2는 두 입력 연산의 평균 연산의 값
    • dst3는 dsr1과 반대로 255를 뺏으니 0보다 작아져서 가운데가 검정색으로 되었고 테두리는 0으로 빼서 변화가 없음
    • dst4는 기존 src1에서 흰색인 0을 빼도 같은 값이 나오지만 기존 src1에서 255의 값을 빼고 절댓값을 씌우면 그레이스케일 값이 반전되는 것을 확인

image

행렬의 논리 연산

void bitwise_and(InputArray src1, InputArray src2, OutputArray dst, InputArray mask = noArray());
void bitwise_or(InputArray src1, InputArray src2, OutputArray dst, InputArray mask = noArray());
void bitwise_xor(InputArray src1, InputArray src2, OutputArray dst, InputArray mask = noArray());
void bitwise_not(InputArray src, OutputArray dst, InputArray mask = noArray());
  • src1 : 첫 번째 입력 행렬 또는 스칼라
  • src1 : 첫 번째 입력 행렬 또는 스칼라

  • src : 입력 행렬 또는 스칼라
  • dst : 출력 행렬, 입력 행렬과 같은 크기, 같은 채널 수
  • mask : 마스크 행렬

image

예제 코드

#include <iostream>
#include "opencv2/opencv.hpp"

using namespace std;
using namespace cv;

int main()
{
	Mat src1 = imread("lenna256.bmp", IMREAD_GRAYSCALE);
	Mat src2 = imread("square.bmp", IMREAD_GRAYSCALE);

	if (src1.empty() || src2.empty()) {
		cerr << "Image load failed!" << endl;
		return -1;
	}

	imshow("src1", src1);
	imshow("src2", src2);

	Mat dst1, dst2, dst3, dst4;

	bitwise_and(src1, src2, dst1);
	bitwise_or(src1, src2, dst2);
	bitwise_xor(src1, src2, dst3);
	bitwise_not(src1, dst4);

	imshow("dst1", dst1);
	imshow("dst2", dst2);
	imshow("dst3", dst3);
	imshow("dst4", dst4);
	waitKey();
}
  • 실행 결과
    • src2의 검정색 부분은 0000000 으로 2진수로 표현이 가능하고
    • src2의 흰색 부분은 11111111로 2진수로 표현이 가능함

image