cellseg_sribd / overlay.py
Lewislou's picture
Upload overlay.py
2f17f86
raw
history blame
3.88 kB
#!/usr/bin/env python
# coding: utf-8
###overlay
import cv2
import math
import random
import colorsys
import numpy as np
import itertools
import matplotlib.pyplot as plt
from matplotlib import cm
import os
import scipy.io as io
def get_bounding_box(img):
"""Get bounding box coordinate information."""
rows = np.any(img, axis=1)
cols = np.any(img, axis=0)
rmin, rmax = np.where(rows)[0][[0, -1]]
cmin, cmax = np.where(cols)[0][[0, -1]]
# due to python indexing, need to add 1 to max
# else accessing will be 1px in the box, not out
rmax += 1
cmax += 1
return [rmin, rmax, cmin, cmax]
####
def colorize(ch, vmin, vmax):
"""Will clamp value value outside the provided range to vmax and vmin."""
cmap = plt.get_cmap("jet")
ch = np.squeeze(ch.astype("float32"))
vmin = vmin if vmin is not None else ch.min()
vmax = vmax if vmax is not None else ch.max()
ch[ch > vmax] = vmax # clamp value
ch[ch < vmin] = vmin
ch = (ch - vmin) / (vmax - vmin + 1.0e-16)
# take RGB from RGBA heat map
ch_cmap = (cmap(ch)[..., :3] * 255).astype("uint8")
return ch_cmap
####
def random_colors(N, bright=True):
"""Generate random colors.
To get visually distinct colors, generate them in HSV space then
convert to RGB.
"""
brightness = 1.0 if bright else 0.7
hsv = [(i / N, 1, brightness) for i in range(N)]
colors = list(map(lambda c: colorsys.hsv_to_rgb(*c), hsv))
random.shuffle(colors)
return colors
####
def visualize_instances_map(
input_image, inst_map, type_map=None, type_colour=None, line_thickness=2
):
"""Overlays segmentation results on image as contours.
Args:
input_image: input image
inst_map: instance mask with unique value for every object
type_map: type mask with unique value for every class
type_colour: a dict of {type : colour} , `type` is from 0-N
and `colour` is a tuple of (R, G, B)
line_thickness: line thickness of contours
Returns:
overlay: output image with segmentation overlay as contours
"""
overlay = np.copy((input_image).astype(np.uint8))
inst_list = list(np.unique(inst_map)) # get list of instances
inst_list.remove(0) # remove background
inst_rng_colors = random_colors(len(inst_list))
inst_rng_colors = np.array(inst_rng_colors) * 255
inst_rng_colors = inst_rng_colors.astype(np.uint8)
for inst_idx, inst_id in enumerate(inst_list):
inst_map_mask = np.array(inst_map == inst_id, np.uint8) # get single object
y1, y2, x1, x2 = get_bounding_box(inst_map_mask)
y1 = y1 - 2 if y1 - 2 >= 0 else y1
x1 = x1 - 2 if x1 - 2 >= 0 else x1
x2 = x2 + 2 if x2 + 2 <= inst_map.shape[1] - 1 else x2
y2 = y2 + 2 if y2 + 2 <= inst_map.shape[0] - 1 else y2
inst_map_crop = inst_map_mask[y1:y2, x1:x2]
contours_crop = cv2.findContours(
inst_map_crop, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE
)
# only has 1 instance per map, no need to check #contour detected by opencv
#print(contours_crop)
contours_crop = np.squeeze(
contours_crop[0][0].astype("int32")
) # * opencv protocol format may break
if len(contours_crop.shape) == 1:
contours_crop = contours_crop.reshape(1,-1)
#print(contours_crop.shape)
contours_crop += np.asarray([[x1, y1]]) # index correction
if type_map is not None:
type_map_crop = type_map[y1:y2, x1:x2]
type_id = np.unique(type_map_crop).max() # non-zero
inst_colour = type_colour[type_id]
else:
inst_colour = (inst_rng_colors[inst_idx]).tolist()
cv2.drawContours(overlay, [contours_crop], -1, inst_colour, line_thickness)
return overlay
# In[ ]: