오늘은 http://opencvexamples.blogspot.com/p/learning-opencv-functions-step-by-step.html에 있는 세번째 예제를 따라해보도록 하겠습니다.
3. Basic drawing examples
1) 선 그리기
소스코드부터 보시죠.
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
using namespace cv;
int main()
{
// Create black empty images
Mat image = Mat::zeros(400, 400, CV_8UC3); // 세로, 가로 각각 400, 400 사이즈의 검정 이미지를 만든다.
// Draw a line
line(image, Point(15, 20), Point(300, 350), Scalar(0, 255, 0), 10, 8);
imshow("Image", image);
imwrite("result.bmp", image);
waitKey(0);
return(0);
}
링크의 예제에서는 #include <opencv2/imgproc/imgproc.hpp>가 없는데, 이걸 포함해줘야 line 함수를 사용할 수 있습니다. line 함수에 대해서 아는 한 설명을 해보겠습니다.
line(image, Point(15, 20), Point(300, 350), Scalar(0, 255, 0), 10, 8);
- 1번째 인수: 도화지가 되어줄 이미지를 넣어줍니다.
-
2번째, 3번째 인수: 어디서부터 어디까지 선을 그릴지 픽셀 위치들을 뜻합니다. 즉 (15, 20)부터 (300, 350)을 잇는 선을 그리겠다는 것입니다.
-
4번째 인수: 선의 색을 결정지어줍니다. Scalar(0, 255, 0)은 녹색 선을 그리겠다는 것입니다. BGR순서로 되어 있습니다. 만약 Scalar(0, 0, 255)라고 세팅-하면 빨간색 선이 될 것입니다.
-
5번째 인수: 선의 굵기를 선택합니다. 클수록 굵어집니다.
-
6번째 인수: 라인의 타입을 결정해줍니다. (이것의 역할은 잘 몰라서, 일단 그냥 default값으로 놔두겠습니다.)
실행결과 아래와 같은 이미지가 전시되고, 저장됩니다.
2) 원 그리기
이번에는 원을 그려보도록 하겠습니다. 소스코드는 아래와 같습니다.
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
using namespace cv;
int main()
{
// Create black empty images
Mat image = Mat::zeros(400, 400, CV_8UC3); // 세로, 가로 각각 400, 400 사이즈의 검정 이미지를 만든다.
// Draw a circle
circle(image, Point(200, 200), 32.0, Scalar(0, 0, 255), 5, 8);
circle(image, Point(100, 300), 40.0, Scalar(255, 0, 255), 10, 8);
imshow("Image", image);
imwrite("result.bmp", image);
waitKey(0);
return(0);
}
circle 함수
- 1번째 인수: 역시 도화지가 되어줄 이미지입니다. 여기서는 400 x 400의 검정 이미지이겠지요?
- 2번째 인수: 원의 중심의 픽셀 위치입니다.
- 3번째 인수: 원의 반지름입니다.
- 4번째 인수: 원의 색깔로 역시 BGR순서로 되어 있습니다. 첫번째 원은 빨간 색이 되게 Scalar(0, 0, 255)로 설정했습니다.
- 5번째 인수: 원의 두께를 결정해주는 것입니다. 클수록 두꺼워집니다.
- 6번째 인수: 라인의 타입을 결정해주는 것입니다.
line 함수의 인수들의 진행패턴과 크게 다르지 않습니다. 아래 그림은 결과로 그려진 두 개의 원을 보여줍니다.
3) 타원 그리기
이번에는 타원을 그리겠습니다.
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
using namespace cv;
int main()
{
// Create black empty images
Mat image = Mat::zeros(400, 400, CV_8UC3); // 세로, 가로 각각 400, 400 사이즈의 검정 이미지를 만든다.
// Draw a ellipse
ellipse(image, Point(200, 200), Size(100.0, 160.0), 45, 0, 360, Scalar(255, 0, 0), 1, 8);
ellipse(image, Point(200, 200), Size(100.0, 160.0), 0, 0, 360, Scalar(255, 0, 0), 5, 8);
ellipse(image, Point(200, 200), Size(100.0, 160.0), 135, 0, 360, Scalar(255, 0, 0), 10, 8);
imshow("Image", image);
imwrite("result.bmp", image);
waitKey(0);
return(0);
}
ellipse 함수가 타원을 그릴 때 사용하는 함수입니다.
- 1번째 인수: 도화지가 될 이미지입니다.
- 2번째 인수: 타원의 중심위치입니다.
- 3번째 인수: 타원축들의 길이를 의미합니다. 즉, 세번째 인수가 Size(100,0, 160,0)라면 x축으로는 100만큼, y축으로는 160만큼 긴 모양의 타원을 만들겠다는 것입니다.
- 4번째 인수: 타원이 회전된 각도입니다. 첫번째 타원의 경우 45도만큼 오른쪽으로 회전시키겠다는 것입니다.
- 5번째, 6번째 인수: 타원이 시작하는 각도와 끝나는 각도를 결정지어주는 것인데 완전한 타원을 그리고 싶다면 0, 360으로 설정해주면 됩니다.
- 7번째 인수: 색을 결정해주는 것입니다. 세 타원 모두 파란색으로 설정해줬습니다.
- 8번째 인수: 타원의 굵기를 결정해주는 것입니다. 크면 클수록 굵어집니다.
- 9번째 인수: 역시 선의 타입을 결정해주는 것입니다.
아래 그림은 결과적으로 그려진 3개의 타원을 보여줍니다. 뭔가 멋있네요.
4) 직사각형 그리기
직사각형 그리는 코드입니다.
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
using namespace cv;
int main()
{
// Create black empty images
Mat image = Mat::zeros(400, 400, CV_8UC3); // 세로, 가로 각각 400, 400 사이즈의 검정 이미지를 만든다.
// Draw a rectangle
rectangle(image, Point(15, 20), Point(70, 50), Scalar(0, 55, 255), +1, 4);
rectangle(image, Point(200, 300), Point(300, 350), Scalar(100, 100, 0), -1, 8);
imshow("Image", image);
imwrite("result.bmp", image);
waitKey(0);
return(0);
}
직사각형을 그려주는 rectangle 함수를 살펴봅시다.
- 1번째 인수: 도화지가 되어줄 이미지입니다.
- 2번째 인수: 직사각형의 왼쪽 상단 모서리 픽셀 위치입니다.
- 3번째 인수: 직사각형의 오른쪽 하단 모서리 픽셀 위치입니다.
- 4번째 인수: 색을 결정해줍니다.
- 5번째 인수: 양수면 빈 직사각형, 음수면 채워진 직사각형을 만듭니다.
- 6번째 인수: 라인의 타입을 결정해줍니다.
구현된 결과이미지입니다. 하나의 빈 직사각형과 하나의 채워진 직사각형을 보실 수 있습니다.
5) 다각형 그리기
이번에는 채워져있는 다각형을 그려보겠습니다.
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
using namespace cv;
int main()
{
// Create black empty images
Mat image = Mat::zeros(400, 400, CV_8UC3); // 세로, 가로 각각 400, 400 사이즈의 검정 이미지를 만든다.
int w = 400;
/** Create some points */
Point rook_points[1][20]; // 여기서 rook는 체스의 말의 이름입니다.
rook_points[0][0] = Point(w / 4.0, 7 * w / 8.0);
rook_points[0][1] = Point(3 * w / 4.0, 7 * w / 8.0);
rook_points[0][2] = Point(3 * w / 4.0, 13 * w / 16.0);
rook_points[0][3] = Point(11 * w / 16.0, 13 * w / 16.0);
rook_points[0][4] = Point(19 * w / 32.0, 3 * w / 8.0);
rook_points[0][5] = Point(3 * w / 4.0, 3 * w / 8.0);
rook_points[0][6] = Point(3 * w / 4.0, w / 8.0);
rook_points[0][7] = Point(26 * w / 40.0, w / 8.0);
rook_points[0][8] = Point(26 * w / 40.0, w / 4.0);
rook_points[0][9] = Point(22 * w / 40.0, w / 4.0);
rook_points[0][10] = Point(22 * w / 40.0, w / 8.0);
rook_points[0][11] = Point(18 * w / 40.0, w / 8.0);
rook_points[0][12] = Point(18 * w / 40.0, w / 4.0);
rook_points[0][13] = Point(14 * w / 40.0, w / 4.0);
rook_points[0][14] = Point(14 * w / 40.0, w / 8.0);
rook_points[0][15] = Point(w / 4.0, w / 8.0);
rook_points[0][16] = Point(w / 4.0, 3 * w / 8.0);
rook_points[0][17] = Point(13 * w / 32.0, 3 * w / 8.0);
rook_points[0][18] = Point(5 * w / 16.0, 13 * w / 16.0);
rook_points[0][19] = Point(w / 4.0, 13 * w / 16.0);
const Point* ppt[1] = { rook_points[0] };
int npt[] = { 20 };
fillPoly(image, ppt, npt, 1, Scalar(255, 255, 255), 8);
imshow("Image", image);
imwrite("result.bmp", image);
waitKey(0);
return(0);
}
fillPoly함수의 인수들을 살펴봅시다.
- 1번째 인수: 도화지가 될 이미지입니다.
- 2번째 인수: 꼭지점들을 담고 있는 배열입니다. (Array of polygons where each polygon is represented as an array of points)
- 3번째 인수: 꼭지점들의 갯수를 담고 있는 배열입니다. (Array of polygon vertex counters)
- 4번째 인수: 색으로 채워진 지역을 감싸는 가장자리의 갯수를 설정해줍니다. (Number of contours that bind the filled region)
- 5번째 인수: 다각형의 색을 설정합니다.
- 6번째 인수: 라인의 타입을 결정해줍니다.
아래 그림과 같이 체스의 rook가 그려집니다.
이번에는 fillPoly 함수를 사용해서 다각형 중의 하나인 삼각형을 하나 그려보겠습니다. 코드는 아래와 같습니다.
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
using namespace cv;
int main()
{
// Create black empty images
Mat image = Mat::zeros(400, 400, CV_8UC3); // 세로, 가로 각각 400, 400 사이즈의 검정 이미지를 만든다.
int w = 400;
/** Create some points */
Point rook_points[1][3]; // 여기서 rook는 체스의 말의 이름입니다.
rook_points[0][0] = Point(w / 2.0, w / 4.0); // Point(가로 픽셀 위치, 세로 픽셀 위치)
rook_points[0][1] = Point(w / 4.0, 3 * w / 4.0);
rook_points[0][2] = Point(3 * w / 4.0, 3 * w / 4.0);
const Point* ppt[1] = { rook_points[0] };
int npt[] = { 3 };
fillPoly(image, ppt, npt, 1, Scalar(255, 255, 255), 8);
imshow("Image", image);
imwrite("result.bmp", image);
waitKey(0);
return(0);
}
삼각형을 그리므로 세 점만 있으면 됩니다. 그려진 그림은 아래와 같습니다.
6) 이미지에 텍스트 넣기
이제 마지막으로 이미지에 텍스트 넣는 것을 따라해보겠습니다.
#include <opencv2/core/core.hpp>#include <opencv2/highgui/highgui.hpp>#include <opencv2/imgproc/imgproc.hpp>using namespace cv;int main(){// Create black empty imagesMat image = Mat::zeros(400, 400, CV_8UC3); // 세로, 가로 각각 400, 400 사이즈의 검정 이미지를 만든다.putText(image, "God is good!", Point(50, 100), FONT_HERSHEY_PLAIN, 2, Scalar(0, 200, 200), 3); //이미지에 텍스트 넣기imshow("Image", image);imwrite("result.bmp", image);waitKey(0);return(0);}
- 1번째 인수: 도화지가 될 이미지입니다.
- 2번째 인수: 텍스트 내용을 적어줍니다.
- 3번째 인수: 이미지에서 텍스트가 배치될 위치를 결정해줍니다. 텍스트 스트링의 왼쪽 아래 위치가 됩니다.
- 4번째 인수: 폰트를 선택합니다. FONT_HERSHEY_SIMPLEX, FONT_HERSHEY_PLAIN,FONT_HERSHEY_DUPLEX, FONT_HERSHEY_COMPLEX, FONT_HERSHEY_TRIPLEX,FONT_HERSHEY_COMPLEX_SMALL, FONT_HERSHEY_SCRIPT_SIMPLEX, FONT_HERSHEY_SCRIPT_COMPLEX
- 5번째 인수: 글자의 크기를 결정합니다.
- 6번째 인수: 글자의 색을 선택합니다.
- 7번째 인수: 글자의 두께를 선택합니다.
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
using namespace cv;
int main()
{
// Create black empty images
Mat image = Mat::zeros(400, 400, CV_8UC3); // 세로, 가로 각각 400, 400 사이즈의 검은색 이미지를 만든다.
rectangle(image, Point(0, 0), Point(399, 399), Scalar(255, 255, 255), -1, 8); // 흰색 도화지로 바꿔준다.
// 큰 지붕, 다각형 함수 활용
int w = 400;
Point roof1_points[1][4];
roof1_points[0][0] = Point(140, 40);
roof1_points[0][1] = Point(260, 40);
roof1_points[0][2] = Point(360, 160);
roof1_points[0][3] = Point(40, 160);
const Point* ppt1[1] = { roof1_points[0] };
int npt1[] = { 4 };
fillPoly(image, ppt1, npt1, 1, Scalar(30, 30, 30), 8);
// 건물의 몸통. 직사각형 함수 활용
rectangle(image, Point(70, 161), Point(330, 340), Scalar(150, 150, 150), -1, 8);
rectangle(image, Point(70, 341), Point(330, 360), Scalar(30, 30, 30), -1, 8);
// 작은 지붕
Point roof2_points[1][4];
roof2_points[0][0] = Point(160, 100);
roof2_points[0][1] = Point(240, 100);
roof2_points[0][2] = Point(300, 172);
roof2_points[0][3] = Point(100, 172);
const Point* ppt2[1] = { roof2_points[0] };
int npt2[] = { 4 };
fillPoly(image, ppt2, npt2, 1, Scalar(60, 60, 60), 8);
// 중간에 회색 두 줄
rectangle(image, Point(150, 173), Point(160, 340), Scalar(100, 100, 100), -1, 8);
rectangle(image, Point(240, 173), Point(250, 340), Scalar(100, 100, 100), -1, 8);
//굴뚝
Point chimney_points[1][4];
chimney_points[0][0] = Point(70, 60);
chimney_points[0][1] = Point(92, 60);
chimney_points[0][2] = Point(92, 97);
chimney_points[0][3] = Point(70, 124);
const Point* ppt3[1] = { chimney_points[0] };
int npt3[] = { 4 };
fillPoly(image, ppt3, npt3, 1, Scalar(60, 60, 60), 8);
//굴뚝 덮개
rectangle(image, Point(67, 48), Point(95, 59), Scalar(30, 30, 30), -1, 8);
//문
rectangle(image, Point(172, 252), Point(228, 340), Scalar(70, 70, 90), -1, 8);
//문에 있는 창문 두 개
rectangle(image, Point(180, 264), Point(190, 288), Scalar(255, 200, 150), -1, 8);
rectangle(image, Point(210, 264), Point(220, 288), Scalar(255, 200, 150), -1, 8);
//문에 있는 점 두 개, 원 그리기 활용
circle(image, Point(190, 300), 2, Scalar(30, 30, 30), 2, 8);
circle(image, Point(210, 300), 2, Scalar(30, 30, 30), 2, 8);
//중간 원형 창문의 테두리
circle(image, Point(200, 210), 18, Scalar(55, 55, 55), 10, 8);
//중간 원형 창문
circle(image, Point(200, 210), 8, Scalar(255, 200, 150), 18, 8);
//중간 원형 창문 십자
rectangle(image, Point(199, 190), Point(201, 230), Scalar(55, 55, 55), -1, 8);
rectangle(image, Point(180, 209), Point(220, 211), Scalar(55, 55, 55), -1, 8);
//왼쪽 상단 창문 회색 틀
rectangle(image, Point(85, 240), Point(135, 247), Scalar(55, 55, 55), -1, 8);
//왼쪽 상단 창문 검은 틀
Point win1_points[1][4];
win1_points[0][0] = Point(88, 248);
win1_points[0][1] = Point(132, 248);
win1_points[0][2] = Point(127, 255);
win1_points[0][3] = Point(93, 255);
const Point* win1_ppt[1] = { win1_points[0] };
int win1_npt[] = { 4 };
fillPoly(image, win1_ppt, win1_npt, 1, Scalar(30, 30, 30), 8);
//왼쪽 상단 창문
rectangle(image, Point(88, 190), Point(132, 239), Scalar(255, 200, 150), -1, 8);
//왼쪽 상단 창문 십자
rectangle(image, Point(88, 215), Point(132, 217), Scalar(55, 55, 55), -1, 8);
rectangle(image, Point(109, 190), Point(111, 239), Scalar(55, 55, 55), -1, 8);
//오른쪽 상단 창문 회색 틀
rectangle(image, Point(265, 240), Point(315, 247), Scalar(55, 55, 55), -1, 8);
//오른쪽 상단 창문 검은 틀
Point win2_points[1][4];
win2_points[0][0] = Point(268, 248);
win2_points[0][1] = Point(312, 248);
win2_points[0][2] = Point(307, 255);
win2_points[0][3] = Point(273, 255);
const Point* win2_ppt[1] = { win2_points[0] };
int win2_npt[] = { 4 };
fillPoly(image, win2_ppt, win2_npt, 1, Scalar(30, 30, 30), 8);
//오른쪽 상단 창문
rectangle(image, Point(268, 190), Point(312, 239), Scalar(255, 200, 150), -1, 8);
//오른쪽 상단 창문 십자
rectangle(image, Point(268, 215), Point(312, 217), Scalar(55, 55, 55), -1, 8);
rectangle(image, Point(289, 190), Point(291, 239), Scalar(55, 55, 55), -1, 8);
//왼쪽 하단 창문 회색 틀
rectangle(image, Point(85, 315), Point(135, 322), Scalar(55, 55, 55), -1, 8);
//왼쪽 하단 창문 검은 틀
Point win3_points[1][4];
win3_points[0][0] = Point(88, 323);
win3_points[0][1] = Point(132, 323);
win3_points[0][2] = Point(127, 330);
win3_points[0][3] = Point(93, 330);
const Point* win3_ppt[1] = { win3_points[0] };
int win3_npt[] = { 4 };
fillPoly(image, win3_ppt, win3_npt, 1, Scalar(30, 30, 30), 8);
//왼쪽 하단 창문
rectangle(image, Point(88, 265), Point(132, 314), Scalar(255, 200, 150), -1, 8);
//왼쪽 하단 창문 십자
rectangle(image, Point(88, 290), Point(132, 292), Scalar(55, 55, 55), -1, 8);
rectangle(image, Point(109, 265), Point(111, 314), Scalar(55, 55, 55), -1, 8);
//오른쪽 하단 창문 회색 틀
rectangle(image, Point(265, 315), Point(315, 322), Scalar(55, 55, 55), -1, 8);
//오른쪽 하단 창문 검은 틀
Point win4_points[1][4];
win4_points[0][0] = Point(268, 323);
win4_points[0][1] = Point(312, 323);
win4_points[0][2] = Point(307, 330);
win4_points[0][3] = Point(273, 330);
const Point* win4_ppt[1] = { win4_points[0] };
int win4_npt[] = { 4 };
fillPoly(image, win4_ppt, win4_npt, 1, Scalar(30, 30, 30), 8);
//오른쪽 하단 창문
rectangle(image, Point(268, 265), Point(312, 314), Scalar(255, 200, 150), -1, 8);
//오른쪽 하단 창문 십자
rectangle(image, Point(268, 290), Point(312, 292), Scalar(55, 55, 55), -1, 8);
rectangle(image, Point(289, 265), Point(291, 314), Scalar(55, 55, 55), -1, 8);
imshow("Image", image);
imwrite("result.bmp", image);
waitKey(0);
return(0);
}
구현된 이미지는 밑에 있습니다. 노가다였지만 나름 성취감이 있네요. ㅋㅋ
'Dev > C, C++' 카테고리의 다른 글
opencv에서 픽셀값 접근하기 (2) | 2017.07.05 |
---|---|
[Learn opencv by examples] 8 (1). Sobel 엣지 검출 (6) | 2017.06.15 |
[Learn opencv by examples] 7. 2D 컨볼루션 / 새로운 필터 만들기 (0) | 2017.06.14 |
[Learn opencv by examples] 6. Gaussian 필터, Bilateral 필터, Median 필터 (2) | 2017.06.03 |
[Learn opencv by examples] 5. 영상 이진화, Threshold operation (0) | 2017.06.02 |
[Learn opencv by examples] 4. RGB 이미지를 그레이 영상 또는 다른 컬러 공간으로 전환하기 (0) | 2017.06.02 |
[Learn opencv by examples] 2. 카메라로부터 비디오 캡쳐하기 (0) | 2017.05.12 |
[Learn opencv by examples] 1. 이미지 불러오고, 전시하고, 저장하기 (3) | 2017.05.12 |