Mat 기본 이미지 컨테이너 - gonft/OpenCVApple GitHub Wiki
목적
디지털 카메라, 스캐너, CT(컴퓨터 단층 촬영), MRI(자기 공명 영상)과 같은 여러가지 방법으로 실제 세계에서 디지털 이미지를 수집 할 수 있습니다. 사실 실제 우리가 눈으로 보는 이 모든 이미지를 디지털 장치로 변환 할때 이미지의 각 점(픽셀)에 대한 숫자 값이 기록됩니다.
예를 들어 위의 이미지에서 자동차의 사이드 미러는 각 픽셀 포인트의 모든 강도 값을 포함 하는 하나의 행렬에 불과하다는 것을 알 수 있습니다. 픽셀 값을 얻고 저장하는 방법은 필요에 따라 다를 수 있지만 결국 컴퓨터 세계의 모든 이미지는 수치 행렬 및 행렬 자체를 설명하는 다른 정보로 축소 될 수 있습니다. OpenCV는 이 정보를 처리하고 조작하는 것이 주된 목표인 컴퓨터 비전 라이브러리 입니다. 따라서 가장 먼저 익숙해져야 할 것은 OpenCV가 이미지를 저장하고 처리하는 방법입니다.
Mat
C언어 기반을 중심으로 인터페이스가 구축되어 있던 OpenCV 라이브러리 버전에서는 메모리에 이미지를 저장하기위해 IplImage라는 C언어의 구조체를 사용하였습니다. 이것은 대부분의 오래된 자습서 및 교육자료에서 볼수 있는 것 입니다. 이것의 문제점은 C언어의 마이너스 요인을 가져온다는 것이며, 가장 큰 문제는 수동 메모리 관리입니다. 사용자가 메모리 할당 및 할당 해제를 담당한다는 가정하에 코드가 작성되기 때문에 작은프로그램에서는 문제가 되지 않지만 코드베이스가 커지면 개발 목표를 해결하는 데 집중하는 것이 아니라 C언어가 가진 모든 문제를 처리하느라 어려울 것입니다.
운이 좋게도 C++은 자동 메모리 관리를 통해 사용자가 보다 쉽게 클래스를 만드는 개념을 도입했습니다. 좋은 소식은 C++이 C와 완벽하게 호환되므로 변경시 호환성 문제가 발생할 수 없다는 것입니다. 따라서 OpenCV 2.0은 새로운 C++인터페이스를 선보였습니다. 이 인터페이스는 메모리 관리를 할 필요가 없으며 코드를 간결하게 만듭니다. C++ 인터페이스의 가장 큰 단점은 현재 많은 임베디드 개발 시스템이 C만 지원한다는 것입니다. 따라서 임베디드 플랫폼을 목표로하지 않는 한 오래된 방법을 사용할 필요가 없습니다.
Mat에 관해 알아야 할 첫 번째 사항은 더 이상 수동으로 메모리를 할당하고 더 이상 필요하지 않을때 수동으로 해제 할 필요가 없다는 것입니다. 이 작업을 수행하는 것은 여전히 가능하지만 대부분의 OpenCV 기능은 출력 데이터를 자동으로 할당합니다. 좋은 보너스로 만일 이미 존재하는 Mat 객체를 무시하고 필요한 공간을 이미 할당한 행렬을 전달하면 Mat은 재사용됩니다. 즉 우리는 작업을 수행하는데 필요한만큼의 메모리만 사용합니다.
Mat 객체는 기본적으로 두 개의 데이터 파츠를 가지고 있습니다. 행렬헤더(행렬의 크기, 저장에 사용된 방법, 주소가 저장된 행렬 참조 등) 및 행렬을 포함하는 행렬에 대한 포인터 픽셀 값 (저장하기 위해 선택한 방법에 따라 임의의 차원을 취함). 행렬 헤더 크기는 일정하지만 행렬 자체의 크기는 이미지마다 다를 수 있으며 일반적으로 크기 순서에 따라 더 큽니다.
OpenCV는 이미지 처리 라이브러리입니다. 여기에는 많은 이미지 처리 기능이 포함되어 있습니다. 계산상의 문제를 해결하기 위해 대부분의 경우 라이브러리의 여러 기능을 사용하게 될 것입니다. 이 때문에 이미지를 함수에 전달하는 것이 일반적입니다. 꽤 계산량이 많은 이미지 처리 알고리즘에 대해 이야기하고 있다는 것을 잊지 말아야 합니다. 마지막으로 우리가하고 싶은 일은 잠재적으로 큰 이미지를 불필요하게 복사하여 프로그램의 속도를 더욱 낮추는??? 것입니다.
이 문제를 해결하기 위해 OpenCV는 참조 계산 시스템을 사용합니다. 아이디어는 각 Mat 객체가 고유한 헤더를 가지고 있지만 행렬은 행렬 포인터가 동일한 주소를 가리킴으로써 두 인스턴스간에 공유 될 수 있습니다. 또한 복사 작업자는 데이터 자체가 아니라 큰 행렬에 대한 헤더와 포인터만 복사합니다.
Mat A, C; // 단순히 새로운 헤더들만 만들어냅니다.
A = imread(argv[1], IMREAD_COLOR); // A Mat Object에 행렬을 할당하는 메소드를 사용합니다.
Mat B(A); // 복사생성자를 사용 (헤더만 새로 생성된다, 매트릭스는 동일하게 참조)
C = A; // 할당 연산자 사용 (헤더만 새로 생성된다, 매트릭스는 동일하게 참조)
위의 모든 객체는 결국 동일한 단일 데이터 행렬을 참조합니다. 그러나 헤더는 서로 다르며 그 중 하나를 사용하여 수정하면 다른 모든 헤더에도 영향을 미칩니다. 실제로 서로 다른 객체는 동일한 기본 데이터에 다른 엑세스 방법을 제공합니다. 그럼에도 불구하고 그들의 헤더 부분은 다릅니다. 가장 흥미로운 부분은 전체 데이터의 하위 섹션만을 참조하는 헤더를 만들 수 있다는 것입니다. 예를들어 이미지에서 관심 영역(ROI:Region of Interest)을 만들려면 새 바운더리를 가지고있는 새로운 해더를 만듭니다.
Mat D (A, Rect(10, 10, 100, 100) ); // using a rectangle
Mat E = A(Range::all(), Range(1,3)); // using row and column boundaries
이제 우리는 행렬 자체가 더이상 필요하지 않을 때 정리 작업을 담당하는 여러 Mat 객체에 속할 수 있는지 물어 볼 수 있습니다. 짧게 대답하면 그것을 사용한 마지막 객체 입니다. 이것은 참조 카운팅 메커니즘을 사용하여 처리됩니다. 누군가 Mat 객체의 헤더를 복사 할 때마다 행렬에 대한 참조 카운터가 증가합니다. 헤더가 정리 될 때마다 카운터가 감소합니다. 카운터가 0에 도달하면(더 이상 어디서도 참조하지 않는 다는 의미) 행렬도 해제됩니다. 때로는 행렬 자체도 복사하려고하므로 OpenCV는 cv::Mat::clone()
및 cv::Mat::copyTo()
함수를 제공합니다.
Mat F = A.clone();
Mat G;
A.copyTo(G);
이제 Mat 객체 F
또는 G
를 수정해도 Mat 헤더가 가리키는 행렬에는 영향을 주지 않습니다. 이 모든 것에서 기억해야할 사항은 다음과 같습니다.
- OpenCV 기능에 대한 출력 이미지 할당은 자동입니다 (별도로 지정하지 않는 한).
- OpenCV C++ 인터페이스로 메모리 관리에 대해 생각할 필요가 없습니다.
- 할당 연산자(
=
)와 복사생성자(Mat B(A)
)는 헤더 만 복사합니다. - 이미지의 기본 행렬은
cv::Mat::clone()
및cv::Mat::copyTo()
함수를 사용하여 복사 할 수 있습니다.
강력한 메서드들
이것은 픽셀 값을 저장하는 방법입니다. 사용된 색상 공간과 데이터 유형을 선택할 수 있습니다. 색상 공간은 주어진 색상을 코딩하기 위해 색상 구성 요소를 결합하는 방법을 나타냅니다. 가장 단순한 것은 그레이 스케일입니다.
다채로운 방법을 위해 우리는 훨씬더 다양한 메소드들을 선택할수 있습니다. 평범하게는 RGB와 Alpha(A)가 추가된 RGBA가 있고 이밖에 각기 다른 장점을 가진 다른 여러 컬러 스페이스들도 있습니다.
이해하기 쉽게 아래의 이미지링크를 참조하였습니다 클릭하면 위키로 이동합니다.
OpenCV 표준 디스플레이 시스템은 RGB 컬러 스페이스입니다.
YCrCb는 널리 사용되는 JPEG 이미지 형식에서 사용됩니다.
cie Lab*는 지각 적으로 균일한 색상 공간으로, 주어진 색상과 다른 색상의 거리를 측정해야하는 경우 편리합니다.
명시적으로 Mat객체 생성하기
아래 예제를통해 여러가지 방법으로 Mat객체를 만드는것을 학습합니다.
예제보기