PandaArtStation commited on
Commit
8f51460
·
verified ·
1 Parent(s): de4e465

Update models.py

Browse files
Files changed (1) hide show
  1. models.py +194 -225
models.py CHANGED
@@ -3,35 +3,30 @@ from diffusers import (
3
  StableDiffusionImg2ImgPipeline,
4
  StableDiffusionInpaintPipeline,
5
  DDIMScheduler,
6
- PNDMScheduler,
7
- EulerDiscreteScheduler
8
  )
9
  from PIL import Image, ImageFilter, ImageEnhance
10
  import numpy as np
11
- from typing import List, Union, Optional
12
- import cv2
13
 
14
  class InteriorDesignerPro:
15
  def __init__(self):
16
- self.device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
 
17
  self.model_name = "stabilityai/stable-diffusion-2-1"
18
 
19
  # Определяем мощность GPU
20
- if self.device.type == "cuda":
21
- gpu_name = torch.cuda.get_device_name(0).lower()
22
- self.is_powerful_gpu = any(x in gpu_name for x in ["a100", "v100", "h100", "h200", "rtx 40", "rtx 30"])
23
- else:
24
- self.is_powerful_gpu = False
25
-
26
- print(f"🚀 Инициализация на {self.device}")
27
- if self.device.type == "cuda":
28
- print(f"🎮 GPU: {torch.cuda.get_device_name(0)}")
29
- print(f"💪 Мощный GPU: {'Да' if self.is_powerful_gpu else 'Нет'}")
30
-
31
- # Основная модель
32
  self.pipe = StableDiffusionImg2ImgPipeline.from_pretrained(
33
  self.model_name,
34
- torch_dtype=torch.float16 if self.device.type == "cuda" else torch.float32,
35
  safety_checker=None,
36
  requires_safety_checker=False
37
  ).to(self.device)
@@ -40,68 +35,58 @@ class InteriorDesignerPro:
40
  try:
41
  self.inpaint_pipe = StableDiffusionInpaintPipeline.from_pretrained(
42
  "runwayml/stable-diffusion-inpainting",
43
- torch_dtype=torch.float16 if self.device.type == "cuda" else torch.float32,
44
  safety_checker=None,
45
  requires_safety_checker=False,
46
  local_files_only=False,
47
  resume_download=True
48
  ).to(self.device)
49
- print("✅ Inpainting модель загружена")
50
  except Exception as e:
51
- print(f"⚠️ Не удалось загрузить inpainting модель: {e}")
52
- print("Используем основную модель для inpainting")
53
  self.inpaint_pipe = None
54
-
55
  # Оптимизация памяти
56
- if self.device.type == "cuda":
57
- self.pipe.enable_attention_slicing()
58
- if hasattr(self.pipe, 'enable_xformers_memory_efficient_attention'):
59
- try:
60
- self.pipe.enable_xformers_memory_efficient_attention()
61
- if self.inpaint_pipe:
62
- self.inpaint_pipe.enable_xformers_memory_efficient_attention()
63
- print("✅ xFormers оптимизация включена")
64
- except:
65
- print("⚠️ xFormers недоступен")
66
-
67
  # Настройка планировщиков
68
  self.schedulers = {
69
- "ddim": DDIMScheduler.from_config(self.pipe.scheduler.config),
70
- "pndm": PNDMScheduler.from_config(self.pipe.scheduler.config),
71
- "euler": EulerDiscreteScheduler.from_config(self.pipe.scheduler.config)
72
  }
73
-
74
- # Удаление объектов
75
- self.object_remover = ObjectRemover(self.device)
76
-
77
  def apply_style_pro(self, image: Image.Image, style: str, room_type: str,
78
  strength: float = 0.75, quality: str = "balanced") -> Image.Image:
79
- """Применение стиля к изображению"""
80
- from design_styles import DESIGN_STYLES
81
 
82
- if style not in DESIGN_STYLES:
83
- style = "Современный минимализм"
84
-
85
- style_info = DESIGN_STYLES[style]
86
- base_prompt = style_info.get("prompt", "")
 
87
  negative_prompt = style_info.get("negative", "")
88
 
89
- # Добавляем специфику комнаты
90
- if "room_specific" in style_info and room_type in style_info["room_specific"]:
91
- room_prompt = style_info["room_specific"][room_type]
92
- prompt = f"{room_prompt}, {base_prompt}, interior design, professional photo"
93
- else:
94
- prompt = f"{room_type} {base_prompt}, interior design, professional photo"
95
-
96
- # Настройки качества
97
- quality_settings = {
98
- "fast": {"steps": 20, "guidance": 7.5, "scheduler": "euler"},
99
- "balanced": {"steps": 35, "guidance": 8.5, "scheduler": "ddim"},
100
- "ultra": {"steps": 50, "guidance": 10, "scheduler": "ddim"}
101
  }
102
 
103
- settings = quality_settings.get(quality, quality_settings["balanced"])
104
- self.pipe.scheduler = self.schedulers[settings["scheduler"]]
105
 
106
  # Генерация
107
  result = self.pipe(
@@ -114,90 +99,133 @@ class InteriorDesignerPro:
114
  ).images[0]
115
 
116
  return result
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
117
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
118
  def create_variations(self, image: Image.Image, num_variations: int = 4,
119
- strength: float = 0.5) -> List[Image.Image]:
120
- """Создание вариаций изображения"""
121
  variations = []
 
122
 
123
- prompts = [
124
- "modern interior design, bright and airy",
125
- "cozy warm interior, soft lighting",
126
- "minimalist clean space, neutral colors",
127
- "luxury elegant interior, premium materials"
128
- ]
129
-
130
- for i in range(min(num_variations, len(prompts))):
131
- var = self.pipe(
132
- prompt=prompts[i],
133
  image=image,
134
- strength=strength,
135
- num_inference_steps=25,
136
- guidance_scale=7.5
 
137
  ).images[0]
138
- variations.append(var)
139
 
140
- return variations
141
 
 
 
142
  def create_hdr_lighting(self, image: Image.Image, intensity: float = 0.3) -> Image.Image:
143
- """Улучшение освещения (HDR эффект)"""
144
  # Конвертируем в numpy
145
- img_array = np.array(image)
146
 
147
- # Создаем HDR эффект
148
- # Светлая версия
149
- light = cv2.convertScaleAbs(img_array, alpha=1.2, beta=30)
150
- # Темная версия
151
- dark = cv2.convertScaleAbs(img_array, alpha=0.8, beta=-30)
152
-
153
- # Комбинируем
154
- hdr = cv2.addWeighted(img_array, 1-intensity, light, intensity/2, 0)
155
- hdr = cv2.addWeighted(hdr, 1, dark, intensity/2, 0)
156
 
157
- # Улучшаем контраст
158
- lab = cv2.cvtColor(hdr, cv2.COLOR_RGB2LAB)
159
- l, a, b = cv2.split(lab)
160
- clahe = cv2.createCLAHE(clipLimit=3.0, tileGridSize=(8,8))
161
- l = clahe.apply(l)
162
- enhanced = cv2.merge([l, a, b])
163
- result = cv2.cvtColor(enhanced, cv2.COLOR_LAB2RGB)
164
 
165
- return Image.fromarray(result)
 
 
166
 
 
 
 
167
  def enhance_details(self, image: Image.Image) -> Image.Image:
168
  """Улучшение деталей изображения"""
169
  # Увеличиваем резкость
170
  enhancer = ImageEnhance.Sharpness(image)
171
- sharp = enhancer.enhance(1.5)
172
 
173
- # Улучшаем детали
174
- detail_filter = ImageFilter.DETAIL
175
- detailed = sharp.filter(detail_filter)
176
 
177
- # Легкий unsharp mask
178
- blurred = detailed.filter(ImageFilter.GaussianBlur(radius=1))
179
- img_array = np.array(detailed)
180
- blur_array = np.array(blurred)
181
-
182
- # Применяем маску
183
- sharpened = img_array + 0.5 * (img_array - blur_array)
184
- sharpened = np.clip(sharpened, 0, 255).astype(np.uint8)
185
-
186
- return Image.fromarray(sharpened)
187
 
 
 
188
  def change_element(self, image: Image.Image, element: str, value: str,
189
  strength: float = 0.5) -> Image.Image:
190
- """Изменение конкретного элемента интерьера"""
191
  from design_styles import ROOM_ELEMENTS
192
 
193
- if element not in ROOM_ELEMENTS:
194
- return image
195
-
196
- element_info = ROOM_ELEMENTS[element]
197
- prompt_add = element_info.get("prompt_add", "")
198
 
199
- prompt = f"{element} {value}, {prompt_add}, interior design"
200
- negative = "bad quality, distorted"
201
 
202
  result = self.pipe(
203
  prompt=prompt,
@@ -205,124 +233,64 @@ class InteriorDesignerPro:
205
  image=image,
206
  strength=strength,
207
  num_inference_steps=30,
208
- guidance_scale=8.0
209
  ).images[0]
210
 
211
  return result
212
-
213
- def remove_objects(self, image: Image.Image, mask: Image.Image,
214
- inpaint_prompt: str = None) -> Image.Image:
215
- """Удаление объектов с изображения"""
216
- if self.inpaint_pipe is None:
217
- # Fallback на обычную модель
218
- return self.remove_objects_fallback(image, mask, inpaint_prompt)
219
-
220
- if inpaint_prompt is None:
221
- inpaint_prompt = "empty room, clean space, seamless background"
222
-
223
- # Убеждаемся что маска в правильном формате
224
- if mask.mode != "L":
225
- mask = mask.convert("L")
226
-
227
- # Inpainting
228
- result = self.inpaint_pipe(
229
- prompt=inpaint_prompt,
230
- negative_prompt="furniture, objects, people",
231
- image=image,
232
- mask_image=mask,
233
- strength=0.99,
234
- num_inference_steps=50,
235
- guidance_scale=7.5
236
- ).images[0]
237
-
238
- return result
239
-
240
- def remove_objects_fallback(self, image: Image.Image, mask: Image.Image,
241
- inpaint_prompt: str = None) -> Image.Image:
242
- """Альтернативный метод удаления объектов"""
243
- # Используем OpenCV inpainting
244
- img_array = np.array(image)
245
- mask_array = np.array(mask.convert("L"))
246
-
247
- # Расширяем маску для лучшего результата
248
- kernel = np.ones((5,5), np.uint8)
249
- mask_array = cv2.dilate(mask_array, kernel, iterations=2)
250
-
251
- # Inpainting
252
- result = cv2.inpaint(img_array, mask_array, 3, cv2.INPAINT_TELEA)
253
-
254
- # Постобработка через img2img для улучшения
255
- result_img = Image.fromarray(result)
256
-
257
- if inpaint_prompt is None:
258
- inpaint_prompt = "clean empty space, seamless texture"
259
-
260
- enhanced = self.pipe(
261
- prompt=inpaint_prompt,
262
- image=result_img,
263
- strength=0.3,
264
- num_inference_steps=20,
265
- guidance_scale=7.5
266
- ).images[0]
267
-
268
- return enhanced
269
-
270
- def create_style_comparison(self, image: Image.Image, styles: List[str],
271
- room_type: str = "living room") -> Image.Image:
272
  """Создание сравнения нескольких стилей"""
273
  styled_images = []
274
 
275
- # Генерируем для каждого стиля
276
  for style in styles:
277
- styled = self.apply_style_pro(
278
- image, style, room_type,
279
- strength=0.75,
280
- quality="fast" # Быстрый режим для множественной генерации
281
- )
282
  styled_images.append(styled)
283
-
284
- # Создаем сетку
285
  return self._create_comparison_grid(styled_images, styles)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
286
 
287
- def _create_comparison_grid(self, images: List[Image.Image],
288
- titles: List[str]) -> Image.Image:
289
- """Создание сетки из изображений"""
290
- if not images:
291
- return None
292
-
293
- # Определяем размер сетки
294
- n = len(images)
295
- cols = min(3, n)
296
- rows = (n + cols - 1) // cols
297
-
298
- # Размер одного изображения
299
- img_width, img_height = images[0].size
300
-
301
- # Создаем холст
302
- grid_width = cols * img_width
303
- grid_height = rows * img_height
304
- grid = Image.new('RGB', (grid_width, grid_height), 'white')
305
-
306
- # Размещаем изображения
307
- for idx, (img, title) in enumerate(zip(images, titles)):
308
- row = idx // cols
309
- col = idx % cols
310
- x = col * img_width
311
- y = row * img_height
312
- grid.paste(img, (x, y))
313
-
314
- return grid
315
-
316
 
 
317
  class ObjectRemover:
318
- """Класс для удаления объектов"""
319
- def __init__(self, device):
320
- self.device = device
321
-
322
- def generate_mask_from_text(self, image: Image.Image, text: str,
323
  precision: float = 0.3) -> Image.Image:
324
  """Генерация маски на основе текстового описания"""
325
  # Простая реализация - создаем маску в центре
 
 
326
  width, height = image.size
327
  mask = Image.new('L', (width, height), 0)
328
 
@@ -334,12 +302,13 @@ class ObjectRemover:
334
  margin_x = int(width * (0.5 - precision))
335
  margin_y = int(height * (0.5 - precision))
336
 
337
- draw.ellipse(
 
338
  [margin_x, margin_y, width - margin_x, height - margin_y],
339
  fill=255
340
  )
341
 
342
- # Размываем маску
343
  mask = mask.filter(ImageFilter.GaussianBlur(radius=20))
344
 
345
  return mask
 
3
  StableDiffusionImg2ImgPipeline,
4
  StableDiffusionInpaintPipeline,
5
  DDIMScheduler,
6
+ EulerDiscreteScheduler,
7
+ PNDMScheduler
8
  )
9
  from PIL import Image, ImageFilter, ImageEnhance
10
  import numpy as np
11
+ from typing import List, Optional, Tuple
 
12
 
13
  class InteriorDesignerPro:
14
  def __init__(self):
15
+ """Инициализация AI дизайнера"""
16
+ self.device = torch.device("cuda") # ТОЛЬКО GPU!
17
  self.model_name = "stabilityai/stable-diffusion-2-1"
18
 
19
  # Определяем мощность GPU
20
+ gpu_name = torch.cuda.get_device_name(0)
21
+ self.is_powerful_gpu = any(x in gpu_name.lower() for x in ['h100', 'a100', 'h200', 'a6000'])
22
+
23
+ print(f"🚀 Initializing on GPU: {gpu_name}")
24
+ print(f"💪 Powerful GPU detected: {self.is_powerful_gpu}")
25
+
26
+ # Основная модель для дизайна
 
 
 
 
 
27
  self.pipe = StableDiffusionImg2ImgPipeline.from_pretrained(
28
  self.model_name,
29
+ torch_dtype=torch.float16,
30
  safety_checker=None,
31
  requires_safety_checker=False
32
  ).to(self.device)
 
35
  try:
36
  self.inpaint_pipe = StableDiffusionInpaintPipeline.from_pretrained(
37
  "runwayml/stable-diffusion-inpainting",
38
+ torch_dtype=torch.float16,
39
  safety_checker=None,
40
  requires_safety_checker=False,
41
  local_files_only=False,
42
  resume_download=True
43
  ).to(self.device)
44
+ print("✅ Inpainting model loaded")
45
  except Exception as e:
46
+ print(f"⚠️ Failed to load inpainting model: {e}")
47
+ print("Using img2img as fallback for object removal")
48
  self.inpaint_pipe = None
49
+
50
  # Оптимизация памяти
51
+ self.pipe.enable_attention_slicing()
52
+ if hasattr(self.pipe, 'enable_xformers_memory_efficient_attention'):
53
+ try:
54
+ self.pipe.enable_xformers_memory_efficient_attention()
55
+ print("✅ xFormers optimization enabled")
56
+ except:
57
+ pass
58
+
 
 
 
59
  # Настройка планировщиков
60
  self.schedulers = {
61
+ "fast": EulerDiscreteScheduler.from_config(self.pipe.scheduler.config),
62
+ "balanced": DDIMScheduler.from_config(self.pipe.scheduler.config),
63
+ "quality": PNDMScheduler.from_config(self.pipe.scheduler.config)
64
  }
65
+
 
 
 
66
  def apply_style_pro(self, image: Image.Image, style: str, room_type: str,
67
  strength: float = 0.75, quality: str = "balanced") -> Image.Image:
68
+ """Применение стиля к интерьеру"""
69
+ from design_styles import DESIGN_STYLES, get_detailed_prompt
70
 
71
+ # Подготовка изображения
72
+ image = self._prepare_image(image)
73
+
74
+ # Получаем промпт для стиля
75
+ style_info = DESIGN_STYLES.get(style, DESIGN_STYLES["Современный минимализм"])
76
+ prompt = get_detailed_prompt(style, room_type)
77
  negative_prompt = style_info.get("negative", "")
78
 
79
+ # Выбираем планировщик
80
+ self.pipe.scheduler = self.schedulers.get(quality, self.schedulers["balanced"])
81
+
82
+ # Параметры генерации
83
+ params = {
84
+ "fast": {"steps": 20, "guidance": 7.5},
85
+ "balanced": {"steps": 35, "guidance": 8.5},
86
+ "ultra": {"steps": 50, "guidance": 10}
 
 
 
 
87
  }
88
 
89
+ settings = params.get(quality, params["balanced"])
 
90
 
91
  # Генерация
92
  result = self.pipe(
 
99
  ).images[0]
100
 
101
  return result
102
+
103
+ def remove_objects(self, image: Image.Image, mask: Image.Image,
104
+ inpaint_prompt: str = None) -> Image.Image:
105
+ """Удаление объектов с изображения"""
106
+ if self.inpaint_pipe is None:
107
+ # Fallback метод через img2img
108
+ return self._remove_objects_fallback(image, mask)
109
+
110
+ # Подготовка
111
+ image = self._prepare_image(image, size=(512, 512))
112
+ mask = self._prepare_mask(mask, size=(512, 512))
113
+
114
+ # Промпт для заполнения
115
+ if not inpaint_prompt:
116
+ inpaint_prompt = "empty room interior, clean walls, seamless texture, high quality"
117
+
118
+ # Inpainting
119
+ result = self.inpaint_pipe(
120
+ prompt=inpaint_prompt,
121
+ negative_prompt="furniture, objects, people, clutter",
122
+ image=image,
123
+ mask_image=mask,
124
+ num_inference_steps=50,
125
+ guidance_scale=7.5,
126
+ strength=0.99
127
+ ).images[0]
128
+
129
+ return result
130
+
131
+ def _remove_objects_fallback(self, image: Image.Image, mask: Image.Image) -> Image.Image:
132
+ """Альтернативный метод удаления объектов"""
133
+ # Размываем область под маской
134
+ import cv2
135
+
136
+ img_np = np.array(image)
137
+ mask_np = np.array(mask.convert('L'))
138
+
139
+ # Расширяем маску
140
+ kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (15, 15))
141
+ mask_np = cv2.dilate(mask_np, kernel, iterations=2)
142
 
143
+ # Inpaint через OpenCV
144
+ result_np = cv2.inpaint(img_np, mask_np, 7, cv2.INPAINT_TELEA)
145
+ result = Image.fromarray(result_np)
146
+
147
+ # Улучшаем через img2img
148
+ enhanced = self.pipe(
149
+ prompt="clean empty interior space, seamless walls",
150
+ negative_prompt="objects, furniture",
151
+ image=result,
152
+ strength=0.3,
153
+ num_inference_steps=20,
154
+ guidance_scale=5
155
+ ).images[0]
156
+
157
+ return enhanced
158
+
159
  def create_variations(self, image: Image.Image, num_variations: int = 4,
160
+ variation_strength: float = 0.3) -> List[Image.Image]:
161
+ """Создание вариаций дизайна"""
162
  variations = []
163
+ base_prompt = "interior design, professional photo, high quality"
164
 
165
+ for i in range(num_variations):
166
+ # Немного меняем seed для разнообразия
167
+ generator = torch.Generator(device=self.device).manual_seed(42 + i)
168
+
169
+ result = self.pipe(
170
+ prompt=base_prompt,
 
 
 
 
171
  image=image,
172
+ strength=variation_strength,
173
+ num_inference_steps=30,
174
+ guidance_scale=7.5,
175
+ generator=generator
176
  ).images[0]
 
177
 
178
+ variations.append(result)
179
 
180
+ return variations
181
+
182
  def create_hdr_lighting(self, image: Image.Image, intensity: float = 0.3) -> Image.Image:
183
+ """Создание HDR освещения"""
184
  # Конвертируем в numpy
185
+ img_array = np.array(image).astype(np.float32) / 255.0
186
 
187
+ # Создаем несколько экспозиций
188
+ exposures = [
189
+ img_array * 0.5, # Недоэкспонированная
190
+ img_array, # Нормальная
191
+ np.clip(img_array * 1.5, 0, 1) # Переэкспонированная
192
+ ]
 
 
 
193
 
194
+ # Простой tone mapping
195
+ hdr = np.mean(exposures, axis=0)
 
 
 
 
 
196
 
197
+ # Увеличиваем контраст
198
+ hdr = (hdr - 0.5) * (1 + intensity) + 0.5
199
+ hdr = np.clip(hdr, 0, 1)
200
 
201
+ # Обратно в PIL
202
+ return Image.fromarray((hdr * 255).astype(np.uint8))
203
+
204
  def enhance_details(self, image: Image.Image) -> Image.Image:
205
  """Улучшение деталей изображения"""
206
  # Увеличиваем резкость
207
  enhancer = ImageEnhance.Sharpness(image)
208
+ image = enhancer.enhance(1.5)
209
 
210
+ # Немного увеличиваем контраст
211
+ enhancer = ImageEnhance.Contrast(image)
212
+ image = enhancer.enhance(1.1)
213
 
214
+ # Применяем unsharp mask
215
+ image = image.filter(ImageFilter.UnsharpMask(radius=1, percent=150, threshold=3))
 
 
 
 
 
 
 
 
216
 
217
+ return image
218
+
219
  def change_element(self, image: Image.Image, element: str, value: str,
220
  strength: float = 0.5) -> Image.Image:
221
+ """Изменение отдельного элемента интерьера"""
222
  from design_styles import ROOM_ELEMENTS
223
 
224
+ element_info = ROOM_ELEMENTS.get(element, {})
225
+ prompt_add = element_info.get("prompt_add", element.lower())
 
 
 
226
 
227
+ prompt = f"interior with {value} {prompt_add}, professional photo"
228
+ negative = f"old {element}, damaged, ugly"
229
 
230
  result = self.pipe(
231
  prompt=prompt,
 
233
  image=image,
234
  strength=strength,
235
  num_inference_steps=30,
236
+ guidance_scale=8
237
  ).images[0]
238
 
239
  return result
240
+
241
+ def create_style_comparison(self, image: Image.Image, styles: List[str]) -> Image.Image:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
242
  """Создание сравнения нескольких стилей"""
243
  styled_images = []
244
 
 
245
  for style in styles:
246
+ styled = self.apply_style_pro(image, style, "living room", strength=0.75, quality="fast")
 
 
 
 
247
  styled_images.append(styled)
248
+
249
+ # Создаем сетку через метод который добавим динамически
250
  return self._create_comparison_grid(styled_images, styles)
251
+
252
+ def _prepare_image(self, image: Image.Image, size: tuple = (768, 768)) -> Image.Image:
253
+ """Подготовка изображения"""
254
+ # Конвертируем в RGB
255
+ if image.mode != 'RGB':
256
+ image = image.convert('RGB')
257
+
258
+ # Изменяем размер сохраняя пропорции
259
+ image.thumbnail(size, Image.Resampling.LANCZOS)
260
+
261
+ # Дополняем до нужного размера
262
+ new_image = Image.new('RGB', size, (255, 255, 255))
263
+ paste_x = (size[0] - image.width) // 2
264
+ paste_y = (size[1] - image.height) // 2
265
+ new_image.paste(image, (paste_x, paste_y))
266
+
267
+ return new_image
268
+
269
+ def _prepare_mask(self, mask: Image.Image, size: tuple = (512, 512)) -> Image.Image:
270
+ """Подготовка маски"""
271
+ # Конвертируем в L (grayscale)
272
+ if mask.mode != 'L':
273
+ mask = mask.convert('L')
274
+
275
+ # Изменяем размер
276
+ mask = mask.resize(size, Image.Resampling.LANCZOS)
277
+
278
+ # Усиливаем контраст (четкие границы)
279
+ mask = mask.point(lambda x: 255 if x > 128 else 0)
280
 
281
+ return mask
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
282
 
283
+ # Класс для удаления объектов
284
  class ObjectRemover:
285
+ def __init__(self):
286
+ self.device = torch.device("cuda") # ТОЛЬКО GPU!
287
+
288
+ def generate_mask_from_text(self, image: Image.Image, text_description: str,
 
289
  precision: float = 0.3) -> Image.Image:
290
  """Генерация маски на основе текстового описания"""
291
  # Простая реализация - создаем маску в центре
292
+ # В реальности здесь должен быть CLIP/SAM для поиска объектов
293
+
294
  width, height = image.size
295
  mask = Image.new('L', (width, height), 0)
296
 
 
302
  margin_x = int(width * (0.5 - precision))
303
  margin_y = int(height * (0.5 - precision))
304
 
305
+ # Рисуем белую область
306
+ draw.rectangle(
307
  [margin_x, margin_y, width - margin_x, height - margin_y],
308
  fill=255
309
  )
310
 
311
+ # Размываем края для плавного перехода
312
  mask = mask.filter(ImageFilter.GaussianBlur(radius=20))
313
 
314
  return mask