File size: 4,083 Bytes
4c62147
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
import gradio as gr
import torch
from torchvision import models, transforms
from PIL import Image
import numpy as np
import cv2

# Cargar el modelo de segmentación preentrenado
weights = models.segmentation.DeepLabV3_ResNet101_Weights.DEFAULT
model = models.segmentation.deeplabv3_resnet101(weights=weights).eval()

# Transformaciones para la imagen
preprocess = transforms.Compose([
    transforms.ToTensor(),
    transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]),
])

# Cargar la imagen de fondo por defecto
default_background = Image.open("environment1024.jpg").convert("RGB")

def process_images(person_image, background_image=None):
    # Si no se proporciona una imagen de fondo, usar la predeterminada
    if background_image is None:
        background_image = default_background

    # Paso 3: Cargar y preprocesar la imagen de la persona
    input_image = Image.fromarray(person_image).convert("RGB")
    
    # Redimensionar si la persona es más grande que el fondo
    bg_width, bg_height = background_image.size
    input_image.thumbnail((bg_width, bg_height), Image.Resampling.LANCZOS)
    
    input_tensor = preprocess(input_image)
    input_batch = input_tensor.unsqueeze(0)

    # Segmentar la imagen
    with torch.no_grad():
        output = model(input_batch)['out'][0]
    output_predictions = output.argmax(0)

    # Crear una máscara binaria
    mask = (output_predictions == 15).cpu().numpy().astype(np.uint8)  # La clase 15 es para la persona en DeepLabV3

    # Convertir a formato BGR para OpenCV
    background_image_cv = cv2.cvtColor(np.array(background_image), cv2.COLOR_RGB2BGR)

    # Crear un mapa de saliencia simple utilizando detección de bordes
    gray = cv2.cvtColor(background_image_cv, cv2.COLOR_BGR2GRAY)
    edges = cv2.Canny(gray, threshold1=30, threshold2=100)
    saliencyMap = cv2.GaussianBlur(edges, (5, 5), 0)

    # Encontrar los puntos de interés más destacados
    (_, maxVal, _, maxLoc) = cv2.minMaxLoc(saliencyMap)
    print(f"Punto de mayor interés visual: {maxLoc}")

    # Paso 5: Aplicar reglas de composición (regla de los tercios)
    height, width = background_image_cv.shape[:2]
    thirds_x = [width // 3, 2 * width // 3]
    thirds_y = [height // 3, 2 * height // 3]

    # Posiciones sugeridas por la regla de los tercios
    positions = [(thirds_x[0], thirds_y[0]), (thirds_x[1], thirds_y[0]),
                 (thirds_x[0], thirds_y[1]), (thirds_x[1], thirds_y[1])]

    # Paso 6: Integración de la persona en las posiciones sugeridas
    person_array = np.array(input_image) * mask[:, :, np.newaxis]

    # Tamaño de la persona segmentada
    person_height, person_width = person_array.shape[:2]

    best_position = maxLoc  # Utilizando el punto de mayor interés visual para este ejemplo
    x, y = best_position
    x -= person_width // 2
    y -= person_height // 2

    # Asegurarse de que las coordenadas estén dentro de los límites
    x = max(0, min(x, width - person_width))
    y = max(0, min(y, height - person_height))

    # Crear una copia del fondo para la posición seleccionada
    combined_image = background_image_cv.copy()

    # Colocar la persona en la posición calculada
    for i in range(person_height):
        for j in range(person_width):
            if mask[i, j]:
                if 0 <= y+i < height and 0 <= x+j < width:  # Verificar límites
                    combined_image[y+i, x+j] = person_array[i, j]

    # Convertir de nuevo a formato RGB para mostrar con Gradio
    final_image = Image.fromarray(cv2.cvtColor(combined_image, cv2.COLOR_BGR2RGB))

    return final_image

# Crear interfaz de Gradio
iface = gr.Interface(
    fn=process_images,
    inputs=[gr.Image(type="numpy", label="Imagen de la persona")],
    outputs=gr.Image(type="numpy", label="Imagen final"),
    title="Integración de Persona en Entorno",
    description="Sube una imagen de una persona y se integrará en el entorno predeterminado."
)

iface.launch()