본 문은 C++ 11 기반으로 작성되었습니다.
배열을 활용한 이미지 표현
이미지 처리를 하다보면 배열을 주로 사용한다. 이미지의 경우 2차원 배열이라고 생각하면 쉽고 따라서 1차원 배열보다 2차원 배열을 사용하는 것이 처리의 직관성을 높일 수 있다.
먼저 배열의 경우 동적할당을 통해 사용하는데 사용하는 코드는 다음과 같다.
BYTE** image = new BYTE*[ (이미지)세로 ];
image[0] = new BYTE[ 세로 * (이미지)가로 ];
for( int i = 1; i < 세로; i++ )
{
image[i] = image[i - 1] + 가로;
}
memset( image, 0, 가로*세로 );
// 사용이 끝난 후
delete[] image[0];
delete[] image;
코드를 살펴보면 1번 라인에서 BYTE 더블 포인터형 변수 image를 생성하고 세로의 길이만큼 BYTE* 형을 생성한다.
현재까지 생성된 것은 실질적인 데이터를 담는 것이 아닌, BYTE 자료형을 가르킬 포인터를 생성한 것이다.
그리고 2번 라인에서 전체적인 이미지 데이터를 담을 배열을 생성한다. 위에서 BYTE* 형을 세로 개수만큼 생성했는데
첫 번째 포인터에 전체 이미지 크기(가로*세로) 만큼 공간을 할당한다.
그리고 4번 라인~7번 라인이 중요한데
세로 개수만큼 생성된 BYTE* 중 0 index, 즉 첫 번째 포인터는 이미지 전체를 가리키도록 했다.
그러므로 다음 두 번째 포인터, 즉 인덱스로는 1 번(i = 1)부터 가로 길이만큼 포인터를 이동시키며 배열을 가리키도록 한다.
이것을 그림으로 나타내면 다음과 같다.
벡터를 활용한 이미지 표현
이미지를 배열로 표현하는 방법과 동일하게 벡터로 표현하는 방법이 있다. 이것의 장점은 시스템 상 조금 더 안정적이며 new를 통해 발생할 메모리 누수를 방지할 수 있다는 장점이 있다.
벡터로 이미지를 표현하는 방법은 다음과 같다.
#include <vector>
using namespace std;
vector< vector<픽셀자료형>> 벡터명( 세로, vector<픽셀자료형>(가로) );
세로 길이만큼 먼저 벡터를 생성하고 각 벡터의 인자에 가로 길이만큼의 벡터들을 생성한 것이다.
아래 예시는 2*2의 이미지를 2차원 벡터로 표현한 것이다.
#include <iostream>
#include <vector>
using namespace std;
int w = 2;
int h = 2;
int main()
{
vector< vector<int> > img( h, vector<int>(w) );
img[0][0] = 1;
img[0][1] = 2;
img[1][0] = 3;
img[1][1] = 4;
for(int j = 0; j < h; j++)
{
for(int i = 0; i < w; i++)
{
cout << img[j][i] << " ";
}
cout << endl;
}
return 0;
}
확실히 사용도 간편하고 직관적인 장점이 있다.
그러나 push_back을 사용하는 경우 주의할 점이 있다. 먼저 다음 코드를 보자
#include <vector>
using namespace std;
int w = 2;
int h = 2;
int main()
{
vector< vector<int> > img( h, vector<int>(w) );
img[0].push_back(1);
img[0].push_back(2);
img[1].push_back(3);
img[1].push_back(4);
for(int j = 0; j < h; j++)
{
for(int i = 0; i < w; i++)
{
cout << img[j][i] << " ";
}
cout << endl;
}
return 0;
}
위 코드는 이전 코드에서 데이터를 삽입하는 부분을 = 대신 push_back으로만 변경한 것이다.
그러나 이렇게 사용할 경우 출력해보면 0(또는 쓰레기) 값만 출력하는 문제가 발생한다.
이는 벡터의 특성에서 문제를 찾을 수 있는데 10번 라인에서 벡터를 생성할 때 vector<int>(w) 를 사용하였다.
이렇게 하면 벡터 내부에는 w 만큼의 빈 공간이 할당된다. 따라서 해당 코드의 경우
0이 2개(w값) 만큼 할당 된 이후 push_back을 통해 1과 2 또는 3과 4가 삽입된다. 즉
0 0 1 2 또는 0 0 3 4가 되는 셈이다.
따라서 push_back을 통해 데이터를 삽입하고자 할 경우 vector를 생성할 때 2번째 인자를 주지 않음으로 해결할 수 있다.
#include <iostream>
#include <vector>
using namespace std;
int w = 2;
int h = 2;
int main()
{
vector< vector<int> > img( h );
img[0].push_back(1);
img[0].push_back(2);
img[1].push_back(3);
img[1].push_back(4);
for(int j = 0; j < h; j++)
{
for(int i = 0; i < w; i++)
{
cout << img[j][i] << " ";
}
cout << endl;
}
return 0;
}
'Vision' 카테고리의 다른 글
색의 표현과 색 체계 Color Space (0) | 2018.12.28 |
---|---|
Raw Data와 Bayer Filter의 원리 (0) | 2018.12.28 |
이미지 센서의 원리와 종류 (0) | 2018.12.28 |
H.265 HEVC 개요 (0) | 2018.12.28 |
HEVC 비디오 영상 포맷 (0) | 2018.12.28 |