Spaces:
Running
Running
s-egg-mentation
/
deployments
/deployment
/Instance segmentation task
/python
/demo_package
/visualizers
/vis_utils.py
# Copyright (C) 2024 Intel Corporation | |
# SPDX-License-Identifier: Apache-2.0 | |
# | |
"""This module implements activation map.""" | |
from __future__ import annotations | |
import colorsys | |
import random | |
from pathlib import Path | |
import cv2 | |
import numpy as np | |
def get_actmap( | |
saliency_map: np.ndarray, | |
output_res: tuple | list, | |
) -> np.ndarray: | |
"""Get activation map (heatmap) from saliency map. | |
It will return activation map from saliency map | |
Args: | |
saliency_map (np.ndarray): Saliency map with pixel values from 0-255 | |
output_res (Union[tuple, list]): Output resolution | |
Returns: | |
saliency_map (np.ndarray): [H, W, 3] colormap, more red means more salient | |
""" | |
if len(saliency_map.shape) == 3: | |
saliency_map = saliency_map[0] | |
saliency_map = cv2.resize(saliency_map, output_res) | |
return cv2.applyColorMap(saliency_map, cv2.COLORMAP_JET) | |
def get_input_names_list(input_path: str | int, capture: cv2.VideoCapture) -> list[str]: | |
"""Lists the filenames of all inputs for demo.""" | |
# Web camera input | |
if isinstance(input_path, int): | |
return [] | |
if "DIR" in str(capture.get_type()): | |
return [f.name for f in Path(input_path).iterdir() if f.is_file()] | |
return [Path(input_path).name] | |
def dump_frames(saved_frames: list, output: str, input_path: str | int, capture: cv2.VideoCapture) -> None: | |
"""Saves images/videos with predictions from saved_frames to output folder with proper names.""" | |
# If no frames are saved, return | |
if not saved_frames: | |
return | |
# Create the output folder if it doesn't exist | |
output_path = Path(output) | |
if not output_path.exists(): | |
output_path.mkdir(parents=True) | |
# Get the list of input names | |
filenames = get_input_names_list(input_path, capture) | |
# If the input is a video, save it as video | |
if "VIDEO" in str(capture.get_type()): | |
filename = filenames[0] | |
w, h, _ = saved_frames[0].shape | |
video_path = str(output_path / filename) | |
codec = cv2.VideoWriter_fourcc(*"mp4v") | |
out = cv2.VideoWriter(video_path, codec, capture.fps(), (h, w)) | |
for frame in saved_frames: | |
out.write(frame) | |
out.release() | |
print(f"Video was saved to {video_path}") | |
# If the input is not a video, save each frame as an image | |
else: | |
if len(filenames) != len(saved_frames): | |
filenames = [f"output_{i}.jpeg" for i, _ in enumerate(saved_frames)] | |
for filename, frame in zip(filenames, saved_frames): | |
image_path = str(output_path / filename) | |
cv2.cvtColor(frame, cv2.COLOR_RGB2BGR) | |
cv2.imwrite(image_path, frame) | |
print(f"Image was saved to {image_path}") | |
class ColorPalette: | |
"""Represents a palette of colors.""" | |
def __init__(self, num_classes: int, rng: random.Random | None = None) -> None: | |
"""Initialize the ColorPalette. | |
Args: | |
- num_classes (int): The number of classes. | |
- rng (Optional[random.Random]): The random number generator. | |
Returns: | |
None | |
""" | |
if num_classes <= 0: | |
msg = "ColorPalette accepts only the positive number of colors" | |
raise ValueError(msg) | |
if rng is None: | |
rng = random.Random(0xACE) # nosec B311 # disable random check | |
candidates_num = 100 | |
hsv_colors = [(1.0, 1.0, 1.0)] | |
for _ in range(1, num_classes): | |
colors_candidates = [ | |
(rng.random(), rng.uniform(0.8, 1.0), rng.uniform(0.5, 1.0)) for _ in range(candidates_num) | |
] | |
min_distances = [self._min_distance(hsv_colors, c) for c in colors_candidates] | |
arg_max = np.argmax(min_distances) | |
hsv_colors.append(colors_candidates[arg_max]) | |
self.palette = [self.hsv2rgb(*hsv) for hsv in hsv_colors] | |
def _dist(c1: tuple[float, float, float], c2: tuple[float, float, float]) -> float: | |
"""Calculate the distance between two colors in 3D space. | |
Args: | |
- c1 (Tuple[float, float, float]): Tuple representing the first RGB color. | |
- c2 (Tuple[float, float, float]): Tuple representing the second RGB color. | |
Returns: | |
float: The distance between the two colors. | |
""" | |
dh = min(abs(c1[0] - c2[0]), 1 - abs(c1[0] - c2[0])) * 2 | |
ds = abs(c1[1] - c2[1]) | |
dv = abs(c1[2] - c2[2]) | |
return dh * dh + ds * ds + dv * dv | |
def _min_distance( | |
cls, | |
colors_set: list[tuple[float, float, float]], | |
color_candidate: tuple[float, float, float], | |
) -> float: | |
"""Calculate the minimum distance between color_candidate and colors_set. | |
Args: | |
- colors_set: List of tuples representing RGB colors. | |
- color_candidate: Tuple representing an RGB color. | |
Returns: | |
- float: The minimum distance between color_candidate and colors_set. | |
""" | |
distances = [cls._dist(o, color_candidate) for o in colors_set] | |
return min(distances) | |
def to_numpy_array(self) -> np.ndarray: | |
"""Convert the palette to a NumPy array. | |
Returns: | |
np.ndarray: The palette as a NumPy array. | |
""" | |
return np.array(self.palette) | |
def hsv2rgb(h: float, s: float, v: float) -> tuple[int, int, int]: | |
"""Convert HSV color to RGB color. | |
Args: | |
- h (float): Hue. | |
- s (float): Saturation. | |
- v (float): Value. | |
Returns: | |
Tuple[int, int, int]: RGB color. | |
""" | |
r, g, b = colorsys.hsv_to_rgb(h, s, v) | |
return int(r * 255), int(g * 255), int(b * 255) | |
def __getitem__(self, n: int) -> tuple[int, int, int]: | |
"""Get the color at index n. | |
Args: | |
- n (int): Index. | |
Returns: | |
Tuple[int, int, int]: RGB color. | |
""" | |
return self.palette[n % len(self.palette)] | |
def __len__(self) -> int: | |
"""Returns the number of colors in the palette. | |
Returns: | |
int: The number of colors in the palette. | |
""" | |
return len(self.palette) | |