JustForWorld commited on
Commit
16ed97d
·
1 Parent(s): 9c900d6

fix(dino): change core to additive logic

Browse files
Files changed (1) hide show
  1. logic.py +29 -23
logic.py CHANGED
@@ -12,14 +12,12 @@ import time
12
  class WatermarkRemover:
13
  def __init__(self, device="cpu"):
14
  self.device = device
15
- # --- Не загружаем модели здесь! Просто инициализируем как None ---
16
  self.dino_processor = None
17
  self.dino_model = None
18
  self.inpainting_model = None
19
  logger.info(f"WatermarkRemover инициализирован для устройства {self.device}. Модели будут загружены по первому требованию.")
20
 
21
  def _get_dino_components(self):
22
- """Лениво загружает и возвращает компоненты DINO."""
23
  if self.dino_model is None:
24
  logger.info("Первый вызов: Загрузка модели детектора Grounding DINO...")
25
  dino_model_id = "IDEA-Research/grounding-dino-base"
@@ -29,7 +27,6 @@ class WatermarkRemover:
29
  return self.dino_processor, self.dino_model
30
 
31
  def _get_inpainting_model(self):
32
- """Лениво загружает и возвращает модель LaMa."""
33
  if self.inpainting_model is None:
34
  logger.info("Первый вызов: Загрузка модели LaMA для закрашивания...")
35
  self.inpainting_model = ModelManager(name="lama", device=self.device)
@@ -43,7 +40,6 @@ class WatermarkRemover:
43
  with torch.no_grad():
44
  outputs = model(**inputs)
45
 
46
- # Фильтрация будет произведена позже, на основе 'confidence'
47
  results = processor.post_process_grounded_object_detection(
48
  outputs,
49
  input_ids=inputs["input_ids"],
@@ -52,19 +48,12 @@ class WatermarkRemover:
52
  target_sizes=[image.size[::-1]]
53
  )[0]
54
 
55
- detections = sv.Detections(
56
  xyxy=results["boxes"].cpu().numpy(),
57
  confidence=results["scores"].cpu().numpy()
58
  )
59
-
60
- if len(detections) > 1:
61
- logger.info(f"Найдено {len(detections)} боксов до NMS. Запускаю очистку...")
62
- return detections.with_nms(class_agnostic=True, threshold=0.7)
63
-
64
- return detections
65
 
66
  def _inpaint_image(self, image_np: np.ndarray, mask_np: np.ndarray) -> np.ndarray:
67
- # Получаем модель через "ленивый" getter
68
  inpainting_model = self._get_inpainting_model()
69
  config = InpaintRequest(ldm_steps=50, ldm_sampler=LDMSampler.ddim, hd_strategy=HDStrategy.CROP)
70
  result = inpainting_model(image_np, mask_np, config)
@@ -74,25 +63,42 @@ class WatermarkRemover:
74
 
75
  def run(self, image: Image.Image) -> Image.Image:
76
  start_time = time.time()
77
- logger.info("Начало процесса удаления вотермарок с Grounding DINO...")
78
-
79
- TEXT_PROMPT = "watermark. logo. text."
80
- BOX_THRESHOLD = 0.35 # Основной порог уверенности
81
- TEXT_THRESHOLD = 0.25 # Дополнительный порог для текста
82
 
83
- # Передаем оба порога в функцию
84
- detections = self._detect_watermarks(image, TEXT_PROMPT, BOX_THRESHOLD, TEXT_THRESHOLD)
 
 
 
 
85
 
 
 
 
 
 
 
 
 
 
 
 
 
86
  if len(detections) == 0:
87
- logger.info("Grounding DINO не нашел вотермарок с достаточной уверенностью. Возвращаем оригинальное изображение.")
88
  return image
 
 
 
 
 
89
 
 
90
  mask = np.zeros(image.size[::-1], dtype=np.uint8)
91
- logger.info(f"Найдено {len(detections)} надежных вотермарок. Создание маски...")
92
- for box in detections.xyxy:
93
  cv2.rectangle(mask, tuple(map(int, box[:2])), tuple(map(int, box[2:])), 255, -1)
94
 
95
- kernel = np.ones((7, 7), np.uint8)
96
  processed_mask = cv2.dilate(mask, kernel, iterations=1)
97
 
98
  image_np = np.array(image.convert("RGB"))
 
12
  class WatermarkRemover:
13
  def __init__(self, device="cpu"):
14
  self.device = device
 
15
  self.dino_processor = None
16
  self.dino_model = None
17
  self.inpainting_model = None
18
  logger.info(f"WatermarkRemover инициализирован для устройства {self.device}. Модели будут загружены по первому требованию.")
19
 
20
  def _get_dino_components(self):
 
21
  if self.dino_model is None:
22
  logger.info("Первый вызов: Загрузка модели детектора Grounding DINO...")
23
  dino_model_id = "IDEA-Research/grounding-dino-base"
 
27
  return self.dino_processor, self.dino_model
28
 
29
  def _get_inpainting_model(self):
 
30
  if self.inpainting_model is None:
31
  logger.info("Первый вызов: Загрузка модели LaMA для закрашивания...")
32
  self.inpainting_model = ModelManager(name="lama", device=self.device)
 
40
  with torch.no_grad():
41
  outputs = model(**inputs)
42
 
 
43
  results = processor.post_process_grounded_object_detection(
44
  outputs,
45
  input_ids=inputs["input_ids"],
 
48
  target_sizes=[image.size[::-1]]
49
  )[0]
50
 
51
+ return sv.Detections(
52
  xyxy=results["boxes"].cpu().numpy(),
53
  confidence=results["scores"].cpu().numpy()
54
  )
 
 
 
 
 
 
55
 
56
  def _inpaint_image(self, image_np: np.ndarray, mask_np: np.ndarray) -> np.ndarray:
 
57
  inpainting_model = self._get_inpainting_model()
58
  config = InpaintRequest(ldm_steps=50, ldm_sampler=LDMSampler.ddim, hd_strategy=HDStrategy.CROP)
59
  result = inpainting_model(image_np, mask_np, config)
 
63
 
64
  def run(self, image: Image.Image) -> Image.Image:
65
  start_time = time.time()
66
+ logger.info("Начало процесса удаления вотермарок...")
 
 
 
 
67
 
68
+ # --- Этап 1: Поиск высококонтрастных частей (текст) ---
69
+ logger.info("--- ЭТАП 1: Поиск текста с высокой уверенностью ---")
70
+ detections_text = self._detect_watermarks(
71
+ image, text_prompt="text . watermark", box_threshold=0.4, text_threshold=0.4
72
+ )
73
+ logger.info(f"Найдено {len(detections_text)} текстовых фрагментов.")
74
 
75
+ # --- Этап 2: Поиск низкоконтрастных частей (фон) ---
76
+ logger.info("--- ЭТАП 2: Поиск фона с низкой уверенностью ---")
77
+ detections_bg = self._detect_watermarks(
78
+ image, text_prompt="semi-transparent background . transparent overlay . watermark background", box_threshold=0.25, text_threshold=0.25
79
+ )
80
+ logger.info(f"Найдено {len(detections_bg)} фоновых фрагментов.")
81
+
82
+ # --- Этап 3: Объединение и очистка ---
83
+ # Складываем все найденные детекции вместе
84
+ all_detections_list = [detections_text, detections_bg]
85
+ detections = sv.Detections.merge(all_detections_list)
86
+
87
  if len(detections) == 0:
88
+ logger.info("Ни один из этапов не нашел вотермарок. Возвращаем оригинальное изображение.")
89
  return image
90
+
91
+ logger.info(f"Всего найдено {len(detections)} фрагментов. Запускаю NMS для слияния...")
92
+ # Применяем NMS для слияния всех пересекающихся рамок в одну
93
+ merged_detections = detections.with_nms(class_agnostic=True, threshold=0.6)
94
+ logger.success(f"После слияния осталось {len(merged_detections)} уникальных областей.")
95
 
96
+ # --- Этап 4: Создание маски и закрашивание ---
97
  mask = np.zeros(image.size[::-1], dtype=np.uint8)
98
+ for box in merged_detections.xyxy:
 
99
  cv2.rectangle(mask, tuple(map(int, box[:2])), tuple(map(int, box[2:])), 255, -1)
100
 
101
+ kernel = np.ones((9, 9), np.uint8)
102
  processed_mask = cv2.dilate(mask, kernel, iterations=1)
103
 
104
  image_np = np.array(image.convert("RGB"))