Spaces:
Running
Running
| # src/visualizer.py | |
| import cv2 | |
| import numpy as np | |
| import os | |
| from pathlib import Path | |
| from typing import Dict, Optional | |
| # Çoklu taş için BGR renk paleti | |
| _STONE_COLORS = [ | |
| (60, 20, 220), # Kırmızı | |
| (220, 100, 20), # Mavi | |
| (20, 180, 220), # Turuncu | |
| (180, 20, 220), # Mor | |
| (20, 220, 120), # Yeşil-sarı | |
| ] | |
| _BBOX_COLOR = (30, 200, 30) # Yeşil — bbox her zaman yeşil | |
| def _stone_color(idx: int) -> tuple: | |
| return _STONE_COLORS[idx % len(_STONE_COLORS)] | |
| def draw_detections( | |
| image_path: str, | |
| detection_result: Dict, | |
| features: Dict, | |
| output_path: Optional[str] = None | |
| ) -> str: | |
| """ | |
| Görüntü üzerine her taş için: | |
| - Yeşil bbox (detection çıktısı) | |
| - Renkli yarı saydam mask dolgusu + kontur (segmentation çıktısı) | |
| - Etiket: taş ID, boyut (mm), confidence | |
| Returns: | |
| Kaydedilen annotated görüntünün path'i | |
| """ | |
| image = cv2.imread(image_path) | |
| if image is None: | |
| raise FileNotFoundError(f"Image not found: {image_path}") | |
| detections = detection_result.get("detections", []) | |
| stone_features = features.get("stones", []) | |
| # ── Adım 1: Mask dolguları ayrı overlay'de çiz ────────────────────────── | |
| overlay = image.copy() | |
| for idx, det in enumerate(detections): | |
| mask_polygon = det.get("mask_polygon") | |
| if mask_polygon: | |
| pts = np.array(mask_polygon, dtype=np.int32) | |
| cv2.fillPoly(overlay, [pts], _stone_color(idx)) | |
| # Yarı saydamlık uygula (dolgu görüntüyle karışsın, çizgiler keskin kalsın) | |
| result = cv2.addWeighted(overlay, 0.30, image, 0.70, 0) | |
| # ── Adım 2: Bbox + mask kontur + etiket üst katmanda çiz ──────────────── | |
| for idx, det in enumerate(detections): | |
| color = _stone_color(idx) | |
| # Bbox — yeşil ince dikdörtgen | |
| x1, y1, x2, y2 = [int(c) for c in det["bbox"]] | |
| cv2.rectangle(result, (x1, y1), (x2, y2), _BBOX_COLOR, 1) | |
| # Mask kontur — taşın gerçek sınırı | |
| mask_polygon = det.get("mask_polygon") | |
| if mask_polygon: | |
| pts = np.array(mask_polygon, dtype=np.int32) | |
| cv2.polylines(result, [pts], isClosed=True, color=color, thickness=2) | |
| # Etiket metni | |
| size_mm = 0.0 | |
| if idx < len(stone_features): | |
| size_mm = stone_features[idx]["size"].get("max_dimension_mm", 0.0) | |
| conf = det["confidence"] | |
| label = f"#{idx + 1} {size_mm}mm conf:{conf:.2f}" | |
| # Etiket arka planı (okunabilirlik için) | |
| font = cv2.FONT_HERSHEY_SIMPLEX | |
| font_scale = 0.45 | |
| thickness = 1 | |
| (tw, th), baseline = cv2.getTextSize(label, font, font_scale, thickness) | |
| lx = x1 | |
| ly = max(y1 - 6, th + 6) | |
| cv2.rectangle(result, | |
| (lx, ly - th - 4), | |
| (lx + tw + 6, ly + baseline), | |
| _BBOX_COLOR, cv2.FILLED) | |
| cv2.putText(result, label, | |
| (lx + 3, ly - 1), | |
| font, font_scale, (255, 255, 255), thickness, cv2.LINE_AA) | |
| # Taş tespit edilmediyse küçük bir uyarı yaz | |
| if not detections: | |
| cv2.putText(result, "No stones detected", | |
| (10, 30), cv2.FONT_HERSHEY_SIMPLEX, | |
| 0.7, (0, 0, 220), 2, cv2.LINE_AA) | |
| # ── Adım 3: Kaydet ────────────────────────────────────────────────────── | |
| if output_path is None: | |
| p = Path(image_path) | |
| output_path = str(p.parent / (p.stem + "_annotated.png")) | |
| parent_dir = os.path.dirname(output_path) | |
| if parent_dir: | |
| os.makedirs(parent_dir, exist_ok=True) | |
| cv2.imwrite(output_path, result) | |
| return output_path | |
| if __name__ == "__main__": | |
| # Hızlı test — gerçek model olmadan mock data ile | |
| import numpy as np | |
| # Siyah test görüntüsü oluştur | |
| test_img = np.zeros((512, 512, 3), dtype=np.uint8) | |
| cv2.imwrite("test_input.png", test_img) | |
| mock_detection = { | |
| "detections": [{ | |
| "bbox": [150, 180, 280, 300], | |
| "confidence": 0.91, | |
| "class_name": "stone", | |
| "mask_polygon": [ | |
| [170, 190], [200, 175], [250, 185], | |
| [270, 220], [260, 270], [220, 290], | |
| [175, 280], [155, 245], [160, 210] | |
| ] | |
| }] | |
| } | |
| mock_features = { | |
| "stones": [{ | |
| "stone_id": 1, | |
| "size": {"max_dimension_mm": 7.2}, | |
| "detection_confidence": 0.91 | |
| }] | |
| } | |
| out = draw_detections("test_input.png", mock_detection, mock_features) | |
| print(f"Saved: {out}") | |