| 영어 | 한국어 | 중국어 | 일본어 |
튜토리얼: 객체 탐지
교통 모니터링
불법 노상 주차를 감지하고 차량이 허용된 시간보다 오래 주차되어 있을 경우 VMS 서버에 알립니다.
# vmspy 설치
# - 시스템의 Python 버전에 맞는 vmspy 패키지를 다운로드합니다
!unzip vmspy.zip
!./vmspy/install-vmspy-collab.sh
# YOLO 설치 (Ultralytics)
%pip install ultralytics
import ultralytics
from ultralytics import YOLO
# YOLO 모델 로드 (경량 버전)
model = YOLO('yolo11n.pt')
# 필요한 모듈 import
from tarfile import NUL # null 반환값으로 사용 (일반적으로는 None 사용을 권장)
import cv2
import time
from shapely.geometry import Point
from shapely.geometry.polygon import Polygon
# 입력 프레임 해상도 (정규화에 사용)
input_width = 640
input_height = 640
# live_video 객체 설정 (VMS 스트리밍 인터페이스)
live_video = vmspy.live_video()
live_video.set_keyframe_only(True) # 성능 최적화를 위해 키프레임만 사용
live_video.set_image_size(input_width, input_height)
live_video.set_pixel_format("BGR") # OpenCV는 BGR 포맷 사용
live_video.init("url.to.vmsserver", 3300, "admin", "admin")
# 모니터링 영역 정의 (정규화 좌표: 0.0 ~ 1.0)
# 이 영역은 VMS 서버에도 시각적으로 표시됩니다
monitoring_zone_points = [
(0.3380152329749104, 0.3314180107526881),
(0.42672491039426524, 0.3404905913978495),
(0.41261200716845886, 0.9241599462365592),
(0.1323700716845878, 0.9060147849462368)
]
monitoring_zone = Polygon(monitoring_zone_points)
# VMS 화면에 모니터링 영역 표시
live_video.draw_polygon(monitoring_zone_points, border_color="purple", border_thickness=5)
# VMS에서 탐지 결과 표시 설정
live_video.set_detection_class(model.names)
live_video.set_detection_box(border_color="blue", border_thickness=5)
live_video.set_detection_caption(
show_object_id=True,
show_class_name=True,
show_confidence=False
)
# 설정 값 (초 단위)
config = {
"parking_violation_sec": 10, # 주차 위반으로 판단하는 시간 기준
"periodic_check_sec": 10, # 반복 보고 간격
"remove_criteria_sec": 10 # 비활성 객체 제거 기준 시간
}
# 객체 추적 및 이벤트 발생을 위한 간단한 추적 로직
class TrackingHistory():
def __init__(self):
self.history = {}
def update(self, key, frame_info):
"""
주어진 객체(track_id)의 추적 정보를 업데이트합니다.
보고 조건이 만족되면 최초 frame_info를 반환합니다.
"""
timestamp = frame_info["timestamp"]
if key in self.history:
track_item = self.history[key]
track_item["timestamp_last"] = timestamp
# 재보고 시점 확인
if timestamp > track_item["timestamp_report"]:
track_item["timestamp_report"] = timestamp + config["periodic_check_sec"]
print(f"{key}: REPORTED / n={len(self.history)}")
return track_item["frameinfo0"]
else:
# 처음 감지된 객체
self.history[key] = {
"frameinfo0": frame_info.copy(), # 최초 프레임 정보 저장
"timestamp_first": timestamp,
"timestamp_last": timestamp,
"timestamp_report": timestamp + config["parking_violation_sec"]
}
print(f"{key}: CREATED / n={len(self.history)}")
return NUL # 보고할 이벤트 없음
def remove_old_items(self, frame_info):
"""
최근 업데이트되지 않은 객체 제거
"""
current_timestamp = frame_info["timestamp"]
min_sec = config["remove_criteria_sec"]
keys_to_remove = [
key for key, value in self.history.items()
if current_timestamp - value["timestamp_last"] > min_sec
]
for key in keys_to_remove:
sec = current_timestamp - self.history[key]["timestamp_first"]
del self.history[key]
print(f"{key}: REMOVED ({sec}sec) / n={len(self.history)}")
return len(keys_to_remove)
tracking = TrackingHistory()
# 채널에서 라이브 영상 시작
ch_no = 1
live_video.start(ch_no)
count = 0
while count < 10000:
count += 1
# 프레임 및 메타데이터 가져오기
(frame_image, frame_info) = live_video.get_frame()
# 종료 조건: 더 이상 프레임 없음
if frame_image.size == 0 and count > 2:
print("\nEnd of stream")
break
# 객체 탐지 / 추적 수행
timestamp_detect_start = time.time_ns()
results = model.track(frame_image, persist=True, verbose=False)
# 대안: results = model.predict(frame_image, verbose=False)
time_detect_elapsed = (time.time_ns() - timestamp_detect_start) / 1_000_000_000
# 탐지 결과 처리
for box in results[0].boxes:
# 트래킹 ID 추출
if box.id is not None:
track_id = int(box.id[0].item())
else:
continue # 트래킹 ID 없는 객체는 무시
# 바운딩 박스를 정규화 좌표로 변환
xyxy = box.xyxy[0].tolist()
x = xyxy[0] / input_width
y = xyxy[1] / input_height
w = (xyxy[2] - xyxy[0]) / input_width
h = (xyxy[3] - xyxy[1]) / input_height
class_id = int(box.cls[0].item())
conf = box.conf[0].item()
# 객체 중심이 모니터링 영역 내부인지 확인
if monitoring_zone.contains(Point(x + w / 2, y + h / 2)):
name = model.names[class_id]
# VMS로 탐지 정보 전송
live_video.input_detection(
x, y, w, h,
class_id=class_id,
object_id=track_id,
confidence=conf
)
# 추적 상태 업데이트
frame_info0 = tracking.update(track_id, frame_info)
# 위반 조건 만족 시 이벤트 보고
if frame_info0 != NUL:
duration = float(frame_info["timestamp"] - frame_info0["timestamp"])
print(f"duration: {duration}")
live_video.report_event(
frame_info0,
x, y, w, h,
duration=duration,
event_type_id=0,
class_id=class_id,
object_id=track_id
)
# 오래된 추적 객체 정리
tracking.remove_old_items(frame_info)
# 모든 탐지 결과를 VMS로 전송
live_video.send_detections(frame_info)


