Updated On : Sep-06,2021  draw-shapes, scikit-image

# How to Draw Shapes on Images using Scikit-Image [Python]?¶

The image processing field has recently seen quite a growth due to advances in neural networks and other useful machine learning algorithms. Image processing involves the processing of images which can be a range of operations like smoothing images, detecting edges, image segmentation, image filtering, etc. The image generated after image processing can be a final image or it can be an image that will be fed to further algorithms. Many times, we might need to add shapes to images in order to prepare them for some other task like adding circles around faces for face detection, adding rectangles around objects for object detection, etc. Manually doing such tasks can be very cumbersome. It can fasten the process if we can automate such tasks.

Python scikit-image library provides us with sub-module name draw which can help us add shapes (circles, rectangle, ellipses, etc.) of different types to our image. It has methods that can handle both grayscale and RGB images. As a part of this tutorial, we'll explain various methods available through draw sub-module with simple and easy-to-understand examples. We'll be adding shapes to both grayscale and RGB images for explanation purposes.

Below is a list of shapes that we'll discuss as a part of this tutorial.

• Line
• Circle Perimeter
• Disk/Filled Circle
• Filled Ellipse
• Ellipse Perimeter
• Filled Rectangle/Square
• Rectangle/Square Perimeter
• Filled Polygon
• Polygon Perimeter
• Bezier Curve
• Set Color Of Given Coords
• Random Shapes

We'll start by importing the necessary modules and images that we'll be using for explanation purposes.

In [1]:
```import skimage
from skimage import data, draw, io

import matplotlib.pyplot as plt
import numpy as np
```

Below we have read colored (RGB) JPEG image from disk using io module of skimage and printed its dimensions as well as data types. The second colored (RGB) image is of a coffee cup available as a part of data module of skimage.

If you are interested in learning about how to perform basic operations with images (reading/writing images, resize, rescale, rotate, etc) using skimaget then please feel free to check our tutorial on the same. It tries to explain things with simple examples.

Please make a note that scikit-image treats all images as a numpy array of integers (0-255) or floats (0.0-1.0). It performs all operations on the array.

In [2]:
```dr_kalam = io.imread("dr_apj_kalam.jpeg")

coffee = skimage.data.coffee()

print("DR Kalam Image Shape : {}, Data Type : {}".format(dr_kalam.shape, dr_kalam.dtype))
print("Coffee Image Shape   : {}, Data Type : {}".format(coffee.shape, coffee.dtype))
```
```DR Kalam Image Shape : (247, 204, 3), Data Type : uint8
Coffee Image Shape   : (400, 600, 3), Data Type : uint8
```

Below we have created a simple function that takes as input two images and displays them next to each other. We'll be reusing this function for showing different images.

In [ ]:
```def display_images(img1, img2, cmap=None):

fig, ax = plt.subplots(nrows=1, ncols=2)

fig.set_figwidth(8)
fig.set_figheight(8)

ax[0].imshow(img1, cmap=cmap);

ax[1].imshow(img2, cmap=cmap);

display_images(coffee, dr_kalam)
```

Below we have loaded two gray scale images from the internet for explanation purposes.

In [4]:
```puppy = io.imread("greyscale_2.jpg", as_gray=True)

girl = io.imread("greyscale_1.jpeg", as_gray=True)

print("Puppy Image Shape : {}  , Data Type : {}".format(puppy.shape, puppy.dtype))

print("Girl Image Shape  : {}, Data Type : {}".format(girl.shape, girl.dtype))
```
```Puppy Image Shape : (300, 332)  , Data Type : float64
Girl Image Shape  : (1333, 1000), Data Type : float64
```
In [ ]:
```display_images(puppy, girl, cmap="gray")
```

If you want to follow the tutorial with your images then you are free to do so but you'll have to make changes to method inputs for drawing shapes based on your image size.

### Line¶

The first shape that we'll explain in a simple line. The skimage.draw module provides us with a method named line() which lets us add lines to our image.

• line(r0,c0,r1,c1) - This method takes as input coordinates of starting and ending points as row and columns of an image. It then returns two lists where the first list has row entries and the second list has column entries consisting of a line. These two lists can be used to index the numpy array holding image data.

NOTE

Please make a note that the majority of methods inside of **skimage.draw** module works with input in the form of row and column of an image. The row and column start at the top-left end of the image. All methods working with images require us to think as if we are working with a numpy array. Normally we think of coordinates in terms of X and Y which start at the bottom-left corner and that will give us wrong results with these methods. The matplotlib also works with coordinates in terms of X and Y. If we want to use the output of methods with matplotlib then we'll have to consider columns as X-axis values and rows as Y-axis values. Please don't worry if you don't get concepts from the theoretical explanations. We have explained below this with examples to make things clear.

Below we have created a line using line() method which starts at (row-100,column-100) and ends at (row-1200,column-800). We'll be using matplotlib for plotting images. We have then created a copy of the girl’s grayscale image. We have then added the value of 1 in each row and column combination provided by line() method. We can do this by simply indexing girl image which is a numpy array. At last, we have plotted a new modified image. The value of 1

In [6]:
```row, col = draw.line(100, 100, 1200, 800)

row,col
```
Out[6]:
```(array([ 100,  101,  102, ..., 1198, 1199, 1200]),
array([100, 101, 101, ..., 799, 799, 800]))```
In [ ]:
```fig, ax = plt.subplots(1,1)

girl_copy = girl.copy()

girl_copy[row,col] = 1

ax.imshow(girl_copy, cmap="gray");
```

Below we have drawn a line to an image by using matplotlib. Please pay ATTENTION to how we have used column values as X values and row values as Y values for drawing the same line using matplotlib. This is the main difference between the coordinate system in numpy array and matplotlib that we need to keep in mind when working with the scikit-image module.

In [ ]:
```fig, ax = plt.subplots(1,1)

ax.imshow(girl, cmap="gray");
ax.plot(col, row, "--r");
```

Below we have explained another example demonstrating usage of line() method on RGB image. We are drawing a line from coordinates (100,50) to (200,200). We have then added a line to the copy of the original image using numpy indexing. At last, we have plotted the image for showing changes.

Please pay ATTENTION that as this is RGB image, we have assigned an array of 3 numbers to the image array when indexing. If we provide only a single value then the same value will be assigned to all 3 channels. We need to provide a proper color combination using 3 RGB values.

In [ ]:
```row, col = draw.line(100, 50, 200, 200)

fig, ax = plt.subplots(1,1)

dr_kalam_copy = dr_kalam.copy()

dr_kalam_copy[row, col] = [255,255,0]

ax.imshow(dr_kalam_copy);
```

Below we have explained how we can draw a line on image without modifying image and using matplotlib.

In [ ]:
```fig, ax = plt.subplots(1,1)

ax.imshow(dr_kalam);
ax.plot(col, row, "--y");
```

### Circle Perimeter¶

As a part of this section, we'll explain how we can draw a circle using circle_perimeter() method of skimage.draw module.

• circle_perimeter(r,c,radius) - This method takes as input center coordinate of circle and radius of circle in pixels.It returns two arrays of rows and columns which have coordinates of circle perimeter.

Below we have created a circle of 10 pixels at location (500,500) in the girl image. We have as usual created a copy of the image and modified the value at returned coordinates. We have then plotted the image using matplotlib to verify changes.

In [ ]:
```row, col = draw.circle_perimeter(500,500, 150)

fig, ax = plt.subplots(1, 1)

girl_copy = girl.copy()

girl_copy[row, col] = 1

ax.imshow(girl_copy, cmap="gray");
```

Below we have created a circle in RGB image of pixel 50 at coordinates (150,150).

In [ ]:
```row, col = draw.circle_perimeter(150,150, 50)

dr_kalam_copy = dr_kalam.copy()

dr_kalam_copy[row, col, :] = [255, 255, 0] ## Yellow Color

fig, ax = plt.subplots(1,1)

ax.imshow(dr_kalam_copy);
```

### Disk/Filled Circle¶

As a part of this section, we'll explain how we can create a filled circle on an image using disk() method of skimage.draw module.

• disk(center, radius) - This method takes as input center of the disk (as a tuple) as a first parameter and the radius of the disk as the second parameter. It then returns two lists that have coordinates of all points that fall within the circle specified using center and radius.

Below we have created a filled circle of radius 100 pixels at the center (150,250). We have then as usual plotted a modified image to show a circle in an image.

In [ ]:
```row, col = draw.disk((150,250), 100)

girl_copy = girl.copy()

girl_copy[row, col] = 1

fig, ax = plt.subplots(1,1)

ax.imshow(girl_copy, cmap="gray");
```

Below we have explained how to add a filled circle to an RGB image.

In [ ]:
```row, col = draw.disk((150,150), 50)

dr_kalam_copy = dr_kalam.copy()

dr_kalam_copy[row, col, :] = [255, 255, 0] ## Yellow Color

fig, ax = plt.subplots(1,1)

ax.imshow(dr_kalam_copy);
```

### Filled Ellipse¶

As a part of this section, we'll explain how to create an ellipse using ellipse() method of skimage.draw module.

• ellipse(r,c,r_radius,c_radius) - This method takes as input four values. The first two values are coordinates of the center of the ellipse. The next two values are radius row-wise and column-wise width of the ellipse.

Below we have created an ellipse at the center (150,250) in the girl image with a height of 60 pixels and a width of 120 pixels.

In [ ]:
```row, col = draw.ellipse(150,250, 60, 120)

girl_copy = girl.copy()

girl_copy[row, col] = 1

fig, ax = plt.subplots(1,1)

ax.imshow(girl_copy, cmap="gray");
```

Below we have created an ellipse at the center (150,150) with a width of 15 pixels and a height of 50 pixels in the RGB image.

In [ ]:
```row, col = draw.ellipse(150,150, 50, 15)

dr_kalam_copy = dr_kalam.copy()

dr_kalam_copy[row, col, :] = [255, 255, 0] ## Yellow Color

fig, ax = plt.subplots(1,1)

ax.imshow(dr_kalam_copy);
```

### Ellipse Perimeter¶

Below we have explained how we can create an ellipse perimeter using ellipse_perimeter() method of skimage.draw module.

• ellipse_perimeter(r,c,r_radius,c_radius) - This method works exactly like ellipse() method with only difference that it returns coordinates of only perimeter of ellipse and not of points inside it.

Below we have drawn an ellipse perimeter in the girl grayscale image.

In [ ]:
```row, col = draw.ellipse_perimeter(150,250, 60, 120)

girl_copy = girl.copy()

girl_copy[row, col] = 1

fig, ax = plt.subplots(1,1)

ax.imshow(girl_copy, cmap="gray");
```

Below we have drawn an ellipse perimeter in an RGB image for explanation purposes.

In [ ]:
```row, col = draw.ellipse_perimeter(150,150, 50, 15)

dr_kalam_copy = dr_kalam.copy()

dr_kalam_copy[row, col, :] = [255, 255, 0] ## Yellow Color

fig, ax = plt.subplots(1,1)

ax.imshow(dr_kalam_copy);
```

### Filled Rectangle/Square¶

As a part of this section, we have explained how we can create a filled rectangle/square using rectangle() method of skimage.draw module.

• rectangle(start, end) - This method takes as input two tuples where the first tuple is the start point of the rectangle and the second tuple is an endpoint of the rectangle. We can use the same method to create a square as well. Like all other draw module methods, it also returns two lists that have coordinates of a square.

Below we have drawn a rectangle between points (150,150) and (250,300) in our grayscale image.

In [ ]:
```row, col = draw.rectangle(start=(150,150), end=(250, 300))

girl_copy = girl.copy()

girl_copy[row, col] = 1

fig, ax = plt.subplots(1,1)

ax.imshow(girl_copy, cmap="gray");
```

Below we have drawn a rectangle between points (150,150) and (175,200) in our RGB image.

In [ ]:
```row, col = draw.rectangle(start=(150,150), end=(175, 200))

dr_kalam_copy = dr_kalam.copy()

dr_kalam_copy[row, col, :] = [255, 255, 0] ## Yellow Color

fig, ax = plt.subplots(1,1)

ax.imshow(dr_kalam_copy);
```

### Rectangle/Square Perimeter¶

As a part of this section, we have explained how we can create a rectangle perimeter using rectangle_perimeter() method of skimage.draw module.

• rectangle_perimeter(start, end) - This method works exactly like rectangle() method with the only difference that it returns coordinates of the perimeter of the rectangle and not of points inside of it.

Below we have drawn a rectangle perimeter between coordinates (150,150) and (250,300) in our grayscale image.

In [ ]:
```row, col = draw.rectangle_perimeter(start=(150,150), end=(250, 300))

girl_copy = girl.copy()

girl_copy[row, col] = 1

fig, ax = plt.subplots(1,1)

ax.imshow(girl_copy, cmap="gray");
```

In [ ]:
```fig, ax = plt.subplots(1,1)

ax.imshow(girl, cmap="gray");
ax.plot(col, row, "--y");
```

Below we have drawn a rectangle perimeter between coordinates (150,150) and (175,200) in our RGB image.

In [ ]:
```row, col = draw.rectangle_perimeter(start=(150,150), end=(175, 200))

dr_kalam_copy = dr_kalam.copy()

dr_kalam_copy[row, col, :] = [255, 255, 0] ## Yellow Color

fig, ax = plt.subplots(1,1)

ax.imshow(dr_kalam_copy);
```

In [ ]:
```fig, ax = plt.subplots(1,1)

ax.imshow(dr_kalam);
ax.plot(col, row, "--y");
```

### Filled Polygon¶

As a part of this section, we have explained how we can create a polygon using polygon() method of skimage.draw module.

• polygon(r,c) - This method accepts two lists where the first list is row values and the second list is column values specifying coordinates of a polygon that we want to draw.

Below we have drawn a triangle in our grayscale image using polygon() method.

In [ ]:
```row, col = draw.polygon((100,200,800), (100,700,400))

girl_copy = girl.copy()

girl_copy[row, col] = 1

fig, ax = plt.subplots(1,1)

ax.imshow(girl_copy, cmap="gray");
```

Below we have drawn a polygon with 4 points in our gray scale image.

In [ ]:
```row, col = draw.polygon((100,200,800, 800), (100,700,400, 200))

girl_copy = girl.copy()

girl_copy[row, col] = 1

fig, ax = plt.subplots(1,1)

ax.imshow(girl_copy, cmap="gray");
```

Below we have drawn a triangle in our RGB image.

In [ ]:
```row, col = draw.polygon((100,150, 230), (100,130, 110))

dr_kalam_copy = dr_kalam.copy()

dr_kalam_copy[row, col, :] = [255, 255, 0] ## Yellow Color

fig, ax = plt.subplots(1,1)

ax.imshow(dr_kalam_copy);
```

Below we have drawn a polygon with 4 points in our RGB image.

In [ ]:
```row, col = draw.polygon((100,150, 230, 230), (100,130, 110, 50))

dr_kalam_copy = dr_kalam.copy()

dr_kalam_copy[row, col, :] = [255, 255, 0] ## Yellow Color

fig, ax = plt.subplots(1,1)

ax.imshow(dr_kalam_copy);
```

### Polygon Perimeter¶

As a part of this section, we have explained how we can draw polygon perimeter using polygon_perimeter() method of skimage.draw module.

• polygon_perimeter(r,c) - This method works exactly like polygon() method with the only difference that it returns coordinates of the perimeter of the polygon and not of points inside of it.

Below we have explained the usage of the method on our grayscale and RGB image.

In [ ]:
```row, col = draw.polygon_perimeter((100,200,800), (100,700,400))

girl_copy = girl.copy()

girl_copy[row, col] = 1

fig, ax = plt.subplots(1,1)

ax.imshow(girl_copy, cmap="gray");
```

In [ ]:
```row, col = draw.polygon_perimeter((100,150, 230, 230), (100,130, 110, 50))

dr_kalam_copy = dr_kalam.copy()

dr_kalam_copy[row, col, :] = [255, 255, 0] ## Yellow Color

fig, ax = plt.subplots(1,1)

ax.imshow(dr_kalam_copy);
```

### Bezier Curve¶

As a part of this section, we have explained how we can create a bezier curve shape on an image using bezier_curve() method of skimage.draw module. The bezier curves are used in the computer graphics field to create curves that appear smooth at almost all scales.

• bezier_curve(r0,c0,r1,c1,r2,c2,weight) - This method takes as input six parameter and returns coordinates of bezier curve created using them.
• The first two parameters (r0,c0) specifies the coordinates of the first control point of the curve.
• The next two parameters (r1,c1) specifies the coordinates of the middle control point of the curve.
• The next two parameters (r2,c2) specifies the coordinates of the last control point of the curve.
• The last weight parameter accepts float value specifying middle control point weight. It's used to describe line tension.

Below we have drawn a bezier curve on a grayscale image for explanation purposes.

In [ ]:
```row, col = draw.bezier_curve(100,800, 250,200, 500, 800, 2)

girl_copy = girl.copy()

girl_copy[row, col] = 1

fig, ax = plt.subplots(1,1)

ax.imshow(girl_copy, cmap="gray");
```

Below we have drawn a bezier curve on an RGB image for explanation purposes.

In [ ]:
```row, col = draw.bezier_curve(50,175, 175,50, 200, 175, 2)

dr_kalam_copy = dr_kalam.copy()

dr_kalam_copy[row, col, :] = [255, 255, 0] ## Yellow Color

fig, ax = plt.subplots(1,1)

ax.imshow(dr_kalam_copy);
```

As a part of this section, we'll explain how we can create a mask from polygon using polygon2mask() method of skimage.draw module.

• polygon2mask(image_shape,polygon) - This method takes as input two parameters. The first parameter is an actual image shape and the second parameter is a list of coordinates specifying polygon. It then returns a numpy array of the same size as the image shape with values for polygon filled in.

Below we have explained how we can create a mask using polygon2mask() method. We have plotted the original grayscale image and mask next to each other. Then we have modified the image to add a mask to the image and plotted it as well in the next code cell.

In [ ]:
```girl_mask = draw.polygon2mask(girl.shape, [(100,100),(200,700),(800,400), (800,200)])

fig, ax = plt.subplots(1,2)

ax[0].imshow(girl, cmap="gray");
```

In [ ]:
```girl_copy = girl.copy()

plt.imshow(girl_copy, cmap="gray");
```

### Set Color Of Given Coords¶

As a part of this section, we have explained how we can change the color of the list of coordinates of an image using set_color() method of skimage.draw module.

• set_color(image,coords,color,alpha=1) - This method takes as input 3 parameter and modifies input image based on given coordinates and color.
• The first parameter is the actual image whose specified coordinate's color we want to change.
• The second input is a tuple of length 2 where the first value is a list of row values and the second value is a list of column values specifying coordinates that we want to modify.
• The third parameter is color value.

Below we have first created a bezier curve and stored its points in a variable. We have then given copied image, bezier curve coordinates, and color value of 1 (white) to set_color() method. The set_color() method will modify the color of coordinates specified by the bezier curve.

In [ ]:
```bezier_curve = draw.bezier_curve(100,800, 250,200, 500, 800, 2)

girl_copy = girl.copy()

draw.set_color(girl_copy, bezier_curve, 1)

plt.imshow(girl_copy, cmap="gray");
```

Below we have drawn a polygon on an image using set_color() method.

In [ ]:
```polygon = draw.polygon((100,200,800, 800), (100,700,400, 200))

girl_copy = girl.copy()

draw.set_color(girl_copy, polygon, 0)

plt.imshow(girl_copy, cmap="gray");
```

Below we have explained the usage of set_color() on an RGB image.

In [ ]:
```bezier_curve = draw.bezier_curve(50,175, 175,50, 200, 175, 2)

dr_kalam_copy = dr_kalam.copy()

draw.set_color(dr_kalam_copy, bezier_curve, [0,255,0])

plt.imshow(dr_kalam_copy);
```

In [ ]:
```polygon = draw.polygon((100,150, 230, 230), (100,130, 110, 50))

dr_kalam_copy = dr_kalam.copy()

draw.set_color(dr_kalam_copy, polygon, [0,255,0])

plt.imshow(dr_kalam_copy);
```

### Random Shapes¶

As a part of this section, we'll explain how we can add random shapes with random sizes, random locations, and random color to our image using random_shapes() method of skimage.draw module.

• random_shapes(image_shape,max_shapes,min_shapes=1,min_size=2,max_size=None,multichannel=True,shape=None,allow_overlap=False,random_seed=None) - This method takes requires image shape and max shapes that we want to draw as input. It returns an image with shapes drawn into it based on image shape and labels for each shape included. The labels are a list of tuples where the first value is the label name and the second value is the coordinates of the bounding box surrounding the shape.
• The max_shapes parameter accepts an integer and specifies a maximum number of shapes to include.
• The min_shapes parameter accepts an integer and specifies the minimum number of shapes to include. The default is 1 shape at least.
• The min_size accepts an integer and specifies the minimum size of each shape.
• The max_size accepts an integer and specifies the maximum size of each shape.
• The multichannel parameter accepts a boolean value. If set to True then it returns shape in RGB image else in a grayscale image.
• The shape parameter accepts string values specifying shape type. The valid values are rectangle, circle, triangle, ellipse, and None. The default is set to None hence shape type is decided by a method.
• The allow_overlap method accepts boolean values specifying whether to allow shapes to overlap or not. The default is False which prevents overlap.
• The random_seed parameter accepts integer value specifying seed for randomness. It can be used for reproducibility. If we specify this parameter then it'll generate the same shapes at the same location each time we call the method.

Below we have generated 3 random shapes for our grayscale image. We have then included logic to include those shapes in our image. We have then plotted images with shapes and shape image returned by a method.

In [ ]:
```girl_random, labels = draw.random_shapes(girl.shape,
max_shapes=3,
min_size=5,
multichannel=False,
random_seed=1234)

girl_random = skimage.img_as_float(girl_random)

girl_copy = girl.copy()

girl_copy = np.where(girl_random == 1.0, girl_copy, girl_random)

fig,ax = plt.subplots(1,2)
ax[0].imshow(girl_copy, cmap="gray");
ax[1].imshow(girl_random, cmap="gray");
```

Below we have printed labels returned by a method.

In [40]:
```labels
```
Out[40]:
```[('rectangle', ((689, 973), (655, 893))),
('triangle', ((358, 443), (892, 989))),
('circle', ((722, 1217), (89, 584)))]```

Below we have explained the usage of a method to generate shapes on an RGB image. The shapes are not overlapping in this image.

In [ ]:
```dr_kalam_random, labels = draw.random_shapes(dr_kalam.shape, max_shapes=3, min_size=5,
multichannel=True,
random_seed=1234)

dr_kalam_copy = dr_kalam.copy()

dr_kalam_copy = np.where(dr_kalam_random==255, dr_kalam_copy, dr_kalam_random)

fig,ax = plt.subplots(1,2)
ax[0].imshow(dr_kalam_copy);
ax[1].imshow(dr_kalam_random);
```

In [42]:
```labels
```
Out[42]:
```[('triangle', ((30, 172), (30, 193))),
('rectangle', ((175, 230), (127, 169))),
('triangle', ((5, 20), (2, 19)))]```

Below we have explained another example specifying the usage of the method to create random shapes. We have included overlapping shapes this time.

In [ ]:
```dr_kalam_random, labels = draw.random_shapes(dr_kalam.shape, max_shapes=3, min_size=5,
multichannel=True,
allow_overlap=True,
random_seed=1234)

dr_kalam_copy = dr_kalam.copy()
dr_kalam_copy = np.where(dr_kalam_random==255, dr_kalam_copy, dr_kalam_random)

fig,ax = plt.subplots(1,2)
ax[0].imshow(dr_kalam_copy);
ax[1].imshow(dr_kalam_random);
```

This ends our small tutorial explaining how we can use draw module of skimage library to draw shapes of various types and sizes in images. Please feel free to let us know your views in the comments section.

Sunny Solanki

## Support Us

Thank You for visiting our website. If you like our work, please support us so that we can keep on creating new tutorials/blogs on interesting topics (like AI, ML, Data Science, Python, Digital Marketing, SEO, etc.) that can help people learn new things faster. You can support us by clicking on the Coffee button at the bottom right corner. We would appreciate even if you can give a thumbs-up to our article in the comments section below.

## Want to Share Your Views? Have Any Suggestions?

If you want to

• provide some suggestions on topic
• share your views
• include some details in tutorial
• suggest some new topics on which we should create tutorials/blogs
Please feel free to let us know in the comments section below (Guest Comments are allowed). We appreciate and value your feedbacks.