본문 바로가기

# 미사용/OpenCV

[OpenCV] 벡터를 행렬로 변환


 vector를 mat을 생성하는 방법

아래의 단계를 따르면 된다.

  • mat의 생성자에 vector를 넘기자.

  • 원하는 형태로 reshape하자.


example)

//! data = [0, 6)
vector<int> data;
for(int i=0; i<6; i++){
    data.push_back(i);
}


//! Mat를 생성한다.
Mat mat = Mat(data);
/*
 * [0;
 *  1;
 *  2;
 *  3;
 *  4;
 *  5;
 */


//! 원하는 형태로 reshape 한다.
Mat reshaped = mat.reshape(2, 3);
/*
 * [(0, 1);
 *  (2, 3);
 *  (4, 5)]
 */


특이사항

  • 크기가 N인 벡터를 넘기면,  N X 1 행렬이 생성.

  • reshape를 통해 행렬의 크기와 채널을 변경해야 함.

  • mat과 reshaped는 아직 같은 행렬 메모리를 참조하고 있다.
    즉, mat이 수정되면 reshaped도 변경된다.



 공유 메모리 이슈

이미 존재하는 데이터를 통해 mat을 만들 때,

2가지 방식을 통해 mat을 생성할 수 있다.

  • 이미 존재하는 데이터의 데이터 영역을 공유

  • 해당 데이터를 복사하여 자신만의 데이터 영역을 소유


mat에 vector를 넘길때 블리언 플래그를 넘겨줌으로써 

행렬 메모리의 생성방식을 제어할 수 있다.


example)

//! data = [0, 1)
vector<int> data;
for(int i=0; i<1; i++){
    data.push_back(i);
}


//! Mat를 생성한다.
Mat ref = Mat(data);        //! 벡터와 메모리 공유
Mat cpy = Mat(data, true);  //! 복사된 메모리 생성


//! data를 변경하면?
data[0] = 9;
cout << ref << '\n';    //! [9]
cout << cpy << '\n';    //! [0]



 참조 방식의 위험성

vector를 참조방식으로 쓸 때의 주의사항을 알아보자.

먼저 참조방식으로 mat을 생성해보자.


step 1)

//! data = [0, 1)
vector<int> data;
for(int i=0; i<1; i++){
    data.push_back(i);
}

//! 참조 방식으로 Mat를 생성한다.
Mat ref = Mat(data);

//! ref를 출력한다.
cout << ref << '\n';    //! [0]

여기까지는 문제가 없음이 자명하다.

문제는 이 다음부터다.



step 2)

//! 벡터에 데이터를 더 붙인다.
//! data = [0, 256)
for(int i=1; i<256; i++){
    data.push_back(i);
}

//! ref를 출력한다.
cout << ref << '\n';    //! [?]

벡터에 데이터를 더 붙이고 다시 ref를 출력하면,

이상한 숫자가 출력될 것 이다.


원인은 바로 벡터의 reallocation에 있다.




 벡터 reallocation

벡터는 현재 capacity를 초과하는 데이터가 push되면,

1.5배 만큼 capacity를 데이터를 수용할 수 있도록 재할당하고, 이전의 데이터를 복사한다.




문제는 재할당이라는 것이다.

이전의 데이터 영역이 버려지는 것 이다.


example)

//! 하나만 붙이고 vec[0]의 주소 출력.
vec.push_back(0);
cout << &vec[0] << '\n';


//! 여러개 붙이고 다시 vec[0]의 주소 출력.
for(int i=0; i<1000; i++){
    vec.push_back(0);
}
cout << &vec[0] << '\n';


/**
 * output : (실행시마다 달라질 수 있음.)
 *  0x1a1790
 *  0x692490
 */




 참조방식 + 재할당 패닉

즉, vector는 재할당이 이루어짐으로써 이전 영역을 해제했지만,

참조방식 mat은 이전 영역을 계속 사용함으로써 문제가 발생했다.



해결 방안은 다음과 같다.

  • true 플래그를 넘겨서 복사 방식으로 mat을 생성한다.

  • vector에 더 이상 데이터를 추가하지 않는다.


하지만 복사 방식으로 mat을 생성할 경우,

데이터를 복사하는데 오버헤드가 크다는 것을 염두해두자.