벌써 세번째 Mat 포스팅이다. 기본클래스의 마지막 포스팅이 될 것 같다. 책에 수록되어있는 Mat에 대한 함수들이 너무 많아서, 자주 쓸 것 같고, 자주 쓰이는 것만 다뤄보도록 하겠다 ㅠㅠ
3.3 Mat 행렬 정보
행렬에 대한 정보들은 영상처리 프로그래밍을 할 때 필수적이다. 쭉 훑어보면 좋을 것 같다. 자주 쓰이는 것은 굵은색으로 표시해두었다.
- Mat::rows 행의 개수
- Mat::cols 열의 개수
- Mat::data 행렬 데이터의 포인터
- Mat::dims 행렬의 차원(2보다 같거나 크다)
- Mat::isContinuous 각 행의 마지막에 공백없이 연속으로 데이터가 저장되었는지를 확인
- Mat::total() 행렬 요소의 전체 개수
- Mat:: elemSize() 행렬 요소 하나의 바이트 크기를 반환
행렬의 한 행의 총 바이트 수는 Mat::cols x Mat::elemSize()
- Mat::type() 행렬의 자료형 반환
- Mat::depth() 행렬의 깊이를 반환
- Mat::channels() 행렬의 채널 개수를 반환
- Mat::empty() 공백행렬인지를 반환
- Mat::size() 행렬의 크기를 Size(cols, rows)로 반환
3.4 Mat::at에 의한 Mat 행렬 요소 접근
저번 포스팅에서 잠깐 다루었었는데 아래와 같은 형태로 쓰인다.
Mat A(3, 3, CV_32F);
for(int i=0; i<A.rows; i++)
for(int j=0; j<A.cols; j++)
A.at<float>(i, j) = i*A.cols+j; // 0~8을 차례대로 행렬에 저장
3.5 Mat::ptr에 의한 Mat 행렬 요소 접근
Mat::ptr() 메소드는 행렬의 지정된 행의 시작주소를 저장한 포인터를 반환한다. uchar* 또는 템플릿으로 명시된 자료형의 포인터를 반환한다.
Mat (3, 3, CV_32F);
for(int i=0; i<A.rows; i++){
float* ptrA = A.ptr<float>(i);
for(int j=0; j<A.cols; j++)
ptrA[j] = i*A.cols+j;
}
확실히 ptr에 의해 행렬요소를 접근하는 것 보다는 Mat::at에 의해 행렬 요소에 접근하는 것이 더 편안(?)해 보인다.
3.6 Mat 행렬의 행/열 지정에 의한 부분 행렬 헤더 생성
행렬의 헤더를 생성한다는 의미는 행렬 데이터를 위한 메모리를 새로 생성하지 않고 공유하여 사용한다는 의미이다.
Mat::row y-행에 대한 행렬 헤더를 생성
Mat::col x-열에 대한 행렬 헤더를 생성
Mat::rowRange startrow에서 endrow-1 까지의 행렬 헤더를 생성
Mat::colRange startcol에서 endcol-1 까지의 행렬 헤더를 생성
3.7 Mat 행렬의 복제, 복사, 변환, 값 설정 및 모양 변환
Mat::clone() 행렬을 완전히 복제하여 반환
Mat::copyTo() 행렬을 다른 행렬 M으로 복사, 크기 및 자료형이 다르면 Mat::create()에 의해 다시 생성
Mat::convertTo() 행렬을 자료형이 rtype인 출력 행렬 m으로 변환, 채널수는 같아야함
Mat::assignTo() convertTo와 동일한데, alpha와 beta가 없는 형태
Mat::setTo() 행렬의 요소를 Scalar 등에 의한 InputArray 자료형의 value 값으로 설정
3.8 Mat 행렬의 메모리 해제(release), 크기 변경(resize), 공간 확보(reserve)
Mat::release() 메소드는 행렬의 참조 카운터를 1 감소시킨다. 참조 카운터의 값이 0이 되면 행렬 데이터의 메모리를 해제하고 Mat::data = NULL로 변경한다. 명시적으로 호출이 가능하지만 대부분 행렬의 파괴자에 의해 자동으로 호출된다.
Mat::resize() 메소드는 행렬에서 행의 개수를 입력한 size로 변경시킨다. 두번째에 오는 값은 새로 추가된 행렬요소의 값을 입력한다.
Mat::reserve() 메소드는 입력한 size 행의 개수 마늠의 메모리 공간을 확보하지만, 메모리 공간이 충분하면 아무 일도 하지 않는다. std::vector 클래스의 reserve 멤버와 같이 미리 메모리 용량을 확보하고 사용하면, 메모리 재할당이 빈번히 일어나는 것을 방지하여 성능저하를 막을 수 있다.
4. Mat_ 클래스
Mat_ 클래스는 Mat 클래스로부터 상속된 템플릿 클래스이다. 뎅터 멤버는 갖지 않고, 메소드만으로 존재하는 클래스이다. Mat 클래스를 감싸서 사용한다. 레퍼런스 &와 *포인터는 자유로이 사용할 수 있으나 자료형 변환은 주의해서 사용하도록 한다.
Mat 클래스에도 _Mat과 상응하는 클래스가 많으나 _Mat 클래스의 메소드가 짧고, 사용하기 편리하다고 한다.
이에 대한 메소드는 따로 다루지 않도록 한다...
5. std::vector 클래스
이 vector 클래스는 C++의 표준 템플릿 라이브러리(STL)의 대표적인 시퀀스 컨테이너 클래스로 C/C++의 배열을 대신하여 사용하면 편리한 점이 많으며, OpenCV 내에서 빈번히 사용된다.
5.1 vector 생성자에 의한 초기화
vector<int> V1; // 벡터 V1 생성
vector<int> V2(3, 0); // 벡터 크기를 3으로, 각 요소값을 0으로 초기화하여 생성
int arr[] = {1,2,3,4,5,6,7,8,9}; // 이 배열을 이용하여 벡터를 초기화시켜 생성
vector<int> V3(arr, arr+sizeof(arr)/sizeof(arr[0])); // arr는 시작주소, 그 뒤는 마지막 주소를 뜻함
Point pts[] = {Point(100,100), Point(200,100), Point(200,200), Point(100,200)};
vector<Point> V4(pts, pts+sizeof(pts)/sizeof(pts[0])); // Point 값을 이용한 벡터 초기화
vector<Point> V5(V4.begin(), V4.end()); // V4를 이용한 벡터 초기화
5.2 vector를 배열로 사용
vector 클래스를 사용하면 데이터의 크기를 지정하지 않고 vector::push_back() 멤버 함수로 데이터를 넣고, 사용할 때는 배열처럼 사용할 수 있으며, vector::size() 멤버 함수로 저장된 데이터의 크기를 알 수 있다. 각 데이터 요소들이 배열과 같이 연속으로 할당되어 임의의 요소에 대한 접근 속도가 빠르고, 끝 지점에서 삽입과 삭제가 빠르다. 현재 할당된 용량은 vector::capacity() 멤버 함수를 통해 할 수 있다. 현재 할당된 용량보다 크게 삽입이 일어나면 메모리 재할당이 일어나며, 이러한 재할당은 성능 저하를 일으킬 수 있다.
그러나 vector::reserve() 함수로 미리 메모리 용량을 확보하고 사용하면 재할당이 빈번히 일어나는 것을 방지 할 수 있다. vector 클래스를 사용하면 C/C++에서 배열을 사용할때 불편하였던 점을 해결 수 있는 장점이 있다.
5.2.1 vector를 1차원 배열로 사용한 예
vector<float> V1;
V1.push_back(10.0f); // push_back 을 이용하여 데이터 삽입
V1.push_back(20.0f);
V1.push_back(30.0f);
V1.push_back(40.0f);
cout << V1.capacity() << endl; // capacity()를 이용하여 할당된 용량 계산 = 4
cout << V1.size() << endl; // size()를 이용하여 크기 계산 = 4
V1.erase(V1.begin()+2); // 30.0 삭제
V1.insert(V1.begin()+2, 30.0f) // 30.0 추가
V1.clear(); // 벡터 내용 삭제, 삭제 후 용량은 4, 크기는 0
5.2.2 vector를 2차원 배열로 사용한 예
// vector<int> V1(3,0);
// vector<vector<int>> M1(2,V1);
vector<vector<int>> M1(2, vector<int>(3,0));
M1[0][0] = 10;
M1[0][1] = 20;
... 이런식으로 M1[1][2]까지 값을 넣음
M1.size() = 2
M1[0].size() = 3 이라는 결과를 얻을 수 있다.
5.3 vector를 다른 자료형으로 변환
vector를 Mat 클래스 또는 Point 배열로 변환할 필요가 있다. vector를 Mat 클래스로 변환 할 때는 Mat 클래스 생성자 template<typename T> explicit Mat::Mat(const vector<T>& vec, bool copyData=false)를 사용한다. vector를 cv::copy 함수를 배열로 복사하거나, C언어 스타일로 사용자 정의 함수를 작성하여 복사하여 사용할 수 있다.
이에 대한 사용법은 나중에 다뤄보도록 하자. 필요할 때. ...
드디어 기본 클래스에 대한 공부가 끝났다. 다음에는 간단한 그래픽 및 영상 파일 입출력을 공부하도록 해보겠다 ㅠㅠ
'Programming > OpenCV' 카테고리의 다른 글
OpenCV 설치 시 에러 LNK1112 (0) | 2016.11.12 |
---|---|
OpenCV 직선 그리기, 사각형 그리기, 직선 클리핑 (0) | 2016.08.13 |
OpenCV 기본클래스 (2) (0) | 2016.08.13 |
OpenCV 기본클래스 (1) (7) | 2016.08.13 |
OpenCV 응용프로그램을 제대로 시작하지 못했습니다(0xc000007b) 오류 해결법 (11) | 2016.08.13 |