ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [OpenCV 4] 3. 주요 클래스
    Computer Vision/OpenCV 2020. 10. 22. 17:11

    Vec 클래스는 다양한 OpenCV 프로그래밍에서 유용하게 사용되고 있으며, 특히 Vec3b, Vec4i, Vec2f 등 이름으로 재정의되어 사용되고 있다. 또한 Vec 클래스의 특별한 형태인 Scalar 클래스는 Mat 클래스만큼 사용 빈도가 많다.

     


    먼저 C++에서 나오는 템플릿이라는 개념을 간단하게 설명하자면

     

    템플릿(Template) 이란?

     

    - 함수나 클래스를 개별적으로 다시 작성하지 않아도, 여러 자료 형으로 사용할 수 있도록 하게 만들어 놓은 틀

    - 함수 템플릿(Function Template)와 클래스 템플릿(Class Template)로 나누어진다.

     

    함수 템플릿(Function Template)

    - 함수를 만들어 낼때, 함수의 기능은 명확하지만, 자료형을 모호하게 두는것

     

    int mul(int a, int b){
        return a * b;
    }
    double mul(double a, double b){
        return a * b;
    }
    

    위와 같이 곱셈을 표현할때 자료형을 다르게 해주는 함수를 template를 사용하게 되면 아래와 같이 하나의 함수만 정의하면 된다.

     

    template <typename T>
    T mul(T a, T b){
        return a * b;
    }
    

    template 함수는 호출할때 명확하게 어떤 자료형을 쓸 건지 < > 안에 표시해주는게 좋다.

    ex) cout << "double 곱" << mul<double>(a1,a2) << endl;

     

    클래스 템플릿(class template)

     

    - 클래스 내부의 맴버 변수의 타입에 ㅐ댛서 template로 선언 할 때 사용한다.

    - 맴버 함수를 클래스 외부에서 선언 할때, 꼭 template를 다시 선언해주어야 한다.

    - 객체를 생성할때 타입을 정해준다.

     

    위에 설명한 함수와 똑같이 클래스를 사용하면 된다. 

    내가 사용할 변수의 타입을 < > 안에 넣어서 사용하면 된다.

    ex)클래스명<변수의타입> 변수명("설명","값")

     

    이런식으로 변수를 사용 할 수 있다.

     

    template를 선언할때 <typename T>, <class T> 둘다 사용 가능하다.


    Vec 클래스

     

    하나의 행으로만 이루어진 행렬은 행 벡터라고 부르고, 하나의 열로만 구성된 행렬은 열 벡터라고 부른다. 그리고 행 벡터와 열 벡터를 합쳐서 벡터 또는 벡터 행렬이라고 부른다. 즉, 벡터는 같은 자료형을 가진 원소 몇 개로 구성된 데이터 형식이라고 볼 수 있다.

     

    template<typename _Tp, int m, int n> class Matx
    02    {
    03    public:
    04        …
    05        _Tp val[mn]; //< matrix elements
    06    };
    07     
    08    template<typename _Tp, int cn> class Vec : public Matx<_Tp, cn, 1>
    09    {
    10    public:
    11        …
    12     /! element access */
    13        _Tp& operator[](int i);
    14    };
    15
    
    16    template<typename _Tp, int n> static inline
    17    std::ostream& operator << (std::ostream& out, const Vec<_Tp, n>& vec);

    간략화한 Matx와 Vex의 정의이다. 

     

    Matx 클래스는 작은 크기의 행렬을 표현하기 위해 만들어진 템플릿 클래스이다.

     

    원소 데이터를 val이라는 이름의 배열에 저장한다.

     

    _Tp는 행렬 원소 자료형이고, m과 n은 각각 행과 열 개수를 의미한다. Vec클래스는 Matx 클래스를 상속받아 만들어지고 열 개수가 1개로 특화된 벡터 표현 클래스이다. 

     

    매번 Vec<uchar, 3> 형태로 입력하는 것은 꽤 번거롭고 불편하기 때문에 OpenCV는 자주 사용되는 자료형과 개수에 대한 Vec 클래스 템플릿의 이름 재정의를 제공한다.

     

    예를 들어 컬러 영상의 픽셀 값을 표현하고 싶을때는 Vec<uchar,3> 형식 대신에 Vec3b 클래스를 사용할 수 있다.

    ex) Vec3b p1, p2(0, 0, 255);

     


    Scalar 클래스

     

    Scalar 클래스는 4채널 이하의 영상에서 픽셀 값을 표현하는 용도로 자주 사용된다. Scalar 클래스는 Scalar라는 이름의 클래스 템플릿 이름 재정의이며, Scalar 클래스는 Vec 클래스를 상속받아 만들어졌다.

     

    01    template<typename Tp> class Scalar : public Vec<Tp, 4>
    02    {
    03    public:
    04        Scalar();
    05        Scalar_(Tp v0);
    06        Scalar(_Tp v0, _Tp v1, _Tp v2=0, Tp v3=0);
    07
    
    08        static Scalar<_Tp> all(Tp v0);
    09        …
    10    };
    11
    
    12    typedef Scalar<double> Scalar;

    간략화한 Scalar_와 Scalar 클래스 정의이다.

     

    Scalar_ 클래스는 Vec 클래스를 상속받았으며, 네 개의 원소를 가지고 있는 템플릿 클래스이다. Scalar_ 클래스는 템플릿 클래스이기 때문에 다양한 자료형에 대해 정의가 가능하다.

     

    특별히 double 자료형을 사용하는 경우에는 Scalar라고 재정의된 이름을 사용할 수 있다. Scalar 클래스는 크기가 4인 double형 배열 val을 멤버 변수로 가지고 있는 자료형이다.

     

    Scalar(밝기)

    Scalar(파란색, 녹색, 빨간색)

    Scalar(파란색, 녹색, 빨간색, 투명도)

     

    보통 네개 이하의 채널을 갖는 영상의 픽셀 값을 표현하는 용도로 사용되는데 위와 같이 표현이 가능하다.

     


    InpurtArray 클래스

     

    InputArray 클래스는 주로 OpenCV 함수의 입력으로 사용되고, OutputArray 클래스는 OpenCV 함수의 출력으로 사용되는 인터페이스 클래스이다.

    typedef const _InputArray& InputArray;

    InputArray 클래스는 다음과 같은 형태로 이름 재정의되어 있다.

     

    _InputArray 클래스는 단순히 사용의 편의성을 위해 만들어진 구현체일 뿐이며 내부 인터페이스는 향후 필요에 따라 변경될 수도 있다. 

     

     _InputArray 함수를 사용하여 Mat 객체 타입 형태로 변환해서 사용하는 방법을 알아보자. InputArray 클래스 타입의 인자를 사용하는 함수를 정의하는 방법과 실제 사용 방법은 예제 코드를 첨부하겠다.

     

    01    void InputArrayOp()
    02    {
    03        uchar data1[] = { 1, 2, 3, 4, 5, 6 };
    04        Mat mat1(2, 3, CV_8U, data1);
    05        printMat(mat1);
    06     
    07        vector<float> vec1 = { 1.2f, 3.4f, -2.1f };
    08        printMat(vec1);
    09    }
    10     
    11    void printMat(InputArray _mat)
    12    {
    13        Mat mat = _mat.getMat();
    14        cout << mat << endl;
    15    }

    13행을 보면 InputArray 타입의 _mat 객체로부터 Mat 객체 mat를 생성한다.

     

    printMat 함수는 Mat 행렬의 원소 값을 출력하는 기능을 가지고 있다.

     

    InputArrayOp 함수에서는 printMat() 함수를 두 번 호출하고, 한번은 Mat 객체를 전달하고 다음에는 vector<float> 객체를 전달한다. 두 가지 경우에 대해 모두 getMat 함수를 통해 Mat 객체를 생선한다.

     

    vector, mat 타입 모두 inputarray를 이용해 mat으로 바꿔준다고 생각하면 된다.

     


    OutputArray 클래스

     

    OutputArray클래스는 다음과 같이 이름 재정의가 되어 있다.

    typedef const _OutputArray& OutputArray;

     

    _OutputArray 클래스는 클래스 계층적으로 _InputArray 클래스를 상속받아 만들여젔으므로 _OutputArray 클래스도 Mat 또는 vector<T> 같은 타입의 객체로부터 생성될 수 있다. 다만 _OutputArray 클래스는 새로운 행렬을 생성하는 _OutputArray::create() 함수가 추가적으로 정의되어있다.

     

    결과 영상을 저장할 새로운 행렬을 먼저 생성한 후, 영상 처리 결과를 저장하는 형태로 OpenCV의 영상 처리 함수가 구현 되어 있다.

     

     

    참고 자료 : blockdmask.tistory.com/45?category=249379 , OpenCV 4로 배우는 컴퓨터 비전과 머신러닝

    댓글

Designed by Tistory.