728x90
반응형

벌써 세번째 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언어 스타일로 사용자 정의 함수를 작성하여 복사하여 사용할 수 있다.


이에 대한 사용법은 나중에 다뤄보도록 하자. 필요할 때. ... 











드디어 기본 클래스에 대한 공부가 끝났다. 다음에는 간단한 그래픽 및 영상 파일 입출력을 공부하도록 해보겠다 ㅠㅠ 

728x90
반응형