import gradio as gr import torch from torchvision import transforms from PIL import Image import torch.nn as nn # ========================== # Konfigurace modelu # ========================== model_path = "models/frUn_OR_13k0050_512.pth" # Model bude nahrán do složky "models" na Hugging Face target_width = 1500 # ========================== # Definice U-Net modelu # ========================== class UNet(nn.Module): def __init__(self, n_channels=3, n_classes=3, bilinear=True): super(UNet, self).__init__() self.n_channels = n_channels self.n_classes = n_classes self.bilinear = bilinear self.inc = double_conv(n_channels, 64) self.down1 = nn.Sequential( nn.MaxPool2d(2), double_conv(64, 128) ) self.down2 = nn.Sequential( nn.MaxPool2d(2), double_conv(128, 256) ) self.down3 = nn.Sequential( nn.MaxPool2d(2), double_conv(256, 512) ) self.down4 = nn.Sequential( nn.MaxPool2d(2), double_conv(512, 512) ) self.up1 = Up(512 + 512, 256, bilinear) self.up2 = Up(256 + 256, 128, bilinear) self.up3 = Up(128 + 128, 64, bilinear) self.up4 = Up(64 + 64, 64, bilinear) self.outc = nn.Conv2d(64, n_classes, kernel_size=1) self.final_activation = nn.Sigmoid() def forward(self, x): x1 = self.inc(x) x2 = self.down1(x1) x3 = self.down2(x2) x4 = self.down3(x3) x5 = self.down4(x4) x = self.up1(x5, x4) x = self.up2(x, x3) x = self.up3(x, x2) x = self.up4(x, x1) x = self.outc(x) x = self.final_activation(x) return x def double_conv(in_channels, out_channels): return nn.Sequential( nn.Conv2d(in_channels, out_channels, kernel_size=3, padding=1), nn.BatchNorm2d(out_channels), nn.ReLU(inplace=True), nn.Conv2d(out_channels, out_channels, kernel_size=3, padding=1), nn.BatchNorm2d(out_channels), nn.ReLU(inplace=True), ) class Up(nn.Module): def __init__(self, in_channels, out_channels, bilinear=True): super(Up, self).__init__() if bilinear: self.up = nn.Upsample(scale_factor=2, mode='bilinear', align_corners=True) self.conv = double_conv(in_channels, out_channels) else: self.up = nn.ConvTranspose2d(in_channels // 2, in_channels // 2, kernel_size=2, stride=2) self.conv = double_conv(in_channels, out_channels) def forward(self, x1, x2): x1 = self.up(x1) diffY = x2.size()[2] - x1.size()[2] diffX = x2.size()[3] - x1.size()[3] x1 = nn.functional.pad(x1, [diffX // 2, diffX - diffX // 2, diffY // 2, diffY - diffY // 2]) x = torch.cat([x2, x1], dim=1) return self.conv(x) # ========================== # Načtení modelu # ========================== device = torch.device("cpu") # Vždy používáme CPU model = UNet(n_channels=3, n_classes=3, bilinear=True).to(device) model.load_state_dict(torch.load(model_path, map_location=device), strict=False) model.eval() # ========================== # Pomocná funkce pro změnu velikosti s zachováním poměru stran # ========================== def resize_keeping_aspect_ratio(image, target_width): aspect_ratio = image.height / image.width target_height = int(target_width * aspect_ratio) return image.resize((target_width, target_height), Image.LANCZOS) # ========================== # Funkce pro převod obrázku modelem # ========================== def generate_sketch(input_image): # Změna velikosti na požadovanou šířku resized_image = resize_keeping_aspect_ratio(input_image, target_width=target_width) # Převod obrázku na tensor transform = transforms.ToTensor() image_tensor = transform(resized_image).unsqueeze(0).to(device) # Provedení převodu modelem with torch.no_grad(): output = model(image_tensor).squeeze(0).cpu() # Převod výsledného tensoru zpět na PIL Image output_image = transforms.ToPILImage()(output) return output_image # ========================== # Rozhraní Gradio # ========================== interface = gr.Interface( fn=generate_sketch, inputs=gr.Image(type="pil", label="Vstupní obrázek"), outputs=gr.Image(type="pil", format="jpeg"), title="U-Net Image2draw", description="" ) interface.launch()