albitro's picture
YOLO26s fire/person detection: baseline vs preprocessed (dehaze+CLAHE)
96f110e verified
Raw
History Blame Contribute Delete
4.98 kB
#!/usr/bin/env python3
"""
์ „์ฒ˜๋ฆฌ ํŒŒ์ดํ”„๋ผ์ธ โ€” mode์— ๋”ฐ๋ฅธ ์ฒ˜๋ฆฌ ์ˆœ์„œ. ROS ๋น„์˜์กด.
๋…ธ๋“œ ์•ˆ์— if๋ฌธ์œผ๋กœ ํฉ์–ด๋†“์œผ๋ฉด rclpy ์—†์ด๋Š” "mode๋ฅผ ๋ฐ”๊ฟจ์„ ๋•Œ ์ •๋ง ๋‹ค๋ฅธ
์ฒ˜๋ฆฌ๊ฐ€ ๋„๋Š”๊ฐ€"๋ฅผ ๊ฒ€์ฆํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ์—ฌ๊ธฐ๋กœ ๋นผ์„œ ๋…ธ๋“œยท์˜คํ”„๋ผ์ธ ๋„๊ตฌยทํ…Œ์ŠคํŠธ๊ฐ€
**๊ฐ™์€ ์ฝ”๋“œ**๋ฅผ ์“ฐ๊ฒŒ ํ–ˆ์Šต๋‹ˆ๋‹ค.
passthrough : ๋ฌด์ฒ˜๋ฆฌ (1๋‹จ๊ณ„ ๋ผˆ๋Œ€ โ€” QoSยทํ—ค๋” ๋ฐฐ์„ ๋งŒ ๊ฒ€์ฆ)
clahe : ๊ฐ๋งˆ -> CLAHE (2๋‹จ๊ณ„)
dehaze : ๊ฐ๋งˆ -> DCP (๊ธฐ์—ฌ๋„ ๋ถ„๋ฆฌ์šฉ)
full : ๊ฐ๋งˆ -> DCP -> CLAHE (3๋‹จ๊ณ„)
aod : ๊ฐ๋งˆ -> AOD-Net (DCP ๋Œ€์•ˆ)
aod_full : ๊ฐ๋งˆ -> AOD-Net -> CLAHE
AOD-Net์„ **๋ณ„๋„ ๋…ธ๋“œ๊ฐ€ ์•„๋‹ˆ๋ผ mode๋กœ** ๋„ฃ์€ ์ด์œ ๋Š” HANDOVER 4-9. ๋น„๊ต ๋„๊ตฌยท
์ •๋‹ต ์ฑ„์ ยท๋ถˆ์”จ ์ƒ์กด ํ…Œ์ŠคํŠธยท๋ฐ์ดํ„ฐ์…‹ ์ƒ์„ฑ๊ธฐยท๋…ธ๋“œ ๋ฐฐ์„ ์ด ์ „๋ถ€ ๊ทธ๋Œ€๋กœ ์žฌ์‚ฌ์šฉ๋˜๊ณ ,
A/B๊ฐ€ ํŒŒ๋ผ๋ฏธํ„ฐ ํ•œ ์ค„์ด ๋ฉ๋‹ˆ๋‹ค.
์ˆœ์„œ๊ฐ€ '๋””ํ—ค์ด์ฆˆ -> CLAHE'์ธ ์ด์œ : ๋””ํ—ค์ด์ฆˆ๋Š” ๋ฌผ๋ฆฌ ๋ชจ๋ธ์˜ ์—ญ์‚ฐ์ด๋ผ
**์ž…๋ ฅ์ด ์›๋ณธ ๊ด€์ธก๊ฐ’ I์—ฌ์•ผ** ์„ฑ๋ฆฝํ•ฉ๋‹ˆ๋‹ค. CLAHE๋ฅผ ๋จผ์ € ๊ฑธ๋ฉด ํžˆ์Šคํ† ๊ทธ๋žจ์ด
๋น„์„ ํ˜•์œผ๋กœ ๋ณ€ํ˜•๋ผ I = Jยทt + A(1-t) ๊ฐ€์ •์ด ๊นจ์ง‘๋‹ˆ๋‹ค.
"""
from __future__ import annotations
import time
from .dehaze import ClaheEnhancer, DarkChannelDehazer, apply_gamma
MODES = ("passthrough", "clahe", "dehaze", "full", "aod", "aod_full")
# ๋””ํ—ค์ด์ฆˆ๊ฐ€ ๋„๋Š” ๋ชจ๋“œ์™€, ๊ทธ์ค‘ AOD-Net์„ ์“ฐ๋Š” ๋ชจ๋“œ.
DEHAZE_MODES = ("dehaze", "full", "aod", "aod_full")
AOD_MODES = ("aod", "aod_full")
CLAHE_MODES = ("clahe", "full", "aod_full")
class Pipeline:
def __init__(
self,
mode: str = "full",
gamma: float = 1.0,
lowlight: bool = False,
clahe: ClaheEnhancer | None = None,
dehazer: DarkChannelDehazer | None = None,
aod=None,
):
self.set_mode(mode)
self.gamma = gamma
self.lowlight = lowlight
self.clahe = clahe or ClaheEnhancer()
self.dehazer = dehazer or DarkChannelDehazer()
# AOD-Net ๋””ํ—ค์ด์ €(`aodnet.GatedDehazer` ๋“ฑ). `process(bgr)->bgr` ์ธํ„ฐํŽ˜์ด์Šค๋งŒ
# ๋งž์œผ๋ฉด ๋ฉ๋‹ˆ๋‹ค. ์—†์œผ๋ฉด aod* ๋ชจ๋“œ๋ฅผ ์“ธ ๋•Œ ์˜ˆ์™ธ โ€” **DCP๋กœ ์กฐ์šฉํžˆ ๋Œ€์ฒดํ•˜์ง€
# ์•Š์Šต๋‹ˆ๋‹ค.** ๋Œ€์ฒดํ•˜๋ฉด "aod ๋ชจ๋“œ๋กœ ์ธก์ •ํ•œ ๊ฒฐ๊ณผ"๊ฐ€ ์‹ค์ œ๋กœ๋Š” DCP ๊ฒฐ๊ณผ๊ฐ€ ๋˜์–ด
# A/B ์‹คํ—˜์ด ํ†ต์งธ๋กœ ๋ฌด์˜๋ฏธํ•ด์ง‘๋‹ˆ๋‹ค.
self.aod = aod
# ๋งˆ์ง€๋ง‰ ํ”„๋ ˆ์ž„์˜ ๋‹จ๊ณ„๋ณ„ ์†Œ์š”์‹œ๊ฐ„(ms). ๋ณ‘๋ชฉ ์ถ”์ ์šฉ.
self.timings: dict[str, float] = {"dehaze": 0.0, "clahe": 0.0, "total": 0.0}
def set_mode(self, mode: str) -> None:
if mode not in MODES:
raise ValueError(f"mode๋Š” {MODES} ์ค‘ ํ•˜๋‚˜์—ฌ์•ผ ํ•ฉ๋‹ˆ๋‹ค (๋ฐ›์€ ๊ฐ’: {mode!r})")
self.mode = mode
def active_dehazer(self):
"""ํ˜„์žฌ mode๊ฐ€ ์“ฐ๋Š” ๋””ํ—ค์ด์ €. aod* ๋ชจ๋“œ์ธ๋ฐ ์—†์œผ๋ฉด ์˜ˆ์™ธ."""
if self.mode in AOD_MODES:
if self.aod is None:
raise ValueError(
f"mode={self.mode!r} ์ธ๋ฐ AOD-Net ๋””ํ—ค์ด์ €๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค. "
"onnx ๊ฒฝ๋กœ๋ฅผ ์ฃผ๊ฑฐ๋‚˜ dehaze/full ๋ชจ๋“œ๋ฅผ ์“ฐ์„ธ์š”. "
"(DCP๋กœ ์ž๋™ ๋Œ€์ฒดํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค โ€” A/B ์‹คํ—˜์ด ์˜ค์—ผ๋ฉ๋‹ˆ๋‹ค)"
)
return self.aod
return self.dehazer
def process(self, bgr):
"""bgr uint8 -> bgr uint8. ์ž…๋ ฅ ๋ฐฐ์—ด์€ ๋ณ€๊ฒฝํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค."""
t_start = time.perf_counter()
self.timings = {"dehaze": 0.0, "clahe": 0.0, "total": 0.0}
if self.mode == "passthrough":
self.timings["total"] = (time.perf_counter() - t_start) * 1000.0
return bgr
img = apply_gamma(bgr, self.gamma)
if self.mode in DEHAZE_MODES:
dehazer = self.active_dehazer()
t = time.perf_counter()
img = dehazer.process(img)
if self.lowlight:
if not hasattr(dehazer, "process_lowlight"):
# HANDOVER 4-9: AOD-Net์—๋Š” ์ €์กฐ๋„ ๋Œ€์‘ ๊ฒฝ๋กœ๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.
# ์กฐ์šฉํžˆ ๊ฑด๋„ˆ๋›ฐ๋ฉด "์ €์กฐ๋„ ๋ณด์ •์ด ์ผœ์ง„ ์ค„ ์•Œ์•˜๋Š”๋ฐ ์•ˆ ๋ˆ"
# ์ƒํƒœ๊ฐ€ ๋˜๋ฏ€๋กœ ๋ง‰์Šต๋‹ˆ๋‹ค.
raise ValueError(
f"mode={self.mode!r} ์˜ ๋””ํ—ค์ด์ €์—๋Š” process_lowlight๊ฐ€ "
"์—†์Šต๋‹ˆ๋‹ค. AOD-Net์€ ์ €์กฐ๋„ ๋Œ€์‘๋ฌผ์ด ์—†์Šต๋‹ˆ๋‹ค "
"(HANDOVER 4-9). lowlight๋ฅผ ๋„๊ฑฐ๋‚˜ dehaze/full์„ ์“ฐ์„ธ์š”."
)
img = dehazer.process_lowlight(img)
self.timings["dehaze"] = (time.perf_counter() - t) * 1000.0
if self.mode in CLAHE_MODES:
t = time.perf_counter()
img = self.clahe.process(img)
self.timings["clahe"] = (time.perf_counter() - t) * 1000.0
self.timings["total"] = (time.perf_counter() - t_start) * 1000.0
return img