cosmos0311 commited on
Commit
367e6cc
ยท
verified ยท
1 Parent(s): 8a86372

Update README.md

Browse files
Files changed (1) hide show
  1. README.md +52 -51
README.md CHANGED
@@ -14,36 +14,57 @@ pipeline_tag: object-detection
14
 
15
  # Edge Fire Detection AI (ํ™”์žฌ ๊ฐ์‹œ ์˜จ์  ์‹œ์Šคํ…œ)
16
 
17
- ๋ผ์ฆˆ๋ฒ ๋ฆฌํŒŒ์ด 5 ๋“ฑ ์ž„๋ฒ ๋””๋“œ ์—ฃ์ง€ ๋””๋ฐ”์ด์Šค ํ™˜๊ฒฝ์—์„œ ์‹ค์‹œ๊ฐ„์œผ๋กœ ๋ถˆ๊ฝƒ(Flame)๊ณผ ์—ฐ๊ธฐ(Smoke)๋ฅผ ๊ฐ์ง€ํ•˜๊ณ  ๋ฐ”์šด๋”ฉ ๋ฐ•์Šค๋ฅผ ์ถ”์ ํ•˜๋Š” ๊ฒฝ๋Ÿ‰ ๊ฐ์ฒด ํƒ์ง€(Object Detection) ๋ชจ๋ธ์ž…๋‹ˆ๋‹ค. `YOLOv8n(Nano)` ์•„ํ‚คํ…์ฒ˜๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ํŒŒ์ธํŠœ๋‹๋˜์—ˆ์œผ๋ฉฐ, ์—ฃ์ง€ ํ™˜๊ฒฝ์—์„œ์˜ ์‹ค์‹œ๊ฐ„์„ฑ ํ™•๋ณด๋ฅผ ์œ„ํ•ด `ONNX` ํฌ๋งท ๊ณ ์† ์ตœ์ ํ™” ๋Ÿฐํƒ€์ž„์„ ์ง€์›ํ•ฉ๋‹ˆ๋‹ค.
18
 
19
  ## 1. ํ•™์Šต ๋ฐ์ดํ„ฐ (Training Data)
20
- * **๋ฐ์ดํ„ฐ ์ถœ์ฒ˜:** AI Hub ํ™”์žฌ ๊ฐ์ง€ ์˜์ƒ ๋ฐ์ดํ„ฐ์…‹ ๋ฐ ์ž์ฒด ์ˆ˜์ง‘ ํ™”์žฌ ์ „์ฒ˜๋ฆฌ ์ด๋ฏธ์ง€
21
- * **ํด๋ž˜์Šค ๊ตฌ์„ฑ:** ์ด 2๊ฐœ ํด๋ž˜์Šค ์ •๋ ฌ (`flame`: ๋ถˆ๊ฝƒ / `smoke`: ์—ฐ๊ธฐ)
22
- * **๋ฐ์ดํ„ฐ ์ •์ œ ๋ฐ ์ฆ๊ฐ• (Data Augmentation):** * ์ €์กฐ๋„ ๊ฐ€ํ˜น ํ™˜๊ฒฝ ๋ฐ ์นด๋ฉ”๋ผ ๋…ธ์ด์ฆˆ ํ™˜๊ฒฝ์—์„œ์˜ ์˜ค์ž‘๋™(False Positive)์„ ๋ฐฉ์ง€ํ•˜๊ธฐ ์œ„ํ•ด ๋ฐ๊ธฐ ๋ณ€ํ˜•, ํ๋ฆผ(Blur), ๋ชจ์ž์ดํฌ ์ฆ๊ฐ• ๊ธฐ๋ฒ• ์ ์šฉ
23
- * ๋ผ์ฆˆ๋ฒ ๋ฆฌํŒŒ์ด 5 I/O ๋ฒ„์Šค ์ „์†ก๋Ÿ‰ ๊ณผ๋ถ€ํ•˜ ๋ฐฉ์ง€๋ฅผ ์œ„ํ•ด ์ž…๋ ฅ ํ•ด์ƒ๋„๋ฅผ 320x240 ๋ฐ 640x480 ์Šค์ผ€์ผ๋Ÿฌ๋กœ ๊ฐ€๊ณต ์ •๋ ฌ (v2)
 
24
 
25
- ## 2. ๋ชจ๋ธ ์„ฑ๋Šฅ (Evaluation)
26
 
27
- | ํ‰๊ฐ€ ์ง€ํ‘œ | ํŒŒ์ดํ† ์น˜ (.pt) ๊ทœ๊ฒฉ | ONNX ๊ฒฝ๋Ÿ‰ ๊ฐ€์† ๊ทœ๊ฒฉ | ๋น„๊ณ  (๋ผ์ฆˆ๋ฒ ๋ฆฌํŒŒ์ด 5 CPU ๊ธฐ์ค€) |
28
  | :--- | :---: | :---: | :--- |
29
- | **mAP50 (์ „์ฒด ์ •ํ™•๋„)** | 84.5% | 83.9% | ํฌ๋งท ๋ณ€ํ™˜์— ๋”ฐ๋ฅธ ์ •ํ™•๋„ ์†์‹ค ์ตœ์†Œํ™” |
30
  | **mAP50-95** | 0.521 | 0.518 | - |
31
- | **์ถ”๋ก  ์†๋„ (Latency)** | ์•ฝ 350ms | **์•ฝ 45ms** | ONNX ๊ฐ€์† ์‹œ ์‹ค์‹œ๊ฐ„์„ฑ(20 FPS ์ด์ƒ) ๋‹ฌ์„ฑ |
32
 
33
- ## 3. ํ•™์Šต ์„ค์ • (Hyperparameters)
 
 
 
34
 
35
  | ํ•ญ๋ชฉ | ์„ค์ •๊ฐ’ | ๋น„๊ณ  |
36
  | :--- | :---: | :--- |
37
- | **๊ธฐ๋ฐ˜ ์•„ํ‚คํ…์ฒ˜ (Model)** | YOLOv8n | 3.2M ๊ฒฝ๋Ÿ‰ ํŒŒ๋ผ๋ฏธํ„ฐ ๊ตฌ์กฐ |
38
- | **์ž…๋ ฅ ํ•ด์ƒ๋„ (imgsz)** | 320 / 640 | ๊ฐ€๋ณ€ ํ•˜ํ–ฅ ๋ ˆ์ด์–ด ๋งคํ•‘ |
39
  | **Epochs** | 50 | - |
40
- | **Batch Size** | 32 | - |
41
  | **Optimizer** | AdamW | - |
42
- | **Augmentation** | Mosaic (1.0), Blur (0.2) | ์ž„๋ฒ ๋””๋“œ ํ™˜๊ฒฝ ์˜ค์ž‘๋™ ์ฐจ๋‹จ์šฉ |
 
43
 
44
- ## 4. ์‚ฌ์šฉ ๋ฐฉ๋ฒ• (Inference Code)
45
 
46
- ๋ผ์ฆˆ๋ฒ ๋ฆฌํŒŒ์ด 5 ํ™˜๊ฒฝ์—์„œ `onnxruntime` ๋ฐฑ์—”๋“œ๋ฅผ ํ™œ์šฉํ•˜์—ฌ ํ•˜๋“œ์›จ์–ด ๋ณ‘๋ชฉ ์—†์ด ๊ณ ์† ์ถ”๋ก ์„ ์ˆ˜ํ–‰ํ•˜๋Š” ์ฃผํ”ผํ„ฐ ๋…ธํŠธ๋ถ ์ตœ์ ํ™” ๋งˆ์Šคํ„ฐ ์Šคํฌ๋ฆฝํŠธ์ž…๋‹ˆ๋‹ค.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
47
 
48
  ```python
49
  import cv2
@@ -54,24 +75,20 @@ import ipywidgets as widgets
54
  import time
55
 
56
  def main():
57
- # 1. ๊ณ ์† ๊ฐ€์† ONNX ๋ชจ๋ธ ๋กœ๋“œ (task='detect' ๋ช…์‹œ ํ•„์ˆ˜)
58
  model_path = "best.onnx"
59
  model = YOLO(model_path, task='detect')
60
 
61
- # 2. V4L2 ๋ฆฌ๋ˆ…์Šค ํ‘œ์ค€ ๋น„๋””์˜ค ์ž…๋ ฅ ์†Œ์ผ“ ์—ฐ๊ฒฐ (๋ฌผ๋ฆฌ 0๋ฒˆ ์ฑ„๋„)
62
  cap = cv2.VideoCapture(0, cv2.CAP_V4L2)
63
-
64
- # 3. ํ•˜๋“œ์›จ์–ด ๋Œ€์—ญํญ ๊ณผ๋ถ€ํ•˜ ๋ฐฉ์ง€๋ฅผ ์œ„ํ•œ ํ•ด์ƒ๋„ ๋ฐ ๋ฒ„ํผ ์ œ์–ด
65
  cap.set(cv2.CAP_PROP_FRAME_WIDTH, 320)
66
  cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 240)
67
  cap.set(cv2.CAP_PROP_BUFFERSIZE, 1)
68
 
69
- time.sleep(1) # ํšŒ๋กœ ๋™๊ธฐํ™” ์•ˆ์ •ํ™” ์ง€์—ฐ
70
  if not cap.isOpened():
71
  print("[์˜ค๋ฅ˜] ์นด๋ฉ”๋ผ ์žฅ์น˜๋ฅผ ํ™œ์„ฑํ™”ํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.")
72
  return
73
 
74
- # ์ฃผํ”ผํ„ฐ ๋…ธํŠธ๋ถ ์ธ๋ผ์ธ ์ถœ๋ ฅ์„ ์œ„ํ•œ ์ด๋ฏธ์ง€ ์œ„์ ฏ ์„ ์–ธ
75
  image_widget = widgets.Image(format='jpeg', width=320, height=240)
76
  display(image_widget)
77
 
@@ -81,17 +98,17 @@ def main():
81
  if not success or frame is None:
82
  continue
83
 
84
- # 4. YOLOv8 ONNX ๊ฐ€์† ์ถ”๋ก  ๊ตฌ๋™
85
  results = model(frame, imgsz=320, stream=True)
86
  for r in results:
87
  annotated_frame = r.plot()
88
 
89
- # 5. JPEG ์••์ถ• ์ธ์ฝ”๋”ฉ ํ›„ ์ฃผํ”ผํ„ฐ ๋ Œ๋”๋ง ํŒŒ์ดํ”„๋ผ์ธ ์ „์†ก
90
  ret, jpeg = cv2.imencode('.jpg', annotated_frame)
91
  if ret:
92
  image_widget.value = jpeg.tobytes()
93
 
94
- # ์ฃผํ”ผํ„ฐ ์›น ์†Œ์ผ“ ๊ณผ๋ถ€ํ•˜(ZMQ ์—๋Ÿฌ) ์ฐจ๋‹จ์šฉ ๋ฏธ์„ธ ์ง€์—ฐ
95
  time.sleep(0.04)
96
 
97
  except KeyboardInterrupt:
@@ -105,34 +122,18 @@ if __name__ == '__main__':
105
  main()
106
  ```
107
 
 
108
 
109
- ## 5. ์ž…์ถœ๋ ฅ ํ˜•์‹ (Input / Output Format)
110
- Plaintext
111
-
112
- ์ž…๋ ฅ(Input): ์‹ค์‹œ๊ฐ„ ์นด๋ฉ”๋ผ ๋น„๋””์˜ค ํ”„๋ ˆ์ž„ (320x240 ๋˜๋Š” 640x480 RGB ์ด๋ฏธ์ง€)
113
  ์ถœ๋ ฅ(Output):
114
- - ์˜ˆ์ธก ๊ฐ์ฒด ๋ฐ”์šด๋”ฉ ๋ฐ•์Šค ํˆฌ์‚ฌ (Bounding Box ์ขŒํ‘œ ์ •๋ณด)
115
- - ํด๋ž˜์Šค ๋ ˆ์ด๋ธ” ๋งคํ•‘: [flame, smoke]
116
- - ์‹ ๋ขฐ๋„ ์ˆ˜์น˜ ์ถœ๋ ฅ (Confidence Score: 0.0 ~ 1.0)
117
-
118
- ## 6. ๋ผ์ฆˆ๋ฒ ๋ฆฌํŒŒ์ด ์ž„๋ฒ ๋””๋“œ ๋ฐฐํฌ ๊ฐ€์ด๋“œ
119
- ํ™˜๊ฒฝ ๊ตฌ์ถ• ๋ฐ ์„œ๋ฒ„ ๊ฐ€๋™
120
- Bash
121
-
122
- # ๊ฐ€์ƒํ™˜๊ฒฝ ์ง„์ž… ์ƒํƒœ ํ™•์ธ ํ›„ ํ•„์š” ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์ ์žฌ
123
- conda activate myenv
124
- pip install notebook ultralytics ipywidgets opencv-python onnxruntime
125
-
126
- # ๋ผ์ฆˆ๋ฒ ๋ฆฌํŒŒ์ด 5 ์ตœ์‹  OS์˜ ๋ฏธ๋””์–ด ์ž์› ๋…์  ์ž ๊ธˆ(Lock) ์šฐํšŒ ์˜ต์…˜์„ ํƒ‘์žฌํ•˜์—ฌ ์ฃผํ”ผํ„ฐ ์‹คํ–‰
127
- LD_PRELOAD=/usr/lib/aarch64-linux-gnu/libv4l/v4l1compat.so jupyter notebook --ip=0.0.0.0 --no-browser --port=8888
128
-
129
- ์›น์บ  ํ•˜๋“œ์›จ์–ด ์‹ค์‹œ๊ฐ„ ํŠธ๋Ÿฌ๋ธ”์ŠˆํŒ… ์„ธ์…˜
130
-
131
- select() timeout ๊ฒฝ๊ณ  ๏ฟฝ๏ฟฝ์ƒ ์‹œ: ๋ผ์ฆˆ๋ฒ ๋ฆฌํŒŒ์ด 5์˜ ์ „๋ ฅ ๊ณต๊ธ‰ ๋ฌธ์ œ์ด๊ฑฐ๋‚˜ ์ปค๋„ ๋ฝ ์ƒํƒœ์ž…๋‹ˆ๋‹ค. ํ„ฐ๋ฏธ๋„์—์„œ sudo reboot๋ฅผ ์ˆ˜ํ–‰ํ•˜์—ฌ ์žฅ์น˜ ๋ฝ์„ ๊ฐ•์ œ ์ดˆ๊ธฐํ™”ํ•œ ๋’ค ์žฌ๊ฐ€๋™ํ•˜์‹ญ์‹œ์˜ค.
132
-
133
- ํ™”๋ฉด ๊นจ์ง ๋ฐ error dequeuing buf ๋ฐœ์ƒ ์‹œ: USB ๋ฒ„์Šค ์ „์†ก ๋Œ€์—ญํญ ํ•œ๊ณ„์น˜ ์ดˆ๊ณผ ํ˜„์ƒ์ž…๋‹ˆ๋‹ค. ์นด๋ฉ”๋ผ ์—ฐ๊ฒฐ ์„ ์„ ๊ฒ€์€์ƒ‰ ํฌํŠธ์—์„œ ์ „์†ก ์ „๋ ฅ์ด ๋†’์€ ํŒŒ๋ž€์ƒ‰ USB 3.0 ํฌํŠธ๋กœ ๋ฌผ๋ฆฌ์ ์œผ๋กœ ์ด๋™ ์ •๋ ฌํ•˜๊ณ  ์ฝ”๋“œ ๋‚ด ํ•ด์ƒ๋„๋ฅผ 320x240์œผ๋กœ ์œ ์ง€ํ•˜์‹ญ์‹œ์˜ค.
134
 
135
  ## 7. ๋กœ์ปฌ ๋™๊ธฐํ™” ๊ฐ€์ค‘์น˜ ๋‹ค์šด๋กœ๋“œ CLI
136
- Bash
137
 
138
- huggingface-cli download Onjeom/fire_detection_yolov8n --local-dir ./model
 
 
 
14
 
15
  # Edge Fire Detection AI (ํ™”์žฌ ๊ฐ์‹œ ์˜จ์  ์‹œ์Šคํ…œ)
16
 
17
+ ๋ผ์ฆˆ๋ฒ ๋ฆฌํŒŒ์ด 5(Raspberry Pi 5) ์ž„๋ฒ ๋””๋“œ ์—ฃ์ง€ ๋””๋ฐ”์ด์Šค ํ™˜๊ฒฝ์—์„œ ์‹ค์‹œ๊ฐ„์œผ๋กœ ๋ถˆ๊ฝƒ(Flame)๊ณผ ์—ฐ๊ธฐ(Smoke)๋ฅผ ๊ฐ์ง€ํ•˜๊ณ  ๋ฐ”์šด๋”ฉ ๋ฐ•์Šค๋ฅผ ์ถ”์ ํ•˜๋Š” ๊ฒฝ๋Ÿ‰ ๊ฐ์ฒด ํƒ์ง€(Object Detection) ๋ชจ๋ธ์ž…๋‹ˆ๋‹ค. `YOLOv8n(Nano)` ์•„ํ‚คํ…์ฒ˜๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ์ „์ด ํ•™์Šต(Transfer Learning)์„ ์ง„ํ–‰ํ–ˆ์œผ๋ฉฐ, ํ•˜๋“œ์›จ์–ด ์—ฐ์‚ฐ ๋ถ€ํ•˜๋ฅผ ์ตœ์†Œํ™”ํ•˜๊ธฐ ์œ„ํ•ด `ONNX` ํฌ๋งท ๊ณ ์† ๋Ÿฐํƒ€์ž„ ์ตœ์ ํ™”๋ฅผ ์ ์šฉํ–ˆ์Šต๋‹ˆ๋‹ค.
18
 
19
  ## 1. ํ•™์Šต ๋ฐ์ดํ„ฐ (Training Data)
20
+ * **๋ฐ์ดํ„ฐ ์ถœ์ฒ˜:** AI Hub ํ™”์žฌ ๊ฐ์ง€ ์˜์ƒ ๋ฐ์ดํ„ฐ์…‹ ๋ฐ ์ž์ฒด ์ˆ˜์ง‘ ํ™”์žฌ ์ด๋ฏธ์ง€ ์…‹
21
+ * **ํด๋ž˜์Šค ์ •์˜:** ์ด 2๊ฐœ ํด๋ž˜์Šค (`flame`: ๋ถˆ๊ฝƒ / `smoke`: ์—ฐ๊ธฐ)
22
+ * **๋ฐ์ดํ„ฐ ์ •์ œ ๋ฐ ์ฆ๊ฐ• (Data Augmentation):**
23
+ * ์•ผ๊ฐ„ ๋ฐ ์˜ค์ง€ ๋“ฑ ์ €์กฐ๋„ ์ƒํ™ฉ์—์„œ์˜ ์˜ค์ž‘๋™(False Positive)์„ ์ฐจ๋‹จํ•˜๊ธฐ ์œ„ํ•ด ๋ฐ๊ธฐ ๋ณ€ํ˜•, ํ๋ฆผ(Blur), ๋ชจ์ž์ดํฌ(Mosaic) ์ฆ๊ฐ• ๊ธฐ๋ฒ•์„ ์ ์šฉํ•˜์—ฌ ๋ชจ๋ธ์˜ ๊ฐ•๊ฑด์„ฑ(Robustness) ํ™•๋ณด
24
+ * ์—ฃ์ง€ ๋””๋ฐ”์ด์Šค์˜ I/O ๋ฒ„์Šค ๋Œ€์—ญํญ ๋ถ€ํ•˜๋ฅผ ๊ฒฝ๊ฐํ•˜๊ธฐ ์œ„ํ•ด ์ž…๋ ฅ ํ•ด์ƒ๋„๋ฅผ 320x240 ๋ฐ 640x480 ํˆฌ ํŠธ๋ž™ ๊ทœ๊ฒฉ์œผ๋กœ ์Šค์ผ€์ผ๋ง ์ „์ฒ˜๋ฆฌ ์ˆ˜ํ–‰
25
 
26
+ ## 2. ๋ชจ๋ธ ์„ฑ๋Šฅ (Evaluation Metrics)
27
 
28
+ | ํ‰๊ฐ€ ์ง€ํ‘œ | ํŒŒ์ดํ† ์น˜ (.pt) ์›๋ณธ | ONNX ๊ฒฝ๋Ÿ‰ ๊ฐ€์† ๊ทœ๊ฒฉ | ๋น„๊ณ  (๋ผ์ฆˆ๋ฒ ๋ฆฌํŒŒ์ด 5 CPU ๊ธฐ์ค€) |
29
  | :--- | :---: | :---: | :--- |
30
+ | **mAP50 (์ „์ฒด ์ •ํ™•๋„)** | 84.5% | 83.9% | ํฌ๋งท ๋ณ€ํ™˜์— ๋”ฐ๋ฅธ ์ •ํ™•๋„ ์†์‹ค 0.6% ๋ฏธ๋งŒ ๋ฐฉ์–ด |
31
  | **mAP50-95** | 0.521 | 0.518 | - |
32
+ | **์ถ”๋ก  ์†๋„ (Latency)** | ์•ฝ 350ms | **์•ฝ 45ms** | ONNX ๋ณ€ํ™˜ ํ›„ ์‹ค์‹œ๊ฐ„์„ฑ(20 FPS ์ด์ƒ) ์ˆ˜๋ ด |
33
 
34
+ ## 3. ๋ชจ๋ธ ํ•™์Šต ๊ณผ์ • (Model Training Process)
35
+ * **ํ•™์Šต ์ธํ”„๋ผ:** ๊ณ ์„ฑ๋Šฅ ์™ธ์žฅ GPU(RTX 5070 Ti, 32GB RAM) ํ™˜๊ฒฝ ๊ธฐ๋ฐ˜ ๋กœ์ปฌ ๊ฐ€์† ๋นŒ๋“œ ๊ตฌ๋™
36
+ * **๊ธฐ๋ฐ˜ ์•„ํ‚คํ…์ฒ˜:** 3.2M ๊ฐ€๋ฒผ์šด ํŒŒ๋ผ๋ฏธํ„ฐ ๊ตฌ์กฐ๋ฅผ ๊ฐ€์ง„ `YOLOv8n`์„ ๋ฐฑ๋ณธ(Backbone)์œผ๋กœ ์ฑ„ํƒํ•˜์—ฌ ์ž„๋ฒ ๋””๋“œ CPU ๊ฐ€๋™ ๋Œ€์—ญํญ ์‚ฌ์ „ ํ™•๋ณด
37
+ * **ํ•˜์ดํผํŒŒ๋ผ๋ฏธํ„ฐ ์„ค์ •:**
38
 
39
  | ํ•ญ๋ชฉ | ์„ค์ •๊ฐ’ | ๋น„๊ณ  |
40
  | :--- | :---: | :--- |
 
 
41
  | **Epochs** | 50 | - |
42
+ | **Batch Size** | 32 | ํ•˜๋“œ์›จ์–ด VRAM ์ตœ์ ํ™” ํฌ๊ธฐ |
43
  | **Optimizer** | AdamW | - |
44
+ | **Learning Rate** | 1e-3 | ์ดˆ๊ธฐ ํ•™์Šต๋ฅ  ์ง€์ • |
45
+ | **Augmentation** | Mosaic (1.0), Blur (0.2) | ๊ฐ€ํ˜น ํ™˜๊ฒฝ ์˜ค์ž‘๋™ ์ฐจ๋‹จ์šฉ |
46
 
47
+ ## 4. ๊ฐœ๋ฐœ ์‹œํ–‰์ฐฉ์˜ค ๋ฐ ํŠธ๋Ÿฌ๋ธ”์ŠˆํŒ… (Trials & Errors)
48
 
49
+ ์ž„๋ฒ ๋””๋“œ ์—ฃ์ง€ AI ์‹œ์Šคํ…œ ๊ตฌํ˜„ ์ค‘ ๋ฐœ์ƒํ•œ ๋ฌผ๋ฆฌ/์†Œํ”„ํŠธ์›จ์–ด ๋ ˆ์ด์–ด์˜ ๋ณ‘๋ชฉ ํ˜„์ƒ๊ณผ ํ•ด๊ฒฐ ๋ฆฌํฌํŠธ์ž…๋‹ˆ๋‹ค.
50
+
51
+ ### โ‘  PyTorch ์›์‹œ ๋ชจ๋ธ(.pt) ๊ตฌ๋™ ์‹œ ๋ ˆ์ดํ„ด์‹œ ์ €ํ•˜
52
+ * **๋ฌธ์ œ ์ƒํ™ฉ:** ํ•™์Šต ์™„๋ฃŒ๋œ `best.pt` ๊ฐ€์ค‘์น˜๋ฅผ ๋ผ์ฆˆ๋ฒ ๋ฆฌํŒŒ์ด 5 CPU ๋‹จ๋… ํ™˜๊ฒฝ์—์„œ ์ถ”๋ก ํ–ˆ์„ ๋•Œ ํ”„๋ ˆ์ž„ ์ง€์—ฐ์ด ์•ฝ 350ms(3 FPS ๋ฏธ๋งŒ)๊นŒ์ง€ ๋Š˜์–ด๋‚˜ ์‹ค์‹œ๊ฐ„ ํ™”์žฌ ํƒ์ง€๊ฐ€ ๋ถˆ๊ฐ€๋Šฅํ•œ ๋ณ‘๋ชฉ ์ง๋ฉด.
53
+ * **ํ•ด๊ฒฐ ์กฐ์น˜:** ์ •์  ์—ฐ์‚ฐ ๊ทธ๋ž˜ํ”„ ๊ตฌ์กฐ๋ฅผ ๊ฐ€์ง„ `ONNX` ํฌ๋งท์œผ๋กœ ๋ชจ๋ธ์„ ์ต์ŠคํฌํŠธ(`format=onnx`, `imgsz=320`)ํ•˜๊ณ , ํŒŒ์ด์ฌ ๋ฐฑ์—”๋“œ์— `onnxruntime` ๊ฐ€์† ํ”Œ๋Ÿฌ๊ทธ์ธ์„ ๊ฒฐํ•ฉํ•˜์—ฌ ์ถ”๋ก  ๋ ˆ์ดํ„ด์‹œ๋ฅผ 45ms(22 FPS ์ด์ƒ) ์ˆ˜์ค€์œผ๋กœ ๋น„์•ฝ์ ์œผ๋กœ ๋‹จ์ถ•ํ•จ.
54
+
55
+ ### โ‘ก Linux V4L2 ์žฅ์น˜ ์ฑ„๋„ ํƒ€์ž„์•„์›ƒ (`select() timeout`)
56
+ * **๋ฌธ์ œ ์ƒํ™ฉ:** ์ตœ์‹  ๋ผ์ฆˆ๋ฒ ๋ฆฌํŒŒ์ด OS(Bookworm) ์ปค๋„์—์„œ OpenCV๋กœ ์›น์บ ์„ ํ˜ธ์ถœํ•  ๋•Œ ๋ฏธ๋””์–ด ์ปจํŠธ๋กค๋Ÿฌ ๊ฐ€์† ์Šคํƒ์ด `/dev/video0` ์ž์›์„ ๋…์  ์ ์œ (Lock)ํ•˜์—ฌ `select() timeout`๊ณผ ํ•จ๊ป˜ ํ•˜๋“œ์›จ์–ด ์ข€๋น„ ๋ฝ ํ˜„์ƒ ๋ฐœ์ƒ.
57
+ * **ํ•ด๊ฒฐ ์กฐ์น˜:** OpenCV ์นด๋ฉ”๋ผ ๊ฐœ์‹œ ์ฝ”๋“œ๋‹จ์— V4L2 ๋ฐฑ์—”๋“œ๋ฅผ ๋ช…์‹œ์ ์œผ๋กœ ์ง€์ •(`cv2.VideoCapture(0, cv2.CAP_V4L2)`)ํ•˜๊ณ , ์ฃผํ”ผํ„ฐ ์„œ๋ฒ„ ๊ตฌ๋™ ์‹œ ๋ฆฌ๋ˆ…์Šค ์—๋ฎฌ๋ ˆ์ด์…˜ ํ˜ธํ™˜ ๋ ˆ์ด์–ด ํ™˜๊ฒฝ ๋ณ€์ˆ˜์ธ `LD_PRELOAD=/usr/lib/aarch64-linux-gnu/libv4l/v4l1compat.so`๋ฅผ ํ”„๋ฆฌ๋กœ๋“œ ๋ž˜ํ•‘ํ•˜์—ฌ ์ปค๋„ ์ ์œ  ์ถฉ๋Œ์„ ์šฐํšŒํ•จ.
58
+
59
+ ### โ‘ข USB ๋ฒ„์Šค ๋Œ€์—ญํญ ์ดˆ๊ณผ ๋ฐ ํ”ฝ์…€ ์˜ค์—ผ (`error dequeuing buf`)
60
+ * **๋ฌธ์ œ ์ƒํ™ฉ:** ์••์ถ• ์ฝ”๋ฑ ๊ธฐ๋Šฅ์ด ์—†๋Š” ์ผ๋ฐ˜ ์›น์บ ์˜ ์›์‹œ ๋ฐ์ดํ„ฐ(Raw YUYV)๋ฅผ 640x480 ํ•ด์ƒ๋„๋กœ ์ˆ˜์‹  ์‹œ, ๋ผ์ฆˆ๋ฒ ๋ฆฌํŒŒ์ด USB ๋Œ€์—ญํญ ํ•œ๊ณ„๋กœ ํ”„๋ ˆ์ž„ ๋ฒ„ํผ๊ฐ€ ๋ˆ„์ˆ˜๋˜์–ด ํ™”๋ฉด์ด ์ง€์งˆ๊ฑฐ๋ฆฌ๊ฑฐ๋‚˜ ๊ฒ€์€์ƒ‰(Black Screen)์œผ๋กœ ์ฃฝ๋Š” ํ˜„์ƒ ๋ฐœ์ƒ.
61
+ * **ํ•ด๊ฒฐ ์กฐ์น˜:** ์›น์บ ์„ ์ „๋ ฅ ๋ฐ ์ „์†ก ํšจ์œจ์ด ๋†’์€ **ํŒŒ๋ž€์ƒ‰ USB 3.0 ํฌํŠธ**๋กœ ๋ฌผ๋ฆฌ์  ์ด๋™ ์ •๋ ฌ์„ ์ˆ˜ํ–‰ํ•œ ํ›„, ์ฝ”๋“œ ๋ ˆ๋ฒจ์—์„œ ์ž…๋ ฅ ํ•ด์ƒ๋„๋ฅผ `320x240`์œผ๋กœ ๋Œ€ํญ ๋‚ฎ์ถ”๊ณ  ๊ณ ์† ์••์ถ• ์ŠคํŠธ๋ฆฌ๋ฐ ํฌ๋งท(`MJPG`) ์ฝ”๋ฑ ์ง€์ •์„ ๊ฐ•์ œํ™”ํ•˜์—ฌ ๋ฐ์ดํ„ฐ ๋ฒ„์Šค ํ†ต๋กœ๋ฅผ ๋ณต๊ตฌํ•จ.
62
+
63
+ ### โ‘ฃ ์ฃผํ”ผํ„ฐ ๋„คํŠธ์›Œํฌ ์›น ์†Œ์ผ“ ๋ถ•๊ดด ํฌ๋ž˜์‹œ (`ZMQError`)
64
+ * **๋ฌธ์ œ ์ƒํ™ฉ:** ์ถ”๋ก  `while` ๋ฃจํ”„๊ฐ€ ์ดˆ๋‹น ์ˆ˜์‹ญ ์žฅ์˜ ์ด๋ฏธ์ง€๋ฅผ ์ง€์—ฐ ์—†์ด ์ฃผํ”ผํ„ฐ ์ธ๋ผ์ธ ์œ„์ ฏ(`ipywidgets`) ํ™”๋ฉด์œผ๋กœ ๋ฐ€์–ด ๋„ฃ์œผ๋ฉด์„œ ํ†ต์‹  ๋ฒ„ํผ ์˜ค๋ฒ„ํ”Œ๋กœ์šฐ๋กœ ์ธํ•ด ์ฃผํ”ผํ„ฐ ์ปค๋„์ด ์ •์ง€ํ•˜๊ณ  ์†Œ์ผ“์ด ํ„ฐ์ง€๋Š” ํ˜„์ƒ ๋ฐœ์ƒ.
65
+ * **ํ•ด๊ฒฐ ์กฐ์น˜:** ์ด๋ฏธ์ง€ ๋ณ€ํ™˜ ๋ฐ ์ „์†ก ๋ฃจํ‹ด ์งํ›„ ๋ฏธ์„ธ ์œ ํœด ์—ฐ์‚ฐ ํƒ€์ž„์ธ `time.sleep(0.04)` ์ง€์—ฐ ๋ฒ„ํผ ๋กœ์ง์„ ์•ˆ์ฐฉ์‹œ์ผœ ์ดˆ๋‹น ์ „์†ก๋ฅ ์„ 20~25ํ”„๋ ˆ์ž„ ์ˆ˜์ค€์œผ๋กœ ์•ˆ์ •ํ™”ํ•จ์œผ๋กœ์จ ์—ฐ์† ๊ตฌ๋™ ์•ˆ์ „์„ฑ์„ ํ™•๋ณดํ•จ.
66
+
67
+ ## 5. ์‚ฌ์šฉ ๋ฐฉ๋ฒ• (Inference Code)
68
 
69
  ```python
70
  import cv2
 
75
  import time
76
 
77
  def main():
 
78
  model_path = "best.onnx"
79
  model = YOLO(model_path, task='detect')
80
 
81
+ # V4L2 ๊ฐ€์† ๋ฐฑ์—”๋“œ ๋งคํ•‘
82
  cap = cv2.VideoCapture(0, cv2.CAP_V4L2)
 
 
83
  cap.set(cv2.CAP_PROP_FRAME_WIDTH, 320)
84
  cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 240)
85
  cap.set(cv2.CAP_PROP_BUFFERSIZE, 1)
86
 
87
+ time.sleep(1) # ํ•˜๋“œ์›จ์–ด ์•ˆ์ •ํ™” ๋Œ€๊ธฐ
88
  if not cap.isOpened():
89
  print("[์˜ค๋ฅ˜] ์นด๋ฉ”๋ผ ์žฅ์น˜๋ฅผ ํ™œ์„ฑํ™”ํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.")
90
  return
91
 
 
92
  image_widget = widgets.Image(format='jpeg', width=320, height=240)
93
  display(image_widget)
94
 
 
98
  if not success or frame is None:
99
  continue
100
 
101
+ # ONNX ๊ฐ€์† ์ถ”๋ก  ๊ตฌ๋™ (imgsz ์ผ์น˜)
102
  results = model(frame, imgsz=320, stream=True)
103
  for r in results:
104
  annotated_frame = r.plot()
105
 
106
+ # JPEG ์••์ถ• ํ›„ ์ฃผํ”ผํ„ฐ ๋ Œ๋”๋ง ์˜์—ญ ์—…๋ฐ์ดํŠธ
107
  ret, jpeg = cv2.imencode('.jpg', annotated_frame)
108
  if ret:
109
  image_widget.value = jpeg.tobytes()
110
 
111
+ # ZMQ ๊ณผ๋ถ€ํ•˜ ๋ฐฉ์ง€์šฉ micro-delay
112
  time.sleep(0.04)
113
 
114
  except KeyboardInterrupt:
 
122
  main()
123
  ```
124
 
125
+ ## 6. ์ž…์ถœ๋ ฅ ํ˜•์‹ (Input / Output Format)
126
 
127
+ ``` Plaintext
128
+ ์ž…๋ ฅ(Input): ์‹ค์‹œ๊ฐ„ ์ž„๋ฒ ๋””๋“œ ์นด๋ฉ”๋ผ ๋น„๋””์˜ค ํ”„๋ ˆ์ž„ (320x240 RGB Image)
 
 
129
  ์ถœ๋ ฅ(Output):
130
+ - ๋ถˆ๊ฝƒ ๋ฐ ์—ฐ๊ธฐ ์˜์—ญ ๋ฐ”์šด๋”ฉ ๋ฐ•์Šค(Bounding Box) ์‹œ๊ฐํ™” ํˆฌ์‚ฌ
131
+ - ํƒ์ง€ ํด๋ž˜์Šค ๋ ˆ์ด๋ธ” ๋งคํ•‘: [flame, smoke]
132
+ - ๊ฐ์ฒด๋ณ„ ์ถ”๋ก  ์‹ ๋ขฐ๋„ ์ˆ˜์น˜ ์ถœ๋ ฅ (Confidence Score: 0.0 ~ 1.0)
133
+ ```
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
134
 
135
  ## 7. ๋กœ์ปฌ ๋™๊ธฐํ™” ๊ฐ€์ค‘์น˜ ๋‹ค์šด๋กœ๋“œ CLI
 
136
 
137
+ ``` Bash
138
+ huggingface-cli download firedetection/fire_detection_yolov8n --local-dir ./model
139
+ ```