panoptic-image-segmentation-gradio / segmentation_utils.py
Manu
fixed bug in segmentation_utils.py
ce469f2
raw
history blame
14.3 kB
import requests
from pycocotools import mask
import matplotlib.pyplot as plt
from PIL import Image, ImageDraw, ImageOps, ImageFont
import os
import base64
import io
import random
import numpy as np
import cv2
from image_utils import print_text_on_image_centered, create_background_image
from icecream import ic
import traceback
from pprint import pprint
# Función para transformar la entrada en un array de numpy
# Si la entrada es una URL, descarga la imagen y la convierte en un array de numpy
# Si la entrada es una ruta de archivo, carga la imagen y la convierte en un array de numpy
# Si la entrada ya es un array de numpy, devuélvela tal cual
# Si la entrada no es ninguna de las anteriores, lanza un ValueError
def transform_image_to_numpy_array(input):
if isinstance(input, np.ndarray):
# Si la entrada es un array de numpy, devuélvela tal cual
h, w = input.shape[:2]
new_height = int(h * (500 / w))
return cv2.resize(input, (500, new_height))
elif isinstance(input, str):
# Si la entrada es una cadena, podría ser una URL o una ruta de archivo
if input.startswith('http://') or input.startswith('https://'):
# Si la entrada es una URL, descarga la imagen y conviértela en un array de numpy
# se necesita un header para evitar el error 403
headers = {"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.114 Safari/537.36"}
response = requests.get(input, headers=headers)
ic(response.status_code)
image_array = np.frombuffer(response.content, dtype=np.uint8)
image = cv2.imdecode(image_array, -1)
# Si la imagen tiene 3 canales (es decir, es una imagen en color),
# convertirla de BGR a RGB
if image.ndim == 3:
image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
image = Image.fromarray(image).convert("RGBA")
image = np.array(image)
else:
# Si la entrada es una ruta de archivo, carga la imagen y conviértela en un array de numpy
image = cv2.imread(input)
h, w = image.shape[:2]
new_height = int(h * (500 / w))
return cv2.resize(image, (500, new_height))
else:
raise ValueError("La entrada no es un array de numpy, una URL ni una ruta de archivo.")
def transform_image_to_numpy_array2(input):
if isinstance(input, np.ndarray):
# Si la entrada es un array de numpy, devuélvela tal cual
return cv2.resize(input, (500, 500))
elif isinstance(input, str):
# Si la entrada es una cadena, podría ser una URL o una ruta de archivo
if input.startswith('http://') or input.startswith('https://'):
# Si la entrada es una URL, descarga la imagen y conviértela en un array de numpy
# se necesita un header para evitar el error 403
headers = {"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.114 Safari/537.36"}
response = requests.get(input, headers=headers)
ic(response.status_code)
image_array = np.frombuffer(response.content, dtype=np.uint8)
image = cv2.imdecode(image_array, -1)
# Si la imagen tiene 3 canales (es decir, es una imagen en color),
# convertirla de BGR a RGB
if image.ndim == 3:
image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
image = Image.fromarray(image).convert("RGBA")
image = np.array(image)
else:
# Si la entrada es una ruta de archivo, carga la imagen y conviértela en un array de numpy
image = cv2.imread(input)
return cv2.resize(image, (500, 500))
else:
raise ValueError("La entrada no es un array de numpy, una URL ni una ruta de archivo.")
def segment_image_from_numpy(image_array, api_token, model):
#API_URL = "https://api-inference.huggingface.co/models/facebook/mask2former-swin-tiny-coco-panoptic"
API_URL = f"https://api-inference.huggingface.co/models/{model}"
headers = {"Authorization": f"Bearer {api_token}"}
ic(API_URL)
ic(headers)
# Convert the image to bytes
is_success, im_buf_arr = cv2.imencode(".jpg", image_array)
data = im_buf_arr.tobytes()
response = requests.post(API_URL, headers=headers, data=data)
pprint(response.json())
return response.json()
def segment_image_from_path(image_path):
with open(image_path, "rb") as f:
data = f.read()
response = requests.post(API_URL, headers=headers, data=data)
return response.json()
def segment_image_from_image(image):
# Convert the image to bytes
is_success, im_buf_arr = cv2.imencode(".jpg", image)
data = im_buf_arr.tobytes()
response = requests.post(API_URL, headers=headers, data=data)
return response.json()
def decode_mask(mask_str, size):
mask_data = base64.b64decode(mask_str)
mask_image = Image.open(io.BytesIO(mask_data))
mask_image = mask_image.resize(size).convert("L")
return mask_image
def overlay_masks_on_image(image, segments, transparency=0.4):
if isinstance(image, np.ndarray):
image = Image.fromarray(image)
original_image = image
if original_image.mode != 'RGBA':
original_image = original_image.convert('RGBA')
overlay = Image.new("RGBA", original_image.size, (255, 255, 255, 0))
text_layer = Image.new("RGBA", original_image.size, (255, 255, 255, 0))
for segment in segments:
mask_str = segment['mask']
mask_image = decode_mask(mask_str, original_image.size)
color = generate_random_color()
color_mask = ImageOps.colorize(mask_image, black="black", white=color)
color_mask.putalpha(mask_image)
overlay = Image.alpha_composite(overlay, color_mask)
# Calcula el centroide de la mascara
x, y = np.where(np.array(mask_image) > 0)
centroid_x = x.mean()
centroid_y = y.mean()
# Imprime la etiqueta y la puntuación en la capa de texto
font_size = 30
draw = ImageDraw.Draw(text_layer)
font = ImageFont.load_default().font_variant(size=font_size)
label = segment['label']
score = segment['score']
text =f"{label}: {score}"
# Calcula el tamaño del texto
text_bbox = draw.textbbox((0, 0), text, font=font)
text_width = text_bbox[2] - text_bbox[0]
text_height = text_bbox[3] - text_bbox[1]
# Asegúrate de que las coordenadas del texto están dentro de los límites de la imagen
text_x = max(0, min(centroid_x - text_width / 2, original_image.size[0] - text_width))
text_y = max(0, min(centroid_y - text_height / 2, original_image.size[1] - text_height))
draw.text((text_x, text_y), text, fill=(255, 255, 255, 255), font=font)
# Ajusta la transparencia de la capa de superposición
overlay = Image.blend(original_image, overlay, transparency)
# Combina la capa de superposición con la capa de texto
final_image = Image.alpha_composite(overlay, text_layer)
return final_image
def overlay_masks_on_image2(image, segments, transparency=0.4):
# Convert numpy array to PIL Image
#original_image = Image.fromarray(image).convert("RGBA")
#original_image = image
#original_image = Image.open(image).convert("RGBA")
# para file es str
# para url es numpy.ndarray
# para cv.imread es numpy.ndarray
# Convertir el array de numpy a una imagen PIL si es necesario
if isinstance(image, np.ndarray):
image = Image.fromarray(image)
print(type(image))
print(image)
original_image = image
if original_image.mode != 'RGBA':
original_image = original_image.convert('RGBA')
print(original_image.size)
overlay = Image.new("RGBA", original_image.size, (255, 255, 255, 0))
print(overlay.size)
# Nueva capa para el texto
text_layer = Image.new("RGBA", original_image.size, (255, 255, 255, 0))
for segment in segments:
print(segment['label'] + " " + str(segment['score']))
mask_str = segment['mask']
mask_image = decode_mask(mask_str, original_image.size)
# Convierte la imagen de la máscara a un array de numpy
mask_array = np.array(mask_image)
# Encuentra los píxeles blancos
y, x = np.where(mask_array > 0)
# Calcula el cuadro delimitador de los píxeles blancos
x_min, y_min, width, height = cv2.boundingRect(np.array(list(zip(x, y))))
# Crea un objeto ImageDraw para dibujar en la imagen original
draw = ImageDraw.Draw(original_image)
# Dibuja el cuadro delimitador en la imagen original
draw.rectangle([(x_min, y_min), (x_min + width, y_min + height)], outline=(0, 255, 0), width=2)
color = generate_random_color()
color_mask = ImageOps.colorize(mask_image, black="black", white=color)
color_mask.putalpha(mask_image)
overlay = Image.alpha_composite(overlay, color_mask)
# Calcula el centroide de la mascara
x, y = np.where(np.array(mask_image) > 0)
centroid_x = x.mean()
centroid_y = y.mean()
# Imprime la etiqueta y la puntuación en la capa de texto
font_size = 30
draw = ImageDraw.Draw(text_layer)
font_path = "/System/Library/Fonts/Arial.ttf" # Path to Arial font on macOS
font = ImageFont.truetype(font_path, font_size)
label = segment['label']
score = segment['score']
text =f"{label}: {score}"
# Estima el tamaño del texto hard rockandroll way
text_width = 500
text_height = 100
# Asegúrate de que las coordenadas del texto están dentro de los límites de la imagen
text_x = max(0, min(centroid_x - text_width / 2, original_image.size[0] - text_width))
text_y = max(0, min(centroid_y - text_height / 2, original_image.size[1] - text_height))
# Asegúrate de que las coordenadas del texto están dentro de los límites de la imagen
text_x = max(0, min(centroid_x, original_image.size[0] - text_width))
text_y = max(0, min(centroid_y, original_image.size[1] - text_height))
# Calcula las coordenadas del texto
text_x = centroid_x - text_width / 2
text_y = centroid_y - text_height / 2
# Asegúrate de que las coordenadas del texto están dentro de los límites de la imagen
text_x = max(0, min(text_x, original_image.size[0] - text_width))
text_y = max(0, min(text_y, original_image.size[1] - text_height))
draw.text((centroid_x - text_width / 2, centroid_y - text_height / 2), text, fill=(255, 255, 255, 255), font=font)
#draw.text((text_x, text_y), text, fill=(255, 255, 255, 255), font=font)
# Ajusta la transparencia de la capa de superposición
print(original_image.size)
print(overlay.size)
overlay = Image.blend(original_image, overlay, transparency)
# Combina la capa de superposición con la capa de texto
final_image = Image.alpha_composite(overlay, text_layer)
#final_image = print_text_on_image_centered(final_image, 'SEGMENTING OK', 'green')
return final_image
def generate_random_color():
return (random.randint(0, 255), random.randint(0, 255), random.randint(0, 255))
def segment_and_overlay_results(image_path, api_token, model):
#segments = segment_image_from_image(image)
#final_image = overlay_masks_on_image(image, segments)
#return final_image
processed_image = None # Initialize processed_image
segments = []
#image_type = None
#if isinstance(image_path, str):
# image_type = 'FILE'
# image = cv2.imread('cats.jpg')
#elif isinstance(image_path, np.ndarray):
# image_type = 'NUMPY ARRAY'
#else:
# raise ValueError("The image is neither a Image nor a local file.")
#ic(image_type)
image = transform_image_to_numpy_array(image_path)
# imprime tres primeros pixeles
print(type(image))
ic(image[0, 0:3])
try:
#segments = segment_image_from_image(image)
#processed_image = overlay_masks_on_image(image, segments)
# debug image contents
#if os.path.isfile(image):
# ic ("--- image is a file ---")
# image = Image.open(image)
# if image is None:
# ic("image is None")
# return None, []
ic("--- calling segment_image_from_path ---")
segments = segment_image_from_numpy(image, api_token, model)
#if image_type == 'FILE':
# segments = segment_image_from_path(image_path)
#if image_type == 'NUMPY ARRAY':
# segments = segment_image_from_image(image_path)
ic("--- printing segments ---")
for segment in segments:
ic(segment['label'] ,segment['score'])
processed_image = print_text_on_image_centered(
create_background_image(500, 500, "white"),
'SEGMENTING OK',
'green'
)
ic("--- calling overlay_masks_on_image ---")
processed_image = overlay_masks_on_image(image, segments)
return processed_image, segments
except Exception as e:
print("EXCEPTION")
ic(e)
print(traceback.format_exc())
processed_image = print_text_on_image_centered(
create_background_image(500, 500, "white"),
e,
'green'
)
segments = []
return processed_image, segments
#finally:
#return processed_image, segments