open-cv 영상처리

opencv 사진 합성

hojung 2021. 6. 18.
728x90
반응형

 

opencv는 이미지나 영상을 다룰 수 있게 해주는 라이브러리다. 오늘은 포토샵이나 사진 편집 툴이 아닌 그 툴들이 어떻게 이미지나 영상을 합성하고 다루는 지에 대해서 들여다 볼 것이다.

 

이미지를 픽셀 단위로 연산하는 함수들은 여러가지가 있다.

대표적으로

bitwise_and(and는 두 개의 operand들이 모두 1이어야 1이 된다.)

bitwise_or(or는 두 개의 operand 중 하나만 1이어도 1이 된다.)

여기서 1이라는 뜻은 픽셀 값이 0이 아니라는 것이다. 즉 , 검정색이 아니라는 것이다. 이 것은 흑백 사진에서 해당된다.

bitwise_and함수에서는 검정색인 부분이 우선 순위를 갖는다.

bitwise_or 함수에서는 검정색이 아닌 부분들이 우선 순위를 갖는다.

또한 픽셀의 값을 더해서 출력해주는 add 함수

픽셀의 값을 빼서 출력해주는 subtract와 같은 함수가 있다.


2. 이미지 합성

 

이미지를 합성하는 것에는 크게 두가지 경우가 있다.

하나는 같은 크기의 이미지를 전체적으로 합성하는 경우이다.

다른 하나는 다른 크기의 이미지가 있다면 작은 이미지를 큰 이미지에 로고처럼 삽입하는 경우이다.

 

1. 같은 크기의 이미지를 전체적으로 합성하는 경우

이 때 주의할 점은 두 이미지의 크기가 같아야한다는 것이다.

따라서 resize함수를 통해 합성할 이미지의 크기를 동일하게 해준다. Mat클래스의 변수인 cols와 rows를 통해 사이즈에 접근할 수 있다.

 

Mat src_img4 = imread("img3.jpg", 1);//화성
Mat src_img5 = imread("img4.jpg", 1);//비네팅
resize(src_img5, src_img5, Size(src_img4.cols, src_img4.rows));//이미지 사이즈 재설정

두 개의 사이즈를 맞춰주었다면 이제는 정말 간단한데

add나 subtract함수를 이용해서 새로운 Mat 변수에 합성본을 저장하는 것이다.

add 함수는 픽셀 값을 더해주므로 대체로 밝아지고 subtract는 픽셀 값을 빼주므로 어두워진다.

Mat dst1;//이미지 저장할 Mat 
subtract(src_img4, src_img5, dst1);

 

3. 이미지 합성 3

이번에는 다른 크기의 사진을 합성해 볼 것이다. 대체로 큰 이미지 위에 작은 이미지가 들어가므로 우리는 mask라는 개념이 필요하다.

나는 다음 아래의 두 개 이미지를 합성할 것이다.

대표사진 삭제

사진 설명을 입력하세요.

대표사진 삭제

사진 설명을 입력하세요.

mask란 큰 이미지 위에 작은 이미지가 들어갈 수 있도록 구멍을 뚫는 역할을 하는 것이다. 실제로 마스크를 보면 눈 ,코, 입 구멍이 뚫려 있지 않은가 그것과 비슷한 이치이다.

 

서로 다른 크기의 이미지를 합성하기 위해서는 다음과 같은 단계가 필요하다.

 

1. 큰 이미지 위에 관심영역(roi)를 잡는다.

roi란 큰 이미지 위에 작은 이미지가 합성될 위치를 의미한다.

Mat roi; // 관심영역 roi = src_img4(Rect(Point(400, 400), Point(1000 ,600))); // roi를 설정할 때는 이미지의 크기를 고려해야한다.

 

roi를 설정할 때 주의할 점은 작은 이미지의 크기를 고려해주어야 한다는 것이다. 아마 이 크기를 맞춰주지 않고 진행했다면 abort() has been called 오류를 맞이했을 것이다.

 

2. 작은 이미지의 graymask를 만든다.

합성될 작은 이미지를 grayscale로 읽어온다.

Mat graymask = imread("img5.jpg", IMREAD_GRAYSCALE); resize(graymask, graymask, Size(600, 200)); // mask사이즈를 roi영역과 맞춰준다.

 

grayscale로 읽어온 이유는 이를 이진화 시키기 위함이다. 이진화란 일정한 픽셀 값을 기준으로 작은 픽셀들은 0으로 만들고 큰 픽셀들은 255(흰색)으로 만드는 것이다.

또한 mask사이즈를 roi영역과 맞춰준다.

 

Mat blackmask; // 글자색이 검정인 마스크 Mat whitemask; // 글자색이 하얀색인 마스크 Mat blackmaskc3; // flag를 color로 바꾼 blackmask Mat whitemaskc3; // flag를 color로 바꾼 whitemask

 

로고를 합성하는 데에는 참 많은 마스크들이 필요하다. 우선 우리가 집어넣고 싶어하는 로고는 검정색 배경은 흰색인 마스크 그 반대인 마스크 , 우리가 처음 mask를 grayscale로 불러왔기에

컬러 이미지와의 연산이 불가능하다.

따라서 위 두 개의 마스크를 컬러 이미지로 바꾼 두 개의 마스크이다.

threshold(graymask, blackmask, 0, 255, THRESH_OTSU); // 그레이 스케일 이미지 이진

 

graymask를 이진화 시켜 만든 black마스크이다. 이 때 THRESH_OTSU알고리즘에 의해 로고모양대로 0과 255로 픽셀 값을 통일 시킨다.

그렇다면 다음과 같은 mask가 생성된다.

대표사진 삭제

사진 설명을 입력하세요.

이 것을 반전시킨 whitemask는 bitwise_not함수를 이용해 만들 수 있다.

bitwise_not(blackmask, whitemask); // black마스크를 반전시키면 whitemask

대표사진 삭제

사진 설명을 입력하세요.

또한 이 들은 grayscale의 이미지들이므로 위의 컬러 사진들과의 연산이 불가능하다. 따라서 colorscale로 바꾸어주는 cvtColor함수를 이용해서 mask를 만들어준다.

cvtColor(blackmask, blackmaskc3, COLOR_GRAY2BGR); // 컬러 스케일로 전환 cvtColor(whitemask, whitemaskc3, COLOR_GRAY2BGR); // 컬러 스케일로 전환

 

다음과 같이 마스크를 얻었으면 이제 활용해주어야한다.

아까 설정해 둔 roi영역과 blackmask를 더해 새로운 Mat 인스턴스 roiblack에 저장해준다.

Mat roiblack; // 영역과 black마스크를 합침 Mat roiwhite; // roiblack에다 whitemaskc3을 합침 roi.copyTo(roiblack, blackmask);//roi와 blackmask는 크기가 같음

 

copyto함수를 이용한다.

roiwhite = whitemaskc3 + roiblack; // 0+하얀색은 하얀색임을 이용

 

roiwhite는 roiblack에 whitemaskc3을 더한 것이다. whitemaskc3는 whitemask와 동일하게 글자만 하얀색이고 나머지 배경은 검정색이기에 글자 부분을 제외한 나머지에는 영향을 미치지 않는다.

대표사진 삭제

roiblack

대표사진 삭제

roiwhite

우리가 검정색과 하얀색 두 가지의 마스크를 만든 건 우선 글자를 검정으로 만들어 픽셀 값을 0으로 만들어주고 그 위에 + 연산자를 사용하여 글자를 하얀색으로 만들어준 후 &연산자를 이용하기 위함이다.

컬러 사진에서 하얀색 & 어떤색 = 어떤 색이기 때문이다.

Mat roiclone; // roi영역에 로고를 넣은 모습 roiclone = roiwhite & src_img6; // 하얀색 & 어떤색 = 어떤색

따라서 Mat 인스턴스를 설정해주고 그 곳에 원본 이미지와 roiwhite를 & 연산한 결과를 넣어주면 다음과 같은 결과가 나온다.

대표사진 삭제

사진 설명을 입력하세요.

이제 이 이미지를 원본 이미지의 roi 영역에 다시 붙여넣기만 하면 끝이다.

 

728x90
반응형

'open-cv 영상처리' 카테고리의 다른 글

opencv C++ BandPass Filter  (2) 2022.03.24
opencv c++ sobel filter  (0) 2022.03.23
opencv c++ 가우시안 필터  (0) 2022.03.23
opencv spread salt  (0) 2021.06.18

댓글