PandaArtStation commited on
Commit
4a08565
·
verified ·
1 Parent(s): de34ce8

Update utils.py

Browse files
Files changed (1) hide show
  1. utils.py +184 -28
utils.py CHANGED
@@ -1,52 +1,208 @@
1
  import numpy as np
2
- from PIL import Image, ImageDraw, ImageFont
3
  import cv2
4
- from typing import List, Tuple, Optional
5
  from sklearn.cluster import KMeans
6
- import os
 
7
 
8
  class ImageProcessor:
9
- """Утилиты для обработки изображений"""
10
 
11
  @staticmethod
12
- def create_before_after(before: Image.Image, after: Image.Image) -> Image.Image:
13
- """Создание изображения до/после"""
14
- # Приводим к одному размеру
 
 
 
 
 
 
 
 
 
15
  width = max(before.width, after.width)
16
  height = max(before.height, after.height)
17
 
18
- before = before.resize((width, height), Image.Resampling.LANCZOS)
19
- after = after.resize((width, height), Image.Resampling.LANCZOS)
20
-
21
- # Создаем объединенное изображение
22
- combined = Image.new('RGB', (width * 2 + 10, height + 60), color='white')
23
 
24
  # Вставляем изображения
25
- combined.paste(before, (0, 50))
26
- combined.paste(after, (width + 10, 50))
27
 
28
  # Добавляем подписи
29
- draw = ImageDraw.Draw(combined)
30
  try:
31
  font = ImageFont.truetype("/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf", 30)
32
  except:
33
  font = None
 
 
 
34
 
35
- # Подписи
36
- draw.text((width//2 - 50, 10), "ДО", fill='black', font=font, anchor="mt")
37
- draw.text((width + width//2 + 5, 10), "ПОСЛЕ", fill='black', font=font, anchor="mt")
38
-
39
- # Разделительная линия
40
- draw.line([(width + 5, 50), (width + 5, height + 50)], fill='gray', width=2)
41
-
42
- return combined
43
 
44
  @staticmethod
45
- def create_grid(images: List[Image.Image], titles: Optional[List[str]] = None,
46
- cols: int = 2) -> Image.Image:
47
- """Создание сетки из изображений"""
48
  if not images:
49
  return None
50
-
51
  n = len(images)
52
- rows = (n + cols - 1) // cols # ✅ ПРАВИЛЬНО!
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  import numpy as np
2
+ from PIL import Image, ImageDraw, ImageFont, ImageFilter, ImageEnhance
3
  import cv2
 
4
  from sklearn.cluster import KMeans
5
+ import io
6
+ import base64
7
 
8
  class ImageProcessor:
9
+ """Класс для обработки изображений"""
10
 
11
  @staticmethod
12
+ def resize_to_standard(image, max_size=1024):
13
+ """Изменяет размер изображения до стандартного"""
14
+ ratio = min(max_size / image.width, max_size / image.height)
15
+ if ratio < 1:
16
+ new_size = (int(image.width * ratio), int(image.height * ratio))
17
+ return image.resize(new_size, Image.Resampling.LANCZOS)
18
+ return image
19
+
20
+ @staticmethod
21
+ def create_before_after(before, after):
22
+ """Создает сравнение до/после"""
23
+ # Убедимся что изображения одного размера
24
  width = max(before.width, after.width)
25
  height = max(before.height, after.height)
26
 
27
+ # Создаем новое изображение
28
+ comparison = Image.new('RGB', (width * 2 + 20, height), (255, 255, 255))
 
 
 
29
 
30
  # Вставляем изображения
31
+ comparison.paste(before, (0, 0))
32
+ comparison.paste(after, (width + 20, 0))
33
 
34
  # Добавляем подписи
35
+ draw = ImageDraw.Draw(comparison)
36
  try:
37
  font = ImageFont.truetype("/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf", 30)
38
  except:
39
  font = None
40
+
41
+ draw.text((width // 2 - 50, height - 50), "ДО", fill=(255, 255, 255), font=font, stroke_width=2, stroke_fill=(0, 0, 0))
42
+ draw.text((width + 20 + width // 2 - 70, height - 50), "ПОСЛЕ", fill=(255, 255, 255), font=font, stroke_width=2, stroke_fill=(0, 0, 0))
43
 
44
+ return comparison
 
 
 
 
 
 
 
45
 
46
  @staticmethod
47
+ def create_grid(images, titles=None, cols=2):
48
+ """Создает сетку из изображений"""
 
49
  if not images:
50
  return None
51
+
52
  n = len(images)
53
+ rows = (n + cols - 1) // cols
54
+
55
+ # Размер одного изображения
56
+ img_width = images[0].width
57
+ img_height = images[0].height
58
+
59
+ # Создаем сетку
60
+ grid_width = img_width * cols + 10 * (cols - 1)
61
+ grid_height = img_height * rows + 10 * (rows - 1) + (50 if titles else 0)
62
+
63
+ grid = Image.new('RGB', (grid_width, grid_height), (255, 255, 255))
64
+ draw = ImageDraw.Draw(grid)
65
+
66
+ try:
67
+ font = ImageFont.truetype("/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf", 20)
68
+ except:
69
+ font = None
70
+
71
+ # Размещаем изображения
72
+ for i, img in enumerate(images):
73
+ row = i // cols
74
+ col = i % cols
75
+ x = col * (img_width + 10)
76
+ y = row * (img_height + 10) + (50 if titles else 0)
77
+
78
+ grid.paste(img, (x, y))
79
+
80
+ # Добавляем заголовок
81
+ if titles and i < len(titles):
82
+ draw.text((x + img_width // 2 - 50, y - 40), titles[i], fill=(0, 0, 0), font=font)
83
+
84
+ return grid
85
+
86
+ @staticmethod
87
+ def detect_room_type(image):
88
+ """Определяет тип комнаты по изображению"""
89
+ # Упрощенная логика определения типа комнаты
90
+ # В реальности здесь может быть ML модель
91
+
92
+ # Конвертируем в numpy array
93
+ img_array = np.array(image)
94
+
95
+ # Анализируем цвета и формы
96
+ # Это упрощенная эвристика
97
+ avg_color = img_array.mean(axis=(0, 1))
98
+
99
+ # Простая логика на основе преобладающих цветов
100
+ if avg_color[2] > avg_color[0] * 1.2: # Больше синего
101
+ return "Ванная"
102
+ elif avg_color[1] > avg_color[0] * 1.1: # Больше зеленого
103
+ return "Детская"
104
+ elif np.std(img_array) < 50: # Низкая контрастность
105
+ return "Спальня"
106
+ else:
107
+ return "Гостиная"
108
+
109
+ @staticmethod
110
+ def apply_vignette(image, intensity=0.3):
111
+ """Применяет эффект виньетки"""
112
+ # Создаем маску виньетки
113
+ width, height = image.size
114
+
115
+ # Создаем радиальный градиент
116
+ x = np.linspace(-1, 1, width)
117
+ y = np.linspace(-1, 1, height)
118
+ X, Y = np.meshgrid(x, y)
119
+ radius = np.sqrt(X**2 + Y**2)
120
+
121
+ # Создаем маску
122
+ vignette = 1 - (radius * intensity)
123
+ vignette = np.clip(vignette, 0, 1)
124
+ vignette = (vignette * 255).astype(np.uint8)
125
+
126
+ # Применяем к изображению
127
+ vignette_img = Image.fromarray(vignette, mode='L')
128
+
129
+ # Накладываем
130
+ result = Image.new('RGB', image.size)
131
+ result.paste(image, (0, 0))
132
+ result.paste((0, 0, 0), (0, 0), vignette_img)
133
+
134
+ return Image.blend(image, result, intensity)
135
+
136
+ class ColorPalette:
137
+ """Класс для работы с цветовыми палитрами"""
138
+
139
+ @staticmethod
140
+ def extract_colors(image, n_colors=5):
141
+ """Извлекает основные цвета из изображения"""
142
+ # Уменьшаем изображение для ускорения
143
+ small_image = image.resize((150, 150), Image.Resampling.LANCZOS)
144
+
145
+ # Конвертируем в массив
146
+ img_array = np.array(small_image)
147
+ img_array = img_array.reshape(-1, 3)
148
+
149
+ # Кластеризация цветов
150
+ kmeans = KMeans(n_clusters=n_colors, random_state=42, n_init=10)
151
+ kmeans.fit(img_array)
152
+
153
+ # Получаем центры кластеров (основные цвета)
154
+ colors = kmeans.cluster_centers_.astype(int)
155
+
156
+ # Создаем изображение палитры
157
+ palette_height = 100
158
+ palette_width = 500
159
+ color_block_width = palette_width // n_colors
160
+
161
+ palette_img = Image.new('RGB', (palette_width, palette_height))
162
+ draw = ImageDraw.Draw(palette_img)
163
+
164
+ for i, color in enumerate(colors):
165
+ x_start = i * color_block_width
166
+ x_end = (i + 1) * color_block_width
167
+ color_tuple = tuple(color)
168
+ draw.rectangle([x_start, 0, x_end, palette_height], fill=color_tuple)
169
+
170
+ return palette_img, colors.tolist()
171
+
172
+ @staticmethod
173
+ def suggest_palette(style_name):
174
+ """Предлагает цветовую палитру для стиля"""
175
+ palettes = {
176
+ "Современный минимализм": ["#FFFFFF", "#F5F5F5", "#E0E0E0", "#9E9E9E", "#424242"],
177
+ "Скандинавский": ["#FFFFFF", "#F8F8F8", "#E8DCC6", "#A8A8A8", "#4A4A4A"],
178
+ "Индустриальный": ["#2C2C2C", "#4A4A4A", "#7A7A7A", "#B8860B", "#8B4513"],
179
+ "Бохо": ["#CD853F", "#DEB887", "#D2691E", "#8B4513", "#A0522D"],
180
+ "Японский": ["#F5DEB3", "#D2B48C", "#BC8F8F", "#8B7355", "#4B4B4B"],
181
+ "Ар-деко": ["#FFD700", "#B8860B", "#2F4F4F", "#000000", "#8B0000"],
182
+ "Прованс": ["#E6E6FA", "#DDA0DD", "#D8BFD8", "#9370DB", "#8B7D6B"],
183
+ "Хай-тек": ["#C0C0C0", "#808080", "#4169E1", "#000000", "#FFFFFF"]
184
+ }
185
+
186
+ return palettes.get(style_name, ["#FFFFFF", "#E0E0E0", "#808080", "#404040", "#000000"])
187
+
188
+ @staticmethod
189
+ def apply_color_filter(image, color_rgb, intensity=0.3):
190
+ """Применяет цветовой фильтр к изображению"""
191
+ # Создаем цветной слой
192
+ color_layer = Image.new('RGB', image.size, color_rgb)
193
+
194
+ # Смешиваем с оригиналом
195
+ return Image.blend(image, color_layer, intensity)
196
+
197
+ @staticmethod
198
+ def adjust_brightness_contrast(image, brightness=1.0, contrast=1.0):
199
+ """Настройка яркости и контраста"""
200
+ # Яркость
201
+ enhancer = ImageEnhance.Brightness(image)
202
+ image = enhancer.enhance(brightness)
203
+
204
+ # Контраст
205
+ enhancer = ImageEnhance.Contrast(image)
206
+ image = enhancer.enhance(contrast)
207
+
208
+ return image