WjExplor Story

01강 opencv 자료형 공부하기 본문

C++/C++ : openCV

01강 opencv 자료형 공부하기

더블유제이플로어 2026. 6. 14. 13:58

openCV 상수 명칭, 자료형

#include "opencv2/opencv.hpp"
using namespace cv;
using namespace std;

int main()
{
    Mat M1(1, 2, CV_8S); // CV_8S CV_depth {U|S|F}C(#channel)
    Mat M2(1, 2, CV_8UC3); // CV_8UC3

    M1.at<char>(0, 0) = 1;
    M1.at<char>(0, 1) = 2;

    M2.at<Vec<uchar, 3>>(0, 0) = Vec3d(11, 12, 13);
    M2.at<Vec<uchar, 3>>(0, 1) = Vec3d(10, 9, 8);

    cout << "M1 = " << M1 << endl;
    cout << "M1 depth = " << M1.depth() << endl;
    cout << "M2 = " << M2 << endl;
    cout << "M2 channels = " << M2.channels() << endl;

}

코드 설명

1. Mat 설정

CV_depth {U|S|F}
U : Unsigned
S : signed
F : Float
3가지를 지정합니다.
C(채널) 이 있다면 그 채널 갯수를 적어줄때 반드시 C라고 정의해야합니다.

Mat 자료형(행렬) 입니다.
이 행렬을 2개 선언하고 (1,2) 에서 각각 자료의 크기를 설정합니다.
CV_8UC3 은 채널이 3개이며 CV_8S 는 채널 갯수를 기입하지 않아서 채널이 1개입니다.
흑백(모노) 인 경우 채널이 1개 입니다.
컬러는 RGB 3가지 색상을 가지고 혼합하였습니다.
그래서 3채널을 쓰는것입니다.

CV_8S, CV_8UC3 등은 미리 정의된 상수형 변수입니다.
DataType<char>::type 으로 정의할 수 있지만 간소하게 설정한것입니다.

2. M1 , M2 대입 값

M1.at<char>(0, 0) = 1;
M2.at<char>(0, 1) = 2;

M1 이라는 행렬 중
(0,0) 캐릭터를 1로 대입(설정) 한 것입니다.
(0,1) 캐릭터를 2로 대입(설정)한 것입니다.

M2.at<Vec<uchar, 3>>(0, 0) = Vec3d(11, 12, 13);
M2.at<Vec<uchar, 3>>(0, 1) = Vec3d(10, 9, 8);

M2 는 채널이 3개입니다 (CV_8UC3)
Vec 함수를 통해 가지고
(0,0) 에 있는 3가지의 값을 각각 정한 것 입니다. (11 , 12, 13)
(0,1) 도 마찬가지로 (10, 9, 8) 로 정하였습니다.


(GPT 에게 실무에 쓰는 코드 예제 물어봤습니다.)

Mat::at<T>()는 OpenCV에서 픽셀이나 행렬 원소에 직접 접근할 때 매우 흔하게 사용하는 함수

다만 실무에서는 상황에 따라 다음과 같이 구분해서 사용합니다.

방법 사용 빈도 특징
at<T>() 높음 직관적, 안전성 좋음
ptr<T>() 매우 높음 속도가 빠름
반복자(iterator) 낮음 STL 스타일
OpenCV 함수 사용 (threshold, cvtColor 등) 매우 높음 실무에서 가장 많음

1. 현재 코드 설명

Mat M1(1, 2, CV_8S);

1행 2열의 signed char 행렬

[ ?, ? ]

M1.at<char>(0,0) = 1;
M1.at<char>(0,1) = 2;

결과

[1, 2]

Mat M2(1, 2, CV_8UC3);

1행 2열

채널 3개(B,G,R)

[(B,G,R), (B,G,R)]

M2.at<Vec3b>(0,0) = Vec3b(11,12,13);

실제로는 이렇게 쓰는 것이 일반적입니다.

Vec3b

typedef Vec<uchar,3> Vec3b;

의 별칭입니다.


주의할 점

작성하신 코드

M2.at<Vec<uchar,3>>(0,0) = Vec3d(11,12,13);

은 타입이 다릅니다.

왼쪽

Vec<uchar,3>

오른쪽

Vec3d

(double)

실무에서는 보통

M2.at<Vec3b>(0,0) = Vec3b(11,12,13);

처럼 동일 타입을 사용합니다.


가장 흔한 예제 1 : 그레이스케일 픽셀 읽기

#include <opencv2/opencv.hpp>
using namespace cv;

int main()
{
    Mat img = imread("lenna.png", IMREAD_GRAYSCALE);

    uchar pixel = img.at<uchar>(100, 200);

    printf("%d\n", pixel);
}

좌표

(y=100, x=200)

의 밝기값을 읽습니다.


가장 흔한 예제 2 : 밝기 증가

실무 교육에서 가장 먼저 만드는 예제입니다.

#include <opencv2/opencv.hpp>
using namespace cv;

int main()
{
    Mat img = imread("lenna.png", IMREAD_GRAYSCALE);

    for(int y=0; y<img.rows; y++)
    {
        for(int x=0; x<img.cols; x++)
        {
            uchar& pixel = img.at<uchar>(y, x);

            pixel = saturate_cast<uchar>(pixel + 50);
        }
    }

    imshow("result", img);
    waitKey();
}

원본보다 50 밝아집니다.


가장 흔한 예제 3 : 컬러 영상 접근

Mat img = imread("lenna.png");

Vec3b color = img.at<Vec3b>(100, 200);

cout << "B = " << (int)color[0] << endl;
cout << "G = " << (int)color[1] << endl;
cout << "R = " << (int)color[2] << endl;

OpenCV는

RGB

가 아니라

BGR

순서입니다.


가장 흔한 예제 4 : 빨간색만 제거

컴퓨터비전 입문자가 많이 만드는 코드입니다.

Mat img = imread("lenna.png");

for(int y=0; y<img.rows; y++)
{
    for(int x=0; x<img.cols; x++)
    {
        Vec3b& pixel = img.at<Vec3b>(y, x);

        pixel[2] = 0;
    }
}

imshow("result", img);
waitKey();

결과

R = 0

이 되어 빨간 성분이 제거됩니다.


실무 스타일 예제 5 : 특정 밝기 이상 검출

비전 검사 장비에서 흔한 패턴입니다.

Mat src = imread("part.png", IMREAD_GRAYSCALE);

Mat dst(src.size(), CV_8UC1);

for(int y=0; y<src.rows; y++)
{
    for(int x=0; x<src.cols; x++)
    {
        uchar pixel = src.at<uchar>(y,x);

        if(pixel > 150)
            dst.at<uchar>(y,x) = 255;
        else
            dst.at<uchar>(y,x) = 0;
    }
}

이것이 Threshold 알고리즘의 가장 기본 형태입니다.

실제 현장에서는 다음 OpenCV 함수를 사용합니다.

threshold(src, dst, 150, 255, THRESH_BINARY);

실무 스타일 예제 6 : 불량 픽셀 개수 세기

공장 자동화 비전검사에서 자주 나오는 패턴입니다.

int count = 0;

for(int y=0; y<img.rows; y++)
{
    for(int x=0; x<img.cols; x++)
    {
        if(img.at<uchar>(y,x) > 200)
            count++;
    }
}

cout << "Bright Pixel = "
     << count << endl;

응용 예

  • 이물질 검사
  • 스크래치 검사
  • LED 점등 검사
  • 인쇄 품질 검사

현업에서는 언제 at<T>()를 쓰나?

자주 사용

img.at<uchar>(y,x)
img.at<Vec3b>(y,x)
  • 알고리즘 공부
  • 프로토타입 제작
  • 디버깅
  • 픽셀 확인

대용량 영상 처리

실무에서는 더 빠른 방법 사용

uchar* row = img.ptr<uchar>(y);

row[x]

for(int y=0; y<img.rows; y++)
{
    uchar* row = img.ptr<uchar>(y);

    for(int x=0; x<img.cols; x++)
    {
        row[x] = 255 - row[x];
    }
}

at<T>()보다 빠르기 때문에 검사 장비나 실시간 비전 시스템에서는 ptr<T>()를 자주 사용합니다.


컴퓨터비전 담당자가 실제로 자주 보는 코드

Mat gray;
cvtColor(src, gray, COLOR_BGR2GRAY);

for(int y=0; y<gray.rows; y++)
{
    for(int x=0; x<gray.cols; x++)
    {
        uchar pixel = gray.at<uchar>(y,x);

        if(pixel > 120)
            gray.at<uchar>(y,x) = 255;
        else
            gray.at<uchar>(y,x) = 0;
    }
}

하지만 현업에서는 결국 아래 한 줄로 바뀝니다.

threshold(gray, gray, 120, 255, THRESH_BINARY);

즉,

  1. at<T>()로 원리를 이해한다.
  2. OpenCV 함수를 배운다.
  3. 속도가 중요하면 ptr<T>()를 사용한다.

이 순서로 학습하는 것이 일반적입니다.

추가로 Mat, Vec3b, Scalar, ptr<T>(), step, isContinuous()까지 이해하면 OpenCV C++ 실무 입문 수준을 넘어서게 됩니다.