본문 바로가기
프로그래밍/OpenCV

[OpenCV] 기본 자료형 클래스

by 별준 2022. 5. 1.

References

Contents

  • Point_, Size_
  • Rect_, RotateRect
  • Range
  • String

OpenCV에서는 컴퓨터 비전 프로그래밍에서 자주 사용되는 다양한 클래스 타입을 지원합니다. 이번 포스팅에서는 유용하게 사용되는 OpenCV 기본 클래스를 살펴보겠습니다.

 

Point_

가장 먼저 살펴볼 클래스는 Point_ 클래스입니다. 이 클래는 2차원 평면 위에 있는 점의 좌표를 표현하는 템플릿 클래스입니다. 클래스 내에는 2차원 좌표를 나타내는 x와 y라는 이름의 멤버 변수가 있으며, 클래스 정의는 다음과 같습니다.

(types.hpp에 정의되어 있습니다.)

template<typename _Tp> class Point_
{
public:
    typedef _Tp value_type;

    //! default constructor
    Point_();
    Point_(_Tp _x, _Tp _y);
#if (defined(__GNUC__) && __GNUC__ < 5) && !defined(__clang__)  // GCC 4.x bug. Details: https://github.com/opencv/opencv/pull/20837
    Point_(const Point_& pt);
    Point_(Point_&& pt) CV_NOEXCEPT = default;
#elif OPENCV_ABI_COMPATIBILITY < 500
    Point_(const Point_& pt) = default;
    Point_(Point_&& pt) CV_NOEXCEPT = default;
#endif
    Point_(const Size_<_Tp>& sz);
    Point_(const Vec<_Tp, 2>& v);

#if (defined(__GNUC__) && __GNUC__ < 5) && !defined(__clang__)  // GCC 4.x bug. Details: https://github.com/opencv/opencv/pull/20837
    Point_& operator = (const Point_& pt);
    Point_& operator = (Point_&& pt) CV_NOEXCEPT = default;
#elif OPENCV_ABI_COMPATIBILITY < 500
    Point_& operator = (const Point_& pt) = default;
    Point_& operator = (Point_&& pt) CV_NOEXCEPT = default;
#endif
    //! conversion to another data type
    template<typename _Tp2> operator Point_<_Tp2>() const;

    //! conversion to the old-style C structures
    operator Vec<_Tp, 2>() const;

    //! dot product
    _Tp dot(const Point_& pt) const;
    //! dot product computed in double-precision arithmetics
    double ddot(const Point_& pt) const;
    //! cross-product
    double cross(const Point_& pt) const;
    //! checks whether the point is inside the specified rectangle
    bool inside(const Rect_<_Tp>& r) const;
    _Tp x; //!< x coordinate of the point
    _Tp y; //!< y coordinate of the point
};

typedef Point_<int> Point2i;
typedef Point_<int64> Point2l;
typedef Point_<float> Point2f;
typedef Point_<double> Point2d;
typedef Point2i Point;

 

몇 가지 생성자(기본, 복사, 대입, 이동)와 대입 연산자들이 있으며, 몇 가지 public 메소드가 있습니다.

Point_::dot()은 두 점 사이의 내적(dot product)을 계산하여 반환하고, Point_::ddot()은 두 점 사이의 내적을 실수형으로 계산하여 double로 반환합니다.

Point_::cross()는 두 점 사이의 외적(cross product)을 반환합니다.

Point_::inside()는 인수로 주어진 사각형 r 영역 안에 점의 좌표가 있다면 true를 반환합니다.

그리고 마지막 부분에서는 typedef를 사용하여 다양한 자료형에 대한 Point_ 클래스 이름을 재정의하고 있습니다.

cv::Point의 경우에는 2차원 정수 좌표계에서 좌표를 표현하는 자료형이 됩니다.

 

Point_ 클래스를 다음과 같이 사용하여 2차원 정수 좌표를 표현할 수 있습니다.

cv::Point pt1;           // pt1 = (0, 0)
pt1.x = 5; pt1.y = 10;   // pt1 = (5, 10)
cv::Point pt2{ 10, 30 }; // pt2 = (10, 30)

 

Point_ 클래스에는 다양한 연산자가 재정의 되어 있는데, 다음과 같은 코드를 사용하여 좌표 연산을 수행할 수 있습니다.

// pt1 = [5, 10], pt2 = [10, 30]
cv::Point pt3 = pt1 + pt2; // pt3 = [15, 40]
cv::Point pt4 = pt1 * 2;   // pt4 = [10, 20]
int d1 = pt1.dot(pt2);     // d1 = 350
bool b1 = (pt1 == pt2);    // b1 = false

 

또한, OpenCV에서 제공하는 대부분의 자료형 클래스는 C++ 표준 출력을 지원합니다. 그래서 'std::cout <<'을 사용하여 아주 쉽게 Point_ 객체의 좌표를 출력할 수 있습니다. 다음은 위에서 생성한 Point_ 객체의 좌표들을 출력합니다.

#include <iostream>
#include "opencv2/opencv.hpp"

int main(int argc, char* argv[])
{
    cv::Point pt1;           // pt1 = [0, 0]
    pt1.x = 5; pt1.y = 10;   // pt1 = [5, 10]
    cv::Point pt2{ 10, 30 }; // pt2 = [10, 30]

    // pt1 = [5, 10], pt2 = [10, 30]
    cv::Point pt3 = pt1 + pt2; // pt3 = [15, 40]
    cv::Point pt4 = pt1 * 2;   // pt4 = [10, 20]
    int d1 = pt1.dot(pt2);     // d1 = 350
    bool b1 = (pt1 == pt2);    // b1 = false

    std::cout << "pt1: " << pt1 << std::endl;
    std::cout << "pt2: " << pt2 << std::endl;
    std::cout << "pt3: " << pt3 << std::endl;
    std::cout << "pt4: " << pt4 << std::endl;

    return 0;
}

 


Size_

사각형 영역의 크기를 표현할 때 Size_ 클래스를 사용합니다. 이 클래스는 사각형의 가로와 세로 크기를 나타내는 width와 height 멤버 변수를 가지고 있습니다. 이 클래스의 정의는 다음과 같습니다.

template<typename _Tp> class Size_
{
public:
    typedef _Tp value_type;

    //! default constructor
    Size_();
    Size_(_Tp _width, _Tp _height);
#if OPENCV_ABI_COMPATIBILITY < 500
    Size_(const Size_& sz) = default;
    Size_(Size_&& sz) CV_NOEXCEPT = default;
#endif
    Size_(const Point_<_Tp>& pt);

#if OPENCV_ABI_COMPATIBILITY < 500
    Size_& operator = (const Size_& sz) = default;
    Size_& operator = (Size_&& sz) CV_NOEXCEPT = default;
#endif
    //! the area (width*height)
    _Tp area() const;
    //! aspect ratio (width/height)
    double aspectRatio() const;
    //! true if empty
    bool empty() const;

    //! conversion of another data type.
    template<typename _Tp2> operator Size_<_Tp2>() const;

    _Tp width; //!< the width
    _Tp height; //!< the height
};

typedef Size_<int> Size2i;
typedef Size_<int64> Size2l;
typedef Size_<float> Size2f;
typedef Size_<double> Size2d;
typedef Size2i Size;

Point_와 마찬가지로 기본적인 생성자들이 있습니다.

그리고 멤버 함수 중 area()를 사용하여 사각형 크기에 해당하는 면적(width x height)을 얻을 수 있습니다.

empty() 멤버 함수는 width나 height가 둘 중 하나가 0 이하일 때 true를 반환합니다. 즉, 유효하지 않은 사각형인 경우에true를 반환합니다.

aspectRatio() 멤버 함수는 종횡비를 반환합니다.

 

Size_ 클래스도 Point_와 비슷하게 다양한 자료형에 대해 이름이 재정의되어 있습니다. 특히 정수형으로 가로, 세로를 표현하는 경우가 많기 때문에 cv::Size는 정수형의 가로, 세로를 표현하는 Size_ 클래스입니다.

 

cv::Size sz1, sz2(10, 20);      // sz1 = [0 x 0], sz2 = [10 x 20]
sz1.width = 5; sz1.height = 10; // sz1 = [5 x 10]

cv::Size의 코드 작성법도 간단합니다. 위 코드에서 변수 sz1은 기본 생성자를 사용하여 생성하였으며, 이 경우 width, height 값은 0으로 초기화됩니다. 따라서 sz1은 유효하지 않은 크기를 가진 객체입니다. 변수 sz2는 생성과 동시에 10x20의 크기를 나타냅니다.

cv::Size sz3 = sz1 + sz2; // sz3 = [15 x 30]
cv::Size sz4 = sz1 * 2;   // sz4 = [10 x 20]
int area1 = sz4.area();   // area1 = 200

std::cout << "sz3: " << sz3 << std::endl;
std::cout << "sz4: " << sz4 << std::endl;

또한, 다양한 연산자에 대해 오버로딩되어 있으므로 위와 같이 사용할 수도 있습니다.

 


Rect_ 클래스

Rect_ 클래스는 사각형의 위치와 크기 정보를 표현할 때 사용합니다. 이 클래스에는 사각형의 좌측 상단 점의 좌표를 나타내는 x, y 멤버 변수와 가로 및 세로 크기를 나타내는 width, height 멤버 변수를 가지고 있습니다. 

클래스 정의는 다음과 같습니다.

template<typename _Tp> class Rect_
{
public:
    typedef _Tp value_type;

    //! default constructor
    Rect_();
    Rect_(_Tp _x, _Tp _y, _Tp _width, _Tp _height);
#if OPENCV_ABI_COMPATIBILITY < 500
    Rect_(const Rect_& r) = default;
    Rect_(Rect_&& r) CV_NOEXCEPT = default;
#endif
    Rect_(const Point_<_Tp>& org, const Size_<_Tp>& sz);
    Rect_(const Point_<_Tp>& pt1, const Point_<_Tp>& pt2);

#if OPENCV_ABI_COMPATIBILITY < 500
    Rect_& operator = (const Rect_& r) = default;
    Rect_& operator = (Rect_&& r) CV_NOEXCEPT = default;
#endif
    //! the top-left corner
    Point_<_Tp> tl() const;
    //! the bottom-right corner
    Point_<_Tp> br() const;

    //! size (width, height) of the rectangle
    Size_<_Tp> size() const;
    //! area (width*height) of the rectangle
    _Tp area() const;
    //! true if empty
    bool empty() const;

    //! conversion to another data type
    template<typename _Tp2> operator Rect_<_Tp2>() const;

    //! checks whether the rectangle contains the point
    bool contains(const Point_<_Tp>& pt) const;

    _Tp x; //!< x coordinate of the top-left corner
    _Tp y; //!< y coordinate of the top-left corner
    _Tp width; //!< width of the rectangle
    _Tp height; //!< height of the rectangle
};

typedef Rect_<int> Rect2i;
typedef Rect_<float> Rect2f;
typedef Rect_<double> Rect2d;
typedef Rect2i Rect;

위에서 살펴본 Point_, Size_와 거의 유사하며, 사용 방법도 마찬가지입니다.

 

cv::Rect rc1;                 // rc1 = [0 x 0 from (0, 0)]
cv::Rect rc2(10, 10, 60, 40); // rc2 = [60 x 40 from (10, 10)]

위의 코드에서 rc1은 기본 생성자를 사용하여 생성되었기 때문에 모든 멤버 변수가 0으로 초기화됩니다. rc2는 (10, 10) 좌표부터 크기가 60x40인 사각형이라는 것을 나타냅니다. 4개 정수를 생성자 인자로 사용하는데, 이 인자들은 차례대로 Rect_ 클래스의 멤버 변수 x, y, width, height 값으로 설정됩니다.

 

Rect_ 클래스는 Size_ 또는 Point_ 클래스 객체와의 산술 연산자가 오버로딩되어 있습니다. 덧셈 연산자를 이용하여 Rect_ 객체와 Size_ 객체를 서로 더하면 사각형의 가로와 세로 크기가 변경됩니다. 반면 Rect_ 객체와 Point_ 객체를 서로 더하거나 빼면 사각형의 위치가 변경됩니다.

아래 코드는 Rect_ 객체의 크기 및 위치를 변경하는 예제 코드입니다.

cv::Rect rc3 = rc1 + cv::Size(50, 40);   // rc3 = [50 x 40 from (0, 0)]
cv::Rect rc4 = rc2 + cv::Point(10, 10);  // rc4 = [60 x 40 from (20, 20)]

 

Rect_ 객체끼리는 서로 '&', '|' 연산자를 이용한 논리 연산도 가능합니다. 두 개의 사각형 객체끼리 '&' 연산을 수행하면 두 사각형이 교차하는 사각형 영역을 반환합니다. 반면 '|' 연산을 수행하면 두 사각형을 모두 포함하는 최소 크기의 사각형을 반환합니다.

cv::Rect rc5 = rc3 & rc4; // rc5 = [30 x 20 from (20, 20)]
cv::Rect rc6 = rc3 | rc4; // rc6 = [80 x 60 from (0, 0)]

 

이 클래스 또한 C++의 표준 입출력 연산을 지원합니다.

std::cout << "rc5: " << rc5 << std::endl;
std::cout << "rc6: " << rc6 << std::endl;

 


RotatedRect

이 클래스는 회전된 사각형을 표현하는 클래스입니다. 여기에는 사각형의 중심 좌표를 나타내는 center, 사각형의 가로 및 세로 크기를 나타내는 size, 회전 각도를 나타내는 angle을 멤버 변수로 갖습니다. 이 클래스의 정의는 다음과 같습니다.

class CV_EXPORTS RotatedRect
{
public:
    //! default constructor
    RotatedRect();
    /** full constructor
    @param center The rectangle mass center.
    @param size Width and height of the rectangle.
    @param angle The rotation angle in a clockwise direction. When the angle is 0, 90, 180, 270 etc.,
    the rectangle becomes an up-right rectangle.
    */
    RotatedRect(const Point2f& center, const Size2f& size, float angle);
    /**
    Any 3 end points of the RotatedRect. They must be given in order (either clockwise or
    anticlockwise).
     */
    RotatedRect(const Point2f& point1, const Point2f& point2, const Point2f& point3);

    /** returns 4 vertices of the rectangle
    @param pts The points array for storing rectangle vertices. The order is bottomLeft, topLeft, topRight, bottomRight.
    */
    void points(Point2f pts[]) const;
    //! returns the minimal up-right integer rectangle containing the rotated rectangle
    Rect boundingRect() const;
    //! returns the minimal (exact) floating point rectangle containing the rotated rectangle, not intended for use with images
    Rect_<float> boundingRect2f() const;
    //! returns the rectangle mass center
    Point2f center;
    //! returns width and height of the rectangle
    Size2f size;
    //! returns the rotation angle. When the angle is 0, 90, 180, 270 etc., the rectangle becomes an up-right rectangle.
    float angle;
};

RotatedRect 클래스는 위에서 살펴본 클래스와는 달리 템플릿 클래스가 아니며, 모든 정보를 float를 사용하여 표현합니다. 중심 좌표를 Size2f 클래스를 사용하고, 크기 정보는 Size2f 클래스, 회전 각도는 float를 사용합니다.

 

RotatedRect 클래스를 사용하여 중심 좌표가 (40, 30), 크기는 40 x 20, 시계 방향으로 30도만큼 회전된 사각형 객체는 다음과 같이 표현할 수 있습니다.

cv::RotatedRect rr1(cv::Point2f(40, 30), cv::Size2f(40, 20), 30.f);

 

만약 회전된 사각형 객체의 각 꼭지점 좌표를 알고 싶다면 RotatedRect::points() 멤버 함수를 사용하면 됩니다. 이 함수는 크기가 4인 Point2f 타입의 배열을 인자로 받습니다.

cv::Point2f pts[4];
rr1.points(pts);

이 함수를 실행하면 사각형의 네 꼭지점 좌표가 pts 배열에 저장되며, 각 좌표는 다음과 같습니다.

이 좌표는 사각형 좌측 하단 꼭지점부터 시계 방향으로 각 좌표를 얻습니다.

 

 

RotatedRect::boundingRect() 함수는 회전된 사각형을 감싸는 최소 크기의 사각형 정보(bounding box)를 반환합니다.

cv::Rect br = rr1.boundingRect();

 


Range

이 클래스는 범위 또는 구간을 표현하는 클래스입니다. 범위의 시작과 끝을 나타내는 start와 end 멤버 변수를 가지고 있으며, 이 클래스의 정의는 다음과 같습니다.

class CV_EXPORTS Range
{
public:
    Range();
    Range(int _start, int _end);
    int size() const;
    bool empty() const;
    static Range all();

    int start, end;
};

멤버 함수 size()는 범위 크기(end - start)를 반환하며, empty() 함수는 start와 end가 같으면 true를 반환합니다.

전역 함수 all()은 start = INT_MIN, end = INT_MAX로 설정된 Range 객체를 반환합니다.

 

Range 클래스는 start부터 end까지의 정수 단위 범위를 표현하는데, 이때, start는 범위에 포함되고 end는 범위에 포함되지 않습니다.

cv::Range r1(0, 10); // [0,1,2,3,4,5,6,7,8,9]

 


String

많은 C/C++ 프로그램이 그러하듯 OpenCV에서 문자열을 다루는 경우가 많습니다. OpenCV에서 이미지를 출력하는 창에 고유 문자열을 지정하여 구분하거나, 이미지에 텍스트를 출력하는 기능도 제공합니다. C++에서 std::string 클래스를 사용하여 처리하듯이 OpenCV에서는 cv::String 클래스를 사용하여 문자열을 저장하고 처리합니다.

 

원래 OpenCV 라이브러리에서는 자체적인 String 클래스를 정의하여 사용했는데, std::string 클래스와 완전히 호환되도록 설계되어 있어 std::string 클래스를 다루는 방식과 유사하게 사용할 수 있었습니다. 그러다 OpenCV 4.0부터 자체적인 String 클래스 정의를 삭제하고, 대신 C++ 표준 라이브러리의 std::string 클래스를 String 클래스로 이름을 재정의하여 사용하고 있습니다.

실제 OpenCV 헤더에는 아래의 코드가 존재합니다.,

typedef std::string String;

 

결국 OpenCV 4.0부터는 std::string와 cv::String 클래스가 완전히 동일한 클래스입니다. 다만 코드 호환성을 위해 OpenCV 코드에서는 여전히 std::string 대신 cv::String을 사용하고 있습니다.

 

 

댓글