-
OpenCV Draw & EventOpenCV/OpenCV_C++ 2023. 12. 14. 20:34
OpenCV Draw
OpenCV에서는 그리기 함수를 제공한다.
선, 도형등을 그릴수 있으며, 문자열도 출력이 가능하다.
그리기 방식 세부 그리기 방식 함수 이름 선 그리기 직선 그리기 line() 화살표 그리기 arrowedLine() 마커 그리기 drawMarker() 도형 그리기 사각형 그리기 rectangle() 원 그리기 circle() 타원 그리기 ellipse() 다각형 그리기 polylines(), fillPoly() 문자열 출력하기 문자열 출력하기 putText() 출력 문자열의 크기 계산 getTextSize() 참고: OpenCV documentation
1. 선 그리기
- 직선 그리기
void line(InputOutputArray img, Point pt1, Point pt2, const Scalar& color, int thickness = 1, int lineType = LINE_8, int shift = 0);
- img: 입출력 영상 또는 이미지
- pt1: 시작점 좌표
- pt2: 끝점 좌표
- color: 선 색상
- thickness: 선 두께
- lineType: 선 타입(LINE_4, LINE_8, LINE_AA중 하나를 지정. LINE_AA가 더 부드러운 선을 그림)
- shift: 그리기 좌표 값의 축소 비율
예제
#include <iostream> #include "opencv2/opencv.hpp" int main() { cv::Mat void_img(cv::Size(640, 480), CV_8UC3, cv::Scalar(0, 0, 0)); int thickness = 5; cv::line(void_img, cv::Point(320, 240), cv::Point(0, 0), cv::Scalar(255, 0, 0), thickness, cv::LINE_4); cv::line(void_img, cv::Point(320, 240), cv::Point(640, 480), cv::Scalar(0, 255, 0), thickness, cv::LINE_8); cv::line(void_img, cv::Point(320, 240), cv::Point(640, 0), cv::Scalar(0, 0, 255), thickness, cv::LINE_AA); cv::imshow("void_img", void_img); cv::waitKey(); cv::destroyAllWindows(); return 0; }
결과
- 화살표 그리기
void line(InputOutputArray img, Point pt1, Point pt2, const Scalar& color, int thickness = 1, int lineType = LINE_8, int shift = 0, double tipLength = 0.1);
- img: 입출력 영상 또는 이미지
- pt1: 시작점 좌표
- pt2: 끝점 좌표
- color: 선 색상
- thickness: 선 두께
- line_type : 선 타입(LINE_4, LINE_8, LINE_AA중 하나를 지정. LINE_AA가 더 부드러운 선을 그림)
- shift: 그리기 좌표 값의 축소 비율
- tipLength: 전체 직선 길이에 대해 화살표 길이 비율
예제
#include <iostream> #include "opencv2/opencv.hpp" int main() { cv::Mat void_img(cv::Size(640, 480), CV_8UC3, cv::Scalar(0, 0, 0)); int thickness = 1; cv::arrowedLine(void_img, cv::Point(320, 240), cv::Point(50, 50), cv::Scalar(0, 0, 255), thickness, cv::LINE_AA, 0, 0.1); cv::imshow("void_img", void_img); cv::waitKey(); cv::destroyAllWindows(); return 0; }
결과
- 마커 그리기
void line(InputOutputArray img, Point position, const Scalar& color, int markerType = MARKER_CROSS, int markerSize = 20, int thickness = 1, line_type = 8);
- img: 입출력 영상 또는 이미지
- position: 마커 출력 위치
- color: 선 색상
- markerType: 마커의 종류, MarkerTypes 열거형 상수 중 하나를 지정.
- markerSize: 마커의 크기
MarkerTypes 열거형 상수 설명 MARKER_CROSS 십자가 MARKER_TILTED_CROSS X모양 MARKER_STAR ⁕모양 (십자가 + X) MARKER_DIAMOND 마름모 MARKER_SQUARE 정사각형 MARKER_TRIANGLE_UP △ 모양 MARKER_TRIANGLE_DOWN ▽ 모양 - markerSize: 마커 크기
- thickness: 선 두께
- line_type: 선 타입(LINE_4, LINE_8, LINE_AA중 하나를 지정. LINE_AA가 더 부드러운 선을 그림)
예제
#include <iostream> #include "opencv2/opencv.hpp" int main() { cv::Mat void_img(cv::Size(640, 480), CV_8UC3, cv::Scalar(0, 0, 0)); cv::drawMarker(void_img, cv::Point(20, 240), cv::Scalar(0, 255, 255), cv::MARKER_CROSS); cv::drawMarker(void_img, cv::Point(60, 240), cv::Scalar(0, 255, 255), cv::MARKER_TILTED_CROSS); cv::drawMarker(void_img, cv::Point(100, 240), cv::Scalar(0, 255, 255), cv::MARKER_STAR); cv::drawMarker(void_img, cv::Point(140, 240), cv::Scalar(0, 255, 255), cv::MARKER_DIAMOND); cv::drawMarker(void_img, cv::Point(180, 240), cv::Scalar(0, 255, 255), cv::MARKER_SQUARE); cv::drawMarker(void_img, cv::Point(220, 240), cv::Scalar(0, 255, 255), cv::MARKER_TRIANGLE_UP); cv::drawMarker(void_img, cv::Point(260, 240), cv::Scalar(0, 255, 255), cv::MARKER_TRIANGLE_DOWN); cv::imshow("void_img", void_img); cv::waitKey(); cv::destroyAllWindows(); return 0; }
결과
2. 도형 그리기
- 사각형 그리기
void rectangle(InputOutputArray img, Point pt1, Point pt2, const Scalar& color, int thickness = 1, lineType = LINE_8, int shift = 0); void rectangle(InputOutputArray img, Rect rec, const Scalar& color, int thickness = 1, lineType = LINE_8, int shift = 0);
- img: 입출력 영상 또는 이미지
- rec: 사각형 위치 정보. Rect 객체(Point 객체 pt1, pt2로 대체 가능)
- color: 선 색상
- thickness: 선 두께. -1 또는 FILLED를 사용하면 내부를 채움.
- lineType: 선 타입.
- shift: 그리기 좌표 값의 축소 비율(오른쪽 비트 시프트 연산 '>>')
예제
#include <iostream> #include "opencv2/opencv.hpp" int main() { cv::Mat void_img(cv::Size(640, 480), CV_8UC3, cv::Scalar(0, 0, 0)); cv::Rect rec1 (20, 20, 50, 100); // 20, 20의 위치에 w = 50, h = 100 사각형을 그림 cv::rectangle(void_img, rec1, cv::Scalar(255, 0, 0), -1); cv::Point2i point1(320, 240); cv::Point2i point2(400, 300); cv::rectangle(void_img, point1, point2, cv::Scalar(0, 255, 255), 1); cv::imshow("void_img", void_img); cv::waitKey(); cv::destroyAllWindows(); return 0; }
결과
- 원 그리기
void circle(InputOutputArray img, Point center, int radius const Scalar& color, int thickness = 1, lineType = LINE_8, int shift = 0);
- img: 입출력 영상 또는 이미지
- center: 원 중심 좌표
- radius: 원 반지름
- color: 선 색상
- thickness: 선 두께. -1 또는 FILLED를 사용하면 내부를 채움.
- lineType: 선 타입
- shift: 그리기 좌표 값의 축소 비율(오른쪽 비트 시프트 연산 '>>')
예제
#include <iostream> #include "opencv2/opencv.hpp" int main() { cv::Mat void_img(cv::Size(640, 480), CV_8UC3, cv::Scalar(0, 0, 0)); cv::Point2i point1(320, 240); int radius = 100; cv::circle(void_img, point1, radius, cv::Scalar(0, 255, 255), 1); cv::Point2i point2(160, 120); cv::circle(void_img, point2, radius, cv::Scalar(0, 255, 0), -1); cv::imshow("void_img", void_img); cv::waitKey(); cv::destroyAllWindows(); return 0; }
결과
- 타원 그리기
void ellipse(InputOutputArray img, Point center, Size axes, double angle, double startAngle, double endAngle, const Scalar& color, int thickness = 1, lineType = LINE_8, int shift = 0);
- img: 입출력 영상 또는 이미지
- center: 타원 중심 좌표
- axes: 타원의 반지름. Size(x축 반지름, y축 반지름)
- angle: 타원 회전 각도(x축 기준, 시계방향)
- startAngle: 타원 호의 시작 각도(x축 기준, 시계방향)
- endAngle: 타원 호의 끝 각도(x축 기준, 시계방향)
- color: 선 색상
- thickness: 선 두께. -1 또는 FILLED를 사용하면 내부를 채움.
- lineType: 선 타입
- shift: 그리기 좌표 값의 축소 비율(오른쪽 비트 시프트 연산 '>>')
예제
#include <iostream> #include "opencv2/opencv.hpp" int main() { cv::Mat void_img(cv::Size(640, 480), CV_8UC3, cv::Scalar(0, 0, 0)); cv::Point2i point1(320, 240); double angle(20); double startAngle(0); double endAngle(360); cv::ellipse(void_img, point1, cv::Size(100, 50), angle, startAngle, endAngle, cv::Scalar(255, 255, 0), -1, cv::LINE_AA); cv::ellipse(void_img, point1, cv::Size(200, 100), angle, startAngle, endAngle, cv::Scalar(0, 0, 255), 2, cv::LINE_AA); cv::imshow("void_img", void_img); cv::waitKey(); cv::destroyAllWindows(); return 0; }
결과
- 다각형 그리기
void polylines(InputOutputArray img, InputArrayOfArrays pts, bool isClosed, const Scalar& color, int thickness = 1, lineType = LINE_8, int shift = 0);
- img: 입출력 영상 또는 이미지
- pts: 다각형 외곽 점들의 좌표 배열. 주로 vector<Point> 타입
- isClosed: 다각형이 닫혀 있는지를 나타내는 플래그. 이 값이 true이면 다각형의 마지막 꼭지점과 첫 번째 꼭지점을 잇는 직선을 추가로 그려준다.
- color: 선 색상
- thickness: 선 두께. -1 또는 FILLED를 사용하면 내부를 채움.
- lineType: 선 타입
- shift: 그리기 좌표 값의 축소 비율(오른쪽 비트 시프트 연산 '>>')
예제
#include <iostream> #include <vector> #include "opencv2/opencv.hpp" int main() { cv::Mat void_img(cv::Size(640, 480), CV_8UC3, cv::Scalar(0, 0, 0)); std::vector<cv::Point> my_points1; std::vector<cv::Point> my_points2; my_points1.push_back(cv::Point(250, 250)); my_points1.push_back(cv::Point(300, 250)); my_points1.push_back(cv::Point(300, 300)); my_points1.push_back(cv::Point(350, 300)); my_points1.push_back(cv::Point(350, 350)); my_points1.push_back(cv::Point(250, 350)); my_points2.push_back(cv::Point(20, 20)); my_points2.push_back(cv::Point(70, 20)); my_points2.push_back(cv::Point(70, 70)); my_points2.push_back(cv::Point(120, 70)); my_points2.push_back(cv::Point(120, 120)); my_points2.push_back(cv::Point(70, 120)); cv::polylines(void_img, my_points1, true, cv::Scalar(0, 255, 255), 1); cv::polylines(void_img, my_points2, false, cv::Scalar(0, 0, 255), 2); cv::imshow("void_img", void_img); cv::waitKey(); cv::destroyAllWindows(); return 0; }
결과
3. 문자열 출력하기
- 문자열 출력하기
void putText(InputOutputArray img, const String& text, Point org, int fontFace, double fontScale Scalar color, int thickness = 1, int lineType = LINE_8, bool bottomLeftOrigin = false);
- img: 입출력 영상 또는 이미지.
- text: 출력할 문자열.
- org: 문자열이 출력될 좌측 하단 시작 좌표.
- fontFace: 폰트 종류. cv::HersheyFonts 참조.
HersheyFonts 열거형 상수 설명 FONT_HERSHEY_SIMPLEX 일반 크기의 산세리프 폰트 FONT_HERSHEY_PLAIN 작은 크기의 산세리프 폰트 FONT_HERSHEY_DUPLEX 일반 크기의 산세리프 폰트( FONT_HERSHEY_SIMPLEX 보다 복잡한 형태) FONT_HERSHEY_COMPLEX 일반 크기의 세리프 폰트 FONT_HERSHEY_TRIPLEX 일반 크기의 세리프 폰트( FONT_HERSHEY_COMPLEX 보다 복잡한 형태) FONT_HERSHEY_COMPLEX_SMALL FONT_HERSHEY_COMPLEX보다 작은 폰트 FONT_HERSHEY_SCRIPT_SIMPLEX 필기체 스타일의 폰트 FONT_HERSHEY_SCRIPT_COMPLEX 필기체 스타일의 폰트(FONT_HERSHEY_SCRIPT_SIMPLEX 보다 복잡한 형태) FONT_ITALIC 이텔릭체를 위한 폰트 - fontScale: 폰트 크기 지정. 기본 폰트 크기의 배수를 지정.
- color: 문자열 색상.
- thickness: 폰트 두께.
- lineType: 선 타입.
- bottomLeftOrigin: 이 값이 true이면 영상 좌측 하단을 원점으로 간주. false이면 좌측 상단을 원점으로 간주.
예제
#include <iostream> #include "opencv2/opencv.hpp" int main() { cv::Mat void_img(cv::Size(640, 480), CV_8UC3, cv::Scalar(0, 0, 0)); std::string my_str("Hellow OpenCV!!"); cv::Point org(320, 240); cv::putText(void_img, my_str, org, cv::FONT_HERSHEY_COMPLEX, 1, cv::Scalar(0, 255, 255), 1, cv::LINE_8, false); cv::putText(void_img, my_str, org, cv::FONT_HERSHEY_SIMPLEX, 1, cv::Scalar(0, 0, 255), 1, cv::LINE_8, true); cv::imshow("void_img", void_img); cv::waitKey(); cv::destroyAllWindows(); return 0; }
결과
- 출력 문자열의 크기 계산
Size getTextSize(const String& text, int fontFace, double fontScale, int thickness, int* baseLine);
- text: 출력할 문자열
- fontFace: 폰트 종류
- fontScale: 폰트 크기 확대/축소 비율
- thickness: 문자열을 그릴 때 사용할 선 두께
- baseLine: (출력) 가장 하단의 텍스트 위치를 기준으로 하는 기준선의 y좌표. 필요 없으면 0으로 지정.
- return: 지정한 문자열 출력시 차지하는 사각형 크기.
영상 중앙에 문자를 출력해보자.
예제
#include <iostream> #include "opencv2/opencv.hpp" int main() { cv::Mat void_img(cv::Size(640, 480), CV_8UC3, cv::Scalar(0, 0, 0)); const std::string my_str("Hellow OpenCV!!"); cv::Size sizeText = cv::getTextSize(my_str, cv::FONT_HERSHEY_COMPLEX, 2.0, 1, 0); cv::Size sizeImg = void_img.size(); cv::Point org((sizeImg.width - sizeText.width) / 2, (sizeImg.height + sizeText.height) / 2); cv::putText(void_img, my_str, org, cv::FONT_HERSHEY_COMPLEX, 2.0, cv::Scalar(0, 255, 0), 1); cv::imshow("void_img", void_img); cv::waitKey(); cv::destroyAllWindows(); return 0; }
결과
OpenCV Event
1. Keyboard Event
int waitKey(int delay = 0);
- delay: ms단위 대기 시간. delay ⩽ 0이면 무한히 기다린다.
- return: 눌린 키의 값. 키가 눌리지 않으면 -1.
참고
- waitKey()는 OpenCV창이 하나라도 있어야 정상 동작한다.
- imshow() 함수 호출 후에 waitKey()함수를 호출해야 영상이 화면에 나타난다.
- 주요 특수키: ESC(27), Enter(13), Tab(9)
- 화살표키, 함수키 등의 특수키에 대한 이벤트는 waitKeyEx()함수를 사용한다.
2. Mouse Event
void setMouseCallback(const String& winname, MouseCallback onMouse, void* userdata = 0);
- winname: 창 이름
- userdata: 콜백 함수에 전달할 사용자 지정 데이터(optional)
- onMouse: 마우스 콜백 함수 이름.
typedef void(*MouseCallback)(int event, int x, int y, int flags, void* userdata);
- event: 마우스 이벤트 종류, MouseEventTypes 상수
- x, y: 마우스 이벤트 발생 좌표
- flags: 마우스 이벤트 플래그, MouseEventFlags 상수.
- userdata: setMouseCallback() 함수에서 지정한 사용자 지정 데이터.
- MouseEventTypes
MouseEventTypes Explain NUM EVENT_MOUSEMOVE mouse pointer move 0 EVENT_LBUTTONDOWN left mouse button is pressed 1 EVENT_RBUTTONDOWN right mouse button is pressed 2 EVENT_MBUTTONDOWN middle mouse button is pressed 3 EVENT_LBUTTONUP left mouse button is released 4 EVENT_RBUTTONUP right mouse button is released 5 EVENT_MBUTTONUP middle mouse button is released 6 EVENT_LBUTTONDBLCLK left mouse button is double clicked 7 EVENT_RBUTTONDBLCLK right mouse button is double clicked 8 EVENT_MBUTTONDBLCLK middle mouse button is double clicked 9 EVENT_MOUSEWHEEL forward and backward scrolling 10 EVENT_MOUSEHWHEEL right and left scrolling 11 - MouseEventFlags
MouseEventFlags Explain NUM EVENT_FLAG_LBUTTON left mouse button is down 1 EVENT_FLAG_RBUTTON right mouse button is down 2 EVENT_FLAG_MBUTTON middle mouse button is down 4 EVENT_FLAG_CTRLKEY CTRL key is pressed 8 EVENT_FLAG_SHIFTKEY SHIFT key is pressed 16 EVENT_FLAG_ALTKEY ALT key is pressed 32 예제1 마우스 좌표 보기
#include <iostream> #include "opencv2/opencv.hpp" void on_mouse(int event, int x, int y, int flags, void*) { switch (event) { case cv::EVENT_LBUTTONDOWN: std::cout << "EVENT_LBUTTONDOWN: " << x << ", " << y << std::endl; break; case cv::EVENT_LBUTTONUP: std::cout << "EVENT_LBUTTONUP: " << x << ", " << y << std::endl; break; case cv::EVENT_MOUSEMOVE: std::cout << "EVENT_MOUSEMOVE: " << x << ", " << y << std::endl; break; } } int main() { cv::Mat img = cv::imread("lenna.bmp"); cv::namedWindow("img"); cv::setMouseCallback("img", on_mouse); cv::imshow("img", img); cv::waitKey(); cv::destroyAllWindows(); return 0; }
마우스 왼쪽 버튼을 누를 때, 뗄 때, 움직일 때 좌표를 출력해주는 것을 볼 수 있다.
예시2 선 그리기
#include <iostream> #include "opencv2/opencv.hpp" cv::Mat img; void on_mouse(int event, int x, int y, int flags, void*) { switch (event) { case cv::EVENT_LBUTTONDOWN: std::cout << "EVENT_LBUTTONDOWN: " << x << ", " << y << std::endl; break; case cv::EVENT_LBUTTONUP: std::cout << "EVENT_LBUTTONUP: " << x << ", " << y << std::endl; break; case cv::EVENT_MOUSEMOVE: if (flags & cv::EVENT_FLAG_LBUTTON) { std::cout << "EVENT_MOUSEMOVE: " << x << ", " << y << std::endl; cv::circle(img, cv::Point(x, y), 2, cv::Scalar(0, 255, 255), -1, cv::LINE_AA); cv::imshow("img", img); } default: break; } } int main() { img = cv::imread("lenna.bmp"); if (img.empty()) { std::cerr << "Image load failed!" << std::endl; return -1; } cv::namedWindow("img"); cv::setMouseCallback("img", on_mouse); cv::imshow("img", img); cv::waitKey(); return 0; }
결과
하지만 끊겨서 그려지므로 마우스 포인터를 이전 포인트에서 현재 포인트로 직선을 긋는 형태를 취해야 한다.
아래는 개선된 코드로 ptOld를 선언하였다.
예제2 개선
#include <iostream> #include "opencv2/opencv.hpp" cv::Mat img; cv::Point ptOld; void on_mouse(int event, int x, int y, int flags, void*) { switch (event) { case cv::EVENT_LBUTTONDOWN: ptOld = cv::Point(x, y); std::cout << "EVENT_LBUTTONDOWN: " << x << ", " << y << std::endl; break; case cv::EVENT_LBUTTONUP: std::cout << "EVENT_LBUTTONUP: " << x << ", " << y << std::endl; break; case cv::EVENT_MOUSEMOVE: if (flags & cv::EVENT_FLAG_LBUTTON) { std::cout << "EVENT_MOUSEMOVE: " << x << ", " << y << std::endl; cv::line(img, ptOld, cv::Point(x, y), cv::Scalar(0, 255, 255), 3, cv::LINE_AA); ptOld = cv::Point(x, y); cv::imshow("img", img); } default: break; } } int main() { img = cv::imread("lenna.bmp"); if (img.empty()) { std::cerr << "Image load failed!" << std::endl; return -1; } cv::namedWindow("img"); cv::setMouseCallback("img", on_mouse); cv::imshow("img", img); cv::waitKey(); return 0; }
결과
3. Track bar
영상의 출력창에 부착되어 프로그램 동작 중에 사용자가 지정된 범위 안의 값을 선택할 수 있는 GUI 슬라이더 컨트롤(Slider Control)이다.
int createTrackbar(const String& trackbarname, const String& sinname, int* value, int count TrackbarCallback onChange = 0, void* userdata = 0);
- trackbarname: 트랙바 이름
- winname: 트랙바를 생성할 창의 이름
- value: 트랙바 위치 값을 받을 정수형 변수의 주소
- count: 트랙바 최대 위치(최소는 항상 0)
- onChange: 트랙바 위치가 변경될 때마다 호출되게 만들 콜백 함수 이름(함수의 포인터). 만약, NULL을 지정하면 콜백 함수는 호출되지 않고 value로 지정한 변수 값만 생성 됨.
typedef void (*TrackbarCallback)(int pos, void* userdata);
- userdata: 트랙바 콜백 함수에 전달할 사용자 데이터의 포인터(Optional)
- return: 정상동작 1, 실패 0
예제
#include <iostream> #include "opencv2/opencv.hpp" void on_level_change(int pos, void* userdata) { cv::Mat img = *(cv::Mat*)userdata; // voidptr 형식으로 받은 이미지 처리 img.setTo(pos * 16); imshow("img", img); } int main() { cv::Mat img = cv::Mat::zeros(480, 640, CV_8UC1); cv::namedWindow("img"); cv::createTrackbar("level", "img", 0, 16, on_level_change, (void*)&img); //img를 voidptr 형식으로 주소 전달. cv::imshow("img", img); cv::waitKey(); return 0; }
결과 트랙바에 따라 이미지의 색이 바뀜.
'OpenCV > OpenCV_C++' 카테고리의 다른 글
OpenCV 유용한 함수 (2) 2023.12.21 OpenCV VideoCapture class (0) 2023.12.13 OpenCV Mat class 기초 사용법 (0) 2023.12.12 OpenCV 주요 클래스 (1) 2023.11.27 OpenCV 기초 및 편하게 사용하기 (2) 2023.11.26