OpenCvSharp - Mat, Blob 기반 Array구조
1. OpenCvSharp.Mat
Open CV의 기본데이터 타입 matrix(행렬) 의 약어로, 영상을 matrix 형태로 표현한 데이터 타입입니다. 보통 Cv2.imread() 함수로 이미지를 로드하면 Mat type 의 변수로 로드되어 지며, 행과 열을 기반으로하는 2차원 Array 구조를 가지게 됩니다.
1-1. Mat 의 Data Type의 종류
CV_8UC1
"8U" 는 Data Type 을 나타내며, 8S, 16U, 16S, 32S, 32F, 64F 등이 있습니다.
"C1" 은 Channel 수를 나타내며, C1, C3, C4 등이 있습니다.
보통 C1 은 GrayScale, C3 는 RGB Array, C4 는 RGBA 등이 있을 수 있습니다.
Q. 250(W) * 250(H) Resolution 을 가진, 32비트 Float 형태의 3 Channel Pixel Data 를 담을 Mat 변수를 생성해보세요.
Mat img = new Mat(new Size(250, 250), MatType.CV_32FC3);
2. CvDnn.BlobFromImage
Onnx Type 의 AI Model 을 사용하기위해서 사용되는 Data의 구조는 4차원 구조로, BCHW (Batch, Channel, Height, Width) 의 형태를 따릅니다. 처음 "imread()" 함수로 Image 를 로드하면 2차원 형태로 데이터가 로드되어 지며, 이후 전처리 과정을 거쳐 "BlobFromImage" 함수를 이용해 4차원 형태의 Array 로 변환되어 집니다.
한 가지 예시를 들여다 보겠습니다.
BCHW 형태의 Input 을 받는 RTMPose Model 파일을 "Netron" 을 이용하여 구조를 도식화한 결과 입니다.
Vision AI 모델들은 보통 이미지의 입력을 위와같이 받으며, OpenCV 에서 로드한 이미지 데이터의 형태는 2차원 Array 이며, 이를 4차원 Array 형태로 변환시켜주는 기능을 합니다.
3. Array 구조
3-1. OpenCvSharp.Imread()
MatType 에 맞추어, Image Width (Column), Height (Row) 형태의 2차원 배열로 이루어 집니다.
ex) MatType : CV_8UC3, Width (100), Height (150)
- Color Array : BGR Pattern
- Total Data Size : 100 * 150 * Channel (3) * Data Unit(1 Byte) => 30000 Bytes
CV_8UC3 란, 8Bit 데이터 3개를 1개의 Data 로 본다라는 의미를 갖습니다.
⭐️Data Indexing
(0,0) 번째 픽셀의 값을 얻기 위한 Pointer 접근 방법은 아래와 같습니다.
BytePointer ptr = &img 기준,
B(0,0) = ptr[0]
G(0,0) = ptr[1]
R(0,0) = ptr[2]
3-2. BlobFromImage()
BCHW 채널 형태를 갖춘 데이터 Array 로 이루어지며, 각 데이터 Type 은 Float 형태로 변환 되어 집니다.
ex) Batch(1) Channel(3), Width(100), Height(150)
- Color Array : RGB Pattern
- Total Data Size : 1 * 3 *100 * 150 * Data Unit(4 Byte) => 180000 Bytes
⭐️Data Indexing
(0,0) 번째 픽셀의 값을 얻기 위한 Pointer 접근 방법은 아래와 같습니다.
Float Pointer ptr = &blob 기준,
R(0,0) = ptr[0]
G(0,0) = ptr[Width * Height + 0]
B(0,0) = ptr[Width * Height * 2 + 0]
4. C# Code 로 픽셀 Data 접근하기
unsafe
{
// Create Matrix Image
Mat img = Cv2.ImRead("./images/demo.jpg");
// Create Blob Image
Mat tblob = CvDnn.BlobFromImage(img, 1);
// Mat Type : BGR Pattern, BGR -> BGR -> BGR
byte* data = img.DataPointer;
// Blob Type : RGB Pattern, R->G->B
float* rgbPtr = (float *)tblob.DataPointer;
// (0,0) Pixel 접근
Console.WriteLine($"{data[0]} {data[1]} {data[2]}");
Console.WriteLine($"{rgbPtr[0]} {rgbPtr[img.Width * img.Height * 1]} {rgbPtr[img.Width * img.Height * 2]} ");
}