LotLingoBGR / app.py
NewbloomAI's picture
Update app.py
d0faf07 verified
import os
import cv2
import numpy as np
import torch
import gradio as gr
import spaces
from typing import Tuple
from PIL import Image
from torchvision import transforms
import requests
from io import BytesIO
import zipfile
# Fix the HF space permission error
os.environ["HF_MODULES_CACHE"] = os.path.join("/tmp/hf_cache", "modules")
import transformers
transformers.utils.move_cache()
torch.set_float32_matmul_precision('high')
torch.jit.script = lambda f: f
device = "cuda" if torch.cuda.is_available() else "cpu"
def refine_foreground(image, mask, r=90):
if mask.size != image.size:
mask = mask.resize(image.size)
image = np.array(image) / 255.0
mask = np.array(mask) / 255.0
estimated_foreground = FB_blur_fusion_foreground_estimator_2(image, mask, r=r)
image_masked = Image.fromarray((estimated_foreground * 255.0).astype(np.uint8))
return image_masked
def FB_blur_fusion_foreground_estimator_2(image, alpha, r=90):
alpha = alpha[:, :, None]
F, blur_B = FB_blur_fusion_foreground_estimator(image, image, image, alpha, r)
return FB_blur_fusion_foreground_estimator(image, F, blur_B, alpha, r=6)[0]
def FB_blur_fusion_foreground_estimator(image, F, B, alpha, r=90):
if isinstance(image, Image.Image):
image = np.array(image) / 255.0
blurred_alpha = cv2.blur(alpha, (r, r))[:, :, None]
blurred_FA = cv2.blur(F * alpha, (r, r))
blurred_F = blurred_FA / (blurred_alpha + 1e-5)
blurred_B1A = cv2.blur(B * (1 - alpha), (r, r))
blurred_B = blurred_B1A / ((1 - blurred_alpha) + 1e-5)
F = blurred_F + alpha * (image - alpha * blurred_F - (1 - alpha) * blurred_B)
F = np.clip(F, 0, 1)
return F, blurred_B
class ImagePreprocessor():
def __init__(self, resolution: Tuple[int, int] = (1024, 1024)) -> None:
self.transform_image = transforms.Compose([
transforms.Resize(resolution[::-1]),
transforms.ToTensor(),
transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225]),
])
def proc(self, image: Image.Image) -> torch.Tensor:
return self.transform_image(image)
# Fixed weights
weights_file = 'BiRefNet'
birefnet = transformers.AutoModelForImageSegmentation.from_pretrained(
'/'.join(('zhengpeng7', weights_file)), trust_remote_code=True
)
birefnet.to(device)
birefnet.eval(); birefnet.half()
@spaces.GPU
def predict(images, resolution):
assert images is not None, 'AssertionError: images cannot be None.'
_weights_file = '/'.join(('zhengpeng7', weights_file))
print('Using weights: {}.'.format(_weights_file))
try:
resolution = [int(int(reso)//32*32) for reso in resolution.strip().split('x')]
except:
resolution = (1024, 1024)
print('Invalid resolution input. Automatically changed to 1024x1024.')
if isinstance(images, list):
save_paths = []
save_dir = 'preds-BiRefNet'
if not os.path.exists(save_dir):
os.makedirs(save_dir)
tab_is_batch = True
else:
images = [images]
tab_is_batch = False
for idx_image, image_src in enumerate(images):
if isinstance(image_src, str):
if os.path.isfile(image_src):
image_ori = Image.open(image_src)
else:
response = requests.get(image_src)
image_data = BytesIO(response.content)
image_ori = Image.open(image_data)
else:
image_ori = Image.fromarray(image_src)
image = image_ori.convert('RGB')
if resolution is None:
resolution_div_by_32 = [int(int(reso)//32*32) for reso in image.size]
resolution = resolution_div_by_32
image_preprocessor = ImagePreprocessor(resolution=tuple(resolution))
image_proc = image_preprocessor.proc(image).unsqueeze(0)
with torch.no_grad():
preds = birefnet(image_proc.to(device).half())[-1].sigmoid().cpu()
pred = preds[0].squeeze()
pred_pil = transforms.ToPILImage()(pred)
image_masked = refine_foreground(image, pred_pil)
image_masked.putalpha(pred_pil.resize(image.size))
torch.cuda.empty_cache()
if tab_is_batch:
save_file_path = os.path.join(save_dir, "{}.png".format(os.path.splitext(os.path.basename(image_src))[0]))
image_masked.save(save_file_path)
save_paths.append(save_file_path)
if tab_is_batch:
zip_file_path = os.path.join(save_dir, "{}.zip".format(save_dir))
with zipfile.ZipFile(zip_file_path, 'w') as zipf:
for file in save_paths:
zipf.write(file, os.path.basename(file))
return save_paths, zip_file_path
else:
return image_masked, image_ori
descriptions = (
"Upload a picture, and we'll remove the background!\n"
"The resolution used is `1024x1024`\n"
)
tab_image = gr.Interface(
fn=predict,
inputs=[
gr.Image(label='Upload an image'),
gr.Textbox(lines=1, placeholder="Type the resolution (`WxH`) you want, e.g., `1024x1024`.", label="Resolution"),
],
outputs=gr.ImageSlider(label="Lot Lingo's prediction", type="pil", format='png'),
api_name="image",
description=descriptions,
)
tab_text = gr.Interface(
fn=predict,
inputs=[
gr.Textbox(label="Paste an image URL"),
gr.Textbox(lines=1, placeholder="Type the resolution (`WxH`) you want, e.g., `1024x1024`.", label="Resolution"),
],
outputs=gr.ImageSlider(label="Lot Lingo's prediction", type="pil", format='png'),
api_name="URL",
)
tab_batch = gr.Interface(
fn=predict,
inputs=[
gr.File(label="Upload multiple images", type="filepath", file_count="multiple"),
gr.Textbox(lines=1, placeholder="Type the resolution (`WxH`) you want, e.g., `1024x1024`.", label="Resolution"),
],
outputs=[gr.Gallery(label="Lot Lingo's predictions"), gr.File(label="Download masked images.")],
api_name="batch",
)
demo = gr.TabbedInterface(
[tab_image, tab_text, tab_batch],
['image', 'URL', 'batch'],
title="Lot Lingo Background Removal Demo",
)
if __name__ == "__main__":
demo.launch(debug=True)