Gray2Color / app.py
Jason Zhang
Added examples and fixed no attribute error
0e02fbd
Raw
History Blame Contribute Delete
5.07 kB
# import gradio as gr
import os
import glob
import time
import numpy as np
from PIL import Image
from skimage import io, color
import torch
import torch.nn.functional as F
from torch import nn, optim
from torchvision import transforms
import segmentation_models_pytorch as smp
import gradio as gr
ENCODER = 'resnet18'
ENCODER_WEIGHTS = 'imagenet'
ACTIVATION = 'tanh'
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
ResUNet = smp.Unet(
encoder_name=ENCODER,
encoder_weights=ENCODER_WEIGHTS,
in_channels=1,
classes=2,
activation=ACTIVATION,
)
class Discriminator(nn.Module):
def __init__(self, in_channels):
super(Discriminator, self).__init__()
self.conv1 = nn.Sequential(
nn.Conv2d(in_channels, 64, kernel_size=4, stride=2, padding=1),
nn.LeakyReLU(0.2, inplace=True)
)
self.conv2 = nn.Sequential(
nn.Conv2d(64, 128, kernel_size=4, stride=2, padding=1, bias=False),
nn.BatchNorm2d(128),
nn.LeakyReLU(0.2, inplace=True)
)
self.conv3 = nn.Sequential(
nn.Conv2d(128, 256, kernel_size=4, stride=2, padding=1, bias=False),
nn.BatchNorm2d(256),
nn.LeakyReLU(0.2, inplace=True)
)
self.conv4 = nn.Sequential(
nn.Conv2d(256, 512, kernel_size=4, stride=1, padding=1, bias=False),
nn.BatchNorm2d(512),
nn.LeakyReLU(0.2, inplace=True)
)
self.conv5 = nn.Conv2d(512, 1, kernel_size=4, stride=1, padding=1)
def forward(self, x):
x = self.conv1(x)
x = self.conv2(x)
x = self.conv3(x)
x = self.conv4(x)
x = self.conv5(x)
return x
def init_weights(net, init_gain=0.02):
def init(m):
if isinstance(m, (nn.Conv2d, nn.ConvTranspose2d)):
nn.init.normal_(m.weight.data, 0.0, init_gain)
if m.bias is not None:
nn.init.constant_(m.bias.data, 0.0)
elif isinstance(m, (nn.BatchNorm2d)):
nn.init.constant_(m.weight, 1)
nn.init.constant_(m.bias, 0)
net.apply(init)
return net
class GAN(nn.Module):
def __init__(self, in_channels, out_channels, generator=None):
super(GAN, self).__init__()
self.generator = generator if generator else init_weights(ResUNet(in_channels, out_channels))
self.generator.to(device)
self.discriminator = init_weights(Discriminator(in_channels=3).to(device))
self.GANLoss = nn.BCEWithLogitsLoss()
self.L1Loss = nn.L1Loss()
self.gen_optim = optim.Adam(self.generator.parameters(), lr=3e-5, betas=(0.5, 0.99))
self.disc_optim = optim.Adam(self.discriminator.parameters(), lr=3e-5, betas=(0.5, 0.99))
def forward(self, L, ab, train):
self.L = L
self.ab = ab
# Generate fake images
self.fake_ab = self.generator(L)
fake_img = torch.cat((self.L, self.fake_ab), dim=1)
disc_fake = self.discriminator(fake_img.detach())
disc_real = self.discriminator(torch.cat((self.L, self.ab), dim=1))
self.disc_loss = (self.GANLoss(disc_real, torch.ones_like(disc_real)) + self.GANLoss(disc_fake, torch.zeros_like(disc_fake)))/2
if train:
self.disc_optim.zero_grad()
self.disc_loss.backward()
self.disc_optim.step()
# Train generator
disc_fake = self.discriminator(fake_img)
gan_loss = self.GANLoss(disc_fake, torch.ones_like(disc_fake))
L1_loss = self.L1Loss(self.fake_ab, self.ab) * 100
self.gen_loss = gan_loss + L1_loss
if train:
self.gen_optim.zero_grad()
self.gen_loss.backward()
self.gen_optim.step()
return self.gen_loss.item(), self.disc_loss.item()
gan = GAN(in_channels=1, out_channels=2, generator=ResUNet).to(device)
gan.load_state_dict(torch.load('gan.pth', map_location=torch.device('cpu'), weights_only=False))
def predict(img):
L = Image.open(img).convert('L')
L = transforms.Resize((256, 256), Image.BICUBIC)(L)
L = transforms.ToTensor()(L)
gan.eval()
with torch.no_grad():
ab = gan.generator(L.unsqueeze(0).to(device))
ab = ab.squeeze(0).cpu()
# Denormalize the L and ab channels
L = L.numpy() * 100 # L is in range [0, 1], scale to [0, 100]
ab = ab.numpy() * 128 # ab is in range [-1, 1], scale to [-128, 128]
# Combine L and ab into a single LAB image
lab_image = np.stack([L[0], ab[0], ab[1]], axis=-1) # Shape: [256, 256, 3]
# Convert LAB to RGB using skimage's color.lab2rgb
rgb_image = color.lab2rgb(lab_image)
rgb_image = (rgb_image * 255).astype(np.uint8)
rgb_image = Image.fromarray(rgb_image)
return rgb_image
image = gr.components.Image(type='filepath')
output = gr.components.Image(type='pil')
demo = gr.Interface(fn=predict, inputs=image, outputs=output, title='Colorize Black and White Images', examples=[['examples/1.jpg'], ['examples/2.jpg']])
demo.launch()