You might need to add borders or frames to your images for presentations or other decorative reasons. Frames are a good way to improve photographic presentation and they bring more focus to the image being presented. Photo frames or borders can even be useful in science publications or consulting reports.
In this tutorial, we will learn how to achieve photo / image frames using Python very quickly and intuitively. We will also provide multiple methods so you can choose the most suitable code for your image frame application.
We are going to be using Image, ImageDraw and ImageOps modules from the PIL library mainly so let’s import those first.
from PIL import Image, ImageDraw, ImageOps
ImageOps
You can create a new image using PIL’s new method as below. It’s important to pay attention to color modes here as they can significantly impact the image manipulations that can be done on them as well as image saving options.
Here is a new image example with .new() method. First parameter is the color mode of the image while the second parameter in a tuple is the dimensions of the image.
img = Image.open('/home/usa/Downloads/Wallpaperz/nick-perez-duvq92-VCZ4-unsplash.jpg')
.expand
method from ImageOps
module of PILnew_img = ImageOps.expand(img, border=100)
new_img.show()
Nice and easy. ImageOps.expand method is probably the most suitable for simple outer border type frames.
Image.new
& .paste
Alternatively, we can create a new image that’s slightly larger than our existing image which we desire to apply borders to and then we can paste the existing image to this new empty canvas that’s slightly larger which would yield a nice border effect.
The code below can be analyzed in 3 steps:
* It’s beneficial to use “Floor Division Operator //
” instead of “Float Division Operator /
” at 3rd step because floor division rounds down the division to the next integer while float division yields a result with decimals which may confuse the program as pixels don’t exist in decimal state. (You can revisit our Python Operator Tips and Arithmetic Python Operators lesson for more insight.)
from PIL import Image
img = Image.open('/home/usa/Downloads/Wallpaperz/nick-perez-duvq92-vcz4-unsplash.jpg')
width, height= img.size
pad = 300
base_img = Image.new("rgba", (width+pad, height+pad), color='papayawhip')
base_img.paste(img,(pad//2, pad//2))
base_img.show()
Alternatively, we can create a new image that’s slightly larger than our existing image which we desire to apply borders to and then we can paste the existing image to this new empty canvas that’s slightly larger which would yield a nice border effect.
ImageDraw.draw.line
We can use “draw.lines” method to improve the aesthetics of an existing border or frame as well as create new borders by drawing each side separately.
Here is an example where 4 lines are drawn for the outer borders and 4 thinner lines are drawn for the inner borders as well resulting in an improved frame look for the existing image.
We have a dedicated Python tutorial with examples for ImageDraw module. Feel free to visit it for more ideas below:
img = Image.open('/home/usa/Downloads/Wallpaperz/nick-perez-duvq92-VCZ4-unsplash.jpg')
width, height= img.size
pad = 400
base_img = Image.new("RGBA", (width+pad, height+pad), color='papayawhip')
draw=ImageDraw.Draw(base_img)
base_img.paste(img,(pad//2, pad//2))
#Frame 1
new_width, new_height = base_img.size
xleft, xright = 100, new_width-100
yhigh, ylow = 100, new_height-100
frame1_line_width=4
frame1_line_color='gray'
draw.line((xleft, yhigh, xright, yhigh), fill=frame1_line_color, width=frame1_line_width)
draw.line((xleft, ylow, xright, ylow), fill=frame1_line_color, width=frame1_line_width)
draw.line((xleft, yhigh, xleft, ylow), fill=frame1_line_color, width=frame1_line_width)
draw.line((xright, yhigh, xright, ylow), fill=frame1_line_color, width=frame1_line_width)
#Frame 2
new_width, new_height = base_img.size
xleft, xright = 80, new_width-80
yhigh, ylow = 80, new_height-80
frame1_line_width=4
frame1_line_color='gray'
draw.line((xleft, yhigh, xright, yhigh), fill=frame1_line_color, width=frame1_line_width)
draw.line((xleft, ylow, xright, ylow), fill=frame1_line_color, width=frame1_line_width)
draw.line((xleft, yhigh, xleft, ylow), fill=frame1_line_color, width=frame1_line_width)
draw.line((xright, yhigh, xright, ylow), fill=frame1_line_color, width=frame1_line_width)
base_img.show()
I just copy pasted the Frame 2 part and only changed the pad variable slightly to line up the frames. Although it’s pretty straightforward and demonstrable this way this code would benefit greatly from writing a user defined Python function to avoid repetitiveness.
ImageDraw.draw.rectangle
We can achieve similar results with draw.rectangle function and the code will be a lot tidier compared to drawing each line separately.
Here is a cool example mixed with text on image feature.
* This code only demonstrates the image frame and excludes the text parts for simplicity.
You can refer to our dedicated tutorial for adding text on images with Python.
x,y = img.size
#Frame 1
xleft, xright = 100, x-100
yhigh, ylow = 100, y-100
frame1_line_width=1
frame1_line_color='gray'
draw.line((xleft, yhigh, xright, yhigh), fill=frame1_line_color, width=frame1_line_width)
draw.line((xleft, ylow, xright, ylow), fill=frame1_line_color, width=frame1_line_width)
draw.line((xleft, yhigh, xleft, ylow), fill=frame1_line_color, width=frame1_line_width)
draw.line((xright, yhigh, xright, ylow), fill=frame1_line_color, width=frame1_line_width)
#Frame 2
xleft, xright = 50, x-50
yhigh, ylow = 50, y-50
frame2_line_width=9
frame2_line_color='white'
draw.line((xleft, yhigh, xright, yhigh), fill=frame2_line_color, width=frame2_line_width)
draw.line((xleft, ylow, xright, ylow), fill=frame2_line_color, width=frame2_line_width)
draw.line((xleft, yhigh, xleft, ylow), fill=frame2_line_color, width=frame2_line_width)
draw.line((xright, yhigh, xright, ylow), fill=frame2_line_color, width=frame2_line_width)
Opencv's copyMakeBorder
Another interesting option we have is from the opencv library. Opencv has a function called copyMakeBorder which can be used to add borders very conveniently.
Additionally, copyMakeBorder has some interesting features that are hard to find elsewhere.
In this section we will take a look at those options and demonstrate them.
BORDER_CONSTANT
parameterimport cv2
img = cv2.imread('/home/usa/Downloads/Wallpaperz/nick-perez-duvq92-VCZ4-unsplash.jpg')
new_img = cv2.copyMakeBorder(img, 280, 280, 280, 280, cv2.BORDER_CONSTANT, value=[100,128,128])
cv2.imwrite('new_img.png', new_img)
BORDER_REFLECT
parameterYou can also use a bunch of specific methods to create a reflection effect along the frame using opencv.
BORDER_WRAP
parameterimport cv2
img = cv2.imread('/home/usa/Downloads/Wallpaperz/nick-perez-duvq92-VCZ4-unsplash.jpg')
new_img = cv2.copyMakeBorder(img, 280, 280, 280, 280, cv2.BORDER_WRAP)
#new_img = cv2.copyMakeBorder(img, 280, 280, 280, 280, cv2.BORDER_CONSTANT, value=[100,128,128])
cv2.imwrite('new_img.png', new_img)
BORDER_REPLICATE
parameterBorder replicate also repeats the edges of the images and can be used for a different effect as well.
BORDER_DEFAULT
parameterThere is also a border_default option which you can choose as the border type.
In this Python Tutorial we learned how to create borders and frames around images using Python’s PIL library as well as the OpenCV library.
We used various image editing methods such as .paste(), .line(), .draw(), .new() and a few others.
We have a few powerful tutorials regarding image editing with Python examples via the PIL library. You are welcome to review those for getting some inspiration and technical new Python skills.