Title: Drawing with OpenCV - PyImageSearch

URL Source: https://pyimagesearch.com/2021/01/27/drawing-with-opencv/

Published Time: 2021-01-27T07:33:00+00:00

Markdown Content:
**In this tutorial, you will learn how to use OpenCV’s basic drawing functions.** You will learn how to use OpenCV to draw:

*   Lines
*   Rectangles
*   Circles

![Image 1](data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%20700%20450'%3E%3C/svg%3E)

You will also learn how to use OpenCV to draw on images and blank/empty arrays initialized with NumPy.

**To learn how to use OpenCV’s basic drawing functions,** **_just keep reading._**

![Image 2](data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%20128%20128'%3E%3C/svg%3E)

#### Looking for the source code to this post?

[Jump Right To The Downloads Section](#download-the-code)

In the first part of this tutorial, we will briefly review OpenCV’s drawing functions.

We will then configure our development environment and review our project directory structure.

With the review taken care of, we will move on to implement two Python scripts:

1.  `basic_drawing.py`
2.  `image_drawing.py`

These scripts will help you understand how to perform basic drawing functions with OpenCV.

By the end of this guide, you will understand how to use OpenCV to draw lines, circles, and rectangles.

### **Drawing functions in OpenCV**

OpenCV has a number of drawing functions you can use to draw various shapes, including polygons of irregular shapes, but the three most common OpenCV drawing functions you will see are:

1.  `cv2.line`: Draws a line on image, starting at a specified _(x, y)_\-coordinate and ending at another _(x, y)_\-coordinate
2.  `cv2.circle`: Draws a circle on an image specified by the center _(x, y)_\-coordinate and a supplied radius
3.  `cv2.rectangle`: Draws a rectangle on an image specified by the _top-left_ corner and _bottom-right_ corner _(x, y)_\-coordinates

**We will cover these three drawing functions today.**

However, it’s worth noting that more advanced OpenCV drawing functions exist, including:

1.  `cv2.ellipse`: Draws an ellipse on an image
2.  `cv2.polylines`: Draws the outline of a polygon specified by a set of _(x, y)_\-coordinates
3.  `cv2.fillPoly`: Draws a polygon, but instead of drawing the outline, instead fills in the polygon
4.  `cv2.arrowedLine`: Draws an arrow pointing from a starting _(x, y)_\-coordinate to an ending _(x, y)_\-coordinate

These OpenCV drawing functions are used less often but are still worth noting. We use them occasionally on the PyImageSearch blog.

### **Configuring your development environment**

To follow along with this guide, you need to have the OpenCV library installed on your system.

Luckily, OpenCV is pip-installable:

$ pip install opencv-contrib-python

**If you need help configuring your development environment for OpenCV, I _highly recommend_ that you read my** [**_pip install OpenCV_ guide**](https://pyimagesearch.com/2018/09/19/pip-install-opencv/) — it will have your system up and running in a matter of minutes.

### **Having problems configuring your development environment?**

[![Image 3](data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%20500%20334'%3E%3C/svg%3E)](https://pyimagesearch.com/pyimagesearch-plus/)

**Figure 1:** Having trouble configuring your development environment? Want access to pre-configured Jupyter Notebooks running on Google Colab? Be sure to join [PyImageSearch Plus](https://pyimagesearch.com/pyimagesearch-plus/) — your system will be up and running with this tutorial in a matter of minutes.

All that said, are you:

*   Short on time?
*   Learning on your employer’s administratively locked system?
*   Wanting to skip the hassle of fighting with the command line, package managers, and virtual environments?
*   **Ready to run the code _right now_ on your Windows, macOS, or Linux systems?**

Then join [PyImageSearch Plus](https://pyimagesearch.com/pyimagesearch-plus/) today!

**Gain access to Jupyter Notebooks for this tutorial and other PyImageSearch guides that are** **_pre-configured_** **to run on Google Colab’s ecosystem right in your web browser!** No installation required.

And best of all, these Jupyter Notebooks will run on Windows, macOS, and Linux!

### **Project structure**

Let’s start by reviewing our project directory structure for our OpenCV drawing project:

$ tree . --dirsfirst
.
├── adrian.png
├── basic\_drawing.py
└── image\_drawing.py

0 directories, 3 files

We have two Python scripts to review today:

1.  `basic_drawing.py`: Initializes an empty NumPy array and utilizes OpenCV to draw lines, circles, and rectangles
2.  `image_drawing.py`: Loads `adrian.png` from disk and then draws on the image (rather than an empty/blank NumPy array canvas).

We are now ready to get started!

### **Implementing basic drawing functions with OpenCV**

Before we draw on actual images, let’s first learn how to initialize an empty NumPy array/image and draw on it.

Open the `basic_drawing.py` file in your project directory structure, and let’s get to work.

\# import the necessary packages
import numpy as np
import cv2

# initialize our canvas as a 300x300 pixel image with 3 channels
# (Red, Green, and Blue) with a black background
canvas = np.zeros((300, 300, 3), dtype="uint8")

**Lines 2 and 3** import the packages we will be using.

As a shortcut, we will create an alias for `numpy` as `np`. You will see this convention utilized in all PyImageSearch tutorials that leverage NumPy (and in fact, you will commonly see this convention in the Python community as well!)

We will also import `cv2`, so we can have access to the OpenCV library.

Initializing our image is handled on **Line 7**. We construct a NumPy array using the `np.zeros` method with 300 rows and 300 columns, yielding a _300 x 300_ pixel image. We also allocate space for 3 channels — one each for Red, Green, and Blue. As the name suggests, the `np.zeros` method fills every element in the array with an initial value of zero.

**Secondly, it’s important to draw your attention to the second argument of the `np.zeros` method: the data type, `dtype`.**

Since we represent our image as an RGB image with pixels in the range _\[0, 255\]_, we must use an 8-bit unsigned integer, or `uint8`. There are many other data types that we can use (common ones include 32-bit integers and 32- and 64-bit floats), but we will mainly use `uint8` for the majority of the examples in this lesson.

Now that we have our canvas initialized, we can do some drawing:

\# draw a green line from the top-left corner of our canvas to the
# bottom-right
green = (0, 255, 0)
cv2.line(canvas, (0, 0), (300, 300), green)
cv2.imshow("Canvas", canvas)
cv2.waitKey(0)

# draw a 3 pixel thick red line from the top-right corner to the
# bottom-left
red = (0, 0, 255)
cv2.line(canvas, (300, 0), (0, 300), red, 3)
cv2.imshow("Canvas", canvas)
cv2.waitKey(0)

The first thing we do on **Line 11** is to define a tuple used to represent the color “green.” Then, we draw a green line from point _(0, 0)_, the _top-left_ corner of the image, to point _(300, 300)_, the _bottom-right_ corner of the image, on **Line 12.**

In order to draw the line, we make use of the `cv2.line` method:

*   **The first argument to this method is the image upon which we are going to draw.** In this case, it’s our `canvas`.
*   **The second argument is the starting point of the line.** We choose to start our line from the _top-left_ corner of the image, at point _(0, 0)_ — again, remember that the Python language is zero-index.
*   **We also need to supply an ending point for the line (the third argument).** We define our ending point to be _(300, 300)_, the _bottom-right_ corner of the image.
*   **The last argument is the color of our line** (in this case, green). **Lines 13 and 14** show our image and then wait for a keypress (see **Figure 2**).

![Image 4](data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%20600%20500'%3E%3C/svg%3E)

**Figure 2:** Drawing lines with OpenCV.

As you can see, using the `cv2.line` function is quite simple! But there is one other important argument to consider in the `cv2.line` method: _the thickness._

On **Lines 18-21,** we define the color red as a tuple (again, in BGR rather than RGB format). We then draw a red line from the _top-right_ corner of the image to the _bottom-left_. The last parameter to the method controls the thickness of the line — we decide to make the thickness 3 pixels. Again, we show our image and wait for a keypress:

![Image 5](data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%20600%20500'%3E%3C/svg%3E)

**Figure 3:** Drawing multiple lines with OpenCV.

Drawing a line was simple enough. Now we can move on to drawing rectangles. Check out the code below for more details:

\# draw a green 50x50 pixel square, starting at 10x10 and ending at 60x60
cv2.rectangle(canvas, (10, 10), (60, 60), green)
cv2.imshow("Canvas", canvas)
cv2.waitKey(0)

# draw another rectangle, this one red with 5 pixel thickness
cv2.rectangle(canvas, (50, 200), (200, 225), red, 5)
cv2.imshow("Canvas", canvas)
cv2.waitKey(0)

# draw a final rectangle (blue and filled in )
blue = (255, 0, 0)
cv2.rectangle(canvas, (200, 50), (225, 125), blue, -1)
cv2.imshow("Canvas", canvas)
cv2.waitKey(0)

On **Line 24**, we make use of the `cv2.rectangle` method. The signature of this method is identical to the `cv2.line` method above, but let’s explore each argument anyway:

*   **The first argument is the image upon which we want to draw our rectangle.** We want to draw on our `canvas`, so we pass it into the method.
*   **The second argument is the starting _(x, y)_ position of our rectangle** — here, we start our rectangle at point _(10, 10)_.
*   **Then, we must provide an ending _(x, y)_ point for the rectangle.** We decide to end our rectangle at _(60, 60)_, defining a region of _50 x 50_ pixels (take a second to convince yourself that the resulting rectangle is _50 x 50_).
*   **Finally, the last argument is the color of the rectangle we want to draw.** Here, we are drawing a green rectangle.

Just as we can control a line’s thickness, we can also control the rectangle’s thickness. **Line 29** provides that thickness argument. Here, we draw a red rectangle that is 5 pixels thick, starting at point _(50, 200)_ and ending at _(200, 225)._

At this point, we have only drawn the outline of a rectangle. How do we draw a rectangle that is “completely filled”?

**Simple. We just pass a negative value for the thickness argument.**

**Line 35** demonstrates how to draw a rectangle of a solid color. We draw a blue rectangle, starting at _(200, 50)_ and ending at _(225, 125)_. By specifying `-1` (or use the `cv2.FILLED` keyword) as the thickness, our rectangle is drawn as a solid blue.

**Figure 4** displays the full output of drawing our lines and rectangles:

![Image 6](data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%20600%20500'%3E%3C/svg%3E)

**Figure 4:** Using OpenCV to draw lines and rectangles.

As you can see, the output matches our code. We could draw a _green line_ from the _top-left_ corner to the _bottom-right_ corner, followed by a _thicker red line_ from the _top-right_ corner to the _bottom-left_ corner.

We were also able to draw a _green rectangle_, a slightly _thicker red rectangle_, and a _completely filled blue rectangle._

That’s great and all — but what about circles?

How can we use OpenCV to draw circles?

Drawing circles is just as simple as drawing rectangles, but the function arguments are a little different:

\# re-initialize our canvas as an empty array, then compute the
# center (x, y)-coordinates of the canvas
canvas = np.zeros((300, 300, 3), dtype="uint8")
(centerX, centerY) = (canvas.shape\[1\] // 2, canvas.shape\[0\] // 2)
white = (255, 255, 255)

# loop over increasing radii, from 25 pixels to 150 pixels in 25
# pixel increments
for r in range(0, 175, 25):
	# draw a white circle with the current radius size
	cv2.circle(canvas, (centerX, centerY), r, white)

# show our work of art
cv2.imshow("Canvas", canvas)
cv2.waitKey(0)

On **Line 41,** we re-initialize our canvas to blank:

![Image 7](data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%20600%20500'%3E%3C/svg%3E)

**Figure 5:** Re-initializing our canvas as a blank image.

**Line 42** calculates two variables: `centerX` and `centerY`. These two variables represent the _(x, y)_\-coordinates of the image’s center.

We calculate the center by examining the shape of our NumPy array and then dividing by two:

*   The height of the image can be found in `canvas.shape[0]` (number of rows)
*   The width is found in `canvas.shape[1]` (number of columns)

Finally, **Line 43** defines a white pixel (i.e., the buckets for each of the Red, Green, and Blue components are “full”).

Now, let’s draw some circles!

On **Line 45,** we loop over several radius values, starting at `0` and ending at `150`, incrementing by `25` at each step. The `range` function is _exclusive_; therefore, we specify a stopping value of `175` rather than `150`.

To demonstrate this for yourself, open a Python shell, and execute the following code:

$ python
>>> list(range(0, 175, 25))
\[0, 25, 50, 75, 100, 125, 150\]

Notice how the output of `range` stops at `150` and does not include `175`.

**Line 49** handles the actual drawing of the circle:

*   The first parameter is our `canvas`, the image upon which we want to draw the circle.
*   We then need to supply the point around which we will draw our circle. We pass in a tuple of `(centerX, centerY)` so that our circles will be centered at the center of the image.
*   The third argument is the radius, `r`, of the circle we wish to draw.
*   Finally, we pass in the color of our circle: in this case, white.

**Lines 52 and 53** then show our image and wait for a keypress:

![Image 8](data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%20600%20500'%3E%3C/svg%3E)

**Figure 6:** Drawing a bullseye with OpenCV.

Check out **Figure 6**, and you will see that we have drawn a simple bullseye! The “dot” in the very center of the image is drawn with a radius of 0. The larger circles are drawn with ever-increasing radii sizes from our `for` loop.

Not too bad. But what else can we do?

Let’s do some abstract drawing:

\# re-initialize our canvas once again
canvas = np.zeros((300, 300, 3), dtype="uint8")

# let's draw 25 random circles
for i in range(0, 25):
	# randomly generate a radius size between 5 and 200, generate a
	# random color, and then pick a random point on our canvas where
	# the circle will be drawn
	radius = np.random.randint(5, high=200)
	color = np.random.randint(0, high=256, size=(3,)).tolist()
	pt = np.random.randint(0, high=300, size=(2,))

	# draw our random circle on the canvas
	cv2.circle(canvas, tuple(pt), radius, color, -1)

# display our masterpiece to our screen
cv2.imshow("Canvas", canvas)
cv2.waitKey(0)

Our code starts on **Line 59** with more looping. This time we aren’t looping over our radii’s size — we are instead going to draw `25` random circles, making use of NumPy’s random number capabilities through the `np.random.randint` function.

To draw a random circle, we need to generate three values: the `radius` of the circle, the `color` of the circle, and the `pt` — the _(x, y)_\-coordinate of where the circle will be drawn.

We generate a `radius` value in the range _\[5, 200\]_ on **Line 63**. This value controls how large our circle will be.

On **Line 64**, we randomly generate a `color`. As we know, the color of an RGB pixel consists of three values in the range _\[0, 255\]_. To get _three_ random integers rather than only one integer, we pass the keyword argument `size=(3,)`, instructing NumPy to return a list of three numbers.

Lastly, we need an _(x, y)_\-center point to draw our circle. We will generate a point in the range _\[0, 300)_, again using NumPy’s `np.random.randint` function.

The drawing of our circle then takes place on **Line 68**, using the `radius`, `color`, and `pt` that we randomly generated. Notice how we use a thickness of `-1`, so our circles are drawn as a solid color and not just an outline.

**Lines 71 and 72** shown our masterpiece, which you can see in **Figure 7**:

![Image 9](data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%20600%20500'%3E%3C/svg%3E)

**Figure 7:** Drawing multiple circles with OpenCV.

Notice how each circle has a different size, color, and placement on our canvas.

### **OpenCV basic drawing results**

To execute our basic drawing script, be sure to access the **_“Downloads”_** section to retrieve the source code and example image.

From there, you can execute the following command:

$ python basic\_drawing.py

Your output should be identical to that of the previous section.

### **Drawing on images with OpenCV**

Up until this point, we have only explored drawing shapes on a _blank canvas_. But what if we want to draw shapes on an _existing image?_

**It turns out that the code to draw shapes on an existing image is** **_exactly the same_** **as if we were drawing on a blank canvas generated from NumPy.**

To demonstrate this, let’s look at some code:

\# import the necessary packages
import argparse
import cv2

# construct the argument parser and parse the arguments
ap = argparse.ArgumentParser()
ap.add\_argument("-i", "--image", type=str, default="adrian.png",
	help="path to the input image")
args = vars(ap.parse\_args())

**Lines 2 and 3** import our required Python packages, while **Lines 6-9** parse our command line arguments.

We only need a single argument, `--image`, which is the path to our input image on disk. By default, we set the `--image` command line argument to point to the `adrian.png` image in our project directory structure.

\# load the input image from disk
image = cv2.imread(args\["image"\])

# draw a circle around my face, two filled in circles covering my
# eyes, and a rectangle over top of my mouth
cv2.circle(image, (168, 188), 90, (0, 0, 255), 2)
cv2.circle(image, (150, 164), 10, (0, 0, 255), -1)
cv2.circle(image, (192, 174), 10, (0, 0, 255), -1)
cv2.rectangle(image, (134, 200), (186, 218), (0, 0, 255), -1)

# show the output image
cv2.imshow("Output", image)
cv2.waitKey(0)

**Line 12** loads our `--image` from disk. From there, we proceed to:

1.  Draw an _empty_ circle (_not_ filled in) surrounding my head (**Line 16**)
2.  Draw two _filled in_ circles covering my eyes (**Lines 17 and 18**)
3.  Draw a rectangle over my mouth (**Line 19**)

Our final output, `image`, is then displayed on our screen.

### **OpenCV image drawing results**

Let’s see how we can use OpenCV to draw on an image versus a “blank canvas” generated by NumPy.

Start by accessing the **_“Downloads”_** section of this guide to retrieve the source code and example image.

You can then execute the following command:

$ python image\_drawing.py

![Image 10](data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%20540%20475'%3E%3C/svg%3E)

**Figure 8:** Drawing shapes on an image with OpenCV.

Here, you can see that we have drawn an outlined circle surrounding my face, two filled circles over my eyes, and a filled rectangle over my mouth.

In fact, there is _no difference_ between drawing shapes on an _image loaded from disk_ versus a _blank NumPy array_. As long as our image/canvas can be represented as a NumPy array, OpenCV will draw on it just the same.

### What's next? We recommend [PyImageSearch University](https://pyimagesearch.com/pyimagesearch-university/?utm_source=blogPost&utm_medium=bottomBanner&utm_campaign=What%27s%20next%3F%20I%20recommend).

**Course information:**  
84 total classes • 114+ hours of on-demand code walkthrough videos • Last updated: February 2024  
★★★★★ 4.84 (128 Ratings) • 16,000+ Students Enrolled

**I strongly believe that if you had the right teacher you could _master_ computer vision and deep learning.**

Do you think learning computer vision and deep learning has to be time-consuming, overwhelming, and complicated? Or has to involve complex mathematics and equations? Or requires a degree in computer science?

That’s _not_ the case.

All you need to master computer vision and deep learning is for someone to explain things to you in _simple, intuitive_ terms. _And that’s exactly what I do_. My mission is to change education and how complex Artificial Intelligence topics are taught.

If you're serious about learning computer vision, your next stop should be PyImageSearch University, the most comprehensive computer vision, deep learning, and OpenCV course online today. Here you’ll learn how to _successfully_ and _confidently_ apply computer vision to your work, research, and projects. Join me in computer vision mastery.

**Inside PyImageSearch University you'll find:**

*   ✓ **84 courses** on essential computer vision, deep learning, and OpenCV topics
*   ✓ **84 Certificates** of Completion
*   ✓ **114+ hours** of on-demand video
*   ✓ **Brand new courses released _regularly_**, ensuring you can keep up with state-of-the-art techniques
*   ✓ **Pre-configured Jupyter Notebooks in Google Colab**
*   ✓ Run all code examples in your web browser — works on Windows, macOS, and Linux (no dev environment configuration required!)
*   ✓ Access to **centralized code repos for _all_ 536+ tutorials** on PyImageSearch
*   ✓ **Easy one-click downloads** for code, datasets, pre-trained models, etc.
*   ✓ **Access** on mobile, laptop, desktop, etc.

[Click here to join PyImageSearch University](https://pyimagesearch.com/pyimagesearch-university/?utm_source=blogPost&utm_medium=bottomBanner&utm_campaign=What%27s%20next%3F%20I%20recommend)

**Summary**
-----------

In this tutorial, you learned how to draw with OpenCV. Specifically, you learned how to use OpenCV to draw:

*   Lines
*   Circles
*   Rectangles

Lines were drawn using the `cv2.line` function. We used the `cv2.circle` function to draw circles and the `cv2.rectangle` method to draw rectangles with OpenCV.

Other drawing functions exist in OpenCV. However, these are the functions you will use most often.

**To download the source code to this post (and be notified when future tutorials are published here on PyImageSearch),** **_simply enter your email address in the form below!_**

![Image 11](data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%20410%20567'%3E%3C/svg%3E)

#### Download the Source Code and FREE 17-page Resource Guide

Enter your email address below to get a .zip of the code and a **FREE 17-page Resource Guide on Computer Vision, OpenCV, and Deep Learning.** Inside you'll find my hand-picked tutorials, books, courses, and libraries to help you master CV and DL!