๋ค์ค ๊ฐ์ฒด ์ถ์ Ultralytics YOLO
๋น๋์ค ๋ถ์ ์์ญ์์ ๊ฐ์ฒด ์ถ์ ์ ํ๋ ์ ๋ด ๊ฐ์ฒด์ ์์น์ ํด๋์ค๋ฅผ ์๋ณํ ๋ฟ๋ง ์๋๋ผ ๋น๋์ค๊ฐ ์งํ๋จ์ ๋ฐ๋ผ ๊ฐ์ง๋ ๊ฐ ๊ฐ์ฒด์ ๋ํ ๊ณ ์ ID๋ฅผ ์ ์งํ๋ ์ค์ํ ์์ ์ ๋๋ค. ๊ฐ์ ๋ฐ ๋ณด์๋ถํฐ ์ค์๊ฐ ์คํฌ์ธ ๋ถ์์ ์ด๋ฅด๊ธฐ๊น์ง ๊ทธ ํ์ฉ ๋ถ์ผ๋ ๋ฌด๊ถ๋ฌด์งํฉ๋๋ค.
๊ฐ์ฒด ์ถ์ ์ Ultralytics YOLO ์ ์ ํํ๋ ์ด์ ๋ ๋ฌด์์ธ๊ฐ์?
Ultralytics ํธ๋์ปค์ ์ถ๋ ฅ์ ํ์ค ๊ฐ์ฒด ๊ฐ์ง์ ์ผ์นํ์ง๋ง ๊ฐ์ฒด ID๋ผ๋ ๋ถ๊ฐ ๊ฐ์น๊ฐ ์์ต๋๋ค. ์ด๋ฅผ ํตํด ๋์์ ์คํธ๋ฆผ์์ ๊ฐ์ฒด๋ฅผ ์ฝ๊ฒ ์ถ์ ํ๊ณ ํ์ ๋ถ์์ ์ํํ ์ ์์ต๋๋ค. ๊ฐ์ฒด ์ถ์ ์ Ultralytics YOLO ์ฌ์ฉ์ ๊ณ ๋ คํด์ผ ํ๋ ์ด์ ๋ ๋ค์๊ณผ ๊ฐ์ต๋๋ค:
- ํจ์จ์ฑ: ์ ํ๋ ์ ํ ์์ด ์ค์๊ฐ์ผ๋ก ๋น๋์ค ์คํธ๋ฆผ์ ์ฒ๋ฆฌํฉ๋๋ค.
- ์ ์ฐ์ฑ: ๋ค์ํ ์ถ์ ์๊ณ ๋ฆฌ์ฆ๊ณผ ๊ตฌ์ฑ์ ์ง์ํฉ๋๋ค.
- ์ฌ์ฉ ํธ์์ฑ: ๊ฐ๋จํ Python API ๋ฐ CLI ์ต์ ์ผ๋ก ๋น ๋ฅด๊ฒ ํตํฉ ๋ฐ ๋ฐฐํฌํ ์ ์์ต๋๋ค.
- ์ฌ์ฉ์ ์ง์ ๊ธฐ๋ฅ: ์ฌ์ฉ์ ์ ์ ํ๋ จ๋ YOLO ๋ชจ๋ธ๋ก ์ฝ๊ฒ ์ฌ์ฉํ ์ ์์ด ๋๋ฉ์ธ๋ณ ์ ํ๋ฆฌ์ผ์ด์ ์ ํตํฉํ ์ ์์ต๋๋ค.
Watch: ๋ฌผ์ฒด ๊ฐ์ง ๋ฐ ์ถ์ Ultralytics YOLOv8 .
์ค์ ์ ํ๋ฆฌ์ผ์ด์
๊ตํตํธ | ๋ฆฌํ ์ผ | ์์์ |
---|---|---|
์ฐจ๋ ์ถ์ | ์ฌ๋ ์ถ์ | ๋ฌผ๊ณ ๊ธฐ ์ถ์ |
๊ธฐ๋ฅ ์ดํด๋ณด๊ธฐ
Ultralytics YOLO ๋ ๋ฌผ์ฒด ๊ฐ์ง ๊ธฐ๋ฅ์ ํ์ฅํ์ฌ ๊ฐ๋ ฅํ๊ณ ๋ค์ํ ๋ฌผ์ฒด ์ถ์ ์ ์ ๊ณตํฉ๋๋ค:
- ์ค์๊ฐ ์ถ์ : ๊ณ ํ๋ ์๋ฅ ๋์์์์ ์ค๋ธ์ ํธ๋ฅผ ์ํํ๊ฒ ์ถ์ ํฉ๋๋ค.
- ์ฌ๋ฌ ํธ๋์ปค ์ง์: ์ด๋ฏธ ํ๋ฆฝ๋ ๋ค์ํ ์ถ์ ์๊ณ ๋ฆฌ์ฆ ์ค์์ ์ ํํ์ธ์.
- ์ฌ์ฉ์ ์ง์ ๊ฐ๋ฅํ ํธ๋์ปค ๊ตฌ์ฑ: ๋ค์ํ ๋งค๊ฐ๋ณ์๋ฅผ ์กฐ์ ํ์ฌ ํน์ ์๊ตฌ์ฌํญ์ ์ถฉ์กฑํ๋๋ก ์ถ์ ์๊ณ ๋ฆฌ์ฆ์ ๋ง์ถค ์ค์ ํ ์ ์์ต๋๋ค.
์ฌ์ฉ ๊ฐ๋ฅํ ํธ๋์ปค
Ultralytics YOLO ๋ ๋ค์๊ณผ ๊ฐ์ ์ถ์ ์๊ณ ๋ฆฌ์ฆ์ ์ง์ํฉ๋๋ค. ๋ค์๊ณผ ๊ฐ์ ๊ด๋ จ YAML ๊ตฌ์ฑ ํ์ผ์ ์ ๋ฌํ์ฌ ํ์ฑํํ ์ ์์ต๋๋ค. tracker=tracker_type.yaml
:
- BoT-SORT - ์ฌ์ฉ
botsort.yaml
๋ฅผ ํด๋ฆญํ์ฌ ์ด ํธ๋์ปค๋ฅผ ํ์ฑํํฉ๋๋ค. - ByteTrack - ์ฌ์ฉ
bytetrack.yaml
๋ฅผ ํด๋ฆญํ์ฌ ์ด ํธ๋์ปค๋ฅผ ํ์ฑํํฉ๋๋ค.
๊ธฐ๋ณธ ํธ๋์ปค๋ BoT-SORT์ ๋๋ค.
์ถ์
ํธ๋์ปค ์๊ณ๊ฐ ์ ๋ณด
๊ฐ์ฒด ์ ๋ขฐ๋ ์ ์๊ฐ ๋ฎ์ ๊ฒฝ์ฐ(์ฆ, ๋ค์๋ณด๋ค ๋ฎ์ ๊ฒฝ์ฐ) track_high_thresh
๋ฅผ ๋๋ฅด๋ฉด ์ฑ๊ณต์ ์ผ๋ก ๋ฐํ ๋ฐ ์
๋ฐ์ดํธ๋ ํธ๋์ด ์์ต๋๋ค.
๋์์ ์คํธ๋ฆผ์์ ํธ๋์ปค๋ฅผ ์คํํ๋ ค๋ฉด YOLOv8n, YOLOv8n-seg ๋ฐ YOLOv8n-pose์ ๊ฐ์ด ํ์ต๋ ๊ฐ์ง, ์ธ๊ทธ๋จผํธ ๋๋ ํฌ์ฆ ๋ชจ๋ธ์ ์ฌ์ฉํ์ธ์.
์
from ultralytics import YOLO
# Load an official or custom model
model = YOLO("yolov8n.pt") # Load an official Detect model
model = YOLO("yolov8n-seg.pt") # Load an official Segment model
model = YOLO("yolov8n-pose.pt") # Load an official Pose model
model = YOLO("path/to/best.pt") # Load a custom trained model
# Perform tracking with the model
results = model.track("https://youtu.be/LNwODJXcvt4", show=True) # Tracking with default tracker
results = model.track("https://youtu.be/LNwODJXcvt4", show=True, tracker="bytetrack.yaml") # with ByteTrack
# Perform tracking with various models using the command line interface
yolo track model=yolov8n.pt source="https://youtu.be/LNwODJXcvt4" # Official Detect model
yolo track model=yolov8n-seg.pt source="https://youtu.be/LNwODJXcvt4" # Official Segment model
yolo track model=yolov8n-pose.pt source="https://youtu.be/LNwODJXcvt4" # Official Pose model
yolo track model=path/to/best.pt source="https://youtu.be/LNwODJXcvt4" # Custom trained model
# Track using ByteTrack tracker
yolo track model=path/to/best.pt tracker="bytetrack.yaml"
์์ ์ฌ์ฉ ์์์ ๋ณผ ์ ์๋ฏ์ด ๋์์ ๋๋ ์คํธ๋ฆฌ๋ฐ ์์ค์์ ์คํ๋๋ ๋ชจ๋ ๊ฐ์ง, ์ธ๊ทธ๋จผํธ ๋ฐ ํฌ์ฆ ๋ชจ๋ธ์์ ์ถ์ ์ ์ฌ์ฉํ ์ ์์ต๋๋ค.
๊ตฌ์ฑ
ํธ๋์ปค ์๊ณ๊ฐ ์ ๋ณด
๊ฐ์ฒด ์ ๋ขฐ๋ ์ ์๊ฐ ๋ฎ์ ๊ฒฝ์ฐ(์ฆ, ๋ค์๋ณด๋ค ๋ฎ์ ๊ฒฝ์ฐ) track_high_thresh
๋ฅผ ๋๋ฅด๋ฉด ์ฑ๊ณต์ ์ผ๋ก ๋ฐํ ๋ฐ ์
๋ฐ์ดํธ๋ ํธ๋์ด ์์ต๋๋ค.
์ถ์ ์ธ์
์ถ์ ๊ตฌ์ฑ์ ๋ค์๊ณผ ๊ฐ์ด ์์ธก ๋ชจ๋์ ์์ฑ์ ๊ณต์ ํฉ๋๋ค. conf
, iou
๋ฐ show
. ์ถ๊ฐ ๊ตฌ์ฑ์ ๋ํด์๋ ์์ธก ๋ชจ๋ธ ํ์ด์ง๋ก ์ด๋ํฉ๋๋ค.
์
ํธ๋์ปค ์ ํ
Ultralytics ๋ฅผ ์ฌ์ฉํ๋ฉด ์์ ๋ ํธ๋์ปค ๊ตฌ์ฑ ํ์ผ์ ์ฌ์ฉํ ์๋ ์์ต๋๋ค. ์ด๋ ๊ฒ ํ๋ ค๋ฉด ํธ๋์ปค ๊ตฌ์ฑ ํ์ผ์ ๋ณต์ฌ๋ณธ์ ๋ง๋ค๊ธฐ๋ง ํ๋ฉด ๋ฉ๋๋ค(์ custom_tracker.yaml
)์์ ultralytics/cfg/trackers ๋ฅผ ํด๋ฆญํ๊ณ ๋ชจ๋ ๊ตฌ์ฑ์ ์์ ํฉ๋๋ค( tracker_type
) ํ์์ ๋ฐ๋ผ ์กฐ์ ํ ์ ์์ต๋๋ค.
์
์ถ์ ์ธ์์ ์ ์ฒด ๋ชฉ๋ก์ ultralytics/cfg/trackers ํ์ด์ง๋ฅผ ์ฐธ์กฐํ์ธ์.
Python ์์
ํธ๋ ๋ฃจํ ์ง์
๋ค์์ OpenCV๋ฅผ ์ฌ์ฉํ๋ Python ์คํฌ๋ฆฝํธ์
๋๋ค(cv2
) ๋ฐ YOLOv8 ๋ฅผ ์ฌ์ฉํ์ฌ ๋น๋์ค ํ๋ ์์์ ๊ฐ์ฒด ์ถ์ ์ ์คํํฉ๋๋ค. ์ด ์คํฌ๋ฆฝํธ๋ ํ์ํ ํจํค์ง๋ฅผ ์ด๋ฏธ ์ค์นํ๋ค๊ณ ๊ฐ์ ํฉ๋๋ค(opencv-python
๊ทธ๋ฆฌ๊ณ ultralytics
). ๊ทธ๋ฆฌ๊ณ persist=True
์ธ์๋ ํธ๋์ปค์๊ฒ ํ์ฌ ์ด๋ฏธ์ง ๋๋ ํ๋ ์์ด ์ํ์ค์ ๋ค์ ์ด๋ฏธ์ง์ด๋ฉฐ ํ์ฌ ์ด๋ฏธ์ง์์ ์ด์ ์ด๋ฏธ์ง์ ํธ๋์ ์์ํ๋๋ก ์ง์ํฉ๋๋ค.
์ถ์ ๊ธฐ๋ฅ์ด ์๋ ํฌ-๋ฃจํ ์คํธ๋ฆฌ๋ฐ
import cv2
from ultralytics import YOLO
# Load the YOLOv8 model
model = YOLO("yolov8n.pt")
# Open the video file
video_path = "path/to/video.mp4"
cap = cv2.VideoCapture(video_path)
# Loop through the video frames
while cap.isOpened():
# Read a frame from the video
success, frame = cap.read()
if success:
# Run YOLOv8 tracking on the frame, persisting tracks between frames
results = model.track(frame, persist=True)
# Visualize the results on the frame
annotated_frame = results[0].plot()
# Display the annotated frame
cv2.imshow("YOLOv8 Tracking", annotated_frame)
# Break the loop if 'q' is pressed
if cv2.waitKey(1) & 0xFF == ord("q"):
break
else:
# Break the loop if the end of the video is reached
break
# Release the video capture object and close the display window
cap.release()
cv2.destroyAllWindows()
๋ค์์ ๋ณ๊ฒฝ ์ฌํญ์ ์ ์ํ์ธ์. model(frame)
์ model.track(frame)
๋ฅผ ์ฌ์ฉํ์ฌ ๋จ์ ๊ฐ์ง ๋์ ๊ฐ์ฒด ์ถ์ ์ ํ์ฑํํ ์ ์์ต๋๋ค. ์ด ์์ ๋ ์คํฌ๋ฆฝํธ๋ ๋์์์ ๊ฐ ํ๋ ์์์ ํธ๋์ปค๋ฅผ ์คํํ๊ณ ๊ฒฐ๊ณผ๋ฅผ ์๊ฐํํ์ฌ ์ฐฝ์ ํ์ํฉ๋๋ค. 'Q'๋ฅผ ๋๋ฌ ๋ฃจํ๋ฅผ ์ข
๋ฃํ ์ ์์ต๋๋ค.
์๊ฐ ๊ฒฝ๊ณผ์ ๋ฐ๋ฅธ ํธ๋ ํ๋กํ
์ฐ์๋ ํ๋ ์์ ๊ฑธ์ณ ๊ฐ์ฒด ํธ๋์ ์๊ฐํํ๋ฉด ๋์์ ๋ด์์ ๊ฐ์ง๋ ๊ฐ์ฒด์ ์์ง์ ํจํด๊ณผ ๋์์ ๋ํ ๊ท์คํ ์ธ์ฌ์ดํธ๋ฅผ ์ป์ ์ ์์ต๋๋ค. Ultralytics YOLOv8 ์ ์ฌ์ฉํ๋ฉด ์ด๋ฌํ ํธ๋์ ์ํํ๊ณ ํจ์จ์ ์ผ๋ก ํ๋กํ ํ ์ ์์ต๋๋ค.
๋ค์ ์์ ์์๋ YOLOv8 ์ ์ถ์ ๊ธฐ๋ฅ์ ํ์ฉํ์ฌ ์ฌ๋ฌ ๋น๋์ค ํ๋ ์์์ ๊ฐ์ง๋ ๊ฐ์ฒด์ ์์ง์์ ํ๋กํ ํ๋ ๋ฐฉ๋ฒ์ ๋ณด์ฌ์ค๋๋ค. ์ด ์คํฌ๋ฆฝํธ์์๋ ๋น๋์ค ํ์ผ์ ์ด๊ณ ํ๋ ์๋ณ๋ก ์ฝ์ ๋ค์ YOLO ๋ชจ๋ธ์ ํ์ฉํ์ฌ ๋ค์ํ ๊ฐ์ฒด๋ฅผ ์๋ณํ๊ณ ์ถ์ ํฉ๋๋ค. ๊ฐ์ง๋ ๊ฒฝ๊ณ ์์์ ์ค์ฌ์ ์ ์ ์งํ๊ณ ์ฐ๊ฒฐํ์ฌ ์ถ์ ๋ ๊ฐ์ฒด๊ฐ ๋ฐ๋ผ๊ฐ ๊ฒฝ๋ก๋ฅผ ๋ํ๋ด๋ ์ ์ ๊ทธ๋ฆด ์ ์์ต๋๋ค.
์ฌ๋ฌ ๋น๋์ค ํ๋ ์์ ๊ฑธ์ณ ํธ๋ ํ๋กํ ํ๊ธฐ
from collections import defaultdict
import cv2
import numpy as np
from ultralytics import YOLO
# Load the YOLOv8 model
model = YOLO("yolov8n.pt")
# Open the video file
video_path = "path/to/video.mp4"
cap = cv2.VideoCapture(video_path)
# Store the track history
track_history = defaultdict(lambda: [])
# Loop through the video frames
while cap.isOpened():
# Read a frame from the video
success, frame = cap.read()
if success:
# Run YOLOv8 tracking on the frame, persisting tracks between frames
results = model.track(frame, persist=True)
# Get the boxes and track IDs
boxes = results[0].boxes.xywh.cpu()
track_ids = results[0].boxes.id.int().cpu().tolist()
# Visualize the results on the frame
annotated_frame = results[0].plot()
# Plot the tracks
for box, track_id in zip(boxes, track_ids):
x, y, w, h = box
track = track_history[track_id]
track.append((float(x), float(y))) # x, y center point
if len(track) > 30: # retain 90 tracks for 90 frames
track.pop(0)
# Draw the tracking lines
points = np.hstack(track).astype(np.int32).reshape((-1, 1, 2))
cv2.polylines(annotated_frame, [points], isClosed=False, color=(230, 230, 230), thickness=10)
# Display the annotated frame
cv2.imshow("YOLOv8 Tracking", annotated_frame)
# Break the loop if 'q' is pressed
if cv2.waitKey(1) & 0xFF == ord("q"):
break
else:
# Break the loop if the end of the video is reached
break
# Release the video capture object and close the display window
cap.release()
cv2.destroyAllWindows()
๋ฉํฐ ์ค๋ ๋ ์ถ์
๋ฉํฐ์ค๋ ๋ ์ถ์ ์ ์ฌ๋ฌ ๋น๋์ค ์คํธ๋ฆผ์์ ๋์์ ๊ฐ์ฒด ์ถ์ ์ ์คํํ ์ ์๋ ๊ธฐ๋ฅ์ ์ ๊ณตํฉ๋๋ค. ์ด ๊ธฐ๋ฅ์ ์ฌ๋ฌ ๋์ ๊ฐ์ ์นด๋ฉ๋ผ์์ ์ฌ๋ฌ ๊ฐ์ ๋น๋์ค ์ ๋ ฅ์ ์ฒ๋ฆฌํ ๋ ํนํ ์ ์ฉํ๋ฉฐ, ๋์ ์ฒ๋ฆฌ๋ฅผ ํตํด ํจ์จ์ฑ๊ณผ ์ฑ๋ฅ์ ํฌ๊ฒ ํฅ์์ํฌ ์ ์์ต๋๋ค.
์ ๊ณต๋ Python ์คํฌ๋ฆฝํธ์์ Python ์ threading
๋ชจ๋์ ์ฌ์ฉํ์ฌ ํธ๋์ปค์ ์ฌ๋ฌ ์ธ์คํด์ค๋ฅผ ๋์์ ์คํํ ์ ์์ต๋๋ค. ๊ฐ ์ค๋ ๋๋ ํ๋์ ๋์์ ํ์ผ์์ ํธ๋์ปค๋ฅผ ์คํํ๋ฉฐ, ๋ชจ๋ ์ค๋ ๋๋ ๋ฐฑ๊ทธ๋ผ์ด๋์์ ๋์์ ์คํ๋ฉ๋๋ค.
๊ฐ ์ค๋ ๋๊ฐ ์ฌ๋ฐ๋ฅธ ๋งค๊ฐ๋ณ์(๋น๋์ค ํ์ผ, ์ฌ์ฉํ ๋ชจ๋ธ ๋ฐ ํ์ผ ์ธ๋ฑ์ค)๋ฅผ ์์ ํ๋๋ก ํ๊ธฐ ์ํด ๋ค์๊ณผ ๊ฐ์ด ํจ์๋ฅผ ์ ์ํฉ๋๋ค. run_tracker_in_thread
์ด ๋งค๊ฐ๋ณ์๋ฅผ ํ์ฉํ๊ณ ๊ธฐ๋ณธ ์ถ์ ๋ฃจํ๋ฅผ ํฌํจํ๋ ํจ์์
๋๋ค. ์ด ํจ์๋ ๋น๋์ค๋ฅผ ํ๋ ์ ๋จ์๋ก ์ฝ๊ณ ํธ๋์ปค๋ฅผ ์คํํ์ฌ ๊ฒฐ๊ณผ๋ฅผ ํ์ํฉ๋๋ค.
์ด ์์์๋ ๋ ๊ฐ์ง ๋ค๋ฅธ ๋ชจ๋ธ์ด ์ฌ์ฉ๋ฉ๋๋ค: yolov8n.pt
๊ทธ๋ฆฌ๊ณ yolov8n-seg.pt
๋ฅผ ์ฌ์ฉํ์ฌ ๊ฐ๊ฐ ๋ค๋ฅธ ๋น๋์ค ํ์ผ์์ ๊ฐ์ฒด๋ฅผ ์ถ์ ํ ์ ์์ต๋๋ค. ๋น๋์ค ํ์ผ์ video_file1
๊ทธ๋ฆฌ๊ณ video_file2
.
๊ทธ๋ฆฌ๊ณ daemon=True
๋งค๊ฐ๋ณ์์ threading.Thread
๋ ๋ฉ์ธ ํ๋ก๊ทธ๋จ์ด ์๋ฃ๋๋ ์ฆ์ ์ด๋ฌํ ์ค๋ ๋๊ฐ ๋ซํ๋ค๋ ์๋ฏธ์
๋๋ค. ๊ทธ๋ฐ ๋ค์ ๋ค์๊ณผ ๊ฐ์ด ์ค๋ ๋๋ฅผ ์์ํฉ๋๋ค. start()
๋ฐ ์ฌ์ฉ join()
๋ฅผ ์ค์ ํ์ฌ ๋ ํธ๋์ปค ์ค๋ ๋๊ฐ ๋ชจ๋ ์๋ฃ๋ ๋๊น์ง ๋ฉ์ธ ์ค๋ ๋๊ฐ ๋๊ธฐํ๋๋ก ํฉ๋๋ค.
๋ง์ง๋ง์ผ๋ก ๋ชจ๋ ์ค๋ ๋๊ฐ ์์
์ ์๋ฃํ๋ฉด ๊ฒฐ๊ณผ๋ฅผ ํ์ํ๋ ์ฐฝ์ด ๋ค์์ ์ฌ์ฉํ์ฌ ๋ซํ๋๋ค. cv2.destroyAllWindows()
.
์ถ์ ๊ธฐ๋ฅ์ด ์๋ ํฌ-๋ฃจํ ์คํธ๋ฆฌ๋ฐ
import threading
import cv2
from ultralytics import YOLO
def run_tracker_in_thread(filename, model, file_index):
"""
Runs a video file or webcam stream concurrently with the YOLOv8 model using threading.
This function captures video frames from a given file or camera source and utilizes the YOLOv8 model for object
tracking. The function runs in its own thread for concurrent processing.
Args:
filename (str): The path to the video file or the identifier for the webcam/external camera source.
model (obj): The YOLOv8 model object.
file_index (int): An index to uniquely identify the file being processed, used for display purposes.
Note:
Press 'q' to quit the video display window.
"""
video = cv2.VideoCapture(filename) # Read the video file
while True:
ret, frame = video.read() # Read the video frames
# Exit the loop if no more frames in either video
if not ret:
break
# Track objects in frames if available
results = model.track(frame, persist=True)
res_plotted = results[0].plot()
cv2.imshow(f"Tracking_Stream_{file_index}", res_plotted)
key = cv2.waitKey(1)
if key == ord("q"):
break
# Release video sources
video.release()
# Load the models
model1 = YOLO("yolov8n.pt")
model2 = YOLO("yolov8n-seg.pt")
# Define the video files for the trackers
video_file1 = "path/to/video1.mp4" # Path to video file, 0 for webcam
video_file2 = 0 # Path to video file, 0 for webcam, 1 for external camera
# Create the tracker threads
tracker_thread1 = threading.Thread(target=run_tracker_in_thread, args=(video_file1, model1, 1), daemon=True)
tracker_thread2 = threading.Thread(target=run_tracker_in_thread, args=(video_file2, model2, 2), daemon=True)
# Start the tracker threads
tracker_thread1.start()
tracker_thread2.start()
# Wait for the tracker threads to finish
tracker_thread1.join()
tracker_thread2.join()
# Clean up and close windows
cv2.destroyAllWindows()
์ด ์์ ๋ ๋ ๋ง์ ์ค๋ ๋๋ฅผ ์์ฑํ๊ณ ๋์ผํ ๋ฐฉ๋ฒ๋ก ์ ์ ์ฉํ์ฌ ๋ ๋ง์ ๋น๋์ค ํ์ผ๊ณผ ๋ชจ๋ธ์ ์ฒ๋ฆฌํ๋๋ก ์ฝ๊ฒ ํ์ฅํ ์ ์์ต๋๋ค.
์๋ก์ด ํธ๋์ปค ๊ธฐ์ฌํ๊ธฐ
๋ค์ค ๊ฐ์ฒด ์ถ์ ์ ๋ฅ์ํ๊ณ ์ถ์ ์๊ณ ๋ฆฌ์ฆ์ ์ฑ๊ณต์ ์ผ๋ก ๊ตฌํํ๊ฑฐ๋ ์ ์ฉํ๋์ Ultralytics YOLO ? ultralytics /cfg/trackers์ ํธ๋์ปค ์น์ ์ ๊ธฐ์ฌํด ์ฃผ์ธ์! ์ฌ๋ฌ๋ถ์ ์ค์ ์ ํ๋ฆฌ์ผ์ด์ ๊ณผ ์๋ฃจ์ ์ ์ถ์ ์์ ์ ์ํํ๋ ์ฌ์ฉ์์๊ฒ ๋งค์ฐ ์ ์ฉํ ์ ์์ต๋๋ค.
์ด ์น์ ์ ๊ธฐ์ฌํจ์ผ๋ก์จ Ultralytics YOLO ํ๋ ์์ํฌ ๋ด์์ ์ฌ์ฉํ ์ ์๋ ์ถ์ ์๋ฃจ์ ์ ๋ฒ์๋ฅผ ํ์ฅํ์ฌ ์ปค๋ฎค๋ํฐ์ ๋ ๋ค๋ฅธ ๊ธฐ๋ฅ๊ณผ ์ ํธ๋ฆฌํฐ๋ฅผ ์ถ๊ฐํ๋ ๋ฐ ๋์์ ์ฃผ์ค ์ ์์ต๋๋ค.
๊ธฐ์ฌ๋ฅผ ์์ํ๋ ค๋ฉด ํ ๋ฆฌํ์คํธ(PR) ์ ์ถ์ ๋ํ ์ข ํฉ์ ์ธ ์ง์นจ์ด ๋ด๊ธด ๊ธฐ์ฌ ๊ฐ์ด๋๋ฅผ ์ฐธ์กฐํ์ธ์(๐ ๏ธ). ์ฌ๋ฌ๋ถ์ ์๊ฒฌ์ ๊ธฐ๋ค๋ฆฌ๊ฒ ์ต๋๋ค!
ํจ๊ป Ultralytics YOLO ์์ฝ์์คํ ์ ์ถ์ ๊ธฐ๋ฅ์ ๊ฐํํด ๋ด ์๋ค ๐!
์์ฃผ ๋ฌป๋ ์ง๋ฌธ
๋ค์ค ๊ฐ์ฒด ์ถ์ ์ด๋ ๋ฌด์์ด๋ฉฐ Ultralytics YOLO ์ด๋ป๊ฒ ์ง์ํ๋์?
๋น๋์ค ๋ถ์์์ ๋ค์ค ๊ฐ์ฒด ์ถ์ ์๋ ๊ฐ์ฒด๋ฅผ ์๋ณํ๊ณ ๋น๋์ค ํ๋ ์์์ ๊ฐ์ง๋ ๊ฐ ๊ฐ์ฒด์ ๊ณ ์ ID๋ฅผ ์ ์งํ๋ ๊ฒ์ด ๋ชจ๋ ํฌํจ๋ฉ๋๋ค. Ultralytics YOLO ๊ฐ์ฒด ID์ ํจ๊ป ์ค์๊ฐ ์ถ์ ์ ์ ๊ณตํ์ฌ ๋ณด์ ๊ฐ์ ๋ฐ ์คํฌ์ธ ๋ถ์๊ณผ ๊ฐ์ ์์ ์ ์ฉ์ดํ๊ฒ ์ง์ํฉ๋๋ค. ์ด ์์คํ ์ YAML ํ์ผ์ ํตํด ๊ตฌ์ฑํ ์ ์๋ BoT-SORT ๋ฐ ByteTrack๊ณผ ๊ฐ์ ํธ๋์ปค๋ฅผ ์ฌ์ฉํฉ๋๋ค.
Ultralytics YOLO ์ ๋ํ ์ฌ์ฉ์ ์ง์ ํธ๋์ปค๋ฅผ ๊ตฌ์ฑํ๋ ค๋ฉด ์ด๋ป๊ฒ ํ๋์?
๊ธฐ์กด ํธ๋์ปค ๊ตฌ์ฑ ํ์ผ์ ๋ณต์ฌํ์ฌ ์ฌ์ฉ์ ์ง์ ํธ๋์ปค๋ฅผ ๊ตฌ์ฑํ ์ ์์ต๋๋ค(์, custom_tracker.yaml
)์์ Ultralytics ํธ๋์ปค ๊ตฌ์ฑ ๋๋ ํ ๋ฆฌ ๋ก ์ค์ ํ๊ณ ํ์์ ๋ฐ๋ผ ๋งค๊ฐ๋ณ์๋ฅผ ์์ ํฉ๋๋ค. tracker_type
. ์ถ์ ๋ชจ๋ธ์์ ์ด ํ์ผ์ ๋ค์๊ณผ ๊ฐ์ด ์ฌ์ฉํ์ธ์:
์
์ฌ๋ฌ ๋น๋์ค ์คํธ๋ฆผ์์ ๋์์ ์ค๋ธ์ ํธ ์ถ์ ์ ์คํํ๋ ค๋ฉด ์ด๋ป๊ฒ ํด์ผ ํ๋์?
์ฌ๋ฌ ๋น๋์ค ์คํธ๋ฆผ์์ ์ค๋ธ์ ํธ ์ถ์ ์ ๋์์ ์คํํ๋ ค๋ฉด Python ์ threading
๋ชจ๋์ ์ฌ์ฉํฉ๋๋ค. ๊ฐ ์ค๋ ๋๋ ๋ณ๋์ ๋์์ ์คํธ๋ฆผ์ ์ฒ๋ฆฌํฉ๋๋ค. ๋ค์์ ์ด๋ฅผ ์ค์ ํ๋ ๋ฐฉ๋ฒ์ ๋ํ ์์์
๋๋ค:
๋ฉํฐ ์ค๋ ๋ ์ถ์
import threading
import cv2
from ultralytics import YOLO
def run_tracker_in_thread(filename, model, file_index):
video = cv2.VideoCapture(filename)
while True:
ret, frame = video.read()
if not ret:
break
results = model.track(frame, persist=True)
res_plotted = results[0].plot()
cv2.imshow(f"Tracking_Stream_{file_index}", res_plotted)
if cv2.waitKey(1) & 0xFF == ord("q"):
break
video.release()
model1 = YOLO("yolov8n.pt")
model2 = YOLO("yolov8n-seg.pt")
video_file1 = "path/to/video1.mp4"
video_file2 = 0 # Path to a second video file, or 0 for a webcam
tracker_thread1 = threading.Thread(target=run_tracker_in_thread, args=(video_file1, model1, 1), daemon=True)
tracker_thread2 = threading.Thread(target=run_tracker_in_thread, args=(video_file2, model2, 2), daemon=True)
tracker_thread1.start()
tracker_thread2.start()
tracker_thread1.join()
tracker_thread2.join()
cv2.destroyAllWindows()
๋ค์ค ๊ฐ์ฒด ์ถ์ ์ ์ค์ ์์ฉ ๋ถ์ผ๋ ๋ฌด์์ ๋๊น Ultralytics YOLO ?
๋ค์ค ๊ฐ์ฒด ์ถ์ ( Ultralytics YOLO )์ ๋ค์๊ณผ ๊ฐ์ ๋ค์ํ ์ ํ๋ฆฌ์ผ์ด์ ์ ์ง์ํฉ๋๋ค:
- ๊ตํต: ๊ตํต ๊ด๋ฆฌ ๋ฐ ์์จ ์ฃผํ์ ์ํ ์ฐจ๋ ์ถ์ .
- ๋ฆฌํ ์ผ: ๋งค์ฅ ๋ด ๋ถ์ ๋ฐ ๋ณด์์ ์ํ ์ฌ๋ ์ถ์ .
- ์์์ : ์์ค ํ๊ฒฝ ๋ชจ๋ํฐ๋ง์ ์ํ ๋ฌผ๊ณ ๊ธฐ ์ถ์ .
์ด๋ฌํ ์ ํ๋ฆฌ์ผ์ด์ ์ ๊ณ ํ๋ ์๋ฅ ๋์์์ ์ค์๊ฐ์ผ๋ก ์ฒ๋ฆฌํ๋ Ultralytics YOLO ์ ๊ธฐ๋ฅ์ ํ์ฉํ ์ ์์ต๋๋ค.
Ultralytics YOLO ์ ์ฌ์ฉํ์ฌ ์ฌ๋ฌ ๋น๋์ค ํ๋ ์์ ๊ฑธ์ณ ์ค๋ธ์ ํธ ํธ๋์ ์๊ฐํํ๋ ค๋ฉด ์ด๋ป๊ฒ ํด์ผ ํ๋์?
์ฌ๋ฌ ๋น๋์ค ํ๋ ์์ ๊ฑธ์ณ ์ค๋ธ์ ํธ ํธ๋์ ์๊ฐํํ๋ ค๋ฉด YOLO ๋ชจ๋ธ์ ์ถ์ ๊ธฐ๋ฅ์ OpenCV์ ํจ๊ป ์ฌ์ฉํ์ฌ ๊ฐ์ง๋ ์ค๋ธ์ ํธ์ ๊ฒฝ๋ก๋ฅผ ๊ทธ๋ฆด ์ ์์ต๋๋ค. ๋ค์์ ์ด๋ฅผ ๋ณด์ฌ์ฃผ๋ ์คํฌ๋ฆฝํธ ์์์ ๋๋ค:
์ฌ๋ฌ ๋น๋์ค ํ๋ ์์ ๊ฑธ์ณ ํธ๋ ํ๋กํ ํ๊ธฐ
from collections import defaultdict
import cv2
import numpy as np
from ultralytics import YOLO
model = YOLO("yolov8n.pt")
video_path = "path/to/video.mp4"
cap = cv2.VideoCapture(video_path)
track_history = defaultdict(lambda: [])
while cap.isOpened():
success, frame = cap.read()
if success:
results = model.track(frame, persist=True)
boxes = results[0].boxes.xywh.cpu()
track_ids = results[0].boxes.id.int().cpu().tolist()
annotated_frame = results[0].plot()
for box, track_id in zip(boxes, track_ids):
x, y, w, h = box
track = track_history[track_id]
track.append((float(x), float(y)))
if len(track) > 30:
track.pop(0)
points = np.hstack(track).astype(np.int32).reshape((-1, 1, 2))
cv2.polylines(annotated_frame, [points], isClosed=False, color=(230, 230, 230), thickness=10)
cv2.imshow("YOLOv8 Tracking", annotated_frame)
if cv2.waitKey(1) & 0xFF == ord("q"):
break
else:
break
cap.release()
cv2.destroyAllWindows()
์ด ์คํฌ๋ฆฝํธ๋ ์ถ์ ๋ ๊ฐ์ฒด์ ์๊ฐ ๊ฒฝ๊ณผ์ ๋ฐ๋ฅธ ์ด๋ ๊ฒฝ๋ก๋ฅผ ๋ณด์ฌ์ฃผ๋ ์ถ์ ์ ์ ํ์ํฉ๋๋ค.