3

I have a 2D color image and a label image (projection of labels)

The output of label image is as follows:

[[16 16 16 ... 16 16 16 ]
 [16 16 16 ... 16 16 16 ]
 [16 16 16 ... 16 16 16 ]
 ...
 [ 2  2  2 ...  2  2  2 ]
 [ 2  2  2 ...  2  2  2 ]
 [ 2  2  2 ...  2  2  2 ]]

How do I draw bounding boxes around all the objects (represented by labels) in the original 2D color image?

Sid
  • 107
  • 2
  • 8
  • Are you doing pixel-level classification? – Alex Walczak Oct 20 '20 at 03:46
  • Yes, these are instance segmentation labels. Each pixel corresponds to a label (for example: 1 is chair, 2 is bed and so on) – Sid Oct 20 '20 at 04:08
  • How are you displaying the images? – Alex Walczak Oct 20 '20 at 04:24
  • Using cv2.imread and cv2.imshow... I would like to display the ground truth bounding boxes (I only have ground truth instance segmentation) on the color image using cv2.rectangle but I don't know how to compute bounding box corner coordinates. – Sid Oct 20 '20 at 04:26
  • Can you compute the points that would belong to each bounding box? If so, you can get the corner coordinates from there. Determining what defines the bounding boxes is something you’ll have to answer by looking at your data. – Alex Walczak Oct 20 '20 at 04:34
  • I'm struggling with that part, any help would be appreciated – Sid Oct 20 '20 at 05:05

1 Answers1

4

This task can be easily done using NumPy's boolean array indexing and OpenCV's boundingRect function.

From here, I took this image

image

and this segmentation mask

mask

The mask is an indexed image, which OpenCV has problems with, see also here. That's why, we'll also use Pillow for this task.

Here's the code:

import cv2
import numpy as np
from PIL import Image

# Read color image
img = cv2.imread('0.jpg')

# Read mask; OpenCV can't handle indexed images, so we need Pillow here
# for that, see also: https://stackoverflow.com/q/59839709/11089932
mask = np.array(Image.open('0_mask.png'))

# Iterate all colors in mask
for color in np.unique(mask):

    # Color 0 is assumed to be background or artifacts
    if color == 0:
        continue

    # Determine bounding rectangle w.r.t. all pixels of the mask with
    # the current color
    x, y, w, h = cv2.boundingRect(np.uint8(mask == color))

    # Draw bounding rectangle to color image
    out = cv2.rectangle(img.copy(), (x, y), (x+w, y+h), (0, int(color), 0), 2)

    # Show image with bounding box
    cv2.imshow('img_' + str(color), out)

# Show mask
cv2.imshow('mask', mask)
cv2.waitKey(0)
cv2.destroyAllWindows()

These are the outputs:

Outputs

I decided to output several images, because for the given image, the bounding boxes heavily overlap. To draw all rectangles to the same image, just replace the corresponding rectangle command by

img = cv2.rectangle(img, (x, y), (x+w, y+h), (0, int(color), 0), 2)
----------------------------------------
System information
----------------------------------------
Platform:    Windows-10-10.0.16299-SP0
Python:      3.8.5
NumPy:       1.19.2
OpenCV:      4.4.0
Pillow:      7.2.0
----------------------------------------
HansHirse
  • 18,010
  • 10
  • 38
  • 67