Spaces:
Runtime error
Runtime error
File size: 6,397 Bytes
3ea2029 ee14fdf 3ea2029 ec4bc2b ee14fdf ec4bc2b ee14fdf 3ea2029 ee14fdf ec4bc2b ee14fdf ec4bc2b ee14fdf ec4bc2b ee14fdf ec4bc2b ee14fdf ec4bc2b ee14fdf ec4bc2b ee14fdf 3c53cb7 ee14fdf |
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 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 |
import gradio as gr
from PIL import Image, ImageFilter, ImageOps
import cv2
import numpy as np
import os
from collections import defaultdict
from skimage.color import deltaE_ciede2000, rgb2lab
def DoG_filter(image, kernel_size=0, sigma=1.0, k_sigma=2.0, gamma=1.5):
g1 = cv2.GaussianBlur(image, (kernel_size, kernel_size), sigma)
g2 = cv2.GaussianBlur(image, (kernel_size, kernel_size), sigma * k_sigma)
return g1 - gamma * g2
def XDoG_filter(image, kernel_size=0, sigma=1.4, k_sigma=1.6, epsilon=0, phi=10, gamma=0.98):
epsilon /= 255
dog = DoG_filter(image, kernel_size, sigma, k_sigma, gamma)
dog /= dog.max()
e = 1 + np.tanh(phi * (dog - epsilon))
e[e >= 1] = 1
return (e * 255).astype('uint8')
def binarize_image(image):
_, binarized = cv2.threshold(image, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)
return binarized
def process_XDoG(image_path):
kernel_size=0
sigma=1.4
k_sigma=1.6
epsilon=0
phi=10
gamma=0.98
image = cv2.imread(image_path, cv2.IMREAD_GRAYSCALE)
xdog_image = XDoG_filter(image, kernel_size, sigma, k_sigma, epsilon, phi, gamma)
binarized_image = binarize_image(xdog_image)
final_image = Image.fromarray(binarized_image)
return final_image
def replace_color(image, color_1, blur_radius=2):
data = np.array(image)
original_shape = data.shape
data = data.reshape(-1, 4)
color_1 = np.array(color_1)
matches = np.all(data[:, :3] == color_1, axis=1)
nochange_count = 0
mask = np.zeros(data.shape[0], dtype=bool)
while np.any(matches):
new_matches = np.zeros_like(matches)
match_num = np.sum(matches)
for i in tqdm(range(len(data))):
if matches[i]:
x, y = divmod(i, original_shape[1])
neighbors = [
(x, y-1), (x, y+1), (x-1, y), (x+1, y)
]
valid_neighbors = []
for nx, ny in neighbors:
if 0 <= nx < original_shape[0] and 0 <= ny < original_shape[1]:
ni = nx * original_shape[1] + ny
if not np.all(data[ni, :3] == color_1, axis=0):
valid_neighbors.append(data[ni, :3])
if valid_neighbors:
new_color = np.mean(valid_neighbors, axis=0).astype(np.uint8)
data[i, :3] = new_color
data[i, 3] = 255
mask[i] = True
else:
new_matches[i] = True
matches = new_matches
if match_num == np.sum(matches):
nochange_count += 1
if nochange_count > 5:
break
data = data.reshape(original_shape)
mask = mask.reshape(original_shape[:2])
result_image = Image.fromarray(data, 'RGBA')
blurred_image = result_image.filter(ImageFilter.GaussianBlur(radius=blur_radius))
blurred_data = np.array(blurred_image)
np.copyto(data, blurred_data, where=mask[..., None])
return Image.fromarray(data, 'RGBA')
def generate_distant_colors(consolidated_colors, distance_threshold):
consolidated_lab = [rgb2lab(np.array([color], dtype=np.float32) / 255.0).reshape(3) for color, _ in consolidated_colors]
max_attempts = 10000
for _ in range(max_attempts):
random_rgb = np.random.randint(0, 256, size=3)
random_lab = rgb2lab(np.array([random_rgb], dtype=np.float32) / 255.0).reshape(3)
if all(deltaE_ciede2000(base_color_lab, random_lab) > distance_threshold for base_color_lab in consolidated_lab):
return tuple(random_rgb)
return (128, 128, 128)
def consolidate_colors(major_colors, threshold):
colors_lab = [rgb2lab(np.array([[color]], dtype=np.float32)/255.0).reshape(3) for color, _ in major_colors]
i = 0
while i < len(colors_lab):
j = i + 1
while j < len(colors_lab):
if deltaE_ciede2000(colors_lab[i], colors_lab[j]) < threshold:
if major_colors[i][1] >= major_colors[j][1]:
major_colors[i] = (major_colors[i][0], major_colors[i][1] + major_colors[j][1])
major_colors.pop(j)
colors_lab.pop(j)
else:
major_colors[j] = (major_colors[j][0], major_colors[j][1] + major_colors[i][1])
major_colors.pop(i)
colors_lab.pop(i)
continue
j += 1
i += 1
return major_colors
def get_major_colors(image, threshold_percentage=0.01):
if image.mode != 'RGB':
image = image.convert('RGB')
color_count = defaultdict(int)
for pixel in image.getdata():
color_count[pixel] += 1
total_pixels = image.width * image.height
major_colors = [(color, count) for color, count in color_count.items() if (count / total_pixels) >= threshold_percentage]
return major_colors
def line_color(image, mask, new_color):
data = np.array(image)
data[mask, :3] = new_color
return Image.fromarray(data, 'RGBA')
def main(image, lineart):
lineart = lineart.point(lambda x: 0 if x < 200 else 255)
lineart = ImageOps.invert(lineart)
kernel = np.ones((3, 3), np.uint8)
lineart = cv2.dilate(np.array(lineart), kernel, iterations=1)
lineart = Image.fromarray(lineart)
mask = np.array(lineart) == 255
major_colors = get_major_colors(image, threshold_percentage=0.05)
major_colors = consolidate_colors(major_colors, 10)
new_color_1 = generate_distant_colors(major_colors, 100)
filled_image = line_color(image, mask, new_color_1)
replace_color_image = replace_color(filled_image, new_color_1, 2).convert('RGB')
return replace_color_image
# Gradioインターフェース用のメイン関数
def gradio_interface(image):
image_path = 'temp_input_image.jpg'
image.save(image_path)
image = Image.open(image_path).convert('RGBA')
lineart = process_XDoG(image_path).convert('L')
replace_color_image = main(image, lineart)
return replace_color_image
# Gradioアプリを設定し、起動する
iface = gr.Interface(
fn=gradio_interface,
inputs=gr.Image(type='pil', label="Original Image"),
outputs=gr.Image(type='pil', label="Processed Image"),
title="Line Art Removal",
description="画像をアップロードして線画を除去します。"
)
iface.launch()
|