Introduction
This tutorial will show you the basic drawing functionality of OpenCV. Previously we saw how to blend two images and how to adjust the brightness of an image. Now we will see how we can draw shapes like rectangle and circle over a given image. Don’t expect to see some sophisticated drawing functionality from OpenCV. Still, the existing functionality is quite good. One area to apply this could be the drawing of a rectangle around a face, when we are doing a face recognition application. Let’s see what we can do with OpenCV.
Drawing lines
Let’s start with the simplest available shape – a line. For the drawing of a line we need to provide two points – the beginning and the end of the line. OpenCV has a dedicated function to draw a line given these two points. Following is an exemplary function on line drawing.
// The sizes of the image matrix constexpr int cMatrixWidth = 600; constexpr int cMatrixHeigth = 480; void drawLines() { // The thickness and type of the lines constexpr int cThickness = 5; constexpr int cLineType = LINE_8; // Create one image matrix with three channels and fill it with zeros Mat l_image = Mat::zeros(cMatrixHeigth, cMatrixWidth, CV_8UC3); // Draw a line using an OpenCV function line( l_image, Point(0,0), Point(cMatrixWidth, cMatrixHeigth), Scalar( 255, 0, 0 ), cThickness, cLineType ); // Draw an arrow using an OpenCV function arrowedLine( l_image, Point(0,cMatrixHeigth), Point(cMatrixWidth-50, 50), Scalar( 0, 0, 255 ), cThickness, cLineType ); // Display the result namedWindow("Output", WINDOW_NORMAL); imshow("Output", l_image); }
First we create one matrix object where we will do our drawing on. As you can see on line 12 I have created such an object and I have made all its values to be equal to zero. Then it is very simple – I just call one OpenCV function line(). Here is more information about it. It takes the image matrix as a first argument. Then we provide two Point object – the beginning and the end of the line. Next we provide the color of the line as a Scalar object. This object keeps the colors in a BGR format – Blue, Green and Red channels. In our case we will have a blue line. Finally we provide the line thickness and the line type. More information about the line type defines here.
The second function, which we call is similar to the first one. In this case it will draw an arrow with the head pointing at the end point. It has the same arguments as the line() function. More information about it here. Finally we show the result in one window. On my side it looks like this:

Drawing rectangles
Next we will see how to draw rectangles using OpenCV functions. In the given example code I am drawing three rectangles. One of them is filled. Here is the code:
// The sizes of the image matrix constexpr int cMatrixWidth = 600; constexpr int cMatrixHeigth = 480; // ... void drawRectangles() { Mat l_image = Mat::zeros(cMatrixHeigth, cMatrixWidth, CV_8UC3); // Set the line thickness and line size of the first rectangle int l_thickness = 5; int l_lineType = FILLED; // Draw the first rectangle using an OpenCV function rectangle( l_image, Point(0,0), Point(cMatrixWidth, cMatrixHeigth), Scalar( 255, 0, 255 ), l_thickness, l_lineType ); // Set the line thickness and line size of the second rectangle // FILLED thickness will draw a filled rectangle l_thickness = FILLED; l_lineType = LINE_8; // Draw the second rectangle. It will be filled rectangle( l_image, Point(50,50), Point(cMatrixWidth-50, cMatrixHeigth-50), Scalar( 255, 255, 0 ), l_thickness, l_lineType); // Set the line thickness and line size of the second rectangle l_thickness = 6; l_lineType = LINE_AA; // Draw the third rectangle rectangle( l_image, Rect(150,150, cMatrixWidth-300, cMatrixHeigth-300), Scalar( 0, 255, 255 ), l_thickness, l_lineType); // Display the result namedWindow("Output", WINDOW_NORMAL); imshow("Output", l_image); }
Again here I create a matrix with zeros only first. Then we set the thickness and line type. After that we call the rectangle() function, which will draw the rectangle. More information about it here and about its overloaded function here. The first function gets the image matrix as a first argument, then two Point objects – the upper left corner point and the lower right corner point. The rest is the color, the line thickness and line type. The overloaded function uses one Rect object instead of two Point objects. Finally we display the result on a window. My result looks like this – One filled and two empty rectangles.

Drawing circles
Now we will draw circles. Again we have an OpenCV function for this. Here is the exemplary code.
// The sizes of the image matrix constexpr int cMatrixWidth = 600; constexpr int cMatrixHeigth = 480; // ... void drawCircles() { Mat l_image = Mat::zeros(cMatrixHeigth, cMatrixWidth, CV_8UC3); // Set the line thickness and line size of the first circle int l_thickness = 5; int l_lineType = FILLED; // Set the redius of the first circle int l_radius = cMatrixHeigth; // Draw the first circle using and OpenCV function circle(l_image, Point(cMatrixWidth/2, cMatrixHeigth/2), l_radius/2, Scalar(255, 0, 0), l_thickness, l_lineType); // Set the line thickness and line size of the second circle l_thickness = FILLED; l_lineType = LINE_8; // Draw the second circle using and OpenCV function. It will be filled circle(l_image, Point(cMatrixWidth / 2, cMatrixHeigth / 2), l_radius/4, Scalar(0, 0, 255), l_thickness, l_lineType); // Display the result namedWindow("Output", WINDOW_NORMAL); imshow("Output", l_image); }
First we start by creating an image matrix with zeros. We set some variables for the line thickness, line type and the radius. Then we call the circle() function. Here is more information about it. It will take an image matrix as a first argument, then we provide a Point object for the center of the circle. Next we provide the radius. Lastly we provide the color of the circle, line thickness and the line type. When the line thickness is equal to FILLED it will draw a filled circle.
I have drawn two circles with different radiuses – one is filled, the other is not. Finally we display the results in a window. Here is my result.

Drawing ellipses
The next figure we will draw is the ellipse. Again we have a defined function in OpenCV for this purpose – ellipse(). More information regarding it and its overloaded variant is available here. Following is my code to draw two ellipses.
// The sizes of the image matrix constexpr int cMatrixWidth = 600; constexpr int cMatrixHeigth = 480; // ... void drawElipses() { Mat l_image = Mat::zeros(cMatrixHeigth, cMatrixWidth, CV_8UC3); // Set the line thickness and line size of the first elipse int l_thickness = 3; int l_lineType = LINE_4; // Set the angle of the first elipse int l_angle = 45; // Draw the first elipse using an OpenCV function ellipse(l_image, Point(cMatrixWidth / 2, cMatrixHeigth / 2), Size(cMatrixHeigth / 4, cMatrixHeigth / 16), l_angle, 0, 360, Scalar(255, 0, 0), l_thickness, l_lineType); // Set the line thickness, line size and angle of the second elipse l_thickness = FILLED; l_lineType = LINE_8; l_angle = 90; // Draw the first elipse using an OpenCV function. It will be a filled elipse ellipse(l_image, RotatedRect(Point2f(cMatrixWidth / 2, cMatrixHeigth / 2), Size2f(cMatrixHeigth / 4, cMatrixHeigth / 16), static_cast<float>(l_angle)), Scalar(0, 0, 255), l_thickness, l_lineType); // Display the result namedWindow("Output", WINDOW_NORMAL); imshow("Output", l_image); }
As with the previous examples I am creating one image matrix and I am setting some variables for the line type, thickness and angle of the ellipse. Then I call the ellipse() function. Its first argument is the image matrix, where we will draw the ellipse on. The second argument is the center Point coordinates. The next argument are the X and Y axes sizes. Then we have the angle at which the ellipse will be rotated. Following are two angles – the start angle and the end angle. By providing 0 and 360 I am drawing a full ellipse. You can provide different angles. Lastly is the color of the ellipse, the line thickness and the line type.
The overload variant of the ellipse function uses RotatedRect object which defines the ellipse begin and end point plus the rotation angle. Finally we output the result to one window. Following is my result.

Polygons
Finally we will see how to render polygons. There are three different functions in OpenCV to draw polygons. And each one of them have an overloaded variant. We will mention each one of them separately. Here is the code.
// The sizes of the image matrix constexpr int cMatrixWidth = 600; constexpr int cMatrixHeigth = 480; // ... void drawPolygons() { Mat l_image = Mat::zeros(cMatrixHeigth, cMatrixWidth, CV_8UC3); // Set the line type of the polygon int l_lineType = LINE_4; // Set the points for the first polygon. // It will be a rectangle Point l_triangle1[1][3]; l_triangle1[0][0] = Point{50, 100}; l_triangle1[0][1] = Point{100, 50}; l_triangle1[0][2] = Point{150, 100}; // Stored them in the required type const Point* l_trianglePoints1[1] = { l_triangle1[0] }; // Set the number of points for the polygon int l_numberOfPoints[] = { 3 }; // Draw a filled polygon using an OpenCV function fillPoly( l_image, l_trianglePoints1, l_numberOfPoints, 1, Scalar( 0, 0, 255 ), l_lineType ); // For the second OpenCV function we need a matrix // which support a 32bit signed type Mat l_triangle2 = Mat::zeros(1, 3, CV_32SC2); // Set the points for the second polygon. // It is a triangle int* l_triangle2Ptr = l_triangle2.ptr<int>(0); l_triangle2Ptr[0] = 150; l_triangle2Ptr[1] = 100; l_triangle2Ptr[2] = 200; l_triangle2Ptr[3] = 50; l_triangle2Ptr[4] = 250; l_triangle2Ptr[5] = 100; InputArrayOfArrays l_trianglePoints2(l_triangle2); // Draw a filled polygon using an OpenCV function fillPoly( l_image, l_trianglePoints2, Scalar( 0, 255, 0 ), l_lineType ); // Set the points for the third polygon. // Again - triangle const Point l_triangle3[1][3] = { Point{250, 100}, Point{300, 50}, Point{350, 100} }; const Point* l_trianglePoints3 = { l_triangle3[0] }; // Draw a filled polygon using another OpenCV function fillConvexPoly( l_image, l_trianglePoints3, 3, Scalar( 255, 0, 0 ), l_lineType ); // Set the points for the fourth polygon. // Again - triangle Mat l_triangle4 = Mat::zeros(1, 3, CV_32SC2); int* l_triangle4Ptr = l_triangle4.ptr<int>(0); l_triangle4Ptr[0] = 350; l_triangle4Ptr[1] = 100; l_triangle4Ptr[2] = 400; l_triangle4Ptr[3] = 50; l_triangle4Ptr[4] = 450; l_triangle4Ptr[5] = 100; InputArray l_trianglePoints4(l_triangle4); // Draw a filled polygon using another OpenCV function fillConvexPoly( l_image, l_trianglePoints4, Scalar( 0, 255, 255 ), l_lineType ); // Set the points for the fifth polygon. // Again - triangle const Point l_triangle5[1][3] = { Point{450, 100}, Point{500, 50}, Point{550, 100} }; const Point * l_trianglePoints5 = { l_triangle5[0] }; const Point * const * l_trianglePointsPtr5 = { &l_trianglePoints5 }; int l_numberOfPoints5[] = { 3 }; // Draw an empty polygon using another OpenCV function polylines(l_image, l_trianglePointsPtr5, l_numberOfPoints5, 1, true, Scalar(255, 255, 0)); // For the second OpenCV function we need a matrix // which support a 32bit signed type Mat l_triangle6 = Mat::zeros(1, 3, CV_32SC2); // Set the points for the second polygon. // It is a triangle int* l_triangle6Ptr = l_triangle6.ptr<int>(0); l_triangle6Ptr[0] = 250; l_triangle6Ptr[1] = 150; l_triangle6Ptr[2] = 300; l_triangle6Ptr[3] = 100; l_triangle6Ptr[4] = 350; l_triangle6Ptr[5] = 150; InputArrayOfArrays l_trianglePoints6(l_triangle6); // Draw an empty polygon using an OpenCV function polylines(l_image, l_trianglePoints6, false, Scalar(255, 0, 255)); // Display the result namedWindow("Output", WINDOW_NORMAL); imshow("Output", l_image); }
The fillpoly() functions
We will start with the fillpoly() function. Information is available here. This function draws a filled polygon. We need to provide it with a set of points to connect and draw the polygon. That is why we create one array of Point objects. Then we create one pointer to that array, because the function requires such a pointer. We call the fillpoly() function and we provide it with the image matrix, the pointer to the array of Point objects, a pointer to a variable, holding the number of points, the number of contours which in my case is 1. Lastly we also provide the color and the line type.
For the overloaded function we need to provide an InputArrayOfArrays. In order to create such an object we need to create one Mat object where we will keep the points’ coordinates. Here is it is very important to create a matrix which uses 32bit signed values. Then we call the function and provide it with the InputArrayOfArrays object. Also we provide it with color and line type.
The fillConvexPoly() functions
Next we will take a look at the fillConvexPoly() function. According to the documentation this function is faster than the fillPoly() one. Both function and their overloaded variants have almost the same signature. Here are details about it. This function also draws a filled polygon.
First we need to create an array of Point objects which will be linked. Then we create a pointer to that array. Now it is time to call the function. The first argument is the image matrix, where we will be drawing on. Then we provide the pointer to the array of Point objects and the number of points. Lastly we set the color and line type.
Similarly to the fillPoly() overloaded function, the overloaded function of fillConvexPoly() works with InputArray. That is why we need to create one Mat object first and fill it with coordinates. Then we create the InputArray object from it. Finally we call the fillConvexPoly() function, providing it with the image matrix, the input array object, the color and the line type.
The polylines() function
The last functions set I am going to introduce is the polylines() functions set. Using these functions you can draw both filled and non-filled polygons. Again, more info about it on the official web site .
The signature of both functions is similar to the one of the previously introduced functions. For the first variant we need to provide an array of Point objects. Then we get a constant pointer to this array, which should also be constant. We also need a pointer to the variable holding the number of points. The function itself needs the following arguments: the image matrix, the constant pointer to the array of points, number of contours, if the polygon is open or closed and the color. The other arguments have default values. If you want a filled polygon you need to set the line thickness to FILLED.
The overloaded function also works with InputArrayOfArrays. This is why we create one Mat object to hold the coordinates and using it we create such an object. Then we just call the function with the provided arguments.
Lastly we display the result. Here it is how it looks like on my side.

Conclusion
In this tutorial we saw how to draw different shapes using OpenCV ready functions. In the future we will use this to draw different shapes in our programs. The API for drawing shapes is not so sophisticated but it gets the job done.
Again, the project will be available for download below. Also, you can find it in GitHub.
Next we will see how to display text, which is also quite useful.

Passionate developer, loving husband and caring father. As an introvert programming is my life. I work as a senior software engineer in a big international company. My hobbies include playing computer games (mostly World of Warcraft), watching TV series and hiking.