Visualize Bounding Boxes
2021-11-22
For certain computer vision tasks, I have an image and bounding boxes associated with that image in a text file. How would I visualize these boxes?
Relevant Packages
# Plotting
import matplotlib.pyplot as plt
import matplotlib.patches as patches
# Loading the Image
from PIL import Image
# Loading the text file
import pandas as pd
Classes for the Boxes
For Yolo models, I might have a separate file that lists the different class names associated with each box. The row number (0-indexed) gives me the class number.
with open('obj.names', 'r') as f:
classes = f.readlines()
classes = [ line.rstrip('\n') for line in classes ]
classes
['slide',
'title',
'banner',
'speaker',
'camera_on',
'camera_off',
'cue_zoom',
'cue_teams',
'cue_meet',
'cue_uberconference']
Load Data
Here I load the image and its associated text file.
im = Image.open('sample_input.jpg')
im
df = pd.read_csv("sample_input.txt", sep=" ", header=None, names=['idx', 'x', 'y', 'w', 'h'])
df
idx x y w h
0 0.500000 0.500000 1.000000 1.000000
1 0.182031 0.133333 0.285938 0.066667
Note that each row is a bounding box. The x,y,w,h values for the bounding box are normalized, that is they are the raw pixel values divided by the image size. I give some details on each value below in the viz_frame
documentation.
Visualize
I convert the normalized values in df
to raw pixel values and plot the bounding boxes over the image.
def viz_frame(im, df):
"""
Will visualize the coordinates in `df` on an image `im`.
Each row of the input `data-frame` is a particular bounding box.
The columns of the input `data-frame` should be:
* x: Center x coordinate of the bounding box normalized by the width of the image.
* y: Center y coordinate of the bounding box normalized by the height of the image.
* w: Normalized width of the bounding box
* h: Normalized height of the bounding box
"""
# Create figure and axes
fig, ax = plt.subplots()
# Display the image
ax.imshow(im)
for _,row in df.iterrows():
# Convert the normalized coordinates to raw pixels
iw = im.size[0]
ih = im.size[1]
w = row.w * iw
h = row.h * ih
x = row.x*iw - w/2. # center x
y = row.y*ih - h/2. # center y
# Create a Rectangle patch
rect = patches.Rectangle((x, y), w, h, linewidth=2, edgecolor='red', fill=False)
# Add the patch to the Axes
ax.add_patch(rect)
plt.show()
viz_frame(im, df)
And that’s it!