Pillow is a fork for the Python Imaging Library, PIL, that provides various image-processing features to manipulate images and apply different filters. ImagDraw()
is one of the modules in the Pillow library which allows drawing on an image, including shapes and text. This helps to obtain different shape objects that can be overlayed on an image to obtain a new image.
Let's draw different types of shapes in an image using PIL
library and show it in Pyplot
.
Note: We can also add text on an image. Read an answer on how to add text on images in Python pillow to learn further about it.
We will use the PIL
library to manipulate the image and then use matplotlib
to display the results once the code is executed successfully.
import matplotlib.pyplot as pltfrom PIL import Image, ImageDraw, ImageFontimport requestsfrom io import BytesIO
matplotlib
: To create visualizations and plots in the Python library.
matplotlib
: To create visualizations and plots in the Python library.
PIL
: Computer vision library to apply operations on images.
Image
: To enhance the image properties that change its appearance.
ImageDraw
: To draw on the image, e.g., adding text in this case.
requests
: To send the requests over the HTTP server to the website.
BytesIO
: To handle the binary data as an in-memory system.
This is a sample code structure that can be used in all the codes to manipulate images by adding different overlay shapes using ImageDraw()
.
#this is a basic code structure, we can add the shape functions on line 23# importing image object from PILimport matplotlib.pyplot as pltfrom PIL import Image, ImageDrawimport requestsfrom io import BytesIOimage_url = "https://images.pexels.com/photos/2680270/pexels-photo-2680270.jpeg?auto=compress&cs=tinysrgb&w=300"# Fetch imageresponse = requests.get(image_url)image_data = BytesIO(response.content)original_image = Image.open(image_data).convert('RGBA')w, h = 200, 180shape = [(40, 40), (w - 10, h - 10)]img = Image.new("RGBA", original_image.size, (0, 0, 0, 0))# Create pieslice imagemyShape = ImageDraw.Draw(img)#Specify the shape that we want to drawnew_image = Image.alpha_composite(original_image, img)plt.figure(figsize=(10, 5))plt.subplots_adjust(wspace=0.4, hspace=0.1)plt.subplot(1, 3, 1)plt.imshow(original_image)plt.axis('off')plt.title('Original Image')plt.subplot(1, 3, 2)plt.imshow(img)plt.axis('off')plt.title('Shape Image')plt.subplot(1, 3, 3)plt.imshow(new_image)plt.axis('off')plt.title('Composite Image')plt.show()
Lines 2–6: Import the required libraries and modules.
Line 8: Store the link of the image that is to be used on image_url
. We can also use a local image file and give its exact name.
Lines 11–12: Use request
to fetch the image from the server and open it using the Image.open()
method and pass the converted image to it.
Lines 13: Convert the image to the RGBA format, open it, and save it in the original_image
object.
Lines 15–16: Specify the width and height of the shape and set a bounding box for it. The specified range is saved in shape
attribute.
Line 19: Create transparent blank images that will contain the text.
Lines 22: Create an ImageDraw()
object and pass the transparent blank image we want to draw on as a parameter to Draw()
.
Lines 23: Use the required shape's function from the ImageDraw()
module and pass the start angle, end angle, fill, and outline color as parameters.
Lines 25: Use composite()
to join the original image and the corresponding transparent image on which the text is added.
Lines 27–28: Specify the figure size that is to appear in the plot and assign the grid size.
Lines 30–33: Display the image using imshow()
and pass the original image to it, turn off the x-axis labels, and specify the title in the title()
.
Lines 35–38: Display the image using imshow()
and pass the shape image to it, turn off the x-axis labels, and specify the title in the title()
.
Lines 40–43: Display the image using imshow()
and pass the composite image to it, turn off the x-axis labels, and specify the title in the title()
.
Line 45: Show the resultant plot.
Now let's use the sample code and code different shapes using ImageDraw()
.
A pie slice is a sector of a circle that represents a specific area of the whole pie. The size of the pie slice corresponds to the proportion of the pie that it represents. We use the following code to draw a pie slice.
myShape.pieslice(shape, start=50, end=260, fill="#A7C7E7", outline="#A7C7E7")
The output of the code with the following specifications should be as follows:
In this example code, we draw a pie slice using a pieslice()
method and specify the start value as 50 and the end value as 260. We can change these values to obtain different pie slice shapes.
import matplotlib.pyplot as plt from PIL import Image, ImageDraw import requests from io import BytesIO image_url = "https://images.pexels.com/photos/2680270/pexels-photo-2680270.jpeg?auto=compress&cs=tinysrgb&w=300" # Fetch image response = requests.get(image_url) image_data = BytesIO(response.content) original_image = Image.open(image_data).convert('RGBA') w, h = 200, 180 shape = [(40, 40), (w - 10, h - 10)] img = Image.new("RGBA", original_image.size, (0, 0, 0, 0)) # Create pieslice image myShape = ImageDraw.Draw(img) myShape.pieslice(shape, start=50, end=260, fill="#A7C7E7", outline="#A7C7E7") new_image = Image.alpha_composite(original_image, img) plt.figure(figsize=(10, 5)) plt.subplots_adjust(wspace=0.4, hspace=0.1) plt.subplot(1, 3, 1) plt.imshow(original_image) plt.axis('off') plt.title('Original Image') plt.subplot(1, 3, 2) plt.imshow(img) plt.axis('off') plt.title('Shape Image') plt.subplot(1, 3, 3) plt.imshow(new_image) plt.axis('off') plt.title('Composite Image') plt.show()
A rectangle is a four-sided shape. The size of the rectangle corresponds to the proportion of the specified width and length of the sides. We use the following code to draw a rectangle.
myShape.rectangle(shape, fill ="#ADD8E6", outline ="#ADD8E6")
The output of the code with the following specifications should be as follows:
In this example code, we draw a circle using rectangle()
method and specify fill and outline colors. We can change these values to obtain different colors of the circle shapes.
import matplotlib.pyplot as plt from PIL import Image, ImageDraw import requests from io import BytesIO image_url = "https://images.pexels.com/photos/2680270/pexels-photo-2680270.jpeg?auto=compress&cs=tinysrgb&w=300" # Fetch image response = requests.get(image_url) image_data = BytesIO(response.content) original_image = Image.open(image_data).convert('RGBA') w, h = 200, 180 shape = [(40, 40), (w - 10, h - 10)] img = Image.new("RGBA", original_image.size, (0, 0, 0, 0)) # Create pieslice image myShape = ImageDraw.Draw(img) myShape.rectangle(shape, fill ="#ADD8E6", outline ="#ADD8E6") new_image = Image.alpha_composite(original_image, img) plt.figure(figsize=(10, 5)) plt.subplots_adjust(wspace=0.4, hspace=0.1) plt.subplot(1, 3, 1) plt.imshow(original_image) plt.axis('off') plt.title('Original Image') plt.subplot(1, 3, 2) plt.imshow(img) plt.axis('off') plt.title('Shape Image') plt.subplot(1, 3, 3) plt.imshow(new_image) plt.axis('off') plt.title('Composite Image') plt.show()
An ellipse is like a flattened circle representing the set of all points in a plane. The sum of the distance of these points from two fixed points is constant. We use the following code to draw a pie slice.
myShape.ellipse(shape, fill ="#ADD8E6", outline ="#ADD8E6")
The output of the code with the following specifications should be as follows:
In this example code, we draw a flattened circle using ellipse()
method and specify fill and outline colors. We can change these values to obtain different colors of the circle shapes.
import matplotlib.pyplot as plt from PIL import Image, ImageDraw import requests from io import BytesIO image_url = "https://images.pexels.com/photos/2680270/pexels-photo-2680270.jpeg?auto=compress&cs=tinysrgb&w=300" # Fetch image response = requests.get(image_url) image_data = BytesIO(response.content) original_image = Image.open(image_data).convert('RGBA') w, h = 200, 180 shape = [(40, 40), (w - 10, h - 10)] img = Image.new("RGBA", original_image.size, (0, 0, 0, 0)) # Create pieslice image myShape = ImageDraw.Draw(img) myShape.ellipse(shape, fill ="#ADD8E6", outline ="#ADD8E6") new_image = Image.alpha_composite(original_image, img) plt.figure(figsize=(10, 5)) plt.subplots_adjust(wspace=0.4, hspace=0.1) plt.subplot(1, 3, 1) plt.imshow(original_image) plt.axis('off') plt.title('Original Image') plt.subplot(1, 3, 2) plt.imshow(img) plt.axis('off') plt.title('Shape Image') plt.subplot(1, 3, 3) plt.imshow(new_image) plt.axis('off') plt.title('Composite Image') plt.show()
A polygon is a 2D shape with a set number of straight lines joined on vertices to form a closed shape. Each edge intersects exactly two other edges. The polygon's size is determined by the number of sides specified for it. We use the following code to draw a polygon.
side = 6shift_amount = 20xy = [((math.cos(th) + 1) * 90 + shift_amount,(math.sin(th) + 1) * 60 + shift_amount)for th in [i * (2 * math.pi) / side for i in range(side)]]polygon_img = ImagePath.Path(xy).getbbox()size = list(map(int, map(math.ceil, polygon_img[2:])))
For drawing a polygon, we import the math
module and calculate the shape coordinates using the sine and cosine functions. The coordinates are then used to calculate the bounding box and store its width and height in the list.
The output of the code with the following specifications should be as follows:
In this example code, we draw a polygon using a polygon()
method to specify fill and outline colors. We can change these values to obtain different colors of the polygon shapes.
import matplotlib.pyplot as plt from PIL import Image, ImageDraw, ImagePath import requests from io import BytesIO import math # Fetch image image_url = "https://images.pexels.com/photos/2680270/pexels-photo-2680270.jpeg?auto=compress&cs=tinysrgb&w=300" response = requests.get(image_url) image_data = BytesIO(response.content) original_image = Image.open(image_data).convert('RGBA') polygon_image = Image.new("RGBA", original_image.size, (0, 0, 0, 0)) side = 6 shift_amount = 20 xy = [ ((math.cos(th) + 1) * 90 + shift_amount, (math.sin(th) + 1) * 60 + shift_amount) for th in [i * (2 * math.pi) / side for i in range(side)] ] polygon_img = ImagePath.Path(xy).getbbox() size = list(map(int, map(math.ceil, polygon_img[2:]))) polygon_draw = ImageDraw.Draw(polygon_image) polygon_draw.polygon(xy, fill="#A7C7E7", outline="#A7C7E7") new_image = Image.alpha_composite(original_image, polygon_image) plt.figure(figsize=(10, 4)) plt.subplots_adjust(wspace=0.3) plt.subplot(1, 3, 1) plt.imshow(original_image) plt.axis('off') plt.title('Original Image') plt.subplot(1, 3, 2) plt.imshow(polygon_image) plt.axis('off') plt.title('Polygon Image') plt.subplot(1, 3, 3) plt.imshow(new_image) plt.axis('off') plt.title('Composite Image') plt.show()
An arc is a curve segment that forms a circle's boundary. It represents a portion of the circle's circumference, a curve between two points. We use the following code to draw an arc.
myShape.arc(shape, start = 20, end = 140, fill ="#00FFFF" ,width=5)
The output of the code with the following specifications should be as follows:
In this example code, we draw an arc using a arc()
method and specify the start value as 20, the end value as 140, and the thickness as 5. We can change these values to obtain different arc shapes.
import matplotlib.pyplot as plt from PIL import Image, ImageDraw import requests from io import BytesIO image_url = "https://images.pexels.com/photos/2680270/pexels-photo-2680270.jpeg?auto=compress&cs=tinysrgb&w=300" # Fetch image response = requests.get(image_url) image_data = BytesIO(response.content) original_image = Image.open(image_data).convert('RGBA') w, h = 200, 180 shape = [(40, 40), (w - 10, h - 10)] img = Image.new("RGBA", original_image.size, (0, 0, 0, 0)) # Create pieslice image myShape = ImageDraw.Draw(img) myShape.arc(shape, start = 20, end = 140, fill ="#00FFFF" ,width=5) new_image = Image.alpha_composite(original_image, img) plt.figure(figsize=(10, 5)) plt.subplots_adjust(wspace=0.4, hspace=0.1) plt.subplot(1, 3, 1) plt.imshow(original_image) plt.axis('off') plt.title('Original Image') plt.subplot(1, 3, 2) plt.imshow(img) plt.axis('off') plt.title('Shape Image') plt.subplot(1, 3, 3) plt.imshow(new_image) plt.axis('off') plt.title('Composite Image') plt.show()
A line is a straight stretched segment from one point to another. Depending on the requirement, it can be horizontal, vertical, or diagonal. We use the following code to draw an arc.
myShape.line(shape, fill ="#00FFFF" ,width=5)
The output of the code with the following specifications should be as follows:
In this example code, we draw a diagonal line using a line()
method and specify the fill and width of the shape. We can change these values to obtain different widths and colors of a line.
import matplotlib.pyplot as plt from PIL import Image, ImageDraw import requests from io import BytesIO image_url = "https://images.pexels.com/photos/2680270/pexels-photo-2680270.jpeg?auto=compress&cs=tinysrgb&w=300" # Fetch image response = requests.get(image_url) image_data = BytesIO(response.content) original_image = Image.open(image_data).convert('RGBA') w, h = 200, 180 shape = [(40, 40), (w - 10, h - 10)] img = Image.new("RGBA", original_image.size, (0, 0, 0, 0)) # Create pieslice image myShape = ImageDraw.Draw(img) myShape.line(shape, fill ="#00FFFF" ,width=5) new_image = Image.alpha_composite(original_image, img) plt.figure(figsize=(10, 5)) plt.subplots_adjust(wspace=0.4, hspace=0.1) plt.subplot(1, 3, 1) plt.imshow(original_image) plt.axis('off') plt.title('Original Image') plt.subplot(1, 3, 2) plt.imshow(img) plt.axis('off') plt.title('Shape Image') plt.subplot(1, 3, 3) plt.imshow(new_image) plt.axis('off') plt.title('Composite Image') plt.show()
ImageDraw()
is a rich pillow module that provides a variety of shapes that can be drawn on an existing image or as standalone images to obtain a figure as per requirement. We can combine different shapes to make a new shape and attractively illustrate our content.
Free Resources