oilbread commited on
Commit
d957ec2
ยท
1 Parent(s): 1bef33c
Files changed (1) hide show
  1. app.py +220 -238
app.py CHANGED
@@ -1,274 +1,256 @@
1
  import gradio as gr
 
2
  from ultralytics import YOLO
3
  import numpy as np
4
- import pandas as pd
5
- import matplotlib.pyplot as plt
6
- from PIL import Image
7
- import cv2
8
- import threading
9
  import time
10
 
11
- # ์ฒด์Šค ๊ธฐ๋ฌผ๋ณ„ ์œ ๋‹ˆ์ฝ”๋“œ ์‹ฌ๋ณผ ๋ฐ ์ƒ‰์ƒ ์ •์˜
12
- CHESS_PIECES = {
13
- 'w_king': {'symbol': 'โ™”', 'color': '#FFFFFF', 'edge': '#000000'},
14
- 'w_queen': {'symbol': 'โ™•', 'color': '#FFFFFF', 'edge': '#000000'},
15
- 'w_rook': {'symbol': 'โ™–', 'color': '#FFFFFF', 'edge': '#000000'},
16
- 'w_bishop': {'symbol': 'โ™—', 'color': '#FFFFFF', 'edge': '#000000'},
17
- 'w_knight': {'symbol': 'โ™˜', 'color': '#FFFFFF', 'edge': '#000000'},
18
- 'w_pawn': {'symbol': 'โ™™', 'color': '#FFFFFF', 'edge': '#000000'},
19
- 'b_king': {'symbol': 'โ™š', 'color': '#000000', 'edge': '#FFFFFF'},
20
- 'b_queen': {'symbol': 'โ™›', 'color': '#000000', 'edge': '#FFFFFF'},
21
- 'b_rook': {'symbol': 'โ™œ', 'color': '#000000', 'edge': '#FFFFFF'},
22
- 'b_bishop': {'symbol': 'โ™', 'color': '#000000', 'edge': '#FFFFFF'},
23
- 'b_knight': {'symbol': 'โ™ž', 'color': '#000000', 'edge': '#FFFFFF'},
24
- 'b_pawn': {'symbol': 'โ™Ÿ', 'color': '#000000', 'edge': '#FFFFFF'}
25
- }
26
 
27
- # ์ „์—ญ ๋ณ€์ˆ˜
28
- current_model = None
29
- cap = None
30
- streaming = False
31
- stream_thread = None
32
 
33
- # YOLOv8 ์ถ”๋ก  ํ•จ์ˆ˜ (์ •์  ์ด๋ฏธ์ง€์šฉ)
34
- def predict_chess(img, model_weight_file, conf, iou):
35
- global current_model
36
 
37
- # ๋ชจ๋ธ ๋กœ๋“œ
38
- weight_path = model_weight_file.name if model_weight_file is not None else 'yolov8n.pt'
39
- model = YOLO(weight_path)
40
- current_model = model
41
 
42
- results = model.predict(img, conf=conf, iou=iou, show_labels=True, show_conf=True)
43
- boxes = results[0].boxes
44
- names = results[0].names
45
- dets = []
46
- for box in boxes:
47
- cls = int(box.cls[0])
48
- name = names[cls]
49
- dets.append({
50
- 'name': name,
51
- 'conf': float(box.conf[0]),
52
- 'xmin': float(box.xyxy[0][0]),
53
- 'ymin': float(box.xyxy[0][1]),
54
- 'xmax': float(box.xyxy[0][2]),
55
- 'ymax': float(box.xyxy[0][3])
56
- })
57
- df = pd.DataFrame(dets)
58
- im_array = results[0].plot()
59
- im = Image.fromarray(im_array[..., ::-1])
60
- return im, df
61
-
62
- # ์›น์บ  ์ŠคํŠธ๋ฆผ ์‹œ์ž‘ ํ•จ์ˆ˜
63
- def start_webcam_stream(model_weight_file, conf, iou):
64
- global current_model, cap, streaming, stream_thread
65
 
66
- # ๋ชจ๋ธ ๋กœ๋“œ
67
- if model_weight_file is not None:
68
- weight_path = model_weight_file.name
69
- current_model = YOLO(weight_path)
70
- elif current_model is None:
71
- current_model = YOLO('yolov8n.pt')
72
 
73
- # ์›น์บ  ์ดˆ๊ธฐํ™”
74
- if cap is None:
75
- cap = cv2.VideoCapture(0)
76
- if not cap.isOpened():
77
- return None, "์›น์บ ์„ ์—ด ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค."
 
 
78
 
79
- streaming = True
 
 
 
 
 
 
 
 
 
 
80
 
81
- def stream_generator():
82
- while streaming and cap is not None and cap.isOpened():
83
- ret, frame = cap.read()
84
- if not ret:
85
- break
86
-
87
- # YOLO ์ถ”๋ก 
88
- results = current_model.predict(frame, conf=conf, iou=iou, show_labels=True, show_conf=True)
89
- annotated_frame = results[0].plot()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
90
 
91
- # BGR์„ RGB๋กœ ๋ณ€ํ™˜
92
- annotated_frame = cv2.cvtColor(annotated_frame, cv2.COLOR_BGR2RGB)
93
- pil_image = Image.fromarray(annotated_frame)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
94
 
95
- yield pil_image
 
 
 
 
 
96
 
97
- time.sleep(0.05) # ์•ฝ 20 FPS
 
 
 
 
 
 
 
 
 
 
 
 
98
 
99
- return stream_generator(), "์›น์บ  ์ŠคํŠธ๋ฆผ์ด ์‹œ์ž‘๋˜์—ˆ์Šต๋‹ˆ๋‹ค."
100
-
101
- # ์›น์บ  ์ŠคํŠธ๋ฆผ ์ค‘์ง€ ํ•จ์ˆ˜
102
- def stop_webcam_stream():
103
- global cap, streaming
104
- streaming = False
105
- if cap is not None:
106
- cap.release()
107
- cap = None
108
- return None, "์›น์บ  ์ŠคํŠธ๋ฆผ์ด ์ค‘์ง€๋˜์—ˆ์Šต๋‹ˆ๋‹ค."
109
 
110
- # ์‹ค์‹œ๊ฐ„ ์›น์บ  ์ฒ˜๋ฆฌ ํ•จ์ˆ˜ (Generator ๋ฐฉ์‹)
111
- def webcam_stream_generator(model_weight_file, conf, iou):
112
- global current_model, cap, streaming
 
 
 
113
 
114
- # ๋ชจ๋ธ ๋กœ๋“œ
115
- if model_weight_file is not None:
116
- weight_path = model_weight_file.name
117
- current_model = YOLO(weight_path)
118
- elif current_model is None:
119
- current_model = YOLO('yolov8n.pt')
 
120
 
121
- # ์›น์บ  ์ดˆ๊ธฐํ™”
122
- if cap is None:
123
- cap = cv2.VideoCapture(0)
124
- if not cap.isOpened():
125
- yield None
126
- return
127
 
128
- streaming = True
 
 
 
129
 
130
- while streaming:
131
- ret, frame = cap.read()
132
- if not ret:
133
- break
134
 
135
- # YOLO ์ถ”๋ก 
136
- results = current_model.predict(frame, conf=conf, iou=iou, show_labels=True, show_conf=True)
137
- annotated_frame = results[0].plot()
138
 
139
- # BGR์„ RGB๋กœ ๋ณ€ํ™˜
140
- annotated_frame = cv2.cvtColor(annotated_frame, cv2.COLOR_BGR2RGB)
141
- pil_image = Image.fromarray(annotated_frame)
142
 
143
- yield pil_image
 
144
 
145
- time.sleep(0.05) # ์•ฝ 20 FPS
146
-
147
- # ๊ธฐ๋ฌผ๋ณ„ ๊ฐœ์ˆ˜ ์‹œ๊ฐํ™”
148
- def plot_piece_count(df):
149
- if df.empty:
150
- fig, ax = plt.subplots()
151
- ax.text(0.5, 0.5, 'No pieces detected', ha='center', va='center')
152
- ax.axis('off')
153
- return fig
154
- counts = df['name'].value_counts().sort_index()
155
- labels = counts.index.tolist()
156
- colors = [CHESS_PIECES.get(n, {'color': '#888'})['color'] for n in counts.index]
157
- edges = [CHESS_PIECES.get(n, {'edge': '#888'})['edge'] for n in counts.index]
158
- fig, ax = plt.subplots(figsize=(8,4))
159
- bars = ax.bar(labels, counts.values, color=colors, edgecolor=edges, linewidth=2)
160
- for i, v in enumerate(counts.values):
161
- text_color = '#000000' if colors[i] == '#FFFFFF' else '#FFFFFF'
162
- ax.text(i, v-0.1, str(v), ha='center', va='top', fontsize=16, color=text_color, fontweight='bold')
163
- ax.set_title('Detected Chess Pieces (by symbol)')
164
- ax.set_ylabel('Count')
165
- ax.set_xticklabels(labels, fontsize=8, rotation=30)
166
- return fig
167
-
168
- # ์ฒด์ŠคํŒ plot (๊ธฐ๋ฌผ ์œ„์น˜ ์‹œ๊ฐํ™”)
169
- def plot_chessboard(df, img_shape):
170
- fig, ax = plt.subplots(figsize=(6,6))
171
- # ์ฒด์ŠคํŒ ๊ทธ๋ฆฌ๋“œ
172
- for i in range(9):
173
- ax.plot([0,8],[i,i], color='k', lw=1)
174
- ax.plot([i,i],[0,8], color='k', lw=1)
175
- # ๊ธฐ๋ฌผ ํ‘œ์‹œ
176
- if not df.empty:
177
- for _, row in df.iterrows():
178
- x = ((row['xmin']+row['xmax'])/2) / img_shape[1] * 8
179
- y = ((row['ymin']+row['ymax'])/2) / img_shape[0] * 8
180
- piece = CHESS_PIECES.get(row['name'], {'symbol': row['name'], 'color': '#888'})
181
- ax.text(x, 8-y, piece['symbol'], fontsize=28, ha='center', va='center', color=piece['color'], fontweight='bold')
182
- ax.set_xlim(0,8)
183
- ax.set_ylim(0,8)
184
- ax.set_xticks(range(9))
185
- ax.set_yticks(range(9))
186
- ax.set_xticklabels([])
187
- ax.set_yticklabels([])
188
- ax.set_title('Chessboard Piece Placement')
189
- ax.set_aspect('equal')
190
- return fig
191
-
192
- # Gradio ์•ฑ ํ•จ์ˆ˜ (์ •์  ์ด๋ฏธ์ง€์šฉ)
193
- def gradio_chess(img, model_weight_file, conf, iou):
194
- im, df = predict_chess(img, model_weight_file, conf, iou)
195
- piece_fig = plot_piece_count(df)
196
- board_fig = plot_chessboard(df, np.array(img).shape)
197
- return im, piece_fig, board_fig
198
-
199
- # Gradio ์ธํ„ฐํŽ˜์ด์Šค
200
- with gr.Blocks() as demo:
201
- gr.Markdown("""
202
- # โ™Ÿ๏ธ YOLOv8 Chess Piece Detection
203
- ์ด๋ฏธ์ง€ ์—…๋กœ๋“œ ๋˜๋Š” ์‹ค์‹œ๊ฐ„ ์›น์บ  ์ŠคํŠธ๋ฆผ์œผ๋กœ ์ฒด์Šค ๊ธฐ๋ฌผ ํƒ์ง€ ๋ฐ ๋ถ„์„ ๊ฒฐ๊ณผ๋ฅผ ๋ณด์—ฌ์ค๋‹ˆ๋‹ค.
204
- """)
205
-
206
- with gr.Tab("์ด๋ฏธ์ง€ ๋ถ„์„"):
207
- with gr.Row():
208
- with gr.Column():
209
- img_in = gr.Image(type="pil", label="์ฒด์ŠคํŒ ์ด๋ฏธ์ง€ ์—…๋กœ๋“œ")
210
- model_in = gr.File(label="YOLOv8 ๋ชจ๋ธ ๊ฐ€์ค‘์น˜ ํŒŒ์ผ ์—…๋กœ๋“œ (.pt, ์„ ํƒ)", file_types=[".pt"])
211
- conf_in = gr.Slider(0,1,step=0.01,value=0.25,label="Confidence Threshold")
212
- iou_in = gr.Slider(0,1,step=0.01,value=0.45,label="IoU Threshold")
213
- btn = gr.Button("๋ถ„์„ ์‹คํ–‰")
214
- with gr.Column():
215
- img_out = gr.Image(label="ํƒ์ง€ ๊ฒฐ๊ณผ ์ด๋ฏธ์ง€")
216
- piece_out = gr.Plot(label="๊ธฐ๋ฌผ๋ณ„ ๊ฐœ์ˆ˜ ์‹œ๊ฐํ™”")
217
 
218
- btn.click(fn=gradio_chess, inputs=[img_in, model_in, conf_in, iou_in], outputs=[img_out, piece_out])
 
 
 
 
 
 
 
 
 
219
 
220
- gr.Examples(
221
- examples=["./sample_object/one_object.jpg", "./sample_object/many_object.jpg"],
222
- inputs=[img_in]
223
- )
224
 
225
- with gr.Tab("์‹ค์‹œ๊ฐ„ ์›น์บ  ์ŠคํŠธ๋ฆผ"):
226
- with gr.Row():
227
- with gr.Column():
228
- # ๋ชจ๋ธ ๋ฐ ํŒŒ๋ผ๋ฏธํ„ฐ ์„ค์ •
229
- model_webcam = gr.File(label="YOLOv8 ๋ชจ๋ธ ๊ฐ€์ค‘์น˜ ํŒŒ์ผ ์—…๋กœ๋“œ (.pt, ์„ ํƒ)", file_types=[".pt"])
230
- conf_webcam = gr.Slider(0,1,step=0.01,value=0.25,label="Confidence Threshold")
231
- iou_webcam = gr.Slider(0,1,step=0.01,value=0.45,label="IoU Threshold")
232
-
233
- # ์ œ์–ด ๋ฒ„ํŠผ
234
- start_btn = gr.Button("์›น์บ  ์ŠคํŠธ๋ฆผ ์‹œ์ž‘", variant="primary")
235
- stop_btn = gr.Button("์›น์บ  ์ŠคํŠธ๋ฆผ ์ค‘๏ฟฝ๏ฟฝ๏ฟฝ", variant="secondary")
 
 
 
236
 
237
- # ์ƒํƒœ ํ‘œ์‹œ
238
- status_text = gr.Textbox(label="์ƒํƒœ", value="์›น์บ  ์ŠคํŠธ๋ฆผ์„ ์‹œ์ž‘ํ•˜๋ ค๋ฉด '์›น์บ  ์ŠคํŠธ๋ฆผ ์‹œ์ž‘' ๋ฒ„ํŠผ์„ ํด๋ฆญํ•˜์„ธ์š”", interactive=False)
 
239
 
240
- with gr.Column():
241
- webcam_output = gr.Image(label="์‹ค์‹œ๊ฐ„ ํƒ์ง€ ๊ฒฐ๊ณผ", streaming=True)
242
-
243
- # ์›น์บ  ์ŠคํŠธ๋ฆผ ์‹œ์ž‘ ๋ฒ„ํŠผ ์ด๋ฒคํŠธ
244
- start_btn.click(
245
- fn=lambda mw, conf, iou: webcam_stream_generator(mw, conf, iou),
246
- inputs=[model_webcam, conf_webcam, iou_webcam],
247
- outputs=[webcam_output]
248
- )
249
-
250
- # ์›น์บ  ์ŠคํŠธ๋ฆผ ์ค‘์ง€ ๋ฒ„ํŠผ ์ด๋ฒคํŠธ
251
- stop_btn.click(
252
- fn=stop_webcam_stream,
253
- inputs=[],
254
- outputs=[webcam_output, status_text]
255
- )
256
-
257
- # ์•ฑ ์ข…๋ฃŒ ์‹œ ์›น์บ  ์ •๋ฆฌ
258
- def cleanup():
259
- global cap, streaming
260
- streaming = False
261
- if cap is not None:
262
- cap.release()
 
263
 
264
- import atexit
265
- atexit.register(cleanup)
 
 
 
 
 
 
 
 
 
 
 
266
 
267
  if __name__ == "__main__":
268
- demo.launch(share=True, server_name='0.0.0.0', server_port=7860, debug=True)
 
 
 
 
 
 
 
 
 
269
 
270
  # ์‹คํ–‰ ๋ฐฉ๋ฒ•:
271
- # 1. ํ•„์š”ํ•œ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์„ค์น˜:
272
- # pip install gradio ultralytics opencv-python matplotlib pandas pillow
273
- # 2. ํŒŒ์ผ์„ app.py๋กœ ์ €์žฅํ•˜๊ณ  ์‹คํ–‰:
274
- # python app.py
 
1
  import gradio as gr
2
+ import cv2
3
  from ultralytics import YOLO
4
  import numpy as np
 
 
 
 
 
5
  import time
6
 
7
+ # YOLOv8 ๋ชจ๋ธ ๋กœ๋“œ (์ตœ์ดˆ ์‹คํ–‰ ์‹œ ์ž๋™ ๋‹ค์šด๋กœ๋“œ)
8
+ model = YOLO("yolov8n.pt") # ๊ฐ€์žฅ ๊ฐ€๋ฒผ์šด ๋ชจ๋ธ, ๋” ์ •ํ™•ํ•œ ๋ชจ๋ธ์€ yolov8s.pt ๋“ฑ ์‚ฌ์šฉ ๊ฐ€๋Šฅ
 
 
 
 
 
 
 
 
 
 
 
 
 
9
 
10
+ # ์ „์—ญ ๋ณ€์ˆ˜๋กœ FPS ๊ณ„์‚ฐ์šฉ
11
+ frame_count = 0
12
+ start_time = time.time()
 
 
13
 
14
+ def object_detection(image, conf_threshold=0.25, iou_threshold=0.45, show_labels=True, show_conf=True):
15
+ global frame_count, start_time
 
16
 
17
+ if image is None:
18
+ return None
 
 
19
 
20
+ # Gradio์—์„œ ์ด๋ฏธ์ง€๋Š” RGB, OpenCV๋Š” BGR์ด๋ฏ€๋กœ ๋ณ€ํ™˜
21
+ img_bgr = cv2.cvtColor(image, cv2.COLOR_RGB2BGR)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
22
 
23
+ # YOLO ์ถ”๋ก  ์‹คํ–‰
24
+ results = model(img_bgr, conf=conf_threshold, iou=iou_threshold)
 
 
 
 
25
 
26
+ # ๋ฐ”์šด๋”ฉ ๋ฐ•์Šค ๋“ฑ ์‹œ๊ฐํ™”๋œ ์ด๋ฏธ์ง€(BGR)
27
+ annotated = results[0].plot(
28
+ show_labels=show_labels,
29
+ show_conf=show_conf,
30
+ line_width=2,
31
+ font_size=1
32
+ )
33
 
34
+ # FPS ๊ณ„์‚ฐ ๋ฐ ํ‘œ์‹œ
35
+ frame_count += 1
36
+ current_time = time.time()
37
+ if current_time - start_time > 1.0: # 1์ดˆ๋งˆ๋‹ค FPS ์—…๋ฐ์ดํŠธ
38
+ fps = frame_count / (current_time - start_time)
39
+ frame_count = 0
40
+ start_time = current_time
41
+
42
+ # FPS๋ฅผ ์ด๋ฏธ์ง€์— ํ‘œ์‹œ
43
+ cv2.putText(annotated, f'FPS: {fps:.1f}', (10, 30),
44
+ cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2)
45
 
46
+ # BGR์„ RGB๋กœ ๋ณ€ํ™˜ํ•˜์—ฌ ๋ฐ˜ํ™˜
47
+ annotated_rgb = cv2.cvtColor(annotated, cv2.COLOR_BGR2RGB)
48
+ return annotated_rgb
49
+
50
+ def reset_fps():
51
+ global frame_count, start_time
52
+ frame_count = 0
53
+ start_time = time.time()
54
+
55
+ # Gradio ์ธํ„ฐํŽ˜์ด์Šค ๊ตฌ์„ฑ
56
+ with gr.Blocks(title="์‹ค์‹œ๊ฐ„ YOLO ๊ฐ์ฒด ํƒ์ง€") as demo:
57
+ gr.Markdown("""
58
+ # ๐Ÿš€ ์‹ค์‹œ๊ฐ„ YOLO ๊ฐ์ฒด ํƒ์ง€
59
+ ์›น์บ ์„ ํ†ตํ•ด ์‹ค์‹œ๊ฐ„์œผ๋กœ ๊ฐ์ฒด๋ฅผ ํƒ์ง€ํ•ฉ๋‹ˆ๋‹ค. ๋‹ค์–‘ํ•œ ์„ค์ •์„ ์กฐ์ •ํ•˜์—ฌ ํƒ์ง€ ์„ฑ๋Šฅ์„ ์ตœ์ ํ™”ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
60
+ """)
61
+
62
+ with gr.Row():
63
+ with gr.Column():
64
+ webcam_input = gr.Image(
65
+ label='๐Ÿ“น ์›น์บ  ์ž…๋ ฅ',
66
+ sources="webcam",
67
+ streaming=True,
68
+ width=640,
69
+ height=480
70
+ )
71
 
72
+ # ์„ค์ • ํŒจ๋„
73
+ with gr.Group():
74
+ gr.Markdown("### โš™๏ธ ํƒ์ง€ ์„ค์ •")
75
+ conf_slider = gr.Slider(
76
+ minimum=0.1,
77
+ maximum=1.0,
78
+ value=0.25,
79
+ step=0.05,
80
+ label="์‹ ๋ขฐ๋„ ์ž„๊ณ„๊ฐ’ (Confidence Threshold)"
81
+ )
82
+ iou_slider = gr.Slider(
83
+ minimum=0.1,
84
+ maximum=1.0,
85
+ value=0.45,
86
+ step=0.05,
87
+ label="IoU ์ž„๊ณ„๊ฐ’ (Non-Max Suppression)"
88
+ )
89
+
90
+ with gr.Row():
91
+ show_labels_cb = gr.Checkbox(label="๋ผ๋ฒจ ํ‘œ์‹œ", value=True)
92
+ show_conf_cb = gr.Checkbox(label="์‹ ๋ขฐ๋„ ํ‘œ์‹œ", value=True)
93
+
94
+ reset_btn = gr.Button("FPS ๋ฆฌ์…‹", variant="secondary")
95
 
96
+ with gr.Column():
97
+ webcam_output = gr.Image(
98
+ label='๐ŸŽฏ ๊ฐ์ฒด ํƒ์ง€ ๊ฒฐ๊ณผ',
99
+ width=640,
100
+ height=480
101
+ )
102
 
103
+ # ์ •๋ณด ํŒจ๋„
104
+ with gr.Group():
105
+ gr.Markdown("""
106
+ ### ๐Ÿ“Š ํƒ์ง€ ์ •๋ณด
107
+ - **์‹ ๋ขฐ๋„ ์ž„๊ณ„๊ฐ’**: ๋‚ฎ์„์ˆ˜๋ก ๋” ๋งŽ์€ ๊ฐ์ฒด ํƒ์ง€ (false positive ์ฆ๊ฐ€)
108
+ - **IoU ์ž„๊ณ„๊ฐ’**: ์ค‘๋ณต ํƒ์ง€ ์ œ๊ฑฐ ๊ธฐ์ค€
109
+ - **FPS**: ์ดˆ๋‹น ํ”„๋ ˆ์ž„ ์ฒ˜๋ฆฌ ์†๋„
110
+
111
+ ### ๐ŸŽฎ ์‚ฌ์šฉ ๋ฐฉ๋ฒ•
112
+ 1. ์›น์บ  ์ ‘๊ทผ ๊ถŒํ•œ ํ—ˆ์šฉ
113
+ 2. ์„ค์ •๊ฐ’ ์กฐ์ •์œผ๋กœ ํƒ์ง€ ์„ฑ๋Šฅ ์ตœ์ ํ™”
114
+ 3. ์‹ค์‹œ๊ฐ„์œผ๋กœ ๊ฐ์ฒด ํƒ์ง€ ๊ฒฐ๊ณผ ํ™•์ธ
115
+ """)
116
 
117
+ # ์ŠคํŠธ๋ฆฌ๋ฐ ์ด๋ฒคํŠธ ์—ฐ๊ฒฐ
118
+ webcam_input.stream(
119
+ fn=object_detection,
120
+ inputs=[webcam_input, conf_slider, iou_slider, show_labels_cb, show_conf_cb],
121
+ outputs=[webcam_output],
122
+ stream_every=0.1 # 100ms๋งˆ๋‹ค ์ฒ˜๋ฆฌ (์•ฝ 10 FPS)
123
+ )
124
+
125
+ # FPS ๋ฆฌ์…‹ ๋ฒ„ํŠผ ์ด๋ฒคํŠธ
126
+ reset_btn.click(fn=reset_fps, inputs=[], outputs=[])
127
 
128
+ # ๋‹ค์–‘ํ•œ ๋ชจ๋ธ ์˜ต์…˜์„ ์ œ๊ณตํ•˜๋Š” ๊ณ ๊ธ‰ ๋ฒ„์ „
129
+ with gr.Blocks(title="๊ณ ๊ธ‰ YOLO ๊ฐ์ฒด ํƒ์ง€") as advanced_demo:
130
+ gr.Markdown("""
131
+ # ๐Ÿ”ฌ ๊ณ ๊ธ‰ YOLO ๊ฐ์ฒด ํƒ์ง€
132
+ ๋‹ค์–‘ํ•œ YOLO ๋ชจ๋ธ์„ ์„ ํƒํ•˜๊ณ  ๊ณ ๊ธ‰ ์„ค์ •์„ ์กฐ์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
133
+ """)
134
 
135
+ # ๋ชจ๋ธ ์„ ํƒ
136
+ model_choice = gr.Dropdown(
137
+ choices=["yolov8n.pt", "yolov8s.pt", "yolov8m.pt", "yolov8l.pt", "yolov8x.pt"],
138
+ value="yolov8n.pt",
139
+ label="YOLO ๋ชจ๋ธ ์„ ํƒ",
140
+ info="n < s < m < l < x (์†๋„ vs ์ •ํ™•๋„)"
141
+ )
142
 
143
+ current_model = model # ํ˜„์žฌ ๋ชจ๋ธ ์ €์žฅ
 
 
 
 
 
144
 
145
+ def change_model(model_name):
146
+ global current_model
147
+ current_model = YOLO(model_name)
148
+ return f"๋ชจ๋ธ์ด {model_name}์œผ๋กœ ๋ณ€๊ฒฝ๋˜์—ˆ์Šต๋‹ˆ๋‹ค."
149
 
150
+ def advanced_object_detection(image, model_name, conf_threshold, iou_threshold, show_labels, show_conf):
151
+ global current_model, frame_count, start_time
 
 
152
 
153
+ if image is None:
154
+ return None
 
155
 
156
+ # ๋ชจ๋ธ ๋ณ€๊ฒฝ ํ™•์ธ
157
+ if current_model.model_name != model_name:
158
+ current_model = YOLO(model_name)
159
 
160
+ img_bgr = cv2.cvtColor(image, cv2.COLOR_RGB2BGR)
161
+ results = current_model(img_bgr, conf=conf_threshold, iou=iou_threshold)
162
 
163
+ annotated = results[0].plot(
164
+ show_labels=show_labels,
165
+ show_conf=show_conf,
166
+ line_width=2,
167
+ font_size=1
168
+ )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
169
 
170
+ # FPS ๊ณ„์‚ฐ
171
+ frame_count += 1
172
+ current_time = time.time()
173
+ if current_time - start_time > 1.0:
174
+ fps = frame_count / (current_time - start_time)
175
+ frame_count = 0
176
+ start_time = current_time
177
+
178
+ cv2.putText(annotated, f'FPS: {fps:.1f} | Model: {model_name}',
179
+ (10, 30), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 255, 0), 2)
180
 
181
+ annotated_rgb = cv2.cvtColor(annotated, cv2.COLOR_BGR2RGB)
182
+ return annotated_rgb
 
 
183
 
184
+ with gr.Row():
185
+ with gr.Column():
186
+ adv_webcam_input = gr.Image(
187
+ label='๐Ÿ“น ์›น์บ  ์ž…๋ ฅ',
188
+ sources="webcam",
189
+ streaming=True,
190
+ width=640,
191
+ height=480
192
+ )
193
+
194
+ with gr.Group():
195
+ gr.Markdown("### ๐ŸŽ›๏ธ ๊ณ ๊ธ‰ ์„ค์ •")
196
+ adv_conf_slider = gr.Slider(0.1, 1.0, 0.25, 0.05, label="์‹ ๋ขฐ๋„ ์ž„๊ณ„๊ฐ’")
197
+ adv_iou_slider = gr.Slider(0.1, 1.0, 0.45, 0.05, label="IoU ์ž„๊ณ„๊ฐ’")
198
 
199
+ with gr.Row():
200
+ adv_show_labels_cb = gr.Checkbox(label="๋ผ๋ฒจ ํ‘œ์‹œ", value=True)
201
+ adv_show_conf_cb = gr.Checkbox(label="์‹ ๋ขฐ๋„ ํ‘œ์‹œ", value=True)
202
 
203
+ change_model_btn = gr.Button("๋ชจ๋ธ ๋ณ€๊ฒฝ", variant="primary")
204
+ model_status = gr.Textbox(label="๋ชจ๋ธ ์ƒํƒœ", interactive=False)
205
+
206
+ with gr.Column():
207
+ adv_webcam_output = gr.Image(
208
+ label='๐ŸŽฏ ๊ฐ์ฒด ํƒ์ง€ ๊ฒฐ๊ณผ',
209
+ width=640,
210
+ height=480
211
+ )
212
+
213
+ # ์ด๋ฒคํŠธ ์—ฐ๊ฒฐ
214
+ adv_webcam_input.stream(
215
+ fn=advanced_object_detection,
216
+ inputs=[adv_webcam_input, model_choice, adv_conf_slider, adv_iou_slider,
217
+ adv_show_labels_cb, adv_show_conf_cb],
218
+ outputs=[adv_webcam_output],
219
+ stream_every=0.1
220
+ )
221
+
222
+ change_model_btn.click(
223
+ fn=change_model,
224
+ inputs=[model_choice],
225
+ outputs=[model_status]
226
+ )
227
 
228
+ # ํƒญ์œผ๋กœ ๊ตฌ์„ฑ๋œ ์ตœ์ข… ์ธํ„ฐํŽ˜์ด์Šค
229
+ with gr.Blocks(title="YOLO ์›น์บ  ๊ฐ์ฒด ํƒ์ง€") as final_demo:
230
+ gr.Markdown("""
231
+ # ๐ŸŽฏ YOLO ์›น์บ  ๊ฐ์ฒด ํƒ์ง€
232
+ ์‹ค์‹œ๊ฐ„ ์›น์บ  ์ŠคํŠธ๋ฆผ์—์„œ ๊ฐ์ฒด๋ฅผ ํƒ์ง€ํ•ฉ๋‹ˆ๋‹ค.
233
+ """)
234
+
235
+ with gr.Tabs():
236
+ with gr.TabItem("๐Ÿš€ ๊ธฐ๋ณธ ๋ชจ๋“œ"):
237
+ demo.render()
238
+
239
+ with gr.TabItem("๐Ÿ”ฌ ๊ณ ๊ธ‰ ๋ชจ๋“œ"):
240
+ advanced_demo.render()
241
 
242
  if __name__ == "__main__":
243
+ # ๊ธฐ๋ณธ ๋ชจ๋“œ๋กœ ์‹คํ–‰
244
+ demo.launch(
245
+ share=True,
246
+ server_name="0.0.0.0",
247
+ server_port=7860,
248
+ debug=False
249
+ )
250
+
251
+ # ๊ณ ๊ธ‰ ๋ชจ๋“œ๋กœ ์‹คํ–‰ํ•˜๋ ค๋ฉด ๋‹ค์Œ ์ค„์˜ ์ฃผ์„์„ ํ•ด์ œํ•˜์„ธ์š”:
252
+ # final_demo.launch(share=True, server_name="0.0.0.0", server_port=7860)
253
 
254
  # ์‹คํ–‰ ๋ฐฉ๋ฒ•:
255
+ # pip install gradio ultralytics opencv-python
256
+ # python app.py