PandaArtStation's picture
Update utils.py
4a08565 verified
import numpy as np
from PIL import Image, ImageDraw, ImageFont, ImageFilter, ImageEnhance
import cv2
from sklearn.cluster import KMeans
import io
import base64
class ImageProcessor:
"""Класс для обработки изображений"""
@staticmethod
def resize_to_standard(image, max_size=1024):
"""Изменяет размер изображения до стандартного"""
ratio = min(max_size / image.width, max_size / image.height)
if ratio < 1:
new_size = (int(image.width * ratio), int(image.height * ratio))
return image.resize(new_size, Image.Resampling.LANCZOS)
return image
@staticmethod
def create_before_after(before, after):
"""Создает сравнение до/после"""
# Убедимся что изображения одного размера
width = max(before.width, after.width)
height = max(before.height, after.height)
# Создаем новое изображение
comparison = Image.new('RGB', (width * 2 + 20, height), (255, 255, 255))
# Вставляем изображения
comparison.paste(before, (0, 0))
comparison.paste(after, (width + 20, 0))
# Добавляем подписи
draw = ImageDraw.Draw(comparison)
try:
font = ImageFont.truetype("/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf", 30)
except:
font = None
draw.text((width // 2 - 50, height - 50), "ДО", fill=(255, 255, 255), font=font, stroke_width=2, stroke_fill=(0, 0, 0))
draw.text((width + 20 + width // 2 - 70, height - 50), "ПОСЛЕ", fill=(255, 255, 255), font=font, stroke_width=2, stroke_fill=(0, 0, 0))
return comparison
@staticmethod
def create_grid(images, titles=None, cols=2):
"""Создает сетку из изображений"""
if not images:
return None
n = len(images)
rows = (n + cols - 1) // cols
# Размер одного изображения
img_width = images[0].width
img_height = images[0].height
# Создаем сетку
grid_width = img_width * cols + 10 * (cols - 1)
grid_height = img_height * rows + 10 * (rows - 1) + (50 if titles else 0)
grid = Image.new('RGB', (grid_width, grid_height), (255, 255, 255))
draw = ImageDraw.Draw(grid)
try:
font = ImageFont.truetype("/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf", 20)
except:
font = None
# Размещаем изображения
for i, img in enumerate(images):
row = i // cols
col = i % cols
x = col * (img_width + 10)
y = row * (img_height + 10) + (50 if titles else 0)
grid.paste(img, (x, y))
# Добавляем заголовок
if titles and i < len(titles):
draw.text((x + img_width // 2 - 50, y - 40), titles[i], fill=(0, 0, 0), font=font)
return grid
@staticmethod
def detect_room_type(image):
"""Определяет тип комнаты по изображению"""
# Упрощенная логика определения типа комнаты
# В реальности здесь может быть ML модель
# Конвертируем в numpy array
img_array = np.array(image)
# Анализируем цвета и формы
# Это упрощенная эвристика
avg_color = img_array.mean(axis=(0, 1))
# Простая логика на основе преобладающих цветов
if avg_color[2] > avg_color[0] * 1.2: # Больше синего
return "Ванная"
elif avg_color[1] > avg_color[0] * 1.1: # Больше зеленого
return "Детская"
elif np.std(img_array) < 50: # Низкая контрастность
return "Спальня"
else:
return "Гостиная"
@staticmethod
def apply_vignette(image, intensity=0.3):
"""Применяет эффект виньетки"""
# Создаем маску виньетки
width, height = image.size
# Создаем радиальный градиент
x = np.linspace(-1, 1, width)
y = np.linspace(-1, 1, height)
X, Y = np.meshgrid(x, y)
radius = np.sqrt(X**2 + Y**2)
# Создаем маску
vignette = 1 - (radius * intensity)
vignette = np.clip(vignette, 0, 1)
vignette = (vignette * 255).astype(np.uint8)
# Применяем к изображению
vignette_img = Image.fromarray(vignette, mode='L')
# Накладываем
result = Image.new('RGB', image.size)
result.paste(image, (0, 0))
result.paste((0, 0, 0), (0, 0), vignette_img)
return Image.blend(image, result, intensity)
class ColorPalette:
"""Класс для работы с цветовыми палитрами"""
@staticmethod
def extract_colors(image, n_colors=5):
"""Извлекает основные цвета из изображения"""
# Уменьшаем изображение для ускорения
small_image = image.resize((150, 150), Image.Resampling.LANCZOS)
# Конвертируем в массив
img_array = np.array(small_image)
img_array = img_array.reshape(-1, 3)
# Кластеризация цветов
kmeans = KMeans(n_clusters=n_colors, random_state=42, n_init=10)
kmeans.fit(img_array)
# Получаем центры кластеров (основные цвета)
colors = kmeans.cluster_centers_.astype(int)
# Создаем изображение палитры
palette_height = 100
palette_width = 500
color_block_width = palette_width // n_colors
palette_img = Image.new('RGB', (palette_width, palette_height))
draw = ImageDraw.Draw(palette_img)
for i, color in enumerate(colors):
x_start = i * color_block_width
x_end = (i + 1) * color_block_width
color_tuple = tuple(color)
draw.rectangle([x_start, 0, x_end, palette_height], fill=color_tuple)
return palette_img, colors.tolist()
@staticmethod
def suggest_palette(style_name):
"""Предлагает цветовую палитру для стиля"""
palettes = {
"Современный минимализм": ["#FFFFFF", "#F5F5F5", "#E0E0E0", "#9E9E9E", "#424242"],
"Скандинавский": ["#FFFFFF", "#F8F8F8", "#E8DCC6", "#A8A8A8", "#4A4A4A"],
"Индустриальный": ["#2C2C2C", "#4A4A4A", "#7A7A7A", "#B8860B", "#8B4513"],
"Бохо": ["#CD853F", "#DEB887", "#D2691E", "#8B4513", "#A0522D"],
"Японский": ["#F5DEB3", "#D2B48C", "#BC8F8F", "#8B7355", "#4B4B4B"],
"Ар-деко": ["#FFD700", "#B8860B", "#2F4F4F", "#000000", "#8B0000"],
"Прованс": ["#E6E6FA", "#DDA0DD", "#D8BFD8", "#9370DB", "#8B7D6B"],
"Хай-тек": ["#C0C0C0", "#808080", "#4169E1", "#000000", "#FFFFFF"]
}
return palettes.get(style_name, ["#FFFFFF", "#E0E0E0", "#808080", "#404040", "#000000"])
@staticmethod
def apply_color_filter(image, color_rgb, intensity=0.3):
"""Применяет цветовой фильтр к изображению"""
# Создаем цветной слой
color_layer = Image.new('RGB', image.size, color_rgb)
# Смешиваем с оригиналом
return Image.blend(image, color_layer, intensity)
@staticmethod
def adjust_brightness_contrast(image, brightness=1.0, contrast=1.0):
"""Настройка яркости и контраста"""
# Яркость
enhancer = ImageEnhance.Brightness(image)
image = enhancer.enhance(brightness)
# Контраст
enhancer = ImageEnhance.Contrast(image)
image = enhancer.enhance(contrast)
return image