remob / app.py
andevs's picture
Create app.py
b68539c verified
Raw
History Blame Contribute Delete
5.22 kB
import gradio as gr
import numpy as np
from PIL import Image, ImageDraw
import cv2
import torch
import warnings
warnings.filterwarnings('ignore')
class ObjectRemover:
"""Remove objects from images using inpainting"""
def __init__(self):
self.methods = {
'simple': self.simple_remove,
'inpaint': self.inpaint_remove,
'clone': self.clone_remove
}
def simple_remove(self, image: np.ndarray, mask: np.ndarray) -> np.ndarray:
"""Simple removal by filling with average color"""
result = image.copy()
# Get average color from surrounding area
kernel = np.ones((5, 5), np.uint8)
dilated_mask = cv2.dilate(mask, kernel, iterations=2)
# Find border pixels
border = dilated_mask - mask
# Get average border color
border_pixels = image[border > 0]
if len(border_pixels) > 0:
avg_color = np.mean(border_pixels, axis=0)
# Fill masked area with average color
result[mask > 0] = avg_color.astype(np.uint8)
return result
def inpaint_remove(self, image: np.ndarray, mask: np.ndarray) -> np.ndarray:
"""Use OpenCV inpainting"""
# Convert to BGR for OpenCV
if len(image.shape) == 3 and image.shape[2] == 3:
bgr_image = cv2.cvtColor(image, cv2.COLOR_RGB2BGR)
else:
bgr_image = cv2.cvtColor(image, cv2.COLOR_RGBA2BGRA)
# Inpaint using Navier-Stokes method
result = cv2.inpaint(
bgr_image,
mask,
inpaintRadius=3,
flags=cv2.INPAINT_TELEA
)
# Convert back to RGB
if len(result.shape) == 3 and result.shape[2] == 3:
return cv2.cvtColor(result, cv2.COLOR_BGR2RGB)
else:
return cv2.cvtColor(result, cv2.COLOR_BGRA2RGBA)
def clone_remove(self, image: np.ndarray, mask: np.ndarray) -> np.ndarray:
"""Use OpenCV seamless cloning"""
# Create a source patch from nearby area
height, width = image.shape[:2]
# Find a nearby clean patch
kernel = np.ones((11, 11), np.uint8)
dilated_mask = cv2.dilate(mask, kernel, iterations=3)
# Find non-masked areas
non_masked = 255 - dilated_mask
# Find contours of non-masked areas
contours, _ = cv2.findContours(non_masked, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
if contours:
# Get largest contour
largest_contour = max(contours, key=cv2.contourArea)
x, y, w, h = cv2.boundingRect(largest_contour)
# Use this area as source
source_patch = image[y:y+h, x:x+w]
# Resize source to match mask size
mask_height, mask_width = np.where(mask > 0)
if len(mask_height) > 0 and len(mask_width) > 0:
min_y, max_y = mask_height.min(), mask_height.max()
min_x, max_x = mask_width.min(), mask_width.max()
patch_height = max_y - min_y + 1
patch_width = max_x - min_x + 1
if patch_height > 0 and patch_width > 0:
source_resized = cv2.resize(source_patch, (patch_width, patch_height))
# Place resized patch
result = image.copy()
result[min_y:max_y+1, min_x:max_x+1] = source_resized
return result
return self.simple_remove(image, mask)
def remove_object(self, image: np.ndarray, mask: np.ndarray, method: str = 'inpaint') -> np.ndarray:
"""Remove object using specified method"""
if method in self.methods:
return self.methods[method](image, mask)
return self.inpaint_remove(image, mask)
# Initialize remover
remover = ObjectRemover()
def process_object_removal(
image: np.ndarray,
brush_size: int,
method: str
) -> Tuple[np.ndarray, np.ndarray, np.ndarray]:
"""Process image with object removal"""
try:
# Initialize mask (all zeros)
mask = np.zeros(image.shape[:2], dtype=np.uint8)
# For demo purposes, create a sample mask (remove center)
height, width = image.shape[:2]
# Create a circle mask in center (for demonstration)
center_x, center_y = width // 2, height // 2
radius = min(width, height) // 4
# Draw circle on mask
cv2.circle(mask, (center_x, center_y), radius, 255, -1)
# Apply removal
result = remover.remove_object(image, mask, method)
# Create visualization
visualization = image.copy()
visualization[mask > 0] = [255, 0, 0] # Highlight area to remove in red
# Create mask visualization
mask_viz = cv2.cvtColor(mask, cv2.COLOR_GRAY2RGB)
return result, visualization, mask_viz
except Exception as e:
print(f"Error: {e}")
return image, image, np.zeros_like(image)