Files
railway-client/tools/render_label_polygons.py
minsung 4c15d5ff5d sam31server 전환, 라멘 파이프라인 정리, 문서 추가
- sam31server를 SAM3.1 서버로 전환 (x-anylabeling01 대체)
- detect_raamen.py: B/C 분류 기반 라멘형 전철주 검출 파이프라인 정비
- sam3_everything_explore.py: Discovery Sweep 탐색 모드 정리
- detect_all_objects.py: 타일 검출 개선
- docs/railway-client-guide.html: 서버·도구·파이프라인 전체 가이드 추가
- tools 추가: detect_control_box, group_ramen_poles, render_everything_by_label, render_label_polygons, debug_vh

Closes #1

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-02 10:11:52 +09:00

84 lines
2.9 KiB
Python

"""LabelMe JSON에서 특정 레이블 폴리곤만 원본 이미지에 표시.
사용:
python tools/render_label_polygons.py \
--image data/역사구간/.../DJI_20260306100900_0034.JPG \
--json output/detect/DJI_20260306100900_0034/tiles1to24_railway_zone_001.json \
--label catenary_pole \
--output output/detect/DJI_20260306100900_0034/catenary_pole_only.jpg
# 여러 레이블:
python tools/render_label_polygons.py ... --label catenary_pole bracket
# 레이블 생략 시 전체 표시:
python tools/render_label_polygons.py ... --json foo.json --image foo.jpg
"""
import argparse
import json
import cv2
import numpy as np
from pathlib import Path
COLORS = [
(0, 0, 255), # red
(0, 200, 0), # green
(255, 100, 0), # blue-orange
(0, 200, 255), # yellow
(200, 0, 200), # magenta
(0, 165, 255), # orange
(255, 0, 100), # pink-blue
(100, 255, 100),# light green
]
def render(image_path: Path, json_path: Path, output_path: Path, labels: list[str] | None):
buf = np.fromfile(str(image_path), dtype=np.uint8)
img = cv2.imdecode(buf, cv2.IMREAD_COLOR)
if img is None:
raise FileNotFoundError(f"이미지 읽기 실패: {image_path}")
with open(json_path, encoding="utf-8") as f:
data = json.load(f)
shapes = data.get("shapes", [])
if labels:
shapes = [s for s in shapes if s["label"] in labels]
# 레이블별 색상 매핑
label_set = sorted({s["label"] for s in shapes})
color_map = {lbl: COLORS[i % len(COLORS)] for i, lbl in enumerate(label_set)}
for s in shapes:
pts = np.array(s["points"], dtype=np.int32).reshape((-1, 1, 2))
color = color_map[s["label"]]
cv2.polylines(img, [pts], isClosed=True, color=color, thickness=8)
x, y = int(s["points"][0][0]), int(s["points"][0][1])
score = s.get("score")
text = f"{s['label']} {score:.2f}" if score is not None else s["label"]
cv2.putText(img, text, (x, max(y - 10, 20)),
cv2.FONT_HERSHEY_SIMPLEX, 2.5, color, 5)
output_path.parent.mkdir(parents=True, exist_ok=True)
ret, buf_out = cv2.imencode(".jpg", img, [cv2.IMWRITE_JPEG_QUALITY, 85])
if not ret:
raise RuntimeError("JPEG 인코딩 실패")
output_path.write_bytes(buf_out.tobytes())
print(f"저장: {output_path} ({len(shapes)}개 폴리곤)")
def main():
p = argparse.ArgumentParser(description="LabelMe JSON 폴리곤 시각화")
p.add_argument("--image", required=True, type=Path)
p.add_argument("--json", required=True, type=Path)
p.add_argument("--output", required=True, type=Path)
p.add_argument("--label", nargs="*", default=None,
help="표시할 레이블 (생략 시 전체)")
args = p.parse_args()
render(args.image, args.json, args.output, args.label)
if __name__ == "__main__":
main()