3. OpenCV 주요 기능

OpenJR·2022년 4월 11일
0

3. OpenCV 주요 기능

VideoCapture 클래스

  • OpenCV에서는 카메라와 동영상으로부터 프레임(frame)을 받아오는 작업을 VideoCapture 클래스 하나로 처리함
  • 일단 카메라와 동영상을 여는 작업이 수행되면, 이후에는 매 프레임을 받아오는 공통의 작업을 수행

카메라 열기

bool VideoCapture::open(int index, int apiPreference = CAP_ANY);
VideoCapture& VideoCapture::operator >> (Mat& image);

VideoCapture cap;
cap.open("media.avi");	// 동영상 사용
cap.open(0);			// 카메라 사용

index

  • 사용할 캡쳐 장치의 ID. (camera_id + domain_offset_id)
  • 시스템 기본 카메라를 기본 방법으로 열려면 0을 지정.
  • 컴퓨터에 여러 대의 카메라가 연결되어 있으면 0, 1, 순서로 지정.

apiPreference: 잘 안씀

  • 선호하는 카메라 처리 방법을 지정.
  • e.g.) cv::CAP_DSHOW, cv::CAP_MSMF, cv::CAP_V4L, etc.

반환값:

  • VideoCapture 생성자는 VideoCapture 객체를 반환.
  • VideoCapture::open() 함수는 작업이 성공하면 true를, 실패하면 false를 반환.

현재 프레임 받아오기

VideoCapture& VideoCapture::operator >> (Mat& image);

Mat frame;
cap >> frame;

image: 현재 프레임. 만약 현재 프레임을 받아오지 못하면 비어 있는 영상으로 설정됨.

반환값: VideoCapture::read() 함수는 작업이 성공하면 true를, 실패하면 false를 반환.

카메라와 동영상 속성 값 참조와 설정

double VideoCapture::get(int propId) const;
bool VideoCapture::set(int propId, double value);

int w = cvRound(cap.get(CAP_PROP_FRAME_WIDTH));		
int h = cvRound(cap.get(CAP_PROP_FRAME_HEIGHT));

propId: 속성 플래그

  • CAP_PROP_FRAME_WIDTH: 프레임 가로 크기

  • CAP_PROP_FRAME_HEIGHT: 프레임 세로 크기

  • CAP_PROP_FPS: 초당 프레임 수

  • CAP_PROP_FRAME_COUNT: 비디오 파일의 총 프레임 수

  • CAP_PROP_POS_FRAMES: 현재 프레임 번호

  • CAP_PROP_EXPOSURE: 노출값

  • ...

value: 속성 값, 필요한 경우 정수형으로 변환해 사용

동영상 저장하기

VideoWriter::VideoWriter(const String& filename, int fourcc, double fps,
                         Size frameSize, bool isColor = true);
bool VideoWriter::open(const String& filename, int fourcc, double fps,
                       Size frameSize, bool isColor = true);

double fps = 30;
Size sz(w, h);
int fourcc = VideoWriter::fourcc('X', 'V', 'I', 'D');

VideoWriter output("output.avi", fourcc, fps, sz);
output.release()
cap.release()

filename: (저장할) 동영상 파일 이름

fourcc: 압축 방식을 나타내는 4개의 문자. videoWriter::fourcc() 함수로 생성.

  • Videowriter::fourcc('D', 'I', 'V', 'X'): DIVX MPEG-4 코덱
  • Videowriter::fourcc('X', 'V', 'I', 'D'): XVID MPEG-4 코덱
  • Videowriter::fourcc('X', '2', '6', '4'): H.264/AVC 코덱
  • Videowriter::fourcc('M', 'J', 'P', 'G'): Motion-JPEG 코덱

fps: 초당 프레임 수

framesize: 비디오 프레임 크기

isColor: 컬러 동영상 플래그. false로 지정하면 그레이스케일 동영상

fps 설정 or 얻기

double fps = 30;
int delay = cvRound(1000 / fps);

if (waitKey(delay) == 27) {
    	...
}
// ------
double fps = cvRound(cap.get(CAP_PROP_FPS));

다양한 그리기 함수

직선 그리기

void line(InputOutputArray img, Point pt1, Point pt2, const Scalar& color,
          int thickness = 1, int lineType = LINE_8, int shift = 0);

line(frame, Point(570, 280), Point(0, 560), Scalar(255, 0, 0), 2);
line(frame, { 570, 280 }, { 0, 560 }, 255, 2);

img: 입출력 영상

pt1: 시작점 좌표

pt2: 끝점 좌표

color: 선 색상(또는 밝기)

thickness: 선 두께

lineType: 선 타입. LINE_4, LINE_8, LINE-AA 중 하나를 지정.

shift: 그리기 좌표 값의 축소 비율.

사각형 그리기

void rectangle(InputoutputArray img, Rect rec, const Scalar& color,
               int thickness = 1, int lineType = LINE_8, int shift = 0);

Rect rec(20, 30, 300, 400);
rectangle(frame, rec, Scalar(255, 0, 0), 2);

img: 입출력 영상

rec: 사각형 위치 정보

color: 선 색상

thickness: 선 두께, -1이면 내부를 채움

lineType: 선 타입. LINE_4, LINE_8, LINE-AA 중 하나를 지정.

shift: 그리기 좌표 값의 축소 비율

원 그리기

void circle(InputOutputArray img, Point center, int radius, const Scalar& color,
            int thickness = 1, int lineType = LINE_8, int shift = 0);

circle(frame, Point(200, 300), 100, Scalar(255, 255, 255), 2);

img: 입출력 영상

center: 원 중심 좌표

radius: 원 반지름

color: 선 색상

thickness: 선 두께, -1이면 내부를 채움

lineType: 선 타입. LINE_4, LINE_8, LINE-AA 중 하나를 지정.

shift: 그리기 좌표 값의 축소 비율

다각형 그리기

void polylines (InputoutputArray img, InputArrayofArrays pts, bool isClosed,
                const Scalar & color, int thickness = 1, int lineType = LINE_8, int shift = 0);

vector<Point> pts = { {240, 280}, {400, 280}, {620, 440}, {20, 440} };
polylines(frame, pts, true, Scalar(255), 1);

img: 입출력 영상

pts: 다각형 외곽선 점들의 집합 (vector<Point>)

isClosed: true면 시작점과 끝점을 서로 이음(폐곡선)

color: 선 색상

thickness: 선 두께, -1이면 내부를 채움

lineType: 선 타입. LINE_4, LINE_8, LINE-AA 중 하나를 지정.

shift: 그리기 좌표 값의 축소 비율

다각형 채우기

void fillPoly(InputOutputArray img, InputArrayOfArrays pts, const Scalar & color,
              int lineType = LINE_8, int shift = 0, Point offset = Point());

vector<Point> pts = { {240, 280}, {400, 280}, {620, 440}, {20, 440} };
fillPoly(frame, pts, Scalar(255));

img: 입출력 영상

pts: 다각형 외곽선 점들의 집합 (vector<Point>)

color: 선 색상

lineType: 선 타입. LINE_4, LINE_8, LINE-AA 중 하나를 지정.

shift: 그리기 좌표 값의 축소 비율

offset: 거의 안씀

문자열 출력

void putText (InputOutputArray img, const String& text, Point org, int fontFace,
              double fontScale, Scalar color, int thickness = 1,
              LINE_8, bool bottomLeftorigin = false);

String text = format("frame number: %d", pos);
putText(frame, text, Point(20, 50), FONT_HERSHEY_SIMPLEX,
        0.7, Scalar(0, 0, 255), 1, LINE_AA);

img: 입출력 영상

text: 출력할 문자열

org: 문자열이 출력될 좌측 하단의 시작 좌표

fontFace: 폰트 종류

  • FONT_HERSHEY_SIMPLEX
  • FONT_HERSHEY_PLAIN (1)
  • FONT_HERSHEY_DUPLEX (2)
  • FONT_HERSHEY_COMPLEX (3)
  • FONT_HERSHEY_TRIPLEX (4)
  • FONT_HERSHEY_COMPLEX_SMALL (5)
  • FONT_HERSHEY_SCRIPT_SIMPLEX (6)
  • FONT_HERSHEY__SCRIPT_SIMPLEX (7)
  • FONT_ITALIC (16)

color: 선 색상

thickness: 선 두께, -1이면 내부를 채움

lineType: 선 타입. LINE_4, LINE_8, LINE-AA 중 하나를 지정.

shift: 그리기 좌표 값의 축소 비율

이벤트 처리하기

마우스 입력 처리하기

void setMouseCallback (const String& winname, MouseCallback onMouse, void* userdata = 0);

setMouseCallback("src", on_mouse);

winname: 창 이름

onMouse: 마우스 콜백 함수 이름, 아래와 같은 형식의 함수를 정의하고, 해당 함수 이름을 지정.

  •   typedef void (*MouseCallback) (int event, int x, int y, int flags,
                                     void* userdata);
      
      void on_mouse(int event, int x, int y, int flags, void*)
      {
      	switch (event) {
      	case EVENT_LBUTTONDOWN:
      		ptOld = Point(x, y);
      		cout << "EVENT_LBUTTONDOWN: " << x << ", " << y << endl;
      		break;
      	case EVENT_LBUTTONUP:
      		cout << "EVENT_LBUTTONUP: " << x << ", " << y << endl;
      		break;
      	case EVENT_MOUSEMOVE:
      		if (flags & EVENT_FLAG_LBUTTON) { // &해야 모든 경우를 고려
      			line(src, ptOld, Point(x, y), Scalar(0, 255, 255), 3, LINE_AA);
      			ptOld = Point(x, y);
      			imshow("src", src); // 그린게 업데이트되게 하는 코드
      		}
      		break;
      	default:
      		break;
      	}
      }

event: 마우스 이벤트 종류. MouseEventTypes 상수.

х, у: 마우스 이벤트 발생 좌표

flags: 마우스 이벤트 플래그. MouseEventFlags 상수.

userdata: setMouseCallback() 함수에서 지정한 사용자 지정 데이터

userdata: 콜백 함수에 전달할 사용자 지정 데이터 (optional)

enum MouseEventTypes {
	EVENT_MOUSEMOVE			= 0, 
    EVENT_LBUTTONDOWN		= 1, 
    EVENT_RBUTTONDOWN		= 2, 
    EVENT_MBUTTONDOWN		= 3, 
    EVENT_LBUTTONUP			= 4, 
    EVENT_RBUTTONUP			= 5, 
    EVENT_MBUTTONUP			= 6, 
    EVENT_LBUTTONDBLCLK		= 7, 
    EVENT_RBUTTONDBLCLK		= 8, 
    EVENT_MBUTTONDBLCLK		= 9, 
    EVENT_MOUSEWHEEL		= 10,//!< positive and negative values mean forward and backward scrolling, respectively.
    EVENT_MOUSEHWHEEL		= 11 //!< positive and negative values mean right and left scrolling, respectively.
};
//! Mouse Event Flags see cv::MouseCallback
enum MouseEventFlags {
    EVENT_FLAG_LBUTTON		= 1, 
    EVENT_FLAG_RBUTTON		= 2, 
    EVENT_FLAG_MBUTTON		= 4, 
    EVENT_FLAG_CTRLKEY		= 8, 
    EVENT_FLAG_SHIFTKEY		= 16,
    EVENT_FLAG_ALTKEY		= 32
};

트랙바 사용하기

int createTrackbar(const String& trackbarname, const String& winname, int* value, 
                   int count, TrackbarCallback onChange = 0, void* userdata = 0);

namedWindow("image");
int value = 0;
createTrackbar("level", "image", &value, 16, on_level_change, (void*)&img);

trackbarname: 트랙바 이름

winname: 트랙바를 생성할 창 이름

value: 트랙바 위치 값을 받을 정수형 변수의 주소

count: 트랙바 최대 위치 (최소 위치는 항상 0)

onChange:

  •   typedef void (*TrackbarCallback)(int pos, void* userdata);
      
      void on_level_change(int pos, void* userdata)
      {
      	Mat img = *(Mat*)userdata; // 이렇게 하면 얕은 복사 동기화
      
      	img.setTo(pos * 16);
      	imshow("image", img);
      }
  • 트랙바 위치가 변경될 때마다 호출되게 만들 콜백 함수 이름(함수의 포인터).

  • 만약 NULL을 지정하면 콜백 함수는 호출되지 않고 value로 지정한 변수 값만 갱신됨.

userdata: 트랙바 콜백 함수에 전달할 사용자 데이터의 포인터 (Optional)

반환값: 정상 동작하면 1, 실패하면 0.

유용한 OpenCV 기능

연산 시간 측정 방법

TickMeter tm;
tm.start();

func1();

tm.stop();
cout << "func1(): << tm.getTimeMilli() << "ms." << endl;
tm.reset();

tm.start();

func2();

tm.stop();
cout << "func2(): << tm.getTimeMilli() << "ms." << endl;

마스크 연산과 ROI

void copyTo(InputArray src, OutputArray dst, InputArray mask);

Mat mask = Mat::zeros(h, w, CV_8U);
fillPoly(mask, roi, Scalar(255));
dst.copyTo(frame, mask);

src: 입력 영상

mask: 마스크 영상. cV_8U. 0이 아닌 픽셀에 대해서만 복사 연산을 수행.

dst: 출력 영상.

유용한 OpenCV 함수

행령의 합

Scalar sum(InputArray src);

uchar data[] = {1, 2, 3, 4, 5, 6};
Mat mat1(2, 3, CV_8UC1, data);
int sum1 = (int)sum(mat1)		// 21

src: 입력 행렬. 1~4 채널.

반환값: 행렬 원소들의 합

행렬의 평균

Scalar mean(InputArray src, InputArray mask = noArray());

Mat img = imread("lenna.bmp", IMREAD_GRAYSCALE);
double mean1 = mean(img)[0]		// 124.0

src: 입력 행렬. 1~4 채널.

mask: 마스크 영상.

반환값: 행렬 원소들의 합

행렬의 최댓값/최솟값 구하기

void minMaxLoc(InputArray src, double* minVal, double* maxVal = 0,
               Point* minloc= 0, Point* maxLoc= 0, InputArray mask = noArray());

Mat img = imread ("lenna.bmp", IMREAD_GRAYSCALE);
double minv, maxv;
double minLoc, maxLoc;
minMaxLoc(img, &minv, &maxv, &minLoc, &maxLoc); // 25, 245, [508, 71], [116, 273]

src: 입력 행렬. 단일 채널.

minVal, maxVal: 최솟값/최댓값 변수 포인터 (필요 없으면 NULL 지정)

minLoc, maxLoc: 최솟값/최댓값 위치 변수 포인터 (필요 없으면 NULL 지정)

mask: 마스크 영상.

행렬의 자료형 변환

void Mat::convertTo(OutputArray m, int rtype, double alpha=1, double beta=0) const;

Mat img = imread ("lenna.bmp", IMREAD_GRAYSCALE);
Mat fimg;
img.convertTo(fimg, CV_32FC1);

m: 출력 영상(행렬)

rtype: 원하는 출력 행렬 타입

alpha: 추가적으로 곱할 값

beta: 추가적으로 더할 값

행렬의 정규화 (원소값 정규화)

void normalize(InputArray src, InputOutputArray dst, double alpha = 1, double beta = 0,
               int norm_type = NORM_L2, int dtype = -1, InputArray mask = noArray());

Mat src = imread ("lenna.bmp", IMREAD_GRAYSCALE);
Mat dst;
normalize(src, dst, 0, 255, NORM_MINMAX);

src: 입력 행렬(영상)

dst: 출력 행렬. src와 같은 크기.

alpha: (노름 정규화인 경우) 목표 노름(norm) 값, (NORM_MINMAX인 경우) 최솟값

beta: (NORM_MINMAX인 경우) 최댓값

norm_type: 정규화 타입. NORM_INF, NORM_L1, NORM_L2, JNORM MINMAX 중 하나를 지정. NORM_MINMAX를 지정할 경우, 출력 행렬 dst의 최솟값은 alpha, 최댓값은 beta가 되도록 설정함.

dtype: 출력 행렬의 타입

mask: 마스크 영상

색 변환 함수

void cvtColor(InputArray src, OutputArray dst, int code, int dstCn = 0);

Mat src = imread ("lenna.bmp");
Mat dst;
cvtColor(src, dst, COLOR_BGR2GRAY);

src: 입력 영상

dst: 출력 영상

code: 색 변환 코드(OpenCV 문서 페이지 참고)

  • COLOR_BGR2GRAY / COLOR_GRAY2BGR: BGR <> GRAY
  • COLOR_BGR2HSV / COLOR_HSV2BGR: BGR <> HSV
  • COLOR_BGR2YCrCb / COLOR_YCrCb2BGR: BGR <> YCrCb

dstCn: 결과 영상의 채널 수. 0이면 자동 결정됨.

채널 분리

void split(InputArray src, OutputArray0fArrays mv);

Mat src = imread("lenna.bmp");

vector<Mat> planes;
split(src, pļanes);

src: (입력) 다채널 영상

mv: (출력) 행렬의 벡터. vector<Mat>

채널 결합

void merge (InputArrayofArrays mv, OutputArray dst);

swap (planes[0], planes[2]);

Mat dst;
merge (planes, dst);

mv: (입력) 1채널 Mat 배열 또는 행렬의 벡터

dst: (출력) 다채널 행렬

profile
Jacob

0개의 댓글