3. 행렬의 복사
// 메모리 공간을 새로 할당하여 픽셀 데이터 전체를 복사 ( 깊은복사 )
Mat Mat::clone() const;
void Mat::copyTo( OutputArray m ) const;
void Mat::copyTo( OutputArray m, InputArray mask ) const;
- clone() 함수는 자기 자신과 동일한 Mat 객체를 완전히 새로 만들어서 반환
- clone() 함수의 반환값은 *this 행렬의 복사본
- copyTo() 함수는 인자로 전달된 m 행렬에 자기 자신을 복사함.
- 함수를 호출한 행렬과 인자로 전달된 행렬 m이 서로 크기와 타입이 같으면 원소 값 복사만 수행
- 함수를 호출한 행렬과 인자로 전달된 행렬 m이 서로 크기와 타입이 다르면 copyTo() 함수 내부에서 행렬 m을 새로 생성한 후 픽셀 값을 복사
- m값은 복사본이 저장될 행렬, mask는 마스크 행렬을 의미.
- 완전히 메모리 공간을 새로 할당하여 픽셀 값을 복사하는 형태의 복사를 깊은복사라고 함.
4. 부분 행렬 추출
// 저장된 영상에서 사각형 모양의 부분 영상 추출하는 방법
// Mat 클래스에 정의된 괄호 연산자 재정의
Mat Mat::operator()(const Rect& roi) const;
Mat Mat::operator()(Range rowRange, Range colRange) const;
- roi : 사각형 관심 영역
- rowRange, colRange : 관심 행, 열 범위
- 반환값은 추출한 부분 행렬 또는 영상.
- 영상 추출 예시 )
Mat img1 = imread("cat.bmp");
Mat img2 = img1(Rect(220, 120, 340, 240);
- 부분 영상 추출 시 주의할 점으로는 픽셀 데이터를 공유하는 얕은 복사 형식이라는 점이다. 이 때문에 부분 영상 추출 후 부분 영상의 픽셀 값을 변경할 경우 추출한 부분 영상뿐 아니라 원본 영상의 픽셀 값도 같이 변경됨.
- 얕은 복사 형식이라는 점때문에 입력 영상에 사각형 모양의 관심 영역(ROI)을 설정하는 용도로 사용 가능.
- ROI : 영상의 전체 영역 중 특정 영역에 대해 영상 처리를 수행할 때 설정하는 영역
- 만약 독립된 메모리 영역 확보하여 부분 영상 추출하고자 한다면, 괄호 연산자 뒤에 Mat::clone() 함수를 함께 사용.
// clone() 함수를 사용하여 독립적인 공간을 사용하게 됨.
// 서로 다른 메모리 공간을 사용하기 때문에 img3 영상 픽셀 변경해도 img1의 변화는 x
Mat img3 = img1(Rect(220, 120, 340, 240)).clone();
// Mat 행렬에서 특정 범위의 행 또는 열을 부분 행렬로 추출할 때
Mat Mat::rowRange(int startrow, int endrow) const;
Mat Mat::rowRange(const Range& r) const;
Mat Mat::colRange(int startcol, int endcol) const;
Mat Mat::colRange(const Range& r) const;
// 하나의 행 또는 열을 추출하여 1행 또는 1열짜리 행렬을 만들고자 할 때
Mat Mat::row(int y) const;
Mat Mat::col(int x) const;
- 모두 부분 행렬을 얕은 복사 형태로 반환하기 때문에 깊은 복사를 하려면 clone() 함수와 함께 써야함.
5. 행렬의 원소 값 참조
OpenCV에서 제공하는 세 가지 픽셀 값 접근 방법
1) Mat::at() 함수
// Mat::at() 함수
template<typename_ Tp> _Tp& Mat::at(int y, int x)
- 가장 직관적 행렬 원소 접근 방법
- 행과 열 2개의 정수를 인자로 받음.
- 해당 위치의 행렬 원소값을 참조 형식으로 반환.
- 예시)
Mat mat1 = Mat::zeros(3,4,CV_8UC1); // mat1은 0으로 초기화된 3x4 행렬, 각원소는 uchar 자료형
for (int j=0; j<mat1.rows; j++) { // 행에 대한 반복
for (int i=0; i<mat1.cols; i++) { // 열에 대한 반복
// at() 함수가 행렬 원소를 참조로 반환하기 때문에 at() 함수의 반환값 변경 시, mat1 행렬 원소값도 함께 변경.
mat1.at<uchar>(j, i)++; // 자료형 명시
}
}
2) Mat::ptr() 함수
// Mat::ptr() 함수
template<typename _Tp>
_Tp* Mat:::ptr<int y)
- _Tp* 타입으로 형변환된 y번째 행의 시작 주소를 반환.
- 지정한 자료형의 포인터를 반환. 이 포인터로 지정한 행의 원소에 접근 가능.
- 행단위로 행렬원소에 접근
- 예시)
Mat mat1 = Mat::zeros(3,4,CV_8UC1); // mat1은 0으로 초기화된 3x4 행렬, 각원소는 uchar 자료형
for (int j=0; j<mat1.rows; j++) { // 행에 대한 반복
// p를 1차원 배열처럼 사용
uchar* p = mat1.ptr1<uchar>( j ); // j번째 행 원소의 시작 주소 반환. 포인터형 변수 p에 저장
for (int i=0; i<mat1.cols; i++) { // 열에 대한 반복
p[i]++;
}
}
3) MatIterator_ 반복자
- at(), ptr() 함수를 사용할 경우 함수 인자로 전달된 값이 행렬의 크기를 벗어나면 에러가 발생할 수 있음. 이 단점 보완을 위해 반복자라는 개념이 도입되었는데 이것이 MatIterator
- Mat::begin() 함수를 이용하면 행렬의 첫 번째 원소 위치를 얻을 수 있음.
- Mat::end() 함수를 이용하면 행렬의 마지막 원소 바로 다음 위치를 얻을 수 있음.
- ptr()에 비해 속도가 느리고, at()처럼 임의의 위치에 자유롭게 접근이 불가능하므로 사용성이 낮음.
'Computer Vision' 카테고리의 다른 글
OpenCV 주요 클래스 - 3. Vec와 Scalar 클래스 (0) | 2020.02.13 |
---|---|
OpenCV 주요 클래스 - 2. Mat 클래스(4) (0) | 2020.02.13 |
OpenCV 주요 클래스 - 2. Mat 클래스(2) (0) | 2020.02.09 |
OpenCV 주요 클래스 - 2. Mat 클래스(1) (0) | 2020.02.09 |
OpenCV 주요 클래스 - 1. 기본 자료형 클래스 (0) | 2020.02.08 |
댓글