Mat 클래스 객체에 저장된 영상 또는 행렬을 복사하는 가장 간단한 방법은
복사 생성자 또는 대입 연산자를 사용하는 것이다.
Mat img1 = imread("Lenna.bmp");
Lenna.bmp 파일을 불러와 Mat 타입의 변수 img1에 저장한다.
Mat img2 = img1; // 복사 생성자(얕은 복사)
img1 변수에 저장된 레나 영상을 복사하여 img2에 저장한다.
img1과 같은 크기, 같은 타입의 새로운 Mat 객체 img2를 생성하고,
img1의 픽셀 데이터를 img2가 참조하도록 설정한다
즉, img1과 img2는 하나의 영상을 공유하는 서로 다른 이름의 변수 형태로 동작한다.
이처럼 Mat 클래스의 복사 생성자는 행렬의 원소 데이터를 공유하는 얕은 복사(Shallow Copy)를 수행한다.
Mat img3;
img3 = img1; // 대입 연산자(얕은 복사)
Mat 클래스의 대입 연산자도 복사 생성자와 마찬가지로 얕은 복사를 수행한다.
Mat 클래스의 복사와 관련된 함수는 Mat::clone() 과 Mat::copyTo() 함수가 있다.
두 함수 모두 새로 영상을 생성할 때 픽셀 데이터를 공유하는 것이 아니라 메모리 공간을 새로 할당하여
픽셀 데이터 전체를 복사한다.
Mat::clone()
Mat Mat::clone() const;
반환값 : *this 행렬의 복사본
Mat::clone() 함수는 자기 자신과 동일한 Mat 객체를 완전히 새로 만든 후에 반환값을 반환한다.
Mat::copyTo()
void Mat::copyTo(OutputArray m) const;
void Mat::CopyTo(OutputArray m, InputArray mask) const;
m : 복사본이 저장된 행렬이다. *this 행렬과 크기 및 타입이 다르면 메모리를 새로 할당한 후 픽셀 값을 복사한다.
mask : 마스크 행렬이다. 마스크 행렬의 원소 값이 0이 아닌 좌표에서만 행렬 원소를 복사시킨다.
Mat::copyTo 함수는 인자로 전달된 m에 자기 자신을 복사한다.
만약 Mat::copyTo() 함수를 호출한 형렬과 인자로 전달된 행렬 m이 서로 크기와 타입이 같으면 원소 값 복사만 수행하고,
서로 크기 또는 타입이 다르면 Mat::copyTo() 함수 내부에서 행렬 m을 새로 생성한 후 픽셀 값을 복사한다.
코드 작성 방법
Mat img4 = img1.clone();
Mag img5;
img1.copyTo(img5);
img4는 img.clone() 함수에 의해 반환되는 행렬 객체를 저장한다.
변수 img5는 비어 있는 상태로 생성되고, 이후 Mat::copyTo() 함수에 의해
img1 객체에 저장된 영상이 img5로 복사된다.
img4, img5는 각각 픽셀 데이터를 저장할 메모리 공간을 따로 가지고 있고,
img1에 저장된 레나 영상의 복사본을 저장한다.
Mat::clone(), Mat::copyTo() 함수처럼 완전히 메모리 공간을 새로 할당하여 픽셀 값을 복사하는 형태의 복사를
깊은 복사(Deep Copy) 라고 한다.
코드 예제
#include "opencv2/opencv.hpp"
#include <iostream>
using namespace cv;
using namespace std;
void img_copy()
{
Mat img1 = imread("Lenna.bmp"); // img1에 Lenna.bmp 파일 저장
Mat img2 = img1; // img2에 img1 파일 저장 (얕은 복사)
Mat img3; // Mat 타입의 img3 변수 선언
img3 = img1; // img3에 img1 파일 저장 (얕은 복사)
Mat img4 = img1.clone(); // Mat 타입의 img4에 img1 파일 저장 (깊은 복사)
Mat img5; // Mat 타입의 img5 변수 선언
img1.copyTo(img5); // img1 파일을 img5에 저장 (깊은 복사)
img1.setTo(Scalar(0, 0, 0)); // black
imshow("img1", img1); // img1 출력
imshow("img2", img2); // img2 출력
imshow("img3", img3); // img3 출력
imshow("img4", img4); // img4 출력
imshow("img5", img5); // img5 출력
}
int main()
{
img_copy();
waitKey(0);
return 0;
}
실행 결과
img1의 얕은 복사를 수행했던 img2, img2 모두 검은색 화면만 출력됐다.
img1의 픽셀 데이터를 그대로 공유하기 때문에 나타난 결과이다.
img1.setTo(scalar(0, 0, 0); 함수를 사용해 검은색을 출력했다.
img4와 img5는 레나 파일이 정상적으로 출력되었다.
img1의 복사를 수행하였지만, 깊은 복사를 수행하였기 때문에 나타난 결과이다.
즉, 깊은 복사는 픽셀의 데이터를 공유하지 않고, 새로운 메모리에 저장 후 생성한다.
'DevelopmentTool > OpenCV' 카테고리의 다른 글
[OpenCV] Mat 클래스의 픽셀 접근 방법 (0) | 2022.11.17 |
---|---|
[OpenCV] Mat 클래스 ROI 추출 함수 (0) | 2022.11.17 |
[OpenCV] Mat 객체 생성과 초기화 함수 (0) | 2022.11.17 |
[OpenCV] Mat 클래스의 자료형 (1) | 2022.11.17 |
[OpenCV] Mat 클래스 (1) | 2022.11.17 |