feat: Integrate YOLOv8 model, rebrand to VIDraft/Shrimp, remove confidential info
Browse files- Add locally trained YOLOv8 model (yolov8m_shrimp2) as default detection option
- Replace all Roboflow references with VIDraft/Shrimp branding in UI
- Remove confidential performance metrics and optimization details from UI
- Add example images to auto-detection and demo tabs for quick testing
- Implement file filtering for labeling tool (exclude -1, -2 suffixed duplicates)
- Improve app startup time with lazy loading of heavy ML modules
- Update documentation and test scripts
๐ค Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- docs/bugfix_cache_key.md +228 -0
- docs/efficient_training_strategy.md +370 -0
- docs/evaluation_report.md +317 -0
- docs/filter_validation_methodology.md +589 -0
- docs/gradio_warnings.md +70 -0
- docs/ground_truth_labeling_guide.md +460 -0
- docs/image_filtering_and_caching.md +526 -0
- docs/labeling_quick_guide.md +77 -0
- docs/labeling_tool_improvements.md +272 -0
- docs/labeling_tool_v2_improvements.md +449 -0
- docs/performance_optimization.md +467 -0
- docs/roboflow_training_guide.md +369 -0
- docs/yolo_training_results.md +268 -0
- evaluate_yolo.py +239 -0
- ground_truth.json +1215 -0
- interactive_validation.py +101 -31
- labeling_tool.py +650 -0
- problem.txt +20 -10
- shrimp_detection_app.py +1150 -0
- test_quantitative_evaluation.py +10 -4
- test_visual_validation.py +103 -28
- train_yolo.py +127 -0
docs/bugfix_cache_key.md
ADDED
|
@@ -0,0 +1,228 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# ๋ฒ๊ทธ ์์ : ๋ฐ์ค ์ ํ ์ KeyError
|
| 2 |
+
|
| 3 |
+
## ๐ ๋ฌธ์
|
| 4 |
+
|
| 5 |
+
**์ฆ์:**
|
| 6 |
+
- ๋ฐ์ค ํด๋ฆญ ์ ์๋ฌ ๋ฐ์
|
| 7 |
+
- `KeyError: '250818_01.jpg'`
|
| 8 |
+
|
| 9 |
+
**์๋ฌ ๋ก๊ทธ:**
|
| 10 |
+
```python
|
| 11 |
+
Traceback (most recent call last):
|
| 12 |
+
File "D:\Project\VIDraft\Shrimp\labeling_tool.py", line 219, in toggle_selection
|
| 13 |
+
detections = current_data['detections'][filename]
|
| 14 |
+
~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^
|
| 15 |
+
KeyError: '250818_01.jpg'
|
| 16 |
+
```
|
| 17 |
+
|
| 18 |
+
---
|
| 19 |
+
|
| 20 |
+
## ๐ ์์ธ ๋ถ์
|
| 21 |
+
|
| 22 |
+
**v2์์ ์ถ๊ฐ๋ ๊ธฐ๋ฅ:**
|
| 23 |
+
- ์ ๋ขฐ๋ ์๊ณ๊ฐ ์กฐ์ ๊ธฐ๋ฅ
|
| 24 |
+
- ์ ๋ขฐ๋๋ณ ์บ์ฑ ์ ๋ต
|
| 25 |
+
|
| 26 |
+
**์บ์ ํค ๋ณ๊ฒฝ:**
|
| 27 |
+
```python
|
| 28 |
+
# Before (v1)
|
| 29 |
+
current_data['detections'][filename] = detections
|
| 30 |
+
|
| 31 |
+
# After (v2)
|
| 32 |
+
cache_key = f"{filename}_{current_data['confidence_threshold']}"
|
| 33 |
+
current_data['detections'][cache_key] = detections
|
| 34 |
+
```
|
| 35 |
+
|
| 36 |
+
**๋ฌธ์ ์ :**
|
| 37 |
+
- `load_image()`์์๋ ์ ๋ขฐ๋๊ฐ ํฌํจ๋ ์บ์ ํค ์ฌ์ฉ
|
| 38 |
+
- `toggle_selection()`์์๋ ํ์ผ๋ช
๋ง ์ฌ์ฉ
|
| 39 |
+
- **์บ์ ํค ๋ถ์ผ์น๋ก KeyError ๋ฐ์**
|
| 40 |
+
|
| 41 |
+
---
|
| 42 |
+
|
| 43 |
+
## โ
ํด๊ฒฐ ๋ฐฉ๋ฒ
|
| 44 |
+
|
| 45 |
+
### ์์ 1: `toggle_selection()` ํจ์
|
| 46 |
+
|
| 47 |
+
**Before:**
|
| 48 |
+
```python
|
| 49 |
+
def toggle_selection(evt: gr.SelectData):
|
| 50 |
+
filename = current_data['images'][current_data['current_idx']]
|
| 51 |
+
detections = current_data['detections'][filename] # โ ์๋ชป๋ ํค
|
| 52 |
+
selections = current_data['selections'][filename]
|
| 53 |
+
```
|
| 54 |
+
|
| 55 |
+
**After:**
|
| 56 |
+
```python
|
| 57 |
+
def toggle_selection(evt: gr.SelectData):
|
| 58 |
+
filename = current_data['images'][current_data['current_idx']]
|
| 59 |
+
cache_key = f"{filename}_{current_data['confidence_threshold']}" # โ
์ฌ๋ฐ๋ฅธ ํค
|
| 60 |
+
detections = current_data['detections'][cache_key]
|
| 61 |
+
selections = current_data['selections'][filename]
|
| 62 |
+
```
|
| 63 |
+
|
| 64 |
+
---
|
| 65 |
+
|
| 66 |
+
### ์์ 2: `save_current_selection()` ํจ์
|
| 67 |
+
|
| 68 |
+
**Before:**
|
| 69 |
+
```python
|
| 70 |
+
def save_current_selection():
|
| 71 |
+
filename = current_data['images'][current_data['current_idx']]
|
| 72 |
+
folder = current_data['folder']
|
| 73 |
+
selections = current_data['selections'].get(filename, [])
|
| 74 |
+
detections = current_data['detections'][filename] # โ ์๋ชป๋ ํค
|
| 75 |
+
```
|
| 76 |
+
|
| 77 |
+
**After:**
|
| 78 |
+
```python
|
| 79 |
+
def save_current_selection():
|
| 80 |
+
filename = current_data['images'][current_data['current_idx']]
|
| 81 |
+
folder = current_data['folder']
|
| 82 |
+
selections = current_data['selections'].get(filename, [])
|
| 83 |
+
cache_key = f"{filename}_{current_data['confidence_threshold']}" # โ
์ฌ๋ฐ๋ฅธ ํค
|
| 84 |
+
detections = current_data['detections'][cache_key]
|
| 85 |
+
```
|
| 86 |
+
|
| 87 |
+
---
|
| 88 |
+
|
| 89 |
+
## ๐ ์บ์ ํค ์ฌ์ฉ ๊ท์น
|
| 90 |
+
|
| 91 |
+
### ์ฌ๋ฐ๋ฅธ ์ฌ์ฉ ํจํด
|
| 92 |
+
|
| 93 |
+
**๊ฒ์ถ ๊ฒฐ๊ณผ ์ ์ฅ/์กฐํ ์:**
|
| 94 |
+
```python
|
| 95 |
+
# ์ ๋ขฐ๋๊ฐ ํฌํจ๋ ์บ์ ํค ์ฌ์ฉ
|
| 96 |
+
cache_key = f"{filename}_{current_data['confidence_threshold']}"
|
| 97 |
+
current_data['detections'][cache_key]
|
| 98 |
+
```
|
| 99 |
+
|
| 100 |
+
**์ ํ ์ํ ์ ์ฅ/์กฐํ ์:**
|
| 101 |
+
```python
|
| 102 |
+
# ํ์ผ๋ช
๋ง ์ฌ์ฉ (์ ๋ขฐ๋์ ๋ฌด๊ด)
|
| 103 |
+
current_data['selections'][filename]
|
| 104 |
+
```
|
| 105 |
+
|
| 106 |
+
**์ด์ :**
|
| 107 |
+
- **๊ฒ์ถ ๊ฒฐ๊ณผ**: ์ ๋ขฐ๋์ ๋ฐ๋ผ ๋ค๋ฆ โ ์ ๋ขฐ๋ ํฌํจ ์บ์ ํค
|
| 108 |
+
- **์ ํ ์ํ**: ์ฌ์ฉ์ ์ ํ์ ์ ๋ขฐ๋์ ๋ฌด๊ด โ ํ์ผ๋ช
๋ง
|
| 109 |
+
|
| 110 |
+
---
|
| 111 |
+
|
| 112 |
+
## ๐งช ํ
์คํธ ์๋๋ฆฌ์ค
|
| 113 |
+
|
| 114 |
+
### ์๋๋ฆฌ์ค 1: ๊ธฐ๋ณธ ์ฌ์ฉ
|
| 115 |
+
```
|
| 116 |
+
1. ์ด๋ฏธ์ง ๋ก๋ (์ ๋ขฐ๋ 0.2)
|
| 117 |
+
โ cache_key = "250818_01.jpg_0.2"
|
| 118 |
+
2. ๋ฐ์ค ํด๋ฆญ
|
| 119 |
+
โ ๊ฐ์ cache_key ์ฌ์ฉ
|
| 120 |
+
โ โ
์ ์ ๋์
|
| 121 |
+
```
|
| 122 |
+
|
| 123 |
+
### ์๋๋ฆฌ์ค 2: ์ ๋ขฐ๋ ๋ณ๊ฒฝ
|
| 124 |
+
```
|
| 125 |
+
1. ์ด๋ฏธ์ง ๋ก๋ (์ ๋ขฐ๋ 0.2)
|
| 126 |
+
โ cache_key = "250818_01.jpg_0.2"
|
| 127 |
+
2. ์ฌ๋ผ์ด๋ ์กฐ์ (0.15)
|
| 128 |
+
โ cache_key = "250818_01.jpg_0.15" (์ฌ๊ฒ์ถ)
|
| 129 |
+
3. ๋ฐ์ค ํด๋ฆญ
|
| 130 |
+
โ ํ์ฌ ์ ๋ขฐ๋์ cache_key ์ฌ์ฉ
|
| 131 |
+
โ โ
์ ์ ๋์
|
| 132 |
+
```
|
| 133 |
+
|
| 134 |
+
### ์๋๋ฆฌ์ค 3: ์ ํ ํ ์ ๋ขฐ๋ ๋ณ๊ฒฝ
|
| 135 |
+
```
|
| 136 |
+
1. ์ด๋ฏธ์ง ๋ก๋ (์ ๋ขฐ๋ 0.2), ๋ฐ์ค 2๊ฐ ์ ํ
|
| 137 |
+
โ selections["250818_01.jpg"] = [0, 1]
|
| 138 |
+
2. ์ฌ๋ผ์ด๋ ์กฐ์ (0.15)
|
| 139 |
+
โ ๋ฐ์ค๊ฐ ๋ ๋ง์ด ํ์๋จ
|
| 140 |
+
โ selections๋ ์ ์ง๋จ (ํ์ผ๋ช
ํค)
|
| 141 |
+
3. ์ถ๊ฐ ๋ฐ์ค ์ ํ
|
| 142 |
+
โ selections["250818_01.jpg"] = [0, 1, 2, 3]
|
| 143 |
+
โ โ
์ ์ ๋์ (์ด์ ์ ํ ์ ์ง)
|
| 144 |
+
```
|
| 145 |
+
|
| 146 |
+
---
|
| 147 |
+
|
| 148 |
+
## โ ๏ธ ์ฃผ์์ฌํญ
|
| 149 |
+
|
| 150 |
+
### ์บ์ ๊ด๋ฆฌ
|
| 151 |
+
|
| 152 |
+
**๋ฉ๋ชจ๋ฆฌ ์ฌ์ฉ:**
|
| 153 |
+
```python
|
| 154 |
+
# ์ ๋ขฐ๋๋ฅผ ์ฌ๋ฌ ๋ฒ ๋ณ๊ฒฝํ๋ฉด ์บ์๊ฐ ๋์ ๋จ
|
| 155 |
+
current_data['detections'] = {
|
| 156 |
+
"250818_01.jpg_0.2": [...], # 10๊ฐ ๋ฐ์ค
|
| 157 |
+
"250818_01.jpg_0.15": [...], # 15๊ฐ ๋ฐ์ค
|
| 158 |
+
"250818_01.jpg_0.3": [...], # 5๊ฐ ๋ฐ์ค
|
| 159 |
+
}
|
| 160 |
+
```
|
| 161 |
+
|
| 162 |
+
**์ํฅ:**
|
| 163 |
+
- ์ฅ์ : ๊ฐ์ ์ ๋ขฐ๋๋ก ๋์๊ฐ๋ฉด ์ฌ๊ฒ์ถ ๋ถํ์
|
| 164 |
+
- ๋จ์ : ๋ฉ๋ชจ๋ฆฌ ์ฌ์ฉ๋ ์ฆ๊ฐ
|
| 165 |
+
|
| 166 |
+
**๊ถ์ฅ ์ฌํญ:**
|
| 167 |
+
- ์ ๋ขฐ๋๋ ํ์ํ ๋๋ง ์กฐ์
|
| 168 |
+
- ๊ฐ์ ์ด๋ฏธ์ง์์ ๋๋ฌด ๋ง์ ์ ๋ขฐ๋ ์๋ํ์ง ๋ง ๊ฒ
|
| 169 |
+
|
| 170 |
+
---
|
| 171 |
+
|
| 172 |
+
### ์ ํ ์ํ ๋ณด์กด
|
| 173 |
+
|
| 174 |
+
**์ ๋ขฐ๋ ๋ณ๊ฒฝ ์ ์ ํ ์ ์ง:**
|
| 175 |
+
```python
|
| 176 |
+
# ์ ํ์ ํ์ผ๋ช
ํค๋ก ์ ์ฅ๋๋ฏ๋ก
|
| 177 |
+
# ์ ๋ขฐ๋๋ฅผ ๋ณ๊ฒฝํด๋ ์ ํ ์ํ๋ ์ ์ง๋จ
|
| 178 |
+
selections["250818_01.jpg"] = [0, 1, 2] # ์ ์ง๋จ
|
| 179 |
+
```
|
| 180 |
+
|
| 181 |
+
**์ฃผ์:**
|
| 182 |
+
- ์ ๋ขฐ๋ ๋ณ๊ฒฝ ์ ๋ฐ์ค ์์๊ฐ ๋ฐ๋ ์ ์์
|
| 183 |
+
- ์ ํํ ์ธ๋ฑ์ค๊ฐ ์๋ก์ด ๋ฐ์ค์ ๋ง์ง ์์ ์ ์์
|
| 184 |
+
- **ํด๊ฒฐ:** ์ ํ ์ด๊ธฐํ ํ ์ฌ์ ํ ๊ถ์ฅ
|
| 185 |
+
|
| 186 |
+
---
|
| 187 |
+
|
| 188 |
+
## ๐ ๋ฐฐํฌ ์ํ
|
| 189 |
+
|
| 190 |
+
**๋ฒ์ :** v2.0.1 (๋ฒ๊ทธ ์์ )
|
| 191 |
+
|
| 192 |
+
**์์ ํ์ผ:**
|
| 193 |
+
- `labeling_tool.py` - `toggle_selection()`, `save_current_selection()`
|
| 194 |
+
|
| 195 |
+
**์๋ฒ ์ํ:**
|
| 196 |
+
- ํฌํธ: 7862
|
| 197 |
+
- PID: 34752
|
| 198 |
+
- ์ํ: โ
์คํ ์ค
|
| 199 |
+
|
| 200 |
+
**์ ์:**
|
| 201 |
+
```
|
| 202 |
+
http://localhost:7862
|
| 203 |
+
```
|
| 204 |
+
|
| 205 |
+
---
|
| 206 |
+
|
| 207 |
+
## ๐ ์ํฅ ๋ฒ์
|
| 208 |
+
|
| 209 |
+
**์์ ๋ ํจ์:**
|
| 210 |
+
1. `toggle_selection()` - ๋ฐ์ค ํด๋ฆญ ์ ํธ์ถ
|
| 211 |
+
2. `save_current_selection()` - ๋ค์/์๋ฃ ๋ฒํผ ์ ํธ์ถ
|
| 212 |
+
|
| 213 |
+
**์ํฅ๋ฐ๋ ๊ธฐ๋ฅ:**
|
| 214 |
+
- โ
๋ฐ์ค ์ ํ/ํด์
|
| 215 |
+
- โ
Ground Truth ์ ์ฅ
|
| 216 |
+
- โ
์ ๋ขฐ๋ ์กฐ์ ํ ์์
|
| 217 |
+
|
| 218 |
+
**ํ
์คํธ ์๋ฃ:**
|
| 219 |
+
- [x] ๊ธฐ๋ณธ ๋ฐ์ค ์ ํ
|
| 220 |
+
- [x] ์ ๋ขฐ๋ ๋ณ๊ฒฝ ํ ๋ฐ์ค ์ ํ
|
| 221 |
+
- [x] ๋ค์ ์ด๋ฏธ์ง ์ด๋
|
| 222 |
+
- [x] Ground Truth ์ ์ฅ
|
| 223 |
+
|
| 224 |
+
---
|
| 225 |
+
|
| 226 |
+
**์์ ๋ ์ง:** 2025-11-10
|
| 227 |
+
**์์ฑ์:** Claude Code
|
| 228 |
+
**ํ
์คํธ ์ํ:** โ
๊ฒ์ฆ ์๋ฃ
|
docs/efficient_training_strategy.md
ADDED
|
@@ -0,0 +1,370 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# ์์ฐ ๊ฒ์ถ ๋ชจ๋ธ ํจ์จ์ ํ์ต ์ ๋ต
|
| 2 |
+
|
| 3 |
+
## ๐ ํ์ฌ ์ํฉ ๋ถ์
|
| 4 |
+
|
| 5 |
+
### ๋ณด์ ๋ฐ์ดํฐ
|
| 6 |
+
- **GT ๋ฐ์ดํฐ**: 50๊ฐ ์ด๋ฏธ์ง (42๊ฐ ์ค์ ํ์ผ, 40๊ฐ ๋ผ๋ฒจ๋ง ์๋ฃ)
|
| 7 |
+
- **GT ๋ฐ์ค ์**: 50๊ฐ
|
| 8 |
+
- **๋ฐ์ดํฐ ํ์ง**: ์๋ ๋ผ๋ฒจ๋ง์ผ๋ก ๋์ ์ ํ๋
|
| 9 |
+
- **ํด๋**: 250818, 250820, 250825
|
| 10 |
+
|
| 11 |
+
### ํ์ฌ ์ฑ๋ฅ (RT-DETR + Filter)
|
| 12 |
+
- **Precision**: 44.2%
|
| 13 |
+
- **Recall**: 94.0%
|
| 14 |
+
- **F1 Score**: 56.1%
|
| 15 |
+
- **์ฃผ์ ๋ฌธ์ **: False Positive ๊ณผ๋ค (FP ๋ฐ์ค๋ GT ๋๋น 17.8๋ฐฐ ํฐ ๊ฒฝํฅ)
|
| 16 |
+
|
| 17 |
+
---
|
| 18 |
+
|
| 19 |
+
## ๐ฏ ํ์ต ๋ชฉํ
|
| 20 |
+
|
| 21 |
+
**ํต์ฌ**: RT-DETR ๋ชจ๋ธ์ ์์ฐ ๋๋ฉ์ธ์ Fine-tuningํ์ฌ ์ด๊ธฐ ๊ฒ์ถ ์ ํ๋ ํฅ์
|
| 22 |
+
|
| 23 |
+
**๊ธฐ๋ ํจ๊ณผ**:
|
| 24 |
+
1. RT-DETR ์์ฒด์ False Positive ๊ฐ์
|
| 25 |
+
2. ํํฐ ์์กด๋ ๊ฐ์ โ ๋ ์์ ์ ์ธ ๊ฒ์ถ
|
| 26 |
+
3. ์์ฐ ํํ/์์ ํน์ฑ ํ์ต์ผ๋ก confidence ํฅ์
|
| 27 |
+
|
| 28 |
+
---
|
| 29 |
+
|
| 30 |
+
## โก ๋จ์๊ฐ ํจ์จ์ ํ์ต ๋ฐฉ๋ฒ
|
| 31 |
+
|
| 32 |
+
### ๋ฐฉ๋ฒ 1: Transfer Learning + Few-shot Fine-tuning โญ **์ถ์ฒ**
|
| 33 |
+
|
| 34 |
+
**์ฅ์ **: ์ต์ ๋ฐ์ดํฐ๋ก ๋น ๋ฅธ ์ฑ๋ฅ ํฅ์ ๊ฐ๋ฅ
|
| 35 |
+
|
| 36 |
+
**์์ ์๊ฐ**: 1-3์๊ฐ
|
| 37 |
+
|
| 38 |
+
**ํ์ ๋ฆฌ์์ค**:
|
| 39 |
+
- GPU: NVIDIA GPU (8GB+ VRAM ๊ถ์ฅ)
|
| 40 |
+
- ํ๋ ์์ํฌ: PyTorch
|
| 41 |
+
- ํ์ต ๋ฐ์ดํฐ: ํ์ฌ 50๊ฐ GT๋ก ์ถฉ๋ถ
|
| 42 |
+
|
| 43 |
+
**๊ตฌํ ๋ฐฉ๋ฒ**:
|
| 44 |
+
|
| 45 |
+
#### 1๋จ๊ณ: ๋ฐ์ดํฐ ์ค๋น (30๋ถ)
|
| 46 |
+
```bash
|
| 47 |
+
# Ground Truth๋ฅผ COCO format์ผ๋ก ๋ณํ
|
| 48 |
+
python convert_gt_to_coco.py
|
| 49 |
+
```
|
| 50 |
+
|
| 51 |
+
**๋๋ ํ ๋ฆฌ ๊ตฌ์กฐ**:
|
| 52 |
+
```
|
| 53 |
+
data/
|
| 54 |
+
โโโ train/
|
| 55 |
+
โ โโโ images/ # 40๊ฐ (80% split)
|
| 56 |
+
โโโ val/
|
| 57 |
+
โ โโโ images/ # 10๊ฐ (20% split)
|
| 58 |
+
โโโ annotations/
|
| 59 |
+
โโโ train.json # COCO format
|
| 60 |
+
โโโ val.json
|
| 61 |
+
```
|
| 62 |
+
|
| 63 |
+
#### 2๋จ๊ณ: RT-DETR Fine-tuning ์ค์ (15๋ถ)
|
| 64 |
+
|
| 65 |
+
**ํ์ต ์ ๋ต**:
|
| 66 |
+
- **Freeze backbone**: ์ด๊ธฐ ๋ ์ด์ด ๊ณ ์ (feature extractor)
|
| 67 |
+
- **Train head only**: Detection head๋ง ํ์ต (๋น ๋ฆ)
|
| 68 |
+
- **Small batch size**: 2-4 (๋ฉ๋ชจ๋ฆฌ ์ ์ฝ)
|
| 69 |
+
- **Few epochs**: 50-100 epochs (๊ณผ์ ํฉ ๋ฐฉ์ง)
|
| 70 |
+
|
| 71 |
+
**ํ์ดํผํ๋ผ๋ฏธํฐ**:
|
| 72 |
+
```yaml
|
| 73 |
+
model: rtdetr_r50vd
|
| 74 |
+
pretrained: true # ImageNet + COCO ์ฌ์ ํ์ต ๊ฐ์ค์น ์ฌ์ฉ
|
| 75 |
+
|
| 76 |
+
train:
|
| 77 |
+
batch_size: 4
|
| 78 |
+
epochs: 50
|
| 79 |
+
learning_rate: 0.0001 # ๋ฎ์ LR (Fine-tuning)
|
| 80 |
+
freeze_backbone: true
|
| 81 |
+
|
| 82 |
+
optimizer:
|
| 83 |
+
type: AdamW
|
| 84 |
+
weight_decay: 0.0001
|
| 85 |
+
|
| 86 |
+
augmentation:
|
| 87 |
+
# ๋ฐ์ดํฐ ๋ถ์กฑ ๋ณด์
|
| 88 |
+
horizontal_flip: 0.5
|
| 89 |
+
brightness: 0.2
|
| 90 |
+
contrast: 0.2
|
| 91 |
+
saturation: 0.2
|
| 92 |
+
```
|
| 93 |
+
|
| 94 |
+
#### 3๋จ๊ณ: ํ์ต ์คํ (1-2์๊ฐ)
|
| 95 |
+
```bash
|
| 96 |
+
# Hugging Face transformers ์ฌ์ฉ (๊ฐํธ)
|
| 97 |
+
python train_rtdetr_finetuning.py \
|
| 98 |
+
--model facebook/detr-resnet-50 \
|
| 99 |
+
--train_dir data/train \
|
| 100 |
+
--val_dir data/val \
|
| 101 |
+
--epochs 50 \
|
| 102 |
+
--batch_size 4 \
|
| 103 |
+
--lr 0.0001
|
| 104 |
+
```
|
| 105 |
+
|
| 106 |
+
#### 4๋จ๊ณ: ํ๊ฐ ๋ฐ ์ ์ฉ (30๋ถ)
|
| 107 |
+
```bash
|
| 108 |
+
# ๊ฒ์ฆ ์ธํธ์์ ์ฑ๋ฅ ํ์ธ
|
| 109 |
+
python evaluate_finetuned_model.py
|
| 110 |
+
|
| 111 |
+
# ๊ธฐ์กด ์์คํ
์ ์ ์ฉ
|
| 112 |
+
python test_quantitative_evaluation.py --use_finetuned
|
| 113 |
+
```
|
| 114 |
+
|
| 115 |
+
---
|
| 116 |
+
|
| 117 |
+
### ๋ฐฉ๋ฒ 2: YOLOv8 Few-shot Training ๐ **๊ฐ์ฅ ๋น ๋ฆ**
|
| 118 |
+
|
| 119 |
+
**์ฅ์ **:
|
| 120 |
+
- ๋งค์ฐ ๊ฐ๋จํ ํ์ต ํ์ดํ๋ผ์ธ
|
| 121 |
+
- ์๋ ๋ฐ์ดํฐ์์๋ ์ฐ์ํ ์ฑ๋ฅ
|
| 122 |
+
- ๋น ๋ฅธ ์ถ๋ก ์๋
|
| 123 |
+
|
| 124 |
+
**์์ ์๊ฐ**: 30๋ถ - 1์๊ฐ
|
| 125 |
+
|
| 126 |
+
**๊ตฌํ ๋ฐฉ๋ฒ**:
|
| 127 |
+
|
| 128 |
+
#### 1๋จ๊ณ: YOLOv8 ์ค์น
|
| 129 |
+
```bash
|
| 130 |
+
pip install ultralytics
|
| 131 |
+
```
|
| 132 |
+
|
| 133 |
+
#### 2๋จ๊ณ: ๋ฐ์ดํฐ ์ค๋น (YOLO format)
|
| 134 |
+
```
|
| 135 |
+
data/
|
| 136 |
+
โโโ images/
|
| 137 |
+
โ โโโ train/
|
| 138 |
+
โ โโโ val/
|
| 139 |
+
โโโ labels/
|
| 140 |
+
โโโ train/ # txt ํ์
|
| 141 |
+
โโโ val/
|
| 142 |
+
```
|
| 143 |
+
|
| 144 |
+
**๋ผ๋ฒจ ํ์** (๊ฐ ์ค: `class x_center y_center width height` - ์ ๊ทํ):
|
| 145 |
+
```
|
| 146 |
+
0 0.5123 0.6234 0.0823 0.1456
|
| 147 |
+
```
|
| 148 |
+
|
| 149 |
+
#### 3๋จ๊ณ: ํ์ต ์คํ
|
| 150 |
+
```python
|
| 151 |
+
from ultralytics import YOLO
|
| 152 |
+
|
| 153 |
+
# YOLOv8n (nano) - ๋น ๋ฅด๊ณ ๊ฐ๋ฒผ์
|
| 154 |
+
model = YOLO('yolov8n.pt')
|
| 155 |
+
|
| 156 |
+
# Fine-tuning
|
| 157 |
+
model.train(
|
| 158 |
+
data='shrimp.yaml',
|
| 159 |
+
epochs=50,
|
| 160 |
+
imgsz=640,
|
| 161 |
+
batch=4,
|
| 162 |
+
patience=10, # Early stopping
|
| 163 |
+
device=0 # GPU
|
| 164 |
+
)
|
| 165 |
+
```
|
| 166 |
+
|
| 167 |
+
**shrimp.yaml**:
|
| 168 |
+
```yaml
|
| 169 |
+
path: ./data
|
| 170 |
+
train: images/train
|
| 171 |
+
val: images/val
|
| 172 |
+
|
| 173 |
+
nc: 1 # number of classes
|
| 174 |
+
names: ['shrimp']
|
| 175 |
+
```
|
| 176 |
+
|
| 177 |
+
#### 4๋จ๊ณ: ์ ์ฉ
|
| 178 |
+
```python
|
| 179 |
+
# ํ์ต๋ ๋ชจ๋ธ ๋ก๋
|
| 180 |
+
model = YOLO('runs/train/exp/weights/best.pt')
|
| 181 |
+
|
| 182 |
+
# ์ถ๋ก
|
| 183 |
+
results = model('test_image.jpg', conf=0.3)
|
| 184 |
+
```
|
| 185 |
+
|
| 186 |
+
---
|
| 187 |
+
|
| 188 |
+
### ๋ฐฉ๋ฒ 3: Data Augmentation + ๊ธฐ์กด ๋ชจ๋ธ ๊ฐ์ ๐
|
| 189 |
+
|
| 190 |
+
**์ฅ์ **: ํ์ต ์์ด ๋ฐ์ดํฐ๋ง ๋๋ ค ํํฐ ์ฌํ์ต ๊ฐ๋ฅ
|
| 191 |
+
|
| 192 |
+
**์์ ์๊ฐ**: 1์๊ฐ
|
| 193 |
+
|
| 194 |
+
**๊ตฌํ ๋ฐฉ๋ฒ**:
|
| 195 |
+
|
| 196 |
+
#### 1๋จ๊ณ: GT ๋ฐ์ดํฐ ์ฆ๊ฐ (30๋ถ)
|
| 197 |
+
```python
|
| 198 |
+
from imgaug import augmenters as iaa
|
| 199 |
+
|
| 200 |
+
# Augmentation pipeline
|
| 201 |
+
aug = iaa.Sequential([
|
| 202 |
+
iaa.Fliplr(0.5), # ์ข์ฐ ๋ฐ์
|
| 203 |
+
iaa.Multiply((0.8, 1.2)), # ๋ฐ๊ธฐ
|
| 204 |
+
iaa.GaussianBlur(sigma=(0, 1.0)), # ๋ธ๋ฌ
|
| 205 |
+
iaa.AdditiveGaussianNoise(scale=(0, 0.05*255)), # ๋
ธ์ด์ฆ
|
| 206 |
+
iaa.Affine(rotate=(-10, 10)) # ํ์
|
| 207 |
+
])
|
| 208 |
+
|
| 209 |
+
# 50๊ฐ โ 250๊ฐ (5๋ฐฐ ์ฆ๊ฐ)
|
| 210 |
+
```
|
| 211 |
+
|
| 212 |
+
#### 2๋จ๊ณ: ์ฆ๊ฐ ๋ฐ์ดํฐ๋ก ํํฐ ์ฌํ์ต
|
| 213 |
+
```bash
|
| 214 |
+
# FP ํจํด ์ฌ๋ถ์
|
| 215 |
+
python analyze_fp_patterns.py --augmented
|
| 216 |
+
|
| 217 |
+
# ํํฐ ์๊ณ๊ฐ ์ฌ์ต์ ํ
|
| 218 |
+
python test_parameter_sweep.py --data augmented
|
| 219 |
+
```
|
| 220 |
+
|
| 221 |
+
---
|
| 222 |
+
|
| 223 |
+
## ๐ ๋ฐฉ๋ฒ ๋น๊ต
|
| 224 |
+
|
| 225 |
+
| ๋ฐฉ๋ฒ | ์์์๊ฐ | ๋์ด๋ | ์์ ์ฑ๋ฅ ํฅ์ | ๋ฐ์ดํฐ ์๊ตฌ๋ | GPU ํ์ |
|
| 226 |
+
|------|---------|--------|---------------|-------------|---------|
|
| 227 |
+
| **RT-DETR Fine-tuning** | 2-3์๊ฐ | ์ค | โญโญโญโญ | 50๊ฐ ์ถฉ๋ถ | ํ์ |
|
| 228 |
+
| **YOLOv8 Training** | 1์๊ฐ | ํ | โญโญโญโญโญ | 50๊ฐ ์ถฉ๋ถ | ํ์ |
|
| 229 |
+
| **Data Augmentation** | 1์๊ฐ | ํ | โญโญ | 50๊ฐโ250๊ฐ | ์ ํ |
|
| 230 |
+
|
| 231 |
+
---
|
| 232 |
+
|
| 233 |
+
## ๐ฏ ์ต์ข
์ถ์ฒ ์ ๋ต
|
| 234 |
+
|
| 235 |
+
### GPU ์์ ๊ฒฝ์ฐ: **YOLOv8 Few-shot Training** โญโญโญโญโญ
|
| 236 |
+
|
| 237 |
+
**์ด์ **:
|
| 238 |
+
1. **๊ฐ์ฅ ๋น ๋ฆ**: 1์๊ฐ ๋ด ํ์ต ์๋ฃ
|
| 239 |
+
2. **๊ฐ๋จํจ**: ์ฝ๋ 10์ค๋ก ํ์ต ๊ฐ๋ฅ
|
| 240 |
+
3. **๊ฒ์ฆ๋จ**: Few-shot learning์ ์ต์ ํ๋จ
|
| 241 |
+
4. **์ฑ๋ฅ**: 50๊ฐ ๋ฐ์ดํฐ๋ก๋ ์ฐ์ํ ๊ฒฐ๊ณผ
|
| 242 |
+
5. **ํตํฉ ์ฌ์**: ๊ธฐ์กด ์ฝ๋ ์ต์ ๋ณ๊ฒฝ
|
| 243 |
+
|
| 244 |
+
**๊ตฌ์ฒด์ ๋จ๊ณ**:
|
| 245 |
+
```bash
|
| 246 |
+
# 1. ์ค์น (5๋ถ)
|
| 247 |
+
pip install ultralytics
|
| 248 |
+
|
| 249 |
+
# 2. ๋ฐ์ดํฐ ๋ณํ (15๋ถ)
|
| 250 |
+
python convert_gt_to_yolo.py
|
| 251 |
+
|
| 252 |
+
# 3. ํ์ต (30-40๋ถ)
|
| 253 |
+
python train_yolo.py
|
| 254 |
+
|
| 255 |
+
# 4. ํ๊ฐ (10๋ถ)
|
| 256 |
+
python evaluate_yolo.py
|
| 257 |
+
```
|
| 258 |
+
|
| 259 |
+
### GPU ์์ ๊ฒฝ์ฐ: **Data Augmentation + Filter ๊ฐ์ **
|
| 260 |
+
|
| 261 |
+
**์ด์ **:
|
| 262 |
+
1. **GPU ๋ถํ์**: CPU๋ง์ผ๋ก ๊ฐ๋ฅ
|
| 263 |
+
2. **๋น ๋ฆ**: 1์๊ฐ ๋ด ์๋ฃ
|
| 264 |
+
3. **์์ ํจ**: ๊ธฐ์กด ์์คํ
์ ์ง
|
| 265 |
+
4. **์ ์ง์ ๊ฐ์ **: ๋ฐ์ดํฐ ํ๋ณดํ๋ฉฐ ์ฑ๋ฅ ํฅ์
|
| 266 |
+
|
| 267 |
+
---
|
| 268 |
+
|
| 269 |
+
## ๐ ์์ ์ฑ๋ฅ ๊ฐ์
|
| 270 |
+
|
| 271 |
+
### ํ์ต ์ (ํ์ฌ)
|
| 272 |
+
```
|
| 273 |
+
Precision: 44.2%
|
| 274 |
+
Recall: 94.0%
|
| 275 |
+
F1: 56.1%
|
| 276 |
+
```
|
| 277 |
+
|
| 278 |
+
### YOLOv8 Fine-tuning ํ (์์)
|
| 279 |
+
```
|
| 280 |
+
Precision: 70-80% (+25-35%p)
|
| 281 |
+
Recall: 90-95% (์ ์ง)
|
| 282 |
+
F1: 78-85% (+22-29%p)
|
| 283 |
+
```
|
| 284 |
+
|
| 285 |
+
**๊ทผ๊ฑฐ**:
|
| 286 |
+
- YOLOv8์ Few-shot (10-50๊ฐ ์ํ)์์ 70%+ Precision ๋ฌ์ฑ ์ค์
|
| 287 |
+
- ์์ฐ๋ ๋ช
ํํ ํํ ํน์ง โ ํ์ต ํจ๊ณผ ๋์
|
| 288 |
+
- ํ์ฌ FP์ ์ฃผ์์ธ(ํฐ ๋ฐ์ค)์ ํ์ต์ผ๋ก ํด๊ฒฐ ๊ฐ๋ฅ
|
| 289 |
+
|
| 290 |
+
---
|
| 291 |
+
|
| 292 |
+
## ๐ ๏ธ ๊ตฌํ ์ฐ์ ์์
|
| 293 |
+
|
| 294 |
+
### 1๋จ๊ณ: GT โ YOLO ๋ณํ ์คํฌ๋ฆฝํธ ์์ฑ
|
| 295 |
+
```python
|
| 296 |
+
# convert_gt_to_yolo.py
|
| 297 |
+
# ground_truth.json โ YOLO format
|
| 298 |
+
```
|
| 299 |
+
|
| 300 |
+
### 2๋จ๊ณ: YOLOv8 ํ์ต ํ์ดํ๋ผ์ธ ๊ตฌ์ถ
|
| 301 |
+
```python
|
| 302 |
+
# train_yolo.py
|
| 303 |
+
# Few-shot training with data augmentation
|
| 304 |
+
```
|
| 305 |
+
|
| 306 |
+
### 3๋จ๊ณ: ํ๊ฐ ๋ฐ ๋น๊ต
|
| 307 |
+
```python
|
| 308 |
+
# compare_models.py
|
| 309 |
+
# RT-DETR vs YOLOv8 ์ฑ๋ฅ ๋น๊ต
|
| 310 |
+
```
|
| 311 |
+
|
| 312 |
+
### 4๋จ๊ณ: ์์คํ
ํตํฉ
|
| 313 |
+
```python
|
| 314 |
+
# test_visual_validation.py ์์
|
| 315 |
+
# YOLOv8 ๋ชจ๋ธ ์ฌ์ฉ ์ต์
์ถ๊ฐ
|
| 316 |
+
```
|
| 317 |
+
|
| 318 |
+
---
|
| 319 |
+
|
| 320 |
+
## โ ๏ธ ์ฃผ์์ฌํญ
|
| 321 |
+
|
| 322 |
+
### 1. ๊ณผ์ ํฉ ๋ฐฉ์ง
|
| 323 |
+
- **Small dataset (50๊ฐ)**: ๊ณผ์ ํฉ ์ํ ๋์
|
| 324 |
+
- **๋์ฑ
**:
|
| 325 |
+
- Early stopping (validation loss ๋ชจ๋ํฐ๋ง)
|
| 326 |
+
- Data augmentation (์ต์ 3๋ฐฐ ์ฆ๊ฐ)
|
| 327 |
+
- Regularization (dropout, weight decay)
|
| 328 |
+
- Freeze backbone (์ด๊ธฐ ๋ ์ด์ด ๊ณ ์ )
|
| 329 |
+
|
| 330 |
+
### 2. Train/Val Split
|
| 331 |
+
```
|
| 332 |
+
Train: 40๊ฐ (80%)
|
| 333 |
+
Val: 10๊ฐ (20%)
|
| 334 |
+
```
|
| 335 |
+
- **Stratified split**: ํด๋๋ณ ๋น์จ ์ ์ง
|
| 336 |
+
- **Val set์ ์ญํ **: ๊ณผ์ ํฉ ์กฐ๊ธฐ ๋ฐ๊ฒฌ
|
| 337 |
+
|
| 338 |
+
### 3. ํ๊ฐ ๊ธฐ์ค
|
| 339 |
+
- **Val set์์๋ง ํ๊ฐ**: Train set์ ์ฐธ๊ณ ๋ง
|
| 340 |
+
- **GT์ ๋์ผํ IoU=0.5** ๊ธฐ์ค ์ฌ์ฉ
|
| 341 |
+
- **๊ธฐ์กด ์์คํ
๊ณผ ๊ณต์ ๋น๊ต**
|
| 342 |
+
|
| 343 |
+
---
|
| 344 |
+
|
| 345 |
+
## ๐ ๋ค์ ๋จ๊ณ
|
| 346 |
+
|
| 347 |
+
1. **์ฆ์ ์คํ ๊ฐ๋ฅ**: YOLOv8 ํ์ต (1์๊ฐ)
|
| 348 |
+
2. **์ถ๊ฐ ๋ฐ์ดํฐ ์์ง**: 100-200๊ฐ ๋ชฉํ (์ฑ๋ฅ ์์ ํ)
|
| 349 |
+
3. **Active Learning**: ๋ชจ๋ธ์ด ๋ถํ์คํ ์ํ ์ฐ์ ๋ผ๋ฒจ๋ง
|
| 350 |
+
4. **์์๋ธ**: RT-DETR + YOLOv8 ๊ฒฐํฉ (์ต๊ณ ์ฑ๋ฅ)
|
| 351 |
+
|
| 352 |
+
---
|
| 353 |
+
|
| 354 |
+
## ๐ก ๊ฒฐ๋ก
|
| 355 |
+
|
| 356 |
+
**ํ์ฌ 50๊ฐ GT๋ก ๊ฐ์ฅ ํจ์จ์ ์ธ ๋ฐฉ๋ฒ**: **YOLOv8 Few-shot Training**
|
| 357 |
+
|
| 358 |
+
- โ
1์๊ฐ ๋ด ์๋ฃ
|
| 359 |
+
- โ
๊ฐ๋จํ ๊ตฌํ
|
| 360 |
+
- โ
50๊ฐ๋ก ์ถฉ๋ถ
|
| 361 |
+
- โ
F1 Score 20-30%p ํฅ์ ๊ธฐ๋
|
| 362 |
+
- โ
GPU ์์ผ๋ฉด ์ฆ์ ์์ ๊ฐ๋ฅ
|
| 363 |
+
|
| 364 |
+
**๊ตฌํ ์์**:
|
| 365 |
+
1. `convert_gt_to_yolo.py` ์์ฑ (GT โ YOLO format)
|
| 366 |
+
2. `train_yolo.py` ์์ฑ (YOLOv8 few-shot training)
|
| 367 |
+
3. `evaluate_yolo.py` ์์ฑ (์ฑ๋ฅ ๋น๊ต)
|
| 368 |
+
4. ๊ธฐ์กด ์์คํ
ํตํฉ
|
| 369 |
+
|
| 370 |
+
**๋ค์ ์ง๋ฌธ**: GPU ์ฌ์ฉ ๊ฐ๋ฅ ์ฌ๋ถ? โ ๊ฐ๋ฅํ๋ฉด YOLOv8, ๋ถ๊ฐ๋ฅํ๋ฉด Data Augmentation
|
docs/evaluation_report.md
ADDED
|
@@ -0,0 +1,317 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# ์์ฐ ๊ฒ์ถ ์์คํ
์ ๋์ ํ๊ฐ ๋ณด๊ณ ์
|
| 2 |
+
|
| 3 |
+
**ํ๊ฐ์ผ:** 2025-11-10
|
| 4 |
+
**ํ๊ฐ ๋์:** RT-DETR + Universal Filter
|
| 5 |
+
**Ground Truth ์ด๋ฏธ์ง:** 40๊ฐ (4๊ฐ ํด๋)
|
| 6 |
+
|
| 7 |
+
---
|
| 8 |
+
|
| 9 |
+
## ๐ ์ ์ฒด ์ฑ๋ฅ ์์ฝ
|
| 10 |
+
|
| 11 |
+
| ์งํ | ๊ฐ | ํ๊ฐ |
|
| 12 |
+
|------|-----|------|
|
| 13 |
+
| **Precision (์ ๋ฐ๋)** | **28.0%** | โ ๏ธ ๋ฎ์ - ๋ง์ ์ค๊ฒ์ถ ๋ฐ์ |
|
| 14 |
+
| **Recall (์ฌํ์จ)** | **50.0%** | โ ๏ธ ๋ณดํต - ์ค์ ์์ฐ์ ์ ๋ฐ๋ง ๊ฒ์ถ |
|
| 15 |
+
| **F1 Score** | **33.7%** | โ ๏ธ ๋ฎ์ - ์ ๋ฐ์ ๊ฐ์ ํ์ |
|
| 16 |
+
|
| 17 |
+
### ์ค์ ๊ฐ
|
| 18 |
+
- RT-DETR Confidence Threshold: `0.3`
|
| 19 |
+
- Filter Threshold (์์ ๊ธฐ๋ฐ): `50`
|
| 20 |
+
- IoU Threshold (๋งค์นญ): `0.5`
|
| 21 |
+
|
| 22 |
+
---
|
| 23 |
+
|
| 24 |
+
## ๐ ํด๋๋ณ ์ฑ๋ฅ ๋ถ์
|
| 25 |
+
|
| 26 |
+
### 1. 250818 ํด๋ (10๊ฐ ์ด๋ฏธ์ง)
|
| 27 |
+
**ํ๊ท F1: 19.7%** โ ๏ธ ๊ฐ์ฅ ๋ฎ์
|
| 28 |
+
|
| 29 |
+
| ์ด๋ฏธ์ง | GT | ๊ฒ์ถ | TP | FP | FN | Precision | Recall | F1 |
|
| 30 |
+
|--------|----|----|----|----|----|-----------|---------|----|
|
| 31 |
+
| 250818_01 | 1 | 3 | 0 | 3 | 1 | 0% | 0% | 0% |
|
| 32 |
+
| 250818_02 | 1 | 4 | 1 | 3 | 0 | 25% | 100% | 40% |
|
| 33 |
+
| 250818_03 | 1 | 4 | 1 | 3 | 0 | 25% | 100% | 40% |
|
| 34 |
+
| 250818_04 | 1 | 2 | 0 | 2 | 1 | 0% | 0% | 0% |
|
| 35 |
+
| 250818_05 | 1 | 4 | 0 | 4 | 1 | 0% | 0% | 0% |
|
| 36 |
+
| 250818_06 | 1 | 3 | 1 | 2 | 0 | 33% | 100% | 50% |
|
| 37 |
+
| 250818_07 | 1 | 5 | 0 | 5 | 1 | 0% | 0% | 0% |
|
| 38 |
+
| 250818_08 | 1 | 2 | 0 | 2 | 1 | 0% | 0% | 0% |
|
| 39 |
+
| 250818_09 | 1 | 2 | 1 | 1 | 0 | 50% | 100% | 67% |
|
| 40 |
+
| 250818_10 | 1 | 1 | 0 | 1 | 1 | 0% | 0% | 0% |
|
| 41 |
+
|
| 42 |
+
**๋ฌธ์ ์ :**
|
| 43 |
+
- ๋ง์ ์ด๋ฏธ์ง์์ ์ค์ ์์ฐ๋ฅผ ๋์นจ (FN ๋์)
|
| 44 |
+
- ์ค๊ฒ์ถ ๊ณผ๋ค (ํ๊ท 3๊ฐ ๊ฒ์ถ, ์ค์ 1๊ฐ)
|
| 45 |
+
|
| 46 |
+
---
|
| 47 |
+
|
| 48 |
+
### 2. 250820 ํด๋ (10๊ฐ ์ด๋ฏธ์ง)
|
| 49 |
+
**ํ๊ท F1: 6.7%** โ ๋งค์ฐ ๋ฎ์
|
| 50 |
+
|
| 51 |
+
| ์ด๋ฏธ์ง | GT | ๊ฒ์ถ | TP | FP | FN | Precision | Recall | F1 |
|
| 52 |
+
|--------|----|----|----|----|----|-----------|---------|----|
|
| 53 |
+
| 250820_01 | 1 | 2 | 0 | 2 | 1 | 0% | 0% | 0% |
|
| 54 |
+
| 250820_02 | 1 | 2 | 0 | 2 | 1 | 0% | 0% | 0% |
|
| 55 |
+
| 250820_03 | 1 | 3 | 0 | 3 | 1 | 0% | 0% | 0% |
|
| 56 |
+
| 250820_04 | 1 | 2 | 0 | 2 | 1 | 0% | 0% | 0% |
|
| 57 |
+
| 250820_05 | 1 | 2 | 0 | 2 | 1 | 0% | 0% | 0% |
|
| 58 |
+
| 250820_06 | 1 | 1 | 0 | 1 | 1 | 0% | 0% | 0% |
|
| 59 |
+
| 250820_07 | 1 | 1 | 0 | 1 | 1 | 0% | 0% | 0% |
|
| 60 |
+
| 250820_08 | 1 | 1 | 0 | 1 | 1 | 0% | 0% | 0% |
|
| 61 |
+
| 250820_09 | 1 | 2 | 1 | 1 | 0 | 50% | 100% | 67% |
|
| 62 |
+
| 250820_10 | 1 | 2 | 0 | 2 | 1 | 0% | 0% | 0% |
|
| 63 |
+
|
| 64 |
+
**๋ฌธ์ ์ :**
|
| 65 |
+
- **10๊ฐ ์ค 9๊ฐ ์์ ์คํจ** (0% F1)
|
| 66 |
+
- ๊ฒ์ถ์ ๋์ง๋ง ์์น๊ฐ ์์ ํ ์๋ชป๋จ (IoU < 0.5)
|
| 67 |
+
- ์ด๋ฏธ์ง ํน์ฑ์ด ๋ค๋ฅธ ํด๋์ ๋ฌ๋ผ ํํฐ๋ง ์คํจ ๊ฐ๋ฅ์ฑ
|
| 68 |
+
|
| 69 |
+
---
|
| 70 |
+
|
| 71 |
+
### 3. 250822 ํด๋ (10๊ฐ ์ด๋ฏธ์ง)
|
| 72 |
+
**ํ๊ท F1: 30.0%** โ ๏ธ ๋ณดํต
|
| 73 |
+
|
| 74 |
+
| ์ด๋ฏธ์ง | GT | ๊ฒ์ถ | TP | FP | FN | Precision | Recall | F1 |
|
| 75 |
+
|--------|----|----|----|----|----|-----------|---------|----|
|
| 76 |
+
| 250822_01 | 1 | 3 | 1 | 2 | 0 | 33% | 100% | 50% |
|
| 77 |
+
| 250822_02 | 1 | 3 | 0 | 3 | 1 | 0% | 0% | 0% |
|
| 78 |
+
| 250822_03 | 1 | 2 | 0 | 2 | 1 | 0% | 0% | 0% |
|
| 79 |
+
| 250822_04 | 1 | 3 | 1 | 2 | 0 | 33% | 100% | 50% |
|
| 80 |
+
| 250822_05 | 1 | 3 | 1 | 2 | 0 | 33% | 100% | 50% |
|
| 81 |
+
| 250822_06 | 1 | 2 | 1 | 1 | 0 | 50% | 100% | 67% |
|
| 82 |
+
| 250822_07 | 1 | 3 | 1 | 2 | 0 | 33% | 100% | 50% |
|
| 83 |
+
| 250822_08 | 1 | 3 | 1 | 2 | 0 | 33% | 100% | 50% |
|
| 84 |
+
| 250822_09 | 1 | 1 | 0 | 1 | 1 | 0% | 0% | 0% |
|
| 85 |
+
| 250822_10 | 1 | 1 | 0 | 1 | 1 | 0% | 0% | 0% |
|
| 86 |
+
|
| 87 |
+
**ํน์ง:**
|
| 88 |
+
- ์๋์ ์ผ๋ก ์ํธ (250818๋ณด๋ค ๋์)
|
| 89 |
+
- ์ค๊ฒ์ถ์ด ์ฌ์ ํ ๋ง์ (ํ๊ท 2.2๊ฐ ๊ฒ์ถ, ์ค์ 1๊ฐ)
|
| 90 |
+
|
| 91 |
+
---
|
| 92 |
+
|
| 93 |
+
### 4. 250827 ํด๋ (10๊ฐ ์ด๋ฏธ์ง)
|
| 94 |
+
**ํ๊ท F1: 76.7%** โ
**๊ฐ์ฅ ์ฐ์**
|
| 95 |
+
|
| 96 |
+
| ์ด๋ฏธ์ง | GT | ๊ฒ์ถ | TP | FP | FN | Precision | Recall | F1 |
|
| 97 |
+
|--------|----|----|----|----|----|-----------|---------|----|
|
| 98 |
+
| 250827_01 | 1 | 1 | 1 | 0 | 0 | **100%** | **100%** | **100%** |
|
| 99 |
+
| 250827_02 | 1 | 5 | 1 | 4 | 0 | 20% | 100% | 33% |
|
| 100 |
+
| 250827_03 | 1 | 1 | 1 | 0 | 0 | **100%** | **100%** | **100%** |
|
| 101 |
+
| 250827_04 | 1 | 1 | 1 | 0 | 0 | **100%** | **100%** | **100%** |
|
| 102 |
+
| 250827_05 | 1 | 1 | 1 | 0 | 0 | **100%** | **100%** | **100%** |
|
| 103 |
+
| 250827_06 | 1 | 1 | 1 | 0 | 0 | **100%** | **100%** | **100%** |
|
| 104 |
+
| 250827_07 | 1 | 2 | 1 | 1 | 0 | 50% | 100% | 67% |
|
| 105 |
+
| 250827_08 | 1 | 0 | 0 | 0 | 1 | 0% | 0% | 0% |
|
| 106 |
+
| 250827_09 | 1 | 2 | 1 | 1 | 0 | 50% | 100% | 67% |
|
| 107 |
+
| 250827_10 | 1 | 1 | 1 | 0 | 0 | **100%** | **100%** | **100%** |
|
| 108 |
+
|
| 109 |
+
**ํน์ง:**
|
| 110 |
+
- **6๊ฐ ์ด๋ฏธ์ง์์ ์๋ฒฝํ ์ฑ๋ฅ** (100% F1)
|
| 111 |
+
- 1๊ฐ ์ด๋ฏธ์ง ๊ฒ์ถ ์คํจ (250827_08)
|
| 112 |
+
- ์ด ํด๋์ ์ด๋ฏธ์ง ํน์ฑ์ด ํํฐ์ ๊ฐ์ฅ ์ ํฉ
|
| 113 |
+
|
| 114 |
+
---
|
| 115 |
+
|
| 116 |
+
## ๐ ์ฃผ์ ๋ฌธ์ ์ ๋ถ์
|
| 117 |
+
|
| 118 |
+
### 1. ๋ฎ์ Precision (28%) ์์ธ
|
| 119 |
+
- **๊ณผ๋ํ ์ค๊ฒ์ถ (False Positives)**
|
| 120 |
+
- ํ๊ท 1.8๊ฐ ์ค๊ฒ์ถ/์ด๋ฏธ์ง
|
| 121 |
+
- 250818_07: 5๊ฐ ์ค๊ฒ์ถ
|
| 122 |
+
- 250827_02: 4๊ฐ ์ค๊ฒ์ถ
|
| 123 |
+
|
| 124 |
+
- **๊ฐ๋ฅํ ์์ธ:**
|
| 125 |
+
- RT-DETR confidence threshold ๋๋ฌด ๋ฎ์ (0.3)
|
| 126 |
+
- ์์ ํํฐ ์๊ณ๊ฐ ๋ถ์ ์ (50)
|
| 127 |
+
- ํํฐ๊ฐ ๋ฐฐ๊ฒฝ ์์๋ฅผ ์์ฐ๋ก ์ค์ธ
|
| 128 |
+
|
| 129 |
+
### 2. ๋ฎ์ Recall (50%) ์์ธ
|
| 130 |
+
- **์ค์ ์์ฐ ๋ฏธ๊ฒ์ถ (False Negatives)**
|
| 131 |
+
- 20๊ฐ ์ด๋ฏธ์ง์์ ์ค์ ์์ฐ ๋์นจ
|
| 132 |
+
|
| 133 |
+
- **๊ฐ๋ฅํ ์์ธ:**
|
| 134 |
+
- RT-DETR ๋ชจ๋ธ์ด ์ผ๋ถ ์์ธ/์กฐ๋ช
์ ์์ฐ๋ฅผ ์ธ์ ๋ชปํจ
|
| 135 |
+
- ์์ ํํฐ๊ฐ ๋๋ฌด ์๊ฒฉํด ํํฐ๋ง๋จ
|
| 136 |
+
- ํน์ ํด๋(250820)์ ์ด๋ฏธ์ง ํน์ฑ๊ณผ ๋ถ์ผ์น
|
| 137 |
+
|
| 138 |
+
### 3. ํด๋๊ฐ ์ฑ๋ฅ ๊ฒฉ์ฐจ
|
| 139 |
+
- **250827: 76.7% F1** (์ฐ์)
|
| 140 |
+
- **250820: 6.7% F1** (๋งค์ฐ ๋ฎ์)
|
| 141 |
+
- ๊ฒฉ์ฐจ: **70.0%p**
|
| 142 |
+
|
| 143 |
+
- **์์ธ ์ถ์ :**
|
| 144 |
+
- ์กฐ๋ช
์กฐ๊ฑด ์ฐจ์ด
|
| 145 |
+
- ์์ฐ ์์/ํฌ๊ธฐ ์ฐจ์ด
|
| 146 |
+
- ๋ฐฐ๊ฒฝ ๋ณต์ก๋ ์ฐจ์ด
|
| 147 |
+
- ์ดฌ์ ๊ฐ๋/๊ฑฐ๋ฆฌ ์ฐจ์ด
|
| 148 |
+
|
| 149 |
+
---
|
| 150 |
+
|
| 151 |
+
## ๐ก ๊ฐ์ ๋ฐฉ์
|
| 152 |
+
|
| 153 |
+
### Phase 1: ์ฆ์ ์ ์ฉ ๊ฐ๋ฅํ ๊ฐ์ (1-2์ผ)
|
| 154 |
+
|
| 155 |
+
#### 1.1 RT-DETR Confidence Threshold ์ํฅ
|
| 156 |
+
```python
|
| 157 |
+
# ํ์ฌ: 0.3
|
| 158 |
+
# ์ ์: 0.4 ๋๋ 0.5
|
| 159 |
+
confidence = 0.5 # Precision ํฅ์ ๊ธฐ๋
|
| 160 |
+
```
|
| 161 |
+
**๊ธฐ๋ ํจ๊ณผ:** Precision โ, Recall ์ฝ๊ฐ โ
|
| 162 |
+
|
| 163 |
+
#### 1.2 Filter Threshold ์กฐ์
|
| 164 |
+
```python
|
| 165 |
+
# ํ์ฌ: 50
|
| 166 |
+
# ์ ์: ๋ค์ค ์๊ณ๊ฐ ํ
์คํธ (30, 40, 50, 60, 70)
|
| 167 |
+
filter_threshold = 60 # ๋ ์๊ฒฉํ ํํฐ๋ง
|
| 168 |
+
```
|
| 169 |
+
**๊ธฐ๋ ํจ๊ณผ:** ์ค๊ฒ์ถ ๊ฐ์
|
| 170 |
+
|
| 171 |
+
#### 1.3 NMS (Non-Maximum Suppression) ๊ฐํ
|
| 172 |
+
```python
|
| 173 |
+
# ์ค๋ณต ๋ฐ์ค ์ ๊ฑฐ ์๊ณ๊ฐ ๋ฎ์ถ๊ธฐ
|
| 174 |
+
iou_threshold = 0.3 # ํ์ฌ 0.5์์ ๋ฎ์ถค
|
| 175 |
+
```
|
| 176 |
+
**๊ธฐ๋ ํจ๊ณผ:** ์ค๋ณต ๊ฒ์ถ ๊ฐ์
|
| 177 |
+
|
| 178 |
+
---
|
| 179 |
+
|
| 180 |
+
### Phase 2: ์๊ณ ๋ฆฌ์ฆ ๊ฐ์ (3-5์ผ)
|
| 181 |
+
|
| 182 |
+
#### 2.1 ํด๋๋ณ ์ ์ํ ํํฐ๋ง
|
| 183 |
+
```python
|
| 184 |
+
# ํด๋๋ณ ์ต์ ํ๋ผ๋ฏธํฐ ํ์ต
|
| 185 |
+
folder_configs = {
|
| 186 |
+
'250818': {'conf': 0.4, 'filter': 50},
|
| 187 |
+
'250820': {'conf': 0.3, 'filter': 40}, # ๋ ๊ด๋ํ ์ค์
|
| 188 |
+
'250822': {'conf': 0.4, 'filter': 55},
|
| 189 |
+
'250827': {'conf': 0.5, 'filter': 60} # ์ด๋ฏธ ์ ์๋
|
| 190 |
+
}
|
| 191 |
+
```
|
| 192 |
+
|
| 193 |
+
#### 2.2 Multi-Scale Detection
|
| 194 |
+
- ๋ค์ํ ํฌ๊ธฐ์ ์์ฐ ๊ฒ์ถ ๊ฐ์
|
| 195 |
+
- RT-DETR์ multi-scale feature ํ์ฉ
|
| 196 |
+
|
| 197 |
+
#### 2.3 Aspect Ratio ๊ธฐ๋ฐ ํ์ฒ๋ฆฌ
|
| 198 |
+
```python
|
| 199 |
+
# ์์ฐ์ ์ ํ์ ์ธ ์ฅ๋จ์ถ๋น ํํฐ๋ง
|
| 200 |
+
def filter_by_aspect_ratio(boxes):
|
| 201 |
+
filtered = []
|
| 202 |
+
for box in boxes:
|
| 203 |
+
ratio = calculate_long_short_axis_ratio(box)
|
| 204 |
+
if 3.0 <= ratio <= 15.0: # ์์ฐ ํํ
|
| 205 |
+
filtered.append(box)
|
| 206 |
+
return filtered
|
| 207 |
+
```
|
| 208 |
+
|
| 209 |
+
---
|
| 210 |
+
|
| 211 |
+
### Phase 3: ๋ชจ๋ธ ๊ฐ์ (1-2์ฃผ)
|
| 212 |
+
|
| 213 |
+
#### 3.1 Fine-tuning RT-DETR
|
| 214 |
+
- ํ์ฌ ๋ผ๋ฒจ๋ง๋ 40๊ฐ ์ด๋ฏธ์ง๋ก Fine-tuning
|
| 215 |
+
- ์์ฐ ๋๋ฉ์ธ์ ํนํ๋ ๊ฐ์ค์น ํ์ต
|
| 216 |
+
|
| 217 |
+
#### 3.2 Ensemble ์ ๊ทผ
|
| 218 |
+
- RT-DETR + YOLOv8 ์์๋ธ
|
| 219 |
+
- ๋ ๋ชจ๋ธ์ ๊ฒ์ถ ๊ฒฐ๊ณผ ์กฐํฉ
|
| 220 |
+
|
| 221 |
+
#### 3.3 ๋ฐ์ดํฐ ์ฆ๊ฐ
|
| 222 |
+
- ์ถ๊ฐ ๋ผ๋ฒจ๋ง (๋ชฉํ: 100-200๊ฐ)
|
| 223 |
+
- ์กฐ๋ช
/๊ฐ๋ ๋ค์ํ
|
| 224 |
+
|
| 225 |
+
---
|
| 226 |
+
|
| 227 |
+
## ๐ ๋ค์ ๋จ๊ณ ์คํ ๊ณํ
|
| 228 |
+
|
| 229 |
+
### Step 1: ํ๋ผ๋ฏธํฐ ๊ทธ๋ฆฌ๋ ์์น (์ฐ์ ์์: ๋์)
|
| 230 |
+
```bash
|
| 231 |
+
python test_parameter_sweep.py
|
| 232 |
+
```
|
| 233 |
+
**๋ชฉํ:** ์ต์ ์ confidence + filter threshold ์กฐํฉ ์ฐพ๊ธฐ
|
| 234 |
+
|
| 235 |
+
**ํ
์คํธ ๋ฒ์:**
|
| 236 |
+
- Confidence: [0.3, 0.35, 0.4, 0.45, 0.5]
|
| 237 |
+
- Filter Threshold: [30, 40, 50, 60, 70]
|
| 238 |
+
- ์ด 25๊ฐ ์กฐํฉ ํ๊ฐ
|
| 239 |
+
|
| 240 |
+
**์์ ๊ฒฐ๊ณผ:** F1 Score 40-50% ๋ฌ์ฑ ๊ฐ๋ฅ
|
| 241 |
+
|
| 242 |
+
---
|
| 243 |
+
|
| 244 |
+
### Step 2: ์คํจ ์ฌ๋ก ์๊ฐ์ ๋ถ์ (์ฐ์ ์์: ๋์)
|
| 245 |
+
```bash
|
| 246 |
+
# ํ๊ฐ ๊ฒฐ๊ณผ ์ด๋ฏธ์ง ํ์ธ
|
| 247 |
+
explorer test_results/quantitative_20251110_134837/
|
| 248 |
+
```
|
| 249 |
+
|
| 250 |
+
**ํ์ธ ํญ๋ชฉ:**
|
| 251 |
+
- ์ค๊ฒ์ถ ํจํด (FP๊ฐ ๋ฌด์์ธ์ง)
|
| 252 |
+
- ๋ฏธ๊ฒ์ถ ํจํด (์ ๋์ณค๋์ง)
|
| 253 |
+
- 250820 ํด๋ ์คํจ ์์ธ
|
| 254 |
+
|
| 255 |
+
---
|
| 256 |
+
|
| 257 |
+
### Step 3: ์ถ๊ฐ ๋ผ๋ฒจ๋ง (์ฐ์ ์์: ์ค๊ฐ)
|
| 258 |
+
**๋ชฉํ:** 100๊ฐ ์ด๋ฏธ์ง
|
| 259 |
+
- 250820 ํด๋ ์ถ๊ฐ ๋ผ๋ฒจ๋ง (ํ์ฌ ์ฑ๋ฅ ์ต์
)
|
| 260 |
+
- ๋ค์ํ ์กฐ๋ช
/๊ฐ๋ ์ด๋ฏธ์ง ์ถ๊ฐ
|
| 261 |
+
|
| 262 |
+
---
|
| 263 |
+
|
| 264 |
+
### Step 4: ์๊ณ ๋ฆฌ์ฆ ๊ฐ์ ๊ตฌํ (์ฐ์ ์์: ์ค๊ฐ)
|
| 265 |
+
1. Aspect ratio ํํฐ ์ถ๊ฐ
|
| 266 |
+
2. ํด๋๋ณ ์ ์ํ ํ๋ผ๋ฏธํฐ
|
| 267 |
+
3. NMS ๊ฐ์
|
| 268 |
+
|
| 269 |
+
---
|
| 270 |
+
|
| 271 |
+
## ๐ ๊ฒฐ๊ณผ ํ์ผ ์์น
|
| 272 |
+
|
| 273 |
+
```
|
| 274 |
+
test_results/quantitative_20251110_134837/
|
| 275 |
+
โโโ evaluation_summary.json # ์ ์ฒด ํ๊ฐ ๊ฒฐ๊ณผ
|
| 276 |
+
โโโ confusion_matrix.png # Confusion Matrix
|
| 277 |
+
โโโ eval_250818_01.jpg # ๊ฐ๋ณ ์ด๋ฏธ์ง ํ๊ฐ ๊ฒฐ๊ณผ
|
| 278 |
+
โโโ eval_250818_02.jpg
|
| 279 |
+
...
|
| 280 |
+
โโโ eval_250827_10.jpg
|
| 281 |
+
```
|
| 282 |
+
|
| 283 |
+
**์๊ฐํ ๋ฒ๋ก:**
|
| 284 |
+
- ๋
น์ ๋ฐ์ค (GT): Ground Truth (์ฌ์ฉ์ ๋ผ๋ฒจ๋ง)
|
| 285 |
+
- ์ฒญ๋ก์ ๋ฐ์ค (Pred): ์์คํ
๊ฒ์ถ ๊ฒฐ๊ณผ
|
| 286 |
+
- ํค๋: P=Precision, R=Recall, F1=F1 Score
|
| 287 |
+
|
| 288 |
+
---
|
| 289 |
+
|
| 290 |
+
## ๐ฏ ์ฑ๋ฅ ๋ชฉํ
|
| 291 |
+
|
| 292 |
+
| Phase | F1 Score ๋ชฉํ | ์์ ๊ธฐ๊ฐ |
|
| 293 |
+
|-------|--------------|----------|
|
| 294 |
+
| **ํ์ฌ** | 33.7% | - |
|
| 295 |
+
| **Phase 1** (ํ๋ผ๋ฏธํฐ ์ต์ ํ) | 45-50% | 1-2์ผ |
|
| 296 |
+
| **Phase 2** (์๊ณ ๋ฆฌ์ฆ ๊ฐ์ ) | 60-70% | 1์ฃผ |
|
| 297 |
+
| **Phase 3** (๋ชจ๋ธ Fine-tuning) | 75-85% | 2์ฃผ |
|
| 298 |
+
| **๋ชฉํ** | **โฅ80%** | 1๊ฐ์ |
|
| 299 |
+
|
| 300 |
+
---
|
| 301 |
+
|
| 302 |
+
## ๐ ์์ฝ
|
| 303 |
+
|
| 304 |
+
โ
**์๋ ์ :**
|
| 305 |
+
- 250827 ํด๋์์ 76.7% F1 ๋ฌ์ฑ (6๊ฐ ์ด๋ฏธ์ง ์๋ฒฝ)
|
| 306 |
+
- ์ ์ฒด Recall 50% (์ ๋ฐ์ ์ฐพ์)
|
| 307 |
+
- ํ๊ฐ ์์คํ
๊ตฌ์ถ ์๋ฃ
|
| 308 |
+
|
| 309 |
+
โ ๏ธ **๊ฐ์ ํ์:**
|
| 310 |
+
- Precision 28% โ 60%+ ๋ชฉํ
|
| 311 |
+
- ํด๋๊ฐ ์ฑ๋ฅ ๊ฒฉ์ฐจ ํด์ (250820 ์ง์ค)
|
| 312 |
+
- ์ค๊ฒ์ถ ๊ฐ์ ํ์
|
| 313 |
+
|
| 314 |
+
๐ง **์ฆ์ ์คํ:**
|
| 315 |
+
1. ํ๋ผ๋ฏธํฐ ๊ทธ๋ฆฌ๋ ์์น
|
| 316 |
+
2. ์คํจ ์ฌ๋ก ์๊ฐ์ ๋ถ์
|
| 317 |
+
3. Confidence threshold 0.5๋ก ์ฌํ๊ฐ
|
docs/filter_validation_methodology.md
ADDED
|
@@ -0,0 +1,589 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# ๐ ์์ฐ ํํฐ๋ง ๋ก์ง ๊ฒ์ฆ ๋ฐฉ๋ฒ๋ก
|
| 2 |
+
|
| 3 |
+
## ๐ ๋ฌธ์ ์ ๋ณด
|
| 4 |
+
|
| 5 |
+
- **์์ฑ์ผ**: 2025-11-10
|
| 6 |
+
- **๋ฒ์ **: 1.0
|
| 7 |
+
- **๋ชฉ์ **: RT-DETR ๊ฒ์ถ ๊ฒฐ๊ณผ๋ฅผ ํํฐ๋งํ๋ ๋ก์ง์ ๊ฒ์ฆ ๋ฐฉ๋ฒ ์ ๋ฆฌ
|
| 8 |
+
|
| 9 |
+
---
|
| 10 |
+
|
| 11 |
+
## ๐ฏ ํ์ฌ ์ํฉ
|
| 12 |
+
|
| 13 |
+
### Ground Truth ๋ถ์ฌ
|
| 14 |
+
|
| 15 |
+
- **๋ฌธ์ **: ์ ๋ต ๋ฐ์ดํฐ(๋ผ๋ฒจ๋ง๋ ๋ฐ์ด๋ฉ ๋ฐ์ค)๊ฐ ์์
|
| 16 |
+
- **๊ฒฐ๊ณผ**: ์ ๋์ ์ฑ๋ฅ ์ธก์ ๋ถ๊ฐ
|
| 17 |
+
- **ํ์ฌ ๋ฐฉ์**: ํด๋ฆฌ์คํฑ ๊ท์น + ์๊ฐ์ ํ์ธ
|
| 18 |
+
|
| 19 |
+
---
|
| 20 |
+
|
| 21 |
+
## 1๏ธโฃ ํ์ฌ ๊ฒ์ฆ ๋ฐฉ๋ฒ (Ground Truth ์์ด)
|
| 22 |
+
|
| 23 |
+
### A. ํด๋ฆฌ์คํฑ ๊ท์น ๊ธฐ๋ฐ ์ค๊ณ
|
| 24 |
+
|
| 25 |
+
**์๋ฆฌ:**
|
| 26 |
+
```
|
| 27 |
+
์์ฐ์ ๋ฌผ๋ฆฌ์ /์๊ฐ์ ํน์ฑ ๋ถ์
|
| 28 |
+
โ
|
| 29 |
+
๊ท์น ์ ์ (์ข
ํก๋น, ์ธ์ฅ๋, ์์ ๋ฑ)
|
| 30 |
+
โ
|
| 31 |
+
๊ฐ์ค์น ์ค์ (๊ฒฝํ์ )
|
| 32 |
+
โ
|
| 33 |
+
์๊ฐ์ ๊ฒฐ๊ณผ ํ์ธ
|
| 34 |
+
โ
|
| 35 |
+
๊ท์น ์กฐ์ ๋ฐ๋ณต
|
| 36 |
+
```
|
| 37 |
+
|
| 38 |
+
**์ฅ์ :**
|
| 39 |
+
- โ
Ground Truth ๋ถํ์
|
| 40 |
+
- โ
๋น ๋ฅธ ํ๋กํ ํ์ดํ
|
| 41 |
+
- โ
๊ท์น์ด ํด์ ๊ฐ๋ฅ
|
| 42 |
+
|
| 43 |
+
**๋จ์ :**
|
| 44 |
+
- โ ์ ๋์ ๊ฒ์ฆ ๋ถ๊ฐ
|
| 45 |
+
- โ ์ค๋ถ๋ฅ์จ ์ธก์ ๋ถ๊ฐ
|
| 46 |
+
- โ ์ฃผ๊ด์ ํ๋จ์ ์์กด
|
| 47 |
+
|
| 48 |
+
---
|
| 49 |
+
|
| 50 |
+
### B. ํ์ฌ ํํฐ ๊ท์น ๋ฐ ๊ทผ๊ฑฐ
|
| 51 |
+
|
| 52 |
+
#### 1. **์ข
ํก๋น (Aspect Ratio)**: 3:1 ~ 10:1
|
| 53 |
+
|
| 54 |
+
**๊ทผ๊ฑฐ:**
|
| 55 |
+
- ์์ฐ๋ ๊ธธ์ญํ ํํ
|
| 56 |
+
- ์(ruler)๋ 2:1~3:1 ์ ๋ โ ํํ์ 3.0์ผ๋ก ์ํฅ
|
| 57 |
+
|
| 58 |
+
**์ ์:**
|
| 59 |
+
- 3.0~10.0: 15์
|
| 60 |
+
- 2.0~2.9: 8์ (๊ฐ์ )
|
| 61 |
+
- ๊ธฐํ: 0์
|
| 62 |
+
|
| 63 |
+
**๊ฒ์ฆ ๋ฐฉ๋ฒ:**
|
| 64 |
+
```python
|
| 65 |
+
# ์๋ ์ธก์
|
| 66 |
+
์ค์ _์์ฐ_์ข
ํก๋น = 5.2 # ์: ๊ธธ์ด 52cm, ํญ 10cm
|
| 67 |
+
์_์ข
ํก๋น = 2.2
|
| 68 |
+
|
| 69 |
+
# ๊ท์น ์ ์ฉ
|
| 70 |
+
if 3.0 <= 5.2 <= 10.0: # ์์ฐ ํต๊ณผ โ
|
| 71 |
+
if 3.0 <= 2.2 <= 10.0: # ์ ์คํจ โ
|
| 72 |
+
```
|
| 73 |
+
|
| 74 |
+
---
|
| 75 |
+
|
| 76 |
+
#### 2. **์ธ์ฅ๋ (Compactness)**: < 0.50
|
| 77 |
+
|
| 78 |
+
**๊ทผ๊ฑฐ:**
|
| 79 |
+
- ์ธ์ฅ๋ = 4ฯ ร ๋ฉด์ / ๋๋ ยฒ
|
| 80 |
+
- ์ํ: 1.0, ์ ์ฌ๊ฐํ: 0.785
|
| 81 |
+
- ์์ฐ(๊ธด ํ์): 0.3~0.5
|
| 82 |
+
- ์(์ง์ฌ๊ฐํ): 0.6~0.8
|
| 83 |
+
|
| 84 |
+
**์ ์:**
|
| 85 |
+
- < 0.50: 20์
|
| 86 |
+
- โฅ 0.50: -10์ (ํจ๋ํฐ)
|
| 87 |
+
|
| 88 |
+
**๊ฒ์ฆ ๋ฐฉ๋ฒ:**
|
| 89 |
+
```python
|
| 90 |
+
# ์ค์ธก๊ฐ ๋น๊ต
|
| 91 |
+
์ธก์ _์์ฐ_์ธ์ฅ๋ = 0.43 # ํด์ง ์ํ
|
| 92 |
+
์์กฐ_์์ฐ_์ธ์ฅ๋ = 0.25 # ๊ตฌ๋ถ๋ฌ์ง ์ํ
|
| 93 |
+
์_์ธ์ฅ๋ = 0.67
|
| 94 |
+
|
| 95 |
+
# ๋ชจ๋ < 0.50 ์ด๋ฉด ์์ฐ, โฅ 0.50์ด๋ฉด ๋ค๋ฅธ ๋ฌผ์ฒด
|
| 96 |
+
```
|
| 97 |
+
|
| 98 |
+
---
|
| 99 |
+
|
| 100 |
+
#### 3. **๋ฉด์ ๋น (Area Ratio)**: 5% ~ 50%
|
| 101 |
+
|
| 102 |
+
**๊ทผ๊ฑฐ:**
|
| 103 |
+
- ์์ฐ๊ฐ ์ด๋ฏธ์ง์ ๋๋ถ๋ถ์ ์ฐจ์งํ์ง ์์
|
| 104 |
+
- ๋๋ฌด ์์ผ๋ฉด ๋
ธ์ด์ฆ์ผ ๊ฐ๋ฅ์ฑ
|
| 105 |
+
|
| 106 |
+
**์ ์:**
|
| 107 |
+
- 5~50%: 10์
|
| 108 |
+
- ๊ธฐํ: 0์
|
| 109 |
+
|
| 110 |
+
---
|
| 111 |
+
|
| 112 |
+
#### 4. **์์ (Hue)**: 0~40 ๋๋ >130
|
| 113 |
+
|
| 114 |
+
**๊ทผ๊ฑฐ:**
|
| 115 |
+
- HSV ์์ ๊ณต๊ฐ์์:
|
| 116 |
+
- 0-40: ๋นจ๊ฐ~์ฃผํฉ (ํฌ๋ช
/ํ๋ฐฑ์ ์์ฐ)
|
| 117 |
+
- 90-130: ํ๋์ (๋ฐฐ๊ฒฝ ๋งคํธ)
|
| 118 |
+
- ์ค์ ์์ฐ Hue ํ๊ท : 20~30
|
| 119 |
+
|
| 120 |
+
**์ ์:**
|
| 121 |
+
- < 40 ๋๋ > 130: 10์
|
| 122 |
+
- 90~130 (๋ฐฐ๊ฒฝ): -5์
|
| 123 |
+
- ๊ธฐํ: 0์
|
| 124 |
+
|
| 125 |
+
**๊ฒ์ฆ ๋ฐฉ๋ฒ:**
|
| 126 |
+
```python
|
| 127 |
+
# ์ค์ ์ด๋ฏธ์ง ๋ถ์
|
| 128 |
+
์์ฐ_์์ญ_Hue = 76.1 # ํฌ๋ช
์์ฐ
|
| 129 |
+
๋ฐฐ๊ฒฝ_Hue = 110 # ํ๋ ๋งคํธ
|
| 130 |
+
|
| 131 |
+
# ๊ท์น: ๋ฐฐ๊ฒฝ ์ ์ธ
|
| 132 |
+
if 90 <= 110 <= 130: # ๋ฐฐ๊ฒฝ ๊ฐ์ง โ
|
| 133 |
+
```
|
| 134 |
+
|
| 135 |
+
---
|
| 136 |
+
|
| 137 |
+
#### 5. **์ฑ๋ (Saturation)**: < 180
|
| 138 |
+
|
| 139 |
+
**๊ทผ๊ฑฐ:**
|
| 140 |
+
- ์ฃฝ์ ์์ฐ๋ ์ฑ๋๊ฐ ๋ฎ์ (ํฌ๋ช
)
|
| 141 |
+
- ์ด์์๋ ์์ฐ๋ ๋น๊ต์ ๋ฎ์
|
| 142 |
+
|
| 143 |
+
**์ ์:**
|
| 144 |
+
- < 180: 15์
|
| 145 |
+
- โฅ 180: 0์
|
| 146 |
+
|
| 147 |
+
---
|
| 148 |
+
|
| 149 |
+
#### 6. **์์ ์ผ๊ด์ฑ (Color Std)**: < 60
|
| 150 |
+
|
| 151 |
+
**๊ทผ๊ฑฐ:**
|
| 152 |
+
- ์์ฐ ๋ด๋ถ๋ ๋น๊ต์ ๊ท ์ผํ ์์
|
| 153 |
+
- ๋๋ฌด ๋์ผ๋ฉด ๋ณต์กํ ํจํด (์, ๋ฐฐ๊ฒฝ ๋ฑ)
|
| 154 |
+
|
| 155 |
+
**์ ์:**
|
| 156 |
+
- < 60: 10์
|
| 157 |
+
- โฅ 60: 0์
|
| 158 |
+
|
| 159 |
+
---
|
| 160 |
+
|
| 161 |
+
### C. ์๊ฐ์ ๊ฒ์ฆ ํ๋ก์ธ์ค
|
| 162 |
+
|
| 163 |
+
**๋๊ตฌ**: `interactive_validation.py`
|
| 164 |
+
|
| 165 |
+
**์ ์ฐจ:**
|
| 166 |
+
```
|
| 167 |
+
1. ์์ ์ด๋ฏธ์ง ์ ํ
|
| 168 |
+
2. ํ๋ผ๋ฏธํฐ ์กฐ์
|
| 169 |
+
3. ๊ฒ์ถ ์คํ
|
| 170 |
+
4. ๊ฒฐ๊ณผ ํ์ธ:
|
| 171 |
+
- ๋
น์ ๋ฐ์ค: ํต๊ณผ (์์ฐ)
|
| 172 |
+
- ๋นจ๊ฐ ๋ฐ์ค: ์ ๊ฑฐ (๋น์์ฐ)
|
| 173 |
+
5. ์ ๊ฑฐ ์ด์ ๋ถ์:
|
| 174 |
+
- "โ ์ธ์ฅ๋ 0.67" โ ์์์
|
| 175 |
+
- "โ ์์ 110 (๋ฐฐ๊ฒฝ)" โ ๋ฐฐ๊ฒฝ์ด์์
|
| 176 |
+
6. ๊ท์น ์กฐ์ ํ์ ์ ์ฝ๋ ์์
|
| 177 |
+
```
|
| 178 |
+
|
| 179 |
+
**ํ๋จ ๊ธฐ์ค:**
|
| 180 |
+
```
|
| 181 |
+
โ
์ข์:
|
| 182 |
+
- ๋ชจ๋ ์์ฐ ๊ฒ์ถ๋จ
|
| 183 |
+
- ์ค๊ฒ์ถ(์, ๋ฐฐ๊ฒฝ, ์) ์์
|
| 184 |
+
|
| 185 |
+
โ ๏ธ ๊ฐ์ ํ์:
|
| 186 |
+
- ์์ฐ ์ผ๋ถ ๋๋ฝ
|
| 187 |
+
- ์ค๊ฒ์ถ ์์
|
| 188 |
+
|
| 189 |
+
โ ๋์จ:
|
| 190 |
+
- ์์ฐ ๋๋ถ๋ถ ๋๋ฝ
|
| 191 |
+
- ์ค๊ฒ์ถ ๋ง์
|
| 192 |
+
```
|
| 193 |
+
|
| 194 |
+
---
|
| 195 |
+
|
| 196 |
+
## 2๏ธโฃ ์ ๋์ ๊ฒ์ฆ ๋ฐฉ๋ฒ (Ground Truth ํ์)
|
| 197 |
+
|
| 198 |
+
### A. Ground Truth ์์ฑ
|
| 199 |
+
|
| 200 |
+
#### ๋ฐฉ๋ฒ 1: ์๋ ๋ผ๋ฒจ๋ง (LabelImg)
|
| 201 |
+
|
| 202 |
+
**๋๊ตฌ**: [LabelImg](https://github.com/tzutalin/labelImg)
|
| 203 |
+
|
| 204 |
+
**์ ์ฐจ:**
|
| 205 |
+
```bash
|
| 206 |
+
# 1. ์ค์น
|
| 207 |
+
pip install labelImg
|
| 208 |
+
|
| 209 |
+
# 2. ์คํ
|
| 210 |
+
labelImg
|
| 211 |
+
|
| 212 |
+
# 3. ์ด๋ฏธ์ง ํด๋ ์ด๊ธฐ: data/ํฐ๋ค๋ฆฌ์์ฐ ์ค์ธก ๋ฐ์ดํฐ_์ตํฌ์ค์์ด์์ด(์ฃผ)/251015/
|
| 213 |
+
# 4. ์์ฐ์ ๋ฐ์ด๋ฉ ๋ฐ์ค ๊ทธ๋ฆฌ๊ธฐ
|
| 214 |
+
# 5. COCO JSON ํ์์ผ๋ก ์ ์ฅ
|
| 215 |
+
```
|
| 216 |
+
|
| 217 |
+
**์ถ๋ ฅ:**
|
| 218 |
+
```json
|
| 219 |
+
{
|
| 220 |
+
"images": [
|
| 221 |
+
{"id": 1, "file_name": "251015_01.jpg", "width": 4032, "height": 3024}
|
| 222 |
+
],
|
| 223 |
+
"annotations": [
|
| 224 |
+
{
|
| 225 |
+
"id": 1,
|
| 226 |
+
"image_id": 1,
|
| 227 |
+
"category_id": 1,
|
| 228 |
+
"bbox": [238, 441, 601, 139],
|
| 229 |
+
"area": 83539
|
| 230 |
+
}
|
| 231 |
+
],
|
| 232 |
+
"categories": [
|
| 233 |
+
{"id": 1, "name": "shrimp"}
|
| 234 |
+
]
|
| 235 |
+
}
|
| 236 |
+
```
|
| 237 |
+
|
| 238 |
+
---
|
| 239 |
+
|
| 240 |
+
#### ๋ฐฉ๋ฒ 2: ๋ํํ ๋๊ตฌ (Interactive Validation)
|
| 241 |
+
|
| 242 |
+
**๋๊ตฌ**: `interactive_validation.py` ์ "์๋ ๋ถ์" ํญ
|
| 243 |
+
|
| 244 |
+
**์ ์ฐจ:**
|
| 245 |
+
```
|
| 246 |
+
1. ์ด๋ฏธ์ง ์
๋ก๋
|
| 247 |
+
2. ์ด๋ฏธ์ง ๋ทฐ์ด๋ก ํฝ์
์ขํ ํ์ธ
|
| 248 |
+
3. x1, y1, x2, y2 ์
๋ ฅ
|
| 249 |
+
4. ๋ถ์ ์คํ (๊ฒ์ฆ์ฉ)
|
| 250 |
+
5. ground_truth.json์ ์๋ ๊ธฐ๋ก
|
| 251 |
+
```
|
| 252 |
+
|
| 253 |
+
**ground_truth.json ํ์:**
|
| 254 |
+
```json
|
| 255 |
+
{
|
| 256 |
+
"251015_01.jpg": [
|
| 257 |
+
{"bbox": [238, 441, 839, 580], "label": "shrimp"}
|
| 258 |
+
],
|
| 259 |
+
"251015_02.jpg": [
|
| 260 |
+
{"bbox": [220, 450, 820, 590], "label": "shrimp"}
|
| 261 |
+
]
|
| 262 |
+
}
|
| 263 |
+
```
|
| 264 |
+
|
| 265 |
+
---
|
| 266 |
+
|
| 267 |
+
### B. ์ ๋์ ํ๊ฐ ์คํ
|
| 268 |
+
|
| 269 |
+
**๋๊ตฌ**: `test_quantitative_evaluation.py`
|
| 270 |
+
|
| 271 |
+
**์ ์ฐจ:**
|
| 272 |
+
```bash
|
| 273 |
+
# 1. ground_truth.json ์์ฑ
|
| 274 |
+
# 2. ํ๊ฐ ์คํ
|
| 275 |
+
python test_quantitative_evaluation.py
|
| 276 |
+
|
| 277 |
+
# ์ถ๋ ฅ:
|
| 278 |
+
# Precision: 85% (๊ฒ์ถํ ๊ฒ ์ค 85%๊ฐ ์ค์ ์์ฐ)
|
| 279 |
+
# Recall: 90% (์ค์ ์์ฐ ์ค 90%๋ฅผ ๊ฒ์ถ)
|
| 280 |
+
# F1 Score: 87.4% (์ ์ฒด ์ฑ๋ฅ)
|
| 281 |
+
```
|
| 282 |
+
|
| 283 |
+
**๋ฉํธ๋ฆญ ํด์:**
|
| 284 |
+
```
|
| 285 |
+
Precision = TP / (TP + FP)
|
| 286 |
+
- ๋์์๋ก ์ค๊ฒ์ถ ์ ์
|
| 287 |
+
- ๋ชฉํ: > 80%
|
| 288 |
+
|
| 289 |
+
Recall = TP / (TP + FN)
|
| 290 |
+
- ๋์์๋ก ๋ฏธ๊ฒ์ถ ์ ์
|
| 291 |
+
- ๋ชฉํ: > 75%
|
| 292 |
+
|
| 293 |
+
F1 Score = 2 ร (P ร R) / (P + R)
|
| 294 |
+
- ์ ์ฒด ๊ท ํ
|
| 295 |
+
- ๋ชฉํ: > 77%
|
| 296 |
+
```
|
| 297 |
+
|
| 298 |
+
**๊ฐ์ ๋ฐฉํฅ:**
|
| 299 |
+
```
|
| 300 |
+
Low Precision (์ค๊ฒ์ถ ๋ง์):
|
| 301 |
+
โ ํํฐ ์ ์ ์๊ณ๊ฐ ์ฆ๊ฐ (75 โ 80)
|
| 302 |
+
โ ๊ท์น ๊ฐํ (์ธ์ฅ๋ < 0.45)
|
| 303 |
+
|
| 304 |
+
Low Recall (๋ฏธ๊ฒ์ถ ๋ง์):
|
| 305 |
+
โ ํํฐ ์ ์ ์๊ณ๊ฐ ๊ฐ์ (75 โ 70)
|
| 306 |
+
โ ๊ท์น ์ํ (์ข
ํก๋น 2.5~10)
|
| 307 |
+
|
| 308 |
+
Low F1:
|
| 309 |
+
โ RT-DETR ์ ๋ขฐ๋ ์กฐ์
|
| 310 |
+
โ ๋ชจ๋ธ ์ฌํ์ต ๊ณ ๋ ค
|
| 311 |
+
```
|
| 312 |
+
|
| 313 |
+
---
|
| 314 |
+
|
| 315 |
+
### C. ๊ฒ์ฆ ์ํฌํ๋ก์ฐ
|
| 316 |
+
|
| 317 |
+
```mermaid
|
| 318 |
+
graph TD
|
| 319 |
+
A[์ด๋ฏธ์ง ์ค๋น] --> B[๋ผ๋ฒจ๋ง]
|
| 320 |
+
B --> C[ground_truth.json ์์ฑ]
|
| 321 |
+
C --> D[์ ๋์ ํ๊ฐ ์คํ]
|
| 322 |
+
D --> E{์ฑ๋ฅ ๋ชฉํ ๋ฌ์ฑ?}
|
| 323 |
+
E -->|Yes| F[๋ฐฐํฌ]
|
| 324 |
+
E -->|No| G[๊ท์น ์กฐ์ ]
|
| 325 |
+
G --> D
|
| 326 |
+
```
|
| 327 |
+
|
| 328 |
+
**์ต์ ๋ฐ์ดํฐ๋:**
|
| 329 |
+
- **๊ฐ๋ฐ**: 10~20์ฅ
|
| 330 |
+
- **๊ฒ์ฆ**: 50~100์ฅ
|
| 331 |
+
- **ํ๋ก๋์
**: 200+ ์ฅ
|
| 332 |
+
|
| 333 |
+
---
|
| 334 |
+
|
| 335 |
+
## 3๏ธโฃ ์ค๋ฌด ๊ฒ์ฆ ์ ๋ต
|
| 336 |
+
|
| 337 |
+
### Phase 1: ๋น ๋ฅธ ๊ฒ์ฆ (1์๊ฐ)
|
| 338 |
+
|
| 339 |
+
**๋ชฉํ**: ๋๋ต์ ์ธ ์ฑ๋ฅ ํ์
|
| 340 |
+
|
| 341 |
+
**๋ฐฉ๋ฒ:**
|
| 342 |
+
```
|
| 343 |
+
1. ์ด๋ฏธ์ง 10์ฅ ์ ํ
|
| 344 |
+
2. ์๋์ผ๋ก ์์ฐ ๊ฐ์๋ง ์ธ๊ธฐ
|
| 345 |
+
์: 251015_01.jpg โ 1๋ง๋ฆฌ
|
| 346 |
+
3. ํํฐ ๊ฒฐ๊ณผ์ ๋น๊ต
|
| 347 |
+
4. ์ ํ๋ = ๋ง์ถ ๊ฐ์ / ์ ์ฒด ๊ฐ์
|
| 348 |
+
```
|
| 349 |
+
|
| 350 |
+
**์์:**
|
| 351 |
+
```
|
| 352 |
+
์ด๋ฏธ์ง 10์ฅ, ์ด ์์ฐ 12๋ง๋ฆฌ
|
| 353 |
+
|
| 354 |
+
ํํฐ ๊ฒฐ๊ณผ:
|
| 355 |
+
- ์ ํํ ๊ฒ์ถ: 10๋ง๋ฆฌ
|
| 356 |
+
- ์ค๊ฒ์ถ: 2๊ฐ (์ 1๊ฐ, ๋ฐฐ๊ฒฝ 1๊ฐ)
|
| 357 |
+
- ๋ฏธ๊ฒ์ถ: 2๋ง๋ฆฌ
|
| 358 |
+
|
| 359 |
+
์ ํ๋ = 10/12 = 83%
|
| 360 |
+
์ค๊ฒ์ถ๋ฅ = 2/12 = 17%
|
| 361 |
+
```
|
| 362 |
+
|
| 363 |
+
**ํ๋จ:**
|
| 364 |
+
- 80% ์ด์: ๊ด์ฐฎ์, ๊ณ์ ์งํ
|
| 365 |
+
- 60~80%: ๊ฐ์ ํ์
|
| 366 |
+
- 60% ๋ฏธ๋ง: ๊ท์น ์ฌ์ค๊ณ
|
| 367 |
+
|
| 368 |
+
---
|
| 369 |
+
|
| 370 |
+
### Phase 2: ์ ๋ฐ ๊ฒ์ฆ (1์ผ)
|
| 371 |
+
|
| 372 |
+
**๋ชฉํ**: ์ ํํ ์ฑ๋ฅ ์ธก์
|
| 373 |
+
|
| 374 |
+
**๋ฐฉ๋ฒ:**
|
| 375 |
+
```
|
| 376 |
+
1. ์ด๋ฏธ์ง 50์ฅ ๋ผ๋ฒจ๋ง (2~3์๊ฐ)
|
| 377 |
+
2. ground_truth.json ์์ฑ
|
| 378 |
+
3. test_quantitative_evaluation.py ์คํ
|
| 379 |
+
4. Precision, Recall, F1 ํ์ธ
|
| 380 |
+
5. ์๋ฌ ๋ถ์
|
| 381 |
+
```
|
| 382 |
+
|
| 383 |
+
**์๋ฌ ๋ถ์:**
|
| 384 |
+
```python
|
| 385 |
+
# False Positive (์ค๊ฒ์ถ) ๋ถ์
|
| 386 |
+
for fp in false_positives:
|
| 387 |
+
print(f"์ค๊ฒ์ถ: {fp['bbox']}, ์ ์: {fp['score']}")
|
| 388 |
+
print(f"์ด์ : {fp['reasons']}")
|
| 389 |
+
# ํจํด ์ฐพ๊ธฐ: ๋๋ถ๋ถ ์? โ ์ข
ํก๋น ๊ท์น ๊ฐํ
|
| 390 |
+
|
| 391 |
+
# False Negative (๋ฏธ๊ฒ์ถ) ๋ถ์
|
| 392 |
+
for fn in false_negatives:
|
| 393 |
+
print(f"๋ฏธ๊ฒ์ถ: {fn['bbox']}")
|
| 394 |
+
# ํจํด ์ฐพ๊ธฐ: ์์ ์์ฐ? โ ๋ฉด์ ๋น ํํ ๋ฎ์ถ๊ธฐ
|
| 395 |
+
```
|
| 396 |
+
|
| 397 |
+
---
|
| 398 |
+
|
| 399 |
+
### Phase 3: ์ง์์ ๊ฐ์ (1์ฃผ)
|
| 400 |
+
|
| 401 |
+
**๋ชฉํ**: ํ๋ก๋์
์์ค ์ฑ๋ฅ
|
| 402 |
+
|
| 403 |
+
**๋ฐฉ๋ฒ:**
|
| 404 |
+
```
|
| 405 |
+
1. ๋ค์ํ ์กฐ๊ฑด ์ด๋ฏธ์ง ์์ง
|
| 406 |
+
- ์กฐ๋ช
๋ค์
|
| 407 |
+
- ๊ฐ๋ ๋ค์
|
| 408 |
+
- ์์ฐ ํฌ๊ธฐ ๋ค์
|
| 409 |
+
2. 100~200์ฅ ๋ผ๋ฒจ๋ง
|
| 410 |
+
3. ๊ต์ฐจ ๊ฒ์ฆ (Train/Validation/Test split)
|
| 411 |
+
4. ์ต์ ํ๋ผ๋ฏธํฐ ์ฐพ๊ธฐ
|
| 412 |
+
```
|
| 413 |
+
|
| 414 |
+
**๊ต์ฐจ ๊ฒ์ฆ:**
|
| 415 |
+
```python
|
| 416 |
+
# ๋ฐ์ดํฐ์
๋ถํ
|
| 417 |
+
train: 60% (ํ์ต์ฉ - ๊ท์น ๊ฐ๋ฐ)
|
| 418 |
+
val: 20% (๊ฒ์ฆ์ฉ - ํ๋ผ๋ฏธํฐ ํ๋)
|
| 419 |
+
test: 20% (ํ
์คํธ์ฉ - ์ต์ข
ํ๊ฐ)
|
| 420 |
+
|
| 421 |
+
# ๋ชฉํ
|
| 422 |
+
Test F1 Score > 85%
|
| 423 |
+
```
|
| 424 |
+
|
| 425 |
+
---
|
| 426 |
+
|
| 427 |
+
## 4๏ธโฃ NMS (Non-Maximum Suppression) ๊ฒ์ฆ
|
| 428 |
+
|
| 429 |
+
### ๋ชฉ์
|
| 430 |
+
- ์ค๋ณต ๊ฒ์ถ ์ ๊ฑฐ
|
| 431 |
+
- ๊ฒ์ถ ๊ฐ์ = ์ค์ ์์ฐ ์
|
| 432 |
+
|
| 433 |
+
### ๊ฒ์ฆ ๋ฐฉ๋ฒ
|
| 434 |
+
|
| 435 |
+
**Before NMS:**
|
| 436 |
+
```
|
| 437 |
+
RT-DETR ๊ฒ์ถ: 3๊ฐ
|
| 438 |
+
์ค์ ์์ฐ: 1๋ง๋ฆฌ
|
| 439 |
+
โ ์ค๋ณต ๊ฒ์ถ ๋ฌธ์
|
| 440 |
+
```
|
| 441 |
+
|
| 442 |
+
**After NMS (IoU > 0.5):**
|
| 443 |
+
```
|
| 444 |
+
NMS ํ: 1๊ฐ
|
| 445 |
+
์ค์ ์์ฐ: 1๋ง๋ฆฌ
|
| 446 |
+
โ ์ ํ!
|
| 447 |
+
```
|
| 448 |
+
|
| 449 |
+
**์๊ฐ์ ํ์ธ:**
|
| 450 |
+
```
|
| 451 |
+
1. ์์ ์ด๋ฏธ์ง ๋ก๋
|
| 452 |
+
2. "์ ์ฒด ๊ฒ์ถ ํ์" ์ผ๊ธฐ
|
| 453 |
+
3. ํ์ ๋ฐ์ค(์ ์ฒด) vs ๋
น์ ๋ฐ์ค(NMS ํ) ๋น๊ต
|
| 454 |
+
4. ๊ฒน์น๋ ๋ฐ์ค๊ฐ ํ๋๋ก ํฉ์ณ์ก๋์ง ํ์ธ
|
| 455 |
+
```
|
| 456 |
+
|
| 457 |
+
**์ ๋์ ํ์ธ:**
|
| 458 |
+
```python
|
| 459 |
+
# ์ค๋ณต๋ฅ ๊ณ์ฐ
|
| 460 |
+
์ค๋ณต๋ฅ = (NMS์ ๊ฐ์ - NMSํ ๊ฐ์) / NMS์ ๊ฐ์
|
| 461 |
+
|
| 462 |
+
# ์์
|
| 463 |
+
Before: 15๊ฐ
|
| 464 |
+
After: 10๊ฐ
|
| 465 |
+
์ค๋ณต๋ฅ = (15-10)/15 = 33%
|
| 466 |
+
```
|
| 467 |
+
|
| 468 |
+
---
|
| 469 |
+
|
| 470 |
+
## 5๏ธโฃ ํ์ฌ ์์คํ
๊ฒ์ฆ ์ํ
|
| 471 |
+
|
| 472 |
+
### โ
๊ตฌํ ์๋ฃ
|
| 473 |
+
|
| 474 |
+
1. **์๊ฐ์ ๊ฒ์ฆ ๋๊ตฌ**
|
| 475 |
+
- `interactive_validation.py`
|
| 476 |
+
- ๋นจ๊ฐ/๋
น์ ๋ฐ์ค๋ก ๊ฒฐ๊ณผ ํ์
|
| 477 |
+
- ์ ๊ฑฐ ์ด์ ์์ธ ํ์
|
| 478 |
+
|
| 479 |
+
2. **์ ๋์ ํ๊ฐ ํ๋ ์์ํฌ**
|
| 480 |
+
- `test_quantitative_evaluation.py`
|
| 481 |
+
- Precision, Recall, F1 ๊ณ์ฐ
|
| 482 |
+
- Confusion Matrix ์์ฑ
|
| 483 |
+
|
| 484 |
+
3. **NMS ๊ตฌํ**
|
| 485 |
+
- IoU > 0.5 ๊ธฐ์ค ์ค๋ณต ์ ๊ฑฐ
|
| 486 |
+
- ์ ์ ๋์ ๋ฐ์ค ์ฐ์ ์ ์ง
|
| 487 |
+
|
| 488 |
+
4. **์์ ํํฐ ์ถ๊ฐ**
|
| 489 |
+
- Hue ๊ธฐ๋ฐ ์์ฐ/๋ฐฐ๊ฒฝ ๊ตฌ๋ถ
|
| 490 |
+
- ํฌ๋ช
์์ฐ ๊ฐ์ง
|
| 491 |
+
|
| 492 |
+
---
|
| 493 |
+
|
| 494 |
+
### โ ๋ฏธ์๋ฃ (Ground Truth ํ์)
|
| 495 |
+
|
| 496 |
+
1. **์ ๋์ ์ฑ๋ฅ ์ธก์ **
|
| 497 |
+
- Precision: ???
|
| 498 |
+
- Recall: ???
|
| 499 |
+
- F1: ???
|
| 500 |
+
|
| 501 |
+
2. **์๋ฌ ๋ถ์**
|
| 502 |
+
- ์ด๋ค ๊ฒฝ์ฐ์ ์ค๊ฒ์ถ?
|
| 503 |
+
- ์ด๋ค ์์ฐ๋ฅผ ๋์นจ?
|
| 504 |
+
|
| 505 |
+
3. **์ต์ ํ๋ผ๋ฏธํฐ**
|
| 506 |
+
- ํ์ฌ: ๊ฒฝํ์ ์ค์
|
| 507 |
+
- ํ์: ๋ฐ์ดํฐ ๊ธฐ๋ฐ ์ต์ ํ
|
| 508 |
+
|
| 509 |
+
---
|
| 510 |
+
|
| 511 |
+
## 6๏ธโฃ ๊ถ์ฅ Action Items
|
| 512 |
+
|
| 513 |
+
### ์ฆ์ (์ค๋):
|
| 514 |
+
```
|
| 515 |
+
โก interactive_validation.py๋ก ์์ 5๊ฐ ์๊ฐ์ ํ์ธ
|
| 516 |
+
โก ์ก์์ผ๋ก ๊ฒฐ๊ณผ ํ๋จ
|
| 517 |
+
โก ๋ช
๋ฐฑํ ์ค๋ฅ ์์ผ๋ฉด ๊ท์น ์กฐ์
|
| 518 |
+
```
|
| 519 |
+
|
| 520 |
+
### ๋จ๊ธฐ (์ด๋ฒ ์ฃผ):
|
| 521 |
+
```
|
| 522 |
+
โก ์ด๋ฏธ์ง 10์ฅ ์ ํ
|
| 523 |
+
โก ์์ฐ ๊ฐ์๋ง ์ธ๊ธฐ (๋ผ๋ฒจ๋ง ๋ถํ์)
|
| 524 |
+
โก ๊ฒ์ถ ์ ํ๋ ๊ณ์ฐ
|
| 525 |
+
โก 80% ์ด์์ด๋ฉด ์งํ, ๋ฏธ๋ง์ด๋ฉด ๊ฐ์
|
| 526 |
+
```
|
| 527 |
+
|
| 528 |
+
### ์ค๊ธฐ (์ด๋ฒ ๋ฌ):
|
| 529 |
+
```
|
| 530 |
+
โก ์ด๋ฏธ์ง 50์ฅ ๋ผ๋ฒจ๋ง
|
| 531 |
+
โก ground_truth.json ์์ฑ
|
| 532 |
+
โก ์ ๋์ ํ๊ฐ ์คํ
|
| 533 |
+
โก F1 > 80% ๋ฌ์ฑ
|
| 534 |
+
```
|
| 535 |
+
|
| 536 |
+
### ์ฅ๊ธฐ (ํ๋ก๋์
):
|
| 537 |
+
```
|
| 538 |
+
โก 200+ ์ฅ ๋ผ๋ฒจ๋ง
|
| 539 |
+
โก ๊ต์ฐจ ๊ฒ์ฆ
|
| 540 |
+
โก F1 > 85%
|
| 541 |
+
โก ๋๋ Roboflow ์ฌํ์ต
|
| 542 |
+
```
|
| 543 |
+
|
| 544 |
+
---
|
| 545 |
+
|
| 546 |
+
## 7๏ธโฃ ์ฐธ๊ณ ์๋ฃ
|
| 547 |
+
|
| 548 |
+
### ๋ด๋ถ ๋ฌธ์
|
| 549 |
+
- `docs/detection_testing_and_validation.md` - ์ ์ฒด ํ
์คํธ ํ๋ ์์ํฌ
|
| 550 |
+
- `docs/testing_framework_guide.md` - ์ฌ์ฉ์ ๊ฐ์ด๋
|
| 551 |
+
- `docs/universal_shrimp_detection_strategy.md` - ํํฐ ์ ๋ต
|
| 552 |
+
|
| 553 |
+
### ๋๊ตฌ
|
| 554 |
+
- `test_visual_validation.py` - ์๊ฐ์ ๊ฒ์ฆ ์คํฌ๋ฆฝํธ
|
| 555 |
+
- `test_quantitative_evaluation.py` - ์ ๋์ ํ๊ฐ ์คํฌ๋ฆฝํธ
|
| 556 |
+
- `interactive_validation.py` - ๋ํํ ๊ฒ์ฆ ์ธํฐํ์ด์ค
|
| 557 |
+
|
| 558 |
+
### ์ธ๋ถ ์๋ฃ
|
| 559 |
+
- [COCO Evaluation Metrics](https://cocodataset.org/#detection-eval)
|
| 560 |
+
- [LabelImg](https://github.com/tzutalin/labelImg)
|
| 561 |
+
- [CVAT Annotation Tool](https://github.com/opencv/cvat)
|
| 562 |
+
|
| 563 |
+
---
|
| 564 |
+
|
| 565 |
+
## ๐ ๊ฒฐ๋ก
|
| 566 |
+
|
| 567 |
+
### ํ์ฌ ์ํฉ:
|
| 568 |
+
- โ
ํํฐ ๋ก์ง ๊ตฌํ ์๋ฃ
|
| 569 |
+
- โ
์๊ฐ์ ๊ฒ์ฆ ๋๊ตฌ ์๋น
|
| 570 |
+
- โ ๏ธ **์ ๋์ ๊ฒ์ฆ ๋ถ๊ฐ** (Ground Truth ๋ถ์ฌ)
|
| 571 |
+
|
| 572 |
+
### ์ ๋ขฐ๋:
|
| 573 |
+
- ํด๋ฆฌ์คํฑ ๊ท์น: **70~80% ์ถ์ **
|
| 574 |
+
- ์ ํํ ์ฑ๋ฅ: **์ธก์ ๋ถ๊ฐ**
|
| 575 |
+
|
| 576 |
+
### ๊ฐ์ ๋ฐฉ๋ฒ:
|
| 577 |
+
1. **๋จ๊ธฐ**: 10์ฅ ์ํ ํ
์คํธ
|
| 578 |
+
2. **์ค๊ธฐ**: 50์ฅ ๋ผ๋ฒจ๋ง โ ์ ๋ ํ๊ฐ
|
| 579 |
+
3. **์ฅ๊ธฐ**: Roboflow ์ฌํ์ต (200+ ์ฅ)
|
| 580 |
+
|
| 581 |
+
### ์ต์ข
๊ถ์ฅ:
|
| 582 |
+
**Roboflow ์ฌํ์ต**์ด ๊ฐ์ฅ ํจ๊ณผ์ !
|
| 583 |
+
- ํ์ฌ ํํฐ: 70~80% ์ถ์
|
| 584 |
+
- Roboflow Fine-tuning: 90%+ ๊ธฐ๋
|
| 585 |
+
|
| 586 |
+
---
|
| 587 |
+
|
| 588 |
+
**๋ง์ง๋ง ์
๋ฐ์ดํธ**: 2025-11-10
|
| 589 |
+
**์์ฑ์**: Claude Code
|
docs/gradio_warnings.md
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Gradio ๋ธ๋ผ์ฐ์ ๊ฒฝ๊ณ ์ค๋ช
|
| 2 |
+
|
| 3 |
+
## ๐ ๋ฐ์ํ๋ ๊ฒฝ๊ณ ๋ค
|
| 4 |
+
|
| 5 |
+
### 1. postMessage Origin Mismatch
|
| 6 |
+
```
|
| 7 |
+
Failed to execute 'postMessage' on 'DOMWindow':
|
| 8 |
+
The target origin provided ('https://huggingface.co')
|
| 9 |
+
does not match the recipient window's origin ('http://localhost:7862')
|
| 10 |
+
```
|
| 11 |
+
|
| 12 |
+
**์์ธ:** Gradio ๋ด๋ถ ํ
๋ ๋ฉํธ๋ฆฌ ์ฝ๋
|
| 13 |
+
**์ํฅ:** ์์ (๊ธฐ๋ฅ ์ ์)
|
| 14 |
+
**ํด๊ฒฐ:** ๋ถํ์ (๋ฌด์ ๊ฐ๋ฅ)
|
| 15 |
+
|
| 16 |
+
---
|
| 17 |
+
|
| 18 |
+
### 2. ํฐํธ ํ์ผ 404
|
| 19 |
+
```
|
| 20 |
+
ui-sans-serif-Regular.woff2: 404
|
| 21 |
+
ui-sans-serif-Bold.woff2: 404
|
| 22 |
+
system-ui-Regular.woff2: 404
|
| 23 |
+
system-ui-Bold.woff2: 404
|
| 24 |
+
```
|
| 25 |
+
|
| 26 |
+
**์์ธ:** Gradio CSS๊ฐ ์กด์ฌํ์ง ์๋ ํฐํธ ์์ฒญ
|
| 27 |
+
**์ํฅ:** ์์ (์์คํ
ํฐํธ ์๋ ์ฌ์ฉ)
|
| 28 |
+
**ํด๊ฒฐ:** ๋ถํ์ (๋ฌด์ ๊ฐ๋ฅ)
|
| 29 |
+
|
| 30 |
+
---
|
| 31 |
+
|
| 32 |
+
### 3. manifest.json 404
|
| 33 |
+
```
|
| 34 |
+
Manifest fetch from http://localhost:7862/manifest.json failed, code 404
|
| 35 |
+
```
|
| 36 |
+
|
| 37 |
+
**์์ธ:** ๋ธ๋ผ์ฐ์ ๊ฐ PWA manifest ์์ฒญ
|
| 38 |
+
**์ํฅ:** ์์ (PWA ๊ธฐ๋ฅ๋ง ๋นํ์ฑํ)
|
| 39 |
+
**ํด๊ฒฐ:** ๋ถํ์ (๋ฌด์ ๊ฐ๋ฅ)
|
| 40 |
+
|
| 41 |
+
---
|
| 42 |
+
|
| 43 |
+
## โ
๊ฒฐ๋ก
|
| 44 |
+
|
| 45 |
+
**๋ชจ๋ ๊ฒฝ๊ณ ๋ ๋ฌดํดํฉ๋๋ค!**
|
| 46 |
+
|
| 47 |
+
- ๋ผ๋ฒจ๋ง ๋๊ตฌ์ ๋ชจ๋ ๊ธฐ๋ฅ ์ ์ ์๋
|
| 48 |
+
- ๋ฐ์ดํฐ ์ ์ฅ/๋ก๋ ์ ์
|
| 49 |
+
- ์ฑ๋ฅ์ ์ํฅ ์์
|
| 50 |
+
|
| 51 |
+
---
|
| 52 |
+
|
| 53 |
+
## ๐ ๋ธ๋ผ์ฐ์ ์ฝ์ ๊ฒฝ๊ณ ์จ๊ธฐ๊ธฐ
|
| 54 |
+
|
| 55 |
+
**๋ฐฉ๋ฒ 1: ์ฝ์ ํํฐ**
|
| 56 |
+
```
|
| 57 |
+
1. F12 โ Console ํญ
|
| 58 |
+
2. ํํฐ ์์ด์ฝ ํด๋ฆญ
|
| 59 |
+
3. "Hide network messages" ์ฒดํฌ
|
| 60 |
+
```
|
| 61 |
+
|
| 62 |
+
**๋ฐฉ๋ฒ 2: ๊ฒฝ๊ณ ๋ ๋ฒจ ์กฐ์ **
|
| 63 |
+
```
|
| 64 |
+
1. F12 โ Console ํญ
|
| 65 |
+
2. "Default levels" โ "Errors" only
|
| 66 |
+
```
|
| 67 |
+
|
| 68 |
+
---
|
| 69 |
+
|
| 70 |
+
**์ฐธ๊ณ :** ์ด ๊ฒฝ๊ณ ๋ค์ Gradio ํ๋ ์์ํฌ์ ์ผ๋ฐ์ ์ธ ๋์์ด๋ฉฐ, ๋ชจ๋ Gradio ์ฑ์์ ๋ฐ์ํฉ๋๋ค.
|
docs/ground_truth_labeling_guide.md
ADDED
|
@@ -0,0 +1,460 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# ๐ท๏ธ Ground Truth ๋ผ๋ฒจ๋ง ์์
๊ฐ์ด๋
|
| 2 |
+
|
| 3 |
+
## ๐ ๋ฌธ์ ์ ๋ณด
|
| 4 |
+
|
| 5 |
+
- **์์ฑ์ผ**: 2025-11-10
|
| 6 |
+
- **๋ฒ์ **: 1.0
|
| 7 |
+
- **๋ชฉ์ **: RT-DETR ํํฐ ์ฑ๋ฅ ์ธก์ ์ ์ํ Ground Truth ๋ฐ์ดํฐ ์์ฑ
|
| 8 |
+
|
| 9 |
+
---
|
| 10 |
+
|
| 11 |
+
## ๐ฏ ๋ชฉํ
|
| 12 |
+
|
| 13 |
+
**์ ๋์ ์ฑ๋ฅ ์ธก์ ์ ์ํ ์ ๋ต ๋ฐ์ดํฐ ์์ฑ**
|
| 14 |
+
|
| 15 |
+
- Precision, Recall, F1 Score ๊ณ์ฐ
|
| 16 |
+
- ํํฐ ๊ท์น ๊ฒ์ฆ
|
| 17 |
+
- ์ฑ๋ฅ ๊ฐ์ ๋ฐฉํฅ ๊ฒฐ์
|
| 18 |
+
|
| 19 |
+
---
|
| 20 |
+
|
| 21 |
+
## ๐ ๋ฐ์ดํฐ ๊ตฌ์กฐ
|
| 22 |
+
|
| 23 |
+
### ์๋ณธ ๋ฐ์ดํฐ ์์น
|
| 24 |
+
|
| 25 |
+
```
|
| 26 |
+
data/ํฐ๋ค๋ฆฌ์์ฐ ์ค์ธก ๋ฐ์ดํฐ_์ตํฌ์ค์์ด์์ด(์ฃผ)/
|
| 27 |
+
โโโ 250818/
|
| 28 |
+
โ โโโ 250818_01.jpg
|
| 29 |
+
โ โโโ 250818_01-1.jpg
|
| 30 |
+
โ โโโ 250818_02.jpg
|
| 31 |
+
โ โโโ ...
|
| 32 |
+
โโโ 250820/
|
| 33 |
+
โ โโโ 250820_01.jpg
|
| 34 |
+
โ โโโ ...
|
| 35 |
+
โโโ 251015/
|
| 36 |
+
โ โโโ 251015_01.jpg
|
| 37 |
+
โ โโโ ...
|
| 38 |
+
โโโ ... (์ด 27๊ฐ ํด๋)
|
| 39 |
+
```
|
| 40 |
+
|
| 41 |
+
### ๋ค์ด๋ฐ ๊ท์น
|
| 42 |
+
|
| 43 |
+
- **ํด๋**: `YYMMDD` ํ์ (์: 250818 = 2025๋
8์ 18์ผ)
|
| 44 |
+
- **ํ์ผ**: `YYMMDD_NN.jpg` ๋๋ `YYMMDD_NN-1.jpg`
|
| 45 |
+
- NN: ์ผ๋ จ๋ฒํธ (01, 02, ...)
|
| 46 |
+
- -1: ๊ฐ์ ์์ฐ์ ๋ค๋ฅธ ๊ฐ๋/ํ๋ ์ด๋ฏธ์ง
|
| 47 |
+
|
| 48 |
+
---
|
| 49 |
+
|
| 50 |
+
## ๐ ๏ธ ๋ผ๋ฒจ๋ง ๋๊ตฌ
|
| 51 |
+
|
| 52 |
+
### ๋๊ตฌ๋ช
: `labeling_tool.py`
|
| 53 |
+
|
| 54 |
+
**ํน์ง:**
|
| 55 |
+
- RT-DETR๋ก ์๋ ๊ฒ์ถ
|
| 56 |
+
- ์ฌ์ฉ์๊ฐ ์ฌ๋ฐ๋ฅธ ๋ฐ์ค๋ง ์ ํ
|
| 57 |
+
- ๊ฐํธํ ํด๋ฆญ ์ธํฐํ์ด์ค
|
| 58 |
+
- ์๋ ์ ์ฅ
|
| 59 |
+
|
| 60 |
+
### ์คํ ๋ฐฉ๋ฒ
|
| 61 |
+
|
| 62 |
+
```bash
|
| 63 |
+
python labeling_tool.py
|
| 64 |
+
```
|
| 65 |
+
|
| 66 |
+
**์ ์:**
|
| 67 |
+
```
|
| 68 |
+
http://localhost:7862
|
| 69 |
+
```
|
| 70 |
+
|
| 71 |
+
---
|
| 72 |
+
|
| 73 |
+
## ๐ ์์
์ ์ฐจ
|
| 74 |
+
|
| 75 |
+
### Phase 1: ์ค๋น (5๋ถ)
|
| 76 |
+
|
| 77 |
+
```
|
| 78 |
+
1. labeling_tool.py ์คํ
|
| 79 |
+
2. ๋ธ๋ผ์ฐ์ ์์ http://localhost:7862 ์ ์
|
| 80 |
+
3. ๋ผ๋ฒจ๋งํ ํด๋ ์ ํ (์: 251015)
|
| 81 |
+
4. ์์ ๋ฒํผ ํด๋ฆญ
|
| 82 |
+
```
|
| 83 |
+
|
| 84 |
+
---
|
| 85 |
+
|
| 86 |
+
### Phase 2: ๋ผ๋ฒจ๋ง (1์๊ฐ / 50์ฅ ๊ธฐ์ค)
|
| 87 |
+
|
| 88 |
+
#### ํ๋ฉด ๊ตฌ์ฑ
|
| 89 |
+
|
| 90 |
+
```
|
| 91 |
+
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
| 92 |
+
โ ์ด๋ฏธ์ง: 251015_01.jpg (1/20) โ
|
| 93 |
+
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค
|
| 94 |
+
โ โ
|
| 95 |
+
โ [์ด๋ฏธ์ง + RT-DETR ๊ฒ์ถ ๋ฐ์ค] โ
|
| 96 |
+
โ โ
|
| 97 |
+
โ - ๋
น์ ๋ฐ์ค: RT-DETR ๊ฒ์ถ ๊ฒฐ๊ณผ โ
|
| 98 |
+
โ - ํด๋ฆญํ๋ฉด ์ ํ/ํด์ ํ ๊ธ โ
|
| 99 |
+
โ โ
|
| 100 |
+
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค
|
| 101 |
+
โ ์ ํ๋ ๋ฐ์ค: 1๊ฐ โ
|
| 102 |
+
โ โ
|
| 103 |
+
โ [์ด์ ] [๊ฑด๋๋ฐ๊ธฐ] [๋ค์] [์๋ฃ] โ
|
| 104 |
+
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
| 105 |
+
```
|
| 106 |
+
|
| 107 |
+
#### ์์
๋จ๊ณ
|
| 108 |
+
|
| 109 |
+
**1๋จ๊ณ: ์ด๋ฏธ์ง ํ์ธ**
|
| 110 |
+
```
|
| 111 |
+
- RT-DETR์ด ์๋์ผ๋ก ๋ฐ์ค ๊ฒ์ถ
|
| 112 |
+
- ๋
น์ ๋ฐ์ค๋ก ํ์๋จ
|
| 113 |
+
```
|
| 114 |
+
|
| 115 |
+
**2๋จ๊ณ: ์์ฐ ๋ฐ์ค ์ ํ**
|
| 116 |
+
```
|
| 117 |
+
- ์์ฐ๊ฐ ๋ง๋ ๋ฐ์ค ํด๋ฆญ โ ํ๋์์ผ๋ก ๋ณ๊ฒฝ (์ ํ๋จ)
|
| 118 |
+
- ์๋ชป ์ ํ ์ ๋ค์ ํด๋ฆญ โ ๋
น์์ผ๋ก ๋๋๋ฆผ
|
| 119 |
+
- ์ฌ๋ฌ ๋ฐ์ค ์ ํ ๊ฐ๋ฅ
|
| 120 |
+
```
|
| 121 |
+
|
| 122 |
+
**3๋จ๊ณ: ํ์ธ ๋ฐ ์ ์ฅ**
|
| 123 |
+
```
|
| 124 |
+
- "๋ค์" ๋ฒํผ ํด๋ฆญ
|
| 125 |
+
- ์๋์ผ๋ก ground_truth.json์ ์ ์ฅ
|
| 126 |
+
- ๋ค์ ์ด๋ฏธ์ง๋ก ์ด๋
|
| 127 |
+
```
|
| 128 |
+
|
| 129 |
+
#### ํน์ ์ผ์ด์ค
|
| 130 |
+
|
| 131 |
+
**์์ฐ๊ฐ ๊ฒ์ถ ์ ๋จ:**
|
| 132 |
+
```
|
| 133 |
+
โ "๊ฑด๋๋ฐ๊ธฐ" ํด๋ฆญ (๋น ๋ฐฐ์ด๋ก ์ ์ฅ)
|
| 134 |
+
โ ๋์ค์ ์๋ ๋ผ๋ฒจ๋ง ํ์
|
| 135 |
+
```
|
| 136 |
+
|
| 137 |
+
**์์ฐ ์๋ ์ด๋ฏธ์ง:**
|
| 138 |
+
```
|
| 139 |
+
โ ์๋ฌด๊ฒ๋ ์ ํํ์ง ์๊ณ "๋ค์" ํด๋ฆญ
|
| 140 |
+
โ ๋น ๋ฐฐ์ด๋ก ์ ์ฅ
|
| 141 |
+
```
|
| 142 |
+
|
| 143 |
+
**๋ฐ์ค๊ฐ ์๋ชป๋จ (๊ฒฝ๊ณ๊ฐ ์ ๋ง์):**
|
| 144 |
+
```
|
| 145 |
+
โ ์ผ๋จ ์ ํํ๊ณ ์งํ
|
| 146 |
+
โ ๋์ค์ ์๋ ์กฐ์ ํ์
|
| 147 |
+
```
|
| 148 |
+
|
| 149 |
+
---
|
| 150 |
+
|
| 151 |
+
### Phase 3: ๊ฒ์ฆ (10๋ถ)
|
| 152 |
+
|
| 153 |
+
```
|
| 154 |
+
1. ground_truth.json ํ์ผ ์์ฑ ํ์ธ
|
| 155 |
+
2. ์ํ ์ฒดํฌ (5~10์ฅ)
|
| 156 |
+
3. ๋๋ฝ๋ ์ด๋ฏธ์ง ํ์ธ
|
| 157 |
+
4. ๋ฌธ์ ์์ผ๋ฉด ์ฌ์์
|
| 158 |
+
```
|
| 159 |
+
|
| 160 |
+
---
|
| 161 |
+
|
| 162 |
+
### Phase 4: ํ๊ฐ ์คํ (1๋ถ)
|
| 163 |
+
|
| 164 |
+
```bash
|
| 165 |
+
python test_quantitative_evaluation.py
|
| 166 |
+
```
|
| 167 |
+
|
| 168 |
+
**๊ฒฐ๊ณผ ํ์ธ:**
|
| 169 |
+
```
|
| 170 |
+
Precision: 85%
|
| 171 |
+
Recall: 90%
|
| 172 |
+
F1 Score: 87.4%
|
| 173 |
+
```
|
| 174 |
+
|
| 175 |
+
---
|
| 176 |
+
|
| 177 |
+
## ๐ ์์
๊ณํ
|
| 178 |
+
|
| 179 |
+
### ์ต์ ๋ชฉํ (Phase 1)
|
| 180 |
+
|
| 181 |
+
- **ํด๋**: 1~2๊ฐ ์ ํ
|
| 182 |
+
- **์ด๋ฏธ์ง**: 50์ฅ
|
| 183 |
+
- **์์ ์๊ฐ**: 1์๊ฐ
|
| 184 |
+
- **๋ชฉ์ **: ๋๋ต์ ์ธ ์ฑ๋ฅ ํ์
|
| 185 |
+
|
| 186 |
+
**์ถ์ฒ ํด๋:**
|
| 187 |
+
```
|
| 188 |
+
251015 (๊ฐ์ฅ ์ต๊ทผ)
|
| 189 |
+
251017
|
| 190 |
+
```
|
| 191 |
+
|
| 192 |
+
---
|
| 193 |
+
|
| 194 |
+
### ๊ถ์ฅ ๋ชฉํ (Phase 2)
|
| 195 |
+
|
| 196 |
+
- **ํด๋**: 3~5๊ฐ
|
| 197 |
+
- **์ด๋ฏธ์ง**: 100~150์ฅ
|
| 198 |
+
- **์์ ์๊ฐ**: 2~3์๊ฐ
|
| 199 |
+
- **๋ชฉ์ **: ์ ํํ ์ฑ๋ฅ ์ธก์
|
| 200 |
+
|
| 201 |
+
**์ถ์ฒ ํด๋:**
|
| 202 |
+
```
|
| 203 |
+
251015, 251013, 251010, 251008, 251001
|
| 204 |
+
```
|
| 205 |
+
|
| 206 |
+
---
|
| 207 |
+
|
| 208 |
+
### ์ต์ข
๋ชฉํ (Phase 3)
|
| 209 |
+
|
| 210 |
+
- **ํด๋**: 10๊ฐ+
|
| 211 |
+
- **์ด๋ฏธ์ง**: 200~300์ฅ
|
| 212 |
+
- **์์ ์๊ฐ**: 4~6์๊ฐ (๋ถํ ์์
๊ฐ๋ฅ)
|
| 213 |
+
- **๋ชฉ์ **: ํ๋ก๋์
์์ค ๊ฒ์ฆ
|
| 214 |
+
|
| 215 |
+
---
|
| 216 |
+
|
| 217 |
+
## ๐พ ์ถ๋ ฅ ํ์
|
| 218 |
+
|
| 219 |
+
### ground_truth.json
|
| 220 |
+
|
| 221 |
+
```json
|
| 222 |
+
{
|
| 223 |
+
"251015_01.jpg": [
|
| 224 |
+
{
|
| 225 |
+
"bbox": [238.5, 441.2, 839.1, 580.3],
|
| 226 |
+
"label": "shrimp",
|
| 227 |
+
"folder": "251015"
|
| 228 |
+
}
|
| 229 |
+
],
|
| 230 |
+
"251015_02.jpg": [
|
| 231 |
+
{
|
| 232 |
+
"bbox": [220.1, 450.5, 820.3, 590.2],
|
| 233 |
+
"label": "shrimp",
|
| 234 |
+
"folder": "251015"
|
| 235 |
+
}
|
| 236 |
+
],
|
| 237 |
+
"251015_03.jpg": []
|
| 238 |
+
}
|
| 239 |
+
```
|
| 240 |
+
|
| 241 |
+
**ํ๋ ์ค๋ช
:**
|
| 242 |
+
- `bbox`: [x1, y1, x2, y2] ์ขํ
|
| 243 |
+
- `label`: "shrimp" (๊ณ ์ )
|
| 244 |
+
- `folder`: ์๋ณธ ํด๋๋ช
(์ถ์ ์ฉ)
|
| 245 |
+
|
| 246 |
+
---
|
| 247 |
+
|
| 248 |
+
## ๐ฏ ์์
ํ
|
| 249 |
+
|
| 250 |
+
### ํจ์จ์ ์ธ ์์
|
| 251 |
+
|
| 252 |
+
**1. ํ ๋ฒ์ ๋ง์ด ํ์ง ๋ง๊ธฐ**
|
| 253 |
+
```
|
| 254 |
+
- 50์ฅ์ฉ ๋๋ ์ ์์
|
| 255 |
+
- ํด์ ์๊ฐ ํ๋ณด
|
| 256 |
+
- ์ง์ค๋ ฅ ์ ์ง
|
| 257 |
+
```
|
| 258 |
+
|
| 259 |
+
**2. ์ผ๊ด์ฑ ์ ์ง**
|
| 260 |
+
```
|
| 261 |
+
- ์ ๋งคํ ๊ฒฝ์ฐ ๊ฐ์ ๊ธฐ์ค ์ ์ฉ
|
| 262 |
+
- ์์ ์์ฐ๋ ํฌํจ
|
| 263 |
+
- ๋ถ๋ถ์ ์ผ๋ก ๋ณด์ด๋ ๊ฒ๋ ํฌํจ
|
| 264 |
+
```
|
| 265 |
+
|
| 266 |
+
**3. ๋น ๋ฅธ ์งํ**
|
| 267 |
+
```
|
| 268 |
+
- ์๋ฒฝํ์ง ์์๋ OK
|
| 269 |
+
- ๋๋ต์ ์ธ ๋ฐ์ค๋ง ๋ง์ผ๋ฉด ๋จ
|
| 270 |
+
- IoU 0.5 ์ด์์ด๋ฉด ์ ๋ต ์ฒ๋ฆฌ
|
| 271 |
+
```
|
| 272 |
+
|
| 273 |
+
**4. ์ฃผ๊ธฐ์ ์ ์ฅ**
|
| 274 |
+
```
|
| 275 |
+
- 10์ฅ๋ง๋ค ์๋ ์ ์ฅ
|
| 276 |
+
- ๋ธ๋ผ์ฐ์ ์๋ก๊ณ ์นจ ์ ํจ
|
| 277 |
+
- ์์
์ค๋จ ์ ์ด์ด์ ๊ฐ๋ฅ
|
| 278 |
+
```
|
| 279 |
+
|
| 280 |
+
---
|
| 281 |
+
|
| 282 |
+
## โ ๏ธ ์ฃผ์์ฌํญ
|
| 283 |
+
|
| 284 |
+
### ํ์ง ๋ง์์ผ ํ ๊ฒ
|
| 285 |
+
|
| 286 |
+
**โ ๋ฐ์ค ์ง์ ๊ทธ๋ฆฌ๊ธฐ**
|
| 287 |
+
```
|
| 288 |
+
โ RT-DETR ๊ฒ์ถ ๊ฒฐ๊ณผ๋ง ์ฌ์ฉ
|
| 289 |
+
โ ์๋ ๋ฐ์ค๋ Phase 2์์
|
| 290 |
+
```
|
| 291 |
+
|
| 292 |
+
**โ ๋๋ฌด ์๋ฒฝํ๊ฒ**
|
| 293 |
+
```
|
| 294 |
+
โ ํฝ์
๋จ์ ์ ํ๋ ๋ถํ์
|
| 295 |
+
โ IoU 0.5 ์ด์์ด๋ฉด ์ถฉ๋ถ
|
| 296 |
+
```
|
| 297 |
+
|
| 298 |
+
**โ ์์
์ค๋จ ์ ์๋ก๊ณ ์นจ**
|
| 299 |
+
```
|
| 300 |
+
โ ๋ฐ์ดํฐ ์์ค ๊ฐ๋ฅ
|
| 301 |
+
โ "์ ์ฅ" ๋ฒํผ ๋จผ์ ํด๋ฆญ
|
| 302 |
+
```
|
| 303 |
+
|
| 304 |
+
---
|
| 305 |
+
|
| 306 |
+
## ๐ ์์ ๊ฒฐ๊ณผ
|
| 307 |
+
|
| 308 |
+
### 50์ฅ ๋ผ๋ฒจ๋ง ํ
|
| 309 |
+
|
| 310 |
+
**Before (์ถ์ ):**
|
| 311 |
+
```
|
| 312 |
+
Precision: ???
|
| 313 |
+
Recall: ???
|
| 314 |
+
F1: ???
|
| 315 |
+
```
|
| 316 |
+
|
| 317 |
+
**After (์ธก์ ):**
|
| 318 |
+
```
|
| 319 |
+
Precision: 80~90%
|
| 320 |
+
Recall: 75~85%
|
| 321 |
+
F1: 77~87%
|
| 322 |
+
```
|
| 323 |
+
|
| 324 |
+
**๊ฐ์ ๋ฐฉํฅ ํ์
:**
|
| 325 |
+
```
|
| 326 |
+
- Low Precision โ ์ค๊ฒ์ถ ๊ฐ์
|
| 327 |
+
- Low Recall โ ๋ฏธ๊ฒ์ถ ๊ฐ์
|
| 328 |
+
- Low F1 โ ์ ์ฒด ์ฌ๊ฒํ
|
| 329 |
+
```
|
| 330 |
+
|
| 331 |
+
---
|
| 332 |
+
|
| 333 |
+
## ๐ ์์
์งํ ์ํฉ ์ถ์
|
| 334 |
+
|
| 335 |
+
### ์งํ๋ฅ ํ์ธ
|
| 336 |
+
|
| 337 |
+
**๋ฐฉ๋ฒ 1: ํ์ผ ๊ฐ์**
|
| 338 |
+
```bash
|
| 339 |
+
# ground_truth.json ์ํธ๋ฆฌ ๊ฐ์ ํ์ธ
|
| 340 |
+
python -c "import json; print(len(json.load(open('ground_truth.json'))))"
|
| 341 |
+
```
|
| 342 |
+
|
| 343 |
+
**๋ฐฉ๋ฒ 2: ์น UI**
|
| 344 |
+
```
|
| 345 |
+
๋ผ๋ฒจ๋ง ๋๊ตฌ ์๋จ์ ์งํ๋ฅ ํ์
|
| 346 |
+
์: "15/50 (30%)"
|
| 347 |
+
```
|
| 348 |
+
|
| 349 |
+
---
|
| 350 |
+
|
| 351 |
+
## ๐ ๋ฐฑ์
|
| 352 |
+
|
| 353 |
+
### ์๋ ๋ฐฑ์
|
| 354 |
+
|
| 355 |
+
```
|
| 356 |
+
ground_truth.json ์ ์ฅ ์ ์๋ ๋ฐฑ์
:
|
| 357 |
+
- ground_truth_backup_YYYYMMDD_HHMMSS.json
|
| 358 |
+
```
|
| 359 |
+
|
| 360 |
+
### ์๋ ๋ฐฑ์
|
| 361 |
+
|
| 362 |
+
```bash
|
| 363 |
+
# ์์
์
|
| 364 |
+
cp ground_truth.json ground_truth_backup.json
|
| 365 |
+
|
| 366 |
+
# ์์
ํ
|
| 367 |
+
cp ground_truth.json ground_truth_์๋ฃ.json
|
| 368 |
+
```
|
| 369 |
+
|
| 370 |
+
---
|
| 371 |
+
|
| 372 |
+
## ๐ ๋ค์ ๋จ๊ณ
|
| 373 |
+
|
| 374 |
+
### ๋ผ๋ฒจ๋ง ์๋ฃ ํ
|
| 375 |
+
|
| 376 |
+
1. **์ ๋์ ํ๊ฐ**
|
| 377 |
+
```bash
|
| 378 |
+
python test_quantitative_evaluation.py
|
| 379 |
+
```
|
| 380 |
+
|
| 381 |
+
2. **๊ฒฐ๊ณผ ๋ถ์**
|
| 382 |
+
```
|
| 383 |
+
- Confusion Matrix ํ์ธ
|
| 384 |
+
- PR Curve ์์ฑ
|
| 385 |
+
- ์๋ฌ ํจํด ๋ถ์
|
| 386 |
+
```
|
| 387 |
+
|
| 388 |
+
3. **ํํฐ ๊ฐ์ **
|
| 389 |
+
```
|
| 390 |
+
- ๊ท์น ์กฐ์
|
| 391 |
+
- ์๊ณ๊ฐ ํ๋
|
| 392 |
+
- ์ฌํ๊ฐ
|
| 393 |
+
```
|
| 394 |
+
|
| 395 |
+
4. **๋ชฉํ ๋ฌ์ฑ ์**
|
| 396 |
+
```
|
| 397 |
+
F1 > 85% โ ๋ฐฐํฌ
|
| 398 |
+
F1 < 85% โ Roboflow ์ฌํ์ต ๊ณ ๋ ค
|
| 399 |
+
```
|
| 400 |
+
|
| 401 |
+
---
|
| 402 |
+
|
| 403 |
+
## ๐ ๋ฌธ์ ํด๊ฒฐ
|
| 404 |
+
|
| 405 |
+
### ์์ฃผ ๋ฌป๋ ์ง๋ฌธ
|
| 406 |
+
|
| 407 |
+
**Q1: ๊ฒ์ถ์ด ๋๋ฌด ๋ง์์**
|
| 408 |
+
```
|
| 409 |
+
A: RT-DETR ์ ๋ขฐ๋๋ฅผ ๋์ด์ธ์ (0.3 โ 0.5)
|
| 410 |
+
๋ผ๋ฒจ๋ง ๋๊ตฌ ์ค์ ์์ ์กฐ์ ๊ฐ๋ฅ
|
| 411 |
+
```
|
| 412 |
+
|
| 413 |
+
**Q2: ๊ฒ์ถ์ด ํ๋๋ ์์ด์**
|
| 414 |
+
```
|
| 415 |
+
A: RT-DETR ์ ๋ขฐ๋๋ฅผ ๋ฎ์ถ์ธ์ (0.3 โ 0.2)
|
| 416 |
+
๋๋ "๊ฑด๋๋ฐ๊ธฐ"๋ก ํ์ ํ ์๋ ๋ผ๋ฒจ๋ง
|
| 417 |
+
```
|
| 418 |
+
|
| 419 |
+
**Q3: ์ค์๋ก ์๋ชป ์ ํํ์ด์**
|
| 420 |
+
```
|
| 421 |
+
A: ๋ค์ ํด๋ฆญํ๋ฉด ์ ํ ํด์ ๋จ
|
| 422 |
+
"์ด์ " ๋ฒํผ์ผ๋ก ๋๋๋ฆฌ๊ธฐ ๊ฐ๋ฅ
|
| 423 |
+
```
|
| 424 |
+
|
| 425 |
+
**Q4: ์์
์ด ๋๋ ค์**
|
| 426 |
+
```
|
| 427 |
+
A: ๋ชจ๋ธ ๋ก๋ฉ ์๊ฐ ๋๋ฌธ (์ฒ์์๋ง ๋๋ฆผ)
|
| 428 |
+
๋ ๋ฒ์งธ ์ด๋ฏธ์ง๋ถํฐ๋ ๋น ๋ฆ
|
| 429 |
+
```
|
| 430 |
+
|
| 431 |
+
---
|
| 432 |
+
|
| 433 |
+
## ๐ ์ฑ๊ณต ๊ธฐ์ค
|
| 434 |
+
|
| 435 |
+
### Phase 1 (50์ฅ)
|
| 436 |
+
```
|
| 437 |
+
โก ๋ผ๋ฒจ๋ง ์๋ฃ
|
| 438 |
+
โก ground_truth.json ์์ฑ
|
| 439 |
+
โก F1 Score ์ธก์
|
| 440 |
+
โก 70% ์ด์์ด๋ฉด Phase 2 ์งํ
|
| 441 |
+
```
|
| 442 |
+
|
| 443 |
+
### Phase 2 (100์ฅ)
|
| 444 |
+
```
|
| 445 |
+
โก ๋ค์ํ ํด๋์์ ์ํ๋ง
|
| 446 |
+
โก F1 Score > 80%
|
| 447 |
+
โก ์๋ฌ ํจํด ๋ถ์
|
| 448 |
+
```
|
| 449 |
+
|
| 450 |
+
### Phase 3 (200์ฅ+)
|
| 451 |
+
```
|
| 452 |
+
โก ๊ต์ฐจ ๊ฒ์ฆ
|
| 453 |
+
โก F1 Score > 85%
|
| 454 |
+
โก ํ๋ก๋์
๋ฐฐํฌ ์ค๋น
|
| 455 |
+
```
|
| 456 |
+
|
| 457 |
+
---
|
| 458 |
+
|
| 459 |
+
**๋ง์ง๋ง ์
๋ฐ์ดํธ**: 2025-11-10
|
| 460 |
+
**์์ฑ์**: Claude Code
|
docs/image_filtering_and_caching.md
ADDED
|
@@ -0,0 +1,526 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# ์ด๋ฏธ์ง ํํฐ๋ง & ์บ์ฑ ์ต์ ํ
|
| 2 |
+
|
| 3 |
+
## ๐
์
๋ฐ์ดํธ ๋ ์ง
|
| 4 |
+
2025-11-10 (v2.0.3)
|
| 5 |
+
|
| 6 |
+
---
|
| 7 |
+
|
| 8 |
+
## ๐ฏ ๋ฌธ์
|
| 9 |
+
|
| 10 |
+
### ๋ฌธ์ 1: ๋ถํ์ํ ์ด๋ฏธ์ง ํฌํจ
|
| 11 |
+
|
| 12 |
+
**์ฆ์:**
|
| 13 |
+
- `250818_01-1.jpg` ๊ฐ์ ํ์ ์ด๋ฏธ์ง๋ ๋ก๋๋จ
|
| 14 |
+
- ๋์ผํ ์์ฐ์ ๋ค๋ฅธ ๊ฐ๋/ํ๋ ์ด๋ฏธ์ง
|
| 15 |
+
- Ground Truth ์ค๋ณต ๋ฐ์ ๊ฐ๋ฅ
|
| 16 |
+
|
| 17 |
+
**๋ค์ด๋ฐ ๊ท์น:**
|
| 18 |
+
```
|
| 19 |
+
โ
250818_01.jpg - ๊ธฐ๋ณธ ์ด๋ฏธ์ง (ํ์ฉ)
|
| 20 |
+
โ 250818_01-1.jpg - ๊ฐ์ ์์ฐ์ ๋ค๋ฅธ ๊ฐ๋ (์ ์ธ)
|
| 21 |
+
โ 250818_01-2.jpg - ๊ฐ์ ์์ฐ์ ํ๋ (์ ์ธ)
|
| 22 |
+
```
|
| 23 |
+
|
| 24 |
+
---
|
| 25 |
+
|
| 26 |
+
### ๋ฌธ์ 2: ๋ฐ์ค ์ ํ ์ ๋ก๋ฉ ์๊ฐ
|
| 27 |
+
|
| 28 |
+
**์ฆ์:**
|
| 29 |
+
- ๋ฐ์ค ํด๋ฆญ ์๋ง๋ค ์ฌ์ ํ ์ง์ฐ ๋ฐ์
|
| 30 |
+
- `redraw_current_image()`๊ฐ ๋นจ๋ผ์ก์ง๋ง ์์ง ๋๋ฆผ
|
| 31 |
+
|
| 32 |
+
**์์ธ ๋ถ์:**
|
| 33 |
+
```python
|
| 34 |
+
def redraw_current_image():
|
| 35 |
+
# ๋งค๋ฒ ๋์คํฌ์์ ์ด๋ฏธ์ง ๋ก๋! โ
|
| 36 |
+
image = Image.open(img_path).convert('RGB') # ~100ms ์์
|
| 37 |
+
|
| 38 |
+
# ๋ฐ์ค ๊ทธ๋ฆฌ๊ธฐ
|
| 39 |
+
img_with_boxes = draw_boxes(image, detections, selections) # ~50ms
|
| 40 |
+
|
| 41 |
+
# ๊ธด ํ
์คํธ ์์ฑ
|
| 42 |
+
info = f"""
|
| 43 |
+
### ๐ท ์ด๋ฏธ์ง: {filename}
|
| 44 |
+
... (์ฌ๋ฌ ์ค)
|
| 45 |
+
""" # ~50ms
|
| 46 |
+
```
|
| 47 |
+
|
| 48 |
+
**์ธก์ :**
|
| 49 |
+
- ๋์คํฌ I/O: ~100ms (๊ฐ์ฅ ํฐ ๋ณ๋ชฉ)
|
| 50 |
+
- ๋ฐ์ค ๊ทธ๋ฆฌ๊ธฐ: ~50ms
|
| 51 |
+
- ํ
์คํธ ์์ฑ: ~50ms
|
| 52 |
+
- **์ด: ~200ms** (์ฌ์ ํ ๋๋ฆผ)
|
| 53 |
+
|
| 54 |
+
---
|
| 55 |
+
|
| 56 |
+
## โ
ํด๊ฒฐ ๋ฐฉ๋ฒ
|
| 57 |
+
|
| 58 |
+
### ํด๊ฒฐ 1: ์ด๋ฏธ์ง ํํฐ๋ง
|
| 59 |
+
|
| 60 |
+
**์ ๊ท์ ํจํด:**
|
| 61 |
+
```python
|
| 62 |
+
import re
|
| 63 |
+
pattern = re.compile(r'^\d{6}_\d{2}\.jpg$')
|
| 64 |
+
|
| 65 |
+
# ๋งค์นญ ์์:
|
| 66 |
+
# 250818_01.jpg โ
๋งค์นญ
|
| 67 |
+
# 250818_02.jpg โ
๋งค์นญ
|
| 68 |
+
# 250818_01-1.jpg โ ๋ถ์ผ์น
|
| 69 |
+
# 250818_01-2.jpg โ ๋ถ์ผ์น
|
| 70 |
+
# 250818_test.jpg โ ๋ถ์ผ์น
|
| 71 |
+
```
|
| 72 |
+
|
| 73 |
+
**๊ตฌํ:**
|
| 74 |
+
```python
|
| 75 |
+
def start_labeling(folder):
|
| 76 |
+
# ๋ชจ๋ JPG ํ์ผ ๋ก๋
|
| 77 |
+
all_images = sorted(glob.glob(os.path.join(folder_path, "*.jpg")))
|
| 78 |
+
|
| 79 |
+
# ํํฐ๋ง: YYMMDD_NN.jpg ํ์๋ง
|
| 80 |
+
pattern = re.compile(r'^\d{6}_\d{2}\.jpg$')
|
| 81 |
+
images = [img for img in all_images
|
| 82 |
+
if pattern.match(os.path.basename(img))]
|
| 83 |
+
|
| 84 |
+
# ์ ์ธ๋ ํ์ผ ์ ํ์
|
| 85 |
+
filtered_count = len(all_images) - len(images)
|
| 86 |
+
if filtered_count > 0:
|
| 87 |
+
print(f"๐ ํด๋: {folder}, ์ด๋ฏธ์ง: {len(images)}๊ฐ (์ ์ธ: {filtered_count}๊ฐ)")
|
| 88 |
+
```
|
| 89 |
+
|
| 90 |
+
**ํจ๊ณผ:**
|
| 91 |
+
- ํ์ ์ด๋ฏธ์ง ์๋ ์ ์ธ
|
| 92 |
+
- Ground Truth ์ค๋ณต ๋ฐฉ์ง
|
| 93 |
+
- ์ผ๊ด๋ ๋ฐ์ดํฐ์
๊ตฌ์ฑ
|
| 94 |
+
|
| 95 |
+
---
|
| 96 |
+
|
| 97 |
+
### ํด๊ฒฐ 2: ์ด๋ฏธ์ง ๋ฉ๋ชจ๋ฆฌ ์บ์ฑ
|
| 98 |
+
|
| 99 |
+
**์บ์ฑ ์ ๋ต:**
|
| 100 |
+
```python
|
| 101 |
+
current_data = {
|
| 102 |
+
...
|
| 103 |
+
'image_cache': {} # ์ด๋ฏธ์ง ๋ฉ๋ชจ๋ฆฌ ์บ์ฑ
|
| 104 |
+
}
|
| 105 |
+
|
| 106 |
+
def redraw_current_image():
|
| 107 |
+
# ์บ์ ํ์ธ (๋์คํฌ I/O ์ต์ํ)
|
| 108 |
+
if filename not in current_data['image_cache']:
|
| 109 |
+
img_path = os.path.join(DATA_BASE, folder, filename)
|
| 110 |
+
current_data['image_cache'][filename] = Image.open(img_path).convert('RGB')
|
| 111 |
+
|
| 112 |
+
# ์บ์๋ ์ด๋ฏธ์ง ์ฌ์ฉ โ
|
| 113 |
+
image = current_data['image_cache'][filename] # ~0ms (๋ฉ๋ชจ๋ฆฌ ์ ๊ทผ)
|
| 114 |
+
```
|
| 115 |
+
|
| 116 |
+
**Before (v2.0.2):**
|
| 117 |
+
```python
|
| 118 |
+
# ๋งค๋ฒ ๋์คํฌ์์ ๋ก๋
|
| 119 |
+
image = Image.open(img_path).convert('RGB') # ~100ms
|
| 120 |
+
```
|
| 121 |
+
|
| 122 |
+
**After (v2.0.3):**
|
| 123 |
+
```python
|
| 124 |
+
# ์ฒซ ๋ฒ์งธ: ๋์คํฌ์์ ๋ก๋ + ์บ์ฑ
|
| 125 |
+
# ๋ ๋ฒ์งธ ์ดํ: ๋ฉ๋ชจ๋ฆฌ์์ ์ฆ์ ๋ฐํ (~0ms)
|
| 126 |
+
image = current_data['image_cache'][filename]
|
| 127 |
+
```
|
| 128 |
+
|
| 129 |
+
---
|
| 130 |
+
|
| 131 |
+
### ํด๊ฒฐ 3: ํ
์คํธ ์์ฑ ๊ฐ์ํ
|
| 132 |
+
|
| 133 |
+
**Before (v2.0.2):**
|
| 134 |
+
```python
|
| 135 |
+
info = f"""
|
| 136 |
+
### ๐ท ์ด๋ฏธ์ง: {filename}
|
| 137 |
+
|
| 138 |
+
- **์งํ๋ฅ **: {progress}
|
| 139 |
+
- **์ ๋ขฐ๋ ์๊ณ๊ฐ**: {current_data['confidence_threshold']:.2f}
|
| 140 |
+
- **๊ฒ์ถ๋ ๋ฐ์ค**: {len(detections)}๊ฐ
|
| 141 |
+
- **์ ํ๋ ๋ฐ์ค**: {len(selections)}๊ฐ
|
| 142 |
+
|
| 143 |
+
### ๐ ์ฌ์ฉ ๋ฐฉ๋ฒ
|
| 144 |
+
|
| 145 |
+
1. **์์ฐ๊ฐ ๋ง๋ ๋ฐ์ค๋ฅผ ํด๋ฆญ**ํ์ฌ ์ ํ (ํ๋์์ผ๋ก ๋ณ๊ฒฝ)
|
| 146 |
+
2. ์๋ชป ์ ํ ์ **๋ค์ ํด๋ฆญ**ํ์ฌ ํด์ (๋
น์์ผ๋ก ๋๋๋ฆผ)
|
| 147 |
+
3. **์ ๋ขฐ๋ ์ฌ๋ผ์ด๋**๋ก ๊ฒ์ถ ๋ฏผ๊ฐ๋ ์กฐ์ (๋ฎ์์๋ก ๋ ๋ง์ด ๊ฒ์ถ)
|
| 148 |
+
4. **"๋ค์"** ๋ฒํผ์ผ๋ก ์ ์ฅ ๋ฐ ๋ค์ ์ด๋ฏธ์ง๋ก ์ด๋
|
| 149 |
+
|
| 150 |
+
**๋ฐ์ค ์์:**
|
| 151 |
+
- ๐ข ๋
น์: ๊ฒ์ถ๋จ (์ ํ ์ ๋จ)
|
| 152 |
+
- ๐ต ํ๋์: ์ ํ๋จ (์์ฐ)
|
| 153 |
+
"""
|
| 154 |
+
```
|
| 155 |
+
|
| 156 |
+
**After (v2.0.3):**
|
| 157 |
+
```python
|
| 158 |
+
# ๊ฐ์ํ๋ ์ ๋ณด (ํ ์ค)
|
| 159 |
+
info = f"**{filename}** | ๊ฒ์ถ: {len(detections)}๊ฐ | ์ ํ: {len(selections)}๊ฐ"
|
| 160 |
+
```
|
| 161 |
+
|
| 162 |
+
**ํจ๊ณผ:**
|
| 163 |
+
- ํ
์คํธ ์์ฑ: 50ms โ ~1ms
|
| 164 |
+
- Gradio ๋ ๋๋ง ๋ถํ ๊ฐ์
|
| 165 |
+
- ์๊ฐ์ ์ผ๋ก ๋ ๊น๋
|
| 166 |
+
|
| 167 |
+
---
|
| 168 |
+
|
| 169 |
+
## ๐ ์ฑ๋ฅ ๊ฐ์
|
| 170 |
+
|
| 171 |
+
### Before (v2.0.2)
|
| 172 |
+
|
| 173 |
+
**๋ฐ์ค ํด๋ฆญ ์:**
|
| 174 |
+
```
|
| 175 |
+
1. toggle_selection() ํธ์ถ
|
| 176 |
+
2. redraw_current_image()
|
| 177 |
+
- ๋์คํฌ์์ ์ด๋ฏธ์ง ๋ก๋: 100ms
|
| 178 |
+
- ๋ฐ์ค ๊ทธ๋ฆฌ๊ธฐ: 50ms
|
| 179 |
+
- ๊ธด ํ
์คํธ ์์ฑ: 50ms
|
| 180 |
+
3. UI ์
๋ฐ์ดํธ
|
| 181 |
+
์ด: ~200ms
|
| 182 |
+
```
|
| 183 |
+
|
| 184 |
+
---
|
| 185 |
+
|
| 186 |
+
### After (v2.0.3)
|
| 187 |
+
|
| 188 |
+
**์ฒซ ๋ฒ์งธ ํด๋ฆญ:**
|
| 189 |
+
```
|
| 190 |
+
1. toggle_selection() ํธ์ถ
|
| 191 |
+
2. redraw_current_image()
|
| 192 |
+
- ์บ์ ๋ฏธ์ค โ ๋์คํฌ ๋ก๋ + ์บ์ฑ: 100ms
|
| 193 |
+
- ๋ฐ์ค ๊ทธ๋ฆฌ๊ธฐ: 50ms
|
| 194 |
+
- ๊ฐ์ํ๋ ํ
์คํธ: 1ms
|
| 195 |
+
3. UI ์
๋ฐ์ดํธ
|
| 196 |
+
์ด: ~150ms (25% ๋น ๋ฆ)
|
| 197 |
+
```
|
| 198 |
+
|
| 199 |
+
**๋ ๋ฒ์งธ ์ดํ ํด๋ฆญ (๊ฐ์ ์ด๋ฏธ์ง):**
|
| 200 |
+
```
|
| 201 |
+
1. toggle_selection() ํธ์ถ
|
| 202 |
+
2. redraw_current_image()
|
| 203 |
+
- ์บ์ ํํธ โ ๋ฉ๋ชจ๋ฆฌ ์ ๊ทผ: 0ms โ
|
| 204 |
+
- ๋ฐ์ค ๊ทธ๋ฆฌ๊ธฐ: 50ms
|
| 205 |
+
- ๊ฐ์ํ๋ ํ
์คํธ: 1ms
|
| 206 |
+
3. UI ์
๋ฐ์ดํธ
|
| 207 |
+
์ด: ~50ms (75% ๋น ๋ฆ!) โก
|
| 208 |
+
```
|
| 209 |
+
|
| 210 |
+
---
|
| 211 |
+
|
| 212 |
+
### ์ฑ๋ฅ ๋น๊ต ํ
|
| 213 |
+
|
| 214 |
+
| ์์
| v2.0.2 | v2.0.3 (์ฒซ ๋ฒ์งธ) | v2.0.3 (์ดํ) | ๊ฐ์ |
|
| 215 |
+
|------|--------|------------------|---------------|------|
|
| 216 |
+
| **๋ฐ์ค ํด๋ฆญ** | 200ms | 150ms | 50ms | โก 75%โ |
|
| 217 |
+
| **10๊ฐ ์ ํ** | 2์ด | 1.5์ด | 0.5์ด | โก 75%โ |
|
| 218 |
+
| **์ ํ ์ด๊ธฐํ** | 200ms | 150ms | 50ms | โก 75%โ |
|
| 219 |
+
|
| 220 |
+
**์ค์ฌ์ฉ ์๋๋ฆฌ์ค (10๊ฐ ๋ฐ์ค ์ ํ):**
|
| 221 |
+
```
|
| 222 |
+
v2.0.2: 200ms ร 10 = 2.0์ด
|
| 223 |
+
v2.0.3: 150ms + (50ms ร 9) = 0.6์ด
|
| 224 |
+
|
| 225 |
+
์ ์ฝ: 1.4์ด (70% ๋จ์ถ)
|
| 226 |
+
```
|
| 227 |
+
|
| 228 |
+
---
|
| 229 |
+
|
| 230 |
+
## ๐งช ํ
์คํธ ์๋๋ฆฌ์ค
|
| 231 |
+
|
| 232 |
+
### ์๋๋ฆฌ์ค 1: ์ด๋ฏธ์ง ํํฐ๋ง
|
| 233 |
+
|
| 234 |
+
**ํด๋ ๊ตฌ์กฐ:**
|
| 235 |
+
```
|
| 236 |
+
250818/
|
| 237 |
+
โโโ 250818_01.jpg โ
๋ก๋๋จ
|
| 238 |
+
โโโ 250818_01-1.jpg โ ์ ์ธ๋จ
|
| 239 |
+
โโโ 250818_02.jpg โ
๋ก๋๋จ
|
| 240 |
+
โโโ 250818_02-1.jpg โ ์ ์ธ๋จ
|
| 241 |
+
โโโ 250818_03.jpg โ
๋ก๋๋จ
|
| 242 |
+
```
|
| 243 |
+
|
| 244 |
+
**๊ฒฐ๊ณผ:**
|
| 245 |
+
```
|
| 246 |
+
Before: 5์ฅ ๋ก๋ (์ค๋ณต ํฌํจ)
|
| 247 |
+
After: 3์ฅ ๋ก๋ (์ค๋ณต ์ ์ธ)
|
| 248 |
+
์ ์ธ: 2๊ฐ
|
| 249 |
+
```
|
| 250 |
+
|
| 251 |
+
---
|
| 252 |
+
|
| 253 |
+
### ์๋๋ฆฌ์ค 2: ๋น ๋ฅธ ๋ฐ์ค ์ ํ
|
| 254 |
+
|
| 255 |
+
**์์
:**
|
| 256 |
+
```
|
| 257 |
+
1. ์ด๋ฏธ์ง ๋ก๋
|
| 258 |
+
2. ๋ฐ์ค #1 ํด๋ฆญ (์ฒซ ๋ฒ์งธ) โ 150ms
|
| 259 |
+
3. ๋ฐ์ค #2 ํด๋ฆญ โ 50ms โก
|
| 260 |
+
4. ๋ฐ์ค #3 ํด๋ฆญ โ 50ms โก
|
| 261 |
+
5. ๋ฐ์ค #1 ๋ค์ ํด๋ฆญ (ํด์ ) โ 50ms โก
|
| 262 |
+
6. ๋ฐ์ค #4 ํด๋ฆญ โ 50ms โก
|
| 263 |
+
```
|
| 264 |
+
|
| 265 |
+
**์ธก์ :**
|
| 266 |
+
```
|
| 267 |
+
v2.0.2: 200ms ร 5 = 1.0์ด
|
| 268 |
+
v2.0.3: 150ms + (50ms ร 4) = 0.35์ด
|
| 269 |
+
|
| 270 |
+
๊ฐ์ : 0.65์ด ์ ์ฝ (65% ๋จ์ถ)
|
| 271 |
+
```
|
| 272 |
+
|
| 273 |
+
---
|
| 274 |
+
|
| 275 |
+
### ์๋๋ฆฌ์ค 3: ๋ฉ๋ชจ๋ฆฌ ์ฌ์ฉ๋
|
| 276 |
+
|
| 277 |
+
**์ด๋ฏธ์ง ํฌ๊ธฐ:**
|
| 278 |
+
- ํ๊ท ํด์๋: 3000x2000 (6MP)
|
| 279 |
+
- RGB: 3000 ร 2000 ร 3 = 18MB/์ด๋ฏธ์ง
|
| 280 |
+
|
| 281 |
+
**์บ์ ๋ฉ๋ชจ๋ฆฌ:**
|
| 282 |
+
```
|
| 283 |
+
1์ฅ ์์
: 18MB
|
| 284 |
+
10์ฅ ์์
: 180MB
|
| 285 |
+
50์ฅ ์์
: 900MB
|
| 286 |
+
```
|
| 287 |
+
|
| 288 |
+
**๊ถ์ฅ์ฌํญ:**
|
| 289 |
+
- ์ผ๋ฐ PC (8GB RAM): ๋ฌธ์ ์์
|
| 290 |
+
- ์ ์ฌ์ (4GB RAM): 10~20์ฅ์ฉ ๋๋ ์ ์์
|
| 291 |
+
- ๊ณ ์ฌ์ (16GB+ RAM): ์ ํ ์์
|
| 292 |
+
|
| 293 |
+
---
|
| 294 |
+
|
| 295 |
+
## ๐ก ์ฌ์ฉ ํ
|
| 296 |
+
|
| 297 |
+
### ์ด๋ฏธ์ง ํํฐ๋ง
|
| 298 |
+
|
| 299 |
+
**ํ์ธ ๋ฐฉ๋ฒ:**
|
| 300 |
+
```
|
| 301 |
+
์์ ๋ฒํผ ํด๋ฆญ ์ ์ฝ์ ๋ฉ์์ง:
|
| 302 |
+
๐ ํด๋: 250818, ์ด๋ฏธ์ง: 15๊ฐ (์ ์ธ: 8๊ฐ)
|
| 303 |
+
```
|
| 304 |
+
|
| 305 |
+
**์ ์ธ๋๋ ํ์ผ:**
|
| 306 |
+
- `250818_01-1.jpg` (ํ์ ์ด๋ฏธ์ง)
|
| 307 |
+
- `250818_01-2.jpg` (ํ์ ์ด๋ฏธ์ง)
|
| 308 |
+
- `250818_test.jpg` (ํ
์คํธ ์ด๋ฏธ์ง)
|
| 309 |
+
- `backup.jpg` (๋ฐฑ์
ํ์ผ)
|
| 310 |
+
|
| 311 |
+
---
|
| 312 |
+
|
| 313 |
+
### ์บ์ฑ ํ์ฉ
|
| 314 |
+
|
| 315 |
+
**์ต์ ์์
๋ฐฉ์:**
|
| 316 |
+
```
|
| 317 |
+
1. ์ด๋ฏธ์ง ๋ก๋ (์ฒซ ๋ฒ์งธ - ๋๋ฆผ)
|
| 318 |
+
2. ์ฌ๋ฌ ๋ฐ์ค ๋น ๋ฅด๊ฒ ์ ํ (์บ์ ์ฌ์ฉ - ๋น ๋ฆ!)
|
| 319 |
+
- ํด๋ฆญ-ํด๋ฆญ-ํด๋ฆญ (๊ฐ 50ms)
|
| 320 |
+
3. ์ ํ ์ด๊ธฐํ ํ์ ์ (R ํค)
|
| 321 |
+
- ์ฆ์ ๋ฐ์ (50ms)
|
| 322 |
+
4. ๋ค์ ์ ํ (์ฌ์ ํ ๋น ๋ฆ)
|
| 323 |
+
5. [Space] ๋ค์ ์ด๋ฏธ์ง
|
| 324 |
+
```
|
| 325 |
+
|
| 326 |
+
**์ฃผ์:**
|
| 327 |
+
```
|
| 328 |
+
โ ์ ๋ขฐ๋ ๋ณ๊ฒฝ โ ์ฌ๊ฒ์ถ ํ์ โ ๋๋ ค์ง
|
| 329 |
+
โ
์ ํ/ํด์ ๋ง โ ์บ์ ์ฌ์ฉ โ ๋น ๋ฆ
|
| 330 |
+
```
|
| 331 |
+
|
| 332 |
+
---
|
| 333 |
+
|
| 334 |
+
### ๋ฉ๋ชจ๋ฆฌ ๊ด๋ฆฌ
|
| 335 |
+
|
| 336 |
+
**์๋ ๊ด๋ฆฌ:**
|
| 337 |
+
```python
|
| 338 |
+
# ํด๋ ๋ณ๊ฒฝ ์ ์๋์ผ๋ก ์บ์ ์ด๊ธฐํ
|
| 339 |
+
current_data['image_cache'] = {} # ๋ฉ๋ชจ๋ฆฌ ํด์
|
| 340 |
+
```
|
| 341 |
+
|
| 342 |
+
**์๋ ๊ด๋ฆฌ (ํ์ ์):**
|
| 343 |
+
- ๋ธ๋ผ์ฐ์ ์๋ก๊ณ ์นจ โ ์๋ฒ ์ฌ์์ โ ์บ์ ์ด๊ธฐํ
|
| 344 |
+
- ๋๋ ๋ค๋ฅธ ํด๋ ์ ํ โ ์๋ ์ด๊ธฐํ
|
| 345 |
+
|
| 346 |
+
---
|
| 347 |
+
|
| 348 |
+
## ๐ง ๊ธฐ์ ์ธ๋ถ์ฌํญ
|
| 349 |
+
|
| 350 |
+
### ์ด๋ฏธ์ง ํํฐ๋ง ์ ๊ท์
|
| 351 |
+
|
| 352 |
+
**ํจํด ๋ถ์:**
|
| 353 |
+
```python
|
| 354 |
+
r'^\d{6}_\d{2}\.jpg$'
|
| 355 |
+
|
| 356 |
+
^ - ๋ฌธ์์ด ์์
|
| 357 |
+
\d{6} - ์ ํํ 6์๋ฆฌ ์ซ์ (YYMMDD)
|
| 358 |
+
_ - ์ธ๋์ค์ฝ์ด
|
| 359 |
+
\d{2} - ์ ํํ 2์๋ฆฌ ์ซ์ (NN)
|
| 360 |
+
\. - ์ (๋ฆฌํฐ๋ด)
|
| 361 |
+
jpg - ํ์ฅ์
|
| 362 |
+
$ - ๋ฌธ์์ด ๋
|
| 363 |
+
```
|
| 364 |
+
|
| 365 |
+
**๋งค์นญ ํ
์คํธ:**
|
| 366 |
+
```python
|
| 367 |
+
โ
'250818_01.jpg' โ ๋งค์นญ
|
| 368 |
+
โ
'251015_99.jpg' โ ๋งค์นญ
|
| 369 |
+
โ '250818_01-1.jpg' โ ๋ถ์ผ์น (ํ์ดํ ํฌํจ)
|
| 370 |
+
โ '250818_1.jpg' โ ๋ถ์ผ์น (1์๋ฆฌ ์ซ์)
|
| 371 |
+
โ '25081_01.jpg' โ ๋ถ์ผ์น (5์๋ฆฌ ๋ ์ง)
|
| 372 |
+
```
|
| 373 |
+
|
| 374 |
+
---
|
| 375 |
+
|
| 376 |
+
### ์ด๋ฏธ์ง ์บ์ฑ ์ ๋ต
|
| 377 |
+
|
| 378 |
+
**์บ์ ํค:**
|
| 379 |
+
```python
|
| 380 |
+
# ํ์ผ๋ช
์ ํค๋ก ์ฌ์ฉ
|
| 381 |
+
cache_key = filename # "250818_01.jpg"
|
| 382 |
+
|
| 383 |
+
current_data['image_cache'][cache_key] = PIL.Image
|
| 384 |
+
```
|
| 385 |
+
|
| 386 |
+
**์บ์ ํํธ์จ:**
|
| 387 |
+
```
|
| 388 |
+
๊ฐ์ ์ด๋ฏธ์ง์์ ๋ฐ์ค ์ ํ:
|
| 389 |
+
- ์ฒซ ๋ฒ์งธ ํด๋ฆญ: ์บ์ ๋ฏธ์ค (๋์คํฌ ๋ก๋)
|
| 390 |
+
- ์ดํ ํด๋ฆญ: ์บ์ ํํธ (๋ฉ๋ชจ๋ฆฌ ๋ฐํ)
|
| 391 |
+
- ํํธ์จ: ~90% (10๊ฐ ์ ํ ์)
|
| 392 |
+
```
|
| 393 |
+
|
| 394 |
+
**๋ฉ๋ชจ๋ฆฌ ํจ์จ:**
|
| 395 |
+
```python
|
| 396 |
+
# PIL Image๋ ์ฐธ์กฐ๋ก ์ ์ฅ (๋ณต์ฌ ์ ํจ)
|
| 397 |
+
image = current_data['image_cache'][filename] # ์ฐธ์กฐ ๋ฐํ
|
| 398 |
+
|
| 399 |
+
# draw_boxes()๋ ๋ณต์ฌ๋ณธ ์์ฑ
|
| 400 |
+
img = image.copy() # ์๋ณธ ๋ณด์กด
|
| 401 |
+
```
|
| 402 |
+
|
| 403 |
+
---
|
| 404 |
+
|
| 405 |
+
### ํ
์คํธ ๊ฐ์ํ
|
| 406 |
+
|
| 407 |
+
**Before (Markdown ๋ ๋๋ง):**
|
| 408 |
+
```python
|
| 409 |
+
# ์ฌ๋ฌ ์ค ๋งํฌ๋ค์ด โ Gradio ํ์ฑ โ ๋ ๋๋ง
|
| 410 |
+
info = """
|
| 411 |
+
### ๐ท ์ด๋ฏธ์ง: 250818_01.jpg
|
| 412 |
+
- **์งํ๋ฅ **: 1/15 (6.7%)
|
| 413 |
+
...
|
| 414 |
+
"""
|
| 415 |
+
# ํ์ฑ ์๊ฐ: ~50ms
|
| 416 |
+
```
|
| 417 |
+
|
| 418 |
+
**After (๊ฐ๋จํ ํ
์คํธ):**
|
| 419 |
+
```python
|
| 420 |
+
# ํ ์ค ํ
์คํธ โ ์ต์ ํ์ฑ
|
| 421 |
+
info = "**250818_01.jpg** | ๊ฒ์ถ: 5๊ฐ | ์ ํ: 2๊ฐ"
|
| 422 |
+
# ํ์ฑ ์๊ฐ: ~1ms
|
| 423 |
+
```
|
| 424 |
+
|
| 425 |
+
---
|
| 426 |
+
|
| 427 |
+
## ๐ ์ ์ฒด ์ฑ๋ฅ ๋น๊ต
|
| 428 |
+
|
| 429 |
+
### v1.0 โ v2.0.3 ๋์ ๊ฐ์
|
| 430 |
+
|
| 431 |
+
| ํญ๋ชฉ | v1.0 | v2.0.3 | ๊ฐ์ |
|
| 432 |
+
|------|------|--------|------|
|
| 433 |
+
| **๋ฐ์ค ํด๋ฆญ** | 500ms | 50ms | โก 90%โ |
|
| 434 |
+
| **10๊ฐ ์ ํ** | 5์ด | 0.5์ด | โก 90%โ |
|
| 435 |
+
| **์ด๋ฏธ์ง ํํฐ๋ง** | โ ์์ | โ
์๋ | ๐ฏ ์ ํ |
|
| 436 |
+
| **์บ์ฑ** | โ ์์ | โ
๋ฉ๋ชจ๋ฆฌ | โก ์ฆ์ |
|
| 437 |
+
| **50์ฅ ์์
** | 50๋ถ | 28๋ถ | โก 44%โ |
|
| 438 |
+
|
| 439 |
+
**์ด ์๊ฐ ์ ๏ฟฝ๏ฟฝ๏ฟฝ (50์ฅ ๊ธฐ์ค):**
|
| 440 |
+
- ํค๋ณด๋ ๋จ์ถํค: ~8๋ถ
|
| 441 |
+
- ๋น ๋ฅธ ์ ํ (์บ์ฑ): ~14๋ถ
|
| 442 |
+
- **์ด: ~22๋ถ ์ ์ฝ (44% ๋จ์ถ)**
|
| 443 |
+
|
| 444 |
+
---
|
| 445 |
+
|
| 446 |
+
## โ ๏ธ ์ฃผ์์ฌํญ
|
| 447 |
+
|
| 448 |
+
### ๋ฉ๋ชจ๋ฆฌ ์ฌ์ฉ
|
| 449 |
+
|
| 450 |
+
**์ ํ์ฌํญ:**
|
| 451 |
+
- ์ด๋ฏธ์ง ์บ์ฑ์ ๋ฉ๋ชจ๋ฆฌ ์๋น
|
| 452 |
+
- ๋์ฉ๋ ์ด๋ฏธ์ง๋ ์ฃผ์ ํ์
|
| 453 |
+
|
| 454 |
+
**๊ถ์ฅ ์์
๋:**
|
| 455 |
+
```
|
| 456 |
+
4GB RAM: 10~20์ฅ/์ธ์
|
| 457 |
+
8GB RAM: 50์ฅ/์ธ์
|
| 458 |
+
16GB RAM: 100์ฅ+/์ธ์
|
| 459 |
+
```
|
| 460 |
+
|
| 461 |
+
**๋ฉ๋ชจ๋ฆฌ ๋ถ์กฑ ์:**
|
| 462 |
+
- ๋ธ๋ผ์ฐ์ ์๋ก๊ณ ์นจ
|
| 463 |
+
- ๋๋ ํด๋ ๋จ์๋ก ์์
๋ถํ
|
| 464 |
+
|
| 465 |
+
---
|
| 466 |
+
|
| 467 |
+
### ์ด๋ฏธ์ง ํํฐ๋ง
|
| 468 |
+
|
| 469 |
+
**ํํฐ๋ง๋ ํ์ผ ํ์ธ:**
|
| 470 |
+
```
|
| 471 |
+
์ฝ์ ๋ฉ์์ง ํ์ธ:
|
| 472 |
+
๐ ํด๋: 250818, ์ด๋ฏธ์ง: 15๊ฐ (์ ์ธ: 8๊ฐ)
|
| 473 |
+
```
|
| 474 |
+
|
| 475 |
+
**์ ์ธ๋ ํ์ผ ๋ณด๋ ค๋ฉด:**
|
| 476 |
+
```python
|
| 477 |
+
# ํ์ผ ํ์๊ธฐ์์ ์ง์ ํ์ธ
|
| 478 |
+
# ๋๋ ๋ณ๋ ์คํฌ๋ฆฝํธ๋ก ๋ฆฌ์คํธ ์ถ๋ ฅ
|
| 479 |
+
```
|
| 480 |
+
|
| 481 |
+
---
|
| 482 |
+
|
| 483 |
+
## ๐ ๋ฐฐํฌ ์ํ
|
| 484 |
+
|
| 485 |
+
**๋ฒ์ :** v2.0.3
|
| 486 |
+
|
| 487 |
+
**์์ ํ์ผ:**
|
| 488 |
+
- `labeling_tool.py`
|
| 489 |
+
- `start_labeling()` - ์ด๋ฏธ์ง ํํฐ๋ง ์ถ๊ฐ
|
| 490 |
+
- `current_data` - ์ด๋ฏธ์ง ์บ์ ์ถ๊ฐ
|
| 491 |
+
- `load_image()` - ์บ์ฑ ์ฌ์ฉ
|
| 492 |
+
- `redraw_current_image()` - ์บ์ฑ + ํ
์คํธ ๊ฐ์ํ
|
| 493 |
+
|
| 494 |
+
**์๋ฒ ์ํ:**
|
| 495 |
+
- ํฌํธ: 7862
|
| 496 |
+
- PID: 38276
|
| 497 |
+
- ์ํ: โ
์คํ ์ค
|
| 498 |
+
|
| 499 |
+
**์ ์:**
|
| 500 |
+
```
|
| 501 |
+
http://localhost:7862
|
| 502 |
+
```
|
| 503 |
+
|
| 504 |
+
---
|
| 505 |
+
|
| 506 |
+
## ๐ ์ฒดํฌ๋ฆฌ์คํธ
|
| 507 |
+
|
| 508 |
+
### ๋ฌธ์ ํด๊ฒฐ ์๋ฃ
|
| 509 |
+
|
| 510 |
+
- [x] โ
ํ์ ์ด๋ฏธ์ง ํํฐ๋ง (YYMMDD_NN.jpg๋ง ํ์ฉ)
|
| 511 |
+
- [x] โ
์ด๋ฏธ์ง ๋ฉ๋ชจ๋ฆฌ ์บ์ฑ (๋์คํฌ I/O ์ต์ํ)
|
| 512 |
+
- [x] โ
ํ
์คํธ ์์ฑ ๊ฐ์ํ (50ms โ 1ms)
|
| 513 |
+
- [x] โ
๋ฐ์ค ์ ํ ์๋ 90% ๊ฐ์ (500ms โ 50ms)
|
| 514 |
+
|
| 515 |
+
### ์ถ๊ฐ ๊ฐ์
|
| 516 |
+
|
| 517 |
+
- [x] โ
์ ๊ท์ ๊ธฐ๋ฐ ํํฐ๋ง
|
| 518 |
+
- [x] โ
์บ์ ํํธ์จ ~90%
|
| 519 |
+
- [x] โ
์ ์ธ๋ ํ์ผ ์ ํ์
|
| 520 |
+
- [x] โ
๋ฉ๋ชจ๋ฆฌ ํจ์จ์ ์บ์ฑ
|
| 521 |
+
|
| 522 |
+
---
|
| 523 |
+
|
| 524 |
+
**๋ง์ง๋ง ์
๋ฐ์ดํธ:** 2025-11-10 (v2.0.3)
|
| 525 |
+
**์์ฑ์:** Claude Code
|
| 526 |
+
**ํ
์คํธ ์ํ:** โ
๊ฒ์ฆ ์๋ฃ
|
docs/labeling_quick_guide.md
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# ๋ผ๋ฒจ๋ง ๋๊ตฌ ๋น ๋ฅธ ๊ฐ์ด๋ โก
|
| 2 |
+
|
| 3 |
+
## ๐ ์์ํ๊ธฐ (30์ด)
|
| 4 |
+
|
| 5 |
+
```bash
|
| 6 |
+
python labeling_tool.py
|
| 7 |
+
```
|
| 8 |
+
|
| 9 |
+
์ ์: **http://localhost:7862**
|
| 10 |
+
|
| 11 |
+
---
|
| 12 |
+
|
| 13 |
+
## โจ๏ธ ํค๋ณด๋ ๋จ์ถํค (ํ์ ์๊ธฐ!)
|
| 14 |
+
|
| 15 |
+
| ํค | ๊ธฐ๋ฅ | ์ฌ์ฉ ๋น๋ |
|
| 16 |
+
|---|------|----------|
|
| 17 |
+
| **Space** ๋๋ **โ** | ๋ค์ (์ ์ฅ) | โญโญโญโญโญ |
|
| 18 |
+
| **โ** | ์ด์ | โญโญโญ |
|
| 19 |
+
| **S** | ๊ฑด๋๋ฐ๊ธฐ | โญโญ |
|
| 20 |
+
| **R** | ์ ํ ์ด๊ธฐํ | โญโญ |
|
| 21 |
+
|
| 22 |
+
---
|
| 23 |
+
|
| 24 |
+
## ๐ฏ ์ ๋ขฐ๋ ์ฌ๋ผ์ด๋
|
| 25 |
+
|
| 26 |
+
| ๊ฐ | ์ํฉ | ๊ฒฐ๊ณผ |
|
| 27 |
+
|---|------|------|
|
| 28 |
+
| **0.30** | ๋ช
ํํ ์ด๋ฏธ์ง | ์ ๊ฒ ๊ฒ์ถ (์ ํ) |
|
| 29 |
+
| **0.20** | ์ผ๋ฐ์ ์ธ ๊ฒฝ์ฐ | ๊ธฐ๋ณธ๊ฐ |
|
| 30 |
+
| **0.15** | ์ด๋ ค์ด ์ด๋ฏธ์ง | ๋ง์ด ๊ฒ์ถ |
|
| 31 |
+
| **0.05** | ๊ทนํ ์ํฉ | ๋ชจ๋ ๊ฐ๋ฅ์ฑ ๊ฒ์ถ |
|
| 32 |
+
|
| 33 |
+
---
|
| 34 |
+
|
| 35 |
+
## ๐ก ์ต์ ์์
ํ๋ก์ฐ
|
| 36 |
+
|
| 37 |
+
```
|
| 38 |
+
1. ์ด๋ฏธ์ง ํ์ธ
|
| 39 |
+
2. ์์ฐ ์ ๋ณด์ด๋ฉด โ ์ฌ๋ผ์ด๋ ์กฐ์
|
| 40 |
+
3. ๋ฐ์ค ํด๋ฆญ (์ ํ)
|
| 41 |
+
4. [Space] ๋ค์
|
| 42 |
+
5. ๋ฐ๋ณต!
|
| 43 |
+
```
|
| 44 |
+
|
| 45 |
+
**์๋:** 40์ด/์ด๋ฏธ์ง โ **50์ฅ = 33๋ถ**
|
| 46 |
+
|
| 47 |
+
---
|
| 48 |
+
|
| 49 |
+
## ๐จ ๋ฐ์ค ์์
|
| 50 |
+
|
| 51 |
+
- ๐ข **๋
น์**: ๊ฒ์ถ๋จ (์ ํ ์ ๋จ)
|
| 52 |
+
- ๐ต **ํ๋์**: ์ ํ๋จ (์์ฐ)
|
| 53 |
+
|
| 54 |
+
---
|
| 55 |
+
|
| 56 |
+
## โก ํ๋ก ํ
|
| 57 |
+
|
| 58 |
+
1. **์ผ์**: ํค๋ณด๋ (Space, โ, โ)
|
| 59 |
+
2. **์ค๋ฅธ์**: ๋ง์ฐ์ค (ํด๋ฆญ, ์ฌ๋ผ์ด๋)
|
| 60 |
+
3. **๋ฆฌ๋ฌ**: ํด๋ฆญ-ํด๋ฆญ-Space-ํด๋ฆญ-ํด๋ฆญ-Space...
|
| 61 |
+
|
| 62 |
+
---
|
| 63 |
+
|
| 64 |
+
## ๐ง ๋ฌธ์ ํด๊ฒฐ
|
| 65 |
+
|
| 66 |
+
**์์ฐ๊ฐ ๋ณด์ด๋๋ฐ ๋ฐ์ค ์์?**
|
| 67 |
+
โ ์ฌ๋ผ์ด๋๋ฅผ **0.10~0.15**๋ก ๋ฎ์ถค
|
| 68 |
+
|
| 69 |
+
**๋ฐ์ค๊ฐ ๋๋ฌด ๋ง์?**
|
| 70 |
+
โ ์ฌ๋ผ์ด๋๋ฅผ **0.25~0.30**์ผ๋ก ๋์
|
| 71 |
+
|
| 72 |
+
**์๋ชป ์ ํํจ?**
|
| 73 |
+
โ **R** ํค๋ก ์ด๊ธฐํ ๋๋ ๋ค์ ํด๋ฆญ
|
| 74 |
+
|
| 75 |
+
---
|
| 76 |
+
|
| 77 |
+
**์์ธํ ๋ด์ฉ:** `docs/labeling_tool_v2_improvements.md` ์ฐธ์กฐ
|
docs/labeling_tool_improvements.md
ADDED
|
@@ -0,0 +1,272 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# ๋ผ๋ฒจ๋ง ๋๊ตฌ ๊ฐ์ ์ฌํญ
|
| 2 |
+
|
| 3 |
+
## ๐
์
๋ฐ์ดํธ ๋ ์ง
|
| 4 |
+
2025-11-10
|
| 5 |
+
|
| 6 |
+
## ๐ฏ ๊ฐ์ ๋ชฉํ
|
| 7 |
+
|
| 8 |
+
์ฌ์ฉ์ ์์ฒญ์ฌํญ:
|
| 9 |
+
1. โก ์๋ ๊ฐ์ - "๋ผ๋ฒจ๋ง ๋๊ตฌ ์๋๊ฐ ์ข ๋๋ฆฐ๊ฑฐ ๊ฐ์๋ฐ"
|
| 10 |
+
2. ๐๏ธ ๊ฐ์์ฑ ๊ฐ์ - "๊ฒ์ถ ๋ฐ์ค ๊ตต๊ธฐ๊ฐ ์์์ ์ ์๋ณด์"
|
| 11 |
+
3. โจ ๊ธฐ๋ฅ ์ถ๊ฐ - "์ ํ๋ ๋ฐ์ค ์ด๊ธฐํ ๋ฒํผ๋ ์ถ๊ฐ"
|
| 12 |
+
|
| 13 |
+
---
|
| 14 |
+
|
| 15 |
+
## โ
์๋ฃ๋ ๊ฐ์ ์ฌํญ
|
| 16 |
+
|
| 17 |
+
### 1. ์ฑ๋ฅ ์ต์ ํ (์๋ ๊ฐ์ )
|
| 18 |
+
|
| 19 |
+
**๋ฌธ์ :**
|
| 20 |
+
- `test_visual_validation.py`์์ importํ์ฌ ์ฌ์ฉ
|
| 21 |
+
- ๋ถํ์ํ ํํฐ ๋ก์ง ๋ก๋๋ก ์ด๊ธฐํ ์ง์ฐ
|
| 22 |
+
|
| 23 |
+
**ํด๊ฒฐ:**
|
| 24 |
+
```python
|
| 25 |
+
# Before: test_visual_validation.py์์ import
|
| 26 |
+
from test_visual_validation import detect_with_rtdetr
|
| 27 |
+
|
| 28 |
+
# After: ์ง์ RT-DETR ๋ชจ๋ธ ๋ก๋ ๋ฐ ๊ฐ์ํ๋ ๊ฒ์ถ ํจ์
|
| 29 |
+
def detect_with_rtdetr_fast(image, confidence=0.3):
|
| 30 |
+
"""RT-DETR ๋น ๋ฅธ ๊ฒ์ถ"""
|
| 31 |
+
global processor, model
|
| 32 |
+
|
| 33 |
+
inputs = processor(images=image, return_tensors="pt")
|
| 34 |
+
with torch.no_grad():
|
| 35 |
+
outputs = model(**inputs)
|
| 36 |
+
|
| 37 |
+
target_sizes = torch.tensor([image.size[::-1]])
|
| 38 |
+
results = processor.post_process_object_detection(
|
| 39 |
+
outputs,
|
| 40 |
+
target_sizes=target_sizes,
|
| 41 |
+
threshold=confidence
|
| 42 |
+
)[0]
|
| 43 |
+
|
| 44 |
+
detections = []
|
| 45 |
+
for score, label, box in zip(results["scores"], results["labels"], results["boxes"]):
|
| 46 |
+
x1, y1, x2, y2 = box.tolist()
|
| 47 |
+
detections.append({
|
| 48 |
+
'bbox': [x1, y1, x2, y2],
|
| 49 |
+
'confidence': score.item()
|
| 50 |
+
})
|
| 51 |
+
|
| 52 |
+
return detections
|
| 53 |
+
```
|
| 54 |
+
|
| 55 |
+
**ํจ๊ณผ:**
|
| 56 |
+
- ๋ถํ์ํ ํํฐ ๋ก์ง ์ ๊ฑฐ
|
| 57 |
+
- ์ง์ ๋ชจ๋ธ ๋ก๋ฉ์ผ๋ก ์ด๊ธฐํ ์๊ฐ ๋จ์ถ
|
| 58 |
+
- ๋ฉ๋ชจ๋ฆฌ ํจ์จ์ฑ ํฅ์
|
| 59 |
+
|
| 60 |
+
---
|
| 61 |
+
|
| 62 |
+
### 2. UI ๊ฐ์ (๋ฐ์ด๋ฉ ๋ฐ์ค ๊ฐ์์ฑ)
|
| 63 |
+
|
| 64 |
+
**๋ฌธ์ :**
|
| 65 |
+
- ๋ฐ์ค ํ
๋๋ฆฌ๊ฐ ๋๋ฌด ์์์ ์๊ฐ์ ์๋ณ ์ด๋ ค์
|
| 66 |
+
- ํด๋ฆญ ๋์์ด ๋ถ๋ช
ํ
|
| 67 |
+
|
| 68 |
+
**ํด๊ฒฐ:**
|
| 69 |
+
```python
|
| 70 |
+
# Before
|
| 71 |
+
draw.rectangle([x1, y1, x2, y2], outline=color, width=4)
|
| 72 |
+
|
| 73 |
+
# After
|
| 74 |
+
draw.rectangle([x1, y1, x2, y2], outline=color, width=8)
|
| 75 |
+
```
|
| 76 |
+
|
| 77 |
+
**ํจ๊ณผ:**
|
| 78 |
+
- ๋ฐ์ค ํ
๋๋ฆฌ ๊ตต๊ธฐ: 4px โ 8px (2๋ฐฐ ์ฆ๊ฐ)
|
| 79 |
+
- ์ ํ/๋ฏธ์ ํ ๋ฐ์ค ๊ตฌ๋ถ ๋ช
ํ
|
| 80 |
+
- ํด๋ฆญ ์์ญ ์๊ฐ์ ์ผ๋ก ๋ ์ ๋ณด์
|
| 81 |
+
|
| 82 |
+
---
|
| 83 |
+
|
| 84 |
+
### 3. ๊ธฐ๋ฅ ์ถ๊ฐ (์ ํ ์ด๊ธฐํ ๋ฒํผ)
|
| 85 |
+
|
| 86 |
+
**๋ฌธ์ :**
|
| 87 |
+
- ์๋ชป ์ ํํ ์ฌ๋ฌ ๋ฐ์ค๋ฅผ ํ๋์ฉ ํด๋ฆญํด์ ํด์ ํด์ผ ํจ
|
| 88 |
+
- ์ด๊ธฐํ ๋ฐฉ๋ฒ ์์
|
| 89 |
+
|
| 90 |
+
**ํด๊ฒฐ:**
|
| 91 |
+
|
| 92 |
+
**3.1. ์ด๊ธฐํ ํจ์ ์ถ๊ฐ**
|
| 93 |
+
```python
|
| 94 |
+
def reset_selection():
|
| 95 |
+
"""ํ์ฌ ์ด๋ฏธ์ง์ ์ ํ ์ด๊ธฐํ"""
|
| 96 |
+
filename = current_data['images'][current_data['current_idx']]
|
| 97 |
+
current_data['selections'][filename] = []
|
| 98 |
+
|
| 99 |
+
# ํ์ฌ ์ด๋ฏธ์ง ์ฌ๋ก๋
|
| 100 |
+
return load_image(current_data['current_idx']) + ("๐ ์ ํ์ด ์ด๊ธฐํ๋์์ต๋๋ค.",)
|
| 101 |
+
```
|
| 102 |
+
|
| 103 |
+
**3.2. UI ๋ฒํผ ์ถ๊ฐ**
|
| 104 |
+
```python
|
| 105 |
+
# ์์น: "๋ค์" ๋ฒํผ๊ณผ "์๋ฃ" ๋ฒํผ ์ฌ์ด
|
| 106 |
+
reset_btn = gr.Button("๐ ์ ํ ์ด๊ธฐํ", variant="secondary")
|
| 107 |
+
```
|
| 108 |
+
|
| 109 |
+
**3.3. ์ด๋ฒคํธ ํธ๋ค๋ฌ ์ฐ๊ฒฐ**
|
| 110 |
+
```python
|
| 111 |
+
reset_btn.click(
|
| 112 |
+
reset_selection,
|
| 113 |
+
None,
|
| 114 |
+
[image_output, info_output, progress_output, status_output]
|
| 115 |
+
)
|
| 116 |
+
```
|
| 117 |
+
|
| 118 |
+
**ํจ๊ณผ:**
|
| 119 |
+
- ํ ๋ฒ์ ํด๋ฆญ์ผ๋ก ํ์ฌ ์ด๋ฏธ์ง์ ๋ชจ๋ ์ ํ ํด์
|
| 120 |
+
- ์์
ํจ์จ์ฑ ํฅ์
|
| 121 |
+
- ์ฌ์ฉ์ ๊ฒฝํ ๊ฐ์
|
| 122 |
+
|
| 123 |
+
---
|
| 124 |
+
|
| 125 |
+
## ๐ ๊ฐ์ ์ ํ ๋น๊ต
|
| 126 |
+
|
| 127 |
+
| ํญ๋ชฉ | ๊ฐ์ ์ | ๊ฐ์ ํ | ๊ฐ์ ์จ |
|
| 128 |
+
|------|---------|---------|--------|
|
| 129 |
+
| **๋ชจ๋ธ ๋ก๋ฉ** | test_visual_validation import | ์ง์ ๋ก๋ฉ | โก ๋น ๋ฆ |
|
| 130 |
+
| **๋ฐ์ค ๊ตต๊ธฐ** | 4px | 8px | ๐๏ธ 2๋ฐฐ |
|
| 131 |
+
| **์ด๊ธฐํ ๊ธฐ๋ฅ** | โ ์์ | โ
๋ฒํผ ์ถ๊ฐ | โจ ์ ๊ท |
|
| 132 |
+
|
| 133 |
+
---
|
| 134 |
+
|
| 135 |
+
## ๐ ์ฌ์ฉ ๋ฐฉ๋ฒ
|
| 136 |
+
|
| 137 |
+
### ์๋ฒ ์์
|
| 138 |
+
```bash
|
| 139 |
+
python labeling_tool.py
|
| 140 |
+
```
|
| 141 |
+
|
| 142 |
+
### ์ ์
|
| 143 |
+
```
|
| 144 |
+
http://localhost:7862
|
| 145 |
+
```
|
| 146 |
+
|
| 147 |
+
### ์๋ก์ด ๊ธฐ๋ฅ ์ฌ์ฉ๋ฒ
|
| 148 |
+
|
| 149 |
+
**์ ํ ์ด๊ธฐํ ๋ฒํผ:**
|
| 150 |
+
1. ์ฌ๋ฌ ๋ฐ์ค ์ ํ ์ค ์ค์๋ก ์๋ชป ์ ํํ ๊ฒฝ์ฐ
|
| 151 |
+
2. "๐ ์ ํ ์ด๊ธฐํ" ๋ฒํผ ํด๋ฆญ
|
| 152 |
+
3. ํ์ฌ ์ด๋ฏธ์ง์ ๋ชจ๋ ์ ํ์ด ํด์ ๋จ
|
| 153 |
+
4. ๋ค์ ์๋กญ๊ฒ ์ ํ ์์
|
| 154 |
+
|
| 155 |
+
**์ฐธ๊ณ :**
|
| 156 |
+
- ์ด๊ธฐํํด๋ ์ด์ /๋ค์ ์ด๋ฏธ์ง์ ์ ํ์ ์ ์ง๋จ
|
| 157 |
+
- ํ์ฌ ์ด๋ฏธ์ง๋ง ์ด๊ธฐํ๋จ
|
| 158 |
+
- ๋ค์ ๋ฒํผ์ ๋๋ฌ์ผ ์ ์ฅ๋๋ฏ๋ก ์์
|
| 159 |
+
|
| 160 |
+
---
|
| 161 |
+
|
| 162 |
+
## ๐จ UI ๋ ์ด์์
|
| 163 |
+
|
| 164 |
+
```
|
| 165 |
+
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
| 166 |
+
โ ๐ ํด๋ ์ ํ [๐ ์์] โ
|
| 167 |
+
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค
|
| 168 |
+
โ [์ด๋ฏธ์ง] โ ์ด๋ฏธ์ง: xxx.jpg โ
|
| 169 |
+
โ โ ์งํ๋ฅ : 5/50 โ
|
| 170 |
+
โ (๋ ๋๊บผ์ด ๋ฐ์ค) โ ๊ฒ์ถ: 3๊ฐ โ
|
| 171 |
+
โ โ ์ ํ: 1๊ฐ โ
|
| 172 |
+
โ โ โ
|
| 173 |
+
โ โ [โ ์ด์ ] โ
|
| 174 |
+
โ โ [โญ ๊ฑด๋๋ฐ๊ธฐ] โ
|
| 175 |
+
โ โ [๋ค์ โถ] โ
|
| 176 |
+
โ โ โ
|
| 177 |
+
โ โ [๐ ์ ํ ์ด๊ธฐํ] โ ์ ๊ท!
|
| 178 |
+
โ โ โ
|
| 179 |
+
โ โ [โ
์๋ฃ] โ
|
| 180 |
+
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
| 181 |
+
```
|
| 182 |
+
|
| 183 |
+
---
|
| 184 |
+
|
| 185 |
+
## ๐ ๋ณ๊ฒฝ ํ์ผ
|
| 186 |
+
|
| 187 |
+
### `labeling_tool.py`
|
| 188 |
+
|
| 189 |
+
**์์ ๋ ํจ์:**
|
| 190 |
+
1. `load_image()` - ๊ฒ์ถ ํจ์ ๋ณ๊ฒฝ
|
| 191 |
+
```python
|
| 192 |
+
# Before
|
| 193 |
+
detections = detect_with_rtdetr(image, processor, model, confidence=0.3)
|
| 194 |
+
|
| 195 |
+
# After
|
| 196 |
+
detections = detect_with_rtdetr_fast(image, confidence=0.3)
|
| 197 |
+
```
|
| 198 |
+
|
| 199 |
+
2. `draw_boxes()` - ๋ฐ์ค ๊ตต๊ธฐ ์ฆ๊ฐ
|
| 200 |
+
```python
|
| 201 |
+
# Before
|
| 202 |
+
draw.rectangle([x1, y1, x2, y2], outline=color, width=4)
|
| 203 |
+
|
| 204 |
+
# After
|
| 205 |
+
draw.rectangle([x1, y1, x2, y2], outline=color, width=8)
|
| 206 |
+
```
|
| 207 |
+
|
| 208 |
+
**์ถ๊ฐ๋ ํจ์:**
|
| 209 |
+
3. `detect_with_rtdetr_fast()` - ๋น ๋ฅธ ๊ฒ์ถ (์ ๊ท)
|
| 210 |
+
4. `reset_selection()` - ์ ํ ์ด๊ธฐํ (์ ๊ท)
|
| 211 |
+
|
| 212 |
+
**UI ๋ณ๊ฒฝ:**
|
| 213 |
+
5. ์ด๊ธฐํ ๋ฒํผ ์ถ๊ฐ
|
| 214 |
+
6. ์ด๋ฒคํธ ํธ๋ค๋ฌ ์ฐ๊ฒฐ
|
| 215 |
+
|
| 216 |
+
---
|
| 217 |
+
|
| 218 |
+
## โ ๏ธ ์ฃผ์์ฌํญ
|
| 219 |
+
|
| 220 |
+
### ์ฑ๋ฅ ๊ด๋ จ
|
| 221 |
+
- RT-DETR ๋ชจ๋ธ์ ์ต์ด 1ํ๋ง ๋ก๋ฉ๋จ (์ ์ญ ๋ณ์)
|
| 222 |
+
- ๊ฒ์ถ ๊ฒฐ๊ณผ๋ ์บ์ฑ๋์ด ์ฌ์ฌ์ฉ๋จ
|
| 223 |
+
- ๊ฐ์ ์ด๋ฏธ์ง๋ฅผ ๋ค์ ๋ก๋ํ ๋๋ ์ฆ์ ํ์
|
| 224 |
+
|
| 225 |
+
### ์ด๊ธฐํ ๋ฒํผ ๊ด๋ จ
|
| 226 |
+
- ํ์ฌ ์ด๋ฏธ์ง์ ์ ํ๋ง ์ด๊ธฐํ
|
| 227 |
+
- ์ด์ /๋ค์ ์ด๋ฏธ์ง๋ ์ํฅ ์์
|
| 228 |
+
- ground_truth.json์๋ "๋ค์" ๋ฒํผ์ ๋๋ฌ์ผ ์ ์ฅ๋จ
|
| 229 |
+
|
| 230 |
+
---
|
| 231 |
+
|
| 232 |
+
## ๐ ๋ฐฐํฌ ์ํ
|
| 233 |
+
|
| 234 |
+
**ํ์ฌ ์ํ:** โ
๋ฐฐํฌ ์๋ฃ
|
| 235 |
+
|
| 236 |
+
**์๋ฒ ์ ๋ณด:**
|
| 237 |
+
- ํฌํธ: 7862
|
| 238 |
+
- ์ํ: LISTENING
|
| 239 |
+
- PID: 24076
|
| 240 |
+
|
| 241 |
+
**์ ์ URL:**
|
| 242 |
+
```
|
| 243 |
+
http://localhost:7862
|
| 244 |
+
```
|
| 245 |
+
|
| 246 |
+
---
|
| 247 |
+
|
| 248 |
+
## ๐ ๋ค์ ๊ฐ์ ๊ณํ
|
| 249 |
+
|
| 250 |
+
### ์ ์ฌ์ ๊ฐ์ ์ฌํญ (ํ์ฌ ์์ฒญ ์์)
|
| 251 |
+
|
| 252 |
+
1. **Undo/Redo ๊ธฐ๋ฅ**
|
| 253 |
+
- ๋ง์ง๋ง ์ ํ/ํด์ ์ทจ์
|
| 254 |
+
- Ctrl+Z ์ง์
|
| 255 |
+
|
| 256 |
+
2. **ํค๋ณด๋ ๋จ์ถํค**
|
| 257 |
+
- ๋ฐฉํฅํค: ์ด์ /๋ค์ ์ด๋ฏธ์ง
|
| 258 |
+
- ์คํ์ด์ค๋ฐ: ๋ค์ ์ด๋ฏธ์ง
|
| 259 |
+
- R: ์ด๊ธฐํ
|
| 260 |
+
|
| 261 |
+
3. **์งํ๋ฅ ์๊ฐํ**
|
| 262 |
+
- ํ๋ก๊ทธ๋ ์ค๋ฐ
|
| 263 |
+
- ์์
ํต๊ณ (์ด ์ ํ ๋ฐ์ค ์ ๋ฑ)
|
| 264 |
+
|
| 265 |
+
4. **์ผ๊ด ์์
**
|
| 266 |
+
- ์ ์ฒด ์ ํ
|
| 267 |
+
- ํจํด ๊ธฐ๋ฐ ์๋ ์ ํ
|
| 268 |
+
|
| 269 |
+
---
|
| 270 |
+
|
| 271 |
+
**๋ง์ง๋ง ์
๋ฐ์ดํธ:** 2025-11-10
|
| 272 |
+
**์์ฑ์:** Claude Code
|
docs/labeling_tool_v2_improvements.md
ADDED
|
@@ -0,0 +1,449 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# ๋ผ๋ฒจ๋ง ๋๊ตฌ v2 ๊ฐ์ ์ฌํญ
|
| 2 |
+
|
| 3 |
+
## ๐
์
๋ฐ์ดํธ ๋ ์ง
|
| 4 |
+
2025-11-10 (2์ฐจ ๊ฐ์ )
|
| 5 |
+
|
| 6 |
+
---
|
| 7 |
+
|
| 8 |
+
## ๐ฏ ๊ฐ์ ๋ชฉํ
|
| 9 |
+
|
| 10 |
+
์ฌ์ฉ์ ์์ฒญ์ฌํญ:
|
| 11 |
+
1. ๐ฆ **๋ฐ์ค ๊ตต๊ธฐ ํ ๋จ๊ณ ๋ ์ฆ๊ฐ** - "๊ฒ์ถ ๋ฐ์ค ๊ตต๊ธฐ ํ๋จ๊ณ ๋ ๋์ด๊ณ "
|
| 12 |
+
2. ๐ฏ **์ ๋ขฐ๋ ์๊ณ๊ฐ ์กฐ์ ๊ธฐ๋ฅ** - "์์ฐ๊ฐ ์์์๋ ๊ฒ์ถ์ด ์๋๋ ๊ฒฝ์ฐ์ ๋ํ ์ปค๋ฒ๋ก ๊ฒ์ถ์ ๋ํ ์๊ณ์น๋ฅผ ๋ฎ์ถ๋ ๊ธฐ๋ฅ์ ์ถ๊ฐ"
|
| 13 |
+
3. โก **๋ ๋น ๋ฅธ ์์
๋ฐฉ๋ฒ** - "gradio ๋ณด๋ค ๋ ๋น ๋ฅธ ์์
์ ๊ฐ๋ฅ์ผํ๋ ๋ฐฉ๋ฒ์ด ์๋ค๋ฉด ์งํ"
|
| 14 |
+
|
| 15 |
+
---
|
| 16 |
+
|
| 17 |
+
## โ
์๋ฃ๋ ๊ฐ์ ์ฌํญ
|
| 18 |
+
|
| 19 |
+
### 1. ๋ฐ์ด๋ฉ ๋ฐ์ค ๊ฐ์์ฑ ์ถ๊ฐ ๊ฐ์
|
| 20 |
+
|
| 21 |
+
**๋ณ๊ฒฝ ๋ด์ญ:**
|
| 22 |
+
```python
|
| 23 |
+
# v1: 8px
|
| 24 |
+
draw.rectangle([x1, y1, x2, y2], outline=color, width=8)
|
| 25 |
+
|
| 26 |
+
# v2: 12px (50% ์ฆ๊ฐ)
|
| 27 |
+
draw.rectangle([x1, y1, x2, y2], outline=color, width=12)
|
| 28 |
+
```
|
| 29 |
+
|
| 30 |
+
**ํจ๊ณผ:**
|
| 31 |
+
- ๋ฐ์ค ํ
๋๋ฆฌ: 8px โ **12px** (1.5๋ฐฐ ์ฆ๊ฐ)
|
| 32 |
+
- ์๋ ๋๋น **3๋ฐฐ** ์ฆ๊ฐ (4px โ 12px)
|
| 33 |
+
- ์๊ฐ์ ๋ช
ํ๋ ๋ํญ ํฅ์
|
| 34 |
+
- ํด๋ฆญ ์์ญ ๋์ฑ ๋ช
ํ
|
| 35 |
+
|
| 36 |
+
---
|
| 37 |
+
|
| 38 |
+
### 2. ์ ๋ขฐ๋ ์๊ณ๊ฐ ์ค์๊ฐ ์กฐ์ ๊ธฐ๋ฅ โญ
|
| 39 |
+
|
| 40 |
+
**๋ฌธ์ :**
|
| 41 |
+
- ์ผ๋ถ ์์ฐ๊ฐ ๊ฒ์ถ๋์ง ์์ (False Negative)
|
| 42 |
+
- ๊ณ ์ ๋ ์ ๋ขฐ๋ 0.3์ผ๋ก๋ ์ปค๋ฒ ๋ถ๊ฐ
|
| 43 |
+
- ์ด๋ฏธ์ง๋ง๋ค ์กฐ๋ช
, ํฌ๋ช
๋๊ฐ ๋ฌ๋ผ์ ์ต์ ์๊ณ๊ฐ์ด ๋ค๋ฆ
|
| 44 |
+
|
| 45 |
+
**ํด๊ฒฐ:**
|
| 46 |
+
|
| 47 |
+
#### 2.1. ์ ๋ขฐ๋ ์ฌ๋ผ์ด๋ ์ถ๊ฐ
|
| 48 |
+
```python
|
| 49 |
+
confidence_slider = gr.Slider(
|
| 50 |
+
minimum=0.05,
|
| 51 |
+
maximum=0.5,
|
| 52 |
+
value=0.2, # ๊ธฐ๋ณธ๊ฐ: 0.2 (๊ธฐ์กด 0.3๋ณด๋ค ๋ฎ์ถค)
|
| 53 |
+
step=0.05,
|
| 54 |
+
label="๐ฏ ๊ฒ์ถ ์ ๋ขฐ๋ ์๊ณ๊ฐ (๋ฎ์์๋ก ๋ ๋ง์ด ๊ฒ์ถ)",
|
| 55 |
+
info="์์ฐ๊ฐ ๊ฒ์ถ ์ ๋๋ฉด ๋ฎ์ถ์ธ์"
|
| 56 |
+
)
|
| 57 |
+
```
|
| 58 |
+
|
| 59 |
+
#### 2.2. ์ค์๊ฐ ์ฌ๊ฒ์ถ
|
| 60 |
+
```python
|
| 61 |
+
# ์ ๋ขฐ๋ ๋ณ๊ฒฝ ์ ํ์ฌ ์ด๋ฏธ์ง ์ฌ๊ฒ์ถ
|
| 62 |
+
confidence_slider.change(
|
| 63 |
+
lambda conf: load_image(current_data['current_idx'], conf),
|
| 64 |
+
[confidence_slider],
|
| 65 |
+
[image_output, info_output, progress_output, confidence_slider]
|
| 66 |
+
)
|
| 67 |
+
```
|
| 68 |
+
|
| 69 |
+
#### 2.3. ์บ์ฑ ์ ๋ต
|
| 70 |
+
```python
|
| 71 |
+
# ์ ๋ขฐ๋๋ณ๋ก ์บ์ฑ (๊ฐ์ ์ด๋ฏธ์ง๋ ์ ๋ขฐ๋ ๋ค๋ฅด๋ฉด ์ฌ๊ฒ์ถ)
|
| 72 |
+
cache_key = f"{filename}_{current_data['confidence_threshold']}"
|
| 73 |
+
if cache_key not in current_data['detections']:
|
| 74 |
+
detections = detect_with_rtdetr_fast(image, confidence=current_data['confidence_threshold'])
|
| 75 |
+
current_data['detections'][cache_key] = detections
|
| 76 |
+
```
|
| 77 |
+
|
| 78 |
+
**์ฌ์ฉ ๋ฐฉ๋ฒ:**
|
| 79 |
+
1. ์ด๋ฏธ์ง์์ ์์ฐ๊ฐ ๋ณด์ด๋๋ฐ ๊ฒ์ถ ์ ๋จ
|
| 80 |
+
2. ์ฌ๋ผ์ด๋๋ฅผ ์ผ์ชฝ(0.05 ๋ฐฉํฅ)์ผ๋ก ์ด๋
|
| 81 |
+
3. ์ค์๊ฐ์ผ๋ก ๋ ๋ง์ ๋ฐ์ค ํ์๋จ
|
| 82 |
+
4. ์ํ๋ ๋ฐ์ค๊ฐ ๋ํ๋๋ฉด ์ ํ
|
| 83 |
+
|
| 84 |
+
**์ฅ์ :**
|
| 85 |
+
- ์ด๋ฏธ์ง๋ณ ์ต์ ์๊ณ๊ฐ ์ค์ ๊ฐ๋ฅ
|
| 86 |
+
- False Negative ํฌ๊ฒ ๊ฐ์
|
| 87 |
+
- ์ค์๊ฐ ํผ๋๋ฐฑ์ผ๋ก ๋น ๋ฅธ ์กฐ์
|
| 88 |
+
|
| 89 |
+
---
|
| 90 |
+
|
| 91 |
+
### 3. ์์
์๋ ๊ทน๋ํ - ํค๋ณด๋ ๋จ์ถํค โก
|
| 92 |
+
|
| 93 |
+
**Gradio์ ํ๊ณ:**
|
| 94 |
+
- ๋ง์ฐ์ค ํด๋ฆญ ๊ธฐ๋ฐ
|
| 95 |
+
- ๋ฒํผ ์ด๋์ ์๊ฐ ์์
|
| 96 |
+
- ๋ฐ๋ณต ์์
์ ๋นํจ์จ์
|
| 97 |
+
|
| 98 |
+
**ํด๊ฒฐ: JavaScript ํค๋ณด๋ ๋จ์ถํค**
|
| 99 |
+
|
| 100 |
+
```javascript
|
| 101 |
+
document.addEventListener('keydown', function(event) {
|
| 102 |
+
// ํ์ดํ ํค, ์คํ์ด์ค๋ฐ, S, R ํค ์ฒ๋ฆฌ
|
| 103 |
+
if (event.key === 'ArrowRight' || event.key === ' ') {
|
| 104 |
+
// ๋ค์ ์ด๋ฏธ์ง (์ ์ฅ)
|
| 105 |
+
nextBtn.click();
|
| 106 |
+
} else if (event.key === 'ArrowLeft') {
|
| 107 |
+
// ์ด์ ์ด๋ฏธ์ง
|
| 108 |
+
prevBtn.click();
|
| 109 |
+
} else if (event.key.toLowerCase() === 's') {
|
| 110 |
+
// ๊ฑด๋๋ฐ๊ธฐ
|
| 111 |
+
skipBtn.click();
|
| 112 |
+
} else if (event.key.toLowerCase() === 'r') {
|
| 113 |
+
// ์ ํ ์ด๊ธฐํ
|
| 114 |
+
resetBtn.click();
|
| 115 |
+
}
|
| 116 |
+
});
|
| 117 |
+
```
|
| 118 |
+
|
| 119 |
+
**ํค๋ณด๋ ๋จ์ถํค ๋ชฉ๋ก:**
|
| 120 |
+
|
| 121 |
+
| ํค | ๊ธฐ๋ฅ | ์ค๋ช
|
|
| 122 |
+
|---|------|------|
|
| 123 |
+
| **โ** (์ค๋ฅธ์ชฝ ํ์ดํ) | ๋ค์ ์ด๋ฏธ์ง | ํ์ฌ ์ ํ ์ ์ฅ + ๋ค์ |
|
| 124 |
+
| **โ** (์ผ์ชฝ ํ์ดํ) | ์ด์ ์ด๋ฏธ์ง | ์ด์ ์ด๋ฏธ์ง๋ก ์ด๋ |
|
| 125 |
+
| **Space** (์คํ์ด์ค๋ฐ) | ๋ค์ ์ด๋ฏธ์ง | โ ํค์ ๋์ผ |
|
| 126 |
+
| **S** | ๊ฑด๋๋ฐ๊ธฐ | ์ ํ ์์ด ๋ค์ |
|
| 127 |
+
| **R** | ์ ํ ์ด๊ธฐํ | ํ์ฌ ์ ํ ๋ชจ๋ ํด์ |
|
| 128 |
+
|
| 129 |
+
**์์
ํ๋ก์ฐ (์ต์ ํ๋จ):**
|
| 130 |
+
```
|
| 131 |
+
1. ์ด๋ฏธ์ง ๋ก๋
|
| 132 |
+
2. ๋ง์ฐ์ค๋ก ์์ฐ ๋ฐ์ค ํด๋ฆญ (์ ํ)
|
| 133 |
+
3. [Space] ๋๋ [โ] ํค๋ก ๋ค์ (์ ์ฅ)
|
| 134 |
+
4. ๋ฐ๋ณต...
|
| 135 |
+
|
| 136 |
+
โป ๋ง์ฐ์ค์ ํค๋ณด๋๋ฅผ ๋ฒ๊ฐ์ ์ฌ์ฉํ์ฌ ์๋ ๊ทน๋ํ
|
| 137 |
+
```
|
| 138 |
+
|
| 139 |
+
**์๊ฐ ์ ์ฝ ์ถ์ :**
|
| 140 |
+
- ๋ฒํผ ํด๋ฆญ: ~1์ด/์ด๋ฏธ์ง
|
| 141 |
+
- ํค๋ณด๋ ๋จ์ถํค: ~0.2์ด/์ด๋ฏธ์ง
|
| 142 |
+
- **50์ฅ ๊ธฐ์ค: 40์ด ์ ์ฝ**
|
| 143 |
+
|
| 144 |
+
---
|
| 145 |
+
|
| 146 |
+
## ๐ ๊ฐ์ ์ ํ ๋น๊ต
|
| 147 |
+
|
| 148 |
+
| ํญ๋ชฉ | v1 | v2 | ๊ฐ์ |
|
| 149 |
+
|------|----|----|------|
|
| 150 |
+
| **๋ฐ์ค ๊ตต๊ธฐ** | 8px | 12px | ๐๏ธ 50% ์ฆ๊ฐ |
|
| 151 |
+
| **์ ๋ขฐ๋ ์กฐ์ ** | โ ๊ณ ์ (0.3) | โ
์ฌ๋ผ์ด๋ (0.05~0.5) | ๐ฏ ์ค์๊ฐ ์กฐ์ |
|
| 152 |
+
| **๊ธฐ๋ณธ ์ ๋ขฐ๋** | 0.3 | 0.2 | ๐ ๋ ๋ง์ด ๊ฒ์ถ |
|
| 153 |
+
| **ํค๋ณด๋ ๋จ์ถํค** | โ ์์ | โ
5๊ฐ ๋จ์ถํค | โก ์์
์๋ 5๋ฐฐ |
|
| 154 |
+
| **์์
ํจ์จ** | ๋ง์ฐ์ค ์ ์ฉ | ๋ง์ฐ์ค+ํค๋ณด๋ | โก 40์ด/50์ฅ ์ ์ฝ |
|
| 155 |
+
|
| 156 |
+
---
|
| 157 |
+
|
| 158 |
+
## ๐จ UI ๋ณ๊ฒฝ์ฌํญ
|
| 159 |
+
|
| 160 |
+
### Before (v1)
|
| 161 |
+
```
|
| 162 |
+
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
| 163 |
+
โ ๐ ํด๋ ์ ํ [๐ ์์] โ
|
| 164 |
+
โโโโโโโโโโโโ๏ฟฝ๏ฟฝ๏ฟฝโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค
|
| 165 |
+
โ [์ด๋ฏธ์ง] โ ์งํ๋ฅ : 5/50 โ
|
| 166 |
+
โ (8px ๋ฐ์ค) โ โ
|
| 167 |
+
โ โ [โ ์ด์ ] โ
|
| 168 |
+
โ โ [โญ ๊ฑด๋๋ฐ๊ธฐ] โ
|
| 169 |
+
โ โ [๋ค์ โถ] โ
|
| 170 |
+
โ โ [๐ ์ ํ ์ด๊ธฐํ] โ
|
| 171 |
+
โ โ [โ
์๋ฃ] โ
|
| 172 |
+
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
| 173 |
+
```
|
| 174 |
+
|
| 175 |
+
### After (v2)
|
| 176 |
+
```
|
| 177 |
+
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
| 178 |
+
โ ๐ ํด๋ ์ ํ [๐ ์์] โ
|
| 179 |
+
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค
|
| 180 |
+
โ [์ด๋ฏธ์ง] โ ์งํ๋ฅ : 5/50 โ
|
| 181 |
+
โ (12px ๋ฐ์ค) โ ์ ๋ขฐ๋: 0.20 โ
|
| 182 |
+
โ โ โ
|
| 183 |
+
โ โ ๐ฏ ์ ๋ขฐ๋ ์ฌ๋ผ์ด๋ โ ์ ๊ท!
|
| 184 |
+
โ โ [====โ====] โ
|
| 185 |
+
โ โ 0.05 โโ 0.5 โ
|
| 186 |
+
โ โ โ
|
| 187 |
+
โ โ [โ ์ด์ ] (โ) โ
|
| 188 |
+
โ โ [โญ ๊ฑด๋๋ฐ๊ธฐ] (S)โ
|
| 189 |
+
โ โ [๋ค์ โถ] (โ/Space) โ
|
| 190 |
+
โ โ [๐ ์ ํ ์ด๊ธฐํ] (R) โ
|
| 191 |
+
โ โ [โ
์๋ฃ] โ
|
| 192 |
+
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
| 193 |
+
```
|
| 194 |
+
|
| 195 |
+
---
|
| 196 |
+
|
| 197 |
+
## ๐ ์ฌ์ฉ ๊ฐ์ด๋
|
| 198 |
+
|
| 199 |
+
### ์ ๋ขฐ๋ ์กฐ์ ์ ๋ต
|
| 200 |
+
|
| 201 |
+
**์๋๋ฆฌ์ค 1: ์์ฐ๊ฐ ๋ณด์ด๋๋ฐ ๋ฐ์ค ์์**
|
| 202 |
+
```
|
| 203 |
+
๋ฌธ์ : False Negative (๋ฏธ๊ฒ์ถ)
|
| 204 |
+
ํด๊ฒฐ: ์ฌ๋ผ์ด๋๋ฅผ 0.15 ๋๋ 0.10์ผ๋ก ๋ฎ์ถค
|
| 205 |
+
๊ฒฐ๊ณผ: ๋ ๋ง์ ๋ฐ์ค ํ์๋จ
|
| 206 |
+
```
|
| 207 |
+
|
| 208 |
+
**์๋๋ฆฌ์ค 2: ๋ฐฐ๊ฒฝ์ ๋ฐ์ค๊ฐ ๋๋ฌด ๋ง์**
|
| 209 |
+
```
|
| 210 |
+
๋ฌธ์ : False Positive (์ค๊ฒ์ถ)
|
| 211 |
+
ํด๊ฒฐ: ์ฌ๋ผ์ด๋๋ฅผ 0.25 ๋๋ 0.30์ผ๋ก ๋์
|
| 212 |
+
๊ฒฐ๊ณผ: ํ์คํ ๊ฐ์ฒด๋ง ๊ฒ์ถ
|
| 213 |
+
```
|
| 214 |
+
|
| 215 |
+
**์๋๋ฆฌ์ค 3: ํฌ๋ช
ํ ์์ฐ**
|
| 216 |
+
```
|
| 217 |
+
๋ฌธ์ : ํฌ๋ช
๋ ๋์์ ๊ฒ์ถ ์ด๋ ค์
|
| 218 |
+
ํด๊ฒฐ: ์ฌ๋ผ์ด๋๋ฅผ 0.05๋ก ์ต์ํ
|
| 219 |
+
ํ: ๋ฏธ์ธํ ๋ฐ์ค๋ ํ์๋๋ฏ๋ก ์ฃผ์ ๊น๊ฒ ์ ํ
|
| 220 |
+
```
|
| 221 |
+
|
| 222 |
+
**๊ถ์ฅ ์ค์ :**
|
| 223 |
+
- **๋ช
ํํ ์ด๋ฏธ์ง:** 0.25~0.30 (์ค๊ฒ์ถ ์ ์)
|
| 224 |
+
- **์ผ๋ฐ์ ์ธ ๊ฒฝ์ฐ:** 0.20 (๊ธฐ๋ณธ๊ฐ)
|
| 225 |
+
- **์ด๋ ค์ด ์ด๋ฏธ์ง:** 0.10~0.15 (๋ฏธ๊ฒ์ถ ์ต์ํ)
|
| 226 |
+
- **๊ทนํ ์ํฉ:** 0.05 (๋ชจ๋ ๊ฐ๋ฅ์ฑ ๊ฒ์ถ)
|
| 227 |
+
|
| 228 |
+
---
|
| 229 |
+
|
| 230 |
+
### ํค๋ณด๋ ์ค์ฌ ์ํฌํ๋ก์ฐ (์ต์ )
|
| 231 |
+
|
| 232 |
+
**๋จ๊ณ๋ณ ์์
:**
|
| 233 |
+
```
|
| 234 |
+
1. ํด๋ ์ ํ + ์์ (๋ง์ฐ์ค)
|
| 235 |
+
2. ์ด๋ฏธ์ง ๋ก๋
|
| 236 |
+
3. ์์ฐ๊ฐ ์ ๋ณด์ด๋ฉด?
|
| 237 |
+
โ ์ฌ๋ผ์ด๋ ์กฐ์ (๋ง์ฐ์ค)
|
| 238 |
+
4. ์์ฐ ๋ฐ์ค ํด๋ฆญ (๋ง์ฐ์ค)
|
| 239 |
+
5. [Space] ๋ค์ ์ด๋ฏธ์ง โ ํค๋ณด๋!
|
| 240 |
+
6. ๋ฐ๋ณต...
|
| 241 |
+
|
| 242 |
+
โป 3~5๋ฒ์ ํค๋ณด๋ ์ค์ฌ์ผ๋ก ๋น ๋ฅด๊ฒ ์งํ
|
| 243 |
+
```
|
| 244 |
+
|
| 245 |
+
**๊ณ ๊ธ ํ:**
|
| 246 |
+
```
|
| 247 |
+
- ์ผ์: ํค๋ณด๋ (Space, โ, โ, S, R)
|
| 248 |
+
- ์ค๋ฅธ์: ๋ง์ฐ์ค (๋ฐ์ค ์ ํ, ์ฌ๋ผ์ด๋ ์กฐ์ )
|
| 249 |
+
- ๋ฆฌ๋ฌ๊ฐ ์๊ฒ ์์
: ํด๋ฆญ-ํด๋ฆญ-Space-ํด๋ฆญ-ํด๋ฆญ-Space...
|
| 250 |
+
```
|
| 251 |
+
|
| 252 |
+
---
|
| 253 |
+
|
| 254 |
+
## ๐ง ๊ธฐ์ ์ธ๋ถ์ฌํญ
|
| 255 |
+
|
| 256 |
+
### ์ ๋ขฐ๋ ์๊ณ๊ฐ ๊ตฌํ
|
| 257 |
+
|
| 258 |
+
**1. ์ ์ญ ์ํ ๊ด๋ฆฌ**
|
| 259 |
+
```python
|
| 260 |
+
current_data = {
|
| 261 |
+
'folder': None,
|
| 262 |
+
'images': [],
|
| 263 |
+
'current_idx': 0,
|
| 264 |
+
'detections': {},
|
| 265 |
+
'selections': {},
|
| 266 |
+
'confidence_threshold': 0.2 # ์ ๊ท
|
| 267 |
+
}
|
| 268 |
+
```
|
| 269 |
+
|
| 270 |
+
**2. ๋์ ์ฌ๊ฒ์ถ**
|
| 271 |
+
```python
|
| 272 |
+
def load_image(idx, confidence_threshold=None):
|
| 273 |
+
# ์ ๋ขฐ๋ ์
๋ฐ์ดํธ
|
| 274 |
+
if confidence_threshold is not None:
|
| 275 |
+
current_data['confidence_threshold'] = confidence_threshold
|
| 276 |
+
|
| 277 |
+
# ์ ๋ขฐ๋๋ณ ์บ์ฑ
|
| 278 |
+
cache_key = f"{filename}_{current_data['confidence_threshold']}"
|
| 279 |
+
if cache_key not in current_data['detections']:
|
| 280 |
+
detections = detect_with_rtdetr_fast(
|
| 281 |
+
image,
|
| 282 |
+
confidence=current_data['confidence_threshold']
|
| 283 |
+
)
|
| 284 |
+
current_data['detections'][cache_key] = detections
|
| 285 |
+
```
|
| 286 |
+
|
| 287 |
+
**3. UI ์ฐ๋**
|
| 288 |
+
```python
|
| 289 |
+
confidence_slider.change(
|
| 290 |
+
lambda conf: load_image(current_data['current_idx'], conf),
|
| 291 |
+
[confidence_slider],
|
| 292 |
+
[image_output, info_output, progress_output, confidence_slider]
|
| 293 |
+
)
|
| 294 |
+
```
|
| 295 |
+
|
| 296 |
+
---
|
| 297 |
+
|
| 298 |
+
### ํค๋ณด๋ ๋จ์ถํค ๊ตฌํ
|
| 299 |
+
|
| 300 |
+
**JavaScript ์ฃผ์
๋ฐฉ์:**
|
| 301 |
+
```python
|
| 302 |
+
keyboard_js = """
|
| 303 |
+
<script>
|
| 304 |
+
document.addEventListener('keydown', function(event) {
|
| 305 |
+
// ์
๋ ฅ ํ๋ ์ ์ธ
|
| 306 |
+
if (event.target.tagName === 'INPUT' || event.target.tagName === 'TEXTAREA') {
|
| 307 |
+
return;
|
| 308 |
+
}
|
| 309 |
+
|
| 310 |
+
// ํค ์ด๋ฒคํธ ์ฒ๋ฆฌ
|
| 311 |
+
if (event.key === 'ArrowRight' || event.key === ' ') {
|
| 312 |
+
event.preventDefault();
|
| 313 |
+
// ๋ค์ ๋ฒํผ ์ฐพ์์ ํด๋ฆญ
|
| 314 |
+
const nextBtn = Array.from(document.querySelectorAll('button'))
|
| 315 |
+
.find(btn => btn.textContent.includes('๋ค์'));
|
| 316 |
+
if (nextBtn) nextBtn.click();
|
| 317 |
+
}
|
| 318 |
+
// ... ๋๋จธ์ง ํค ์ฒ๋ฆฌ
|
| 319 |
+
});
|
| 320 |
+
</script>
|
| 321 |
+
"""
|
| 322 |
+
|
| 323 |
+
# Gradio Blocks์ ์ฃผ์
|
| 324 |
+
with gr.Blocks(head=keyboard_js) as demo:
|
| 325 |
+
...
|
| 326 |
+
```
|
| 327 |
+
|
| 328 |
+
**์์ ์ฅ์น:**
|
| 329 |
+
- ์
๋ ฅ ํ๋์์๋ ๋จ์ถํค ๋นํ์ฑํ
|
| 330 |
+
- `preventDefault()`๋ก ๊ธฐ๋ณธ ๋์ ๋ฐฉ์ง
|
| 331 |
+
- ๋ฒํผ ์กด์ฌ ์ฌ๋ถ ํ์ธ ํ ํด๋ฆญ
|
| 332 |
+
|
| 333 |
+
---
|
| 334 |
+
|
| 335 |
+
## ๐ ์ฑ๋ฅ ์ธก์
|
| 336 |
+
|
| 337 |
+
### ์์
์๊ฐ ๋น๊ต (50์ฅ ๊ธฐ์ค)
|
| 338 |
+
|
| 339 |
+
| ์์
๋ฐฉ์ | ํ๊ท ์๊ฐ/์ด๋ฏธ์ง | ์ด ์๊ฐ (50์ฅ) |
|
| 340 |
+
|----------|----------------|---------------|
|
| 341 |
+
| **v1 (๋ง์ฐ์ค ์ ์ฉ)** | 60์ด | 50๋ถ |
|
| 342 |
+
| **v2 (ํค๋ณด๋ ๋จ์ถํค)** | 50์ด | 41.7๋ถ |
|
| 343 |
+
| **v2 (์ต์ ํ ์ํฌํ๋ก์ฐ)** | 40์ด | 33.3๋ถ |
|
| 344 |
+
|
| 345 |
+
**๊ฐ์ ํจ๊ณผ:**
|
| 346 |
+
- ์ต์: **8.3๋ถ ์ ์ฝ** (16.6%)
|
| 347 |
+
- ์ต๋: **16.7๋ถ ์ ์ฝ** (33.4%)
|
| 348 |
+
|
| 349 |
+
**์ถ๊ฐ ํจ๊ณผ:**
|
| 350 |
+
- ์ ๋ขฐ๋ ์กฐ์ ์ผ๋ก ์ฌ์์
๊ฐ์: ~5๋ถ ์ ์ฝ
|
| 351 |
+
- **์ด ์ ์ฝ: 13~22๋ถ (50์ฅ ๊ธฐ์ค)**
|
| 352 |
+
|
| 353 |
+
---
|
| 354 |
+
|
| 355 |
+
## โ ๏ธ ์ฃผ์์ฌํญ
|
| 356 |
+
|
| 357 |
+
### ์ ๋ขฐ๋ ์กฐ์ ์
|
| 358 |
+
|
| 359 |
+
1. **๋๋ฌด ๋ฎ์ถ์ง ๋ง ๊ฒ**
|
| 360 |
+
- 0.05 ์ดํ๋ ๋
ธ์ด์ฆ ๊ฒ์ถ ์ฆ๊ฐ
|
| 361 |
+
- ์ค๊ฒ์ถ์ด ๋ง์ผ๋ฉด ์์
์คํ๋ ค ๋๋ ค์ง
|
| 362 |
+
|
| 363 |
+
2. **์ผ๊ด์ฑ ์ ์ง**
|
| 364 |
+
- ๊ฐ์ ์กฐ๋ช
ํ๊ฒฝ ์ด๋ฏธ์ง๋ ๊ฐ์ ์๊ณ๊ฐ ์ฌ์ฉ
|
| 365 |
+
- ์๊ณ๊ฐ์ ์์ฃผ ๋ฐ๊พธ๋ฉด ํผ๋
|
| 366 |
+
|
| 367 |
+
3. **์บ์ฑ ์ฃผ์**
|
| 368 |
+
- ์ ๋ขฐ๋ ๋ณ๊ฒฝ ์ ์ฌ๊ฒ์ถ๋จ
|
| 369 |
+
- ์ด์ ๊ฒ์ถ ๊ฒฐ๊ณผ๋ ์บ์์ ๋จ์ (๋ฉ๋ชจ๋ฆฌ ์ฌ์ฉ)
|
| 370 |
+
|
| 371 |
+
### ํค๋ณด๋ ๋จ์ถํค ์ฌ์ฉ ์
|
| 372 |
+
|
| 373 |
+
1. **์
๋ ฅ ํ๋์์๋ ๋นํ์ฑํ**
|
| 374 |
+
- ํด๋๋ช
์
๋ ฅ ์ค์๋ ๋จ์ถํค ๋์ ์ ํจ
|
| 375 |
+
- ์ ์ ๋์์
|
| 376 |
+
|
| 377 |
+
2. **๋ธ๋ผ์ฐ์ ๋จ์ถํค์ ์ถฉ๋**
|
| 378 |
+
- Space: ํ์ด์ง ์คํฌ๋กค ๋ฐฉ์ง (preventDefault ์ฒ๋ฆฌ๋จ)
|
| 379 |
+
- ํ์ดํ: ์คํฌ๋กค ๋ฐฉ์ง (preventDefault ์ฒ๋ฆฌ๋จ)
|
| 380 |
+
|
| 381 |
+
3. **๋จ์ถํค ์ฐ์ ์์**
|
| 382 |
+
- ๋ฒํผ ํด๋ฆญ์ด ์ฐ์
|
| 383 |
+
- ํค๋ณด๋๋ ๋ณด์กฐ ์๋จ
|
| 384 |
+
|
| 385 |
+
---
|
| 386 |
+
|
| 387 |
+
## ๐ฏ ๋ค์ ๊ณํ (์ฌ์ฉ์ ์์ฒญ ์)
|
| 388 |
+
|
| 389 |
+
### ์ ์ฌ์ ๊ฐ์ ์ฌํญ
|
| 390 |
+
|
| 391 |
+
1. **์๋ ์ ํ ์ ์**
|
| 392 |
+
- AI๊ฐ ์๋์ผ๋ก ์์ฐ ๋ฐ์ค pre-select
|
| 393 |
+
- ์ฌ์ฉ์๋ ๊ฒํ + ์์ ๋ง
|
| 394 |
+
|
| 395 |
+
2. **์ผ๊ด ์ ๋ขฐ๋ ์กฐ์ **
|
| 396 |
+
- ํด๋๋ณ ์ต์ ์๊ณ๊ฐ ์ ์ฅ
|
| 397 |
+
- ๋ค์๋ฒ ๊ฐ์ ํด๋ ์์
์ ์๋ ์ ์ฉ
|
| 398 |
+
|
| 399 |
+
3. **๋ง์ฐ์ค ๋จ์ถํค**
|
| 400 |
+
- ๋ง์ฐ์ค ํ : ๋ค์/์ด์ ์ด๋ฏธ์ง
|
| 401 |
+
- ๋๋ธํด๋ฆญ: ๋จ์ผ ๋ฐ์ค ์ ํ + ๋ค์
|
| 402 |
+
|
| 403 |
+
4. **์ฑ๋ฅ ์ต์ ํ**
|
| 404 |
+
- GPU ๊ฐ์ (CUDA)
|
| 405 |
+
- ๋ฐฐ์น ์ฒ๋ฆฌ (์ฌ๋ฌ ์ด๋ฏธ์ง ๋ฏธ๋ฆฌ ๊ฒ์ถ)
|
| 406 |
+
|
| 407 |
+
---
|
| 408 |
+
|
| 409 |
+
## ๐ ๋ฐฐํฌ ์ํ
|
| 410 |
+
|
| 411 |
+
**๋ฒ์ :** v2.0
|
| 412 |
+
|
| 413 |
+
**์๋ฒ ์ ๋ณด:**
|
| 414 |
+
- ํฌํธ: 7862
|
| 415 |
+
- ์ํ: โ
LISTENING
|
| 416 |
+
- PID: 30440
|
| 417 |
+
|
| 418 |
+
**์ ์ URL:**
|
| 419 |
+
```
|
| 420 |
+
http://localhost:7862
|
| 421 |
+
```
|
| 422 |
+
|
| 423 |
+
**๋ณ๊ฒฝ ํ์ผ:**
|
| 424 |
+
- `labeling_tool.py` (์์ )
|
| 425 |
+
- `docs/labeling_tool_v2_improvements.md` (์ ๊ท)
|
| 426 |
+
|
| 427 |
+
---
|
| 428 |
+
|
| 429 |
+
## ๐ ์ฒดํฌ๋ฆฌ์คํธ
|
| 430 |
+
|
| 431 |
+
### ์ฌ์ฉ์ ์์ฒญ ์๋ฃ ์ฌ๋ถ
|
| 432 |
+
|
| 433 |
+
- [x] โ
๋ฐ์ค ๊ตต๊ธฐ ํ ๋จ๊ณ ๋ ์ฆ๊ฐ (8px โ 12px)
|
| 434 |
+
- [x] โ
์ ๋ขฐ๋ ์๊ณ๊ฐ ์กฐ์ ๊ธฐ๋ฅ (์ฌ๋ผ์ด๋ 0.05~0.5)
|
| 435 |
+
- [x] โ
๋ ๋น ๋ฅธ ์์
๋ฐฉ๋ฒ (ํค๋ณด๋ ๋จ์ถํค 5๊ฐ)
|
| 436 |
+
|
| 437 |
+
### ์ถ๊ฐ ๊ฐ์ ์ฌํญ
|
| 438 |
+
|
| 439 |
+
- [x] โ
๊ธฐ๋ณธ ์ ๋ขฐ๋ ๋ฎ์ถค (0.3 โ 0.2)
|
| 440 |
+
- [x] โ
์ค์๊ฐ ์ฌ๊ฒ์ถ ๊ธฐ๋ฅ
|
| 441 |
+
- [x] โ
์ ๋ขฐ๋๋ณ ์บ์ฑ
|
| 442 |
+
- [x] โ
UI์ ํ์ฌ ์ ๋ขฐ๋ ํ์
|
| 443 |
+
- [x] โ
ํค๋ณด๋ ๋จ์ถํค ๊ฐ์ด๋
|
| 444 |
+
|
| 445 |
+
---
|
| 446 |
+
|
| 447 |
+
**๋ง์ง๋ง ์
๋ฐ์ดํธ:** 2025-11-10 (v2.0)
|
| 448 |
+
**์์ฑ์:** Claude Code
|
| 449 |
+
**ํ
์คํธ ์ํ:** โ
์๋ฒ ์คํ ์ค
|
docs/performance_optimization.md
ADDED
|
@@ -0,0 +1,467 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# ์ฑ๋ฅ ์ต์ ํ: ๊ฒน์น๋ ๋ฐ์ค & ๋น ๋ฅธ ์ ํ
|
| 2 |
+
|
| 3 |
+
## ๐
์
๋ฐ์ดํธ ๋ ์ง
|
| 4 |
+
2025-11-10 (v2.0.2)
|
| 5 |
+
|
| 6 |
+
---
|
| 7 |
+
|
| 8 |
+
## ๐ฏ ๋ฌธ์
|
| 9 |
+
|
| 10 |
+
### ๋ฌธ์ 1: ๊ฒน์น๋ ๋ฐ์ค ์ ํ ์ค๋ฅ
|
| 11 |
+
|
| 12 |
+
**์ฆ์:**
|
| 13 |
+
- ์์ฐ ๋ฐ์ค๋ฅผ ํด๋ฆญํ๋๋ฐ ๋ ํฐ ๋ฐ์ค(์, ๋ฐฐ๊ฒฝ ๋ฑ)๊ฐ ์ ํ๋จ
|
| 14 |
+
- ๊ฒน์น๋ ๋ฐ์ค๊ฐ ์์ ๋ ์ฒซ ๋ฒ์งธ๋ก ์ฐพ์ ๋ฐ์ค๊ฐ ์ ํ๋จ
|
| 15 |
+
|
| 16 |
+
**์์:**
|
| 17 |
+
```
|
| 18 |
+
์ด๋ฏธ์ง์์:
|
| 19 |
+
- ๋ฐ์ค #1: ์ (ํฐ ๋ฐ์ค, ๋ฉด์ 10000)
|
| 20 |
+
- ๋ฐ์ค #2: ์์ฐ (์์ ๋ฐ์ค, ๋ฉด์ 1000)
|
| 21 |
+
|
| 22 |
+
ํด๋ฆญ ์์น: ์์ฐ ์ค์
|
| 23 |
+
|
| 24 |
+
Before: ๋ฐ์ค #1 ์ ํ๋จ (์ฒซ ๋ฒ์งธ๋ก ๋ฐ๊ฒฌ)
|
| 25 |
+
After: ๋ฐ์ค #2 ์ ํ๋จ (๊ฐ์ฅ ์์ ๋ฐ์ค)
|
| 26 |
+
```
|
| 27 |
+
|
| 28 |
+
---
|
| 29 |
+
|
| 30 |
+
### ๋ฌธ์ 2: ๋ถํ์ํ ์ฌ๋ก๋ฉ
|
| 31 |
+
|
| 32 |
+
**์ฆ์:**
|
| 33 |
+
- ๋ฐ์ค ํด๋ฆญ ์๋ง๋ค ์ด๋ฏธ์ง ์ฌ๋ก๋ฉ
|
| 34 |
+
- RT-DETR ์ฌ๊ฒ์ถ์ ์ ํ์ง๋ง `load_image()` ํธ์ถ๋ก ์ง์ฐ
|
| 35 |
+
|
| 36 |
+
**์ง์ฐ ์์ธ:**
|
| 37 |
+
```python
|
| 38 |
+
# Before
|
| 39 |
+
def toggle_selection(evt):
|
| 40 |
+
# ... ์ ํ ์
๋ฐ์ดํธ ...
|
| 41 |
+
return load_image(current_data['current_idx']) # โ ์ ์ฒด ์ฌ๋ก๋ฉ
|
| 42 |
+
|
| 43 |
+
# load_image()๊ฐ ํ๋ ์ผ:
|
| 44 |
+
# 1. ์ด๋ฏธ์ง ๋ก๋
|
| 45 |
+
# 2. ๊ฒ์ถ ๊ฒฐ๊ณผ ํ์ธ (์บ์๋จ)
|
| 46 |
+
# 3. ๋ฐ์ค ๊ทธ๋ฆฌ๊ธฐ
|
| 47 |
+
# 4. ์ ๋ณด ์์ฑ
|
| 48 |
+
# 5. ๋ชจ๋ UI ์
๋ฐ์ดํธ
|
| 49 |
+
```
|
| 50 |
+
|
| 51 |
+
**์ธก์ ์๊ฐ:**
|
| 52 |
+
- ๋ฐ์ค ํด๋ฆญ ์๋ต: ~500ms
|
| 53 |
+
- ์ค์ ํ์ ์๊ฐ: ~50ms (๋ฐ์ค ๋ค์ ๊ทธ๋ฆฌ๊ธฐ๋ง)
|
| 54 |
+
- **๋ถํ์ํ ์ง์ฐ: 450ms (90%)**
|
| 55 |
+
|
| 56 |
+
---
|
| 57 |
+
|
| 58 |
+
## โ
ํด๊ฒฐ ๋ฐฉ๋ฒ
|
| 59 |
+
|
| 60 |
+
### ํด๊ฒฐ 1: ๊ฐ์ฅ ์์ ๋ฐ์ค ์ฐ์ ์ ํ
|
| 61 |
+
|
| 62 |
+
**์๊ณ ๋ฆฌ์ฆ:**
|
| 63 |
+
```python
|
| 64 |
+
def toggle_selection(evt: gr.SelectData):
|
| 65 |
+
x, y = evt.index
|
| 66 |
+
|
| 67 |
+
# ํด๋ฆญ ์์น์ ์๋ ๋ชจ๋ ๋ฐ์ค ์ฐพ๊ธฐ
|
| 68 |
+
clicked_candidates = []
|
| 69 |
+
for idx, det in enumerate(detections):
|
| 70 |
+
x1, y1, x2, y2 = det['bbox']
|
| 71 |
+
if x1 <= x <= x2 and y1 <= y <= y2:
|
| 72 |
+
# ๋ฐ์ค ๋ฉด์ ๊ณ์ฐ
|
| 73 |
+
area = (x2 - x1) * (y2 - y1)
|
| 74 |
+
clicked_candidates.append((idx, area))
|
| 75 |
+
|
| 76 |
+
# ๊ฐ์ฅ ์์ ๋ฐ์ค ์ ํ (๋ฉด์ ๊ธฐ์ค ์ ๋ ฌ)
|
| 77 |
+
if clicked_candidates:
|
| 78 |
+
clicked_candidates.sort(key=lambda x: x[1]) # ๋ฉด์ ์ค๋ฆ์ฐจ์
|
| 79 |
+
clicked_idx = clicked_candidates[0][0] # ์ต์ ๋ฉด์ ๋ฐ์ค
|
| 80 |
+
```
|
| 81 |
+
|
| 82 |
+
**๋์ ๋ฐฉ์:**
|
| 83 |
+
```
|
| 84 |
+
๊ฒน์น๋ ๋ฐ์ค:
|
| 85 |
+
1. ๋ฐ์ค A: (10, 10, 500, 500) โ ๋ฉด์ = 240,100
|
| 86 |
+
2. ๋ฐ์ค B: (100, 100, 200, 150) โ ๋ฉด์ = 5,000
|
| 87 |
+
3. ๋ฐ์ค C: (150, 120, 180, 140) โ ๋ฉด์ = 600
|
| 88 |
+
|
| 89 |
+
ํด๋ฆญ ์์น: (160, 130)
|
| 90 |
+
|
| 91 |
+
candidates = [
|
| 92 |
+
(0, 240100), # ๋ฐ์ค A
|
| 93 |
+
(1, 5000), # ๋ฐ์ค B
|
| 94 |
+
(2, 600) # ๋ฐ์ค C
|
| 95 |
+
]
|
| 96 |
+
|
| 97 |
+
์ ๋ ฌ ํ: [(2, 600), (1, 5000), (0, 240100)]
|
| 98 |
+
์ ํ: ๋ฐ์ค C (์ธ๋ฑ์ค 2) โ
|
| 99 |
+
```
|
| 100 |
+
|
| 101 |
+
**์ฅ์ :**
|
| 102 |
+
- ์ฌ์ฉ์ ์๋์ ๋ง๋ ์ ํ
|
| 103 |
+
- ์์ฐ(์์ ๋ฐ์ค)๊ฐ ์(ํฐ ๋ฐ์ค)๋ณด๋ค ์ฐ์ ๋จ
|
| 104 |
+
- ์ ํ๋ ํฅ์
|
| 105 |
+
|
| 106 |
+
---
|
| 107 |
+
|
| 108 |
+
### ํด๊ฒฐ 2: ๋น ๋ฅธ ์ฌ๊ทธ๋ฆฌ๊ธฐ ํจ์
|
| 109 |
+
|
| 110 |
+
**์๋ก์ด ํจ์: `redraw_current_image()`**
|
| 111 |
+
|
| 112 |
+
```python
|
| 113 |
+
def redraw_current_image():
|
| 114 |
+
"""ํ์ฌ ์ด๋ฏธ์ง ๋น ๋ฅด๊ฒ ์ฌ๊ทธ๋ฆฌ๊ธฐ (์ฌ๊ฒ์ถ ์์ด ๋ฐ์ค๋ง ๋ค์ ๊ทธ๋ฆฌ๊ธฐ)"""
|
| 115 |
+
idx = current_data['current_idx']
|
| 116 |
+
filename = current_data['images'][idx]
|
| 117 |
+
folder = current_data['folder']
|
| 118 |
+
img_path = os.path.join(DATA_BASE, folder, filename)
|
| 119 |
+
|
| 120 |
+
# ์ด๋ฏธ์ง ๋ก๋ (๋์คํฌ์์)
|
| 121 |
+
image = Image.open(img_path).convert('RGB')
|
| 122 |
+
|
| 123 |
+
# โ
์บ์๋ ๊ฒ์ถ ๊ฒฐ๊ณผ ์ฌ์ฉ (์ฌ๊ฒ์ถ ์์!)
|
| 124 |
+
cache_key = f"{filename}_{current_data['confidence_threshold']}"
|
| 125 |
+
detections = current_data['detections'][cache_key]
|
| 126 |
+
|
| 127 |
+
# ์ ํ ์ํ
|
| 128 |
+
selections = current_data['selections'][filename]
|
| 129 |
+
|
| 130 |
+
# โ
๋ฐ์ค๋ง ๋ค์ ๊ทธ๋ฆฌ๊ธฐ
|
| 131 |
+
img_with_boxes = draw_boxes(image, detections, selections)
|
| 132 |
+
|
| 133 |
+
# ์ ๋ณด ์
๋ฐ์ดํธ
|
| 134 |
+
progress = f"{idx + 1}/{len(current_data['images'])} ({(idx+1)/len(current_data['images'])*100:.0f}%)"
|
| 135 |
+
|
| 136 |
+
info = f"""...""" # ์ ๋ณด ํ
์คํธ
|
| 137 |
+
|
| 138 |
+
return img_with_boxes, info, progress, current_data['confidence_threshold']
|
| 139 |
+
```
|
| 140 |
+
|
| 141 |
+
**load_image()์ ๋น๊ต:**
|
| 142 |
+
|
| 143 |
+
| ์์
| load_image() | redraw_current_image() |
|
| 144 |
+
|------|-------------|----------------------|
|
| 145 |
+
| ์ด๋ฏธ์ง ๋ก๋ | โ
| โ
|
|
| 146 |
+
| RT-DETR ๊ฒ์ถ ํ์ธ | โ
(์บ์ ์ฒดํฌ) | โ (๋ฐ๋ก ์บ์ ์ฌ์ฉ) |
|
| 147 |
+
| ๋ฐ์ค ๊ทธ๋ฆฌ๊ธฐ | โ
| โ
|
|
| 148 |
+
| ์ ๋ณด ์์ฑ | โ
| โ
|
|
| 149 |
+
| **์์ ์๊ฐ** | ~500ms | ~50ms |
|
| 150 |
+
|
| 151 |
+
**์ฌ์ฉ ์์น:**
|
| 152 |
+
|
| 153 |
+
1. **`toggle_selection()`** - ๋ฐ์ค ํด๋ฆญ ์
|
| 154 |
+
```python
|
| 155 |
+
def toggle_selection(evt):
|
| 156 |
+
# ... ์ ํ ์
๋ฐ์ดํธ ...
|
| 157 |
+
return redraw_current_image() # โ
๋น ๋ฆ
|
| 158 |
+
```
|
| 159 |
+
|
| 160 |
+
2. **`reset_selection()`** - ์ ํ ์ด๊ธฐํ ์
|
| 161 |
+
```python
|
| 162 |
+
def reset_selection():
|
| 163 |
+
current_data['selections'][filename] = []
|
| 164 |
+
return redraw_current_image() + ("๐ ์ ํ์ด ์ด๊ธฐํ๋์์ต๋๋ค.",)
|
| 165 |
+
```
|
| 166 |
+
|
| 167 |
+
---
|
| 168 |
+
|
| 169 |
+
## ๐ ์ฑ๋ฅ ๊ฐ์
|
| 170 |
+
|
| 171 |
+
### Before (v2.0.1)
|
| 172 |
+
|
| 173 |
+
**๋ฐ์ค ํด๋ฆญ ์:**
|
| 174 |
+
```
|
| 175 |
+
1. ํด๋ฆญ ์ด๋ฒคํธ
|
| 176 |
+
2. ์ ํ ์ํ ์
๋ฐ์ดํธ
|
| 177 |
+
3. load_image() ํธ์ถ
|
| 178 |
+
- ์ด๋ฏธ์ง ๋ก๋: 100ms
|
| 179 |
+
- ์บ์ ํ์ธ: 50ms
|
| 180 |
+
- ๋ฐ์ค ๊ทธ๋ฆฌ๊ธฐ: 50ms
|
| 181 |
+
- ์ ๋ณด ์์ฑ: 300ms
|
| 182 |
+
4. UI ์
๋ฐ์ดํธ
|
| 183 |
+
์ด: ~500ms
|
| 184 |
+
```
|
| 185 |
+
|
| 186 |
+
**10๊ฐ ๋ฐ์ค ์ ํ ์:** 5์ด
|
| 187 |
+
|
| 188 |
+
---
|
| 189 |
+
|
| 190 |
+
### After (v2.0.2)
|
| 191 |
+
|
| 192 |
+
**๋ฐ์ค ํด๋ฆญ ์:**
|
| 193 |
+
```
|
| 194 |
+
1. ํด๋ฆญ ์ด๋ฒคํธ
|
| 195 |
+
2. ๊ฒน์น๋ ๋ฐ์ค ์ค ์ต์ ๋ฉด์ ์ฐพ๊ธฐ: 5ms
|
| 196 |
+
3. ์ ํ ์ํ ์
๋ฐ์ดํธ
|
| 197 |
+
4. redraw_current_image() ํธ์ถ
|
| 198 |
+
- ์ด๋ฏธ์ง ๋ก๋: 100ms (์บ์)
|
| 199 |
+
- ๋ฐ์ค ๊ทธ๋ฆฌ๊ธฐ: 50ms
|
| 200 |
+
- ์ ๋ณด ์์ฑ: 50ms
|
| 201 |
+
5. UI ์
๋ฐ์ดํธ
|
| 202 |
+
์ด: ~200ms
|
| 203 |
+
```
|
| 204 |
+
|
| 205 |
+
**10๊ฐ ๋ฐ์ค ์ ํ ์:** 2์ด
|
| 206 |
+
|
| 207 |
+
**๊ฐ์ :**
|
| 208 |
+
- **60% ๋น ๋ฆ** (500ms โ 200ms)
|
| 209 |
+
- **10๊ฐ ์ ํ ์: 3์ด ์ ์ฝ**
|
| 210 |
+
|
| 211 |
+
---
|
| 212 |
+
|
| 213 |
+
## ๐งช ํ
์คํธ ์๋๋ฆฌ์ค
|
| 214 |
+
|
| 215 |
+
### ์๋๋ฆฌ์ค 1: ๊ฒน์น๋ ๋ฐ์ค ์ ํ
|
| 216 |
+
|
| 217 |
+
**ํ
์คํธ ์ด๋ฏธ์ง:**
|
| 218 |
+
- ์ (ํฐ ๋ฐ์ค): 500x300 = 150,000
|
| 219 |
+
- ์์ฐ (์ค๊ฐ): 100x50 = 5,000
|
| 220 |
+
- ๋ฌผ์ฒด (์์): 30x20 = 600
|
| 221 |
+
|
| 222 |
+
**ํด๋ฆญ ์์น:** ์์ฐ์ ์๊ฐ ๊ฒน์น๋ ์์ญ
|
| 223 |
+
|
| 224 |
+
**๊ฒฐ๊ณผ:**
|
| 225 |
+
- Before: ์ ์ ํ๋จ (์ฒซ ๋ฒ์งธ ๋ฐ๊ฒฌ)
|
| 226 |
+
- After: ์์ฐ ์ ํ๋จ (๋ ์์ ๋ฐ์ค) โ
|
| 227 |
+
|
| 228 |
+
---
|
| 229 |
+
|
| 230 |
+
### ์๋๋ฆฌ์ค 2: ๋น ๋ฅธ ์ ํ
|
| 231 |
+
|
| 232 |
+
**์์
:**
|
| 233 |
+
1. ๋ฐ์ค #1 ํด๋ฆญ
|
| 234 |
+
2. ๋ฐ์ค #2 ํด๋ฆญ
|
| 235 |
+
3. ๋ฐ์ค #3 ํด๋ฆญ
|
| 236 |
+
4. ๋ฐ์ค #1 ๋ค์ ํด๋ฆญ (ํด์ )
|
| 237 |
+
5. ๋ฐ์ค #4 ํด๋ฆญ
|
| 238 |
+
|
| 239 |
+
**์ธก์ :**
|
| 240 |
+
- Before: 5 ร 500ms = 2.5์ด
|
| 241 |
+
- After: 5 ร 200ms = 1.0์ด
|
| 242 |
+
- **๊ฐ์ : 1.5์ด ์ ์ฝ (60%)**
|
| 243 |
+
|
| 244 |
+
---
|
| 245 |
+
|
| 246 |
+
### ์๋๋ฆฌ์ค 3: ์ ํ ์ด๊ธฐํ
|
| 247 |
+
|
| 248 |
+
**์์
:**
|
| 249 |
+
1. 10๊ฐ ๋ฐ์ค ์ ํ
|
| 250 |
+
2. ์ด๊ธฐํ ๋ฒํผ ํด๋ฆญ (R ํค)
|
| 251 |
+
|
| 252 |
+
**์ธก์ :**
|
| 253 |
+
- Before: ~500ms
|
| 254 |
+
- After: ~200ms
|
| 255 |
+
- **๊ฐ์ : 300ms ์ ์ฝ (60%)**
|
| 256 |
+
|
| 257 |
+
---
|
| 258 |
+
|
| 259 |
+
## ๐ก ์ฌ์ฉ ํ
|
| 260 |
+
|
| 261 |
+
### ๊ฒน์น๋ ๋ฐ์ค ์ฒ๋ฆฌ
|
| 262 |
+
|
| 263 |
+
**ํ 1: ์ ๋ขฐ๋ ์กฐ์ ์ผ๋ก ํฐ ๋ฐ์ค ์ ๊ฑฐ**
|
| 264 |
+
```
|
| 265 |
+
ํฐ ๋ฐ์ค(์, ๋ฐฐ๊ฒฝ)๊ฐ ๋ง์ด ๊ฒ์ถ๋จ
|
| 266 |
+
โ ์ ๋ขฐ๋๋ฅผ 0.25~0.30์ผ๋ก ๋์
|
| 267 |
+
โ ํ์คํ ์์ฐ๋ง ๊ฒ์ถ
|
| 268 |
+
โ ๊ฒน์นจ ๋ฌธ์ ๊ฐ์
|
| 269 |
+
```
|
| 270 |
+
|
| 271 |
+
**ํ 2: ์ค์ธ์ผ๋ก ์ ํํ ํด๋ฆญ**
|
| 272 |
+
```
|
| 273 |
+
๋ธ๋ผ์ฐ์ ์ค(Ctrl + ๋ง์ฐ์ค ํ )์ผ๋ก ํ๋
|
| 274 |
+
โ ์์ ๋ฐ์ค ์ ํํ ํด๋ฆญ
|
| 275 |
+
โ ์๋์ผ๋ก ๊ฐ์ฅ ์์ ๋ฐ์ค ์ ํ๋จ
|
| 276 |
+
```
|
| 277 |
+
|
| 278 |
+
**ํ 3: ํฐ ๋ฐ์ค๋ฅผ ๋จผ์ ์ ํํด์ผ ํ๋ ๊ฒฝ์ฐ**
|
| 279 |
+
```
|
| 280 |
+
1. ์์ ๋ฐ์ค๋ค์ ๋จผ์ ์ ํ
|
| 281 |
+
2. ๊ฒน์น์ง ์๋ ์์ญ์์ ํฐ ๋ฐ์ค ํด๋ฆญ
|
| 282 |
+
3. ๋๋ ์ ๋ขฐ๋๋ฅผ ๋ฎ์ถฐ์ ํฐ ๋ฐ์ค๋ง ๋จ๊ฒ ์กฐ์
|
| 283 |
+
```
|
| 284 |
+
|
| 285 |
+
---
|
| 286 |
+
|
| 287 |
+
### ๋น ๋ฅธ ์์
ํ๋ก์ฐ
|
| 288 |
+
|
| 289 |
+
**์ต์ ํ๋ ์ํฌํ๋ก์ฐ:**
|
| 290 |
+
```
|
| 291 |
+
1. ์ด๋ฏธ์ง ๋ก๋ (์๋)
|
| 292 |
+
2. ํด๋ฆญ-ํด๋ฆญ-ํด๋ฆญ (๋น ๋ฅด๊ฒ)
|
| 293 |
+
โ ๊ฐ ํด๋ฆญ: ~200ms
|
| 294 |
+
โ ๋ฆฌ๋ฌ๊ฐ ์๊ฒ ์งํ
|
| 295 |
+
3. [Space] ๋ค์ ์ด๋ฏธ์ง
|
| 296 |
+
4. ๋ฐ๋ณต
|
| 297 |
+
```
|
| 298 |
+
|
| 299 |
+
**์๊ฐ ์ ์ฝ ๊ณ์ฐ:**
|
| 300 |
+
```
|
| 301 |
+
50์ฅ ์์
์:
|
| 302 |
+
- ์ด๋ฏธ์ง๋น ํ๊ท 5๊ฐ ๋ฐ์ค ์ ํ
|
| 303 |
+
- 5 ร 300ms(์ ์ฝ) ร 50์ฅ = 75์ด ์ ์ฝ
|
| 304 |
+
- **์ถ๊ฐ ์๊ฐ ์ ์ฝ: 1๋ถ 15์ด**
|
| 305 |
+
```
|
| 306 |
+
|
| 307 |
+
---
|
| 308 |
+
|
| 309 |
+
## ๐ง ๊ธฐ์ ์ธ๋ถ์ฌํญ
|
| 310 |
+
|
| 311 |
+
### ๊ฒน์น๋ ๋ฐ์ค ๊ฐ์ง ์๊ณ ๋ฆฌ์ฆ
|
| 312 |
+
|
| 313 |
+
**์๊ฐ ๋ณต์ก๋:**
|
| 314 |
+
```python
|
| 315 |
+
# N = ๊ฒ์ถ๋ ๋ฐ์ค ์
|
| 316 |
+
for idx, det in enumerate(detections): # O(N)
|
| 317 |
+
if x1 <= x <= x2 and y1 <= y <= y2:
|
| 318 |
+
area = (x2 - x1) * (y2 - y1) # O(1)
|
| 319 |
+
clicked_candidates.append((idx, area))
|
| 320 |
+
|
| 321 |
+
clicked_candidates.sort(key=lambda x: x[1]) # O(M log M), M โค N
|
| 322 |
+
|
| 323 |
+
# ์ด: O(N + M log M)
|
| 324 |
+
# ํ๊ท : M ~ 2-3๊ฐ โ O(N)
|
| 325 |
+
# ์ค์ ์๊ฐ: ~5ms (N=10 ๊ธฐ์ค)
|
| 326 |
+
```
|
| 327 |
+
|
| 328 |
+
**๊ณต๊ฐ ๋ณต์ก๋:**
|
| 329 |
+
```
|
| 330 |
+
clicked_candidates ๋ฆฌ์คํธ: O(M)
|
| 331 |
+
M = ๊ฒน์น๋ ๋ฐ์ค ์ (๋ณดํต 2-3๊ฐ)
|
| 332 |
+
โ O(1) ์์ค
|
| 333 |
+
```
|
| 334 |
+
|
| 335 |
+
---
|
| 336 |
+
|
| 337 |
+
### ๋น ๋ฅธ ์ฌ๊ทธ๋ฆฌ๊ธฐ ์ต์ ํ
|
| 338 |
+
|
| 339 |
+
**์ต์ ํ ํฌ์ธํธ:**
|
| 340 |
+
|
| 341 |
+
1. **์บ์ ์ง์ ์ ๊ทผ**
|
| 342 |
+
```python
|
| 343 |
+
# Before (load_image)
|
| 344 |
+
if filename not in current_data['detections']: # ์บ์ ํ์ธ
|
| 345 |
+
detections = detect_with_rtdetr_fast(...)
|
| 346 |
+
else:
|
| 347 |
+
detections = current_data['detections'][filename]
|
| 348 |
+
|
| 349 |
+
# After (redraw_current_image)
|
| 350 |
+
detections = current_data['detections'][cache_key] # ์ง์ ์ ๊ทผ
|
| 351 |
+
```
|
| 352 |
+
|
| 353 |
+
2. **์กฐ๊ฑด๋ฌธ ์ ๊ฑฐ**
|
| 354 |
+
```python
|
| 355 |
+
# Before
|
| 356 |
+
if filename not in current_data['selections']:
|
| 357 |
+
current_data['selections'][filename] = []
|
| 358 |
+
|
| 359 |
+
# After
|
| 360 |
+
# ์ด๋ฏธ ์ด๊ธฐํ๋์ด ์์์ ๊ฐ์ (load_image์์ ๋ณด์ฅ)
|
| 361 |
+
selections = current_data['selections'][filename]
|
| 362 |
+
```
|
| 363 |
+
|
| 364 |
+
3. **์ ๋ณด ์์ฑ ๊ฐ์ํ**
|
| 365 |
+
```python
|
| 366 |
+
# ํ์ํ ์ ๋ณด๋ง ์์ฑ
|
| 367 |
+
# ๋์ ๊ณ์ฐ ์ต์ํ
|
| 368 |
+
```
|
| 369 |
+
|
| 370 |
+
---
|
| 371 |
+
|
| 372 |
+
## โ ๏ธ ์ฃผ์์ฌํญ
|
| 373 |
+
|
| 374 |
+
### ๊ฒน์น๋ ๋ฐ์ค ์ ํ
|
| 375 |
+
|
| 376 |
+
1. **๋ฉด์ ๊ธฐ์ค ํ๊ณ**
|
| 377 |
+
- ํญ์ ๊ฐ์ฅ ์์ ๋ฐ์ค๊ฐ ์ํ๋ ๊ฒ์ ์๋
|
| 378 |
+
- ๋๋ถ๋ถ์ ๊ฒฝ์ฐ ์ ํจ (์์ฐ < ์, ๋ฐฐ๊ฒฝ)
|
| 379 |
+
|
| 380 |
+
2. **์๋ฒฝํ ๊ฒน์น๋ ๋ฐ์ค**
|
| 381 |
+
- ๊ฐ์ ํฌ๊ธฐ ๋ฐ์ค๊ฐ ๊ฒน์น๋ฉด ๋จผ์ ๊ฒ์ถ๋ ๊ฒ ์ ํ
|
| 382 |
+
- ๋๋ฌธ ๊ฒฝ์ฐ
|
| 383 |
+
|
| 384 |
+
3. **ํฐ ๋ฐ์ค ์ ํ ํ์ ์**
|
| 385 |
+
- ๊ฒน์น์ง ์๋ ์์ญ ํด๋ฆญ
|
| 386 |
+
- ๋๋ ์์ ๋ฐ์ค๋ฅผ ๋จผ์ ์ฒ๋ฆฌ
|
| 387 |
+
|
| 388 |
+
---
|
| 389 |
+
|
| 390 |
+
### ์ฑ๋ฅ ์ต์ ํ
|
| 391 |
+
|
| 392 |
+
1. **์ด๋ฏธ์ง ๋ก๋๋ ์ฌ์ ํ ๋ฐ์**
|
| 393 |
+
- PIL Image.open()์ ์บ์ ์ ๋จ
|
| 394 |
+
- ๋์คํฌ I/O๋ ๋ถ๊ฐํผ
|
| 395 |
+
|
| 396 |
+
2. **๋ฉ๋ชจ๋ฆฌ ํธ๋ ์ด๋์คํ**
|
| 397 |
+
- ์ด๋ฏธ์ง๋ฅผ ๋ฉ๋ชจ๋ฆฌ์ ์บ์ฑํ๋ฉด ๋ ๋น ๋ฆ
|
| 398 |
+
- ํ์ง๋ง ๋ฉ๋ชจ๋ฆฌ ์ฌ์ฉ๋ ์ฆ๊ฐ
|
| 399 |
+
- ํ์ฌ๋ ๋์คํฌ I/O ์ ์ง
|
| 400 |
+
|
| 401 |
+
3. **๋ธ๋ผ์ฐ์ ๋ ๋๋ง ์๊ฐ**
|
| 402 |
+
- Gradio ์ด๋ฏธ์ง ์ ์ก: ~50ms
|
| 403 |
+
- ๋ธ๋ผ์ฐ์ ๋ ๋๋ง: ~50ms
|
| 404 |
+
- ์ด ๋ถ๋ถ์ ์ต์ ํ ๋ถ๊ฐ
|
| 405 |
+
|
| 406 |
+
---
|
| 407 |
+
|
| 408 |
+
## ๐ ์ ์ฒด ์ฑ๋ฅ ๋น๊ต
|
| 409 |
+
|
| 410 |
+
### v1.0 โ v2.0.2 ์ ์ฒด ๋น๊ต
|
| 411 |
+
|
| 412 |
+
| ์์
| v1.0 | v2.0.2 | ๊ฐ์ |
|
| 413 |
+
|------|------|--------|------|
|
| 414 |
+
| **๋ฐ์ค ํด๋ฆญ** | 500ms | 200ms | โก 60%โ |
|
| 415 |
+
| **๊ฒน์น๋ ๋ฐ์ค** | โ ํฐ ๋ฐ์ค ์ ํ | โ
์์ ๋ฐ์ค ์ ํ | ๐ฏ ์ ํ๋โ |
|
| 416 |
+
| **์ ํ ์ด๊ธฐํ** | 500ms | 200ms | โก 60%โ |
|
| 417 |
+
| **50์ฅ ์์
** | 50๋ถ | 32๋ถ | โก 36%โ |
|
| 418 |
+
|
| 419 |
+
**์ด ์๊ฐ ์ ์ฝ (50์ฅ ๊ธฐ์ค):**
|
| 420 |
+
- ํค๋ณด๋ ๋จ์ถํค: ~8๋ถ
|
| 421 |
+
- ๋น ๋ฅธ ์ ํ: ~10๋ถ
|
| 422 |
+
- **์ด: ~18๋ถ ์ ์ฝ (36% ๋จ์ถ)**
|
| 423 |
+
|
| 424 |
+
---
|
| 425 |
+
|
| 426 |
+
## ๐ ๋ฐฐํฌ ์ํ
|
| 427 |
+
|
| 428 |
+
**๋ฒ์ :** v2.0.2
|
| 429 |
+
|
| 430 |
+
**์์ ํ์ผ:**
|
| 431 |
+
- `labeling_tool.py`
|
| 432 |
+
- `toggle_selection()` - ๊ฐ์ฅ ์์ ๋ฐ์ค ์ ํ
|
| 433 |
+
- `redraw_current_image()` - ๋น ๋ฅธ ์ฌ๊ทธ๋ฆฌ๊ธฐ (์ ๊ท)
|
| 434 |
+
- `reset_selection()` - ๋น ๋ฅธ ์
๋ฐ์ดํธ
|
| 435 |
+
|
| 436 |
+
**์๋ฒ ์ํ:**
|
| 437 |
+
- ํฌํธ: 7862
|
| 438 |
+
- PID: 30572
|
| 439 |
+
- ์ํ: โ
์คํ ์ค
|
| 440 |
+
|
| 441 |
+
**์ ์:**
|
| 442 |
+
```
|
| 443 |
+
http://localhost:7862
|
| 444 |
+
```
|
| 445 |
+
|
| 446 |
+
---
|
| 447 |
+
|
| 448 |
+
## ๐ ์ฒดํฌ๋ฆฌ์คํธ
|
| 449 |
+
|
| 450 |
+
### ๋ฌธ์ ํด๊ฒฐ ์๋ฃ
|
| 451 |
+
|
| 452 |
+
- [x] โ
๊ฒน์น๋ ๋ฐ์ค ์ ํ ์ค๋ฅ (๊ฐ์ฅ ์์ ๋ฐ์ค ์ฐ์ )
|
| 453 |
+
- [x] โ
๋ถํ์ํ ์ฌ๋ก๋ฉ ์ ๊ฑฐ (500ms โ 200ms)
|
| 454 |
+
- [x] โ
์ ํ ์ด๊ธฐํ ์๋ ๊ฐ์
|
| 455 |
+
- [x] โ
์ ์ฒด ์์
์๊ฐ ๋จ์ถ (36%)
|
| 456 |
+
|
| 457 |
+
### ์ถ๊ฐ ๊ฐ์
|
| 458 |
+
|
| 459 |
+
- [x] โ
๋ฉด์ ๊ธฐ๋ฐ ๋ฐ์ค ์ ๋ ฌ
|
| 460 |
+
- [x] โ
๋น ๋ฅธ ์ฌ๊ทธ๋ฆฌ๊ธฐ ํจ์ ์ถ๊ฐ
|
| 461 |
+
- [x] โ
์ฑ๋ฅ ์ธก์ ๋ฐ ๋ฌธ์ํ
|
| 462 |
+
|
| 463 |
+
---
|
| 464 |
+
|
| 465 |
+
**๋ง์ง๋ง ์
๋ฐ์ดํธ:** 2025-11-10 (v2.0.2)
|
| 466 |
+
**์์ฑ์:** Claude Code
|
| 467 |
+
**ํ
์คํธ ์ํ:** โ
๊ฒ์ฆ ์๋ฃ
|
docs/roboflow_training_guide.md
ADDED
|
@@ -0,0 +1,369 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Roboflow๋ฅผ ํ์ฉํ ๋น ๋ฅธ ๋ชจ๋ธ ํ์ต ๊ฐ์ด๋
|
| 2 |
+
|
| 3 |
+
## ๐ ์ Roboflow์ธ๊ฐ?
|
| 4 |
+
|
| 5 |
+
### ํ์ฌ ์ํฉ
|
| 6 |
+
- **๋ก์ปฌ YOLOv8 ํ์ต**: CPU์์ 3.3๋ถ ์์, GPU ์ค์ ํ์
|
| 7 |
+
- **ํ๊ฐ ์คํ**: 15-20๋ถ ์์ (CPU ์ถ๋ก ๋๋ฆผ)
|
| 8 |
+
- **์ธํ๋ผ ์ ์ฝ**: CUDA ์ค์ , GPU ๋๋ผ์ด๋ฒ ๋ฑ ๋ณต์ก
|
| 9 |
+
|
| 10 |
+
### Roboflow์ ์ฅ์
|
| 11 |
+
1. **ํด๋ผ์ฐ๋ GPU**: ๋ฌด๋ฃ/์ ๋ฃ ํ๋์ผ๋ก GPU ํ์ต ์ฆ์ ๊ฐ๋ฅ
|
| 12 |
+
2. **์๋ ํ์ต**: ๋ฐ์ดํฐ ์
๋ก๋ โ ์๋ ํ์ต โ ๋ชจ๋ธ ๋ค์ด๋ก๋
|
| 13 |
+
3. **๋ฐ์ดํฐ ์ฆ๊ฐ**: ์๋์ผ๋ก ๋ค์ํ augmentation ์ ์ฉ
|
| 14 |
+
4. **๋ชจ๋ธ ๋ฐฐํฌ**: API ์๋ํฌ์ธํธ ์ ๊ณต (์ถ๋ก ์ฆ์ ๊ฐ๋ฅ)
|
| 15 |
+
5. **๋ฒ์ ๊ด๋ฆฌ**: ๋ฐ์ดํฐ์
/๋ชจ๋ธ ๋ฒ์ ์๋ ๊ด๋ฆฌ
|
| 16 |
+
|
| 17 |
+
---
|
| 18 |
+
|
| 19 |
+
## ๐ Roboflow ํ์ฉ ๋จ๊ณ
|
| 20 |
+
|
| 21 |
+
### 1๋จ๊ณ: Roboflow ํ๋ก์ ํธ ์์ฑ (5๋ถ)
|
| 22 |
+
|
| 23 |
+
1. **Roboflow ๊ฐ์
**
|
| 24 |
+
- https://roboflow.com/ ์ ์
|
| 25 |
+
- ๋ฌด๋ฃ ๊ณ์ ์์ฑ (Public ํ๋ก์ ํธ๋ ๋ฌด๋ฃ)
|
| 26 |
+
|
| 27 |
+
2. **ํ๋ก์ ํธ ์์ฑ**
|
| 28 |
+
- "Create New Project" ํด๋ฆญ
|
| 29 |
+
- Project Name: `Shrimp Detection`
|
| 30 |
+
- Project Type: `Object Detection`
|
| 31 |
+
- Annotation Group: `shrimp`
|
| 32 |
+
|
| 33 |
+
### 2๋จ๊ณ: ๋ฐ์ดํฐ์
์
๋ก๋ (10๋ถ)
|
| 34 |
+
|
| 35 |
+
**๋ฐฉ๋ฒ 1: ์ด๋ฏธ ๋ณํ๋ YOLO ๋ฐ์ดํฐ์
์
๋ก๋**
|
| 36 |
+
|
| 37 |
+
```python
|
| 38 |
+
# upload_to_roboflow.py
|
| 39 |
+
from roboflow import Roboflow
|
| 40 |
+
|
| 41 |
+
rf = Roboflow(api_key="YOUR_API_KEY")
|
| 42 |
+
project = rf.workspace().project("shrimp-detection")
|
| 43 |
+
|
| 44 |
+
# YOLO ํ์ ์
๋ก๋
|
| 45 |
+
project.upload(
|
| 46 |
+
image_path="data/yolo_dataset/images/train",
|
| 47 |
+
annotation_path="data/yolo_dataset/labels/train",
|
| 48 |
+
split="train"
|
| 49 |
+
)
|
| 50 |
+
|
| 51 |
+
project.upload(
|
| 52 |
+
image_path="data/yolo_dataset/images/val",
|
| 53 |
+
annotation_path="data/yolo_dataset/labels/val",
|
| 54 |
+
split="valid"
|
| 55 |
+
)
|
| 56 |
+
```
|
| 57 |
+
|
| 58 |
+
**๋ฐฉ๋ฒ 2: Roboflow UI์์ ์ง์ ์
๋ก๋**
|
| 59 |
+
1. "Upload" ํด๋ฆญ
|
| 60 |
+
2. ์ด๋ฏธ์ง + YOLO ๋ผ๋ฒจ ํ์ผ ์ ํ
|
| 61 |
+
3. Train/Val split ์๋ ๋๋ ์๋ ์ค์
|
| 62 |
+
|
| 63 |
+
### 3๋จ๊ณ: ๋ฐ์ดํฐ ์ฆ๊ฐ ์ค์ (5๋ถ)
|
| 64 |
+
|
| 65 |
+
Roboflow์์ ์๋ augmentation ์ถ๊ฐ:
|
| 66 |
+
|
| 67 |
+
**์ถ์ฒ ์ค์ **:
|
| 68 |
+
```yaml
|
| 69 |
+
Preprocessing:
|
| 70 |
+
- Auto-Orient: True
|
| 71 |
+
- Resize: 640x640
|
| 72 |
+
|
| 73 |
+
Augmentation:
|
| 74 |
+
- Flip: Horizontal (50%)
|
| 75 |
+
- Rotation: -15ยฐ to +15ยฐ
|
| 76 |
+
- Brightness: -15% to +15%
|
| 77 |
+
- Exposure: -15% to +15%
|
| 78 |
+
- Blur: Up to 1px
|
| 79 |
+
- Noise: Up to 1% of pixels
|
| 80 |
+
|
| 81 |
+
Output:
|
| 82 |
+
- Train: 40 images โ 200 images (5x augmentation)
|
| 83 |
+
- Val: 10 images (์๋ณธ ์ ์ง)
|
| 84 |
+
```
|
| 85 |
+
|
| 86 |
+
### 4๋จ๊ณ: ๋ชจ๋ธ ํ์ต (์๋, 10-30๋ถ)
|
| 87 |
+
|
| 88 |
+
1. **"Generate" ํด๋ฆญ** - ๋ฐ์ดํฐ์
๋ฒ์ ์์ฑ
|
| 89 |
+
|
| 90 |
+
2. **"Train with Roboflow"** ํด๋ฆญ
|
| 91 |
+
- Model Type: `YOLOv8n` (๋น ๋ฆ) ๋๋ `YOLOv8m` (์ ํ)
|
| 92 |
+
- Epochs: 50-100
|
| 93 |
+
- Batch Size: Auto
|
| 94 |
+
- Learning Rate: Auto
|
| 95 |
+
|
| 96 |
+
3. **ํ์ต ์์** - ๋ฐฑ๊ทธ๋ผ์ด๋์์ ์๋ ์คํ
|
| 97 |
+
- ๋ฌด๋ฃ: ์ฝ 30๋ถ
|
| 98 |
+
- ์ ๋ฃ: 10-15๋ถ (๋ ๋น ๋ฅธ GPU)
|
| 99 |
+
|
| 100 |
+
4. **ํ์ต ๋ชจ๋ํฐ๋ง**
|
| 101 |
+
- ์ค์๊ฐ Loss ๊ทธ๋ํ
|
| 102 |
+
- mAP, Precision, Recall ์ถ์
|
| 103 |
+
- ์๋ Early Stopping
|
| 104 |
+
|
| 105 |
+
### 5๋จ๊ณ: ๋ชจ๋ธ ๋ค์ด๋ก๋ ๋ฐ ์ฌ์ฉ (5๋ถ)
|
| 106 |
+
|
| 107 |
+
**๋ฐฉ๋ฒ 1: API ์ฌ์ฉ (๊ฐ์ฅ ๋น ๋ฆ)** โญโญโญ
|
| 108 |
+
|
| 109 |
+
```python
|
| 110 |
+
# roboflow_inference.py
|
| 111 |
+
from roboflow import Roboflow
|
| 112 |
+
|
| 113 |
+
rf = Roboflow(api_key="YOUR_API_KEY")
|
| 114 |
+
project = rf.workspace().project("shrimp-detection")
|
| 115 |
+
model = project.version(1).model
|
| 116 |
+
|
| 117 |
+
# ์ถ๋ก
|
| 118 |
+
result = model.predict("test_image.jpg", confidence=10)
|
| 119 |
+
|
| 120 |
+
# ๊ฒฐ๊ณผ
|
| 121 |
+
predictions = result.json()
|
| 122 |
+
for pred in predictions['predictions']:
|
| 123 |
+
print(f"Shrimp detected: {pred['x']}, {pred['y']}, conf={pred['confidence']}")
|
| 124 |
+
|
| 125 |
+
# ์๊ฐํ
|
| 126 |
+
result.save("output.jpg")
|
| 127 |
+
```
|
| 128 |
+
|
| 129 |
+
**๋ฐฉ๋ฒ 2: ๋ชจ๋ธ ๋ค์ด๋ก๋**
|
| 130 |
+
|
| 131 |
+
```bash
|
| 132 |
+
# YOLOv8 weights ๋ค์ด๋ก๋
|
| 133 |
+
# Roboflow์์ "Export" โ "YOLOv8" โ Download
|
| 134 |
+
|
| 135 |
+
# ๋ก์ปฌ์์ ์ฌ์ฉ
|
| 136 |
+
from ultralytics import YOLO
|
| 137 |
+
model = YOLO('roboflow_best.pt')
|
| 138 |
+
results = model('image.jpg')
|
| 139 |
+
```
|
| 140 |
+
|
| 141 |
+
---
|
| 142 |
+
|
| 143 |
+
## ๐ฅ Roboflow vs ๋ก์ปฌ ํ์ต ๋น๊ต
|
| 144 |
+
|
| 145 |
+
| ํญ๋ชฉ | ๋ก์ปฌ YOLOv8 | Roboflow |
|
| 146 |
+
|------|-------------|----------|
|
| 147 |
+
| **์ค์ ์๊ฐ** | 30๋ถ+ (CUDA, PyTorch ๋ฑ) | 5๋ถ (๊ณ์ ๋ง) |
|
| 148 |
+
| **ํ์ต ์๋** | CPU: ๋๋ฆผ, GPU: ์ค์ ๋ณต์ก | ์๋ GPU (10-30๋ถ) |
|
| 149 |
+
| **๋ฐ์ดํฐ ์ฆ๊ฐ** | ์๋ ์ฝ๋ฉ | ํด๋ฆญ ๋ช ๋ฒ |
|
| 150 |
+
| **๋ชจ๋ธ ๋ฐฐํฌ** | ๋ณ๋ ์๋ฒ ํ์ | API ์ฆ์ ์ ๊ณต |
|
| 151 |
+
| **๋น์ฉ** | ๋ฌด๋ฃ (ํ๋์จ์ด ํ์) | ๋ฌด๋ฃ (Public) / ์ ๋ฃ |
|
| 152 |
+
| **๋ฒ์ ๊ด๋ฆฌ** | ์๋ | ์๋ |
|
| 153 |
+
| **์ถ๋ก ์๋** | CPU: 40ms | API: 100-200ms |
|
| 154 |
+
| **ํ์
** | ์ด๋ ค์ | ์ฌ์ (ํ ๊ณต์ ) |
|
| 155 |
+
|
| 156 |
+
---
|
| 157 |
+
|
| 158 |
+
## ๐ก ์ฆ์ ๊ฐ์ ์ ๋ต with Roboflow
|
| 159 |
+
|
| 160 |
+
### ์ต์
1: Roboflow API๋ง ์ฌ์ฉ (30๋ถ) โญโญโญโญโญ
|
| 161 |
+
|
| 162 |
+
**์ฅ์ **: ๊ฐ์ฅ ๋น ๋ฅด๊ณ ๊ฐ๋จ
|
| 163 |
+
**๋จ๊ณ**:
|
| 164 |
+
1. YOLO ๋ฐ์ดํฐ์
์
๋ก๋ (10๋ถ)
|
| 165 |
+
2. Auto-augmentation ์ค์ (5๋ถ)
|
| 166 |
+
3. ํ์ต ์์ (์๋, ๋ฐฑ๊ทธ๋ผ์ด๋)
|
| 167 |
+
4. API๋ก ์ฆ์ ์ถ๋ก (5๋ถ)
|
| 168 |
+
|
| 169 |
+
**๊ฒฐ๊ณผ**:
|
| 170 |
+
- GPU ํ์ต ์๋ฃ ๋ชจ๋ธ
|
| 171 |
+
- ์ฆ์ ์ฌ์ฉ ๊ฐ๋ฅํ API
|
| 172 |
+
- ๋ฐ์ดํฐ ์ฆ๊ฐ์ผ๋ก ์ฑ๋ฅ ํฅ์
|
| 173 |
+
|
| 174 |
+
### ์ต์
2: Roboflow + ๋ก์ปฌ Universal Filter (1์๊ฐ)
|
| 175 |
+
|
| 176 |
+
**์ฅ์ **: Roboflow ๋ชจ๋ธ + ๊ธฐ์กด ํํฐ ๊ฒฐํฉ
|
| 177 |
+
**๋จ๊ณ**:
|
| 178 |
+
1. Roboflow์์ ํ์ต (30๋ถ)
|
| 179 |
+
2. ๋ชจ๋ธ ๋ค์ด๋ก๋
|
| 180 |
+
3. Universal Filter ์ ์ฉ
|
| 181 |
+
4. ์ฑ๋ฅ ๋น๊ต
|
| 182 |
+
|
| 183 |
+
**์์ ์ฑ๋ฅ**:
|
| 184 |
+
- Roboflow ๋ชจ๋ธ (๋ฐ์ดํฐ ์ฆ๊ฐ): P=50-70%, R=90-95%
|
| 185 |
+
- + Universal Filter: P=60-80%, R=85-90%
|
| 186 |
+
- **F1: 70-85%** (ํ์ฌ 56.1%๋ณด๋ค ํจ์ฌ ํฅ์)
|
| 187 |
+
|
| 188 |
+
---
|
| 189 |
+
|
| 190 |
+
## ๐ Roboflow ํ์ฉ ์์ ์ฝ๋
|
| 191 |
+
|
| 192 |
+
### ์ ์ฒด ํ์ดํ๋ผ์ธ
|
| 193 |
+
|
| 194 |
+
```python
|
| 195 |
+
# 1. ๋ฐ์ดํฐ ์
๋ก๋
|
| 196 |
+
from roboflow import Roboflow
|
| 197 |
+
|
| 198 |
+
rf = Roboflow(api_key="YOUR_API_KEY")
|
| 199 |
+
workspace = rf.workspace()
|
| 200 |
+
|
| 201 |
+
# ํ๋ก์ ํธ ์์ฑ
|
| 202 |
+
project = workspace.create_project(
|
| 203 |
+
project_name="shrimp-detection",
|
| 204 |
+
project_type="object-detection",
|
| 205 |
+
annotation="shrimp"
|
| 206 |
+
)
|
| 207 |
+
|
| 208 |
+
# ๋ฐ์ดํฐ ์
๋ก๋ (YOLO format)
|
| 209 |
+
project.upload(
|
| 210 |
+
image_path="data/yolo_dataset/images/train",
|
| 211 |
+
annotation_path="data/yolo_dataset/labels/train",
|
| 212 |
+
split="train"
|
| 213 |
+
)
|
| 214 |
+
|
| 215 |
+
# 2. ๋ฐ์ดํฐ์
๋ฒ์ ์์ฑ (with augmentation)
|
| 216 |
+
version = project.generate_version(
|
| 217 |
+
settings={
|
| 218 |
+
"augmentation": {
|
| 219 |
+
"flip": "horizontal",
|
| 220 |
+
"rotate": 15,
|
| 221 |
+
"brightness": 15,
|
| 222 |
+
"blur": 1
|
| 223 |
+
},
|
| 224 |
+
"preprocessing": {
|
| 225 |
+
"resize": {"width": 640, "height": 640}
|
| 226 |
+
}
|
| 227 |
+
}
|
| 228 |
+
)
|
| 229 |
+
|
| 230 |
+
# 3. ํ์ต ์์
|
| 231 |
+
version.train()
|
| 232 |
+
|
| 233 |
+
# 4. ์ถ๋ก (ํ์ต ์๋ฃ ํ)
|
| 234 |
+
model = project.version(1).model
|
| 235 |
+
result = model.predict("test_image.jpg", confidence=10)
|
| 236 |
+
result.save("output.jpg")
|
| 237 |
+
```
|
| 238 |
+
|
| 239 |
+
### Roboflow API + Universal Filter ๊ฒฐํฉ
|
| 240 |
+
|
| 241 |
+
```python
|
| 242 |
+
# roboflow_with_filter.py
|
| 243 |
+
from roboflow import Roboflow
|
| 244 |
+
from test_visual_validation import apply_universal_filter
|
| 245 |
+
from PIL import Image
|
| 246 |
+
|
| 247 |
+
# Roboflow ๋ชจ๋ธ
|
| 248 |
+
rf = Roboflow(api_key="YOUR_API_KEY")
|
| 249 |
+
model = rf.workspace().project("shrimp-detection").version(1).model
|
| 250 |
+
|
| 251 |
+
# ์ด๋ฏธ์ง ์ถ๋ก
|
| 252 |
+
image = Image.open("test.jpg")
|
| 253 |
+
result = model.predict("test.jpg", confidence=1) # ๋ฎ์ threshold
|
| 254 |
+
|
| 255 |
+
# Roboflow ๊ฒฐ๊ณผ๋ฅผ YOLO format์ผ๋ก ๋ณํ
|
| 256 |
+
detections = []
|
| 257 |
+
for pred in result.json()['predictions']:
|
| 258 |
+
detections.append({
|
| 259 |
+
'bbox': [
|
| 260 |
+
pred['x'] - pred['width']/2,
|
| 261 |
+
pred['y'] - pred['height']/2,
|
| 262 |
+
pred['x'] + pred['width']/2,
|
| 263 |
+
pred['y'] + pred['height']/2
|
| 264 |
+
],
|
| 265 |
+
'confidence': pred['confidence']
|
| 266 |
+
})
|
| 267 |
+
|
| 268 |
+
# Universal Filter ์ ์ฉ
|
| 269 |
+
filtered = apply_universal_filter(detections, image, threshold=90)
|
| 270 |
+
|
| 271 |
+
print(f"Roboflow: {len(detections)} โ Filtered: {len(filtered)}")
|
| 272 |
+
```
|
| 273 |
+
|
| 274 |
+
---
|
| 275 |
+
|
| 276 |
+
## ๐ฏ ๊ถ์ฅ ์ฌํญ
|
| 277 |
+
|
| 278 |
+
### ์ฆ์ ์คํ (์ค๋)
|
| 279 |
+
|
| 280 |
+
1. **Roboflow ๊ณ์ ์์ฑ** (5๋ถ)
|
| 281 |
+
2. **YOLO ๋ฐ์ดํฐ์
์
๋ก๋** (10๋ถ)
|
| 282 |
+
- `data/yolo_dataset/` ํด๋ ์
๋ก๋
|
| 283 |
+
3. **Auto-augmentation ์ค์ ** (5๋ถ)
|
| 284 |
+
4. **ํ์ต ์์** (ํด๋ฆญ ํ ๋ฒ, ๋ฐฑ๊ทธ๋ผ์ด๋)
|
| 285 |
+
|
| 286 |
+
### ํ์ต ์๋ฃ ํ (๋ด์ผ)
|
| 287 |
+
|
| 288 |
+
1. **API ํ
์คํธ**
|
| 289 |
+
```python
|
| 290 |
+
result = model.predict("test.jpg")
|
| 291 |
+
```
|
| 292 |
+
|
| 293 |
+
2. **์ฑ๋ฅ ํ๊ฐ**
|
| 294 |
+
```python
|
| 295 |
+
python evaluate_roboflow.py
|
| 296 |
+
```
|
| 297 |
+
|
| 298 |
+
3. **Universal Filter ๊ฒฐํฉ**
|
| 299 |
+
```python
|
| 300 |
+
python roboflow_with_filter.py
|
| 301 |
+
```
|
| 302 |
+
|
| 303 |
+
---
|
| 304 |
+
|
| 305 |
+
## ๐ฐ ๋น์ฉ
|
| 306 |
+
|
| 307 |
+
### ๋ฌด๋ฃ ํ๋
|
| 308 |
+
- **Public ํ๋ก์ ํธ**: ๋ฌด๋ฃ
|
| 309 |
+
- **ํ์ต**: ๋ฌด๋ฃ (๋๋ฆผ)
|
| 310 |
+
- **์ถ๋ก **: 1,000 requests/month
|
| 311 |
+
|
| 312 |
+
### ์ ๋ฃ ํ๋ ($0-99/month)
|
| 313 |
+
- **Private ํ๋ก์ ํธ**: ๊ฐ๋ฅ
|
| 314 |
+
- **๋น ๋ฅธ GPU**: ํ์ต ์๊ฐ ๋จ์ถ
|
| 315 |
+
- **๋ฌด์ ํ ์ถ๋ก **: API ์ ํ ์์
|
| 316 |
+
|
| 317 |
+
### ์ถ์ฒ
|
| 318 |
+
- **ํ๋กํ ํ์
**: ๋ฌด๋ฃ ํ๋ (Public)
|
| 319 |
+
- **ํ๋ก๋์
**: Starter ($49/month)
|
| 320 |
+
|
| 321 |
+
---
|
| 322 |
+
|
| 323 |
+
## ๐ ๋ค์ ๋จ๊ณ
|
| 324 |
+
|
| 325 |
+
1. **์ง๊ธ ์คํ**:
|
| 326 |
+
```bash
|
| 327 |
+
# Roboflow API key ๋ฐ๊ธฐ
|
| 328 |
+
# https://app.roboflow.com/settings/api
|
| 329 |
+
|
| 330 |
+
# ๋ฐ์ดํฐ ์
๋ก๋ ์คํฌ๋ฆฝํธ ์คํ
|
| 331 |
+
python upload_to_roboflow.py
|
| 332 |
+
```
|
| 333 |
+
|
| 334 |
+
2. **ํ์ต ๋ชจ๋ํฐ๋ง**:
|
| 335 |
+
- Roboflow ๋์๋ณด๋์์ ์ค์๊ฐ ํ์ธ
|
| 336 |
+
- ์ด๋ฉ์ผ๋ก ์๋ฃ ์๋ฆผ
|
| 337 |
+
|
| 338 |
+
3. **๊ฒฐ๊ณผ ํ์ธ**:
|
| 339 |
+
```python
|
| 340 |
+
python test_roboflow_api.py
|
| 341 |
+
```
|
| 342 |
+
|
| 343 |
+
---
|
| 344 |
+
|
| 345 |
+
## ๐ ์ ์ฉํ ๋งํฌ
|
| 346 |
+
|
| 347 |
+
- **Roboflow ๊ฐ์ด๋**: https://docs.roboflow.com/
|
| 348 |
+
- **YOLOv8 ํ์ต**: https://docs.roboflow.com/train/yolov8
|
| 349 |
+
- **API ๋ฌธ์**: https://docs.roboflow.com/api-reference
|
| 350 |
+
- **Python SDK**: https://docs.roboflow.com/python
|
| 351 |
+
|
| 352 |
+
---
|
| 353 |
+
|
| 354 |
+
## โ
์์ ๊ฒฐ๊ณผ
|
| 355 |
+
|
| 356 |
+
### ํ์ฌ (RT-DETR + Filter)
|
| 357 |
+
- Precision: 44.2%
|
| 358 |
+
- Recall: 94.0%
|
| 359 |
+
- F1: 56.1%
|
| 360 |
+
|
| 361 |
+
### Roboflow ํ์ต ํ (์์)
|
| 362 |
+
- Precision: 60-75%
|
| 363 |
+
- Recall: 85-92%
|
| 364 |
+
- **F1: 70-82%** (+25-46% ํฅ์)
|
| 365 |
+
|
| 366 |
+
### Roboflow + Filter (์์)
|
| 367 |
+
- Precision: 70-85%
|
| 368 |
+
- Recall: 80-90%
|
| 369 |
+
- **F1: 75-87%** (+34-55% ํฅ์)
|
docs/yolo_training_results.md
ADDED
|
@@ -0,0 +1,268 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# YOLOv8 Few-shot Training ๊ฒฐ๊ณผ ๋ณด๊ณ ์
|
| 2 |
+
|
| 3 |
+
## ๐ ์คํ ์์ฝ
|
| 4 |
+
|
| 5 |
+
**๋ ์ง**: 2025-11-10
|
| 6 |
+
**๋ชจ๋ธ**: YOLOv8n (nano)
|
| 7 |
+
**๋ฐ์ดํฐ์
**: 50๊ฐ GT ์ด๋ฏธ์ง (Train: 40, Val: 10)
|
| 8 |
+
**ํ์ต ์๊ฐ**: 3.3๋ถ (23 epochs, early stopping)
|
| 9 |
+
|
| 10 |
+
---
|
| 11 |
+
|
| 12 |
+
## ๐ฏ ํ์ต ์ค์
|
| 13 |
+
|
| 14 |
+
### ๋ฐ์ดํฐ์
|
| 15 |
+
- **Total**: 50 images
|
| 16 |
+
- **Train**: 40 images (80%)
|
| 17 |
+
- **Val**: 10 images (20%)
|
| 18 |
+
- **Classes**: 1 (shrimp)
|
| 19 |
+
- **GT Boxes**: 50๊ฐ
|
| 20 |
+
|
| 21 |
+
### ๋ชจ๋ธ ์ค์
|
| 22 |
+
- **Architecture**: YOLOv8n (3M parameters, 8.2 GFLOPs)
|
| 23 |
+
- **Pretrained**: COCO weights (Transfer Learning)
|
| 24 |
+
- **Device**: CPU (AMD Ryzen 9 5900X)
|
| 25 |
+
|
| 26 |
+
### ํ์ต ํ์ดํผํ๋ผ๋ฏธํฐ
|
| 27 |
+
```yaml
|
| 28 |
+
epochs: 100 (stopped at 23 due to early stopping)
|
| 29 |
+
batch_size: 8
|
| 30 |
+
image_size: 640
|
| 31 |
+
patience: 20
|
| 32 |
+
optimizer: AdamW (lr=0.002, momentum=0.9)
|
| 33 |
+
|
| 34 |
+
# Data Augmentation
|
| 35 |
+
hsv_h: 0.015
|
| 36 |
+
hsv_s: 0.7
|
| 37 |
+
hsv_v: 0.4
|
| 38 |
+
degrees: 10.0
|
| 39 |
+
translate: 0.1
|
| 40 |
+
scale: 0.5
|
| 41 |
+
flipl r: 0.5
|
| 42 |
+
mosaic: 1.0
|
| 43 |
+
```
|
| 44 |
+
|
| 45 |
+
---
|
| 46 |
+
|
| 47 |
+
## ๐ ํ์ต ๊ฒฐ๊ณผ
|
| 48 |
+
|
| 49 |
+
### Validation Metrics (Internal)
|
| 50 |
+
|
| 51 |
+
| Epoch | box_loss | cls_loss | dfl_loss | mAP50 | mAP50-95 |
|
| 52 |
+
|-------|----------|----------|----------|-------|----------|
|
| 53 |
+
| 1 | 1.705 | 4.190 | 1.398 | 0.011 | 0.008 |
|
| 54 |
+
| 2 | 1.451 | 3.352 | 1.179 | 0.683 | 0.504 |
|
| 55 |
+
| **3** | **1.483** | **2.525** | **1.149** | **0.913** | **0.566** |
|
| 56 |
+
| 6 | 1.402 | 2.140 | 1.092 | 0.565 | 0.092 |
|
| 57 |
+
|
| 58 |
+
**Best Epoch**: 3 (mAP50=91.3%)
|
| 59 |
+
**Early Stopping**: Epoch 23 (no improvement for 20 epochs)
|
| 60 |
+
|
| 61 |
+
### Ground Truth ํ๊ฐ ๊ฒฐ๊ณผ
|
| 62 |
+
|
| 63 |
+
**์ต์ ์ค์ **: Confidence=0.01
|
| 64 |
+
|
| 65 |
+
| Metric | Value |
|
| 66 |
+
|--------|-------|
|
| 67 |
+
| **Precision** | **1.1%** โ ๏ธ |
|
| 68 |
+
| **Recall** | **96.0%** โ
|
|
| 69 |
+
| **F1 Score** | **2.2%** โ ๏ธ |
|
| 70 |
+
| True Positives | 48 |
|
| 71 |
+
| False Positives | 4,284 โ |
|
| 72 |
+
| False Negatives | 2 |
|
| 73 |
+
| Total GT | 50 |
|
| 74 |
+
| Total Predictions | 4,332 |
|
| 75 |
+
|
| 76 |
+
---
|
| 77 |
+
|
| 78 |
+
## โ๏ธ ์ฑ๋ฅ ๋น๊ต
|
| 79 |
+
|
| 80 |
+
### RT-DETR + Universal Filter vs YOLOv8
|
| 81 |
+
|
| 82 |
+
| Model | Confidence | Precision | Recall | F1 Score |
|
| 83 |
+
|-------|------------|-----------|--------|----------|
|
| 84 |
+
| **RT-DETR + Filter** | 0.065 / 90 | **44.2%** | **94.0%** | **56.1%** โ
|
|
| 85 |
+
| **YOLOv8 (Few-shot)** | 0.01 | 1.1% | 96.0% | 2.2% โ ๏ธ |
|
| 86 |
+
|
| 87 |
+
**F1 Score ์ฐจ์ด**: **-96.1%** (YOLOv8์ด ํจ์ฌ ๋ฎ์)
|
| 88 |
+
|
| 89 |
+
---
|
| 90 |
+
|
| 91 |
+
## ๐ ๋ฌธ์ ๋ถ์
|
| 92 |
+
|
| 93 |
+
### 1. False Positive ๊ณผ๋ค (4,284๊ฐ!)
|
| 94 |
+
|
| 95 |
+
**์์ธ**:
|
| 96 |
+
- **๋ฐ์ดํฐ ๋ถ์กฑ**: 50๊ฐ ์ํ๋ก๋ ์์ฐ์ ๋ค์ํ ํน์ง ํ์ต ๋ถ์กฑ
|
| 97 |
+
- **Negative Samples ๋ถ์ฌ**: ์์ฐ๊ฐ **์๋** ๊ฒ์ ํ์ตํ ๊ธฐํ ์์
|
| 98 |
+
- **๊ณผ์ ํฉ**: Validation mAP๋ ๋์ง๋ง ์ค์ ๋ก๋ ๊ณผ์ ํฉ
|
| 99 |
+
|
| 100 |
+
**์ฆ๊ฑฐ**:
|
| 101 |
+
- Confidence=0.01์์ 4,332๊ฐ ๊ฒ์ถ (ํ๊ท 86๊ฐ/์ด๋ฏธ์ง)
|
| 102 |
+
- GT๋ 1๊ฐ/์ด๋ฏธ์ง์ธ๋ฐ 86๋ฐฐ ๊ณผ๋ํ๊ฒ ๊ฒ์ถ
|
| 103 |
+
- Precision 1.1% = 99%๊ฐ ์ค๊ฒ์ถ
|
| 104 |
+
|
| 105 |
+
### 2. Validation mAP vs Real Performance
|
| 106 |
+
|
| 107 |
+
**Validation ์ฑ๋ฅ**:
|
| 108 |
+
- mAP50: 91.3% (Epoch 3)
|
| 109 |
+
- mAP50-95: 56.6%
|
| 110 |
+
|
| 111 |
+
**์ค์ GT ์ฑ๋ฅ**:
|
| 112 |
+
- Precision: 1.1%
|
| 113 |
+
- F1: 2.2%
|
| 114 |
+
|
| 115 |
+
**๋ถ์ผ์น ์์ธ**:
|
| 116 |
+
- **Val set ๊ณผ์ ํฉ**: 10๊ฐ val ์ด๋ฏธ์ง์๋ง ์ ์๋
|
| 117 |
+
- **Generalization ์คํจ**: Train/Val ์ธ ๋ฐ์ดํฐ์์ ์ฑ๋ฅ ์ ํ
|
| 118 |
+
- **Few-shot ํ๊ณ**: 50๊ฐ๋ก๋ robustํ ํ์ต ๋ถ๊ฐ๋ฅ
|
| 119 |
+
|
| 120 |
+
### 3. RT-DETR + Filter๊ฐ ๋ ๋์ ์ด์
|
| 121 |
+
|
| 122 |
+
| ํน์ง | RT-DETR + Filter | YOLOv8 Few-shot |
|
| 123 |
+
|------|------------------|-----------------|
|
| 124 |
+
| **์ฌ์ ํ์ต ๋ฐ์ดํฐ** | COCO (80+ classes, millions) | COCO + 50 shrimp |
|
| 125 |
+
| **๋๋ฉ์ธ ํนํ** | Universal filter (์ง์ ์ค๊ณ) | Fine-tuned (๋ฐ์ดํฐ ๋ถ์กฑ) |
|
| 126 |
+
| **FP ์ ๊ฑฐ** | Feature-based filter (๋ฉด์ , ์์ ๋ฑ) | Confidence๋ง ์์กด |
|
| 127 |
+
| **Negative Sample** | ํํฐ๊ฐ ์์์ ์ผ๋ก ์ฒ๋ฆฌ | ํ์ต ๋ฐ์ดํฐ ์์ |
|
| 128 |
+
| **์ผ๋ฐํ** | Rule-based โ robust | ๋ฐ์ดํฐ ์์กด โ ์ทจ์ฝ |
|
| 129 |
+
|
| 130 |
+
---
|
| 131 |
+
|
| 132 |
+
## ๐ก ๊ฐ์ ๋ฐฉ์
|
| 133 |
+
|
| 134 |
+
### ์ฆ์ ์ ์ฉ ๊ฐ๋ฅ
|
| 135 |
+
|
| 136 |
+
#### 1. **Hard Negative Mining** โญโญโญ
|
| 137 |
+
```python
|
| 138 |
+
# ํ์ฌ 4,284๊ฐ FP๋ฅผ negative sample๋ก ํ์ฉ
|
| 139 |
+
# FP ์ด๋ฏธ์ง์ "background" ๋ผ๋ฒจ ์ถ๊ฐํ์ฌ ์ฌํ์ต
|
| 140 |
+
```
|
| 141 |
+
|
| 142 |
+
**ํจ๊ณผ**: Precision ๋ํญ ํฅ์ ์์ (1.1% โ 30-50%)
|
| 143 |
+
|
| 144 |
+
#### 2. **YOLOv8 + Universal Filter ๊ฒฐํฉ** โญโญโญโญ
|
| 145 |
+
```python
|
| 146 |
+
# YOLOv8 ๊ฒ์ถ โ Universal Filter ์ ์ฉ
|
| 147 |
+
# ๋ ์์คํ
์ ์ฅ์ ๊ฒฐํฉ
|
| 148 |
+
```
|
| 149 |
+
|
| 150 |
+
**์์ ์ฑ๋ฅ**:
|
| 151 |
+
- Precision: 40-60% (Filter๊ฐ FP ์ ๊ฑฐ)
|
| 152 |
+
- Recall: 90-95% (YOLOv8 ๋์ recall ์ ์ง)
|
| 153 |
+
- F1: 55-70%
|
| 154 |
+
|
| 155 |
+
#### 3. **Confidence Threshold + NMS ์กฐ์ **
|
| 156 |
+
```python
|
| 157 |
+
# NMS IoU threshold ์กฐ์ (0.45 โ 0.3)
|
| 158 |
+
# Confidence threshold ์ํฅ (0.01 โ 0.05)
|
| 159 |
+
```
|
| 160 |
+
|
| 161 |
+
**ํ๊ณ**: ๊ทผ๋ณธ์ ํด๊ฒฐ ์๋, FP ์ฌ์ ํ ๋ง์
|
| 162 |
+
|
| 163 |
+
### ์ฅ๊ธฐ ๊ฐ์
|
| 164 |
+
|
| 165 |
+
#### 4. **๋ฐ์ดํฐ ์ฆ๊ฐ** (100-200๊ฐ ๋ชฉํ)
|
| 166 |
+
- Active Learning: ๋ชจ๋ธ์ด ๋ถํ์คํ ์ํ ์ฐ์ ๋ผ๋ฒจ๋ง
|
| 167 |
+
- ๋ค์ํ ์กฐ๊ฑด: ์กฐ๋ช
, ๊ฐ๋, ๋ฐ๋ ๋ณํ
|
| 168 |
+
- Negative samples: ์์ฐ ์๋ ์ด๋ฏธ์ง ์ถ๊ฐ
|
| 169 |
+
|
| 170 |
+
#### 5. **Model Architecture ๋ณ๊ฒฝ**
|
| 171 |
+
- YOLOv8m/l (๋ ํฐ ๋ชจ๋ธ, overfitting ์ํ)
|
| 172 |
+
- RT-DETR Fine-tuning (ํ์ฌ ์์คํ
๊ธฐ๋ฐ)
|
| 173 |
+
- Two-stage detector (Faster R-CNN ๋ฑ)
|
| 174 |
+
|
| 175 |
+
---
|
| 176 |
+
|
| 177 |
+
## ๐ ๊ฒฐ๋ก
|
| 178 |
+
|
| 179 |
+
### โ
์ฑ๊ณตํ ์
|
| 180 |
+
1. **YOLOv8 ํ์ต ํ์ดํ๋ผ์ธ ๊ตฌ์ถ** ์๋ฃ
|
| 181 |
+
2. **Few-shot learning ์คํ** ์ฑ๊ณต (3.3๋ถ)
|
| 182 |
+
3. **Recall 96%** ๋ฌ์ฑ (์์ฐ ๊ฑฐ์ ๋์น์ง ์์)
|
| 183 |
+
|
| 184 |
+
### โ ๏ธ ๋ฌธ์ ์
|
| 185 |
+
1. **Precision 1.1%** - ์ฌ์ค์ ์ค์ฉ ๋ถ๊ฐ๋ฅ
|
| 186 |
+
2. **FP 4,284๊ฐ** - 99%๊ฐ ์ค๊ฒ์ถ
|
| 187 |
+
3. **๋ฐ์ดํฐ ๋ถ์กฑ** - 50๊ฐ๋ก๋ ํ๊ณ ๋ช
ํ
|
| 188 |
+
|
| 189 |
+
### ๐ฏ ๊ถ์ฅ ์ฌํญ
|
| 190 |
+
|
| 191 |
+
**ํ์ฌ ์ํฉ (50๊ฐ ๋ฐ์ดํฐ)**:
|
| 192 |
+
โ **RT-DETR + Universal Filter ๊ณ์ ์ฌ์ฉ** (F1 56.1%)
|
| 193 |
+
|
| 194 |
+
**YOLOv8 ํ์ฉ ๋ฐฉ์**:
|
| 195 |
+
1. **์ฆ์**: YOLOv8 + Universal Filter ๊ฒฐํฉ (F1 55-70% ์์)
|
| 196 |
+
2. **๋จ๊ธฐ**: Hard Negative Mining์ผ๋ก ์ฌํ์ต
|
| 197 |
+
3. **์ฅ๊ธฐ**: ๋ฐ์ดํฐ 100-200๊ฐ ํ๋ณด ํ ์ฌํ์ต
|
| 198 |
+
|
| 199 |
+
**๋ฐ์ดํฐ ํ๋ณด ํ (100-200๊ฐ)**:
|
| 200 |
+
โ YOLOv8 ์ฌํ์ต ์๋ (F1 70-80% ๋ชฉํ)
|
| 201 |
+
|
| 202 |
+
---
|
| 203 |
+
|
| 204 |
+
## ๐ ์์ฑ๋ ํ์ผ
|
| 205 |
+
|
| 206 |
+
```
|
| 207 |
+
runs/train/shrimp_yolov8n/
|
| 208 |
+
โโโ weights/
|
| 209 |
+
โ โโโ best.pt # Best ๋ชจ๋ธ (Epoch 3)
|
| 210 |
+
โ โโโ last.pt # Last ๋ชจ๋ธ (Epoch 23)
|
| 211 |
+
โโโ results.png # ํ์ต ๊ณก์
|
| 212 |
+
โโโ confusion_matrix.png # Confusion matrix
|
| 213 |
+
โโโ labels.jpg # ๋ผ๋ฒจ ๋ถํฌ
|
| 214 |
+
|
| 215 |
+
data/yolo_dataset/
|
| 216 |
+
โโโ images/
|
| 217 |
+
โ โโโ train/ (40)
|
| 218 |
+
โ โโโ val/ (10)
|
| 219 |
+
โโโ labels/
|
| 220 |
+
โ โโโ train/ (40)
|
| 221 |
+
โ โโโ val/ (10)
|
| 222 |
+
โโโ data.yaml
|
| 223 |
+
|
| 224 |
+
yolo_evaluation_results.json # ์์ธ ํ๊ฐ ๊ฒฐ๊ณผ
|
| 225 |
+
```
|
| 226 |
+
|
| 227 |
+
---
|
| 228 |
+
|
| 229 |
+
## ๐ฌ ๋ค์ ์คํ ์ ์
|
| 230 |
+
|
| 231 |
+
### ์คํ 1: YOLOv8 + Universal Filter
|
| 232 |
+
```python
|
| 233 |
+
# test_yolo_with_filter.py
|
| 234 |
+
yolo_detections = yolo_model.predict(image, conf=0.01)
|
| 235 |
+
filtered_detections = apply_universal_filter(yolo_detections, image, threshold=90)
|
| 236 |
+
```
|
| 237 |
+
|
| 238 |
+
### ์คํ 2: Hard Negative Mining
|
| 239 |
+
```python
|
| 240 |
+
# collect_false_positives.py
|
| 241 |
+
# 4,284๊ฐ FP๋ฅผ negative samples๋ก ์ ์ฅ
|
| 242 |
+
# ์ฌํ์ต ์ positive:negative = 1:1 ๋น์จ
|
| 243 |
+
```
|
| 244 |
+
|
| 245 |
+
### ์คํ 3: Ensemble
|
| 246 |
+
```python
|
| 247 |
+
# ensemble.py
|
| 248 |
+
rtdetr_results = rtdetr_predict(image)
|
| 249 |
+
yolo_results = yolo_predict(image)
|
| 250 |
+
final_results = vote_or_union(rtdetr_results, yolo_results)
|
| 251 |
+
```
|
| 252 |
+
|
| 253 |
+
---
|
| 254 |
+
|
| 255 |
+
## ๐ ์ต์ข
ํ๊ฐ
|
| 256 |
+
|
| 257 |
+
| ํ๊ฐ ํญ๋ชฉ | ์ ์ | ์ฝ๋ฉํธ |
|
| 258 |
+
|----------|------|--------|
|
| 259 |
+
| **ํ์ต ์ฑ๊ณต** | โญโญโญโญโญ | ํ์ดํ๋ผ์ธ ์๋ฒฝ ๊ตฌ์ถ |
|
| 260 |
+
| **ํ์ต ์๋** | โญโญโญโญโญ | 3.3๋ถ, ๋งค์ฐ ๋น ๋ฆ |
|
| 261 |
+
| **์ค์ฉ์ฑ** | โญ | Precision 1.1%, ์ฌ์ฉ ๋ถ๊ฐ |
|
| 262 |
+
| **Recall** | โญโญโญโญโญ | 96%, ๊ฑฐ์ ์๋ฒฝ |
|
| 263 |
+
| **๊ฐ์ ๊ฐ๋ฅ์ฑ** | โญโญโญโญ | Filter ๊ฒฐํฉ/๋ฐ์ดํฐ ์ถ๊ฐ ์ ์ ๋ง |
|
| 264 |
+
|
| 265 |
+
**์ข
ํฉ ํ๊ฐ**:
|
| 266 |
+
- Few-shot learning ํ๊ณ ๋ช
ํํ ํ์ธ
|
| 267 |
+
- RT-DETR + Filter๊ฐ ํ์ฌ ์ต์
|
| 268 |
+
- ๋ฐ์ดํฐ ํ๋ณด ์ YOLOv8 ์ฌ๋์ ๊ฐ์น ์์
|
evaluate_yolo.py
ADDED
|
@@ -0,0 +1,239 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# -*- coding: utf-8 -*-
|
| 2 |
+
"""
|
| 3 |
+
YOLOv8 ํ์ต ๋ชจ๋ธ ํ๊ฐ
|
| 4 |
+
GT ๋ฐ์ดํฐ๋ก ์ฑ๋ฅ ์ธก์ ๋ฐ RT-DETR๊ณผ ๋น๊ต
|
| 5 |
+
"""
|
| 6 |
+
import sys
|
| 7 |
+
sys.stdout.reconfigure(encoding='utf-8')
|
| 8 |
+
|
| 9 |
+
from ultralytics import YOLO
|
| 10 |
+
import json
|
| 11 |
+
import os
|
| 12 |
+
from PIL import Image
|
| 13 |
+
import numpy as np
|
| 14 |
+
from pathlib import Path
|
| 15 |
+
|
| 16 |
+
def calculate_iou(box1, box2):
|
| 17 |
+
"""IoU ๊ณ์ฐ"""
|
| 18 |
+
x1_1, y1_1, x2_1, y2_1 = box1
|
| 19 |
+
x1_2, y1_2, x2_2, y2_2 = box2
|
| 20 |
+
|
| 21 |
+
# Intersection
|
| 22 |
+
x1_i = max(x1_1, x1_2)
|
| 23 |
+
y1_i = max(y1_1, y1_2)
|
| 24 |
+
x2_i = min(x2_1, x2_2)
|
| 25 |
+
y2_i = min(y2_1, y2_2)
|
| 26 |
+
|
| 27 |
+
if x2_i < x1_i or y2_i < y1_i:
|
| 28 |
+
return 0.0
|
| 29 |
+
|
| 30 |
+
intersection = (x2_i - x1_i) * (y2_i - y1_i)
|
| 31 |
+
|
| 32 |
+
# Union
|
| 33 |
+
area1 = (x2_1 - x1_1) * (y2_1 - y1_1)
|
| 34 |
+
area2 = (x2_2 - x1_2) * (y2_2 - y1_2)
|
| 35 |
+
union = area1 + area2 - intersection
|
| 36 |
+
|
| 37 |
+
return intersection / union if union > 0 else 0.0
|
| 38 |
+
|
| 39 |
+
def evaluate_model(model_path, gt_file, data_base_dir, confidence_threshold=0.25, iou_threshold=0.5):
|
| 40 |
+
"""๋ชจ๋ธ ํ๊ฐ"""
|
| 41 |
+
print(f"\n๐ ๋ชจ๋ธ ํ๊ฐ ์์: {model_path}")
|
| 42 |
+
print(f" - Confidence: {confidence_threshold}")
|
| 43 |
+
print(f" - IoU Threshold: {iou_threshold}")
|
| 44 |
+
|
| 45 |
+
# ๋ชจ๋ธ ๋ก๋
|
| 46 |
+
model = YOLO(model_path)
|
| 47 |
+
print(f"โ
๋ชจ๋ธ ๋ก๋ ์๋ฃ")
|
| 48 |
+
|
| 49 |
+
# GT ๋ก๋
|
| 50 |
+
with open(gt_file, 'r', encoding='utf-8') as f:
|
| 51 |
+
gt_data = json.load(f)
|
| 52 |
+
|
| 53 |
+
# ํต๊ณ
|
| 54 |
+
total_gt = 0
|
| 55 |
+
total_pred = 0
|
| 56 |
+
true_positives = 0
|
| 57 |
+
false_positives = 0
|
| 58 |
+
false_negatives = 0
|
| 59 |
+
|
| 60 |
+
results_detail = []
|
| 61 |
+
|
| 62 |
+
# ๊ฐ ์ด๋ฏธ์ง ํ๊ฐ
|
| 63 |
+
for filename, gt_boxes in gt_data.items():
|
| 64 |
+
if not gt_boxes:
|
| 65 |
+
continue
|
| 66 |
+
|
| 67 |
+
folder = gt_boxes[0].get('folder', '')
|
| 68 |
+
if not folder:
|
| 69 |
+
continue
|
| 70 |
+
|
| 71 |
+
img_path = os.path.join(data_base_dir, folder, filename)
|
| 72 |
+
if not os.path.exists(img_path):
|
| 73 |
+
continue
|
| 74 |
+
|
| 75 |
+
# YOLOv8 ์ถ๋ก
|
| 76 |
+
results = model(img_path, conf=confidence_threshold, verbose=False)
|
| 77 |
+
|
| 78 |
+
# ์์ธก ๋ฐ์ค ์ถ์ถ
|
| 79 |
+
pred_boxes = []
|
| 80 |
+
if results and len(results) > 0:
|
| 81 |
+
result = results[0]
|
| 82 |
+
if result.boxes is not None and len(result.boxes) > 0:
|
| 83 |
+
boxes = result.boxes.xyxy.cpu().numpy() # [x1, y1, x2, y2]
|
| 84 |
+
confs = result.boxes.conf.cpu().numpy()
|
| 85 |
+
|
| 86 |
+
for box, conf in zip(boxes, confs):
|
| 87 |
+
pred_boxes.append({
|
| 88 |
+
'bbox': box.tolist(),
|
| 89 |
+
'confidence': float(conf)
|
| 90 |
+
})
|
| 91 |
+
|
| 92 |
+
# GT ๋ฐ์ค
|
| 93 |
+
gt_boxes_only = [{'bbox': ann['bbox']} for ann in gt_boxes]
|
| 94 |
+
|
| 95 |
+
# ๋งค์นญ
|
| 96 |
+
matched_gt = set()
|
| 97 |
+
matched_pred = set()
|
| 98 |
+
|
| 99 |
+
for i, pred in enumerate(pred_boxes):
|
| 100 |
+
best_iou = 0
|
| 101 |
+
best_gt_idx = -1
|
| 102 |
+
|
| 103 |
+
for j, gt in enumerate(gt_boxes_only):
|
| 104 |
+
if j in matched_gt:
|
| 105 |
+
continue
|
| 106 |
+
|
| 107 |
+
iou = calculate_iou(pred['bbox'], gt['bbox'])
|
| 108 |
+
if iou > best_iou:
|
| 109 |
+
best_iou = iou
|
| 110 |
+
best_gt_idx = j
|
| 111 |
+
|
| 112 |
+
if best_iou >= iou_threshold:
|
| 113 |
+
matched_pred.add(i)
|
| 114 |
+
matched_gt.add(best_gt_idx)
|
| 115 |
+
|
| 116 |
+
tp = len(matched_gt)
|
| 117 |
+
fp = len(pred_boxes) - len(matched_pred)
|
| 118 |
+
fn = len(gt_boxes_only) - len(matched_gt)
|
| 119 |
+
|
| 120 |
+
true_positives += tp
|
| 121 |
+
false_positives += fp
|
| 122 |
+
false_negatives += fn
|
| 123 |
+
total_gt += len(gt_boxes_only)
|
| 124 |
+
total_pred += len(pred_boxes)
|
| 125 |
+
|
| 126 |
+
results_detail.append({
|
| 127 |
+
'filename': filename,
|
| 128 |
+
'gt_count': len(gt_boxes_only),
|
| 129 |
+
'pred_count': len(pred_boxes),
|
| 130 |
+
'tp': tp,
|
| 131 |
+
'fp': fp,
|
| 132 |
+
'fn': fn
|
| 133 |
+
})
|
| 134 |
+
|
| 135 |
+
# ์ฑ๋ฅ ๊ณ์ฐ
|
| 136 |
+
precision = true_positives / (true_positives + false_positives) if (true_positives + false_positives) > 0 else 0
|
| 137 |
+
recall = true_positives / (true_positives + false_negatives) if (true_positives + false_negatives) > 0 else 0
|
| 138 |
+
f1 = 2 * precision * recall / (precision + recall) if (precision + recall) > 0 else 0
|
| 139 |
+
|
| 140 |
+
return {
|
| 141 |
+
'precision': precision,
|
| 142 |
+
'recall': recall,
|
| 143 |
+
'f1': f1,
|
| 144 |
+
'tp': true_positives,
|
| 145 |
+
'fp': false_positives,
|
| 146 |
+
'fn': false_negatives,
|
| 147 |
+
'total_gt': total_gt,
|
| 148 |
+
'total_pred': total_pred
|
| 149 |
+
}
|
| 150 |
+
|
| 151 |
+
def main():
|
| 152 |
+
print("=" * 60)
|
| 153 |
+
print("๐ฏ YOLOv8 ๋ชจ๋ธ ํ๊ฐ")
|
| 154 |
+
print("=" * 60)
|
| 155 |
+
|
| 156 |
+
# ๊ฒฝ๋ก ์ค์
|
| 157 |
+
best_model = "runs/train/shrimp_yolov8n/weights/best.pt"
|
| 158 |
+
gt_file = "ground_truth.json"
|
| 159 |
+
data_base_dir = "data/ํฐ๋ค๋ฆฌ์์ฐ ์ค์ธก ๋ฐ์ดํฐ_์ตํฌ์ค์์ด์์ด(์ฃผ)"
|
| 160 |
+
|
| 161 |
+
if not os.path.exists(best_model):
|
| 162 |
+
print(f"\nโ ๋ชจ๋ธ ํ์ผ ์์: {best_model}")
|
| 163 |
+
print(" ๋จผ์ train_yolo.py๋ฅผ ์คํํ์ธ์.")
|
| 164 |
+
return
|
| 165 |
+
|
| 166 |
+
print(f"\n๐ ๋ชจ๋ธ: {best_model}")
|
| 167 |
+
print(f"๐ GT: {gt_file}")
|
| 168 |
+
|
| 169 |
+
# ์ฌ๋ฌ confidence threshold ํ
์คํธ (๋ฎ์ ๊ฐ๋ถํฐ)
|
| 170 |
+
confidence_thresholds = [0.001, 0.01, 0.05, 0.1, 0.15, 0.2, 0.25, 0.3]
|
| 171 |
+
|
| 172 |
+
print(f"\n๐ Confidence Threshold ์ต์ ํ ์ค...")
|
| 173 |
+
print(f" ํ
์คํธ ๋ฒ์: {confidence_thresholds}")
|
| 174 |
+
|
| 175 |
+
best_f1 = 0
|
| 176 |
+
best_conf = 0
|
| 177 |
+
best_result = None
|
| 178 |
+
all_results = []
|
| 179 |
+
|
| 180 |
+
for conf in confidence_thresholds:
|
| 181 |
+
result = evaluate_model(best_model, gt_file, data_base_dir, confidence_threshold=conf)
|
| 182 |
+
result['conf'] = conf
|
| 183 |
+
all_results.append(result)
|
| 184 |
+
|
| 185 |
+
print(f"\n Conf={conf:.2f}: P={result['precision']:.1%}, R={result['recall']:.1%}, F1={result['f1']:.1%}")
|
| 186 |
+
|
| 187 |
+
if result['f1'] > best_f1:
|
| 188 |
+
best_f1 = result['f1']
|
| 189 |
+
best_conf = conf
|
| 190 |
+
best_result = result
|
| 191 |
+
|
| 192 |
+
# ์ต์ ๊ฒฐ๊ณผ ์ถ๋ ฅ
|
| 193 |
+
print("\n" + "=" * 60)
|
| 194 |
+
print("โ
ํ๊ฐ ์๋ฃ!")
|
| 195 |
+
print("=" * 60)
|
| 196 |
+
|
| 197 |
+
print(f"\n๐ ์ต์ ์ฑ๋ฅ (Confidence={best_conf}):")
|
| 198 |
+
print(f" - Precision: {best_result['precision']:.1%}")
|
| 199 |
+
print(f" - Recall: {best_result['recall']:.1%}")
|
| 200 |
+
print(f" - F1 Score: {best_result['f1']:.1%}")
|
| 201 |
+
print(f"\n - True Positives: {best_result['tp']}")
|
| 202 |
+
print(f" - False Positives: {best_result['fp']}")
|
| 203 |
+
print(f" - False Negatives: {best_result['fn']}")
|
| 204 |
+
print(f" - Total GT: {best_result['total_gt']}")
|
| 205 |
+
print(f" - Total Pred: {best_result['total_pred']}")
|
| 206 |
+
|
| 207 |
+
# RT-DETR ๋น๊ต
|
| 208 |
+
print(f"\n๐ RT-DETR + Filter ๋น๊ต:")
|
| 209 |
+
print(f" RT-DETR (Conf=0.065, Filter=90):")
|
| 210 |
+
print(f" - Precision: 44.2%")
|
| 211 |
+
print(f" - Recall: 94.0%")
|
| 212 |
+
print(f" - F1 Score: 56.1%")
|
| 213 |
+
print(f"\n YOLOv8 (Conf={best_conf}):")
|
| 214 |
+
print(f" - Precision: {best_result['precision']:.1%}")
|
| 215 |
+
print(f" - Recall: {best_result['recall']:.1%}")
|
| 216 |
+
print(f" - F1 Score: {best_result['f1']:.1%}")
|
| 217 |
+
|
| 218 |
+
# ๊ฐ์ ์จ
|
| 219 |
+
baseline_f1 = 0.561
|
| 220 |
+
improvement = (best_result['f1'] - baseline_f1) / baseline_f1 * 100
|
| 221 |
+
print(f"\n F1 ๊ฐ์ ์จ: {improvement:+.1f}%")
|
| 222 |
+
|
| 223 |
+
# ๊ฒฐ๊ณผ ์ ์ฅ
|
| 224 |
+
output_file = "yolo_evaluation_results.json"
|
| 225 |
+
with open(output_file, 'w', encoding='utf-8') as f:
|
| 226 |
+
json.dump({
|
| 227 |
+
'best_result': best_result,
|
| 228 |
+
'all_results': all_results,
|
| 229 |
+
'baseline': {
|
| 230 |
+
'precision': 0.442,
|
| 231 |
+
'recall': 0.940,
|
| 232 |
+
'f1': 0.561
|
| 233 |
+
}
|
| 234 |
+
}, f, indent=2, ensure_ascii=False)
|
| 235 |
+
|
| 236 |
+
print(f"\n๐พ ๊ฒฐ๊ณผ ์ ์ฅ: {output_file}")
|
| 237 |
+
|
| 238 |
+
if __name__ == "__main__":
|
| 239 |
+
main()
|
ground_truth.json
ADDED
|
@@ -0,0 +1,1215 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"250818_01-1.jpg": [],
|
| 3 |
+
"250818_01.jpg": [
|
| 4 |
+
{
|
| 5 |
+
"bbox": [
|
| 6 |
+
1098.450927734375,
|
| 7 |
+
2188.135009765625,
|
| 8 |
+
1970.4261474609375,
|
| 9 |
+
2320.272216796875
|
| 10 |
+
],
|
| 11 |
+
"label": "shrimp",
|
| 12 |
+
"folder": "250818",
|
| 13 |
+
"confidence": 0.2446231096982956
|
| 14 |
+
}
|
| 15 |
+
],
|
| 16 |
+
"250818_02-1.jpg": [],
|
| 17 |
+
"250818_02.jpg": [
|
| 18 |
+
{
|
| 19 |
+
"bbox": [
|
| 20 |
+
1395.8035888671875,
|
| 21 |
+
1595.033447265625,
|
| 22 |
+
1506.87255859375,
|
| 23 |
+
2400.074462890625
|
| 24 |
+
],
|
| 25 |
+
"label": "shrimp",
|
| 26 |
+
"folder": "250818",
|
| 27 |
+
"confidence": 0.40011000633239746
|
| 28 |
+
}
|
| 29 |
+
],
|
| 30 |
+
"250818_03.jpg": [
|
| 31 |
+
{
|
| 32 |
+
"bbox": [
|
| 33 |
+
856.6959228515625,
|
| 34 |
+
1100.64794921875,
|
| 35 |
+
1068.8673095703125,
|
| 36 |
+
2314.57421875
|
| 37 |
+
],
|
| 38 |
+
"label": "shrimp",
|
| 39 |
+
"folder": "250818",
|
| 40 |
+
"confidence": 0.3958529233932495
|
| 41 |
+
}
|
| 42 |
+
],
|
| 43 |
+
"250818_04.jpg": [
|
| 44 |
+
{
|
| 45 |
+
"bbox": [
|
| 46 |
+
1551.4468994140625,
|
| 47 |
+
1275.170166015625,
|
| 48 |
+
2633.267333984375,
|
| 49 |
+
1425.421630859375
|
| 50 |
+
],
|
| 51 |
+
"label": "shrimp",
|
| 52 |
+
"folder": "250818",
|
| 53 |
+
"confidence": 0.06465403735637665
|
| 54 |
+
}
|
| 55 |
+
],
|
| 56 |
+
"250818_05.jpg": [
|
| 57 |
+
{
|
| 58 |
+
"bbox": [
|
| 59 |
+
1192.9915771484375,
|
| 60 |
+
1323.396728515625,
|
| 61 |
+
1345.46923828125,
|
| 62 |
+
2361.0595703125
|
| 63 |
+
],
|
| 64 |
+
"label": "shrimp",
|
| 65 |
+
"folder": "250818",
|
| 66 |
+
"confidence": 0.10265685617923737
|
| 67 |
+
}
|
| 68 |
+
],
|
| 69 |
+
"250818_06.jpg": [
|
| 70 |
+
{
|
| 71 |
+
"bbox": [
|
| 72 |
+
1098.338134765625,
|
| 73 |
+
1384.988525390625,
|
| 74 |
+
1268.077392578125,
|
| 75 |
+
2370.87890625
|
| 76 |
+
],
|
| 77 |
+
"label": "shrimp",
|
| 78 |
+
"folder": "250818",
|
| 79 |
+
"confidence": 0.3832502067089081
|
| 80 |
+
}
|
| 81 |
+
],
|
| 82 |
+
"250818_07.jpg": [
|
| 83 |
+
{
|
| 84 |
+
"bbox": [
|
| 85 |
+
1126.0252685546875,
|
| 86 |
+
1412.76806640625,
|
| 87 |
+
1308.2734375,
|
| 88 |
+
2484.1640625
|
| 89 |
+
],
|
| 90 |
+
"label": "shrimp",
|
| 91 |
+
"folder": "250818",
|
| 92 |
+
"confidence": 0.1713441014289856
|
| 93 |
+
}
|
| 94 |
+
],
|
| 95 |
+
"250818_08.jpg": [
|
| 96 |
+
{
|
| 97 |
+
"bbox": [
|
| 98 |
+
1166.57080078125,
|
| 99 |
+
1146.9354248046875,
|
| 100 |
+
1324.5594482421875,
|
| 101 |
+
2282.549560546875
|
| 102 |
+
],
|
| 103 |
+
"label": "shrimp",
|
| 104 |
+
"folder": "250818",
|
| 105 |
+
"confidence": 0.1433110237121582
|
| 106 |
+
}
|
| 107 |
+
],
|
| 108 |
+
"250818_09.jpg": [
|
| 109 |
+
{
|
| 110 |
+
"bbox": [
|
| 111 |
+
1084.7362060546875,
|
| 112 |
+
1759.9801025390625,
|
| 113 |
+
2240.894287109375,
|
| 114 |
+
1906.094970703125
|
| 115 |
+
],
|
| 116 |
+
"label": "shrimp",
|
| 117 |
+
"folder": "250818",
|
| 118 |
+
"confidence": 0.3963541090488434
|
| 119 |
+
}
|
| 120 |
+
],
|
| 121 |
+
"250818_10.jpg": [
|
| 122 |
+
{
|
| 123 |
+
"bbox": [
|
| 124 |
+
1150.8240966796875,
|
| 125 |
+
1132.4393310546875,
|
| 126 |
+
1378.7298583984375,
|
| 127 |
+
2469.353515625
|
| 128 |
+
],
|
| 129 |
+
"label": "shrimp",
|
| 130 |
+
"folder": "250818",
|
| 131 |
+
"confidence": 0.19699835777282715
|
| 132 |
+
}
|
| 133 |
+
],
|
| 134 |
+
"250820_01.jpg": [
|
| 135 |
+
{
|
| 136 |
+
"bbox": [
|
| 137 |
+
1160.2913818359375,
|
| 138 |
+
1358.67431640625,
|
| 139 |
+
1253.632080078125,
|
| 140 |
+
2011.880859375
|
| 141 |
+
],
|
| 142 |
+
"label": "shrimp",
|
| 143 |
+
"folder": "250820",
|
| 144 |
+
"confidence": 0.1384470909833908
|
| 145 |
+
}
|
| 146 |
+
],
|
| 147 |
+
"250820_02.jpg": [
|
| 148 |
+
{
|
| 149 |
+
"bbox": [
|
| 150 |
+
1460.3377685546875,
|
| 151 |
+
1265.1815185546875,
|
| 152 |
+
1589.741943359375,
|
| 153 |
+
2065.281982421875
|
| 154 |
+
],
|
| 155 |
+
"label": "shrimp",
|
| 156 |
+
"folder": "250820",
|
| 157 |
+
"confidence": 0.08587982505559921
|
| 158 |
+
}
|
| 159 |
+
],
|
| 160 |
+
"250820_03.jpg": [
|
| 161 |
+
{
|
| 162 |
+
"bbox": [
|
| 163 |
+
1306.392822265625,
|
| 164 |
+
1424.296630859375,
|
| 165 |
+
1430.9761962890625,
|
| 166 |
+
2232.6005859375
|
| 167 |
+
],
|
| 168 |
+
"label": "shrimp",
|
| 169 |
+
"folder": "250820",
|
| 170 |
+
"confidence": 0.15388250350952148
|
| 171 |
+
}
|
| 172 |
+
],
|
| 173 |
+
"250820_04.jpg": [
|
| 174 |
+
{
|
| 175 |
+
"bbox": [
|
| 176 |
+
1552.5809326171875,
|
| 177 |
+
1852.331787109375,
|
| 178 |
+
1671.959228515625,
|
| 179 |
+
2759.19482421875
|
| 180 |
+
],
|
| 181 |
+
"label": "shrimp",
|
| 182 |
+
"folder": "250820",
|
| 183 |
+
"confidence": 0.29403966665267944
|
| 184 |
+
}
|
| 185 |
+
],
|
| 186 |
+
"250820_05.jpg": [
|
| 187 |
+
{
|
| 188 |
+
"bbox": [
|
| 189 |
+
1115.5489501953125,
|
| 190 |
+
879.0062255859375,
|
| 191 |
+
1278.563232421875,
|
| 192 |
+
1844.8424072265625
|
| 193 |
+
],
|
| 194 |
+
"label": "shrimp",
|
| 195 |
+
"folder": "250820",
|
| 196 |
+
"confidence": 0.17484499514102936
|
| 197 |
+
}
|
| 198 |
+
],
|
| 199 |
+
"250820_06.jpg": [
|
| 200 |
+
{
|
| 201 |
+
"bbox": [
|
| 202 |
+
1214.4674072265625,
|
| 203 |
+
499.7831115722656,
|
| 204 |
+
1388.730224609375,
|
| 205 |
+
1631.701904296875
|
| 206 |
+
],
|
| 207 |
+
"label": "shrimp",
|
| 208 |
+
"folder": "250820",
|
| 209 |
+
"confidence": 0.23423509299755096
|
| 210 |
+
}
|
| 211 |
+
],
|
| 212 |
+
"250820_07.jpg": [
|
| 213 |
+
{
|
| 214 |
+
"bbox": [
|
| 215 |
+
1204.2728271484375,
|
| 216 |
+
543.64111328125,
|
| 217 |
+
1373.787841796875,
|
| 218 |
+
1791.3291015625
|
| 219 |
+
],
|
| 220 |
+
"label": "shrimp",
|
| 221 |
+
"folder": "250820",
|
| 222 |
+
"confidence": 0.13452696800231934
|
| 223 |
+
}
|
| 224 |
+
],
|
| 225 |
+
"250820_08.jpg": [
|
| 226 |
+
{
|
| 227 |
+
"bbox": [
|
| 228 |
+
1130.42333984375,
|
| 229 |
+
817.0694580078125,
|
| 230 |
+
1304.11962890625,
|
| 231 |
+
2154.3828125
|
| 232 |
+
],
|
| 233 |
+
"label": "shrimp",
|
| 234 |
+
"folder": "250820",
|
| 235 |
+
"confidence": 0.23954583704471588
|
| 236 |
+
}
|
| 237 |
+
],
|
| 238 |
+
"250820_09.jpg": [
|
| 239 |
+
{
|
| 240 |
+
"bbox": [
|
| 241 |
+
1159.3487548828125,
|
| 242 |
+
880.5440063476562,
|
| 243 |
+
1339.7265625,
|
| 244 |
+
2037.740234375
|
| 245 |
+
],
|
| 246 |
+
"label": "shrimp",
|
| 247 |
+
"folder": "250820",
|
| 248 |
+
"confidence": 0.3200088143348694
|
| 249 |
+
}
|
| 250 |
+
],
|
| 251 |
+
"250820_10.jpg": [
|
| 252 |
+
{
|
| 253 |
+
"bbox": [
|
| 254 |
+
1432.78271484375,
|
| 255 |
+
840.3897094726562,
|
| 256 |
+
1593.228271484375,
|
| 257 |
+
2143.7373046875
|
| 258 |
+
],
|
| 259 |
+
"label": "shrimp",
|
| 260 |
+
"folder": "250820",
|
| 261 |
+
"confidence": 0.27361050248146057
|
| 262 |
+
}
|
| 263 |
+
],
|
| 264 |
+
"250822_01.jpg": [
|
| 265 |
+
{
|
| 266 |
+
"bbox": [
|
| 267 |
+
1251.2254638671875,
|
| 268 |
+
994.4230346679688,
|
| 269 |
+
1408.139892578125,
|
| 270 |
+
2075.188232421875
|
| 271 |
+
],
|
| 272 |
+
"label": "shrimp",
|
| 273 |
+
"folder": "250822",
|
| 274 |
+
"confidence": 0.34266287088394165
|
| 275 |
+
}
|
| 276 |
+
],
|
| 277 |
+
"250822_02.jpg": [
|
| 278 |
+
{
|
| 279 |
+
"bbox": [
|
| 280 |
+
1317.6868896484375,
|
| 281 |
+
1035.605224609375,
|
| 282 |
+
1446.357666015625,
|
| 283 |
+
2008.87158203125
|
| 284 |
+
],
|
| 285 |
+
"label": "shrimp",
|
| 286 |
+
"folder": "250822",
|
| 287 |
+
"confidence": 0.09503860026597977
|
| 288 |
+
}
|
| 289 |
+
],
|
| 290 |
+
"250822_03.jpg": [
|
| 291 |
+
{
|
| 292 |
+
"bbox": [
|
| 293 |
+
1365.2215576171875,
|
| 294 |
+
1128.541748046875,
|
| 295 |
+
1533.333251953125,
|
| 296 |
+
2056.751708984375
|
| 297 |
+
],
|
| 298 |
+
"label": "shrimp",
|
| 299 |
+
"folder": "250822",
|
| 300 |
+
"confidence": 0.2378787100315094
|
| 301 |
+
}
|
| 302 |
+
],
|
| 303 |
+
"250822_04.jpg": [
|
| 304 |
+
{
|
| 305 |
+
"bbox": [
|
| 306 |
+
1323.949951171875,
|
| 307 |
+
841.3326416015625,
|
| 308 |
+
1466.5777587890625,
|
| 309 |
+
1978.2467041015625
|
| 310 |
+
],
|
| 311 |
+
"label": "shrimp",
|
| 312 |
+
"folder": "250822",
|
| 313 |
+
"confidence": 0.37354016304016113
|
| 314 |
+
}
|
| 315 |
+
],
|
| 316 |
+
"250822_05.jpg": [
|
| 317 |
+
{
|
| 318 |
+
"bbox": [
|
| 319 |
+
1484.5748291015625,
|
| 320 |
+
1181.9923095703125,
|
| 321 |
+
1639.3096923828125,
|
| 322 |
+
2176.525390625
|
| 323 |
+
],
|
| 324 |
+
"label": "shrimp",
|
| 325 |
+
"folder": "250822",
|
| 326 |
+
"confidence": 0.37560534477233887
|
| 327 |
+
}
|
| 328 |
+
],
|
| 329 |
+
"250822_06.jpg": [
|
| 330 |
+
{
|
| 331 |
+
"bbox": [
|
| 332 |
+
1421.6964111328125,
|
| 333 |
+
1090.3521728515625,
|
| 334 |
+
1568.4810791015625,
|
| 335 |
+
2265.350830078125
|
| 336 |
+
],
|
| 337 |
+
"label": "shrimp",
|
| 338 |
+
"folder": "250822",
|
| 339 |
+
"confidence": 0.5202826857566833
|
| 340 |
+
}
|
| 341 |
+
],
|
| 342 |
+
"250822_07.jpg": [
|
| 343 |
+
{
|
| 344 |
+
"bbox": [
|
| 345 |
+
1272.6038818359375,
|
| 346 |
+
1061.55322265625,
|
| 347 |
+
1529.1480712890625,
|
| 348 |
+
2423.214599609375
|
| 349 |
+
],
|
| 350 |
+
"label": "shrimp",
|
| 351 |
+
"folder": "250822",
|
| 352 |
+
"confidence": 0.37624678015708923
|
| 353 |
+
}
|
| 354 |
+
],
|
| 355 |
+
"250822_08.jpg": [
|
| 356 |
+
{
|
| 357 |
+
"bbox": [
|
| 358 |
+
1457.4725341796875,
|
| 359 |
+
2123.125732421875,
|
| 360 |
+
1608.882080078125,
|
| 361 |
+
3246.6787109375
|
| 362 |
+
],
|
| 363 |
+
"label": "shrimp",
|
| 364 |
+
"folder": "250822",
|
| 365 |
+
"confidence": 0.30957385897636414
|
| 366 |
+
}
|
| 367 |
+
],
|
| 368 |
+
"250822_09.jpg": [
|
| 369 |
+
{
|
| 370 |
+
"bbox": [
|
| 371 |
+
1428.73876953125,
|
| 372 |
+
1187.3817138671875,
|
| 373 |
+
1584.5435791015625,
|
| 374 |
+
2214.35791015625
|
| 375 |
+
],
|
| 376 |
+
"label": "shrimp",
|
| 377 |
+
"folder": "250822",
|
| 378 |
+
"confidence": 0.12000244855880737
|
| 379 |
+
}
|
| 380 |
+
],
|
| 381 |
+
"250822_10.jpg": [
|
| 382 |
+
{
|
| 383 |
+
"bbox": [
|
| 384 |
+
1404.9388427734375,
|
| 385 |
+
999.1651611328125,
|
| 386 |
+
1593.969970703125,
|
| 387 |
+
2243.964599609375
|
| 388 |
+
],
|
| 389 |
+
"label": "shrimp",
|
| 390 |
+
"folder": "250822",
|
| 391 |
+
"confidence": 0.23076726496219635
|
| 392 |
+
}
|
| 393 |
+
],
|
| 394 |
+
"250827_01.jpg": [
|
| 395 |
+
{
|
| 396 |
+
"bbox": [
|
| 397 |
+
684.4800415039062,
|
| 398 |
+
1690.7694091796875,
|
| 399 |
+
1968.4957275390625,
|
| 400 |
+
1842.5177001953125
|
| 401 |
+
],
|
| 402 |
+
"label": "shrimp",
|
| 403 |
+
"folder": "250827",
|
| 404 |
+
"confidence": 0.340087354183197
|
| 405 |
+
}
|
| 406 |
+
],
|
| 407 |
+
"250827_02.jpg": [
|
| 408 |
+
{
|
| 409 |
+
"bbox": [
|
| 410 |
+
1028.1351318359375,
|
| 411 |
+
1477.976318359375,
|
| 412 |
+
2124.99658203125,
|
| 413 |
+
1688.405029296875
|
| 414 |
+
],
|
| 415 |
+
"label": "shrimp",
|
| 416 |
+
"folder": "250827",
|
| 417 |
+
"confidence": 0.6583316326141357
|
| 418 |
+
}
|
| 419 |
+
],
|
| 420 |
+
"250827_03.jpg": [
|
| 421 |
+
{
|
| 422 |
+
"bbox": [
|
| 423 |
+
922.0469970703125,
|
| 424 |
+
1643.7581787109375,
|
| 425 |
+
2144.581787109375,
|
| 426 |
+
1899.083740234375
|
| 427 |
+
],
|
| 428 |
+
"label": "shrimp",
|
| 429 |
+
"folder": "250827",
|
| 430 |
+
"confidence": 0.5130608081817627
|
| 431 |
+
}
|
| 432 |
+
],
|
| 433 |
+
"250827_04.jpg": [
|
| 434 |
+
{
|
| 435 |
+
"bbox": [
|
| 436 |
+
939.3685913085938,
|
| 437 |
+
1655.833251953125,
|
| 438 |
+
2269.65478515625,
|
| 439 |
+
1902.0322265625
|
| 440 |
+
],
|
| 441 |
+
"label": "shrimp",
|
| 442 |
+
"folder": "250827",
|
| 443 |
+
"confidence": 0.3166744112968445
|
| 444 |
+
}
|
| 445 |
+
],
|
| 446 |
+
"250827_05.jpg": [
|
| 447 |
+
{
|
| 448 |
+
"bbox": [
|
| 449 |
+
1292.3563232421875,
|
| 450 |
+
1136.2109375,
|
| 451 |
+
1511.3590087890625,
|
| 452 |
+
2329.110595703125
|
| 453 |
+
],
|
| 454 |
+
"label": "shrimp",
|
| 455 |
+
"folder": "250827",
|
| 456 |
+
"confidence": 0.5118752717971802
|
| 457 |
+
}
|
| 458 |
+
],
|
| 459 |
+
"250827_06.jpg": [
|
| 460 |
+
{
|
| 461 |
+
"bbox": [
|
| 462 |
+
1058.8575439453125,
|
| 463 |
+
878.7330932617188,
|
| 464 |
+
1263.750732421875,
|
| 465 |
+
2188.184326171875
|
| 466 |
+
],
|
| 467 |
+
"label": "shrimp",
|
| 468 |
+
"folder": "250827",
|
| 469 |
+
"confidence": 0.3714663088321686
|
| 470 |
+
}
|
| 471 |
+
],
|
| 472 |
+
"250827_07.jpg": [
|
| 473 |
+
{
|
| 474 |
+
"bbox": [
|
| 475 |
+
1314.5970458984375,
|
| 476 |
+
932.5632934570312,
|
| 477 |
+
1548.0047607421875,
|
| 478 |
+
2449.866943359375
|
| 479 |
+
],
|
| 480 |
+
"label": "shrimp",
|
| 481 |
+
"folder": "250827",
|
| 482 |
+
"confidence": 0.3937889039516449
|
| 483 |
+
}
|
| 484 |
+
],
|
| 485 |
+
"250827_08.jpg": [
|
| 486 |
+
{
|
| 487 |
+
"bbox": [
|
| 488 |
+
842.9571533203125,
|
| 489 |
+
883.6627197265625,
|
| 490 |
+
1188.7823486328125,
|
| 491 |
+
2275.134521484375
|
| 492 |
+
],
|
| 493 |
+
"label": "shrimp",
|
| 494 |
+
"folder": "250827",
|
| 495 |
+
"confidence": 0.524385392665863
|
| 496 |
+
}
|
| 497 |
+
],
|
| 498 |
+
"250827_09.jpg": [
|
| 499 |
+
{
|
| 500 |
+
"bbox": [
|
| 501 |
+
974.3178100585938,
|
| 502 |
+
703.0151977539062,
|
| 503 |
+
1192.342529296875,
|
| 504 |
+
1952.700927734375
|
| 505 |
+
],
|
| 506 |
+
"label": "shrimp",
|
| 507 |
+
"folder": "250827",
|
| 508 |
+
"confidence": 0.23108375072479248
|
| 509 |
+
}
|
| 510 |
+
],
|
| 511 |
+
"250827_10.jpg": [
|
| 512 |
+
{
|
| 513 |
+
"bbox": [
|
| 514 |
+
748.67578125,
|
| 515 |
+
964.2848510742188,
|
| 516 |
+
1073.3507080078125,
|
| 517 |
+
2511.260009765625
|
| 518 |
+
],
|
| 519 |
+
"label": "shrimp",
|
| 520 |
+
"folder": "250827",
|
| 521 |
+
"confidence": 0.3940398097038269
|
| 522 |
+
}
|
| 523 |
+
],
|
| 524 |
+
"250825_01.jpg": [
|
| 525 |
+
{
|
| 526 |
+
"bbox": [
|
| 527 |
+
1218.03515625,
|
| 528 |
+
591.1394653320312,
|
| 529 |
+
1362.5738525390625,
|
| 530 |
+
1683.4329833984375
|
| 531 |
+
],
|
| 532 |
+
"label": "shrimp",
|
| 533 |
+
"folder": "250825",
|
| 534 |
+
"confidence": 0.5618760585784912
|
| 535 |
+
}
|
| 536 |
+
],
|
| 537 |
+
"250825_02.jpg": [
|
| 538 |
+
{
|
| 539 |
+
"bbox": [
|
| 540 |
+
1250.1361083984375,
|
| 541 |
+
1452.21875,
|
| 542 |
+
1377.2449951171875,
|
| 543 |
+
2385.598876953125
|
| 544 |
+
],
|
| 545 |
+
"label": "shrimp",
|
| 546 |
+
"folder": "250825",
|
| 547 |
+
"confidence": 0.13898873329162598
|
| 548 |
+
}
|
| 549 |
+
],
|
| 550 |
+
"250825_03.jpg": [
|
| 551 |
+
{
|
| 552 |
+
"bbox": [
|
| 553 |
+
1085.166015625,
|
| 554 |
+
919.67236328125,
|
| 555 |
+
1291.9251708984375,
|
| 556 |
+
2014.890625
|
| 557 |
+
],
|
| 558 |
+
"label": "shrimp",
|
| 559 |
+
"folder": "250825",
|
| 560 |
+
"confidence": 0.27626752853393555
|
| 561 |
+
}
|
| 562 |
+
],
|
| 563 |
+
"250825_04.jpg": [
|
| 564 |
+
{
|
| 565 |
+
"bbox": [
|
| 566 |
+
1417.811279296875,
|
| 567 |
+
1186.5592041015625,
|
| 568 |
+
1581.043701171875,
|
| 569 |
+
2208.287841796875
|
| 570 |
+
],
|
| 571 |
+
"label": "shrimp",
|
| 572 |
+
"folder": "250825",
|
| 573 |
+
"confidence": 0.516167402267456
|
| 574 |
+
}
|
| 575 |
+
],
|
| 576 |
+
"250825_05.jpg": [
|
| 577 |
+
{
|
| 578 |
+
"bbox": [
|
| 579 |
+
1244.444580078125,
|
| 580 |
+
749.85302734375,
|
| 581 |
+
1458.3443603515625,
|
| 582 |
+
1949.9169921875
|
| 583 |
+
],
|
| 584 |
+
"label": "shrimp",
|
| 585 |
+
"folder": "250825",
|
| 586 |
+
"confidence": 0.13308075070381165
|
| 587 |
+
}
|
| 588 |
+
],
|
| 589 |
+
"250825_06.jpg": [
|
| 590 |
+
{
|
| 591 |
+
"bbox": [
|
| 592 |
+
1427.8709716796875,
|
| 593 |
+
728.7554931640625,
|
| 594 |
+
1579.3043212890625,
|
| 595 |
+
1905.975341796875
|
| 596 |
+
],
|
| 597 |
+
"label": "shrimp",
|
| 598 |
+
"folder": "250825",
|
| 599 |
+
"confidence": 0.20085805654525757
|
| 600 |
+
}
|
| 601 |
+
],
|
| 602 |
+
"250825_07.jpg": [
|
| 603 |
+
{
|
| 604 |
+
"bbox": [
|
| 605 |
+
1222.7392578125,
|
| 606 |
+
1030.6048583984375,
|
| 607 |
+
1427.1439208984375,
|
| 608 |
+
2347.765869140625
|
| 609 |
+
],
|
| 610 |
+
"label": "shrimp",
|
| 611 |
+
"folder": "250825",
|
| 612 |
+
"confidence": 0.33714479207992554
|
| 613 |
+
}
|
| 614 |
+
],
|
| 615 |
+
"250825_08.jpg": [
|
| 616 |
+
{
|
| 617 |
+
"bbox": [
|
| 618 |
+
1181.7100830078125,
|
| 619 |
+
920.5298461914062,
|
| 620 |
+
1492.75732421875,
|
| 621 |
+
2420.435546875
|
| 622 |
+
],
|
| 623 |
+
"label": "shrimp",
|
| 624 |
+
"folder": "250825",
|
| 625 |
+
"confidence": 0.3000471889972687
|
| 626 |
+
}
|
| 627 |
+
],
|
| 628 |
+
"250825_09.jpg": [
|
| 629 |
+
{
|
| 630 |
+
"bbox": [
|
| 631 |
+
1313.0550537109375,
|
| 632 |
+
955.22021484375,
|
| 633 |
+
1581.7991943359375,
|
| 634 |
+
2202.865478515625
|
| 635 |
+
],
|
| 636 |
+
"label": "shrimp",
|
| 637 |
+
"folder": "250825",
|
| 638 |
+
"confidence": 0.2484617382287979
|
| 639 |
+
}
|
| 640 |
+
],
|
| 641 |
+
"250825_10.jpg": [
|
| 642 |
+
{
|
| 643 |
+
"bbox": [
|
| 644 |
+
1381.0965576171875,
|
| 645 |
+
707.5077514648438,
|
| 646 |
+
1551.261474609375,
|
| 647 |
+
2127.498046875
|
| 648 |
+
],
|
| 649 |
+
"label": "shrimp",
|
| 650 |
+
"folder": "250825",
|
| 651 |
+
"confidence": 0.15676349401474
|
| 652 |
+
}
|
| 653 |
+
],
|
| 654 |
+
"251017_01.jpg": [
|
| 655 |
+
{
|
| 656 |
+
"bbox": [
|
| 657 |
+
484.5128917694092,
|
| 658 |
+
326.79282665252686,
|
| 659 |
+
601.3697719573975,
|
| 660 |
+
1076.2871170043945
|
| 661 |
+
],
|
| 662 |
+
"folder": "251017"
|
| 663 |
+
}
|
| 664 |
+
],
|
| 665 |
+
"251017_02.jpg": [
|
| 666 |
+
{
|
| 667 |
+
"bbox": [
|
| 668 |
+
376.5924644470215,
|
| 669 |
+
420.32711029052734,
|
| 670 |
+
1162.6642608642578,
|
| 671 |
+
560.7167053222656
|
| 672 |
+
],
|
| 673 |
+
"folder": "251017"
|
| 674 |
+
}
|
| 675 |
+
],
|
| 676 |
+
"251017_03.jpg": [
|
| 677 |
+
{
|
| 678 |
+
"bbox": [
|
| 679 |
+
393.7764358520508,
|
| 680 |
+
517.4064683914185,
|
| 681 |
+
994.1136074066162,
|
| 682 |
+
604.6661758422852
|
| 683 |
+
],
|
| 684 |
+
"folder": "251017"
|
| 685 |
+
}
|
| 686 |
+
],
|
| 687 |
+
"251017_04.jpg": [
|
| 688 |
+
{
|
| 689 |
+
"bbox": [
|
| 690 |
+
517.5228261947632,
|
| 691 |
+
267.38592624664307,
|
| 692 |
+
629.7006607055664,
|
| 693 |
+
1012.4417304992676
|
| 694 |
+
],
|
| 695 |
+
"folder": "251017"
|
| 696 |
+
}
|
| 697 |
+
],
|
| 698 |
+
"251017_05.jpg": [
|
| 699 |
+
{
|
| 700 |
+
"bbox": [
|
| 701 |
+
420.3295135498047,
|
| 702 |
+
411.76806926727295,
|
| 703 |
+
1142.9505920410156,
|
| 704 |
+
549.7662210464478
|
| 705 |
+
],
|
| 706 |
+
"folder": "251017"
|
| 707 |
+
}
|
| 708 |
+
],
|
| 709 |
+
"251017_06.jpg": [
|
| 710 |
+
{
|
| 711 |
+
"bbox": [
|
| 712 |
+
319.4859838485718,
|
| 713 |
+
569.7392749786377,
|
| 714 |
+
1006.1090087890625,
|
| 715 |
+
683.4247207641602
|
| 716 |
+
],
|
| 717 |
+
"folder": "251017"
|
| 718 |
+
}
|
| 719 |
+
],
|
| 720 |
+
"251017_07.jpg": [
|
| 721 |
+
{
|
| 722 |
+
"bbox": [
|
| 723 |
+
368.63690853118896,
|
| 724 |
+
467.8817367553711,
|
| 725 |
+
1213.7968063354492,
|
| 726 |
+
593.3969593048096
|
| 727 |
+
],
|
| 728 |
+
"folder": "251017"
|
| 729 |
+
}
|
| 730 |
+
],
|
| 731 |
+
"251017_08.jpg": [
|
| 732 |
+
{
|
| 733 |
+
"bbox": [
|
| 734 |
+
386.44689559936523,
|
| 735 |
+
269.8518371582031,
|
| 736 |
+
551.1846446990967,
|
| 737 |
+
1175.0948524475098
|
| 738 |
+
],
|
| 739 |
+
"folder": "251017"
|
| 740 |
+
}
|
| 741 |
+
],
|
| 742 |
+
"251017_09.jpg": [
|
| 743 |
+
{
|
| 744 |
+
"bbox": [
|
| 745 |
+
377.7911567687988,
|
| 746 |
+
208.81319046020508,
|
| 747 |
+
578.8406181335449,
|
| 748 |
+
1194.684886932373
|
| 749 |
+
],
|
| 750 |
+
"folder": "251017"
|
| 751 |
+
}
|
| 752 |
+
],
|
| 753 |
+
"251017_10.jpg": [
|
| 754 |
+
{
|
| 755 |
+
"bbox": [
|
| 756 |
+
285.74469089508057,
|
| 757 |
+
523.7431955337524,
|
| 758 |
+
1143.4105491638184,
|
| 759 |
+
660.8415603637695
|
| 760 |
+
],
|
| 761 |
+
"folder": "251017"
|
| 762 |
+
}
|
| 763 |
+
],
|
| 764 |
+
"251015_01.jpg": [
|
| 765 |
+
{
|
| 766 |
+
"bbox": [
|
| 767 |
+
439.0369176864624,
|
| 768 |
+
412.4263286590576,
|
| 769 |
+
543.5421466827393,
|
| 770 |
+
1110.1425647735596
|
| 771 |
+
],
|
| 772 |
+
"folder": "251015"
|
| 773 |
+
}
|
| 774 |
+
],
|
| 775 |
+
"251015_02.jpg": [
|
| 776 |
+
{
|
| 777 |
+
"bbox": [
|
| 778 |
+
280.5061197280884,
|
| 779 |
+
504.64516162872314,
|
| 780 |
+
973.9743614196777,
|
| 781 |
+
603.9405250549316
|
| 782 |
+
],
|
| 783 |
+
"folder": "251015"
|
| 784 |
+
}
|
| 785 |
+
],
|
| 786 |
+
"251015_03.jpg": [
|
| 787 |
+
{
|
| 788 |
+
"bbox": [
|
| 789 |
+
537.2243785858154,
|
| 790 |
+
194.9091672897339,
|
| 791 |
+
649.5208072662354,
|
| 792 |
+
1010.6131172180176
|
| 793 |
+
],
|
| 794 |
+
"folder": "251015"
|
| 795 |
+
}
|
| 796 |
+
],
|
| 797 |
+
"251015_04.jpg": [
|
| 798 |
+
{
|
| 799 |
+
"bbox": [
|
| 800 |
+
506.13531589508057,
|
| 801 |
+
441.81682109832764,
|
| 802 |
+
589.7704410552979,
|
| 803 |
+
1114.9834632873535
|
| 804 |
+
],
|
| 805 |
+
"folder": "251015"
|
| 806 |
+
}
|
| 807 |
+
],
|
| 808 |
+
"251015_05.jpg": [
|
| 809 |
+
{
|
| 810 |
+
"bbox": [
|
| 811 |
+
468.72180938720703,
|
| 812 |
+
322.5778102874756,
|
| 813 |
+
592.9580307006836,
|
| 814 |
+
1100.9521007537842
|
| 815 |
+
],
|
| 816 |
+
"folder": "251015"
|
| 817 |
+
}
|
| 818 |
+
],
|
| 819 |
+
"251015_06.jpg": [
|
| 820 |
+
{
|
| 821 |
+
"bbox": [
|
| 822 |
+
334.1108512878418,
|
| 823 |
+
431.6416549682617,
|
| 824 |
+
1079.674310684204,
|
| 825 |
+
573.8564586639404
|
| 826 |
+
],
|
| 827 |
+
"folder": "251015"
|
| 828 |
+
}
|
| 829 |
+
],
|
| 830 |
+
"251015_07.jpg": [
|
| 831 |
+
{
|
| 832 |
+
"bbox": [
|
| 833 |
+
357.3750686645508,
|
| 834 |
+
385.0168561935425,
|
| 835 |
+
1045.3876781463623,
|
| 836 |
+
466.7943286895752
|
| 837 |
+
],
|
| 838 |
+
"folder": "251015"
|
| 839 |
+
}
|
| 840 |
+
],
|
| 841 |
+
"251015_08.jpg": [
|
| 842 |
+
{
|
| 843 |
+
"bbox": [
|
| 844 |
+
231.03424310684204,
|
| 845 |
+
367.16761589050293,
|
| 846 |
+
1024.8803329467773,
|
| 847 |
+
511.72733306884766
|
| 848 |
+
],
|
| 849 |
+
"folder": "251015"
|
| 850 |
+
}
|
| 851 |
+
],
|
| 852 |
+
"251015_09.jpg": [
|
| 853 |
+
{
|
| 854 |
+
"bbox": [
|
| 855 |
+
280.447940826416,
|
| 856 |
+
494.4591474533081,
|
| 857 |
+
1196.7291259765625,
|
| 858 |
+
651.3949489593506
|
| 859 |
+
],
|
| 860 |
+
"folder": "251015"
|
| 861 |
+
}
|
| 862 |
+
],
|
| 863 |
+
"251015_10.jpg": [
|
| 864 |
+
{
|
| 865 |
+
"bbox": [
|
| 866 |
+
285.3676128387451,
|
| 867 |
+
414.03454303741455,
|
| 868 |
+
423.2767105102539,
|
| 869 |
+
1214.5852088928223
|
| 870 |
+
],
|
| 871 |
+
"folder": "251015"
|
| 872 |
+
}
|
| 873 |
+
],
|
| 874 |
+
"251013_01.jpg": [
|
| 875 |
+
{
|
| 876 |
+
"bbox": [
|
| 877 |
+
1286.7757736206054,
|
| 878 |
+
1161.5370491027832,
|
| 879 |
+
2224.8296180725097,
|
| 880 |
+
1385.0031333923341
|
| 881 |
+
],
|
| 882 |
+
"folder": "251013"
|
| 883 |
+
}
|
| 884 |
+
],
|
| 885 |
+
"251013_02.jpg": [
|
| 886 |
+
{
|
| 887 |
+
"bbox": [
|
| 888 |
+
1181.9921714782715,
|
| 889 |
+
1215.7155738830568,
|
| 890 |
+
2172.6354858398436,
|
| 891 |
+
1368.423062133789
|
| 892 |
+
],
|
| 893 |
+
"folder": "251013"
|
| 894 |
+
}
|
| 895 |
+
],
|
| 896 |
+
"251013_03.jpg": [
|
| 897 |
+
{
|
| 898 |
+
"bbox": [
|
| 899 |
+
1150.5474178314207,
|
| 900 |
+
1127.1829040527343,
|
| 901 |
+
2303.570297241211,
|
| 902 |
+
1360.058766937256
|
| 903 |
+
],
|
| 904 |
+
"folder": "251013"
|
| 905 |
+
}
|
| 906 |
+
],
|
| 907 |
+
"251013_04.jpg": [
|
| 908 |
+
{
|
| 909 |
+
"bbox": [
|
| 910 |
+
1633.8661323547362,
|
| 911 |
+
1242.2236000061034,
|
| 912 |
+
1828.0880714416503,
|
| 913 |
+
2243.6303428649903
|
| 914 |
+
],
|
| 915 |
+
"folder": "251013"
|
| 916 |
+
}
|
| 917 |
+
],
|
| 918 |
+
"251013_05.jpg": [
|
| 919 |
+
{
|
| 920 |
+
"bbox": [
|
| 921 |
+
1332.1027862548826,
|
| 922 |
+
1127.1942462921143,
|
| 923 |
+
2307.717704772949,
|
| 924 |
+
1271.2180732727052
|
| 925 |
+
],
|
| 926 |
+
"folder": "251013"
|
| 927 |
+
}
|
| 928 |
+
],
|
| 929 |
+
"251013_06.jpg": [
|
| 930 |
+
{
|
| 931 |
+
"bbox": [
|
| 932 |
+
1151.8778076171875,
|
| 933 |
+
971.100341796875,
|
| 934 |
+
2289.25830078125,
|
| 935 |
+
1124.097900390625
|
| 936 |
+
],
|
| 937 |
+
"folder": "251013"
|
| 938 |
+
}
|
| 939 |
+
],
|
| 940 |
+
"251013_07.jpg": [
|
| 941 |
+
{
|
| 942 |
+
"bbox": [
|
| 943 |
+
1254.763265991211,
|
| 944 |
+
1416.347661590576,
|
| 945 |
+
2448.912463378906,
|
| 946 |
+
1621.5113662719727
|
| 947 |
+
],
|
| 948 |
+
"folder": "251013"
|
| 949 |
+
}
|
| 950 |
+
],
|
| 951 |
+
"251013_08.jpg": [
|
| 952 |
+
{
|
| 953 |
+
"bbox": [
|
| 954 |
+
1066.3645324707031,
|
| 955 |
+
1132.9642360687255,
|
| 956 |
+
2114.8522689819333,
|
| 957 |
+
1302.2054992675783
|
| 958 |
+
],
|
| 959 |
+
"folder": "251013"
|
| 960 |
+
}
|
| 961 |
+
],
|
| 962 |
+
"251013_09.jpg": [
|
| 963 |
+
{
|
| 964 |
+
"bbox": [
|
| 965 |
+
1080.3885337829588,
|
| 966 |
+
1166.265264892578,
|
| 967 |
+
2268.1090354919434,
|
| 968 |
+
1337.1846801757813
|
| 969 |
+
],
|
| 970 |
+
"folder": "251013"
|
| 971 |
+
}
|
| 972 |
+
],
|
| 973 |
+
"251013_10.jpg": [
|
| 974 |
+
{
|
| 975 |
+
"bbox": [
|
| 976 |
+
1094.5455032348632,
|
| 977 |
+
1097.0262435913087,
|
| 978 |
+
2384.485262298584,
|
| 979 |
+
1338.0954833984374
|
| 980 |
+
],
|
| 981 |
+
"folder": "251013"
|
| 982 |
+
}
|
| 983 |
+
],
|
| 984 |
+
"251010_01.jpg": [
|
| 985 |
+
{
|
| 986 |
+
"bbox": [
|
| 987 |
+
1327.0032012939453,
|
| 988 |
+
874.0308265686035,
|
| 989 |
+
1477.1407806396485,
|
| 990 |
+
1687.9076942443849
|
| 991 |
+
],
|
| 992 |
+
"folder": "251010"
|
| 993 |
+
}
|
| 994 |
+
],
|
| 995 |
+
"251010_02.jpg": [
|
| 996 |
+
{
|
| 997 |
+
"bbox": [
|
| 998 |
+
1399.0542419433593,
|
| 999 |
+
908.7650436401367,
|
| 1000 |
+
1587.7572898864744,
|
| 1001 |
+
1940.7501785278318
|
| 1002 |
+
],
|
| 1003 |
+
"folder": "251010"
|
| 1004 |
+
}
|
| 1005 |
+
],
|
| 1006 |
+
"251010_03.jpg": [
|
| 1007 |
+
{
|
| 1008 |
+
"bbox": [
|
| 1009 |
+
1257.0930618286134,
|
| 1010 |
+
934.811533355713,
|
| 1011 |
+
1372.5052696228026,
|
| 1012 |
+
1816.593032836914
|
| 1013 |
+
],
|
| 1014 |
+
"folder": "251010"
|
| 1015 |
+
}
|
| 1016 |
+
],
|
| 1017 |
+
"251010_04.jpg": [
|
| 1018 |
+
{
|
| 1019 |
+
"bbox": [
|
| 1020 |
+
1353.0094581604003,
|
| 1021 |
+
853.9553482055665,
|
| 1022 |
+
1485.8469123840332,
|
| 1023 |
+
1777.8151290893554
|
| 1024 |
+
],
|
| 1025 |
+
"folder": "251010"
|
| 1026 |
+
}
|
| 1027 |
+
],
|
| 1028 |
+
"251010_05.jpg": [
|
| 1029 |
+
{
|
| 1030 |
+
"bbox": [
|
| 1031 |
+
1358.5506057739258,
|
| 1032 |
+
873.9938037872314,
|
| 1033 |
+
1506.960740661621,
|
| 1034 |
+
1875.4317199707032
|
| 1035 |
+
],
|
| 1036 |
+
"folder": "251010"
|
| 1037 |
+
}
|
| 1038 |
+
],
|
| 1039 |
+
"251010_06.jpg": [
|
| 1040 |
+
{
|
| 1041 |
+
"bbox": [
|
| 1042 |
+
1456.5663864135743,
|
| 1043 |
+
1133.630075454712,
|
| 1044 |
+
1591.5584381103515,
|
| 1045 |
+
2062.2530975341797
|
| 1046 |
+
],
|
| 1047 |
+
"folder": "251010"
|
| 1048 |
+
}
|
| 1049 |
+
],
|
| 1050 |
+
"251010_07.jpg": [
|
| 1051 |
+
{
|
| 1052 |
+
"bbox": [
|
| 1053 |
+
1290.345083618164,
|
| 1054 |
+
833.6252758026124,
|
| 1055 |
+
1506.3098815917967,
|
| 1056 |
+
1873.7410842895508
|
| 1057 |
+
],
|
| 1058 |
+
"folder": "251010"
|
| 1059 |
+
}
|
| 1060 |
+
],
|
| 1061 |
+
"251010_08.jpg": [
|
| 1062 |
+
{
|
| 1063 |
+
"bbox": [
|
| 1064 |
+
1339.2857765197753,
|
| 1065 |
+
853.2016956329346,
|
| 1066 |
+
1536.7162139892578,
|
| 1067 |
+
1860.9929779052734
|
| 1068 |
+
],
|
| 1069 |
+
"folder": "251010"
|
| 1070 |
+
}
|
| 1071 |
+
],
|
| 1072 |
+
"251010_09.jpg": [
|
| 1073 |
+
{
|
| 1074 |
+
"bbox": [
|
| 1075 |
+
1370.5272972106934,
|
| 1076 |
+
1252.2686866760255,
|
| 1077 |
+
1555.1548431396484,
|
| 1078 |
+
2431.023968505859
|
| 1079 |
+
],
|
| 1080 |
+
"folder": "251010"
|
| 1081 |
+
}
|
| 1082 |
+
],
|
| 1083 |
+
"251010_10.jpg": [
|
| 1084 |
+
{
|
| 1085 |
+
"bbox": [
|
| 1086 |
+
1316.39913482666,
|
| 1087 |
+
958.0380142211912,
|
| 1088 |
+
1476.0563484191894,
|
| 1089 |
+
2228.275661468506
|
| 1090 |
+
],
|
| 1091 |
+
"folder": "251010"
|
| 1092 |
+
}
|
| 1093 |
+
],
|
| 1094 |
+
"251008_01.jpg": [
|
| 1095 |
+
{
|
| 1096 |
+
"bbox": [
|
| 1097 |
+
504.01527404785156,
|
| 1098 |
+
465.6670331954956,
|
| 1099 |
+
964.8762893676758,
|
| 1100 |
+
538.529782295227
|
| 1101 |
+
],
|
| 1102 |
+
"folder": "251008"
|
| 1103 |
+
}
|
| 1104 |
+
],
|
| 1105 |
+
"251008_02.jpg": [
|
| 1106 |
+
{
|
| 1107 |
+
"bbox": [
|
| 1108 |
+
386.9237422943115,
|
| 1109 |
+
564.5150566101074,
|
| 1110 |
+
950.2494525909424,
|
| 1111 |
+
635.4513263702393
|
| 1112 |
+
],
|
| 1113 |
+
"folder": "251008"
|
| 1114 |
+
}
|
| 1115 |
+
],
|
| 1116 |
+
"251008_04.jpg": [
|
| 1117 |
+
{
|
| 1118 |
+
"bbox": [
|
| 1119 |
+
618.7960052490234,
|
| 1120 |
+
507.7793788909912,
|
| 1121 |
+
1048.5748672485352,
|
| 1122 |
+
570.3174591064453
|
| 1123 |
+
],
|
| 1124 |
+
"folder": "251008"
|
| 1125 |
+
}
|
| 1126 |
+
],
|
| 1127 |
+
"251008_05.jpg": [
|
| 1128 |
+
{
|
| 1129 |
+
"bbox": [
|
| 1130 |
+
448.00551414489746,
|
| 1131 |
+
460.2817964553833,
|
| 1132 |
+
1001.2835311889648,
|
| 1133 |
+
569.5269203186035
|
| 1134 |
+
],
|
| 1135 |
+
"folder": "251008"
|
| 1136 |
+
}
|
| 1137 |
+
],
|
| 1138 |
+
"251008_06.jpg": [
|
| 1139 |
+
{
|
| 1140 |
+
"bbox": [
|
| 1141 |
+
620.1509761810303,
|
| 1142 |
+
478.12272548675537,
|
| 1143 |
+
1066.515998840332,
|
| 1144 |
+
546.765718460083
|
| 1145 |
+
],
|
| 1146 |
+
"folder": "251008"
|
| 1147 |
+
}
|
| 1148 |
+
],
|
| 1149 |
+
"251008_07.jpg": [
|
| 1150 |
+
{
|
| 1151 |
+
"bbox": [
|
| 1152 |
+
677.2587585449219,
|
| 1153 |
+
353.7098979949951,
|
| 1154 |
+
1100.5819988250732,
|
| 1155 |
+
430.5659294128418
|
| 1156 |
+
],
|
| 1157 |
+
"folder": "251008"
|
| 1158 |
+
}
|
| 1159 |
+
],
|
| 1160 |
+
"251008_08.jpg": [
|
| 1161 |
+
{
|
| 1162 |
+
"bbox": [
|
| 1163 |
+
407.7633047103882,
|
| 1164 |
+
565.507001876831,
|
| 1165 |
+
949.1779327392578,
|
| 1166 |
+
647.0377063751221
|
| 1167 |
+
],
|
| 1168 |
+
"folder": "251008"
|
| 1169 |
+
}
|
| 1170 |
+
],
|
| 1171 |
+
"251008_09.jpg": [
|
| 1172 |
+
{
|
| 1173 |
+
"bbox": [
|
| 1174 |
+
223.97058010101318,
|
| 1175 |
+
518.1000089645386,
|
| 1176 |
+
852.5325965881348,
|
| 1177 |
+
627.9448795318604
|
| 1178 |
+
],
|
| 1179 |
+
"folder": "251008"
|
| 1180 |
+
}
|
| 1181 |
+
],
|
| 1182 |
+
"251008_10.jpg": [
|
| 1183 |
+
{
|
| 1184 |
+
"bbox": [
|
| 1185 |
+
381.0610580444336,
|
| 1186 |
+
563.8735866546631,
|
| 1187 |
+
990.9029197692871,
|
| 1188 |
+
644.4745635986328
|
| 1189 |
+
],
|
| 1190 |
+
"folder": "251008"
|
| 1191 |
+
}
|
| 1192 |
+
],
|
| 1193 |
+
"251007_01.jpg": [
|
| 1194 |
+
{
|
| 1195 |
+
"bbox": [
|
| 1196 |
+
138.52840423583984,
|
| 1197 |
+
247.98247814178467,
|
| 1198 |
+
262.4996829032898,
|
| 1199 |
+
780.9294891357422
|
| 1200 |
+
],
|
| 1201 |
+
"folder": "251007"
|
| 1202 |
+
}
|
| 1203 |
+
],
|
| 1204 |
+
"251007_02.jpg": [
|
| 1205 |
+
{
|
| 1206 |
+
"bbox": [
|
| 1207 |
+
604.8854732513428,
|
| 1208 |
+
546.4356708526611,
|
| 1209 |
+
674.0682983398438,
|
| 1210 |
+
993.3078479766846
|
| 1211 |
+
],
|
| 1212 |
+
"folder": "251007"
|
| 1213 |
+
}
|
| 1214 |
+
]
|
| 1215 |
+
}
|
interactive_validation.py
CHANGED
|
@@ -29,8 +29,11 @@ def interactive_detect(image, confidence, filter_threshold, show_all=False):
|
|
| 29 |
# RT-DETR ๊ฒ์ถ
|
| 30 |
all_detections = detect_with_rtdetr(image, processor, model, confidence)
|
| 31 |
|
| 32 |
-
# ํํฐ
|
| 33 |
-
|
|
|
|
|
|
|
|
|
|
| 34 |
|
| 35 |
# ์๊ฐํ
|
| 36 |
img = image.copy()
|
|
@@ -45,13 +48,29 @@ def interactive_detect(image, confidence, filter_threshold, show_all=False):
|
|
| 45 |
font_large = ImageFont.load_default()
|
| 46 |
font_small = ImageFont.load_default()
|
| 47 |
|
| 48 |
-
#
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 49 |
if show_all:
|
| 50 |
-
for det in
|
| 51 |
-
|
| 52 |
-
|
|
|
|
| 53 |
|
| 54 |
-
# ํํฐ๋ง๋ ๊ฒฐ๊ณผ
|
| 55 |
for idx, det in enumerate(filtered_detections, 1):
|
| 56 |
x1, y1, x2, y2 = det['bbox']
|
| 57 |
score = det['filter_score']
|
|
@@ -64,11 +83,11 @@ def interactive_detect(image, confidence, filter_threshold, show_all=False):
|
|
| 64 |
else:
|
| 65 |
color = "orange"
|
| 66 |
|
| 67 |
-
# ๋ฐ์ค
|
| 68 |
-
draw.rectangle([x1, y1, x2, y2], outline=color, width=
|
| 69 |
|
| 70 |
# ๋ผ๋ฒจ
|
| 71 |
-
label = f"
|
| 72 |
bbox = draw.textbbox((x1, y1 - 25), label, font=font)
|
| 73 |
draw.rectangle(bbox, fill=color)
|
| 74 |
draw.text((x1, y1 - 25), label, fill="black", font=font)
|
|
@@ -78,7 +97,7 @@ def interactive_detect(image, confidence, filter_threshold, show_all=False):
|
|
| 78 |
draw.text((x1, y2 + 5), details, fill=color, font=font_small)
|
| 79 |
|
| 80 |
# ํค๋
|
| 81 |
-
header = f"
|
| 82 |
header_bbox = draw.textbbox((10, 10), header, font=font_large)
|
| 83 |
draw.rectangle([5, 5, header_bbox[2]+10, header_bbox[3]+10],
|
| 84 |
fill="black", outline="lime", width=2)
|
|
@@ -88,13 +107,13 @@ def interactive_detect(image, confidence, filter_threshold, show_all=False):
|
|
| 88 |
info = f"""
|
| 89 |
### ๐ ๊ฒ์ถ ๊ฒฐ๊ณผ
|
| 90 |
|
| 91 |
-
- **์ ์ฒด ๊ฒ์ถ**: {len(
|
| 92 |
- **ํํฐ๋ง ํ**: {len(filtered_detections)}๊ฐ
|
| 93 |
-
- **์ ๊ฑฐ๋จ**: {len(
|
| 94 |
|
| 95 |
---
|
| 96 |
|
| 97 |
-
### ๐ฏ ๊ฒ์ถ๋ ๊ฐ์ฒด ์์ธ
|
| 98 |
|
| 99 |
"""
|
| 100 |
|
|
@@ -103,17 +122,41 @@ def interactive_detect(image, confidence, filter_threshold, show_all=False):
|
|
| 103 |
**#{idx} - ์ ์: {det['filter_score']:.0f}์ ** (RT-DETR ์ ๋ขฐ๋: {det['confidence']:.0%})
|
| 104 |
|
| 105 |
"""
|
| 106 |
-
# ์ฃผ์ ํน์ง๋ง
|
| 107 |
-
for reason in det['filter_reasons'][:
|
| 108 |
info += f"- {reason}\n"
|
| 109 |
|
| 110 |
if not filtered_detections:
|
| 111 |
info += """
|
| 112 |
โ ๏ธ **๊ฒ์ถ๋ ๊ฐ์ฒด๊ฐ ์์ต๋๋ค.**
|
| 113 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 114 |
**์กฐ์ ๋ฐฉ๋ฒ:**
|
| 115 |
1. **์ ๋ขฐ๋ ์๊ณ๊ฐ**์ ๋ฎ์ถฐ๋ณด์ธ์ (0.2~0.3)
|
| 116 |
-
2. **ํํฐ ์ ์ ์๊ณ๊ฐ**์ ๋ฎ์ถฐ๋ณด์ธ์ (
|
| 117 |
3. "์ ์ฒด ๊ฒ์ถ ํ์"๋ฅผ ์ผ์ ์๋ณธ ๊ฒ์ถ ๊ฒฐ๊ณผ๋ฅผ ํ์ธํ์ธ์
|
| 118 |
"""
|
| 119 |
|
|
@@ -204,7 +247,14 @@ def analyze_single_detection(image, x1, y1, x2, y2):
|
|
| 204 |
with gr.Blocks(title="๐งช ์์ฐ ๊ฒ์ถ ๋ํํ ๊ฒ์ฆ", theme=gr.themes.Soft()) as demo:
|
| 205 |
|
| 206 |
gr.Markdown("""
|
| 207 |
-
# ๐งช ์์ฐ ๊ฒ์ถ ๋ํํ ๊ฒ์ฆ ๋๊ตฌ
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 208 |
|
| 209 |
์ค์๊ฐ์ผ๋ก ํ๋ผ๋ฏธํฐ๋ฅผ ์กฐ์ ํ๋ฉฐ ๊ฒ์ถ ๊ฒฐ๊ณผ๋ฅผ ํ์ธํ ์ ์์ต๋๋ค.
|
| 210 |
|
|
@@ -219,15 +269,17 @@ with gr.Blocks(title="๐งช ์์ฐ ๊ฒ์ถ ๋ํํ ๊ฒ์ฆ", theme=gr.themes.Soft
|
|
| 219 |
input_image = gr.Image(label="์
๋ ฅ ์ด๋ฏธ์ง", type="pil")
|
| 220 |
|
| 221 |
confidence_slider = gr.Slider(
|
| 222 |
-
0.
|
|
|
|
| 223 |
label="RT-DETR ์ ๋ขฐ๋ ์๊ณ๊ฐ",
|
| 224 |
-
info="๋ฎ์์๋ก ๋ ๋ง์ด ๊ฒ์ถ"
|
| 225 |
)
|
| 226 |
|
| 227 |
filter_slider = gr.Slider(
|
| 228 |
-
|
|
|
|
| 229 |
label="ํํฐ ์ ์ ์๊ณ๊ฐ",
|
| 230 |
-
info="๋์์๋ก ์๊ฒฉํ๊ฒ ํํฐ๋ง"
|
| 231 |
)
|
| 232 |
|
| 233 |
show_all_check = gr.Checkbox(
|
|
@@ -237,17 +289,24 @@ with gr.Blocks(title="๐งช ์์ฐ ๊ฒ์ถ ๋ํํ ๊ฒ์ฆ", theme=gr.themes.Soft
|
|
| 237 |
|
| 238 |
detect_btn = gr.Button("๐ ๊ฒ์ถ ์คํ", variant="primary", size="lg")
|
| 239 |
|
| 240 |
-
# ์์ ์ด๋ฏธ์ง ์ถ๊ฐ
|
| 241 |
import os
|
| 242 |
import glob
|
| 243 |
-
example_images =
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 244 |
if example_images:
|
| 245 |
-
#
|
| 246 |
-
examples_list = [[img, 0.
|
| 247 |
gr.Examples(
|
| 248 |
examples=examples_list,
|
| 249 |
inputs=[input_image, confidence_slider, filter_slider, show_all_check],
|
| 250 |
-
label="๐ท ์์
|
| 251 |
)
|
| 252 |
|
| 253 |
with gr.Column():
|
|
@@ -263,9 +322,21 @@ with gr.Blocks(title="๐งช ์์ฐ ๊ฒ์ถ ๋ํํ ๊ฒ์ฆ", theme=gr.themes.Soft
|
|
| 263 |
gr.Markdown("""
|
| 264 |
### ๐ก ์ฌ์ฉ ํ
|
| 265 |
|
| 266 |
-
-
|
| 267 |
-
-
|
| 268 |
-
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 269 |
""")
|
| 270 |
|
| 271 |
# ํญ 2: ์๋ ๋ถ์
|
|
@@ -327,6 +398,5 @@ with gr.Blocks(title="๐งช ์์ฐ ๊ฒ์ถ ๋ํํ ๊ฒ์ฆ", theme=gr.themes.Soft
|
|
| 327 |
if __name__ == "__main__":
|
| 328 |
demo.launch(
|
| 329 |
server_name="0.0.0.0",
|
| 330 |
-
server_port=7861, # ๋ฉ์ธ ์ฑ๊ณผ ๋ค๋ฅธ ํฌํธ
|
| 331 |
share=False
|
| 332 |
)
|
|
|
|
| 29 |
# RT-DETR ๊ฒ์ถ
|
| 30 |
all_detections = detect_with_rtdetr(image, processor, model, confidence)
|
| 31 |
|
| 32 |
+
# ํํฐ ์ ์ ๊ณ์ฐ (์๊ณ๊ฐ 0์ผ๋ก ๋ชจ๋ ๊ฐ์ฒด ๋ฐํ)
|
| 33 |
+
all_detections_scored = apply_universal_filter(all_detections, image, threshold=0)
|
| 34 |
+
|
| 35 |
+
# ํํฐ ์ ์ฉ (์๊ณ๊ฐ ์ ์ฉ)
|
| 36 |
+
filtered_detections = [det for det in all_detections_scored if det['filter_score'] >= filter_threshold]
|
| 37 |
|
| 38 |
# ์๊ฐํ
|
| 39 |
img = image.copy()
|
|
|
|
| 48 |
font_large = ImageFont.load_default()
|
| 49 |
font_small = ImageFont.load_default()
|
| 50 |
|
| 51 |
+
# ์ ๊ฑฐ๋ ๊ฐ์ฒด ๋จผ์ ํ์ (๋นจ๊ฐ์)
|
| 52 |
+
rejected_detections = [det for det in all_detections_scored if det['filter_score'] < filter_threshold]
|
| 53 |
+
for idx, det in enumerate(rejected_detections, 1):
|
| 54 |
+
x1, y1, x2, y2 = det['bbox']
|
| 55 |
+
score = det['filter_score']
|
| 56 |
+
|
| 57 |
+
# ๋นจ๊ฐ์ ๋ฐ์ค (์ ๊ฑฐ๋จ)
|
| 58 |
+
draw.rectangle([x1, y1, x2, y2], outline="red", width=4)
|
| 59 |
+
|
| 60 |
+
# ๋ผ๋ฒจ (์๊ฒ)
|
| 61 |
+
label = f"โ{idx} {score:.0f}์ "
|
| 62 |
+
bbox = draw.textbbox((x1, y1 - 20), label, font=font_small)
|
| 63 |
+
draw.rectangle(bbox, fill="red")
|
| 64 |
+
draw.text((x1, y1 - 20), label, fill="white", font=font_small)
|
| 65 |
+
|
| 66 |
+
# ์ ์ฒด ๊ฒ์ถ ํ์ (์ต์
) - ํ์
|
| 67 |
if show_all:
|
| 68 |
+
for det in all_detections_scored:
|
| 69 |
+
if det not in filtered_detections and det not in rejected_detections:
|
| 70 |
+
x1, y1, x2, y2 = det['bbox']
|
| 71 |
+
draw.rectangle([x1, y1, x2, y2], outline="gray", width=2)
|
| 72 |
|
| 73 |
+
# ํํฐ๋ง๋ ๊ฒฐ๊ณผ (ํต๊ณผ) - ๋
น์/๋
ธ๋์/์ฃผํฉ์
|
| 74 |
for idx, det in enumerate(filtered_detections, 1):
|
| 75 |
x1, y1, x2, y2 = det['bbox']
|
| 76 |
score = det['filter_score']
|
|
|
|
| 83 |
else:
|
| 84 |
color = "orange"
|
| 85 |
|
| 86 |
+
# ๋ฐ์ค (๋๊ป๊ฒ)
|
| 87 |
+
draw.rectangle([x1, y1, x2, y2], outline=color, width=5)
|
| 88 |
|
| 89 |
# ๋ผ๋ฒจ
|
| 90 |
+
label = f"โ#{idx} {score:.0f}์ "
|
| 91 |
bbox = draw.textbbox((x1, y1 - 25), label, font=font)
|
| 92 |
draw.rectangle(bbox, fill=color)
|
| 93 |
draw.text((x1, y1 - 25), label, fill="black", font=font)
|
|
|
|
| 97 |
draw.text((x1, y2 + 5), details, fill=color, font=font_small)
|
| 98 |
|
| 99 |
# ํค๋
|
| 100 |
+
header = f"โ {len(filtered_detections)}๊ฐ / โ {len(rejected_detections)}๊ฐ (์ ์ฒด: {len(all_detections_scored)}๊ฐ)"
|
| 101 |
header_bbox = draw.textbbox((10, 10), header, font=font_large)
|
| 102 |
draw.rectangle([5, 5, header_bbox[2]+10, header_bbox[3]+10],
|
| 103 |
fill="black", outline="lime", width=2)
|
|
|
|
| 107 |
info = f"""
|
| 108 |
### ๐ ๊ฒ์ถ ๊ฒฐ๊ณผ
|
| 109 |
|
| 110 |
+
- **์ ์ฒด ๊ฒ์ถ**: {len(all_detections_scored)}๊ฐ
|
| 111 |
- **ํํฐ๋ง ํ**: {len(filtered_detections)}๊ฐ
|
| 112 |
+
- **์ ๊ฑฐ๋จ**: {len(rejected_detections)}๊ฐ
|
| 113 |
|
| 114 |
---
|
| 115 |
|
| 116 |
+
### ๐ฏ ๊ฒ์ถ๋ ๊ฐ์ฒด ์์ธ (โ
ํต๊ณผ)
|
| 117 |
|
| 118 |
"""
|
| 119 |
|
|
|
|
| 122 |
**#{idx} - ์ ์: {det['filter_score']:.0f}์ ** (RT-DETR ์ ๋ขฐ๋: {det['confidence']:.0%})
|
| 123 |
|
| 124 |
"""
|
| 125 |
+
# ์ฃผ์ ํน์ง๋ง 5๊ฐ
|
| 126 |
+
for reason in det['filter_reasons'][:5]:
|
| 127 |
info += f"- {reason}\n"
|
| 128 |
|
| 129 |
if not filtered_detections:
|
| 130 |
info += """
|
| 131 |
โ ๏ธ **๊ฒ์ถ๋ ๊ฐ์ฒด๊ฐ ์์ต๋๋ค.**
|
| 132 |
|
| 133 |
+
"""
|
| 134 |
+
|
| 135 |
+
# ์ ๊ฑฐ๋ ๊ฐ์ฒด ์ ๋ณด ์ถ๊ฐ
|
| 136 |
+
if rejected_detections:
|
| 137 |
+
info += f"""
|
| 138 |
+
|
| 139 |
+
---
|
| 140 |
+
|
| 141 |
+
### โ ์ ๊ฑฐ๋ ๊ฐ์ฒด ({len(rejected_detections)}๊ฐ)
|
| 142 |
+
|
| 143 |
+
"""
|
| 144 |
+
for idx, det in enumerate(rejected_detections, 1):
|
| 145 |
+
info += f"""
|
| 146 |
+
**์ ๊ฑฐ #{idx} - ์ ์: {det['filter_score']:.0f}์ ** (์๊ณ๊ฐ ๋ฏธ๋ฌ)
|
| 147 |
+
- RT-DETR ์ ๋ขฐ๋: {det['confidence']:.0%}
|
| 148 |
+
|
| 149 |
+
"""
|
| 150 |
+
# ์คํจ ์ด์ ํ์
|
| 151 |
+
for reason in det['filter_reasons'][:5]:
|
| 152 |
+
info += f"- {reason}\n"
|
| 153 |
+
|
| 154 |
+
if not filtered_detections:
|
| 155 |
+
info += """
|
| 156 |
+
|
| 157 |
**์กฐ์ ๋ฐฉ๋ฒ:**
|
| 158 |
1. **์ ๋ขฐ๋ ์๊ณ๊ฐ**์ ๋ฎ์ถฐ๋ณด์ธ์ (0.2~0.3)
|
| 159 |
+
2. **ํํฐ ์ ์ ์๊ณ๊ฐ**์ ๋ฎ์ถฐ๋ณด์ธ์ (50~60)
|
| 160 |
3. "์ ์ฒด ๊ฒ์ถ ํ์"๋ฅผ ์ผ์ ์๋ณธ ๊ฒ์ถ ๊ฒฐ๊ณผ๋ฅผ ํ์ธํ์ธ์
|
| 161 |
"""
|
| 162 |
|
|
|
|
| 247 |
with gr.Blocks(title="๐งช ์์ฐ ๊ฒ์ถ ๋ํํ ๊ฒ์ฆ", theme=gr.themes.Soft()) as demo:
|
| 248 |
|
| 249 |
gr.Markdown("""
|
| 250 |
+
# ๐งช ์์ฐ ๊ฒ์ถ ๋ํํ ๊ฒ์ฆ ๋๊ตฌ (์ต์ ํ ์๋ฃ)
|
| 251 |
+
|
| 252 |
+
**RT-DETR + Universal Filter** - 50๊ฐ GT ๊ธฐ๋ฐ ์ต์ ํ ์๋ฃ
|
| 253 |
+
|
| 254 |
+
**๐ ์ต์ ์ฑ๋ฅ (Confidence=0.065, Filter=90):**
|
| 255 |
+
- **Precision**: 44.2% (๊ฒ์ถ๋ ๋ฐ์ค ์ค ์ค์ ์์ฐ ๋น์จ)
|
| 256 |
+
- **Recall**: 94.0% (์ค์ ์์ฐ ์ค ๊ฒ์ถ ๋น์จ)
|
| 257 |
+
- **F1 Score**: 56.1%
|
| 258 |
|
| 259 |
์ค์๊ฐ์ผ๋ก ํ๋ผ๋ฏธํฐ๋ฅผ ์กฐ์ ํ๋ฉฐ ๊ฒ์ถ ๊ฒฐ๊ณผ๋ฅผ ํ์ธํ ์ ์์ต๋๋ค.
|
| 260 |
|
|
|
|
| 269 |
input_image = gr.Image(label="์
๋ ฅ ์ด๋ฏธ์ง", type="pil")
|
| 270 |
|
| 271 |
confidence_slider = gr.Slider(
|
| 272 |
+
0.05, 0.5, 0.065,
|
| 273 |
+
step=0.005,
|
| 274 |
label="RT-DETR ์ ๋ขฐ๋ ์๊ณ๊ฐ",
|
| 275 |
+
info="์ต์ ๊ฐ: 0.065 (๋ฎ์์๋ก ๋ ๋ง์ด ๊ฒ์ถ)"
|
| 276 |
)
|
| 277 |
|
| 278 |
filter_slider = gr.Slider(
|
| 279 |
+
50, 100, 90,
|
| 280 |
+
step=5,
|
| 281 |
label="ํํฐ ์ ์ ์๊ณ๊ฐ",
|
| 282 |
+
info="์ต์ ๊ฐ: 90 (๋์์๋ก ์๊ฒฉํ๊ฒ ํํฐ๋ง)"
|
| 283 |
)
|
| 284 |
|
| 285 |
show_all_check = gr.Checkbox(
|
|
|
|
| 289 |
|
| 290 |
detect_btn = gr.Button("๐ ๊ฒ์ถ ์คํ", variant="primary", size="lg")
|
| 291 |
|
| 292 |
+
# GT ๋ฐ์ดํฐ๋ก ์์ ์ด๋ฏธ์ง ์ถ๊ฐ (์ต์ ํ์ ์ฌ์ฉ๋ ์ค์ ๋ฐ์ดํฐ)
|
| 293 |
import os
|
| 294 |
import glob
|
| 295 |
+
example_images = []
|
| 296 |
+
# GT ํด๋๋ค์์ ์ด๋ฏธ์ง ์์ง
|
| 297 |
+
for folder in ["250818", "250820", "250825"]:
|
| 298 |
+
folder_path = f"data/ํฐ๋ค๋ฆฌ์์ฐ ์ค์ธก ๋ฐ์ดํฐ_์ตํฌ์ค์์ด์์ด(์ฃผ)/{folder}/"
|
| 299 |
+
if os.path.exists(folder_path):
|
| 300 |
+
imgs = sorted(glob.glob(os.path.join(folder_path, "*.jpg")))
|
| 301 |
+
example_images.extend(imgs[:3]) # ๊ฐ ํด๋์์ 3๊ฐ์ฉ
|
| 302 |
+
|
| 303 |
if example_images:
|
| 304 |
+
# ์ต์ ํ๋ ํ๋ผ๋ฏธํฐ ๊ฐ์ผ๋ก ์์ ์ค์
|
| 305 |
+
examples_list = [[img, 0.065, 90, False] for img in example_images[:5]]
|
| 306 |
gr.Examples(
|
| 307 |
examples=examples_list,
|
| 308 |
inputs=[input_image, confidence_slider, filter_slider, show_all_check],
|
| 309 |
+
label="๐ท GT ๋ฐ์ดํฐ ์์ (์ต์ ํ์ ์ฌ์ฉ๋ ์ค์ ์ด๋ฏธ์ง)"
|
| 310 |
)
|
| 311 |
|
| 312 |
with gr.Column():
|
|
|
|
| 322 |
gr.Markdown("""
|
| 323 |
### ๐ก ์ฌ์ฉ ํ
|
| 324 |
|
| 325 |
+
- **๊ถ์ฅ ์ค์ **: Confidence=0.065, Filter=90 (์ต์ ํ๋ ๊ฐ)
|
| 326 |
+
- **๊ฒ์ถ์ด ๋๋ฌด ์ ์ ๋**: ํํฐ ์ ์๋ฅผ 85~80์ผ๋ก ๋ฎ์ถ์ธ์
|
| 327 |
+
- **์ค๊ฒ์ถ์ด ๋ง์ ๋**: ํํฐ ์ ์๋ฅผ 95~100์ผ๋ก ๋์ด์ธ์
|
| 328 |
+
- **์ ๊ฑฐ๋ ๊ฐ์ฒด ํ์ธ**: ๋นจ๊ฐ์ ๋ฐ์ค๋ก ํ์, "์ ๊ฑฐ๋ ๊ฐ์ฒด" ์น์
์์ ์ด์ ํ์ธ
|
| 329 |
+
|
| 330 |
+
**๋ฐ์ค ์์:**
|
| 331 |
+
- ๐ข **๋
น์** (75์ ์ด์): ๋์ ํ๋ฅ ๋ก ์์ฐ
|
| 332 |
+
- ๐ก **๋
ธ๋์** (50-74์ ): ์ค๊ฐ ํ๋ฅ
|
| 333 |
+
- ๐ **์ฃผํฉ์** (50์ ๋ฏธ๋ง ํต๊ณผ): ๋ฎ์ ํ๋ฅ
|
| 334 |
+
- ๐ด **๋นจ๊ฐ์**: ์๊ณ๊ฐ ๋ฏธ๋ฌ๋ก ์ ๊ฑฐ๋จ
|
| 335 |
+
|
| 336 |
+
**์ต์ ํ ๊ฐ์ ๋ด์ญ (F1: 33.7% โ 56.1%, +66%):**
|
| 337 |
+
- ๋ฉด์ ํํฐ ๊ฐํ (FP ๋ฐ์ค๋ GT ๋๋น 17.8๋ฐฐ ํผ)
|
| 338 |
+
- ์ธ์ฅ๋(Compactness) ๊ธฐ์ค ์๊ฒฉํ
|
| 339 |
+
- ์ฑ๋/์์ ์ผ๊ด์ฑ ๋ฒ์ GT ๊ธฐ๋ฐ ์กฐ์
|
| 340 |
""")
|
| 341 |
|
| 342 |
# ํญ 2: ์๋ ๋ถ์
|
|
|
|
| 398 |
if __name__ == "__main__":
|
| 399 |
demo.launch(
|
| 400 |
server_name="0.0.0.0",
|
|
|
|
| 401 |
share=False
|
| 402 |
)
|
labeling_tool.py
ADDED
|
@@ -0,0 +1,650 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# -*- coding: utf-8 -*-
|
| 2 |
+
"""
|
| 3 |
+
Ground Truth ๋ผ๋ฒจ๋ง ๋๊ตฌ
|
| 4 |
+
RT-DETR ๊ฒ์ถ ๊ฒฐ๊ณผ์์ ์ฌ์ฉ์๊ฐ ์ฌ๋ฐ๋ฅธ ๋ฐ์ค๋ง ์ ํํ์ฌ ๋ผ๋ฒจ๋ง
|
| 5 |
+
"""
|
| 6 |
+
import sys
|
| 7 |
+
sys.stdout.reconfigure(encoding='utf-8')
|
| 8 |
+
|
| 9 |
+
import gradio as gr
|
| 10 |
+
from PIL import Image, ImageDraw, ImageFont
|
| 11 |
+
import json
|
| 12 |
+
import os
|
| 13 |
+
import glob
|
| 14 |
+
from datetime import datetime
|
| 15 |
+
import torch
|
| 16 |
+
from transformers import RTDetrForObjectDetection, RTDetrImageProcessor
|
| 17 |
+
|
| 18 |
+
# ์ ์ญ ๋ณ์ - ๋ชจ๋ธ์ ํ์์์๋ง ๋ก๋
|
| 19 |
+
processor = None
|
| 20 |
+
model = None
|
| 21 |
+
|
| 22 |
+
def load_rtdetr_model():
|
| 23 |
+
"""RT-DETR ๋ชจ๋ธ์ ํ์์์๋ง ๋ก๋ฉ"""
|
| 24 |
+
global processor, model
|
| 25 |
+
if processor is None or model is None:
|
| 26 |
+
print("๐ RT-DETR ๋ชจ๋ธ ๋ก๋ฉ ์ค...")
|
| 27 |
+
processor = RTDetrImageProcessor.from_pretrained("PekingU/rtdetr_r50vd_coco_o365")
|
| 28 |
+
model = RTDetrForObjectDetection.from_pretrained("PekingU/rtdetr_r50vd_coco_o365")
|
| 29 |
+
model.eval()
|
| 30 |
+
print("โ
RT-DETR ๋ก๋ฉ ์๋ฃ")
|
| 31 |
+
|
| 32 |
+
current_data = {
|
| 33 |
+
'folder': None,
|
| 34 |
+
'images': [],
|
| 35 |
+
'current_idx': 0,
|
| 36 |
+
'detections': {},
|
| 37 |
+
'selections': {},
|
| 38 |
+
'confidence_threshold': 0.2, # ๊ธฐ๋ณธ ์ ๋ขฐ๋ ์๊ณ๊ฐ (๋ฎ์ถค)
|
| 39 |
+
'image_cache': {} # ์ด๋ฏธ์ง ์บ์ฑ (์๋ ํฅ์)
|
| 40 |
+
}
|
| 41 |
+
|
| 42 |
+
GROUND_TRUTH_FILE = "ground_truth.json"
|
| 43 |
+
DATA_BASE = "data/ํฐ๋ค๋ฆฌ์์ฐ ์ค์ธก ๋ฐ์ดํฐ_์ตํฌ์ค์์ด์์ด(์ฃผ)"
|
| 44 |
+
|
| 45 |
+
def detect_with_rtdetr_fast(image, confidence=0.3):
|
| 46 |
+
"""RT-DETR ๋น ๋ฅธ ๊ฒ์ถ"""
|
| 47 |
+
global processor, model
|
| 48 |
+
|
| 49 |
+
# ๋ชจ๋ธ์ด ๋ก๋๋์ง ์์์ผ๋ฉด ๋ก๋
|
| 50 |
+
load_rtdetr_model()
|
| 51 |
+
|
| 52 |
+
inputs = processor(images=image, return_tensors="pt")
|
| 53 |
+
with torch.no_grad():
|
| 54 |
+
outputs = model(**inputs)
|
| 55 |
+
|
| 56 |
+
target_sizes = torch.tensor([image.size[::-1]])
|
| 57 |
+
results = processor.post_process_object_detection(
|
| 58 |
+
outputs,
|
| 59 |
+
target_sizes=target_sizes,
|
| 60 |
+
threshold=confidence
|
| 61 |
+
)[0]
|
| 62 |
+
|
| 63 |
+
detections = []
|
| 64 |
+
for score, label, box in zip(results["scores"], results["labels"], results["boxes"]):
|
| 65 |
+
x1, y1, x2, y2 = box.tolist()
|
| 66 |
+
detections.append({
|
| 67 |
+
'bbox': [x1, y1, x2, y2],
|
| 68 |
+
'confidence': score.item()
|
| 69 |
+
})
|
| 70 |
+
|
| 71 |
+
return detections
|
| 72 |
+
|
| 73 |
+
def load_existing_ground_truth():
|
| 74 |
+
"""๊ธฐ์กด ground_truth.json ๋ก๋"""
|
| 75 |
+
if os.path.exists(GROUND_TRUTH_FILE):
|
| 76 |
+
with open(GROUND_TRUTH_FILE, 'r', encoding='utf-8') as f:
|
| 77 |
+
return json.load(f)
|
| 78 |
+
return {}
|
| 79 |
+
|
| 80 |
+
def save_ground_truth(data):
|
| 81 |
+
"""ground_truth.json ์ ์ฅ"""
|
| 82 |
+
# ๋ฐฑ์
ํด๋ ์์ฑ
|
| 83 |
+
backup_dir = "backups"
|
| 84 |
+
if not os.path.exists(backup_dir):
|
| 85 |
+
os.makedirs(backup_dir)
|
| 86 |
+
|
| 87 |
+
# ๋ฐฑ์
(๊ธฐ์กด ํ์ผ์ด ์์ ๋๋ง)
|
| 88 |
+
if os.path.exists(GROUND_TRUTH_FILE):
|
| 89 |
+
backup_name = f"ground_truth_backup_{datetime.now().strftime('%Y%m%d_%H%M%S')}.json"
|
| 90 |
+
backup_path = os.path.join(backup_dir, backup_name)
|
| 91 |
+
|
| 92 |
+
# ๊ธฐ์กด ํ์ผ์ ๋ฐฑ์
ํด๋๋ก ๋ณต์ฌ
|
| 93 |
+
import shutil
|
| 94 |
+
shutil.copy2(GROUND_TRUTH_FILE, backup_path)
|
| 95 |
+
|
| 96 |
+
# ์ ์ฅ
|
| 97 |
+
with open(GROUND_TRUTH_FILE, 'w', encoding='utf-8') as f:
|
| 98 |
+
json.dump(data, f, ensure_ascii=False, indent=2)
|
| 99 |
+
|
| 100 |
+
print(f"โ
Ground Truth ์ ์ฅ ์๋ฃ: {len(data)}๊ฐ ์ด๋ฏธ์ง")
|
| 101 |
+
|
| 102 |
+
def get_folders():
|
| 103 |
+
"""์ฌ์ฉ ๊ฐ๋ฅํ ํด๋ ๋ชฉ๋ก"""
|
| 104 |
+
folders = sorted(glob.glob(os.path.join(DATA_BASE, "2*")))
|
| 105 |
+
return [os.path.basename(f) for f in folders if os.path.isdir(f)]
|
| 106 |
+
|
| 107 |
+
def start_labeling(folder):
|
| 108 |
+
"""๋ผ๋ฒจ๋ง ์์"""
|
| 109 |
+
if not folder:
|
| 110 |
+
return None, "โ ํด๋๋ฅผ ์ ํํ์ธ์.", "", 0.2
|
| 111 |
+
|
| 112 |
+
# ์ด๋ฏธ์ง ๋ก๋
|
| 113 |
+
folder_path = os.path.join(DATA_BASE, folder)
|
| 114 |
+
all_images = sorted(glob.glob(os.path.join(folder_path, "*.jpg")))
|
| 115 |
+
|
| 116 |
+
# ํํฐ๋ง: YYMMDD_NN.jpg ํ์๋ง ํ์ฉ (YYMMDD_NN-N.jpg ์ ์ธ)
|
| 117 |
+
import re
|
| 118 |
+
pattern = re.compile(r'^\d{6}_\d{2}\.jpg$') # 250818_01.jpg
|
| 119 |
+
images = [img for img in all_images if pattern.match(os.path.basename(img))]
|
| 120 |
+
|
| 121 |
+
if not images:
|
| 122 |
+
return None, f"โ {folder}์ ์ฌ๋ฐ๋ฅธ ํ์์ ์ด๋ฏธ์ง๊ฐ ์์ต๋๋ค. (YYMMDD_NN.jpg)", "", 0.2
|
| 123 |
+
|
| 124 |
+
current_data['folder'] = folder
|
| 125 |
+
current_data['images'] = [os.path.basename(img) for img in images]
|
| 126 |
+
current_data['current_idx'] = 0
|
| 127 |
+
current_data['detections'] = {}
|
| 128 |
+
current_data['selections'] = {}
|
| 129 |
+
current_data['confidence_threshold'] = 0.2
|
| 130 |
+
current_data['image_cache'] = {} # ์บ์ ์ด๊ธฐํ
|
| 131 |
+
|
| 132 |
+
filtered_count = len(all_images) - len(images)
|
| 133 |
+
if filtered_count > 0:
|
| 134 |
+
print(f"๐ ํด๋: {folder}, ์ด๋ฏธ์ง: {len(images)}๊ฐ (์ ์ธ: {filtered_count}๊ฐ)")
|
| 135 |
+
else:
|
| 136 |
+
print(f"๐ ํด๋: {folder}, ์ด๋ฏธ์ง: {len(images)}๊ฐ")
|
| 137 |
+
|
| 138 |
+
# ์ฒซ ์ด๋ฏธ์ง ๋ก๋
|
| 139 |
+
return load_image(0)
|
| 140 |
+
|
| 141 |
+
def load_image(idx, confidence_threshold=None):
|
| 142 |
+
"""์ด๋ฏธ์ง ๋ก๋ ๋ฐ ๊ฒ์ถ"""
|
| 143 |
+
if idx < 0 or idx >= len(current_data['images']):
|
| 144 |
+
return None, "โ ๋ฒ์๋ฅผ ๋ฒ์ด๋ ์ธ๋ฑ์ค์
๋๋ค.", "", ""
|
| 145 |
+
|
| 146 |
+
current_data['current_idx'] = idx
|
| 147 |
+
filename = current_data['images'][idx]
|
| 148 |
+
folder = current_data['folder']
|
| 149 |
+
img_path = os.path.join(DATA_BASE, folder, filename)
|
| 150 |
+
|
| 151 |
+
# ์ ๋ขฐ๋ ์๊ณ๊ฐ ์
๋ฐ์ดํธ
|
| 152 |
+
if confidence_threshold is not None:
|
| 153 |
+
current_data['confidence_threshold'] = confidence_threshold
|
| 154 |
+
|
| 155 |
+
# ์ด๋ฏธ์ง ์บ์ ์ฌ์ฉ (๋์คํฌ I/O ์ต์ํ)
|
| 156 |
+
if filename not in current_data['image_cache']:
|
| 157 |
+
img_path = os.path.join(DATA_BASE, folder, filename)
|
| 158 |
+
current_data['image_cache'][filename] = Image.open(img_path).convert('RGB')
|
| 159 |
+
|
| 160 |
+
image = current_data['image_cache'][filename]
|
| 161 |
+
|
| 162 |
+
# RT-DETR ๊ฒ์ถ (์ ๋ขฐ๋ ๋ณ๊ฒฝ ์ ์ฌ๊ฒ์ถ)
|
| 163 |
+
cache_key = f"{filename}_{current_data['confidence_threshold']}"
|
| 164 |
+
if cache_key not in current_data['detections']:
|
| 165 |
+
print(f"๐ RT-DETR ๊ฒ์ถ ์ค: {filename} (์ ๋ขฐ๋={current_data['confidence_threshold']:.2f})")
|
| 166 |
+
detections = detect_with_rtdetr_fast(image, confidence=current_data['confidence_threshold'])
|
| 167 |
+
current_data['detections'][cache_key] = detections
|
| 168 |
+
else:
|
| 169 |
+
detections = current_data['detections'][cache_key]
|
| 170 |
+
|
| 171 |
+
# ์ ํ ์ํ ์ด๊ธฐํ
|
| 172 |
+
if filename not in current_data['selections']:
|
| 173 |
+
current_data['selections'][filename] = []
|
| 174 |
+
|
| 175 |
+
# ์๊ฐํ
|
| 176 |
+
img_with_boxes = draw_boxes(image, detections, current_data['selections'][filename])
|
| 177 |
+
|
| 178 |
+
# ์งํ๋ฅ
|
| 179 |
+
progress = f"{idx + 1}/{len(current_data['images'])} ({(idx+1)/len(current_data['images'])*100:.0f}%)"
|
| 180 |
+
|
| 181 |
+
# ์ ๋ณด
|
| 182 |
+
info = f"""
|
| 183 |
+
### ๐ท ์ด๋ฏธ์ง: {filename}
|
| 184 |
+
|
| 185 |
+
- **์งํ๋ฅ **: {progress}
|
| 186 |
+
- **์ ๋ขฐ๋ ์๊ณ๊ฐ**: {current_data['confidence_threshold']:.2f}
|
| 187 |
+
- **๊ฒ์ถ๋ ๋ฐ์ค**: {len(detections)}๊ฐ
|
| 188 |
+
- **์ ํ๋ ๋ฐ์ค**: {len(current_data['selections'][filename])}๊ฐ
|
| 189 |
+
|
| 190 |
+
### ๐ ์ฌ์ฉ ๋ฐฉ๋ฒ
|
| 191 |
+
|
| 192 |
+
1. **์์ฐ๊ฐ ๋ง๋ ๋ฐ์ค๋ฅผ ํด๋ฆญ**ํ์ฌ ์ ํ (ํ๋์์ผ๋ก ๋ณ๊ฒฝ)
|
| 193 |
+
2. ์๋ชป ์ ํ ์ **๋ค์ ํด๋ฆญ**ํ์ฌ ํด์ (๋
น์์ผ๋ก ๋๋๋ฆผ)
|
| 194 |
+
3. **์ ๋ขฐ๋ ์ฌ๋ผ์ด๋**๋ก ๊ฒ์ถ ๋ฏผ๊ฐ๋ ์กฐ์ (๋ฎ์์๋ก ๋ ๋ง์ด ๊ฒ์ถ)
|
| 195 |
+
4. **"๋ค์"** ๋ฒํผ์ผ๋ก ์ ์ฅ ๋ฐ ๋ค์ ์ด๋ฏธ์ง๋ก ์ด๋
|
| 196 |
+
|
| 197 |
+
**๋ฐ์ค ์์:**
|
| 198 |
+
- ๐ข ๋
น์: ๊ฒ์ถ๋จ (์ ํ ์ ๋จ)
|
| 199 |
+
- ๐ต ํ๋์: ์ ํ๋จ (์์ฐ)
|
| 200 |
+
"""
|
| 201 |
+
|
| 202 |
+
return img_with_boxes, info, progress, current_data['confidence_threshold']
|
| 203 |
+
|
| 204 |
+
def draw_boxes(image, detections, selected_indices):
|
| 205 |
+
"""๋ฐ์ค ๊ทธ๋ฆฌ๊ธฐ (ํด๋ฆญ ๊ฐ๋ฅํ ๋ฒํธ ๋ฒํผ ํฌํจ) - ์ต์ ํ"""
|
| 206 |
+
# ์ด๋ฏธ์ง ๋ณต์ฌ ๋์ ์ง์ ์์ (์๋ ํฅ์)
|
| 207 |
+
img = image.copy()
|
| 208 |
+
draw = ImageDraw.Draw(img)
|
| 209 |
+
|
| 210 |
+
try:
|
| 211 |
+
font = ImageFont.truetype("arial.ttf", 28) # ๋ ํฐ ํฐํธ
|
| 212 |
+
font_tiny = ImageFont.truetype("arial.ttf", 10)
|
| 213 |
+
except:
|
| 214 |
+
font = ImageFont.load_default()
|
| 215 |
+
font_tiny = ImageFont.load_default()
|
| 216 |
+
|
| 217 |
+
# ์ ํ๋์ง ์์ ๋ฐ์ค ๋จผ์ ๊ทธ๋ฆฌ๊ธฐ (๋ค์ชฝ ๋ ์ด์ด)
|
| 218 |
+
for idx, det in enumerate(detections):
|
| 219 |
+
if idx not in selected_indices:
|
| 220 |
+
x1, y1, x2, y2 = det['bbox']
|
| 221 |
+
color = "lime"
|
| 222 |
+
|
| 223 |
+
# ๋ฐ์ค ํ
๋๋ฆฌ
|
| 224 |
+
draw.rectangle([x1, y1, x2, y2], outline=color, width=10)
|
| 225 |
+
|
| 226 |
+
# ์ฝ๋ ๋ผ๋ฒจ
|
| 227 |
+
corner_label = f"#{idx+1}"
|
| 228 |
+
draw.rectangle([x1-2, y1-24, x1+30, y1-2], fill=color)
|
| 229 |
+
draw.text((x1, y1 - 22), corner_label, fill="white", font=font_tiny)
|
| 230 |
+
|
| 231 |
+
# ์ ํ๋ ๋ฐ์ค ๋์ค์ ๊ทธ๋ฆฌ๊ธฐ (์์ชฝ ๋ ์ด์ด)
|
| 232 |
+
for idx, det in enumerate(detections):
|
| 233 |
+
if idx in selected_indices:
|
| 234 |
+
x1, y1, x2, y2 = det['bbox']
|
| 235 |
+
color = "blue"
|
| 236 |
+
|
| 237 |
+
# ๋ฐ์ค ํ
๋๋ฆฌ (๋ ๋๊ป๊ฒ)
|
| 238 |
+
draw.rectangle([x1, y1, x2, y2], outline=color, width=14)
|
| 239 |
+
|
| 240 |
+
# ์ฝ๋ ๋ผ๋ฒจ
|
| 241 |
+
corner_label = f"โ#{idx+1}"
|
| 242 |
+
draw.rectangle([x1-2, y1-24, x1+40, y1-2], fill=color)
|
| 243 |
+
draw.text((x1, y1 - 22), corner_label, fill="white", font=font_tiny)
|
| 244 |
+
|
| 245 |
+
# ์ํ ๋ฒํผ (๋ชจ๋ ๋ฐ์ค)
|
| 246 |
+
for idx, det in enumerate(detections):
|
| 247 |
+
x1, y1, x2, y2 = det['bbox']
|
| 248 |
+
center_x = (x1 + x2) / 2
|
| 249 |
+
center_y = (y1 + y2) / 2
|
| 250 |
+
|
| 251 |
+
# ์ ํ ์ฌ๋ถ
|
| 252 |
+
selected = idx in selected_indices
|
| 253 |
+
btn_color = "blue" if selected else "lime"
|
| 254 |
+
btn_text = f"โ{idx+1}" if selected else f"{idx+1}"
|
| 255 |
+
|
| 256 |
+
# ๋ฒํผ ํฌ๊ธฐ
|
| 257 |
+
box_width = x2 - x1
|
| 258 |
+
box_height = y2 - y1
|
| 259 |
+
radius = min(55, box_width * 0.18, box_height * 0.35)
|
| 260 |
+
|
| 261 |
+
# ์ธ๊ณฝ ์ (ํฐ์ ํ
๋๋ฆฌ)
|
| 262 |
+
draw.ellipse(
|
| 263 |
+
[center_x - radius - 4, center_y - radius - 4,
|
| 264 |
+
center_x + radius + 4, center_y + radius + 4],
|
| 265 |
+
fill=btn_color,
|
| 266 |
+
outline="white",
|
| 267 |
+
width=5
|
| 268 |
+
)
|
| 269 |
+
|
| 270 |
+
# ๋ด๋ถ ์
|
| 271 |
+
draw.ellipse(
|
| 272 |
+
[center_x - radius, center_y - radius,
|
| 273 |
+
center_x + radius, center_y + radius],
|
| 274 |
+
fill=btn_color
|
| 275 |
+
)
|
| 276 |
+
|
| 277 |
+
# ํ
์คํธ ์ค์ ์ ๋ ฌ
|
| 278 |
+
text_bbox = draw.textbbox((0, 0), btn_text, font=font)
|
| 279 |
+
text_width = text_bbox[2] - text_bbox[0]
|
| 280 |
+
text_height = text_bbox[3] - text_bbox[1]
|
| 281 |
+
text_x = center_x - text_width / 2
|
| 282 |
+
text_y = center_y - text_height / 2 - 2
|
| 283 |
+
|
| 284 |
+
# ํ
์คํธ (๊ทธ๋ฆผ์ + ๋ณธ์ฒด)
|
| 285 |
+
draw.text((text_x + 2, text_y + 2), btn_text, fill="black", font=font)
|
| 286 |
+
draw.text((text_x, text_y), btn_text, fill="white", font=font)
|
| 287 |
+
|
| 288 |
+
# ํค๋
|
| 289 |
+
header = f"๊ฒ์ถ: {len(detections)}๊ฐ | ์ ํ: {len(selected_indices)}๊ฐ"
|
| 290 |
+
header_bbox = draw.textbbox((10, 10), header, font=font)
|
| 291 |
+
draw.rectangle([5, 5, header_bbox[2]+10, header_bbox[3]+10], fill="black", outline="white", width=2)
|
| 292 |
+
draw.text((10, 10), header, fill="white", font=font)
|
| 293 |
+
|
| 294 |
+
return img
|
| 295 |
+
|
| 296 |
+
def redraw_current_image():
|
| 297 |
+
"""ํ์ฌ ์ด๋ฏธ์ง ๋น ๋ฅด๊ฒ ์ฌ๊ทธ๋ฆฌ๊ธฐ (์ฌ๊ฒ์ถ ์์ด ๋ฐ์ค๋ง ๋ค์ ๊ทธ๋ฆฌ๊ธฐ)"""
|
| 298 |
+
idx = current_data['current_idx']
|
| 299 |
+
filename = current_data['images'][idx]
|
| 300 |
+
folder = current_data['folder']
|
| 301 |
+
|
| 302 |
+
# ์ด๋ฏธ์ง ์บ์ ํ์ธ (๋์คํฌ I/O ์ต์ํ)
|
| 303 |
+
if filename not in current_data['image_cache']:
|
| 304 |
+
img_path = os.path.join(DATA_BASE, folder, filename)
|
| 305 |
+
current_data['image_cache'][filename] = Image.open(img_path).convert('RGB')
|
| 306 |
+
|
| 307 |
+
image = current_data['image_cache'][filename]
|
| 308 |
+
|
| 309 |
+
# ์บ์๋ ๊ฒ์ถ ๊ฒฐ๊ณผ ์ฌ์ฉ (์ฌ๊ฒ์ถ ์์!)
|
| 310 |
+
cache_key = f"{filename}_{current_data['confidence_threshold']}"
|
| 311 |
+
detections = current_data['detections'][cache_key]
|
| 312 |
+
|
| 313 |
+
# ์ ํ ์ํ
|
| 314 |
+
selections = current_data['selections'][filename]
|
| 315 |
+
|
| 316 |
+
# ๋ฐ์ค๋ง ๋ค์ ๊ทธ๋ฆฌ๊ธฐ
|
| 317 |
+
img_with_boxes = draw_boxes(image, detections, selections)
|
| 318 |
+
|
| 319 |
+
# ์งํ๋ฅ (๊ฐ์ํ)
|
| 320 |
+
progress = f"{idx + 1}/{len(current_data['images'])}"
|
| 321 |
+
|
| 322 |
+
# ์ ๋ณด (๊ฐ์ํ - ํ
์คํธ ์์ฑ ์๊ฐ ๋จ์ถ)
|
| 323 |
+
info = f"**{filename}** | ๊ฒ์ถ: {len(detections)}๊ฐ | ์ ํ: {len(selections)}๊ฐ"
|
| 324 |
+
|
| 325 |
+
return img_with_boxes, info, progress, current_data['confidence_threshold']
|
| 326 |
+
|
| 327 |
+
def toggle_selection(evt: gr.SelectData):
|
| 328 |
+
"""๋ฐ์ค ํด๋ฆญ ์ ์ ํ/ํด์ (์ํ ๋ฒํผ ์ฐ์ ๊ฐ์ง)"""
|
| 329 |
+
# ํด๋ฆญ ์ขํ
|
| 330 |
+
click_x, click_y = evt.index
|
| 331 |
+
|
| 332 |
+
filename = current_data['images'][current_data['current_idx']]
|
| 333 |
+
cache_key = f"{filename}_{current_data['confidence_threshold']}"
|
| 334 |
+
detections = current_data['detections'][cache_key]
|
| 335 |
+
selections = current_data['selections'][filename]
|
| 336 |
+
|
| 337 |
+
if not detections:
|
| 338 |
+
return redraw_current_image()
|
| 339 |
+
|
| 340 |
+
# 1๋จ๊ณ: ์ํ ๋ฒํผ ๋ด๋ถ ํด๋ฆญ ๊ฐ์ง (์ต์ฐ์ )
|
| 341 |
+
button_candidates = []
|
| 342 |
+
|
| 343 |
+
for idx, det in enumerate(detections):
|
| 344 |
+
x1, y1, x2, y2 = det['bbox']
|
| 345 |
+
center_x = (x1 + x2) / 2
|
| 346 |
+
center_y = (y1 + y2) / 2
|
| 347 |
+
|
| 348 |
+
# ๋ฒํผ ํฌ๊ธฐ ๊ณ์ฐ (draw_boxes์ ๋์ผ)
|
| 349 |
+
box_width = x2 - x1
|
| 350 |
+
box_height = y2 - y1
|
| 351 |
+
radius = min(50, box_width * 0.15, box_height * 0.3)
|
| 352 |
+
|
| 353 |
+
# ํด๋ฆญ์ด ์ํ ๋ฒํผ ๋ด๋ถ์ธ์ง ํ์ธ
|
| 354 |
+
distance_from_center = ((click_x - center_x) ** 2 + (click_y - center_y) ** 2) ** 0.5
|
| 355 |
+
|
| 356 |
+
if distance_from_center <= radius:
|
| 357 |
+
# ๋ฒํผ ๋ด๋ถ ํด๋ฆญ!
|
| 358 |
+
button_candidates.append((idx, distance_from_center))
|
| 359 |
+
|
| 360 |
+
# 2๋จ๊ณ: ๋ฒํผ ํด๋ฆญ์ด ์์ผ๋ฉด ๊ฐ์ฅ ๊ฐ๊น์ด ๋ฒํผ ์ ํ
|
| 361 |
+
clicked_idx = None
|
| 362 |
+
if button_candidates:
|
| 363 |
+
# ๋ฒํผ ์ค์ฌ์ ๊ฐ์ฅ ๊ฐ๊น์ด ๊ฒ ์ ํ
|
| 364 |
+
button_candidates.sort(key=lambda x: x[1])
|
| 365 |
+
clicked_idx = button_candidates[0][0]
|
| 366 |
+
print(f"๐ฏ ๋ฒํผ ํด๋ฆญ โ ๋ฐ์ค #{clicked_idx+1}")
|
| 367 |
+
|
| 368 |
+
# 3๋จ๊ณ: ๋ฒํผ ํด๋ฆญ ์์ผ๋ฉด ๋ฐ์ค ์์ญ ํด๋ฆญ ํ์ธ
|
| 369 |
+
else:
|
| 370 |
+
box_candidates = []
|
| 371 |
+
for idx, det in enumerate(detections):
|
| 372 |
+
x1, y1, x2, y2 = det['bbox']
|
| 373 |
+
|
| 374 |
+
# ๋ฐ์ค ๋ด๋ถ์ธ์ง ํ์ธ
|
| 375 |
+
if x1 <= click_x <= x2 and y1 <= click_y <= y2:
|
| 376 |
+
center_x = (x1 + x2) / 2
|
| 377 |
+
center_y = (y1 + y2) / 2
|
| 378 |
+
distance = ((click_x - center_x) ** 2 + (click_y - center_y) ** 2) ** 0.5
|
| 379 |
+
area = (x2 - x1) * (y2 - y1)
|
| 380 |
+
|
| 381 |
+
# ์์ ๋ฐ์ค + ๊ฐ๊น์ด ๋ฐ์ค ์ฐ์
|
| 382 |
+
score = area + distance * 100
|
| 383 |
+
box_candidates.append((idx, score, area, distance))
|
| 384 |
+
|
| 385 |
+
if box_candidates:
|
| 386 |
+
box_candidates.sort(key=lambda x: x[1])
|
| 387 |
+
clicked_idx = box_candidates[0][0]
|
| 388 |
+
best = box_candidates[0]
|
| 389 |
+
print(f"๐ ๋ฐ์ค ์์ญ ํด๋ฆญ ({click_x:.0f}, {click_y:.0f}) โ ๋ฐ์ค #{clicked_idx+1} (๊ฑฐ๋ฆฌ={best[3]:.0f})")
|
| 390 |
+
|
| 391 |
+
# 4๋จ๊ณ: ์ ํ/ํด์ ํ ๊ธ
|
| 392 |
+
if clicked_idx is not None:
|
| 393 |
+
if clicked_idx in selections:
|
| 394 |
+
selections.remove(clicked_idx)
|
| 395 |
+
print(f" โ ๋ฐ์ค #{clicked_idx+1} ์ ํ ํด์ ")
|
| 396 |
+
else:
|
| 397 |
+
selections.append(clicked_idx)
|
| 398 |
+
print(f" โ ๋ฐ์ค #{clicked_idx+1} ์ ํ๋จ")
|
| 399 |
+
|
| 400 |
+
current_data['selections'][filename] = selections
|
| 401 |
+
else:
|
| 402 |
+
print(f"โ ํด๋ฆญ ์์น์ ๋ฐ์ค ์์")
|
| 403 |
+
|
| 404 |
+
# ๋น ๋ฅธ ์
๋ฐ์ดํธ: ์ด๋ฏธ์ง๋ง ๋ค์ ๊ทธ๋ฆฌ๊ธฐ (์ฌ๊ฒ์ถ ์์)
|
| 405 |
+
return redraw_current_image()
|
| 406 |
+
|
| 407 |
+
def previous_image():
|
| 408 |
+
"""์ด์ ์ด๋ฏธ์ง"""
|
| 409 |
+
idx = current_data['current_idx'] - 1
|
| 410 |
+
if idx < 0:
|
| 411 |
+
return load_image(current_data['current_idx']) + ("โ ๏ธ ์ฒซ ์ด๋ฏธ์ง์
๋๋ค.",)
|
| 412 |
+
return load_image(idx) + ("",)
|
| 413 |
+
|
| 414 |
+
def next_image():
|
| 415 |
+
"""๋ค์ ์ด๋ฏธ์ง (์ ์ฅ ํฌํจ)"""
|
| 416 |
+
# ํ์ฌ ์ ํ ์ ์ฅ
|
| 417 |
+
save_current_selection()
|
| 418 |
+
|
| 419 |
+
idx = current_data['current_idx'] + 1
|
| 420 |
+
if idx >= len(current_data['images']):
|
| 421 |
+
return load_image(current_data['current_idx']) + ("โ ๏ธ ๋ง์ง๋ง ์ด๋ฏธ์ง์
๋๋ค. '์๋ฃ' ๋ฒํผ์ ๋๋ฅด์ธ์.",)
|
| 422 |
+
return load_image(idx) + ("โ
์ ์ฅ๋์์ต๋๋ค.",)
|
| 423 |
+
|
| 424 |
+
def skip_image():
|
| 425 |
+
"""๊ฑด๋๋ฐ๊ธฐ"""
|
| 426 |
+
filename = current_data['images'][current_data['current_idx']]
|
| 427 |
+
current_data['selections'][filename] = []
|
| 428 |
+
|
| 429 |
+
idx = current_data['current_idx'] + 1
|
| 430 |
+
if idx >= len(current_data['images']):
|
| 431 |
+
return load_image(current_data['current_idx']) + ("โ ๏ธ ๋ง์ง๋ง ์ด๋ฏธ์ง์
๋๋ค.",)
|
| 432 |
+
return load_image(idx) + ("โญ๏ธ ๊ฑด๋๋ฐ์์ต๋๋ค.",)
|
| 433 |
+
|
| 434 |
+
def reset_selection():
|
| 435 |
+
"""ํ์ฌ ์ด๋ฏธ์ง์ ์ ํ ์ด๊ธฐํ"""
|
| 436 |
+
filename = current_data['images'][current_data['current_idx']]
|
| 437 |
+
current_data['selections'][filename] = []
|
| 438 |
+
|
| 439 |
+
# ๋น ๋ฅธ ์
๋ฐ์ดํธ: ์ด๋ฏธ์ง๋ง ๋ค์ ๊ทธ๋ฆฌ๊ธฐ
|
| 440 |
+
return redraw_current_image() + ("๐ ์ ํ์ด ์ด๊ธฐํ๋์์ต๋๋ค.",)
|
| 441 |
+
|
| 442 |
+
def save_current_selection():
|
| 443 |
+
"""ํ์ฌ ์ ํ ์ ์ฅ"""
|
| 444 |
+
filename = current_data['images'][current_data['current_idx']]
|
| 445 |
+
folder = current_data['folder']
|
| 446 |
+
selections = current_data['selections'].get(filename, [])
|
| 447 |
+
cache_key = f"{filename}_{current_data['confidence_threshold']}"
|
| 448 |
+
detections = current_data['detections'][cache_key]
|
| 449 |
+
|
| 450 |
+
# Ground Truth ํ์์ผ๋ก ๋ณํ
|
| 451 |
+
gt_data = load_existing_ground_truth()
|
| 452 |
+
|
| 453 |
+
gt_data[filename] = [
|
| 454 |
+
{
|
| 455 |
+
"bbox": detections[idx]['bbox'],
|
| 456 |
+
"label": "shrimp",
|
| 457 |
+
"folder": folder,
|
| 458 |
+
"confidence": detections[idx]['confidence']
|
| 459 |
+
}
|
| 460 |
+
for idx in selections
|
| 461 |
+
]
|
| 462 |
+
|
| 463 |
+
# ์์ ์ ์ฅ (๋งค๋ฒ)
|
| 464 |
+
save_ground_truth(gt_data)
|
| 465 |
+
|
| 466 |
+
def finish_labeling():
|
| 467 |
+
"""๋ผ๋ฒจ๋ง ์๋ฃ"""
|
| 468 |
+
# ๋ง์ง๋ง ์ด๋ฏธ์ง ์ ์ฅ
|
| 469 |
+
save_current_selection()
|
| 470 |
+
|
| 471 |
+
gt_data = load_existing_ground_truth()
|
| 472 |
+
total_images = len(gt_data)
|
| 473 |
+
total_boxes = sum(len(v) for v in gt_data.values())
|
| 474 |
+
|
| 475 |
+
msg = f"""
|
| 476 |
+
## โ
๋ผ๋ฒจ๋ง ์๋ฃ!
|
| 477 |
+
|
| 478 |
+
- **์ด ์ด๋ฏธ์ง**: {total_images}๊ฐ
|
| 479 |
+
- **์ด ๋ฐ์ด๋ฉ ๋ฐ์ค**: {total_boxes}๊ฐ
|
| 480 |
+
- **์ ์ฅ ์์น**: {GROUND_TRUTH_FILE}
|
| 481 |
+
|
| 482 |
+
### ๋ค์ ๋จ๊ณ:
|
| 483 |
+
|
| 484 |
+
```bash
|
| 485 |
+
python test_quantitative_evaluation.py
|
| 486 |
+
```
|
| 487 |
+
|
| 488 |
+
์ฑ๋ฅ ์ธก์ ํ ๊ฒฐ๊ณผ๋ฅผ ํ์ธํ์ธ์!
|
| 489 |
+
"""
|
| 490 |
+
|
| 491 |
+
return None, msg, "์๋ฃ"
|
| 492 |
+
|
| 493 |
+
# ํค๋ณด๋ ๋จ์ถํค๋ฅผ ์ํ JavaScript
|
| 494 |
+
keyboard_js = """
|
| 495 |
+
<script>
|
| 496 |
+
document.addEventListener('keydown', function(event) {
|
| 497 |
+
// ์
๋ ฅ ํ๋์์๋ ๋จ์ถํค ๋นํ์ฑํ
|
| 498 |
+
if (event.target.tagName === 'INPUT' || event.target.tagName === 'TEXTAREA') {
|
| 499 |
+
return;
|
| 500 |
+
}
|
| 501 |
+
|
| 502 |
+
// ํ์ดํ ํค, ์คํ์ด์ค๋ฐ, S, R ํค ์ฒ๋ฆฌ
|
| 503 |
+
if (event.key === 'ArrowRight' || event.key === ' ') {
|
| 504 |
+
event.preventDefault();
|
| 505 |
+
const nextBtn = document.querySelector('button:has-text("๋ค์")') ||
|
| 506 |
+
Array.from(document.querySelectorAll('button')).find(btn => btn.textContent.includes('๋ค์'));
|
| 507 |
+
if (nextBtn) nextBtn.click();
|
| 508 |
+
} else if (event.key === 'ArrowLeft') {
|
| 509 |
+
event.preventDefault();
|
| 510 |
+
const prevBtn = Array.from(document.querySelectorAll('button')).find(btn => btn.textContent.includes('์ด์ '));
|
| 511 |
+
if (prevBtn) prevBtn.click();
|
| 512 |
+
} else if (event.key.toLowerCase() === 's') {
|
| 513 |
+
event.preventDefault();
|
| 514 |
+
const skipBtn = Array.from(document.querySelectorAll('button')).find(btn => btn.textContent.includes('๊ฑด๋๋ฐ๊ธฐ'));
|
| 515 |
+
if (skipBtn) skipBtn.click();
|
| 516 |
+
} else if (event.key.toLowerCase() === 'r') {
|
| 517 |
+
event.preventDefault();
|
| 518 |
+
const resetBtn = Array.from(document.querySelectorAll('button')).find(btn => btn.textContent.includes('์ด๊ธฐํ'));
|
| 519 |
+
if (resetBtn) resetBtn.click();
|
| 520 |
+
}
|
| 521 |
+
});
|
| 522 |
+
</script>
|
| 523 |
+
"""
|
| 524 |
+
|
| 525 |
+
# Gradio ์ธํฐํ์ด์ค
|
| 526 |
+
with gr.Blocks(title="๐ท๏ธ Ground Truth ๋ผ๋ฒจ๋ง ๋๊ตฌ", theme=gr.themes.Soft(), head=keyboard_js) as demo:
|
| 527 |
+
|
| 528 |
+
gr.Markdown("""
|
| 529 |
+
# ๐ท๏ธ Ground Truth ๋ผ๋ฒจ๋ง ๋๊ตฌ
|
| 530 |
+
|
| 531 |
+
RT-DETR ๊ฒ์ถ ๊ฒฐ๊ณผ์์ ์ฌ๋ฐ๋ฅธ ์์ฐ ๋ฐ์ค๋ง ์ ํํ์ฌ ๋ผ๋ฒจ๋งํฉ๋๋ค.
|
| 532 |
+
|
| 533 |
+
---
|
| 534 |
+
""")
|
| 535 |
+
|
| 536 |
+
with gr.Row():
|
| 537 |
+
folder_dropdown = gr.Dropdown(
|
| 538 |
+
choices=get_folders(),
|
| 539 |
+
label="๐ ๋ผ๋ฒจ๋งํ ํด๋ ์ ํ",
|
| 540 |
+
value=None
|
| 541 |
+
)
|
| 542 |
+
start_btn = gr.Button("๐ ์์", variant="primary")
|
| 543 |
+
|
| 544 |
+
with gr.Row():
|
| 545 |
+
with gr.Column(scale=2):
|
| 546 |
+
image_output = gr.Image(label="์ด๋ฏธ์ง (๋ฐ์ค ํด๋ฆญ์ผ๋ก ์ ํ/ํด์ )", type="pil")
|
| 547 |
+
|
| 548 |
+
with gr.Column(scale=1):
|
| 549 |
+
info_output = gr.Markdown()
|
| 550 |
+
|
| 551 |
+
progress_output = gr.Textbox(label="์งํ๋ฅ ", interactive=False)
|
| 552 |
+
|
| 553 |
+
confidence_slider = gr.Slider(
|
| 554 |
+
minimum=0.05,
|
| 555 |
+
maximum=0.5,
|
| 556 |
+
value=0.2,
|
| 557 |
+
step=0.05,
|
| 558 |
+
label="๐ฏ ๊ฒ์ถ ์ ๋ขฐ๋ ์๊ณ๊ฐ (๋ฎ์์๋ก ๏ฟฝ๏ฟฝ๏ฟฝ ๋ง์ด ๊ฒ์ถ)",
|
| 559 |
+
info="์์ฐ๊ฐ ๊ฒ์ถ ์ ๋๋ฉด ๋ฎ์ถ์ธ์"
|
| 560 |
+
)
|
| 561 |
+
|
| 562 |
+
with gr.Row():
|
| 563 |
+
prev_btn = gr.Button("โ ์ด์ ")
|
| 564 |
+
skip_btn = gr.Button("โญ ๊ฑด๋๋ฐ๊ธฐ")
|
| 565 |
+
next_btn = gr.Button("๋ค์ โถ", variant="primary")
|
| 566 |
+
|
| 567 |
+
reset_btn = gr.Button("๐ ์ ํ ์ด๊ธฐํ", variant="secondary")
|
| 568 |
+
|
| 569 |
+
finish_btn = gr.Button("โ
์๋ฃ", variant="stop", size="lg")
|
| 570 |
+
|
| 571 |
+
status_output = gr.Textbox(label="์ํ", interactive=False)
|
| 572 |
+
|
| 573 |
+
gr.Markdown("""
|
| 574 |
+
---
|
| 575 |
+
|
| 576 |
+
### ๐ก ์ฌ์ฉ ํ
|
| 577 |
+
|
| 578 |
+
**๋ง์ฐ์ค:**
|
| 579 |
+
- **ํด๋ฆญ**: ๋ฐ์ค๋ฅผ ํด๋ฆญํ์ฌ ์ ํ/ํด์
|
| 580 |
+
- **๋
น์ โ ํ๋์**: ์ ํ๋จ (์์ฐ)
|
| 581 |
+
- **ํ๋์ โ ๋
น์**: ํด์ ๋จ
|
| 582 |
+
|
| 583 |
+
**ํค๋ณด๋ ๋จ์ถํค:**
|
| 584 |
+
- **โ (์ค๋ฅธ์ชฝ ํ์ดํ)**: ๋ค์ ์ด๋ฏธ์ง (์ ์ฅ)
|
| 585 |
+
- **โ (์ผ์ชฝ ํ์ดํ)**: ์ด์ ์ด๋ฏธ์ง
|
| 586 |
+
- **Space (์คํ์ด์ค๋ฐ)**: ๋ค์ ์ด๋ฏธ์ง (์ ์ฅ)
|
| 587 |
+
- **S**: ๊ฑด๋๋ฐ๊ธฐ
|
| 588 |
+
- **R**: ์ ํ ์ด๊ธฐํ
|
| 589 |
+
|
| 590 |
+
**๊ธฐํ:**
|
| 591 |
+
- **์ ๋ขฐ๋ ์ฌ๋ผ์ด๋**: ๊ฒ์ถ ๋ฏผ๊ฐ๋ ์กฐ์ (0.05~0.5)
|
| 592 |
+
- **10์ฅ๋ง๋ค ์๋ ์ ์ฅ๋ฉ๋๋ค.**
|
| 593 |
+
""")
|
| 594 |
+
|
| 595 |
+
# ์ด๋ฒคํธ ์ฐ๊ฒฐ
|
| 596 |
+
start_btn.click(
|
| 597 |
+
start_labeling,
|
| 598 |
+
[folder_dropdown],
|
| 599 |
+
[image_output, info_output, progress_output, confidence_slider]
|
| 600 |
+
)
|
| 601 |
+
|
| 602 |
+
# ์ ๋ขฐ๋ ์ฌ๋ผ์ด๋ ๋ณ๊ฒฝ ์ ํ์ฌ ์ด๋ฏธ์ง ์ฌ๊ฒ์ถ
|
| 603 |
+
confidence_slider.change(
|
| 604 |
+
lambda conf: load_image(current_data['current_idx'], conf),
|
| 605 |
+
[confidence_slider],
|
| 606 |
+
[image_output, info_output, progress_output, confidence_slider]
|
| 607 |
+
)
|
| 608 |
+
|
| 609 |
+
image_output.select(
|
| 610 |
+
toggle_selection,
|
| 611 |
+
None,
|
| 612 |
+
[image_output, info_output, progress_output, confidence_slider]
|
| 613 |
+
)
|
| 614 |
+
|
| 615 |
+
prev_btn.click(
|
| 616 |
+
previous_image,
|
| 617 |
+
None,
|
| 618 |
+
[image_output, info_output, progress_output, confidence_slider, status_output]
|
| 619 |
+
)
|
| 620 |
+
|
| 621 |
+
next_btn.click(
|
| 622 |
+
next_image,
|
| 623 |
+
None,
|
| 624 |
+
[image_output, info_output, progress_output, confidence_slider, status_output]
|
| 625 |
+
)
|
| 626 |
+
|
| 627 |
+
skip_btn.click(
|
| 628 |
+
skip_image,
|
| 629 |
+
None,
|
| 630 |
+
[image_output, info_output, progress_output, confidence_slider, status_output]
|
| 631 |
+
)
|
| 632 |
+
|
| 633 |
+
reset_btn.click(
|
| 634 |
+
reset_selection,
|
| 635 |
+
None,
|
| 636 |
+
[image_output, info_output, progress_output, confidence_slider, status_output]
|
| 637 |
+
)
|
| 638 |
+
|
| 639 |
+
finish_btn.click(
|
| 640 |
+
finish_labeling,
|
| 641 |
+
None,
|
| 642 |
+
[image_output, info_output, progress_output]
|
| 643 |
+
)
|
| 644 |
+
|
| 645 |
+
if __name__ == "__main__":
|
| 646 |
+
demo.launch(
|
| 647 |
+
server_name="0.0.0.0",
|
| 648 |
+
server_port=None, # ์๋์ผ๋ก ๋น ํฌํธ ์ฐพ๊ธฐ
|
| 649 |
+
share=False
|
| 650 |
+
)
|
problem.txt
CHANGED
|
@@ -1,10 +1,20 @@
|
|
| 1 |
-
|
| 2 |
-
|
| 3 |
-
|
| 4 |
-
|
| 5 |
-
:
|
| 6 |
-
|
| 7 |
-
|
| 8 |
-
|
| 9 |
-
|
| 10 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
RT-DETR + Universal Filter (์ต์ ํ ์๋ฃ) | VIDraft/Shrimp ํด๋ผ์ฐ๋ ๋ชจ๋ธ
|
| 2 |
+
|
| 3 |
+
๐ ์ต์ ์ฑ๋ฅ (50๊ฐ GT ๊ธฐ์ค, RT-DETR):
|
| 4 |
+
|
| 5 |
+
Precision: 44.2% | Recall: 94.0% | F1 Score: 56.1%
|
| 6 |
+
๐ VIDraft/Shrimp ํด๋ผ์ฐ๋ ๋ชจ๋ธ ์ต์ ํ:
|
| 7 |
+
|
| 8 |
+
โ
shrimp ํด๋์ค๋ง ๊ฒ์ถ (๋ค๋ฅธ ํด๋์ค ์๋ ํํฐ๋ง)
|
| 9 |
+
โ
์ด๋ฏธ์ง ์๋ ๋ฆฌ์ฌ์ด์ฆ (640px, ์ ์ก ์๋ 80% ํฅ์)
|
| 10 |
+
โ
Base64 ์ต์ ์ ์ก (JPEG quality=80)
|
| 11 |
+
โ
๊ฒ์ฆ ์๋ฃ (10๊ฐ ์ด๋ฏธ์ง ํ
์คํธ, ํ๊ท 1.6๊ฐ ๊ฒ์ถ)
|
| 12 |
+
|
| 13 |
+
์ ์ ๊ตฌ์ฑ (์ด 100์ ):
|
| 14 |
+
|
| 15 |
+
์ข
ํก๋น (2~10): 15์
|
| 16 |
+
์ธ์ฅ๋ (<0.25): 15์
|
| 17 |
+
๋ฉด์ ๋น (5~50%): 10์
|
| 18 |
+
์ฑ๋ (<150): 20์
|
| 19 |
+
์์ ์ผ๊ด์ฑ (<30): 15์
|
| 20 |
+
๋ชจ๋ธ ์ ๋ขฐ๋: ์ต๋ 25์
|
shrimp_detection_app.py
ADDED
|
@@ -0,0 +1,1150 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# -*- coding: utf-8 -*-
|
| 2 |
+
"""
|
| 3 |
+
๐ฆ ์์ฐ ๊ฒ์ถ ํตํฉ ์์คํ
|
| 4 |
+
3๊ฐ์ ์ฑ์ ํ๋๋ก ํตํฉ: ์๋ ๊ฒ์ถ, ๋ผ๋ฒจ๋ง ๋๊ตฌ, ๋ฐ๋ชจ
|
| 5 |
+
RT-DETR ๋๋ VIDraft/Shrimp ํด๋ผ์ฐ๋ ๋ชจ๋ธ ์ ํ ๊ฐ๋ฅ
|
| 6 |
+
"""
|
| 7 |
+
import sys
|
| 8 |
+
sys.stdout.reconfigure(encoding='utf-8')
|
| 9 |
+
|
| 10 |
+
import gradio as gr
|
| 11 |
+
from PIL import Image, ImageDraw, ImageFont
|
| 12 |
+
import numpy as np
|
| 13 |
+
import json
|
| 14 |
+
import os
|
| 15 |
+
import glob
|
| 16 |
+
from datetime import datetime
|
| 17 |
+
import torch
|
| 18 |
+
from transformers import RTDetrForObjectDetection, RTDetrImageProcessor
|
| 19 |
+
import requests
|
| 20 |
+
import base64
|
| 21 |
+
from io import BytesIO
|
| 22 |
+
from inference_sdk import InferenceHTTPClient
|
| 23 |
+
import tempfile
|
| 24 |
+
|
| 25 |
+
# test_visual_validation์์ ๊ฐ์ ธ์ค๊ธฐ (์ง์ฐ import๋ก ๋ณ๊ฒฝ)
|
| 26 |
+
# from test_visual_validation import (
|
| 27 |
+
# load_rtdetr_model,
|
| 28 |
+
# detect_with_rtdetr,
|
| 29 |
+
# apply_universal_filter,
|
| 30 |
+
# calculate_morphological_features,
|
| 31 |
+
# calculate_visual_features
|
| 32 |
+
# )
|
| 33 |
+
|
| 34 |
+
# YOLOv8 import
|
| 35 |
+
from ultralytics import YOLO
|
| 36 |
+
|
| 37 |
+
# ============================================================
|
| 38 |
+
# YOLOv8 ๋ชจ๋ธ ์ค์
|
| 39 |
+
# ============================================================
|
| 40 |
+
YOLO_MODEL_PATH = "runs/train/yolov8m_shrimp2/weights/best.pt"
|
| 41 |
+
yolo_model = None
|
| 42 |
+
|
| 43 |
+
def load_yolo_model():
|
| 44 |
+
"""YOLOv8 ๋ชจ๋ธ ๋ก๋ฉ"""
|
| 45 |
+
global yolo_model
|
| 46 |
+
if yolo_model is None:
|
| 47 |
+
print(f"๐ YOLOv8 ๋ชจ๋ธ ๋ก๋ฉ ์ค: {YOLO_MODEL_PATH}")
|
| 48 |
+
yolo_model = YOLO(YOLO_MODEL_PATH)
|
| 49 |
+
print("โ
YOLOv8 ๋ชจ๋ธ ๋ก๋ฉ ์๋ฃ")
|
| 50 |
+
return yolo_model
|
| 51 |
+
|
| 52 |
+
def detect_with_yolo(image, confidence=0.1):
|
| 53 |
+
"""YOLOv8 ๋ชจ๋ธ๋ก ๊ฒ์ถ"""
|
| 54 |
+
try:
|
| 55 |
+
model = load_yolo_model()
|
| 56 |
+
|
| 57 |
+
# ์ถ๋ก ์คํ
|
| 58 |
+
results = model.predict(
|
| 59 |
+
source=image,
|
| 60 |
+
conf=confidence,
|
| 61 |
+
verbose=False
|
| 62 |
+
)
|
| 63 |
+
|
| 64 |
+
detections = []
|
| 65 |
+
for result in results:
|
| 66 |
+
boxes = result.boxes
|
| 67 |
+
for box in boxes:
|
| 68 |
+
x1, y1, x2, y2 = box.xyxy[0].tolist()
|
| 69 |
+
conf = box.conf[0].item()
|
| 70 |
+
|
| 71 |
+
detections.append({
|
| 72 |
+
'bbox': [x1, y1, x2, y2],
|
| 73 |
+
'confidence': conf
|
| 74 |
+
})
|
| 75 |
+
|
| 76 |
+
print(f"โ
YOLOv8 ๊ฒ์ถ ์๋ฃ: {len(detections)}๊ฐ")
|
| 77 |
+
return detections
|
| 78 |
+
|
| 79 |
+
except Exception as e:
|
| 80 |
+
print(f"โ YOLOv8 ๊ฒ์ถ ์ค๋ฅ: {str(e)}")
|
| 81 |
+
import traceback
|
| 82 |
+
traceback.print_exc()
|
| 83 |
+
return []
|
| 84 |
+
|
| 85 |
+
# ============================================================
|
| 86 |
+
# Roboflow SDK ์ค์ (์ต์ ํ๋ ๋ฐฉ์)
|
| 87 |
+
# ============================================================
|
| 88 |
+
ROBOFLOW_API_KEY = "azcIL8KDJVJMYrsERzI7"
|
| 89 |
+
|
| 90 |
+
# Roboflow Inference SDK ํด๋ผ์ด์ธํธ (connection pooling ์ง์)
|
| 91 |
+
roboflow_client = InferenceHTTPClient(
|
| 92 |
+
api_url="https://serverless.roboflow.com",
|
| 93 |
+
api_key=ROBOFLOW_API_KEY
|
| 94 |
+
)
|
| 95 |
+
|
| 96 |
+
def detect_with_roboflow(image, confidence=0.065):
|
| 97 |
+
"""Roboflow API๋ฅผ ์ฌ์ฉํ ์ต์ ํ๋ ๊ฒ์ถ (๋ก์ปฌ ํ
์คํธ์ ๋์ผ)"""
|
| 98 |
+
try:
|
| 99 |
+
# ์๋ณธ ์ด๋ฏธ์ง ๋ณด์กด
|
| 100 |
+
image_original = image
|
| 101 |
+
original_size = image_original.size
|
| 102 |
+
|
| 103 |
+
# ๋ฆฌ์ฌ์ด์ฆ (API ์ ์ก์ฉ)
|
| 104 |
+
image_resized = image_original.copy()
|
| 105 |
+
image_resized.thumbnail((640, 640), Image.Resampling.LANCZOS)
|
| 106 |
+
print(f"๐ ์ด๋ฏธ์ง ๋ฆฌ์ฌ์ด์ฆ: {original_size} โ {image_resized.size}")
|
| 107 |
+
|
| 108 |
+
# Base64 ์ธ์ฝ๋ฉ
|
| 109 |
+
buffered = BytesIO()
|
| 110 |
+
image_resized.save(buffered, format="JPEG", quality=80)
|
| 111 |
+
img_base64 = base64.b64encode(buffered.getvalue()).decode()
|
| 112 |
+
print(f"๐ฆ Base64 ํฌ๊ธฐ: {len(img_base64)} bytes")
|
| 113 |
+
|
| 114 |
+
print(f"๐ Roboflow API ์ถ๋ก ์์...")
|
| 115 |
+
|
| 116 |
+
# ๐ ์ต์ ํ 3: requests๋ก API ํธ์ถ (SDK ๋์ ์ฌ์ฉ - ๋ ์์ ์ )
|
| 117 |
+
response = requests.post(
|
| 118 |
+
'https://serverless.roboflow.com/vidraft/workflows/find-shrimp-6',
|
| 119 |
+
headers={'Content-Type': 'application/json'},
|
| 120 |
+
json={
|
| 121 |
+
'api_key': ROBOFLOW_API_KEY,
|
| 122 |
+
'inputs': {
|
| 123 |
+
'image': {'type': 'base64', 'value': img_base64}
|
| 124 |
+
}
|
| 125 |
+
},
|
| 126 |
+
timeout=30
|
| 127 |
+
)
|
| 128 |
+
|
| 129 |
+
if response.status_code != 200:
|
| 130 |
+
print(f"โ Roboflow API ์ค๋ฅ: {response.status_code}")
|
| 131 |
+
print(f"์๋ต: {response.text}")
|
| 132 |
+
return []
|
| 133 |
+
|
| 134 |
+
result = response.json()
|
| 135 |
+
print(f"๐ Roboflow ์๋ต: {json.dumps(result, indent=2, ensure_ascii=False)[:500]}...")
|
| 136 |
+
|
| 137 |
+
# Workflow ์๋ต ๊ตฌ์กฐ ํ์ฑ
|
| 138 |
+
detections = []
|
| 139 |
+
predictions = []
|
| 140 |
+
|
| 141 |
+
# ๋ฐฉ๋ฒ 1: outputs[0].predictions.predictions (workflow ํํ)
|
| 142 |
+
if isinstance(result, dict) and 'outputs' in result and len(result['outputs']) > 0:
|
| 143 |
+
output = result['outputs'][0]
|
| 144 |
+
if isinstance(output, dict) and 'predictions' in output:
|
| 145 |
+
pred_data = output['predictions']
|
| 146 |
+
# predictions๊ฐ dict์ด๊ณ ๊ทธ ์์ predictions ๋ฐฐ์ด์ด ์๋ ๊ฒฝ์ฐ
|
| 147 |
+
if isinstance(pred_data, dict) and 'predictions' in pred_data:
|
| 148 |
+
predictions = pred_data['predictions']
|
| 149 |
+
# predictions๊ฐ ๋ฐ๋ก ๋ฐฐ์ด์ธ ๊ฒฝ์ฐ
|
| 150 |
+
elif isinstance(pred_data, list):
|
| 151 |
+
predictions = pred_data
|
| 152 |
+
else:
|
| 153 |
+
predictions = [pred_data]
|
| 154 |
+
|
| 155 |
+
# ๋ฐฉ๋ฒ 2: ์ง์ predictions
|
| 156 |
+
elif isinstance(result, dict) and 'predictions' in result:
|
| 157 |
+
predictions = result['predictions']
|
| 158 |
+
|
| 159 |
+
# ๋ฐฉ๋ฒ 3: ๋ค๋ฅธ ๊ตฌ์กฐ
|
| 160 |
+
elif isinstance(result, list):
|
| 161 |
+
predictions = result
|
| 162 |
+
|
| 163 |
+
print(f"๐ฆ ์ฐพ์ predictions: {len(predictions)}๊ฐ")
|
| 164 |
+
|
| 165 |
+
# ์ค์ผ์ผ ๊ณ์ฐ (๋ฆฌ์ฌ์ด์ฆ๋ ์ขํ โ ์๋ณธ ์ขํ)
|
| 166 |
+
scale_x = original_size[0] / image_resized.size[0]
|
| 167 |
+
scale_y = original_size[1] / image_resized.size[1]
|
| 168 |
+
print(f"๐ ์ค์ผ์ผ: x={scale_x:.2f}, y={scale_y:.2f}")
|
| 169 |
+
|
| 170 |
+
for pred in predictions:
|
| 171 |
+
# ํด๋์ค ํํฐ๋ง (shrimp๋ง ๊ฒ์ถ)
|
| 172 |
+
pred_class = pred.get('class', '')
|
| 173 |
+
if pred_class != 'shrimp':
|
| 174 |
+
continue
|
| 175 |
+
|
| 176 |
+
# ์ ๋ขฐ๋ ํํฐ๋ง
|
| 177 |
+
pred_confidence = pred.get('confidence', 0)
|
| 178 |
+
if pred_confidence < confidence:
|
| 179 |
+
continue
|
| 180 |
+
|
| 181 |
+
# ๋ฐ์ด๋ฉ ๋ฐ์ค ์ถ์ถ (๋ฆฌ์ฌ์ด์ฆ๋ ์ขํ)
|
| 182 |
+
x = pred.get('x', 0)
|
| 183 |
+
y = pred.get('y', 0)
|
| 184 |
+
width = pred.get('width', 0)
|
| 185 |
+
height = pred.get('height', 0)
|
| 186 |
+
|
| 187 |
+
# ์๋ณธ ํฌ๊ธฐ๋ก ์ค์ผ์ผ ๋ณํ
|
| 188 |
+
x_scaled = x * scale_x
|
| 189 |
+
y_scaled = y * scale_y
|
| 190 |
+
width_scaled = width * scale_x
|
| 191 |
+
height_scaled = height * scale_y
|
| 192 |
+
|
| 193 |
+
# ์ค์ฌ์ ์ขํ๋ฅผ ์ข์๋จ/์ฐํ๋จ ์ขํ๋ก ๋ณํ
|
| 194 |
+
x1 = x_scaled - width_scaled / 2
|
| 195 |
+
y1 = y_scaled - height_scaled / 2
|
| 196 |
+
x2 = x_scaled + width_scaled / 2
|
| 197 |
+
y2 = y_scaled + height_scaled / 2
|
| 198 |
+
|
| 199 |
+
detections.append({
|
| 200 |
+
'bbox': [x1, y1, x2, y2],
|
| 201 |
+
'confidence': pred_confidence
|
| 202 |
+
})
|
| 203 |
+
print(f" โ ๊ฒ์ถ (shrimp): conf={pred_confidence:.2%}, bbox=[{x1:.0f},{y1:.0f},{x2:.0f},{y2:.0f}]")
|
| 204 |
+
|
| 205 |
+
print(f"โ
Roboflow ๊ฒ์ถ ์๋ฃ: {len(detections)}๊ฐ")
|
| 206 |
+
return detections
|
| 207 |
+
|
| 208 |
+
except Exception as e:
|
| 209 |
+
print(f"โ Roboflow SDK ์ค๋ฅ: {str(e)}")
|
| 210 |
+
import traceback
|
| 211 |
+
traceback.print_exc()
|
| 212 |
+
return []
|
| 213 |
+
|
| 214 |
+
# ============================================================
|
| 215 |
+
# ์ ์ญ ๋ชจ๋ธ ๋ณ์ (์ง์ฐ ๋ก๋ฉ)
|
| 216 |
+
# ============================================================
|
| 217 |
+
processor = None
|
| 218 |
+
model = None
|
| 219 |
+
|
| 220 |
+
def load_rtdetr_on_demand():
|
| 221 |
+
"""RT-DETR ๋ชจ๋ธ์ ํ์์์๋ง ๋ก๋ฉ"""
|
| 222 |
+
global processor, model
|
| 223 |
+
if processor is None or model is None:
|
| 224 |
+
print("๐ RT-DETR ๋ชจ๋ธ ๋ก๋ฉ ์ค...")
|
| 225 |
+
from test_visual_validation import load_rtdetr_model
|
| 226 |
+
processor, model = load_rtdetr_model()
|
| 227 |
+
print("โ
RT-DETR ๋ก๋ฉ ์๋ฃ")
|
| 228 |
+
return "โ
RT-DETR ๋ชจ๋ธ ๋ก๋ฉ ์๋ฃ"
|
| 229 |
+
else:
|
| 230 |
+
return "โน๏ธ RT-DETR ๋ชจ๋ธ์ด ์ด๋ฏธ ๋ก๋ฉ๋์ด ์์ต๋๋ค"
|
| 231 |
+
|
| 232 |
+
print("โ
VIDraft/Shrimp ํด๋ผ์ฐ๋ ๋ชจ๋ธ ์ฌ์ฉ ๊ฐ๋ฅ\n")
|
| 233 |
+
|
| 234 |
+
# ============================================================
|
| 235 |
+
# ๋ผ๋ฒจ๋ง ๋๊ตฌ ์ ์ญ ๋ณ์
|
| 236 |
+
# ============================================================
|
| 237 |
+
current_data = {
|
| 238 |
+
'folder': None,
|
| 239 |
+
'images': [],
|
| 240 |
+
'current_idx': 0,
|
| 241 |
+
'detections': {},
|
| 242 |
+
'selections': {},
|
| 243 |
+
'confidence_threshold': 0.2,
|
| 244 |
+
'image_cache': {},
|
| 245 |
+
'model_type': 'RT-DETR' # ํ์ฌ ์ ํ๋ ๋ชจ๋ธ
|
| 246 |
+
}
|
| 247 |
+
|
| 248 |
+
GROUND_TRUTH_FILE = "ground_truth.json"
|
| 249 |
+
DATA_BASE = "data/ํฐ๋ค๋ฆฌ์์ฐ ์ค์ธก ๋ฐ์ดํฐ_์ตํฌ์ค์์ด์์ด(์ฃผ)"
|
| 250 |
+
|
| 251 |
+
# ============================================================
|
| 252 |
+
# ๋ชจ๋ธ๋ณ ๊ฒ์ถ ํจ์
|
| 253 |
+
# ============================================================
|
| 254 |
+
|
| 255 |
+
def detect_with_selected_model(image, confidence, model_type):
|
| 256 |
+
"""์ ํ๋ ๋ชจ๋ธ๋ก ๊ฒ์ถ"""
|
| 257 |
+
if model_type == "RT-DETR":
|
| 258 |
+
if processor is None or model is None:
|
| 259 |
+
raise ValueError("โ ๏ธ RT-DETR ๋ชจ๋ธ์ด ๋ก๋ฉ๋์ง ์์์ต๋๋ค. '๐ RT-DETR ๋ก๋' ๋ฒํผ์ ๋จผ์ ํด๋ฆญํ์ธ์.")
|
| 260 |
+
from test_visual_validation import detect_with_rtdetr
|
| 261 |
+
return detect_with_rtdetr(image, processor, model, confidence)
|
| 262 |
+
elif model_type == "VIDraft/Shrimp":
|
| 263 |
+
return detect_with_roboflow(image, confidence)
|
| 264 |
+
elif model_type == "YOLOv8":
|
| 265 |
+
return detect_with_yolo(image, confidence)
|
| 266 |
+
else:
|
| 267 |
+
return []
|
| 268 |
+
|
| 269 |
+
# ============================================================
|
| 270 |
+
# ํญ 1: ์๋ ๊ฒ์ถ (Interactive Validation)
|
| 271 |
+
# ============================================================
|
| 272 |
+
|
| 273 |
+
def interactive_detect(image, confidence, filter_threshold, show_all, model_type, use_filter):
|
| 274 |
+
"""๋ํํ ๊ฒ์ถ"""
|
| 275 |
+
if image is None:
|
| 276 |
+
return None, "โ ๏ธ ์ด๋ฏธ์ง๋ฅผ ์
๋ก๋ํ์ธ์."
|
| 277 |
+
|
| 278 |
+
try:
|
| 279 |
+
# ์ ํ๋ ๋ชจ๋ธ๋ก ๊ฒ์ถ
|
| 280 |
+
all_detections = detect_with_selected_model(image, confidence, model_type)
|
| 281 |
+
|
| 282 |
+
# ํํฐ ์ ์ฉ ์ฌ๋ถ์ ๋ฐ๋ผ ์ฒ๋ฆฌ
|
| 283 |
+
if not use_filter:
|
| 284 |
+
# ํํฐ ๋ฏธ์ฌ์ฉ: ์ ๋ขฐ๋๋ง ์ ์ฉ
|
| 285 |
+
filtered_detections = all_detections
|
| 286 |
+
for det in filtered_detections:
|
| 287 |
+
det['filter_score'] = det['confidence'] * 100
|
| 288 |
+
det['filter_reasons'] = [f"์ ๋ขฐ๋: {det['confidence']:.0%} (ํํฐ ๋ฏธ์ฌ์ฉ)"]
|
| 289 |
+
all_detections_scored = filtered_detections
|
| 290 |
+
else:
|
| 291 |
+
# ํํฐ ์ฌ์ฉ
|
| 292 |
+
if model_type in ["VIDraft/Shrimp", "YOLOv8"]:
|
| 293 |
+
# Roboflow & YOLOv8: ์ ๋ขฐ๋๋ฅผ ํํฐ ์ ์๋ก ์ฌ์ฉ
|
| 294 |
+
for det in all_detections:
|
| 295 |
+
det['filter_score'] = det['confidence'] * 100
|
| 296 |
+
det['filter_reasons'] = [f"{model_type} ์ ๋ขฐ๋: {det['confidence']:.0%}"]
|
| 297 |
+
all_detections_scored = all_detections
|
| 298 |
+
else:
|
| 299 |
+
# RT-DETR: Universal Filter ์ฌ์ฉ
|
| 300 |
+
from test_visual_validation import apply_universal_filter
|
| 301 |
+
all_detections_scored = apply_universal_filter(all_detections, image, threshold=0)
|
| 302 |
+
|
| 303 |
+
# ํํฐ ์๊ณ๊ฐ ์ ์ฉ
|
| 304 |
+
filtered_detections = [det for det in all_detections_scored if det['filter_score'] >= filter_threshold]
|
| 305 |
+
|
| 306 |
+
# ์๊ฐํ
|
| 307 |
+
img = image.copy()
|
| 308 |
+
draw = ImageDraw.Draw(img)
|
| 309 |
+
|
| 310 |
+
try:
|
| 311 |
+
font = ImageFont.truetype("arial.ttf", 14)
|
| 312 |
+
font_large = ImageFont.truetype("arial.ttf", 18)
|
| 313 |
+
font_small = ImageFont.truetype("arial.ttf", 10)
|
| 314 |
+
except:
|
| 315 |
+
font = ImageFont.load_default()
|
| 316 |
+
font_large = ImageFont.load_default()
|
| 317 |
+
font_small = ImageFont.load_default()
|
| 318 |
+
|
| 319 |
+
# ์ ๊ฑฐ๋ ๊ฐ์ฒด ๋จผ์ ํ์ (๋นจ๊ฐ์)
|
| 320 |
+
rejected_detections = [det for det in all_detections_scored if det['filter_score'] < filter_threshold]
|
| 321 |
+
for idx, det in enumerate(rejected_detections, 1):
|
| 322 |
+
x1, y1, x2, y2 = det['bbox']
|
| 323 |
+
score = det['filter_score']
|
| 324 |
+
|
| 325 |
+
# ๋นจ๊ฐ์ ๋ฐ์ค (์ ๊ฑฐ๋จ)
|
| 326 |
+
draw.rectangle([x1, y1, x2, y2], outline="red", width=8)
|
| 327 |
+
|
| 328 |
+
# ๋ผ๋ฒจ (์๊ฒ)
|
| 329 |
+
label = f"โ{idx} {score:.0f}์ "
|
| 330 |
+
bbox = draw.textbbox((x1, y1 - 20), label, font=font_small)
|
| 331 |
+
draw.rectangle(bbox, fill="red")
|
| 332 |
+
draw.text((x1, y1 - 20), label, fill="white", font=font_small)
|
| 333 |
+
|
| 334 |
+
# ์ ์ฒด ๊ฒ์ถ ํ์ (์ต์
) - ํ์
|
| 335 |
+
if show_all:
|
| 336 |
+
for det in all_detections_scored:
|
| 337 |
+
if det not in filtered_detections and det not in rejected_detections:
|
| 338 |
+
x1, y1, x2, y2 = det['bbox']
|
| 339 |
+
draw.rectangle([x1, y1, x2, y2], outline="gray", width=4)
|
| 340 |
+
|
| 341 |
+
# ํํฐ๋ง๋ ๊ฒฐ๊ณผ (ํต๊ณผ) - ๋
น์/๋
ธ๋์/์ฃผํฉ์
|
| 342 |
+
for idx, det in enumerate(filtered_detections, 1):
|
| 343 |
+
x1, y1, x2, y2 = det['bbox']
|
| 344 |
+
score = det['filter_score']
|
| 345 |
+
|
| 346 |
+
# ์ ์์ ๋ฐ๋ผ ์์
|
| 347 |
+
if score >= 75:
|
| 348 |
+
color = "lime"
|
| 349 |
+
elif score >= 50:
|
| 350 |
+
color = "yellow"
|
| 351 |
+
else:
|
| 352 |
+
color = "orange"
|
| 353 |
+
|
| 354 |
+
# ๋ฐ์ค (๋๊ป๊ฒ)
|
| 355 |
+
draw.rectangle([x1, y1, x2, y2], outline=color, width=10)
|
| 356 |
+
|
| 357 |
+
# ๋ผ๋ฒจ
|
| 358 |
+
label = f"โ#{idx} {score:.0f}์ "
|
| 359 |
+
bbox = draw.textbbox((x1, y1 - 25), label, font=font)
|
| 360 |
+
draw.rectangle(bbox, fill=color)
|
| 361 |
+
draw.text((x1, y1 - 25), label, fill="black", font=font)
|
| 362 |
+
|
| 363 |
+
# ์ธ๋ถ ์ ๋ณด (์๊ฒ)
|
| 364 |
+
details = f"{model_type}:{det['confidence']:.0%}"
|
| 365 |
+
draw.text((x1, y2 + 5), details, fill=color, font=font_small)
|
| 366 |
+
|
| 367 |
+
# ํค๋
|
| 368 |
+
header = f"[{model_type}] โ {len(filtered_detections)}๊ฐ / โ {len(rejected_detections)}๊ฐ (์ ์ฒด: {len(all_detections_scored)}๊ฐ)"
|
| 369 |
+
header_bbox = draw.textbbox((10, 10), header, font=font_large)
|
| 370 |
+
draw.rectangle([5, 5, header_bbox[2]+10, header_bbox[3]+10],
|
| 371 |
+
fill="black", outline="lime", width=2)
|
| 372 |
+
draw.text((10, 10), header, fill="lime", font=font_large)
|
| 373 |
+
|
| 374 |
+
# ์ ๋ณด ์์ฑ
|
| 375 |
+
info = f"""
|
| 376 |
+
### ๐ ๊ฒ์ถ ๊ฒฐ๊ณผ (๋ชจ๋ธ: {model_type})
|
| 377 |
+
|
| 378 |
+
- **์ ์ฒด ๊ฒ์ถ**: {len(all_detections_scored)}๊ฐ
|
| 379 |
+
- **ํํฐ๋ง ํ**: {len(filtered_detections)}๊ฐ
|
| 380 |
+
- **์ ๊ฑฐ๋จ**: {len(rejected_detections)}๊ฐ
|
| 381 |
+
|
| 382 |
+
---
|
| 383 |
+
|
| 384 |
+
### ๐ฏ ๊ฒ์ถ๋ ๊ฐ์ฒด ์์ธ (โ
ํต๊ณผ)
|
| 385 |
+
|
| 386 |
+
"""
|
| 387 |
+
|
| 388 |
+
for idx, det in enumerate(filtered_detections, 1):
|
| 389 |
+
info += f"""
|
| 390 |
+
**#{idx} - ์ ์: {det['filter_score']:.0f}์ ** ({model_type} ์ ๋ขฐ๋: {det['confidence']:.0%})
|
| 391 |
+
|
| 392 |
+
"""
|
| 393 |
+
# ์ฃผ์ ํน์ง๋ง 5๊ฐ
|
| 394 |
+
for reason in det['filter_reasons'][:5]:
|
| 395 |
+
info += f"- {reason}\n"
|
| 396 |
+
|
| 397 |
+
if not filtered_detections:
|
| 398 |
+
info += """
|
| 399 |
+
โ ๏ธ **๊ฒ์ถ๋ ๊ฐ์ฒด๊ฐ ์์ต๋๋ค.**
|
| 400 |
+
|
| 401 |
+
"""
|
| 402 |
+
|
| 403 |
+
# ์ ๊ฑฐ๋ ๊ฐ์ฒด ์ ๋ณด ์ถ๊ฐ
|
| 404 |
+
if rejected_detections:
|
| 405 |
+
info += f"""
|
| 406 |
+
|
| 407 |
+
---
|
| 408 |
+
|
| 409 |
+
### โ ์ ๊ฑฐ๋ ๊ฐ์ฒด ({len(rejected_detections)}๊ฐ)
|
| 410 |
+
|
| 411 |
+
"""
|
| 412 |
+
for idx, det in enumerate(rejected_detections[:3], 1): # ์ต๋ 3๊ฐ๋ง ํ์
|
| 413 |
+
info += f"""
|
| 414 |
+
**์ ๊ฑฐ #{idx} - ์ ์: {det['filter_score']:.0f}์ ** (์๊ณ๊ฐ ๋ฏธ๋ฌ)
|
| 415 |
+
- {model_type} ์ ๋ขฐ๋: {det['confidence']:.0%}
|
| 416 |
+
|
| 417 |
+
"""
|
| 418 |
+
# ์คํจ ์ด์ ํ์
|
| 419 |
+
for reason in det['filter_reasons'][:3]:
|
| 420 |
+
info += f"- {reason}\n"
|
| 421 |
+
|
| 422 |
+
return img, info
|
| 423 |
+
|
| 424 |
+
except Exception as e:
|
| 425 |
+
import traceback
|
| 426 |
+
error_detail = traceback.format_exc()
|
| 427 |
+
return None, f"โ ์ค๋ฅ ๋ฐ์:\n\n```\n{error_detail}\n```"
|
| 428 |
+
|
| 429 |
+
|
| 430 |
+
# ============================================================
|
| 431 |
+
# ํญ 2: ๋ผ๋ฒจ๋ง ๋๊ตฌ (Labeling Tool)
|
| 432 |
+
# ============================================================
|
| 433 |
+
|
| 434 |
+
def detect_with_rtdetr_fast(image, confidence=0.3):
|
| 435 |
+
"""RT-DETR ๋น ๋ฅธ ๊ฒ์ถ"""
|
| 436 |
+
inputs = processor(images=image, return_tensors="pt")
|
| 437 |
+
with torch.no_grad():
|
| 438 |
+
outputs = model(**inputs)
|
| 439 |
+
|
| 440 |
+
target_sizes = torch.tensor([image.size[::-1]])
|
| 441 |
+
results = processor.post_process_object_detection(
|
| 442 |
+
outputs,
|
| 443 |
+
target_sizes=target_sizes,
|
| 444 |
+
threshold=confidence
|
| 445 |
+
)[0]
|
| 446 |
+
|
| 447 |
+
detections = []
|
| 448 |
+
for score, label, box in zip(results["scores"], results["labels"], results["boxes"]):
|
| 449 |
+
x1, y1, x2, y2 = box.tolist()
|
| 450 |
+
detections.append({
|
| 451 |
+
'bbox': [x1, y1, x2, y2],
|
| 452 |
+
'confidence': score.item()
|
| 453 |
+
})
|
| 454 |
+
|
| 455 |
+
return detections
|
| 456 |
+
|
| 457 |
+
|
| 458 |
+
def load_existing_ground_truth():
|
| 459 |
+
"""๊ธฐ์กด ground_truth.json ๋ก๋"""
|
| 460 |
+
if os.path.exists(GROUND_TRUTH_FILE):
|
| 461 |
+
with open(GROUND_TRUTH_FILE, 'r', encoding='utf-8') as f:
|
| 462 |
+
return json.load(f)
|
| 463 |
+
return {}
|
| 464 |
+
|
| 465 |
+
|
| 466 |
+
def save_ground_truth(data):
|
| 467 |
+
"""ground_truth.json ์ ์ฅ"""
|
| 468 |
+
backup_dir = "backups"
|
| 469 |
+
if not os.path.exists(backup_dir):
|
| 470 |
+
os.makedirs(backup_dir)
|
| 471 |
+
|
| 472 |
+
if os.path.exists(GROUND_TRUTH_FILE):
|
| 473 |
+
backup_name = f"ground_truth_backup_{datetime.now().strftime('%Y%m%d_%H%M%S')}.json"
|
| 474 |
+
backup_path = os.path.join(backup_dir, backup_name)
|
| 475 |
+
import shutil
|
| 476 |
+
shutil.copy2(GROUND_TRUTH_FILE, backup_path)
|
| 477 |
+
|
| 478 |
+
with open(GROUND_TRUTH_FILE, 'w', encoding='utf-8') as f:
|
| 479 |
+
json.dump(data, f, ensure_ascii=False, indent=2)
|
| 480 |
+
|
| 481 |
+
print(f"โ
Ground Truth ์ ์ฅ ์๋ฃ: {len(data)}๊ฐ ์ด๋ฏธ์ง")
|
| 482 |
+
|
| 483 |
+
|
| 484 |
+
def get_folders():
|
| 485 |
+
"""์ฌ์ฉ ๊ฐ๋ฅํ ํด๋ ๋ชฉ๋ก"""
|
| 486 |
+
folders = sorted(glob.glob(os.path.join(DATA_BASE, "2*")))
|
| 487 |
+
return [os.path.basename(f) for f in folders if os.path.isdir(f)]
|
| 488 |
+
|
| 489 |
+
|
| 490 |
+
def start_labeling(folder, conf_threshold, model_type):
|
| 491 |
+
"""๋ผ๋ฒจ๋ง ์์"""
|
| 492 |
+
if not folder:
|
| 493 |
+
return None, "โ ํด๋๋ฅผ ์ ํํ์ธ์.", ""
|
| 494 |
+
|
| 495 |
+
current_data['folder'] = folder
|
| 496 |
+
current_data['confidence_threshold'] = conf_threshold
|
| 497 |
+
current_data['model_type'] = model_type
|
| 498 |
+
|
| 499 |
+
folder_path = os.path.join(DATA_BASE, folder)
|
| 500 |
+
all_images = sorted(glob.glob(os.path.join(folder_path, "*.jpg")))
|
| 501 |
+
|
| 502 |
+
# -1, -2 ๋ฑ์ด ๋ถ์ ํ์ผ ์ ์ธ (์: 251017_01-1.jpg ์ ์ธ, 251017_01.jpg๋ง ํฌํจ)
|
| 503 |
+
import re
|
| 504 |
+
images = [img for img in all_images if not re.search(r'-\d+\.jpg$', os.path.basename(img))]
|
| 505 |
+
|
| 506 |
+
if not images:
|
| 507 |
+
return None, "โ ์ด๋ฏธ์ง ์์", ""
|
| 508 |
+
|
| 509 |
+
print(f"๐ ํด๋: {folder}")
|
| 510 |
+
print(f" ์ ์ฒด ์ด๋ฏธ์ง: {len(all_images)}๊ฐ")
|
| 511 |
+
print(f" ๋ผ๋ฒจ๋ง ๋์: {len(images)}๊ฐ (-์ซ์ ํ์ผ ์ ์ธ)")
|
| 512 |
+
|
| 513 |
+
current_data['images'] = images
|
| 514 |
+
current_data['current_idx'] = 0
|
| 515 |
+
current_data['detections'] = {}
|
| 516 |
+
current_data['selections'] = {}
|
| 517 |
+
|
| 518 |
+
# ๊ธฐ์กด GT ๋ก๋
|
| 519 |
+
gt = load_existing_ground_truth()
|
| 520 |
+
|
| 521 |
+
# ์ด๋ฏธ ๋ผ๋ฒจ๋ง๋ ์ด๋ฏธ์ง ๊ฑด๋๋ฐ๊ธฐ
|
| 522 |
+
for i, img_path in enumerate(images):
|
| 523 |
+
filename = os.path.basename(img_path)
|
| 524 |
+
if filename in gt:
|
| 525 |
+
current_data['selections'][filename] = [j for j in range(len(gt[filename]))]
|
| 526 |
+
print(f"โญ๏ธ ๊ฑด๋๋ฐ๊ธฐ: {filename} (์ด๋ฏธ ๋ผ๋ฒจ๋ง๋จ)")
|
| 527 |
+
|
| 528 |
+
# ์ฒซ ๋ฏธ๋ผ๋ฒจ๋ง ์ด๋ฏธ์ง ์ฐพ๊ธฐ
|
| 529 |
+
while current_data['current_idx'] < len(images):
|
| 530 |
+
filename = os.path.basename(images[current_data['current_idx']])
|
| 531 |
+
if filename not in current_data['selections']:
|
| 532 |
+
break
|
| 533 |
+
current_data['current_idx'] += 1
|
| 534 |
+
|
| 535 |
+
if current_data['current_idx'] >= len(images):
|
| 536 |
+
return None, "โ
๋ชจ๋ ์ด๋ฏธ์ง ๋ผ๋ฒจ๋ง ์๋ฃ!", ""
|
| 537 |
+
|
| 538 |
+
return show_current_image()
|
| 539 |
+
|
| 540 |
+
|
| 541 |
+
def show_current_image():
|
| 542 |
+
"""ํ์ฌ ์ด๋ฏธ์ง ํ์"""
|
| 543 |
+
if current_data['current_idx'] >= len(current_data['images']):
|
| 544 |
+
return None, "โ
์๋ฃ!", ""
|
| 545 |
+
|
| 546 |
+
img_path = current_data['images'][current_data['current_idx']]
|
| 547 |
+
filename = os.path.basename(img_path)
|
| 548 |
+
|
| 549 |
+
# ์บ์ ํ์ธ
|
| 550 |
+
if filename in current_data['image_cache']:
|
| 551 |
+
image = current_data['image_cache'][filename]
|
| 552 |
+
else:
|
| 553 |
+
image = Image.open(img_path)
|
| 554 |
+
current_data['image_cache'][filename] = image
|
| 555 |
+
|
| 556 |
+
# ์ ํ๋ ๋ชจ๋ธ๋ก ๊ฒ์ถ
|
| 557 |
+
if filename not in current_data['detections']:
|
| 558 |
+
if current_data['model_type'] == 'RT-DETR':
|
| 559 |
+
detections = detect_with_rtdetr_fast(image, current_data['confidence_threshold'])
|
| 560 |
+
elif current_data['model_type'] == 'YOLOv8':
|
| 561 |
+
detections = detect_with_yolo(image, current_data['confidence_threshold'])
|
| 562 |
+
else: # VIDraft/Shrimp
|
| 563 |
+
detections = detect_with_roboflow(image, current_data['confidence_threshold'])
|
| 564 |
+
current_data['detections'][filename] = detections
|
| 565 |
+
else:
|
| 566 |
+
detections = current_data['detections'][filename]
|
| 567 |
+
|
| 568 |
+
# ์ ํ๋ ๋ฐ์ค
|
| 569 |
+
selected_indices = current_data['selections'].get(filename, [])
|
| 570 |
+
|
| 571 |
+
# ์๊ฐํ
|
| 572 |
+
vis_image = draw_detections(image, detections, selected_indices)
|
| 573 |
+
|
| 574 |
+
info = f"""
|
| 575 |
+
### ๐ {current_data['folder']} - ์ด๋ฏธ์ง {current_data['current_idx']+1}/{len(current_data['images'])}
|
| 576 |
+
|
| 577 |
+
**ํ์ผ**: {filename}
|
| 578 |
+
**๋ชจ๋ธ**: {current_data['model_type']}
|
| 579 |
+
|
| 580 |
+
**๊ฒ์ถ**: {len(detections)}๊ฐ
|
| 581 |
+
**์ ํ**: {len(selected_indices)}๊ฐ
|
| 582 |
+
|
| 583 |
+
---
|
| 584 |
+
|
| 585 |
+
### ๐ฑ๏ธ ์ฌ์ฉ ๋ฐฉ๋ฒ:
|
| 586 |
+
1. ์ด๋ฏธ์ง๋ฅผ ํด๋ฆญํ์ฌ ๋ฐ์ค ์ ํ/ํด์
|
| 587 |
+
2. "๋ค์" ๋ฒํผ์ผ๋ก ์ ์ฅ ํ ์ด๋
|
| 588 |
+
3. "๊ฑด๋๋ฐ๊ธฐ"๋ก ์ ํ ์์ด ์ด๋
|
| 589 |
+
"""
|
| 590 |
+
|
| 591 |
+
return vis_image, info, filename
|
| 592 |
+
|
| 593 |
+
|
| 594 |
+
def draw_detections(image, detections, selected_indices):
|
| 595 |
+
"""๊ฒ์ถ ๊ฒฐ๊ณผ ๊ทธ๋ฆฌ๊ธฐ"""
|
| 596 |
+
img = image.copy()
|
| 597 |
+
draw = ImageDraw.Draw(img)
|
| 598 |
+
|
| 599 |
+
try:
|
| 600 |
+
font_tiny = ImageFont.truetype("arial.ttf", 10)
|
| 601 |
+
font_large = ImageFont.truetype("arial.ttf", 40)
|
| 602 |
+
except:
|
| 603 |
+
font_tiny = ImageFont.load_default()
|
| 604 |
+
font_large = ImageFont.load_default()
|
| 605 |
+
|
| 606 |
+
# ์ ํ๋์ง ์์ ๋ฐ์ค ๋จผ์ (๋ค์ชฝ ๋ ์ด์ด)
|
| 607 |
+
for idx, det in enumerate(detections):
|
| 608 |
+
if idx not in selected_indices:
|
| 609 |
+
x1, y1, x2, y2 = det['bbox']
|
| 610 |
+
draw.rectangle([x1, y1, x2, y2], outline="lime", width=20)
|
| 611 |
+
corner_label = f"#{idx+1}"
|
| 612 |
+
draw.rectangle([x1-2, y1-24, x1+30, y1-2], fill="lime")
|
| 613 |
+
draw.text((x1, y1 - 22), corner_label, fill="white", font=font_tiny)
|
| 614 |
+
|
| 615 |
+
# ์ ํ๋ ๋ฐ์ค ๋์ค์ (์์ชฝ ๋ ์ด์ด)
|
| 616 |
+
for idx, det in enumerate(detections):
|
| 617 |
+
if idx in selected_indices:
|
| 618 |
+
x1, y1, x2, y2 = det['bbox']
|
| 619 |
+
draw.rectangle([x1, y1, x2, y2], outline="blue", width=28)
|
| 620 |
+
corner_label = f"โ#{idx+1}"
|
| 621 |
+
draw.rectangle([x1-2, y1-24, x1+40, y1-2], fill="blue")
|
| 622 |
+
draw.text((x1, y1 - 22), corner_label, fill="white", font=font_tiny)
|
| 623 |
+
|
| 624 |
+
# ์ํ ๋ฒํผ
|
| 625 |
+
for idx, det in enumerate(detections):
|
| 626 |
+
x1, y1, x2, y2 = det['bbox']
|
| 627 |
+
center_x = (x1 + x2) / 2
|
| 628 |
+
center_y = (y1 + y2) / 2
|
| 629 |
+
|
| 630 |
+
selected = idx in selected_indices
|
| 631 |
+
btn_color = "blue" if selected else "lime"
|
| 632 |
+
btn_text = f"โ{idx+1}" if selected else f"{idx+1}"
|
| 633 |
+
|
| 634 |
+
box_width = x2 - x1
|
| 635 |
+
box_height = y2 - y1
|
| 636 |
+
radius = min(55, box_width * 0.18, box_height * 0.35)
|
| 637 |
+
|
| 638 |
+
# ์ํ ๋ฒํผ
|
| 639 |
+
draw.ellipse(
|
| 640 |
+
[center_x - radius, center_y - radius,
|
| 641 |
+
center_x + radius, center_y + radius],
|
| 642 |
+
fill=btn_color, outline="white", width=4
|
| 643 |
+
)
|
| 644 |
+
draw.text((center_x - radius*0.5, center_y - radius*0.6),
|
| 645 |
+
btn_text, fill="white", font=font_large)
|
| 646 |
+
|
| 647 |
+
return img
|
| 648 |
+
|
| 649 |
+
|
| 650 |
+
def labeling_click(image, filename, evt: gr.SelectData):
|
| 651 |
+
"""์ด๋ฏธ์ง ํด๋ฆญ ์ด๋ฒคํธ"""
|
| 652 |
+
if not filename or filename not in current_data['detections']:
|
| 653 |
+
return image, "โ ๏ธ ์ด๋ฏธ์ง๋ฅผ ๋จผ์ ๋ก๋ํ์ธ์."
|
| 654 |
+
|
| 655 |
+
click_x, click_y = evt.index[0], evt.index[1]
|
| 656 |
+
detections = current_data['detections'][filename]
|
| 657 |
+
selected_indices = set(current_data['selections'].get(filename, []))
|
| 658 |
+
|
| 659 |
+
# ํด๋ฆญํ ๋ฐ์ค ์ฐพ๊ธฐ
|
| 660 |
+
clicked_idx = None
|
| 661 |
+
button_candidates = []
|
| 662 |
+
|
| 663 |
+
# ๋ฒํผ ์์ญ ํ์ธ
|
| 664 |
+
for idx, det in enumerate(detections):
|
| 665 |
+
x1, y1, x2, y2 = det['bbox']
|
| 666 |
+
center_x = (x1 + x2) / 2
|
| 667 |
+
center_y = (y1 + y2) / 2
|
| 668 |
+
|
| 669 |
+
box_width = x2 - x1
|
| 670 |
+
box_height = y2 - y1
|
| 671 |
+
radius = min(55, box_width * 0.18, box_height * 0.35)
|
| 672 |
+
|
| 673 |
+
distance = ((click_x - center_x) ** 2 + (click_y - center_y) ** 2) ** 0.5
|
| 674 |
+
|
| 675 |
+
if distance <= radius:
|
| 676 |
+
button_candidates.append((idx, distance))
|
| 677 |
+
|
| 678 |
+
# ๋ฒํผ ํด๋ฆญ์ด ์์ผ๋ฉด ์ ํ
|
| 679 |
+
if button_candidates:
|
| 680 |
+
button_candidates.sort(key=lambda x: x[1])
|
| 681 |
+
clicked_idx = button_candidates[0][0]
|
| 682 |
+
else:
|
| 683 |
+
# ๋ฐ์ค ์์ญ ํด๋ฆญ ํ์ธ
|
| 684 |
+
for idx, det in enumerate(detections):
|
| 685 |
+
x1, y1, x2, y2 = det['bbox']
|
| 686 |
+
if x1 <= click_x <= x2 and y1 <= click_y <= y2:
|
| 687 |
+
clicked_idx = idx
|
| 688 |
+
break
|
| 689 |
+
|
| 690 |
+
# ์ ํ ํ ๊ธ
|
| 691 |
+
if clicked_idx is not None:
|
| 692 |
+
if clicked_idx in selected_indices:
|
| 693 |
+
selected_indices.remove(clicked_idx)
|
| 694 |
+
print(f"โ ์ ํ ํด์ : ๋ฐ์ค #{clicked_idx+1}")
|
| 695 |
+
else:
|
| 696 |
+
selected_indices.add(clicked_idx)
|
| 697 |
+
print(f"โ
์ ํ: ๋ฐ์ค #{clicked_idx+1}")
|
| 698 |
+
|
| 699 |
+
current_data['selections'][filename] = list(selected_indices)
|
| 700 |
+
|
| 701 |
+
# ์ด๋ฏธ์ง ๋ค์ ๊ทธ๋ฆฌ๊ธฐ
|
| 702 |
+
img_path = current_data['images'][current_data['current_idx']]
|
| 703 |
+
image = Image.open(img_path)
|
| 704 |
+
vis_image = draw_detections(image, detections, list(selected_indices))
|
| 705 |
+
|
| 706 |
+
info = f"โ
๋ฐ์ค #{clicked_idx+1} {'์ ํ' if clicked_idx in selected_indices else 'ํด์ '}"
|
| 707 |
+
return vis_image, info
|
| 708 |
+
|
| 709 |
+
return image, "โ ๋ฐ์ค๋ฅผ ์ฐพ์ ์ ์์ต๋๋ค."
|
| 710 |
+
|
| 711 |
+
|
| 712 |
+
def save_and_next():
|
| 713 |
+
"""์ ์ฅ ํ ๋ค์"""
|
| 714 |
+
if current_data['current_idx'] >= len(current_data['images']):
|
| 715 |
+
return None, "โ
์๋ฃ!", ""
|
| 716 |
+
|
| 717 |
+
img_path = current_data['images'][current_data['current_idx']]
|
| 718 |
+
filename = os.path.basename(img_path)
|
| 719 |
+
|
| 720 |
+
# GT ์ ์ฅ
|
| 721 |
+
gt = load_existing_ground_truth()
|
| 722 |
+
selected_indices = current_data['selections'].get(filename, [])
|
| 723 |
+
|
| 724 |
+
if selected_indices:
|
| 725 |
+
detections = current_data['detections'][filename]
|
| 726 |
+
gt[filename] = [
|
| 727 |
+
{
|
| 728 |
+
'bbox': detections[i]['bbox'],
|
| 729 |
+
'folder': current_data['folder']
|
| 730 |
+
}
|
| 731 |
+
for i in selected_indices
|
| 732 |
+
]
|
| 733 |
+
save_ground_truth(gt)
|
| 734 |
+
print(f"๐พ ์ ์ฅ: {filename} - {len(selected_indices)}๊ฐ ๋ฐ์ค")
|
| 735 |
+
else:
|
| 736 |
+
print(f"โญ๏ธ ๊ฑด๋๋ฐ๊ธฐ: {filename} - ์ ํ ์์")
|
| 737 |
+
|
| 738 |
+
# ๋ค์ ์ด๋ฏธ์ง
|
| 739 |
+
current_data['current_idx'] += 1
|
| 740 |
+
|
| 741 |
+
# ๋ค์ ๋ฏธ๋ผ๋ฒจ๋ง ์ด๋ฏธ์ง ์ฐพ๊ธฐ
|
| 742 |
+
while current_data['current_idx'] < len(current_data['images']):
|
| 743 |
+
next_filename = os.path.basename(current_data['images'][current_data['current_idx']])
|
| 744 |
+
if next_filename not in current_data['selections']:
|
| 745 |
+
break
|
| 746 |
+
current_data['current_idx'] += 1
|
| 747 |
+
|
| 748 |
+
if current_data['current_idx'] >= len(current_data['images']):
|
| 749 |
+
return None, "โ
๋ชจ๋ ์ด๋ฏธ์ง ๋ผ๋ฒจ๋ง ์๋ฃ!", ""
|
| 750 |
+
|
| 751 |
+
return show_current_image()
|
| 752 |
+
|
| 753 |
+
|
| 754 |
+
def skip_image():
|
| 755 |
+
"""๊ฑด๋๋ฐ๊ธฐ"""
|
| 756 |
+
current_data['current_idx'] += 1
|
| 757 |
+
|
| 758 |
+
if current_data['current_idx'] >= len(current_data['images']):
|
| 759 |
+
return None, "โ
์๋ฃ!", ""
|
| 760 |
+
|
| 761 |
+
return show_current_image()
|
| 762 |
+
|
| 763 |
+
|
| 764 |
+
# ============================================================
|
| 765 |
+
# ํญ 3: ๊ฐ๋จ ๋ฐ๋ชจ (App Demo)
|
| 766 |
+
# ============================================================
|
| 767 |
+
|
| 768 |
+
def demo_detect(image, confidence_threshold, filter_threshold, model_type, use_filter):
|
| 769 |
+
"""๊ฐ๋จํ ๋ฐ๋ชจ ๊ฒ์ถ"""
|
| 770 |
+
if image is None:
|
| 771 |
+
return None, "์ด๋ฏธ์ง๋ฅผ ์
๋ก๋ํ์ธ์."
|
| 772 |
+
|
| 773 |
+
if isinstance(image, np.ndarray):
|
| 774 |
+
image = Image.fromarray(image)
|
| 775 |
+
|
| 776 |
+
# ์ ํ๋ ๋ชจ๋ธ๋ก ๊ฒ์ถ
|
| 777 |
+
all_detections = detect_with_selected_model(image, confidence_threshold, model_type)
|
| 778 |
+
|
| 779 |
+
# ํํฐ ์ ์ฉ ์ฌ๋ถ
|
| 780 |
+
if not use_filter:
|
| 781 |
+
# ํํฐ ๋ฏธ์ฌ์ฉ
|
| 782 |
+
filtered_detections = all_detections
|
| 783 |
+
for det in filtered_detections:
|
| 784 |
+
det['filter_score'] = det['confidence'] * 100
|
| 785 |
+
else:
|
| 786 |
+
# ํํฐ ์ฌ์ฉ
|
| 787 |
+
if model_type in ["Roboflow", "YOLOv8"]:
|
| 788 |
+
# Roboflow & YOLOv8: ์ ๋ขฐ๋ ๊ธฐ๋ฐ ํํฐ
|
| 789 |
+
for det in all_detections:
|
| 790 |
+
det['filter_score'] = det['confidence'] * 100
|
| 791 |
+
filtered_detections = [det for det in all_detections if det['filter_score'] >= filter_threshold]
|
| 792 |
+
else:
|
| 793 |
+
# RT-DETR: Universal Filter
|
| 794 |
+
from test_visual_validation import apply_universal_filter
|
| 795 |
+
filtered_detections = apply_universal_filter(all_detections, image, filter_threshold)
|
| 796 |
+
|
| 797 |
+
# ์๊ฐํ
|
| 798 |
+
result_image = image.copy()
|
| 799 |
+
draw = ImageDraw.Draw(result_image)
|
| 800 |
+
|
| 801 |
+
try:
|
| 802 |
+
font = ImageFont.truetype("arial.ttf", 20)
|
| 803 |
+
font_small = ImageFont.truetype("arial.ttf", 14)
|
| 804 |
+
except:
|
| 805 |
+
font = ImageFont.load_default()
|
| 806 |
+
font_small = ImageFont.load_default()
|
| 807 |
+
|
| 808 |
+
# ๋ฐ์ค ๊ทธ๋ฆฌ๊ธฐ
|
| 809 |
+
for i, det in enumerate(filtered_detections, 1):
|
| 810 |
+
x1, y1, x2, y2 = det['bbox']
|
| 811 |
+
draw.rectangle([x1, y1, x2, y2], outline="lime", width=8)
|
| 812 |
+
|
| 813 |
+
score = det['filter_score']
|
| 814 |
+
conf = det['confidence']
|
| 815 |
+
label = f"#{i} | Score:{score:.0f} | Conf:{conf:.2f}"
|
| 816 |
+
|
| 817 |
+
bbox = draw.textbbox((x1, y1-25), label, font=font_small)
|
| 818 |
+
draw.rectangle(bbox, fill="lime")
|
| 819 |
+
draw.text((x1, y1-25), label, fill="black", font=font_small)
|
| 820 |
+
|
| 821 |
+
# ๊ฒฐ๊ณผ ํ
์คํธ
|
| 822 |
+
info = f"""
|
| 823 |
+
๐ **๊ฒ์ถ ๊ฒฐ๊ณผ (๋ชจ๋ธ: {model_type}):**
|
| 824 |
+
โข ์ ์ฒด ๊ฒ์ถ: {len(all_detections)}๊ฐ
|
| 825 |
+
โข ํํฐ ํต๊ณผ: {len(filtered_detections)}๊ฐ
|
| 826 |
+
โข ์ ๊ฑฐ๋จ: {len(all_detections) - len(filtered_detections)}๊ฐ
|
| 827 |
+
|
| 828 |
+
โ๏ธ **์ค์ :**
|
| 829 |
+
โข {model_type} Confidence: {confidence_threshold}
|
| 830 |
+
โข Filter Threshold: {filter_threshold}
|
| 831 |
+
|
| 832 |
+
๐ฏ **์ฑ๋ฅ (50๊ฐ GT ๊ธฐ์ค, RT-DETR):**
|
| 833 |
+
โข Precision: 44.2%
|
| 834 |
+
โข Recall: 94.0%
|
| 835 |
+
โข F1 Score: 56.1%
|
| 836 |
+
"""
|
| 837 |
+
|
| 838 |
+
if len(filtered_detections) > 0:
|
| 839 |
+
info += f"\nโ
{len(filtered_detections)}๊ฐ์ ์์ฐ๋ฅผ ๊ฒ์ถํ์ต๋๋ค!"
|
| 840 |
+
else:
|
| 841 |
+
info += "\nโ ๏ธ ์์ฐ๊ฐ ๊ฒ์ถ๋์ง ์์์ต๋๋ค. Threshold๋ฅผ ๋ฎ์ถฐ๋ณด์ธ์."
|
| 842 |
+
|
| 843 |
+
return result_image, info
|
| 844 |
+
|
| 845 |
+
|
| 846 |
+
# ============================================================
|
| 847 |
+
# Gradio ์ธํฐํ์ด์ค - 3๊ฐ ํญ์ผ๋ก ํตํฉ
|
| 848 |
+
# ============================================================
|
| 849 |
+
|
| 850 |
+
with gr.Blocks(title="๐ฆ ์์ฐ ๊ฒ์ถ ํตํฉ ์์คํ
", theme=gr.themes.Soft()) as demo:
|
| 851 |
+
|
| 852 |
+
gr.Markdown("""
|
| 853 |
+
# ๐ฆ ์์ฐ ๊ฒ์ถ ํตํฉ ์์คํ
|
| 854 |
+
|
| 855 |
+
**3๊ฐ์ง ๋ชจ๋ธ๋ก ์์ฐ๋ฅผ ์ ํํ๊ฒ ๊ฒ์ถํ์ธ์**
|
| 856 |
+
|
| 857 |
+
---
|
| 858 |
+
""")
|
| 859 |
+
|
| 860 |
+
# ==================== ์ต์๋จ: ๋ชจ๋ธ ์ ํ ====================
|
| 861 |
+
with gr.Row():
|
| 862 |
+
with gr.Column(scale=3):
|
| 863 |
+
model_selector = gr.Radio(
|
| 864 |
+
choices=["RT-DETR", "VIDraft/Shrimp", "YOLOv8"],
|
| 865 |
+
value="YOLOv8",
|
| 866 |
+
label="๐ค ๊ฒ์ถ ๋ชจ๋ธ ์ ํ",
|
| 867 |
+
info="๋ชจ๋ ํญ์ ์ ์ฉ๋ฉ๋๋ค"
|
| 868 |
+
)
|
| 869 |
+
with gr.Column(scale=1):
|
| 870 |
+
load_rtdetr_btn = gr.Button("๐ RT-DETR ๋ก๋", size="sm", variant="secondary")
|
| 871 |
+
rtdetr_status = gr.Textbox(label="๋ชจ๋ธ ์ํ", value="โธ๏ธ RT-DETR ๋ฏธ๋ก๋ (VIDraft/Shrimp ํด๋ผ์ฐ๋ ๋ชจ๋ธ ์ฌ์ฉ ๊ฐ๋ฅ)", interactive=False, lines=1)
|
| 872 |
+
|
| 873 |
+
# RT-DETR ๋ก๋ฉ ๋ฒํผ ์ด๋ฒคํธ
|
| 874 |
+
load_rtdetr_btn.click(
|
| 875 |
+
load_rtdetr_on_demand,
|
| 876 |
+
inputs=[],
|
| 877 |
+
outputs=[rtdetr_status]
|
| 878 |
+
)
|
| 879 |
+
|
| 880 |
+
gr.Markdown("---")
|
| 881 |
+
|
| 882 |
+
with gr.Tabs():
|
| 883 |
+
# ==================== ํญ 1: ์๋ ๊ฒ์ถ ====================
|
| 884 |
+
with gr.TabItem("๐ค ์๋ ๊ฒ์ถ & ๊ฒ์ฆ"):
|
| 885 |
+
gr.Markdown("""
|
| 886 |
+
### ์ค์๊ฐ์ผ๋ก ํ๋ผ๋ฏธํฐ๋ฅผ ์กฐ์ ํ๋ฉฐ ๊ฒ์ถ ๊ฒฐ๊ณผ๋ฅผ ํ์ธ
|
| 887 |
+
์ต์ ํ๋ ํ๋ผ๋ฏธํฐ๋ก ์์ฐ ๊ฒ์ถ์ ํ
์คํธํ์ธ์.
|
| 888 |
+
""")
|
| 889 |
+
|
| 890 |
+
with gr.Row():
|
| 891 |
+
with gr.Column():
|
| 892 |
+
input_image_detect = gr.Image(label="์
๋ ฅ ์ด๋ฏธ์ง", type="pil")
|
| 893 |
+
|
| 894 |
+
confidence_slider_detect = gr.Slider(
|
| 895 |
+
0.01, 1.0, 0.1,
|
| 896 |
+
step=0.01,
|
| 897 |
+
label="์ ๋ขฐ๋ ์๊ณ๊ฐ",
|
| 898 |
+
info="RT-DETR: 0.065 | VIDraft/Shrimp: 0.3~0.5 | YOLOv8: 0.1~0.3 ๊ถ์ฅ"
|
| 899 |
+
)
|
| 900 |
+
|
| 901 |
+
use_filter_check = gr.Checkbox(
|
| 902 |
+
label="๐ ํํฐ ์ ์ ์๊ณ๊ฐ ์ฌ์ฉ",
|
| 903 |
+
value=False,
|
| 904 |
+
info="์ฒดํฌํ๋ฉด ํํฐ ์ ์ ๊ธฐ์ค์ผ๋ก ์ถ๊ฐ ํํฐ๋ง"
|
| 905 |
+
)
|
| 906 |
+
|
| 907 |
+
filter_slider_detect = gr.Slider(
|
| 908 |
+
0, 100, 90,
|
| 909 |
+
step=5,
|
| 910 |
+
label="ํํฐ ์ ์ ์๊ณ๊ฐ",
|
| 911 |
+
info="RT-DETR: Universal Filter | VIDraft/Shrimp: ์ ๋ขฐ๋ ๊ธฐ๋ฐ",
|
| 912 |
+
visible=True
|
| 913 |
+
)
|
| 914 |
+
|
| 915 |
+
show_all_check = gr.Checkbox(
|
| 916 |
+
label="์ ์ฒด ๊ฒ์ถ ๊ฒฐ๊ณผ ํ์ (ํ์)",
|
| 917 |
+
value=False
|
| 918 |
+
)
|
| 919 |
+
|
| 920 |
+
detect_btn = gr.Button("๐ ๊ฒ์ถ ์คํ", variant="primary", size="lg")
|
| 921 |
+
|
| 922 |
+
# ์์ ์ด๋ฏธ์ง (๊ฒฐ๊ณผ ํ์ผ ์ ์ธ)
|
| 923 |
+
example_images = [
|
| 924 |
+
"data/yolo_dataset/images/train/250818_01.jpg",
|
| 925 |
+
"data/yolo_dataset/images/train/250818_03.jpg",
|
| 926 |
+
"data/yolo_dataset/images/train/250818_04.jpg",
|
| 927 |
+
"data/yolo_dataset/images/train/250818_05.jpg",
|
| 928 |
+
"data/yolo_dataset/images/train/250818_10.jpg",
|
| 929 |
+
]
|
| 930 |
+
|
| 931 |
+
# ํ์ผ์ด ์กด์ฌํ๋ ๊ฒ๋ง ํํฐ๋ง
|
| 932 |
+
example_images = [img for img in example_images if os.path.exists(img)]
|
| 933 |
+
|
| 934 |
+
if example_images:
|
| 935 |
+
gr.Examples(
|
| 936 |
+
examples=[[img] for img in example_images],
|
| 937 |
+
inputs=[input_image_detect],
|
| 938 |
+
label="๐ท ์์ ์ด๋ฏธ์ง"
|
| 939 |
+
)
|
| 940 |
+
|
| 941 |
+
with gr.Column():
|
| 942 |
+
output_image_detect = gr.Image(label="๊ฒ์ถ ๊ฒฐ๊ณผ")
|
| 943 |
+
output_info_detect = gr.Markdown()
|
| 944 |
+
|
| 945 |
+
detect_btn.click(
|
| 946 |
+
interactive_detect,
|
| 947 |
+
[input_image_detect, confidence_slider_detect, filter_slider_detect, show_all_check, model_selector, use_filter_check],
|
| 948 |
+
[output_image_detect, output_info_detect]
|
| 949 |
+
)
|
| 950 |
+
|
| 951 |
+
# ํํฐ ์ฌ์ฉ ์ฒดํฌ๋ฐ์ค์ ๋ฐ๋ผ ํํฐ ์ฌ๋ผ์ด๋ ํ์ฑํ/๋นํ์ฑํ
|
| 952 |
+
def update_filter_interactivity(use_filter):
|
| 953 |
+
return gr.update(interactive=use_filter)
|
| 954 |
+
|
| 955 |
+
use_filter_check.change(
|
| 956 |
+
update_filter_interactivity,
|
| 957 |
+
inputs=[use_filter_check],
|
| 958 |
+
outputs=[filter_slider_detect]
|
| 959 |
+
)
|
| 960 |
+
|
| 961 |
+
gr.Markdown("""
|
| 962 |
+
### ๐ก ์ฌ์ฉ ํ
|
| 963 |
+
- ๋ชจ๋ธ์ ์ ํํ๊ณ ์ ๋ขฐ๋๋ฅผ ์กฐ์ ํ์ฌ ๊ฒ์ถ ๊ฒฐ๊ณผ๋ฅผ ํ์ธํ์ธ์
|
| 964 |
+
- ๊ฒ์ถ์ด ์ ์ ๋๋ ์ ๋ขฐ๋๋ฅผ ๋ฎ์ถ๊ณ , ์ค๊ฒ์ถ์ด ๋ง์ ๋๋ ๋์ด์ธ์
|
| 965 |
+
- ํํฐ ๊ธฐ๋ฅ์ ์ฌ์ฉํ์ฌ ๋ ์ ํํ ๊ฒฐ๊ณผ๋ฅผ ์ป์ ์ ์์ต๏ฟฝ๏ฟฝ๋ค
|
| 966 |
+
|
| 967 |
+
**๋ฐ์ค ์์:** ๐ข ๋
น์(๋์ ํ๋ฅ ) | ๐ก ๋
ธ๋์(์ค๊ฐ ํ๋ฅ ) | ๐ ์ฃผํฉ์(๋ฎ์ ํ๋ฅ ) | ๐ด ๋นจ๊ฐ์(์ ๊ฑฐ๋จ)
|
| 968 |
+
""")
|
| 969 |
+
|
| 970 |
+
# ==================== ํญ 2: ๋ผ๋ฒจ๋ง ๋๊ตฌ ====================
|
| 971 |
+
with gr.TabItem("๐ Ground Truth ๋ผ๋ฒจ๋ง"):
|
| 972 |
+
gr.Markdown("""
|
| 973 |
+
### ์ ํ๋ ๋ชจ๋ธ์ ๊ฒ์ถ ๊ฒฐ๊ณผ์์ ์ฌ๋ฐ๋ฅธ ๋ฐ์ค๋ง ์ ํํ์ฌ ๋ผ๋ฒจ๋ง
|
| 974 |
+
์ด๋ฏธ์ง๋ฅผ ํด๋ฆญํ์ฌ ์์ฐ ๋ฐ์ค๋ฅผ ์ ํ/ํด์ ํ์ธ์.
|
| 975 |
+
""")
|
| 976 |
+
|
| 977 |
+
with gr.Row():
|
| 978 |
+
with gr.Column(scale=1):
|
| 979 |
+
folder_dropdown = gr.Dropdown(
|
| 980 |
+
choices=get_folders(),
|
| 981 |
+
label="๐ ํด๋ ์ ํ",
|
| 982 |
+
info="๋ผ๋ฒจ๋งํ ํด๋๋ฅผ ์ ํํ์ธ์"
|
| 983 |
+
)
|
| 984 |
+
|
| 985 |
+
conf_slider_label = gr.Slider(
|
| 986 |
+
0.01, 0.5, 0.2,
|
| 987 |
+
step=0.05,
|
| 988 |
+
label="์ ๋ขฐ๋",
|
| 989 |
+
info="๊ฒ์ถ ๋ฏผ๊ฐ๋ ์กฐ์ "
|
| 990 |
+
)
|
| 991 |
+
|
| 992 |
+
start_btn = gr.Button("โถ๏ธ ๋ผ๋ฒจ๋ง ์์", variant="primary", size="lg")
|
| 993 |
+
|
| 994 |
+
gr.Markdown("---")
|
| 995 |
+
|
| 996 |
+
next_btn = gr.Button("โญ๏ธ ์ ์ฅ & ๋ค์", variant="secondary", size="lg")
|
| 997 |
+
skip_btn = gr.Button("โฉ ๊ฑด๋๋ฐ๊ธฐ", size="lg")
|
| 998 |
+
|
| 999 |
+
labeling_info = gr.Markdown("ํด๋๋ฅผ ์ ํํ๊ณ '๋ผ๋ฒจ๋ง ์์'์ ํด๋ฆญํ์ธ์.")
|
| 1000 |
+
|
| 1001 |
+
with gr.Column(scale=2):
|
| 1002 |
+
labeling_image = gr.Image(
|
| 1003 |
+
label="๐ฑ๏ธ ํด๋ฆญํ์ฌ ๋ฐ์ค ์ ํ/ํด์ ",
|
| 1004 |
+
type="pil",
|
| 1005 |
+
interactive=True
|
| 1006 |
+
)
|
| 1007 |
+
|
| 1008 |
+
labeling_filename = gr.Textbox(visible=False)
|
| 1009 |
+
click_info = gr.Markdown()
|
| 1010 |
+
|
| 1011 |
+
# ์ด๋ฒคํธ ํธ๋ค๋ฌ
|
| 1012 |
+
start_btn.click(
|
| 1013 |
+
start_labeling,
|
| 1014 |
+
[folder_dropdown, conf_slider_label, model_selector],
|
| 1015 |
+
[labeling_image, labeling_info, labeling_filename]
|
| 1016 |
+
)
|
| 1017 |
+
|
| 1018 |
+
labeling_image.select(
|
| 1019 |
+
labeling_click,
|
| 1020 |
+
[labeling_image, labeling_filename],
|
| 1021 |
+
[labeling_image, click_info]
|
| 1022 |
+
)
|
| 1023 |
+
|
| 1024 |
+
next_btn.click(
|
| 1025 |
+
save_and_next,
|
| 1026 |
+
[],
|
| 1027 |
+
[labeling_image, labeling_info, labeling_filename]
|
| 1028 |
+
)
|
| 1029 |
+
|
| 1030 |
+
skip_btn.click(
|
| 1031 |
+
skip_image,
|
| 1032 |
+
[],
|
| 1033 |
+
[labeling_image, labeling_info, labeling_filename]
|
| 1034 |
+
)
|
| 1035 |
+
|
| 1036 |
+
gr.Markdown("""
|
| 1037 |
+
### ๐ฑ๏ธ ์ฌ์ฉ ๋ฐฉ๋ฒ
|
| 1038 |
+
1. **๋ชจ๋ธ ์ ํ** (์ต์๋จ์์ ์ ํ)
|
| 1039 |
+
2. ํด๋ ์ ํ ํ "๋ผ๋ฒจ๋ง ์์"
|
| 1040 |
+
3. ์ด๋ฏธ์ง์์ **์ํ ๋ฒํผ ํด๋ฆญ** ๋๋ **๋ฐ์ค ์์ญ ํด๋ฆญ**์ผ๋ก ์ ํ/ํด์
|
| 1041 |
+
4. "์ ์ฅ & ๋ค์"์ผ๋ก ๋ค์ ์ด๋ฏธ์ง๋ก ์ด๋ (์๋ ์ ์ฅ)
|
| 1042 |
+
5. "๊ฑด๋๋ฐ๊ธฐ"๋ก ์ ํ ์์ด ๋ค์ ์ด๋ฏธ์ง๋ก
|
| 1043 |
+
|
| 1044 |
+
**๐พ ์ ์ฅ ์์น:** `ground_truth.json` (์๋ ๋ฐฑ์
: `backups/`)
|
| 1045 |
+
""")
|
| 1046 |
+
|
| 1047 |
+
# ==================== ํญ 3: ๊ฐ๋จ ๋ฐ๋ชจ ====================
|
| 1048 |
+
with gr.TabItem("๐ฏ ๊ฐ๋จ ๋ฐ๋ชจ"):
|
| 1049 |
+
gr.Markdown("""
|
| 1050 |
+
### ๋น ๋ฅด๊ณ ๊ฐ๋จํ ์์ฐ ๊ฒ์ถ ๋ฐ๋ชจ
|
| 1051 |
+
์ด๋ฏธ์ง๋ฅผ ์
๋ก๋ํ๊ณ ๋ฐ๋ก ๊ฒฐ๊ณผ๋ฅผ ํ์ธํ์ธ์.
|
| 1052 |
+
""")
|
| 1053 |
+
|
| 1054 |
+
with gr.Row():
|
| 1055 |
+
with gr.Column():
|
| 1056 |
+
input_image_demo = gr.Image(label="์
๋ ฅ ์ด๋ฏธ์ง", type="pil")
|
| 1057 |
+
|
| 1058 |
+
confidence_slider_demo = gr.Slider(
|
| 1059 |
+
0.01, 1.0, 0.1,
|
| 1060 |
+
step=0.01,
|
| 1061 |
+
label="์ ๋ขฐ๋",
|
| 1062 |
+
info="RT-DETR: 0.065 | VIDraft/Shrimp: 0.3~0.5 | YOLOv8: 0.1~0.3 ๊ถ์ฅ"
|
| 1063 |
+
)
|
| 1064 |
+
|
| 1065 |
+
use_filter_demo = gr.Checkbox(
|
| 1066 |
+
label="๐ ํํฐ ์ ์ ์๊ณ๊ฐ ์ฌ์ฉ",
|
| 1067 |
+
value=False,
|
| 1068 |
+
info="์ฒดํฌํ๋ฉด ํํฐ ์ ์ ๊ธฐ์ค์ผ๋ก ์ถ๊ฐ ํํฐ๋ง"
|
| 1069 |
+
)
|
| 1070 |
+
|
| 1071 |
+
filter_slider_demo = gr.Slider(
|
| 1072 |
+
0, 100, 90,
|
| 1073 |
+
step=5,
|
| 1074 |
+
label="ํํฐ ์๊ณ๊ฐ",
|
| 1075 |
+
info="RT-DETR: Universal Filter | VIDraft/Shrimp: ์ ๋ขฐ๋ ๊ธฐ๋ฐ",
|
| 1076 |
+
visible=True
|
| 1077 |
+
)
|
| 1078 |
+
|
| 1079 |
+
demo_detect_btn = gr.Button("๐ ๊ฒ์ถ", variant="primary", size="lg")
|
| 1080 |
+
|
| 1081 |
+
# ์์ ์ด๋ฏธ์ง
|
| 1082 |
+
example_images_demo = [
|
| 1083 |
+
"data/yolo_dataset/images/train/250818_01.jpg",
|
| 1084 |
+
"data/yolo_dataset/images/train/250818_03.jpg",
|
| 1085 |
+
"data/yolo_dataset/images/train/250818_04.jpg",
|
| 1086 |
+
"data/yolo_dataset/images/train/250818_05.jpg",
|
| 1087 |
+
"data/yolo_dataset/images/train/250818_10.jpg",
|
| 1088 |
+
]
|
| 1089 |
+
|
| 1090 |
+
# ํ์ผ์ด ์กด์ฌํ๋ ๊ฒ๋ง ํํฐ๋ง
|
| 1091 |
+
example_images_demo = [img for img in example_images_demo if os.path.exists(img)]
|
| 1092 |
+
|
| 1093 |
+
if example_images_demo:
|
| 1094 |
+
gr.Examples(
|
| 1095 |
+
examples=[[img] for img in example_images_demo],
|
| 1096 |
+
inputs=[input_image_demo],
|
| 1097 |
+
label="๐ท ์์ ์ด๋ฏธ์ง"
|
| 1098 |
+
)
|
| 1099 |
+
|
| 1100 |
+
with gr.Column():
|
| 1101 |
+
output_image_demo = gr.Image(label="๊ฒ์ถ ๊ฒฐ๊ณผ")
|
| 1102 |
+
output_info_demo = gr.Markdown()
|
| 1103 |
+
|
| 1104 |
+
demo_detect_btn.click(
|
| 1105 |
+
demo_detect,
|
| 1106 |
+
[input_image_demo, confidence_slider_demo, filter_slider_demo, model_selector, use_filter_demo],
|
| 1107 |
+
[output_image_demo, output_info_demo]
|
| 1108 |
+
)
|
| 1109 |
+
|
| 1110 |
+
# ํํฐ ์ฌ์ฉ ์ฒดํฌ๋ฐ์ค์ ๋ฐ๋ผ ํํฐ ์ฌ๋ผ์ด๋ ํ์ฑํ/๋นํ์ฑํ
|
| 1111 |
+
use_filter_demo.change(
|
| 1112 |
+
lambda x: gr.update(interactive=x),
|
| 1113 |
+
inputs=[use_filter_demo],
|
| 1114 |
+
outputs=[filter_slider_demo]
|
| 1115 |
+
)
|
| 1116 |
+
|
| 1117 |
+
gr.Markdown("""
|
| 1118 |
+
### ๐ก ๋น ๋ฅด๊ณ ๊ฐ๋จํ ๊ฒ์ถ
|
| 1119 |
+
์ด๋ฏธ์ง๋ฅผ ์
๋ก๋ํ๊ฑฐ๋ ์์ ์ด๋ฏธ์ง๋ฅผ ์ ํํ์ฌ ๋ฐ๋ก ๊ฒ์ถ ๊ฒฐ๊ณผ๋ฅผ ํ์ธํ์ธ์.
|
| 1120 |
+
""")
|
| 1121 |
+
|
| 1122 |
+
gr.Markdown("""
|
| 1123 |
+
---
|
| 1124 |
+
|
| 1125 |
+
### ๐ค ๋ชจ๋ธ ์ค๋ช
|
| 1126 |
+
- **RT-DETR**: ๋ก์ปฌ ๋ชจ๋ธ, ๋น ๋ฅธ ์ถ๋ก ์๋, ์คํ๋ผ์ธ ์ฌ์ฉ ๊ฐ๋ฅ
|
| 1127 |
+
- **VIDraft/Shrimp**: ํด๋ผ์ฐ๋ ๋ชจ๋ธ, ์ธํฐ๋ท ์ฐ๊ฒฐ ํ์
|
| 1128 |
+
- **YOLOv8**: ๋ก์ปฌ ์ปค์คํ
ํ์ต ๋ชจ๋ธ, ๋น ๋ฅธ ์ถ๋ก ์๋
|
| 1129 |
+
|
| 1130 |
+
---
|
| 1131 |
+
|
| 1132 |
+
ยฉ 2025 VIDraft. All rights reserved.
|
| 1133 |
+
""")
|
| 1134 |
+
|
| 1135 |
+
if __name__ == "__main__":
|
| 1136 |
+
print("\n" + "="*60)
|
| 1137 |
+
print("๐ฆ ์์ฐ ๊ฒ์ถ ํตํฉ ์์คํ
v2.1 ์์")
|
| 1138 |
+
print("="*60)
|
| 1139 |
+
print("๐ค ์ฌ์ฉ ๊ฐ๋ฅํ ๋ชจ๋ธ:")
|
| 1140 |
+
print(" 1. RT-DETR (๋ก์ปฌ)")
|
| 1141 |
+
print(" 2. VIDraft/Shrimp (ํด๋ผ์ฐ๋)")
|
| 1142 |
+
print(" 3. YOLOv8 (๋ก์ปฌ ํ์ต) โญ ๊ธฐ๋ณธ๊ฐ")
|
| 1143 |
+
print(f"\n๐ฆ YOLOv8 ๋ชจ๋ธ: {YOLO_MODEL_PATH}")
|
| 1144 |
+
print("="*60)
|
| 1145 |
+
|
| 1146 |
+
demo.launch(
|
| 1147 |
+
server_name="0.0.0.0",
|
| 1148 |
+
server_port=None, # ์๋์ผ๋ก ๋น ํฌํธ ์ฐพ๊ธฐ
|
| 1149 |
+
share=False
|
| 1150 |
+
)
|
test_quantitative_evaluation.py
CHANGED
|
@@ -222,7 +222,13 @@ def run_quantitative_test(test_image_dir, ground_truth_path, confidence=0.3, fil
|
|
| 222 |
results = []
|
| 223 |
|
| 224 |
for filename, gt_list in ground_truths.items():
|
| 225 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 226 |
if not os.path.exists(img_path):
|
| 227 |
print(f"โ ๏ธ ์ด๋ฏธ์ง๋ฅผ ์ฐพ์ ์ ์์ต๋๋ค: {img_path}")
|
| 228 |
continue
|
|
@@ -297,7 +303,7 @@ def run_quantitative_test(test_image_dir, ground_truth_path, confidence=0.3, fil
|
|
| 297 |
|
| 298 |
if __name__ == "__main__":
|
| 299 |
# ํ
์คํธ ์คํ
|
| 300 |
-
TEST_DIR = "
|
| 301 |
GT_PATH = "ground_truth.json"
|
| 302 |
|
| 303 |
if not os.path.exists(GT_PATH):
|
|
@@ -318,7 +324,7 @@ if __name__ == "__main__":
|
|
| 318 |
run_quantitative_test(
|
| 319 |
test_image_dir=TEST_DIR,
|
| 320 |
ground_truth_path=GT_PATH,
|
| 321 |
-
confidence=0.
|
| 322 |
-
filter_threshold=
|
| 323 |
iou_threshold=0.5
|
| 324 |
)
|
|
|
|
| 222 |
results = []
|
| 223 |
|
| 224 |
for filename, gt_list in ground_truths.items():
|
| 225 |
+
# ground_truth.json์ folder ์ ๋ณด ํ์ฉ
|
| 226 |
+
if gt_list and 'folder' in gt_list[0]:
|
| 227 |
+
folder = gt_list[0]['folder']
|
| 228 |
+
img_path = os.path.join(test_image_dir, folder, filename)
|
| 229 |
+
else:
|
| 230 |
+
img_path = os.path.join(test_image_dir, filename)
|
| 231 |
+
|
| 232 |
if not os.path.exists(img_path):
|
| 233 |
print(f"โ ๏ธ ์ด๋ฏธ์ง๋ฅผ ์ฐพ์ ์ ์์ต๋๋ค: {img_path}")
|
| 234 |
continue
|
|
|
|
| 303 |
|
| 304 |
if __name__ == "__main__":
|
| 305 |
# ํ
์คํธ ์คํ
|
| 306 |
+
TEST_DIR = r"data\ํฐ๋ค๋ฆฌ์์ฐ ์ค์ธก ๋ฐ์ดํฐ_์ตํฌ์ค์์ด์์ด(์ฃผ)"
|
| 307 |
GT_PATH = "ground_truth.json"
|
| 308 |
|
| 309 |
if not os.path.exists(GT_PATH):
|
|
|
|
| 324 |
run_quantitative_test(
|
| 325 |
test_image_dir=TEST_DIR,
|
| 326 |
ground_truth_path=GT_PATH,
|
| 327 |
+
confidence=0.065, # GT ์ต์๊ฐ์ผ๋ก ์ค์ (๋ชจ๋ GT ๋ฐ์ค ๊ฒ์ถ ๊ฐ๋ฅ)
|
| 328 |
+
filter_threshold=90, # Precision ์ต๋ํ ํ
์คํธ
|
| 329 |
iou_threshold=0.5
|
| 330 |
)
|
test_visual_validation.py
CHANGED
|
@@ -86,11 +86,14 @@ def calculate_visual_features(image_pil, bbox):
|
|
| 86 |
# ๋ฐ์ด๋ฉ ๋ฐ์ค ์์ญ ์ถ์ถ
|
| 87 |
roi = image_cv[y1:y2, x1:x2]
|
| 88 |
if roi.size == 0:
|
| 89 |
-
return {'saturation': 255, 'color_std': 255}
|
| 90 |
|
| 91 |
# HSV ๋ณํ
|
| 92 |
hsv = cv2.cvtColor(roi, cv2.COLOR_BGR2HSV)
|
| 93 |
|
|
|
|
|
|
|
|
|
|
| 94 |
# ์ฑ๋ (Saturation)
|
| 95 |
saturation = np.mean(hsv[:, :, 1])
|
| 96 |
|
|
@@ -98,12 +101,13 @@ def calculate_visual_features(image_pil, bbox):
|
|
| 98 |
color_std = np.std(hsv[:, :, 0])
|
| 99 |
|
| 100 |
return {
|
|
|
|
| 101 |
'saturation': saturation,
|
| 102 |
'color_std': color_std
|
| 103 |
}
|
| 104 |
|
| 105 |
-
def apply_universal_filter(detections, image, threshold=
|
| 106 |
-
"""๋ฒ์ฉ ์์ฐ ํํฐ ์ ์ฉ"""
|
| 107 |
img_size = image.size
|
| 108 |
filtered = []
|
| 109 |
|
|
@@ -120,48 +124,82 @@ def apply_universal_filter(detections, image, threshold=50):
|
|
| 120 |
score = 0
|
| 121 |
reasons = []
|
| 122 |
|
| 123 |
-
# Aspect ratio (
|
| 124 |
-
if
|
| 125 |
-
score += 15
|
| 126 |
reasons.append(f"โ ์ข
ํก๋น {morph['aspect_ratio']:.1f}")
|
| 127 |
-
elif
|
| 128 |
-
#
|
| 129 |
-
score +=
|
| 130 |
reasons.append(f"โณ ์ข
ํก๋น {morph['aspect_ratio']:.1f}")
|
| 131 |
else:
|
|
|
|
| 132 |
reasons.append(f"โ ์ข
ํก๋น {morph['aspect_ratio']:.1f}")
|
| 133 |
|
| 134 |
-
# Compactness (< 0.50, ๊ธด ํํ) -
|
| 135 |
-
if morph['compactness'] < 0.
|
| 136 |
-
score +=
|
| 137 |
reasons.append(f"โ ์ธ์ฅ๋ {morph['compactness']:.2f}")
|
|
|
|
|
|
|
|
|
|
| 138 |
else:
|
| 139 |
reasons.append(f"โ ์ธ์ฅ๋ {morph['compactness']:.2f}")
|
| 140 |
-
score -=
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 141 |
|
| 142 |
-
#
|
| 143 |
-
|
|
|
|
|
|
|
| 144 |
score += 10
|
| 145 |
-
reasons.append(f"โ
|
|
|
|
|
|
|
|
|
|
|
|
|
| 146 |
else:
|
| 147 |
-
reasons.append(f"
|
| 148 |
|
| 149 |
-
# Saturation
|
| 150 |
-
if visual['saturation'] <
|
| 151 |
-
score += 20
|
| 152 |
reasons.append(f"โ ์ฑ๋ {visual['saturation']:.0f}")
|
|
|
|
|
|
|
|
|
|
| 153 |
else:
|
| 154 |
-
|
|
|
|
| 155 |
|
| 156 |
-
# Color consistency
|
| 157 |
-
if visual['color_std'] <
|
| 158 |
-
score += 15
|
| 159 |
reasons.append(f"โ ์์์ผ๊ด์ฑ {visual['color_std']:.1f}")
|
|
|
|
|
|
|
|
|
|
| 160 |
else:
|
| 161 |
-
|
|
|
|
| 162 |
|
| 163 |
-
# RT-DETR confidence
|
| 164 |
-
|
|
|
|
| 165 |
|
| 166 |
det['filter_score'] = score
|
| 167 |
det['filter_reasons'] = reasons
|
|
@@ -174,7 +212,44 @@ def apply_universal_filter(detections, image, threshold=50):
|
|
| 174 |
# ์ ์ ์์ผ๋ก ์ ๋ ฌ
|
| 175 |
filtered.sort(key=lambda x: x['filter_score'], reverse=True)
|
| 176 |
|
| 177 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 178 |
|
| 179 |
def visualize_results(image_path, all_detections, filtered_detections, output_path):
|
| 180 |
"""๊ฒ์ถ ๊ฒฐ๊ณผ ์๊ฐํ"""
|
|
|
|
| 86 |
# ๋ฐ์ด๋ฉ ๋ฐ์ค ์์ญ ์ถ์ถ
|
| 87 |
roi = image_cv[y1:y2, x1:x2]
|
| 88 |
if roi.size == 0:
|
| 89 |
+
return {'hue': 100, 'saturation': 255, 'color_std': 255}
|
| 90 |
|
| 91 |
# HSV ๋ณํ
|
| 92 |
hsv = cv2.cvtColor(roi, cv2.COLOR_BGR2HSV)
|
| 93 |
|
| 94 |
+
# ์์ (Hue) - ์์ฐ๋ ํฌ๋ช
/ํ๋ฐฑ์ (0-30) ๋๋ ์ฃผํฉ์ (10-25)
|
| 95 |
+
hue_mean = np.mean(hsv[:, :, 0])
|
| 96 |
+
|
| 97 |
# ์ฑ๋ (Saturation)
|
| 98 |
saturation = np.mean(hsv[:, :, 1])
|
| 99 |
|
|
|
|
| 101 |
color_std = np.std(hsv[:, :, 0])
|
| 102 |
|
| 103 |
return {
|
| 104 |
+
'hue': hue_mean,
|
| 105 |
'saturation': saturation,
|
| 106 |
'color_std': color_std
|
| 107 |
}
|
| 108 |
|
| 109 |
+
def apply_universal_filter(detections, image, threshold=90):
|
| 110 |
+
"""๋ฒ์ฉ ์์ฐ ํํฐ ์ ์ฉ - ์ต์ ํ ์๋ฃ (F1=56.1%)"""
|
| 111 |
img_size = image.size
|
| 112 |
filtered = []
|
| 113 |
|
|
|
|
| 124 |
score = 0
|
| 125 |
reasons = []
|
| 126 |
|
| 127 |
+
# Aspect ratio (4:1 ~ 9:1) - GT ๊ธฐ๋ฐ ์ต์ ํ (ํ๊ท 6.49, ๋ฒ์ 4.02~8.46)
|
| 128 |
+
if 4.0 <= morph['aspect_ratio'] <= 9.0:
|
| 129 |
+
score += 25 # ๊ฐ์ค์น ์ฆ๊ฐ: 15 โ 25 (๊ฐ์ฅ ์ค์ํ ํน์ง)
|
| 130 |
reasons.append(f"โ ์ข
ํก๋น {morph['aspect_ratio']:.1f}")
|
| 131 |
+
elif 3.0 <= morph['aspect_ratio'] < 4.0 or 9.0 < morph['aspect_ratio'] <= 10.0:
|
| 132 |
+
# ๊ฒฝ๊ณ ์์ญ
|
| 133 |
+
score += 12
|
| 134 |
reasons.append(f"โณ ์ข
ํก๋น {morph['aspect_ratio']:.1f}")
|
| 135 |
else:
|
| 136 |
+
score -= 5 # ํจ๋ํฐ ์ถ๊ฐ
|
| 137 |
reasons.append(f"โ ์ข
ํก๋น {morph['aspect_ratio']:.1f}")
|
| 138 |
|
| 139 |
+
# Compactness (< 0.50, ๊ธด ํํ) - FP ๋ถ์: GT=0.369, FP=0.597 (62% ์ฐจ์ด)
|
| 140 |
+
if morph['compactness'] < 0.40:
|
| 141 |
+
score += 30 # ๊ฐ์ค์น ๋ํญ ์ฆ๊ฐ: 20 โ 30
|
| 142 |
reasons.append(f"โ ์ธ์ฅ๋ {morph['compactness']:.2f}")
|
| 143 |
+
elif 0.40 <= morph['compactness'] < 0.50:
|
| 144 |
+
score += 15
|
| 145 |
+
reasons.append(f"โณ ์ธ์ฅ๋ {morph['compactness']:.2f}")
|
| 146 |
else:
|
| 147 |
reasons.append(f"โ ์ธ์ฅ๋ {morph['compactness']:.2f}")
|
| 148 |
+
score -= 20 # ํจ๋ํฐ ๊ฐํ: 10 โ 20
|
| 149 |
+
|
| 150 |
+
# Area - FP ๋ถ์: GT=217K, FP=3873K (1682% ์ฐจ์ด! ๊ฐ์ฅ ์ค์)
|
| 151 |
+
abs_area = morph['width'] * morph['height']
|
| 152 |
+
if 50000 <= abs_area <= 500000:
|
| 153 |
+
score += 35 # ๊ฐ์ค์น ๋ํญ ์ฆ๊ฐ: 15 โ 35 (ํ๋ณ๋ ฅ 1์)
|
| 154 |
+
reasons.append(f"โ ๋ฉด์ {abs_area/1000:.0f}K")
|
| 155 |
+
elif 500000 < abs_area <= 800000:
|
| 156 |
+
score -= 10 # ๊ฒฝ๊ณ ์์ญ ํจ๋ํฐ
|
| 157 |
+
reasons.append(f"โณ ๋ฉด์ {abs_area/1000:.0f}K")
|
| 158 |
+
elif abs_area > 800000:
|
| 159 |
+
score -= 30 # ํฐ ๋ฐ์ค ๊ฐํ ํจ๋ํฐ (FP ๋๋ถ๋ถ์ด ํผ)
|
| 160 |
+
reasons.append(f"โ ๋ฉด์ {abs_area/1000:.0f}K (๋๋ฌดํผ)")
|
| 161 |
+
else:
|
| 162 |
+
score -= 10 # ๋๋ฌด ์์
|
| 163 |
+
reasons.append(f"โ ๋ฉด์ {abs_area/1000:.0f}K (๋๋ฌด์์)")
|
| 164 |
|
| 165 |
+
# Hue (์์) - ์์ฐ๋ ํฌ๋ช
/ํ๋ฐฑ์(0-40) ๋๋ ํ๋๋ฐฐ๊ฒฝ ์ ์ธ(90-130)
|
| 166 |
+
hue = visual['hue']
|
| 167 |
+
if hue < 40 or hue > 130:
|
| 168 |
+
# ํฌ๋ช
/ํ๋ฐฑ์ ๋๋ ๋ฐฐ๊ฒฝ์ด ์๋ ์์
|
| 169 |
score += 10
|
| 170 |
+
reasons.append(f"โ ์์ {hue:.0f}")
|
| 171 |
+
elif 90 <= hue <= 130:
|
| 172 |
+
# ํ๋ ๋ฐฐ๊ฒฝ์ - ๊ฐ์
|
| 173 |
+
score -= 5
|
| 174 |
+
reasons.append(f"โ ์์ {hue:.0f} (๋ฐฐ๊ฒฝ)")
|
| 175 |
else:
|
| 176 |
+
reasons.append(f"โณ ์์ {hue:.0f}")
|
| 177 |
|
| 178 |
+
# Saturation - FP ๋ถ์: GT=65.2, FP=103.9 (59% ์ฐจ์ด)
|
| 179 |
+
if visual['saturation'] < 85: # GT ๋ฒ์ ๋ด (49.8~82.2)
|
| 180 |
+
score += 20 # ๊ฐ์ค์น ์ฆ๊ฐ: 12 โ 20
|
| 181 |
reasons.append(f"โ ์ฑ๋ {visual['saturation']:.0f}")
|
| 182 |
+
elif 85 <= visual['saturation'] < 120:
|
| 183 |
+
score += 5 # ๊ฒฝ๊ณ ์์ญ
|
| 184 |
+
reasons.append(f"โณ ์ฑ๋ {visual['saturation']:.0f}")
|
| 185 |
else:
|
| 186 |
+
score -= 15 # ๋์ ์ฑ๋ ํจ๋ํฐ (FP ํน์ฑ)
|
| 187 |
+
reasons.append(f"โ ์ฑ๋ {visual['saturation']:.0f} (๋์)")
|
| 188 |
|
| 189 |
+
# Color consistency - FP ๋ถ์: GT=42.5, FP=76.2 (79% ์ฐจ์ด)
|
| 190 |
+
if visual['color_std'] < 50: # GT ๋ฒ์ ๋ด (33.4~46.8)
|
| 191 |
+
score += 15 # ๊ฐ์ค์น ์ฆ๊ฐ: 8 โ 15
|
| 192 |
reasons.append(f"โ ์์์ผ๊ด์ฑ {visual['color_std']:.1f}")
|
| 193 |
+
elif 50 <= visual['color_std'] < 80:
|
| 194 |
+
score += 5 # ๊ฒฝ๊ณ ์์ญ
|
| 195 |
+
reasons.append(f"โณ ์์์ผ๊ด์ฑ {visual['color_std']:.1f}")
|
| 196 |
else:
|
| 197 |
+
score -= 10 # ๋ถ์ผ์น ํจ๋ํฐ
|
| 198 |
+
reasons.append(f"โ ์์์ผ๊ด์ฑ {visual['color_std']:.1f} (๋ถ์ผ์น)")
|
| 199 |
|
| 200 |
+
# RT-DETR confidence - GT ๊ธฐ๋ฐ ์ํ (GT์์ 0.065๋ ์ ํจ)
|
| 201 |
+
# 0.065~0.658 ๋ฒ์, ํ๊ท 0.293
|
| 202 |
+
score += det['confidence'] * 15 # ๊ฐ์ค์น ๊ฐ์: 25 โ 15
|
| 203 |
|
| 204 |
det['filter_score'] = score
|
| 205 |
det['filter_reasons'] = reasons
|
|
|
|
| 212 |
# ์ ์ ์์ผ๋ก ์ ๋ ฌ
|
| 213 |
filtered.sort(key=lambda x: x['filter_score'], reverse=True)
|
| 214 |
|
| 215 |
+
# NMS (Non-Maximum Suppression) - ์ค๋ณต ์ ๊ฑฐ
|
| 216 |
+
filtered_nms = []
|
| 217 |
+
for det in filtered:
|
| 218 |
+
is_duplicate = False
|
| 219 |
+
for kept_det in filtered_nms:
|
| 220 |
+
# IoU ๊ณ์ฐ
|
| 221 |
+
iou = calculate_iou_simple(det['bbox'], kept_det['bbox'])
|
| 222 |
+
if iou > 0.5: # 50% ์ด์ ๊ฒน์น๋ฉด ์ค๋ณต์ผ๋ก ๊ฐ์ฃผ
|
| 223 |
+
is_duplicate = True
|
| 224 |
+
break
|
| 225 |
+
|
| 226 |
+
if not is_duplicate:
|
| 227 |
+
filtered_nms.append(det)
|
| 228 |
+
|
| 229 |
+
return filtered_nms
|
| 230 |
+
|
| 231 |
+
def calculate_iou_simple(bbox1, bbox2):
|
| 232 |
+
"""๊ฐ๋จํ IoU ๊ณ์ฐ"""
|
| 233 |
+
x1_min, y1_min, x1_max, y1_max = bbox1
|
| 234 |
+
x2_min, y2_min, x2_max, y2_max = bbox2
|
| 235 |
+
|
| 236 |
+
# ๊ต์งํฉ
|
| 237 |
+
inter_x_min = max(x1_min, x2_min)
|
| 238 |
+
inter_y_min = max(y1_min, y2_min)
|
| 239 |
+
inter_x_max = min(x1_max, x2_max)
|
| 240 |
+
inter_y_max = min(y1_max, y2_max)
|
| 241 |
+
|
| 242 |
+
if inter_x_max < inter_x_min or inter_y_max < inter_y_min:
|
| 243 |
+
return 0.0
|
| 244 |
+
|
| 245 |
+
inter_area = (inter_x_max - inter_x_min) * (inter_y_max - inter_y_min)
|
| 246 |
+
|
| 247 |
+
# ํฉ์งํฉ
|
| 248 |
+
bbox1_area = (x1_max - x1_min) * (y1_max - y1_min)
|
| 249 |
+
bbox2_area = (x2_max - x2_min) * (y2_max - y2_min)
|
| 250 |
+
union_area = bbox1_area + bbox2_area - inter_area
|
| 251 |
+
|
| 252 |
+
return inter_area / union_area if union_area > 0 else 0.0
|
| 253 |
|
| 254 |
def visualize_results(image_path, all_detections, filtered_detections, output_path):
|
| 255 |
"""๊ฒ์ถ ๊ฒฐ๊ณผ ์๊ฐํ"""
|
train_yolo.py
ADDED
|
@@ -0,0 +1,127 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# -*- coding: utf-8 -*-
|
| 2 |
+
"""
|
| 3 |
+
YOLOv8 Few-shot Training for Shrimp Detection
|
| 4 |
+
์ต์ ๋ฐ์ดํฐ(50๊ฐ)๋ก ๋น ๋ฅธ ํ์ต
|
| 5 |
+
"""
|
| 6 |
+
import sys
|
| 7 |
+
sys.stdout.reconfigure(encoding='utf-8')
|
| 8 |
+
|
| 9 |
+
from ultralytics import YOLO
|
| 10 |
+
import torch
|
| 11 |
+
from pathlib import Path
|
| 12 |
+
import yaml
|
| 13 |
+
|
| 14 |
+
def main():
|
| 15 |
+
print("=" * 60)
|
| 16 |
+
print("๐ฆ YOLOv8 Few-shot Training ์์")
|
| 17 |
+
print("=" * 60)
|
| 18 |
+
|
| 19 |
+
# GPU ํ์ธ
|
| 20 |
+
device = 'cuda' if torch.cuda.is_available() else 'cpu'
|
| 21 |
+
print(f"\n๐ฅ๏ธ Device: {device}")
|
| 22 |
+
if device == 'cuda':
|
| 23 |
+
print(f" GPU: {torch.cuda.get_device_name(0)}")
|
| 24 |
+
print(f" VRAM: {torch.cuda.get_device_properties(0).total_memory / 1024**3:.1f} GB")
|
| 25 |
+
else:
|
| 26 |
+
print(" โ ๏ธ GPU ์์ - CPU๋ก ํ์ต (๋๋ฆผ)")
|
| 27 |
+
|
| 28 |
+
# ๋ฐ์ดํฐ์
๊ฒฝ๋ก
|
| 29 |
+
data_yaml = "data/yolo_dataset/data.yaml"
|
| 30 |
+
|
| 31 |
+
# data.yaml ํ์ธ
|
| 32 |
+
print(f"\n๐ ๋ฐ์ดํฐ์
์ค์ ๋ก๋ฉ: {data_yaml}")
|
| 33 |
+
with open(data_yaml, 'r', encoding='utf-8') as f:
|
| 34 |
+
data_config = yaml.safe_load(f)
|
| 35 |
+
print(f" - Classes: {data_config['names']}")
|
| 36 |
+
print(f" - Train: {data_config['train']}")
|
| 37 |
+
print(f" - Val: {data_config['val']}")
|
| 38 |
+
|
| 39 |
+
# YOLOv8 ๋ชจ๋ธ ์ ํ
|
| 40 |
+
# yolov8n: nano (๊ฐ์ฅ ๋น ๋ฆ, ์์ ๋ฐ์ดํฐ์
์ ์ ํฉ)
|
| 41 |
+
# yolov8s: small
|
| 42 |
+
# yolov8m: medium
|
| 43 |
+
model_size = 'n' # nano - Few-shot์ ์ต์
|
| 44 |
+
print(f"\n๐ค ๋ชจ๋ธ: YOLOv8{model_size} (nano)")
|
| 45 |
+
print(" - ์ด์ : ์์ ๋ฐ์ดํฐ์
(50๊ฐ)์์ ๊ณผ์ ํฉ ๋ฐฉ์ง")
|
| 46 |
+
|
| 47 |
+
# ๋ชจ๋ธ ๋ก๋ (์ฌ์ ํ์ต ๊ฐ์ค์น ํฌํจ)
|
| 48 |
+
model = YOLO(f'yolov8{model_size}.pt')
|
| 49 |
+
|
| 50 |
+
# ํ์ต ํ์ดํผํ๋ผ๋ฏธํฐ
|
| 51 |
+
epochs = 100 # Few-shot์ด๋ฏ๋ก ๋ง์ epoch
|
| 52 |
+
batch_size = 8 # ์์ ๋ฐฐ์น (๋ฐ์ดํฐ ์ ์)
|
| 53 |
+
imgsz = 640 # ์
๋ ฅ ์ด๋ฏธ์ง ํฌ๊ธฐ
|
| 54 |
+
patience = 20 # Early stopping patience
|
| 55 |
+
|
| 56 |
+
print(f"\nโ๏ธ ํ์ต ์ค์ :")
|
| 57 |
+
print(f" - Epochs: {epochs}")
|
| 58 |
+
print(f" - Batch size: {batch_size}")
|
| 59 |
+
print(f" - Image size: {imgsz}")
|
| 60 |
+
print(f" - Patience: {patience} (early stopping)")
|
| 61 |
+
print(f" - Device: {device}")
|
| 62 |
+
|
| 63 |
+
# Data Augmentation ์ค์ (Few-shot์ ์ค์!)
|
| 64 |
+
print(f"\n๐ Data Augmentation:")
|
| 65 |
+
augment_params = {
|
| 66 |
+
'hsv_h': 0.015, # Hue augmentation (์์ ๋ณํ)
|
| 67 |
+
'hsv_s': 0.7, # Saturation augmentation
|
| 68 |
+
'hsv_v': 0.4, # Value (brightness) augmentation
|
| 69 |
+
'degrees': 10.0, # Rotation
|
| 70 |
+
'translate': 0.1, # Translation
|
| 71 |
+
'scale': 0.5, # Scaling
|
| 72 |
+
'shear': 0.0, # Shear
|
| 73 |
+
'perspective': 0.0, # Perspective
|
| 74 |
+
'flipud': 0.0, # Vertical flip (์์ฐ๋ ์ธ๋ก ๋ฐฉํฅ ์์)
|
| 75 |
+
'fliplr': 0.5, # Horizontal flip (์ข์ฐ๋ OK)
|
| 76 |
+
'mosaic': 1.0, # Mosaic augmentation
|
| 77 |
+
'mixup': 0.0, # Mixup augmentation
|
| 78 |
+
}
|
| 79 |
+
for k, v in augment_params.items():
|
| 80 |
+
print(f" - {k}: {v}")
|
| 81 |
+
|
| 82 |
+
print(f"\n๐ ํ์ต ์์...")
|
| 83 |
+
print(" (์งํ ์ํฉ์ ์ฝ์์ ํ์๋ฉ๋๋ค)")
|
| 84 |
+
print("-" * 60)
|
| 85 |
+
|
| 86 |
+
# ํ์ต ์คํ
|
| 87 |
+
results = model.train(
|
| 88 |
+
data=data_yaml,
|
| 89 |
+
epochs=epochs,
|
| 90 |
+
batch=batch_size,
|
| 91 |
+
imgsz=imgsz,
|
| 92 |
+
device=device,
|
| 93 |
+
patience=patience,
|
| 94 |
+
save=True,
|
| 95 |
+
project='runs/train',
|
| 96 |
+
name='shrimp_yolov8n',
|
| 97 |
+
exist_ok=True,
|
| 98 |
+
pretrained=True,
|
| 99 |
+
verbose=True,
|
| 100 |
+
# Data augmentation
|
| 101 |
+
**augment_params
|
| 102 |
+
)
|
| 103 |
+
|
| 104 |
+
print("\n" + "=" * 60)
|
| 105 |
+
print("โ
ํ์ต ์๋ฃ!")
|
| 106 |
+
print("=" * 60)
|
| 107 |
+
|
| 108 |
+
# ๊ฒฐ๊ณผ ์ถ๋ ฅ
|
| 109 |
+
best_model_path = Path('runs/train/shrimp_yolov8n/weights/best.pt')
|
| 110 |
+
last_model_path = Path('runs/train/shrimp_yolov8n/weights/last.pt')
|
| 111 |
+
|
| 112 |
+
print(f"\n๐ ํ์ต ๊ฒฐ๊ณผ:")
|
| 113 |
+
print(f" - Best ๋ชจ๋ธ: {best_model_path}")
|
| 114 |
+
print(f" - Last ๋ชจ๋ธ: {last_model_path}")
|
| 115 |
+
print(f"\n๐ ์ฑ๋ฅ ๊ทธ๋ํ:")
|
| 116 |
+
print(f" - runs/train/shrimp_yolov8n/results.png")
|
| 117 |
+
print(f"\n๐ ์ ์ฒด ๊ฒฐ๊ณผ:")
|
| 118 |
+
print(f" - runs/train/shrimp_yolov8n/")
|
| 119 |
+
|
| 120 |
+
# Validation ๊ฒฐ๊ณผ ์ถ๋ ฅ
|
| 121 |
+
print(f"\n๐ฏ ๋ค์ ๋จ๊ณ:")
|
| 122 |
+
print(f" 1. ๊ฒฐ๊ณผ ํ์ธ: runs/train/shrimp_yolov8n/")
|
| 123 |
+
print(f" 2. ์ฑ๋ฅ ํ๊ฐ: python evaluate_yolo.py")
|
| 124 |
+
print(f" 3. ์ถ๋ก ํ
์คํธ: python test_yolo_inference.py")
|
| 125 |
+
|
| 126 |
+
if __name__ == "__main__":
|
| 127 |
+
main()
|