Ver3.0 ๐ฏ OpenCV๋ก ์์ํ๋ ๊ฐ์ฒด ์ถ์ ์๋ฒฝ ๊ฐ์ด๋: ์ค์ ์์ค์ฝ๋์ ํจ๊ป

๐ฏ OpenCV๋ก ์์ํ๋ ๊ฐ์ฒด ์ถ์ ์๋ฒฝ ๊ฐ์ด๋: ์ค์ ์์ค์ฝ๋์ ํจ๊ป
์ด๋ณด์๋ ๋ฐ๋ผํ ์ ์๋ ์ค์ ์์ ๋ก ๋ฐฐ์ฐ๋ ๊ฐ์ฒด ์ถ์ ๊ธฐ์ ๐ป
๐ ์๋
! ์ค๋์ ์ปดํจํฐ ๋น์ ์ ๊ฝ์ด๋ผ๊ณ ํ ์ ์๋ ๊ฐ์ฒด ์ถ์ (Object Tracking)์ ๋ํด ์ด์ผ๊ธฐํด๋ณผ๊ฒ. ์ํ์์ ๋ณด๋ ๊ทธ ๋ฉ์ง ์ถ์ ๊ธฐ์ , ์ฌ์ค ์ฐ๋ฆฌ๋ OpenCV๋ก ์ถฉ๋ถํ ๊ตฌํํ ์ ์์ด! ๐
์ด ๊ธ์์๋ ์ค์ ๋ก ๋์ํ๋ ์์ค์ฝ๋์ ํจ๊ป ๊ฐ์ฒด ์ถ์ ์ ์๋ฆฌ๋ถํฐ ์ค์ ํ์ฉ๊น์ง ๋ชจ๋ ๊ฑธ ๋ค๋ค๋ณผ ๊ฑฐ์ผ. ํ๋ก๊ทธ๋๋ฐ์ด ์ฒ์์ด๋ผ๋ ๊ฑฑ์ ๋ง! ์น๊ตฌํํ
์ค๋ช
ํ๋ฏ์ด ์ฝ๊ฒ ํ์ด์ ์๋ ค์ค๊ฒ. ๐
๐ฌ ๊ฐ์ฒด ์ถ์ ์ด ๋ญ๊ธธ๋?
๊ฐ์ฒด ์ถ์ ์ ๋ง ๊ทธ๋๋ก ์์ ์์์ ํน์ ๋ฌผ์ฒด๋ฅผ ๊ณ์ ๋ฐ๋ผ๊ฐ๋ ๊ธฐ์ ์ด์ผ. ์๊ฐํด๋ด, ์ ํ๋ธ์์ ์คํฌ์ธ ๊ฒฝ๊ธฐ ๋ณผ ๋ ๊ณต์ด๋ ์ ์๋ฅผ ์๋์ผ๋ก ๋ฐ๋ผ๊ฐ๋ ์นด๋ฉ๋ผ ์์์? ๋ฐ๋ก ๊ทธ๊ฒ ๊ฐ์ฒด ์ถ์ ๊ธฐ์ ์ด์ผ! ๐พ
์ผ๋ฐ์ ์ธ ๊ฐ์ฒด ๊ฒ์ถ(Object Detection)์ ๋งค ํ๋ ์๋ง๋ค "์ด๊ฒ ๋ญ์ง?"๋ฅผ ์๋ก ํ๋จํ๋ ๊ฑฐ๋ผ๋ฉด, ๊ฐ์ฒด ์ถ์ ์ "์, ์ ๊ฑฐ ์๊น ๊ทธ๊ฑฐ๋ค!"ํ๊ณ ์ฐ์์ฑ์ ์ ์งํ๋ฉด์ ๋ฐ๋ผ๊ฐ๋ ๊ฑฐ์ง. ํจ์ฌ ํจ์จ์ ์ด๊ณ ๋น ๋ฅด์ง! โก
๐ ๏ธ OpenCV ์ค์น๋ถํฐ ์์ํ์!
๋ณธ๊ฒฉ์ ์ผ๋ก ์ฝ๋ฉํ๊ธฐ ์ ์ OpenCV๋ถํฐ ์ค์นํด์ผ๊ฒ ์ง? Python ํ๊ฒฝ์์ ์งํํ ๊ฑด๋ฐ, ์ ๋ง ๊ฐ๋จํด! ๐
# Python 3.7 ์ด์ ๊ถ์ฅ
pip install opencv-python
pip install opencv-contrib-python
pip install numpy
# ์ ํ์ฌํญ (์์ ์ฒ๋ฆฌ ์ฑ๋ฅ ํฅ์)
pip install imutils
์ค์น๊ฐ ์ ๋๋์ง ํ์ธํด๋ณผ๊น?
import cv2
print(cv2.__version__)
# 4.5.0 ์ด์์ด๋ฉด OK!
๐ฏ OpenCV์ ์ฃผ์ ์ถ์ ์๊ณ ๋ฆฌ์ฆ๋ค
OpenCV๋ ์ฌ๋ฌ ๊ฐ์ง ์ถ์ ์๊ณ ๋ฆฌ์ฆ์ ์ ๊ณตํ๋๋ฐ, ๊ฐ๊ฐ ์ฅ๋จ์ ์ด ์์ด. ์ํฉ์ ๋ง๊ฒ ๊ณจ๋ผ ์ฐ๋ฉด ๋ผ! ๐จ
| ์๊ณ ๋ฆฌ์ฆ | ์๋ | ์ ํ๋ | ํน์ง |
|---|---|---|---|
| BOOSTING | ๋๋ฆผ | ๋ณดํต | ๊ฐ์ฅ ์ค๋๋ ๋ฐฉ์, ์์ ์ |
| MIL | ๋ณดํต | ๋ณดํต | ๋ถ๋ถ ๊ฐ๋ฆผ์ ๊ฐํจ |
| KCF | ๋น ๋ฆ | ์ข์ | ๊ฐ์ฅ ๋ง์ด ์ฌ์ฉ, ๊ท ํ์กํ |
| CSRT | ๋๋ฆผ | ๋งค์ฐ ์ข์ | ์ ํ๋ ์ต๊ณ , ๊ฒฝ๊ณ ์ ๋ฐ |
| MedianFlow | ๋น ๋ฆ | ๋ณดํต | ์์ธก ๊ฐ๋ฅํ ์์ง์์ ์ ํฉ |
| MOSSE | ๋งค์ฐ ๋น ๋ฆ | ๋ฎ์ | ์ค์๊ฐ ์ฒ๋ฆฌ์ ์ต์ |
| TLD | ๋ณดํต | ์ข์ | ๊ฐ๋ฆผ ํ ์ฌํ์ง ๊ฐ๋ฅ |
๐ ์ฒซ ๋ฒ์งธ ์์ : ๋จ์ผ ๊ฐ์ฒด ์ถ์ ๊ธฐ๋ณธ
์, ์ด์ ์ง์ง ์ฝ๋ฉ ์์์ด์ผ! ๊ฐ์ฅ ๊ธฐ๋ณธ์ ์ธ ๋จ์ผ ๊ฐ์ฒด ์ถ์ ๋ถํฐ ํด๋ณด์. ์น์บ ์ผ๋ก ์ค์๊ฐ ์ถ์ ํ๋ ์ฝ๋์ผ! ๐น
import cv2
import sys
# ์ถ์ ๊ธฐ ์์ฑ ํจ์
def create_tracker(tracker_type):
"""
์ํ๋ ์ถ์ ์๊ณ ๋ฆฌ์ฆ์ ์ ํํ๋ ํจ์
"""
if tracker_type == 'BOOSTING':
tracker = cv2.legacy.TrackerBoosting_create()
elif tracker_type == 'MIL':
tracker = cv2.legacy.TrackerMIL_create()
elif tracker_type == 'KCF':
tracker = cv2.TrackerKCF_create()
elif tracker_type == 'CSRT':
tracker = cv2.TrackerCSRT_create()
elif tracker_type == 'MedianFlow':
tracker = cv2.legacy.TrackerMedianFlow_create()
elif tracker_type == 'MOSSE':
tracker = cv2.legacy.TrackerMOSSE_create()
elif tracker_type == 'TLD':
tracker = cv2.legacy.TrackerTLD_create()
else:
tracker = None
print('์๋ชป๋ ์ถ์ ๊ธฐ ์ด๋ฆ์
๋๋ค!')
return tracker
# ๋ฉ์ธ ์คํ ์ฝ๋
def main():
# ์ถ์ ์๊ณ ๋ฆฌ์ฆ ์ ํ (KCF ์ถ์ฒ!)
tracker_type = 'KCF'
# ๋น๋์ค ์บก์ฒ ๊ฐ์ฒด ์์ฑ (0์ ๊ธฐ๋ณธ ์น์บ )
video = cv2.VideoCapture(0)
# ์น์บ ์ด ์ ๋๋ก ์ด๋ ธ๋์ง ํ์ธ
if not video.isOpened():
print("์น์บ ์ ์ด ์ ์์ต๋๋ค!")
sys.exit()
# ์ฒซ ํ๋ ์ ์ฝ๊ธฐ
ok, frame = video.read()
if not ok:
print('ํ๋ ์์ ์ฝ์ ์ ์์ต๋๋ค!')
sys.exit()
# ์ถ์ ํ ๊ฐ์ฒด ์์ญ ์ ํ (๋ง์ฐ์ค๋ก ๋๋๊ทธ)
bbox = cv2.selectROI("๊ฐ์ฒด ์ ํ", frame, False)
print(f"์ ํ๋ ์์ญ: {bbox}")
# ์ถ์ ๊ธฐ ์ด๊ธฐํ
tracker = create_tracker(tracker_type)
ok = tracker.init(frame, bbox)
print("์ถ์ ์์! ESC๋ฅผ ๋๋ฅด๋ฉด ์ข
๋ฃ๋ฉ๋๋ค.")
# ๋ฉ์ธ ๋ฃจํ
while True:
# ํ๋ ์ ์ฝ๊ธฐ
ok, frame = video.read()
if not ok:
break
# ์ถ์ ์
๋ฐ์ดํธ
ok, bbox = tracker.update(frame)
# ์ถ์ ์ฑ๊ณต ์ฌ๋ถ์ ๋ฐ๋ผ ํ์
if ok:
# ์ถ์ ์ฑ๊ณต - ์ด๋ก์ ๋ฐ์ค
p1 = (int(bbox[0]), int(bbox[1]))
p2 = (int(bbox[0] + bbox[2]), int(bbox[1] + bbox[3]))
cv2.rectangle(frame, p1, p2, (0, 255, 0), 2, 1)
# ์ํ ํ
์คํธ
cv2.putText(frame, "Tracking", (10, 30),
cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 255, 0), 2)
else:
# ์ถ์ ์คํจ - ๋นจ๊ฐ์ ๊ฒฝ๊ณ
cv2.putText(frame, "Tracking Failed!", (10, 30),
cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 0, 255), 2)
# ์ถ์ ๊ธฐ ์ ๋ณด ํ์
cv2.putText(frame, f"Tracker: {tracker_type}", (10, 60),
cv2.FONT_HERSHEY_SIMPLEX, 0.6, (255, 255, 255), 2)
# FPS ๊ณ์ฐ ๋ฐ ํ์ (์ ํ์ฌํญ)
cv2.putText(frame, "Press ESC to exit", (10, frame.shape[0] - 10),
cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 255, 255), 1)
# ํ๋ฉด ์ถ๋ ฅ
cv2.imshow("Object Tracking", frame)
# ESC ํค๋ก ์ข
๋ฃ
k = cv2.waitKey(1) & 0xff
if k == 27:
break
# ์ ๋ฆฌ
video.release()
cv2.destroyAllWindows()
print("์ถ์ ์ข
๋ฃ!")
if __name__ == '__main__':
main()
2๏ธโฃ cv2.selectROI(): ๋ง์ฐ์ค๋ก ๋๋๊ทธํด์ ์ถ์ ํ ์์ญ์ ์ ํํ๋ ํจ์. ์ ๋ง ์ง๊ด์ ์ด์ง?
3๏ธโฃ tracker.update(): ๋งค ํ๋ ์๋ง๋ค ๊ฐ์ฒด์ ์๋ก์ด ์์น๋ฅผ ๊ณ์ฐํด์ค. ๋ฐํ๊ฐ์ (์ฑ๊ณต์ฌ๋ถ, ๋ฐ์ด๋ฉ๋ฐ์ค)์ผ.
๐จ ๋ ๋ฒ์งธ ์์ : ๋น๋์ค ํ์ผ์์ ๊ฐ์ฒด ์ถ์
์น์บ ๋ง๊ณ ์ ์ฅ๋ ๋น๋์ค ํ์ผ์์๋ ์ถ์ ํ ์ ์์ด! ์ด๋ฒ์ ์ข ๋ ์ค์ฉ์ ์ธ ์์ ๋ฅผ ๋ง๋ค์ด๋ณผ๊ฒ. ๐ฅ
import cv2
import time
def track_video_file(video_path, tracker_type='CSRT'):
"""
๋น๋์ค ํ์ผ์์ ๊ฐ์ฒด๋ฅผ ์ถ์ ํ๋ ํจ์
Args:
video_path: ๋น๋์ค ํ์ผ ๊ฒฝ๋ก
tracker_type: ์ฌ์ฉํ ์ถ์ ์๊ณ ๋ฆฌ์ฆ
"""
# ๋น๋์ค ํ์ผ ์ด๊ธฐ
video = cv2.VideoCapture(video_path)
if not video.isOpened():
print(f"๋น๋์ค ํ์ผ์ ์ด ์ ์์ต๋๋ค: {video_path}")
return
# ๋น๋์ค ์ ๋ณด ๊ฐ์ ธ์ค๊ธฐ
fps = int(video.get(cv2.CAP_PROP_FPS))
width = int(video.get(cv2.CAP_PROP_FRAME_WIDTH))
height = int(video.get(cv2.CAP_PROP_FRAME_HEIGHT))
total_frames = int(video.get(cv2.CAP_PROP_FRAME_COUNT))
print(f"๋น๋์ค ์ ๋ณด:")
print(f" - ํด์๋: {width}x{height}")
print(f" - FPS: {fps}")
print(f" - ์ด ํ๋ ์: {total_frames}")
# ์ฒซ ํ๋ ์ ์ฝ๊ธฐ
ok, frame = video.read()
if not ok:
print("์ฒซ ํ๋ ์์ ์ฝ์ ์ ์์ต๋๋ค!")
return
# ์ถ์ ์์ญ ์ ํ
print("\n์ถ์ ํ ๊ฐ์ฒด๋ฅผ ๋ง์ฐ์ค๋ก ์ ํํ์ธ์!")
bbox = cv2.selectROI("๊ฐ์ฒด ์ ํ (SPACE: ํ์ธ, ESC: ์ทจ์)", frame, False)
cv2.destroyWindow("๊ฐ์ฒด ์ ํ (SPACE: ํ์ธ, ESC: ์ทจ์)")
# ์ถ์ ๊ธฐ ์์ฑ ๋ฐ ์ด๊ธฐํ
if tracker_type == 'KCF':
tracker = cv2.TrackerKCF_create()
elif tracker_type == 'CSRT':
tracker = cv2.TrackerCSRT_create()
elif tracker_type == 'MOSSE':
tracker = cv2.legacy.TrackerMOSSE_create()
else:
print(f"์ง์ํ์ง ์๋ ์ถ์ ๊ธฐ: {tracker_type}")
return
tracker.init(frame, bbox)
# ๊ฒฐ๊ณผ ์ ์ฅ์ ์ํ VideoWriter (์ ํ์ฌํญ)
output_path = 'tracked_output.mp4'
fourcc = cv2.VideoWriter_fourcc(*'mp4v')
out = cv2.VideoWriter(output_path, fourcc, fps, (width, height))
# ์ถ์ ํต๊ณ
frame_count = 0
success_count = 0
start_time = time.time()
print(f"\n์ถ์ ์์! (์๊ณ ๋ฆฌ์ฆ: {tracker_type})")
print("Q ํค๋ฅผ ๋๋ฅด๋ฉด ์ข
๋ฃ๋ฉ๋๋ค.\n")
# ๋ฉ์ธ ์ถ์ ๋ฃจํ
while True:
ok, frame = video.read()
if not ok:
break
frame_count += 1
# ์ถ์ ์
๋ฐ์ดํธ
timer = cv2.getTickCount()
ok, bbox = tracker.update(frame)
fps_current = cv2.getTickFrequency() / (cv2.getTickCount() - timer)
# ๊ฒฐ๊ณผ ๊ทธ๋ฆฌ๊ธฐ
if ok:
success_count += 1
# ์ถ์ ์ฑ๊ณต - ์ด๋ก์ ๋ฐ์ค
p1 = (int(bbox[0]), int(bbox[1]))
p2 = (int(bbox[0] + bbox[2]), int(bbox[1] + bbox[3]))
cv2.rectangle(frame, p1, p2, (0, 255, 0), 3)
# ์ค์ฌ์ ํ์
center_x = int(bbox[0] + bbox[2]/2)
center_y = int(bbox[1] + bbox[3]/2)
cv2.circle(frame, (center_x, center_y), 5, (0, 255, 0), -1)
# ๊ถค์ ๊ทธ๋ฆฌ๊ธฐ (์ ํ์ฌํญ)
cv2.putText(frame, "TRACKING", (p1[0], p1[1]-10),
cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 255, 0), 2)
else:
# ์ถ์ ์คํจ
cv2.putText(frame, "LOST", (50, 80),
cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 0, 255), 3)
# ์ ๋ณด ์ค๋ฒ๋ ์ด
info_text = [
f"Tracker: {tracker_type}",
f"Frame: {frame_count}/{total_frames}",
f"FPS: {int(fps_current)}",
f"Success Rate: {success_count/frame_count*100:.1f}%"
]
y_offset = 30
for i, text in enumerate(info_text):
cv2.putText(frame, text, (10, y_offset + i*30),
cv2.FONT_HERSHEY_SIMPLEX, 0.6, (255, 255, 255), 2)
# ์งํ๋ฅ ๋ฐ
progress = frame_count / total_frames
bar_width = int(width * 0.8)
bar_height = 20
bar_x = int(width * 0.1)
bar_y = height - 40
cv2.rectangle(frame, (bar_x, bar_y),
(bar_x + bar_width, bar_y + bar_height),
(50, 50, 50), -1)
cv2.rectangle(frame, (bar_x, bar_y),
(bar_x + int(bar_width * progress), bar_y + bar_height),
(0, 255, 0), -1)
# ํ๋ฉด ์ถ๋ ฅ
cv2.imshow("Video Tracking", frame)
# ๊ฒฐ๊ณผ ์ ์ฅ
out.write(frame)
# ํค ์
๋ ฅ ์ฒ๋ฆฌ
key = cv2.waitKey(1) & 0xFF
if key == ord('q') or key == ord('Q'):
print("\n์ฌ์ฉ์๊ฐ ์ข
๋ฃํ์ต๋๋ค.")
break
elif key == ord('p'): # ์ผ์์ ์ง
cv2.waitKey(-1)
# ์ข
๋ฃ ์ฒ๋ฆฌ
elapsed_time = time.time() - start_time
print(f"\n=== ์ถ์ ์๋ฃ ===")
print(f"์ด ์ฒ๋ฆฌ ์๊ฐ: {elapsed_time:.2f}์ด")
print(f"ํ๊ท FPS: {frame_count/elapsed_time:.2f}")
print(f"์ถ์ ์ฑ๊ณต๋ฅ : {success_count/frame_count*100:.1f}%")
print(f"๊ฒฐ๊ณผ ์ ์ฅ: {output_path}")
video.release()
out.release()
cv2.destroyAllWindows()
# ์คํ ์์
if __name__ == '__main__':
# ๋น๋์ค ํ์ผ ๊ฒฝ๋ก ์ง์
video_file = 'sample_video.mp4' # ์ฌ๊ธฐ์ ์ค์ ํ์ผ ๊ฒฝ๋ก ์
๋ ฅ
# CSRT๋ ์ ํ๋๊ฐ ๋์ง๋ง ๋๋ฆผ
# KCF๋ ์๋์ ์ ํ๋์ ๊ท ํ์ด ์ข์
# MOSSE๋ ๋งค์ฐ ๋น ๋ฅด์ง๋ง ์ ํ๋๋ ๋ฎ์
track_video_file(video_file, tracker_type='CSRT')
๐ฏ ์ธ ๋ฒ์งธ ์์ : ๋ค์ค ๊ฐ์ฒด ์ถ์ (Multi-Object Tracking)
ํ๋๋ง ์ถ์ ํ๋ ๊ฑด ์ฌ๋ฏธ์์ง! ์ฌ๋ฌ ๊ฐ๋ฅผ ๋์์ ์ถ์ ํด๋ณด์. ์ด๊ฒ ์ง์ง ์ค์ ์ด์ผ! ๐ช
import cv2
import numpy as np
class MultiObjectTracker:
"""
์ฌ๋ฌ ๊ฐ์ฒด๋ฅผ ๋์์ ์ถ์ ํ๋ ํด๋์ค
"""
def __init__(self, tracker_type='KCF'):
self.tracker_type = tracker_type
self.trackers = []
self.colors = []
self.object_ids = []
self.next_id = 1
def create_tracker(self):
"""์๋ก์ด ์ถ์ ๊ธฐ ์์ฑ"""
if self.tracker_type == 'KCF':
return cv2.TrackerKCF_create()
elif self.tracker_type == 'CSRT':
return cv2.TrackerCSRT_create()
elif self.tracker_type == 'MOSSE':
return cv2.legacy.TrackerMOSSE_create()
else:
return cv2.TrackerKCF_create()
def add_tracker(self, frame, bbox):
"""
์๋ก์ด ์ถ์ ๊ฐ์ฒด ์ถ๊ฐ
Args:
frame: ํ์ฌ ํ๋ ์
bbox: ์ถ์ ํ ์์ญ (x, y, w, h)
"""
tracker = self.create_tracker()
ok = tracker.init(frame, bbox)
if ok:
self.trackers.append(tracker)
# ๋๋ค ์์ ์์ฑ (๊ฐ ๊ฐ์ฒด๋ง๋ค ๋ค๋ฅธ ์)
color = tuple(np.random.randint(0, 255, 3).tolist())
self.colors.append(color)
self.object_ids.append(self.next_id)
self.next_id += 1
print(f"๊ฐ์ฒด #{self.object_ids[-1]} ์ถ๊ฐ๋จ!")
return True
return False
def update(self, frame):
"""
๋ชจ๋ ์ถ์ ๊ธฐ ์
๋ฐ์ดํธ
Returns:
์ฑ๊ณตํ ์ถ์ ๊ฒฐ๊ณผ ๋ฆฌ์คํธ
"""
results = []
for i in range(len(self.trackers)):
ok, bbox = self.trackers[i].update(frame)
if ok:
results.append({
'id': self.object_ids[i],
'bbox': bbox,
'color': self.colors[i],
'success': True
})
else:
results.append({
'id': self.object_ids[i],
'bbox': None,
'color': self.colors[i],
'success': False
})
return results
def remove_failed_trackers(self, results):
"""์คํจํ ์ถ์ ๊ธฐ ์ ๊ฑฐ"""
indices_to_remove = []
for i, result in enumerate(results):
if not result['success']:
indices_to_remove.append(i)
# ์ญ์์ผ๋ก ์ ๊ฑฐ (์ธ๋ฑ์ค ๊ผฌ์ ๋ฐฉ์ง)
for i in sorted(indices_to_remove, reverse=True):
print(f"๊ฐ์ฒด #{self.object_ids[i]} ์ถ์ ์คํจ๋ก ์ ๊ฑฐ๋จ")
del self.trackers[i]
del self.colors[i]
del self.object_ids[i]
def get_count(self):
"""ํ์ฌ ์ถ์ ์ค์ธ ๊ฐ์ฒด ์"""
return len(self.trackers)
def multi_object_tracking_demo():
"""
๋ค์ค ๊ฐ์ฒด ์ถ์ ๋ฐ๋ชจ
"""
# ์น์บ ์ด๊ธฐ
video = cv2.VideoCapture(0)
if not video.isOpened():
print("์น์บ ์ ์ด ์ ์์ต๋๋ค!")
return
# ๋ค์ค ์ถ์ ๊ธฐ ์ด๊ธฐํ
mot = MultiObjectTracker(tracker_type='KCF')
print("\n=== ๋ค์ค ๊ฐ์ฒด ์ถ์ ์์ ===")
print("์ฌ์ฉ๋ฒ:")
print(" S ํค: ์๋ก์ด ๊ฐ์ฒด ์ถ๊ฐ")
print(" D ํค: ์คํจํ ์ถ์ ๊ธฐ ์ ๊ฑฐ")
print(" C ํค: ๋ชจ๋ ์ถ์ ๊ธฐ ์ด๊ธฐํ")
print(" Q ํค: ์ข
๋ฃ")
print("=" * 40)
# ์ถ์ ๊ถค์ ์ ์ฅ (์ ํ์ฌํญ)
trajectories = {}
while True:
ok, frame = video.read()
if not ok:
break
# ๋ชจ๋ ์ถ์ ๊ธฐ ์
๋ฐ์ดํธ
if mot.get_count() > 0:
results = mot.update(frame)
# ๊ฒฐ๊ณผ ๊ทธ๋ฆฌ๊ธฐ
for result in results:
if result['success']:
bbox = result['bbox']
obj_id = result['id']
color = result['color']
# ๋ฐ์ด๋ฉ ๋ฐ์ค
p1 = (int(bbox[0]), int(bbox[1]))
p2 = (int(bbox[0] + bbox[2]), int(bbox[1] + bbox[3]))
cv2.rectangle(frame, p1, p2, color, 3)
# ๊ฐ์ฒด ID ํ์
label = f"ID: {obj_id}"
cv2.putText(frame, label, (p1[0], p1[1]-10),
cv2.FONT_HERSHEY_SIMPLEX, 0.6, color, 2)
# ์ค์ฌ์
center_x = int(bbox[0] + bbox[2]/2)
center_y = int(bbox[1] + bbox[3]/2)
cv2.circle(frame, (center_x, center_y), 4, color, -1)
# ๊ถค์ ์ ์ฅ
if obj_id not in trajectories:
trajectories[obj_id] = []
trajectories[obj_id].append((center_x, center_y))
# ๊ถค์ ๊ทธ๋ฆฌ๊ธฐ (์ต๊ทผ 30๊ฐ ์ )
if len(trajectories[obj_id]) > 1:
points = trajectories[obj_id][-30:]
for i in range(1, len(points)):
cv2.line(frame, points[i-1], points[i], color, 2)
# ์ ๋ณด ํจ๋
info_panel_height = 120
panel = np.zeros((info_panel_height, frame.shape[1], 3), dtype=np.uint8)
panel[:] = (40, 40, 40)
cv2.putText(panel, f"Tracking Objects: {mot.get_count()}",
(10, 30), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (255, 255, 255), 2)
cv2.putText(panel, "Press 'S' to add new object",
(10, 60), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (200, 200, 200), 1)
cv2.putText(panel, "Press 'D' to remove failed | 'C' to clear all | 'Q' to quit",
(10, 85), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (200, 200, 200), 1)
# ํจ๋๊ณผ ํ๋ ์ ํฉ์น๊ธฐ
display = np.vstack([panel, frame])
cv2.imshow("Multi-Object Tracking", display)
# ํค ์
๋ ฅ ์ฒ๋ฆฌ
key = cv2.waitKey(1) & 0xFF
if key == ord('s') or key == ord('S'):
# ์ ๊ฐ์ฒด ์ถ๊ฐ
print("\n์ถ์ ํ ๊ฐ์ฒด๋ฅผ ์ ํํ์ธ์!")
bbox = cv2.selectROI("๊ฐ์ฒด ์ ํ", frame, False)
cv2.destroyWindow("๊ฐ์ฒด ์ ํ")
if bbox[2] > 0 and bbox[3] > 0: # ์ ํจํ ์ ํ์ธ์ง ํ์ธ
mot.add_tracker(frame, bbox)
elif key == ord('d') or key == ord('D'):
# ์คํจํ ์ถ์ ๊ธฐ ์ ๊ฑฐ
if mot.get_count() > 0:
results = mot.update(frame)
mot.remove_failed_trackers(results)
elif key == ord('c') or key == ord('C'):
# ๋ชจ๋ ์ถ์ ๊ธฐ ์ด๊ธฐํ
mot = MultiObjectTracker(tracker_type='KCF')
trajectories = {}
print("\n๋ชจ๋ ์ถ์ ๊ธฐ๊ฐ ์ด๊ธฐํ๋์์ต๋๋ค!")
elif key == ord('q') or key == ord('Q'):
break
video.release()
cv2.destroyAllWindows()
print("\n์ถ์ ์ข
๋ฃ!")
if __name__ == '__main__':
multi_object_tracking_demo()
2๏ธโฃ ์์ ๊ตฌ๋ถ: ๋๋ค ์์์ผ๋ก ๊ฐ ๊ฐ์ฒด๋ฅผ ์๊ฐ์ ์ผ๋ก ๊ตฌ๋ถํ๊ธฐ ์ฝ๊ฒ ๋ง๋ค์์ด
3๏ธโฃ ๊ถค์ ์ถ์ : ๊ฐ์ฒด์ ์ด๋ ๊ฒฝ๋ก๋ฅผ ์ ์ผ๋ก ๊ทธ๋ ค์ ์์ง์ ํจํด์ ํ์ ํ ์ ์์ด
4๏ธโฃ ๋์ ๊ด๋ฆฌ: ์ค์๊ฐ์ผ๋ก ๊ฐ์ฒด๋ฅผ ์ถ๊ฐํ๊ฑฐ๋ ์ ๊ฑฐํ ์ ์์ด์ ์ ์ฐํด!
๐ฅ ๋ค ๋ฒ์งธ ์์ : ์์ ๊ธฐ๋ฐ ๊ฐ์ฒด ์ถ์
์ด๋ฒ์ ์ข ๋ค๋ฅธ ์ ๊ทผ! ํน์ ์์์ ๊ฐ์ง ๊ฐ์ฒด๋ฅผ ์๋์ผ๋ก ์ฐพ์์ ์ถ์ ํ๋ ๋ฐฉ๋ฒ์ด์ผ. ๋นจ๊ฐ ๊ณต์ด๋ ๋ ธ๋ ์ฐจ ๊ฐ์ ๊ฑธ ์ถ์ ํ ๋ ์ ์ฉํด! ๐จ
import cv2
import numpy as np
class ColorBasedTracker:
"""
์์ ๊ธฐ๋ฐ ๊ฐ์ฒด ์ถ์ ํด๋์ค
"""
def __init__(self, color_name='red'):
self.color_name = color_name
self.lower_bound, self.upper_bound = self.get_color_range(color_name)
self.kernel = np.ones((5, 5), np.uint8)
def get_color_range(self, color_name):
"""
์์๋ณ HSV ๋ฒ์ ์ ์
"""
color_ranges = {
'red': ([0, 120, 70], [10, 255, 255]), # ๋นจ๊ฐ
'red2': ([170, 120, 70], [180, 255, 255]), # ๋นจ๊ฐ (์ถ๊ฐ ๋ฒ์)
'blue': ([100, 150, 0], [140, 255, 255]), # ํ๋
'green': ([40, 40, 40], [80, 255, 255]), # ์ด๋ก
'yellow': ([20, 100, 100], [30, 255, 255]), # ๋
ธ๋
'orange': ([10, 100, 100], [20, 255, 255]), # ์ฃผํฉ
'purple': ([140, 50, 50], [160, 255, 255]), # ๋ณด๋ผ
}
if color_name in color_ranges:
lower, upper = color_ranges[color_name]
return np.array(lower), np.array(upper)
else:
# ๊ธฐ๋ณธ๊ฐ (๋นจ๊ฐ)
return np.array([0, 120, 70]), np.array([10, 255, 255])
def detect_color(self, frame):
"""
ํ๋ ์์์ ํน์ ์์ ์์ญ ๊ฒ์ถ
Returns:
mask: ์ด์ง ๋ง์คํฌ
contours: ๊ฒ์ถ๋ ์ค๊ณฝ์ ๋ค
"""
# BGR์ HSV๋ก ๋ณํ
hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)
# ์์ ๋ฒ์๋ก ๋ง์คํฌ ์์ฑ
mask = cv2.inRange(hsv, self.lower_bound, self.upper_bound)
# ๋นจ๊ฐ์ HSV์์ ๋ ๋ฒ์๋ฅผ ์ฌ์ฉ
if self.color_name == 'red':
lower2 = np.array([170, 120, 70])
upper2 = np.array([180, 255, 255])
mask2 = cv2.inRange(hsv, lower2, upper2)
mask = cv2.bitwise_or(mask, mask2)
# ๋
ธ์ด์ฆ ์ ๊ฑฐ (๋ชจํด๋ก์ง ์ฐ์ฐ)
mask = cv2.erode(mask, self.kernel, iterations=2)
mask = cv2.dilate(mask, self.kernel, iterations=2)
# ์ค๊ณฝ์ ์ฐพ๊ธฐ
contours, _ = cv2.findContours(mask, cv2.RETR_EXTERNAL,
cv2.CHAIN_APPROX_SIMPLE)
return mask, contours
def get_largest_contour(self, contours, min_area=500):
"""
๊ฐ์ฅ ํฐ ์ค๊ณฝ์ ์ฐพ๊ธฐ
Args:
contours: ์ค๊ณฝ์ ๋ฆฌ์คํธ
min_area: ์ต์ ๋ฉด์ (์์ ๋
ธ์ด์ฆ ์ ๊ฑฐ)
Returns:
๊ฐ์ฅ ํฐ ์ค๊ณฝ์ ์ ๋ฐ์ด๋ฉ ๋ฐ์ค (x, y, w, h)
"""
if len(contours) == 0:
return None
# ๋ฉด์ ๊ธฐ์ค์ผ๋ก ์ ๋ ฌ
valid_contours = [c for c in contours if cv2.contourArea(c) > min_area]
if len(valid_contours) == 0:
return None
largest_contour = max(valid_contours, key=cv2.contourArea)
x, y, w, h = cv2.boundingRect(largest_contour)
return (x, y, w, h), largest_contour
def color_tracking_demo():
"""
์์ ๊ธฐ๋ฐ ์ถ์ ๋ฐ๋ชจ
"""
# ์ถ์ ํ ์์ ์ ํ
print("์ถ์ ํ ์์์ ์ ํํ์ธ์:")
print("1: ๋นจ๊ฐ(red)")
print("2: ํ๋(blue)")
print("3: ์ด๋ก(green)")
print("4: ๋
ธ๋(yellow)")
choice = input("์ ํ (1-4): ").strip()
color_map = {'1': 'red', '2': 'blue', '3': 'green', '4': 'yellow'}
color_name = color_map.get(choice, 'red')
# ์ถ์ ๊ธฐ ์ด๊ธฐํ
tracker = ColorBasedTracker(color_name)
# ์น์บ ์ด๊ธฐ
video = cv2.VideoCapture(0)
if not video.isOpened():
print("์น์บ ์ ์ด ์ ์์ต๋๋ค!")
return
print(f"\n{color_name.upper()} ์์ ์ถ์ ์์!")
print("Q ํค๋ฅผ ๋๋ฅด๋ฉด ์ข
๋ฃ๋ฉ๋๋ค.\n")
# ๊ถค์ ์ ์ฅ
trajectory = []
max_trajectory_length = 50
while True:
ok, frame = video.read()
if not ok:
break
# ์์ ๊ฒ์ถ
mask, contours = tracker.detect_color(frame)
# ๊ฐ์ฅ ํฐ ๊ฐ์ฒด ์ฐพ๊ธฐ
result = tracker.get_largest_contour(contours)
if result is not None:
bbox, contour = result
x, y, w, h = bbox
# ๋ฐ์ด๋ฉ ๋ฐ์ค ๊ทธ๋ฆฌ๊ธฐ
cv2.rectangle(frame, (x, y), (x+w, y+h), (0, 255, 0), 3)
# ์ค๊ณฝ์ ๊ทธ๋ฆฌ๊ธฐ
cv2.drawContours(frame, [contour], -1, (0, 255, 255), 2)
# ์ค์ฌ์
center_x = x + w // 2
center_y = y + h // 2
cv2.circle(frame, (center_x, center_y), 5, (0, 0, 255), -1)
# ๊ถค์ ์ ์ฅ
trajectory.append((center_x, center_y))
if len(trajectory) > max_trajectory_length:
trajectory.pop(0)
# ๊ถค์ ๊ทธ๋ฆฌ๊ธฐ
for i in range(1, len(trajectory)):
thickness = int(np.sqrt(max_trajectory_length / float(i + 1)) * 2.5)
cv2.line(frame, trajectory[i-1], trajectory[i],
(0, 255, 0), thickness)
# ์ ๋ณด ํ์
area = cv2.contourArea(contour)
cv2.putText(frame, f"Tracking: {color_name.upper()}",
(x, y-30), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 255, 0), 2)
cv2.putText(frame, f"Area: {int(area)}",
(x, y-10), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 255, 0), 2)
else:
cv2.putText(frame, f"No {color_name.upper()} object detected",
(10, 30), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 0, 255), 2)
# ๋ง์คํฌ ์๊ฐํ (์์ ์ฐฝ์ผ๋ก)
mask_display = cv2.cvtColor(mask, cv2.COLOR_GRAY2BGR)
mask_small = cv2.resize(mask_display, (320, 240))
# ํ๋ ์์ ๋ง์คํฌ ์ค๋ฒ๋ ์ด
frame[10:250, 10:330] = mask_small
cv2.rectangle(frame, (10, 10), (330, 250), (255, 255, 255), 2)
cv2.putText(frame, "Color Mask", (15, 30),
cv2.FONT_HERSHEY_SIMPLEX, 0.6, (255, 255, 255), 2)
# ํ๋ฉด ์ถ๋ ฅ
cv2.imshow("Color-Based Tracking", frame)
# ์ข
๋ฃ ํค
if cv2.waitKey(1) & 0xFF == ord('q'):
break
video.release()
cv2.destroyAllWindows()
def interactive_color_picker():
"""
๋ํํ ์์ ๋ฒ์ ์ ํ ๋๊ตฌ
HSV ๊ฐ์ ์ค์๊ฐ์ผ๋ก ์กฐ์ ํ๋ฉด์ ์ต์ ์ ๋ฒ์๋ฅผ ์ฐพ์ ์ ์์ด!
"""
def nothing(x):
pass
video = cv2.VideoCapture(0)
# ํธ๋๋ฐ ์๋์ฐ ์์ฑ
cv2.namedWindow('Color Picker')
# HSV ๋ฒ์ ํธ๋๋ฐ
cv2.createTrackbar('H Low', 'Color Picker', 0, 179, nothing)
cv2.createTrackbar('H High', 'Color Picker', 179, 179, nothing)
cv2.createTrackbar('S Low', 'Color Picker', 0, 255, nothing)
cv2.createTrackbar('S High', 'Color Picker', 255, 255, nothing)
cv2.createTrackbar('V Low', 'Color Picker', 0, 255, nothing)
cv2.createTrackbar('V High', 'Color Picker', 255, 255, nothing)
print("\n=== ๋ํํ ์์ ์ ํ๊ธฐ ===")
print("ํธ๋๋ฐ๋ฅผ ์กฐ์ ํด์ ์ํ๋ ์์ ๋ฒ์๋ฅผ ์ฐพ์ผ์ธ์!")
print("Q ํค๋ฅผ ๋๋ฅด๋ฉด ํ์ฌ ๊ฐ์ด ์ถ๋ ฅ๋๊ณ ์ข
๋ฃ๋ฉ๋๋ค.\n")
while True:
ok, frame = video.read()
if not ok:
break
# ํธ๋๋ฐ ๊ฐ ์ฝ๊ธฐ
h_low = cv2.getTrackbarPos('H Low', 'Color Picker')
h_high = cv2.getTrackbarPos('H High', 'Color Picker')
s_low = cv2.getTrackbarPos('S Low', 'Color Picker')
s_high = cv2.getTrackbarPos('S High', 'Color Picker')
v_low = cv2.getTrackbarPos('V Low', 'Color Picker')
v_high = cv2.getTrackbarPos('V High', 'Color Picker')
# HSV ๋ณํ
hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)
# ๋ง์คํฌ ์์ฑ
lower = np.array([h_low, s_low, v_low])
upper = np.array([h_high, s_high, v_high])
mask = cv2.inRange(hsv, lower, upper)
# ๊ฒฐ๊ณผ ์ ์ฉ
result = cv2.bitwise_and(frame, frame, mask=mask)
# ํ๋ฉด ์ถ๋ ฅ
cv2.imshow('Original', frame)
cv2.imshow('Mask', mask)
cv2.imshow('Result', result)
if cv2.waitKey(1) & 0xFF == ord('q'):
print("\n=== ์ ํ๋ HSV ๋ฒ์ ===")
print(f"Lower: [{h_low}, {s_low}, {v_low}]")
print(f"Upper: [{h_high}, {s_high}, {v_high}]")
break
video.release()
cv2.destroyAllWindows()
if __name__ == '__main__':
# ์ผ๋ฐ ์์ ์ถ์ ์คํ
color_tracking_demo()
# ๋๋ ์์ ๋ฒ์ ์ฐพ๊ธฐ ๋๊ตฌ ์คํ
# interactive_color_picker()
โข ๊ฐ๋จํ ๊ตฌํ: HSV ์๊ณต๊ฐ๋ง ์ดํดํ๋ฉด ์ฝ๊ฒ ๋ง๋ค ์ ์์ด
โข ํน์ ์ํฉ์ ์ต์ : ์์์ด ๋๋ ทํ ๊ฐ์ฒด(๊ณต, ์ฐจ๋, ์ท ๋ฑ) ์ถ์ ์ ์๋ฒฝํด
โข ์กฐ๋ช ๋ณํ ๋์: HSV๋ RGB๋ณด๋ค ์กฐ๋ช ๋ณํ์ ๊ฐํด!
โก ์ฑ๋ฅ ์ต์ ํ ํ
์ถ์ ์ฝ๋๋ฅผ ๋ ๋น ๋ฅด๊ณ ํจ์จ์ ์ผ๋ก ๋ง๋๋ ๋ฐฉ๋ฒ๋ค์ ์๋ ค์ค๊ฒ! ์ค์ ์์ ์ ๋ง ์ค์ํ ๋ถ๋ถ์ด์ผ. ๐
1๏ธโฃ ํ๋ ์ ํฌ๊ธฐ ์กฐ์
# ์๋ณธ ํ๋ ์์ ์๊ฒ ๋ฆฌ์ฌ์ด์ฆํ๋ฉด ์ฒ๋ฆฌ ์๋๊ฐ ํฌ๊ฒ ํฅ์๋ผ!
def resize_frame(frame, width=640):
"""
ํ๋ ์ ํฌ๊ธฐ๋ฅผ ์กฐ์ ํ๋ฉด์ ๋น์จ ์ ์ง
"""
height = int(frame.shape[0] * (width / frame.shape[1]))
return cv2.resize(frame, (width, height))
# ์ฌ์ฉ ์
frame = resize_frame(frame, width=640) # 640px๋ก ์ถ์
2๏ธโฃ ROI (Region of Interest) ํ์ฉ
# ์ ์ฒด ํ๋ ์์ด ์๋ ๊ด์ฌ ์์ญ๋ง ์ฒ๋ฆฌํ๊ธฐ
def expand_roi(bbox, frame_shape, expand_ratio=1.5):
"""
๋ฐ์ด๋ฉ ๋ฐ์ค๋ฅผ ํ์ฅํด์ ROI ์์ฑ
๊ฐ์ฒด๊ฐ ๋น ๋ฅด๊ฒ ์์ง์ฌ๋ ๋์น์ง ์์!
"""
x, y, w, h = bbox
# ์ค์ฌ์ ๊ณ์ฐ
center_x = x + w // 2
center_y = y + h // 2
# ํ์ฅ๋ ํฌ๊ธฐ
new_w = int(w * expand_ratio)
new_h = int(h * expand_ratio)
# ์๋ก์ด ์ขํ (ํ๋ ์ ๋ฒ์ ๋ด๋ก ์ ํ)
new_x = max(0, center_x - new_w // 2)
new_y = max(0, center_y - new_h // 2)
new_x2 = min(frame_shape[1], new_x + new_w)
new_y2 = min(frame_shape[0], new_y + new_h)
return (new_x, new_y, new_x2 - new_x, new_y2 - new_y)
# ์ฌ์ฉ ์
roi = expand_roi(bbox, frame.shape, expand_ratio=1.5)
roi_frame = frame[roi[1]:roi[1]+roi[3], roi[0]:roi[0]+roi[2]]
3๏ธโฃ ๋ฉํฐ์ค๋ ๋ฉ์ผ๋ก ํ๋ ์ ์ฝ๊ธฐ ์ต์ ํ
import threading
import queue
class VideoStream:
"""
๋ณ๋ ์ค๋ ๋์์ ํ๋ ์์ ์ฝ์ด์ ๋ฒํผ๋ง
๋ฉ์ธ ๋ฃจํ์ ์ฒ๋ฆฌ ์๋๊ฐ ํฅ์๋ผ!
"""
def __init__(self, src=0, queue_size=128):
self.stream = cv2.VideoCapture(src)
self.stopped = False
self.queue = queue.Queue(maxsize=queue_size)
# ์ค๋ ๋ ์์
self.thread = threading.Thread(target=self.update, args=())
self.thread.daemon = True
self.thread.start()
def update(self):
"""๋ฐฑ๊ทธ๋ผ์ด๋์์ ํ๋ ์ ์ฝ๊ธฐ"""
while True:
if self.stopped:
return
if not self.queue.full():
ok, frame = self.stream.read()
if not ok:
self.stop()
return
self.queue.put(frame)
def read(self):
"""ํ์์ ํ๋ ์ ๊ฐ์ ธ์ค๊ธฐ"""
return self.queue.get()
def stop(self):
"""์คํธ๋ฆผ ์ค์ง"""
self.stopped = True
self.thread.join()
def __del__(self):
self.stream.release()
# ์ฌ์ฉ ์
vs = VideoStream(src=0)
time.sleep(1.0) # ์นด๋ฉ๋ผ ์๋ฐ์
while True:
frame = vs.read()
# ํ๋ ์ ์ฒ๋ฆฌ...
vs.stop()
4๏ธโฃ ํ๋ ์ ์คํต์ผ๋ก ์๋ ํฅ์
# ๋ชจ๋ ํ๋ ์์ ์ฒ๋ฆฌํ์ง ์๊ณ N๊ฐ๋ง๋ค ์ฒ๋ฆฌ
frame_skip = 2 # 2ํ๋ ์๋ง๋ค 1๋ฒ ์ฒ๋ฆฌ
frame_count = 0
while True:
ok, frame = video.read()
frame_count += 1
# ํ๋ ์ ์คํต
if frame_count % frame_skip != 0:
continue
# ์ถ์ ์
๋ฐ์ดํธ
ok, bbox = tracker.update(frame)
# ...
โข ๋ฆฌ์ฌ์ด์ฆ (640x360): ~45 FPS (3๋ฐฐ ํฅ์!)
โข ROI + ๋ฆฌ์ฌ์ด์ฆ: ~60 FPS (4๋ฐฐ ํฅ์!)
โข ๋ฉํฐ์ค๋ ๋ฉ ์ถ๊ฐ: ~75 FPS (5๋ฐฐ ํฅ์!)
์ํฉ์ ๋ง๊ฒ ์กฐํฉํด์ ์ฌ์ฉํ๋ฉด ์ค์๊ฐ ์ฒ๋ฆฌ๊ฐ ํจ์ฌ ์์ํด์ ธ! ๐ช
๐ ์ค์ ํ๋ก์ ํธ ์์
์ด๋ก ๋ง ๋ฐฐ์ฐ๋ฉด ์ฌ๋ฏธ์์ง! ์ค์ ๋ก ํ์ฉํ ์ ์๋ ํ๋ก์ ํธ๋ฅผ ๋ง๋ค์ด๋ณด์. ๐ฏ
import cv2
import numpy as np
from datetime import datetime
import os
class IntrusionDetectionSystem:
"""
ํน์ ์์ญ์ ๊ฐ์ฒด๊ฐ ์นจ์
ํ๋ฉด ๊ฒฝ๊ณ ํ๊ณ ๋
นํํ๋ ์์คํ
"""
def __init__(self, detection_zone):
"""
Args:
detection_zone: ๊ฐ์ง ์์ญ [(x1,y1), (x2,y2), ...]
"""
self.detection_zone = np.array(detection_zone, dtype=np.int32)
self.is_recording = False
self.video_writer = None
self.alert_count = 0
# ๋
นํ ํด๋ ์์ฑ
self.output_dir = 'intrusion_recordings'
if not os.path.exists(self.output_dir):
os.makedirs(self.output_dir)
def is_inside_zone(self, point):
"""์ ์ด ๊ฐ์ง ์์ญ ์์ ์๋์ง ํ์ธ"""
result = cv2.pointPolygonTest(self.detection_zone, point, False)
return result >= 0
def start_recording(self, frame_size, fps=20):
"""์นจ์
๊ฐ์ง์ ๋
นํ ์์"""
if not self.is_recording:
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
filename = f"{self.output_dir}/intrusion_{timestamp}.mp4"
fourcc = cv2.VideoWriter_fourcc(*'mp4v')
self.video_writer = cv2.VideoWriter(
filename, fourcc, fps, frame_size
)
self.is_recording = True
print(f"๐จ ์นจ์
๊ฐ์ง! ๋
นํ ์์: {filename}")
def stop_recording(self):
"""๋
นํ ์ค์ง"""
if self.is_recording and self.video_writer is not None:
self.video_writer.release()
self.is_recording = False
print("โ
๋
นํ ์ข
๋ฃ")
def draw_zone(self, frame, color=(0, 255, 255), thickness=2):
"""๊ฐ์ง ์์ญ ๊ทธ๋ฆฌ๊ธฐ"""
cv2.polylines(frame, [self.detection_zone], True, color, thickness)
# ์์ญ ๋ด๋ถ๋ฅผ ๋ฐํฌ๋ช
ํ๊ฒ
overlay = frame.copy()
cv2.fillPoly(overlay, [self.detection_zone], color)
cv2.addWeighted(overlay, 0.2, frame, 0.8, 0, frame)
# ํ
์คํธ
cv2.putText(frame, "DETECTION ZONE",
tuple(self.detection_zone[0]),
cv2.FONT_HERSHEY_SIMPLEX, 0.7, color, 2)
def intrusion_detection_demo():
"""์นจ์
๊ฐ์ง ์์คํ
๋ฐ๋ชจ"""
video = cv2.VideoCapture(0)
if not video.isOpened():
print("์น์บ ์ ์ด ์ ์์ต๋๋ค!")
return
# ์ฒซ ํ๋ ์์ผ๋ก ๊ฐ์ง ์์ญ ์ค์
ok, frame = video.read()
height, width = frame.shape[:2]
# ํ๋ฉด ์ค์์ ์ฌ๊ฐํ ๊ฐ์ง ์์ญ ์ค์
margin = 100
detection_zone = [
(margin, margin),
(width - margin, margin),
(width - margin, height - margin),
(margin, height - margin)
]
# ์์คํ
์ด๊ธฐํ
ids = IntrusionDetectionSystem(detection_zone)
# ๋ฐฐ๊ฒฝ ์ ๊ฑฐ๊ธฐ (์์ง์ ๊ฐ์ง์ฉ)
bg_subtractor = cv2.createBackgroundSubtractorMOG2(
history=500, varThreshold=50, detectShadows=True
)
print("\n=== ์นจ์
๊ฐ์ง ์์คํ
์์ ===")
print("๊ฐ์ง ์์ญ ๋ด์ ์์ง์์ด ๊ฐ์ง๋๋ฉด ์๋์ผ๋ก ๋
นํ๋ฉ๋๋ค!")
print("Q ํค๋ฅผ ๋๋ฅด๋ฉด ์ข
๋ฃ๋ฉ๋๋ค.\n")
frame_count = 0
no_intrusion_frames = 0
recording_timeout = 100 # ์นจ์
์ด ์์ผ๋ฉด 100ํ๋ ์ ํ ๋
นํ ์ค์ง
while True:
ok, frame = video.read()
if not ok:
break
frame_count += 1
# ๋ฐฐ๊ฒฝ ์ ๊ฑฐ๋ก ์์ง์ ๊ฐ์ง
fg_mask = bg_subtractor.apply(frame)
# ๋
ธ์ด์ฆ ์ ๊ฑฐ
kernel = np.ones((5, 5), np.uint8)
fg_mask = cv2.morphologyEx(fg_mask, cv2.MORPH_OPEN, kernel)
fg_mask = cv2.morphologyEx(fg_mask, cv2.MORPH_CLOSE, kernel)
# ์ค๊ณฝ์ ์ฐพ๊ธฐ
contours, _ = cv2.findContours(fg_mask, cv2.RETR_EXTERNAL,
cv2.CHAIN_APPROX_SIMPLE)
intrusion_detected = False
# ๊ฐ ์ค๊ณฝ์ ๊ฒ์ฌ
for contour in contours:
area = cv2.contourArea(contour)
# ์์ ๋
ธ์ด์ฆ ๋ฌด์
if area < 1000:
continue
# ๋ฐ์ด๋ฉ ๋ฐ์ค
x, y, w, h = cv2.boundingRect(contour)
center = (x + w//2, y + h//2)
# ๊ฐ์ง ์์ญ ๋ด๋ถ์ธ์ง ํ์ธ
if ids.is_inside_zone(center):
intrusion_detected = True
# ์นจ์
๊ฐ์ฒด ํ์
cv2.rectangle(frame, (x, y), (x+w, y+h), (0, 0, 255), 3)
cv2.circle(frame, center, 5, (0, 0, 255), -1)
cv2.putText(frame, "INTRUDER!", (x, y-10),
cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 0, 255), 2)
# ์นจ์
๊ฐ์ง ์ฒ๋ฆฌ
if intrusion_detected:
no_intrusion_frames = 0
ids.alert_count += 1
# ๋
นํ ์์
if not ids.is_recording:
ids.start_recording((width, height))
# ๊ฒฝ๊ณ ํ์
cv2.putText(frame, "!!! INTRUSION DETECTED !!!",
(width//2 - 200, 50),
cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 0, 255), 3)
else:
no_intrusion_frames += 1
# ์ผ์ ์๊ฐ ์นจ์
์ด ์์ผ๋ฉด ๋
นํ ์ค์ง
if no_intrusion_frames > recording_timeout and ids.is_recording:
ids.stop_recording()
# ๊ฐ์ง ์์ญ ๊ทธ๋ฆฌ๊ธฐ
zone_color = (0, 0, 255) if intrusion_detected else (0, 255, 255)
ids.draw_zone(frame, color=zone_color)
# ์ํ ์ ๋ณด
status_text = "RECORDING" if ids.is_recording else "MONITORING"
status_color = (0, 0, 255) if ids.is_recording else (0, 255, 0)
cv2.putText(frame, f"Status: {status_text}", (10, 30),
cv2.FONT_HERSHEY_SIMPLEX, 0.7, status_color, 2)
cv2.putText(frame, f"Alerts: {ids.alert_count}", (10, 60),
cv2.FONT_HERSHEY_SIMPLEX, 0.7, (255, 255, 255), 2)
# ๋
นํ ์ค์ด๋ฉด ํ์ผ์ ์ ์ฅ
if ids.is_recording:
ids.video_writer.write(frame)
# ๋
นํ ํ์
cv2.circle(frame, (width - 30, 30), 10, (0, 0, 255), -1)
# ํ๋ฉด ์ถ๋ ฅ
cv2.imshow("Intrusion Detection System", frame)
cv2.imshow("Motion Mask", fg_mask)
# ์ข
๋ฃ ํค
if cv2.waitKey(1) & 0xFF == ord('q'):
break
# ์ ๋ฆฌ
ids.stop_recording()
video.release()
cv2.destroyAllWindows()
print(f"\n์ด ์นจ์
๊ฐ์ง ํ์: {ids.alert_count}")
if __name__ == '__main__':
intrusion_detection_demo()
โข ์ฃผ์ฐจ์ฅ ๊ด๋ฆฌ: ๋ถ๋ฒ ์ฃผ์ฐจ ์ฐจ๋ ์๋ ๊ฐ์ง
โข ๊ณต์ฅ ์์ : ์ํ ๊ตฌ์ญ ์นจ์ ๊ฒฝ๊ณ
โข ์ผ์๋๋ฌผ ๋ชจ๋ํฐ๋ง: ํน์ ๊ตฌ์ญ ๋๋ฌผ ์ถํ ๊ธฐ๋ก
์ด๋ฐ ํ๋ก์ ํธ๋ฅผ ์ฌ๋ฅ๋ท์์ ์๋ขฐ๋ฐ๊ฑฐ๋ ํฌํธํด๋ฆฌ์ค๋ก ํ์ฉํ๋ฉด ์ ๋ง ์ข์! ๐ผ
import cv2
import numpy as np
from collections import deque
class ExerciseCounter:
"""
์ด๋ ๋์์ ์ถ์ ํ๊ณ ํ์๋ฅผ ์ธ๋ ํด๋์ค
ํธ์์
, ์ค์ฟผํธ ๋ฑ์ ํ์ฉ ๊ฐ๋ฅ!
"""
def __init__(self, exercise_type='pushup'):
self.exercise_type = exercise_type
self.count = 0
self.state = 'up' # 'up' ๋๋ 'down'
self.position_history = deque(maxlen=30)
# ์ด๋๋ณ ์๊ณ๊ฐ ์ค์
self.thresholds = {
'pushup': {'down': 0.3, 'up': 0.7},
'squat': {'down': 0.4, 'up': 0.8}
}
def update(self, y_position, frame_height):
"""
๊ฐ์ฒด์ Y ์์น๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ์ด๋ ํ์ ์นด์ดํธ
Args:
y_position: ์ถ์ ๊ฐ์ฒด์ Y ์ขํ
frame_height: ํ๋ ์ ๋์ด
"""
# ์ ๊ทํ๋ ์์น (0~1)
normalized_pos = y_position / frame_height
self.position_history.append(normalized_pos)
# ์ถฉ๋ถํ ๋ฐ์ดํฐ๊ฐ ์์ด๋ฉด ๋ถ์
if len(self.position_history) < 10:
return
# ํ๊ท ์์น ๊ณ์ฐ (๋
ธ์ด์ฆ ์ ๊ฑฐ)
avg_pos = np.mean(list(self.position_history)[-10:])
threshold = self.thresholds.get(self.exercise_type,
{'down': 0.3, 'up': 0.7})
# ์ํ ์ ํ ๊ฐ์ง
if self.state == 'up' and avg_pos < threshold['down']:
self.state = 'down'
elif self.state == 'down' and avg_pos > threshold['up']:
self.state = 'up'
self.count += 1
print(f"โ
{self.exercise_type.upper()}: {self.count}ํ")
def get_state_color(self):
"""ํ์ฌ ์ํ์ ๋ฐ๋ฅธ ์์ ๋ฐํ"""
return (0, 255, 0) if self.state == 'up' else (0, 165, 255)
def draw_info(self, frame):
"""์ด๋ ์ ๋ณด๋ฅผ ํ๋ ์์ ๊ทธ๋ฆฌ๊ธฐ"""
height, width = frame.shape[:2]
# ๋ฐํฌ๋ช
ํจ๋
overlay = frame.copy()
cv2.rectangle(overlay, (10, 10), (300, 150), (0, 0, 0), -1)
cv2.addWeighted(overlay, 0.6, frame, 0.4, 0, frame)
# ์ด๋ ์ ๋ณด
cv2.putText(frame, f"Exercise: {self.exercise_type.upper()}",
(20, 40), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (255, 255, 255), 2)
cv2.putText(frame, f"Count: {self.count}",
(20, 75), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2)
cv2.putText(frame, f"State: {self.state.upper()}",
(20, 110), cv2.FONT_HERSHEY_SIMPLEX, 0.7,
self.get_state_color(), 2)
# ์์น ๊ทธ๋ํ (์ ํ์ฌํญ)
if len(self.position_history) > 1:
graph_x = width - 220
graph_y = 20
graph_w = 200
graph_h = 100
# ๊ทธ๋ํ ๋ฐฐ๊ฒฝ
cv2.rectangle(frame, (graph_x, graph_y),
(graph_x + graph_w, graph_y + graph_h),
(50, 50, 50), -1)
# ๋ฐ์ดํฐ ํ๋กฏ
positions = list(self.position_history)
for i in range(1, len(positions)):
x1 = graph_x + int((i-1) / len(positions) * graph_w)
y1 = graph_y + int((1 - positions[i-1]) * graph_h)
x2 = graph_x + int(i / len(positions) * graph_w)
y2 = graph_y + int((1 - positions[i]) * graph_h)
cv2.line(frame, (x1, y1), (x2, y2), (0, 255, 255), 2)
cv2.putText(frame, "Position", (graph_x, graph_y - 5),
cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 255, 255), 1)
def exercise_tracking_demo():
"""์ด๋ ์ถ์ ๋ฐ๋ชจ"""
video = cv2.VideoCapture(0)
if not video.isOpened():
print("์น์บ ์ ์ด ์ ์์ต๋๋ค!")
return
# ์ฒซ ํ๋ ์ ์ฝ๊ธฐ
ok, frame = video.read()
if not ok:
return
print("\n=== ์ด๋ ์ถ์ ์์คํ
===")
print("์ถ์ ํ ์ ์ฒด ๋ถ์(์: ๋จธ๋ฆฌ, ์)๋ฅผ ์ ํํ์ธ์!")
# ์ถ์ ์์ญ ์ ํ
bbox = cv2.selectROI("๊ฐ์ฒด ์ ํ", frame, False)
cv2.destroyWindow("๊ฐ์ฒด ์ ํ")
# ์ถ์ ๊ธฐ ์ด๊ธฐํ
tracker = cv2.TrackerCSRT_create()
tracker.init(frame, bbox)
# ์ด๋ ์นด์ดํฐ ์ด๊ธฐํ
counter = ExerciseCounter(exercise_type='pushup')
print("\n์ถ์ ์์! Q ํค๋ฅผ ๋๋ฅด๋ฉด ์ข
๋ฃ๋ฉ๋๋ค.")
print("R ํค๋ฅผ ๋๋ฅด๋ฉด ์นด์ดํธ๋ฅผ ๋ฆฌ์
ํฉ๋๋ค.\n")
while True:
ok, frame = video.read()
if not ok:
break
# ์ถ์ ์
๋ฐ์ดํธ
ok, bbox = tracker.update(frame)
if ok:
# ๋ฐ์ด๋ฉ ๋ฐ์ค ๊ทธ๋ฆฌ๊ธฐ
p1 = (int(bbox[0]), int(bbox[1]))
p2 = (int(bbox[0] + bbox[2]), int(bbox[1] + bbox[3]))
cv2.rectangle(frame, p1, p2, counter.get_state_color(), 3)
# ์ค์ฌ์
center_y = int(bbox[1] + bbox[3]/2)
center_x = int(bbox[0] + bbox[2]/2)
cv2.circle(frame, (center_x, center_y), 5, (0, 0, 255), -1)
# ์ด๋ ํ์ ์
๋ฐ์ดํธ
counter.update(center_y, frame.shape[0])
else:
cv2.putText(frame, "Tracking Lost!", (50, 50),
cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 0, 255), 2)
# ์ ๋ณด ํ์
counter.draw_info(frame)
# ํ๋ฉด ์ถ๋ ฅ
cv2.imshow("Exercise Tracker", frame)
# ํค ์
๋ ฅ
key = cv2.waitKey(1) & 0xFF
if key == ord('q'):
break
elif key == ord('r'):
counter.count = 0
counter.state = 'up'
print("์นด์ดํธ ๋ฆฌ์
!")
video.release()
cv2.destroyAllWindows()
print(f"\n์ด ์ด๋ ํ์: {counter.count}ํ")
print("์๊ณ ํ์
จ์ต๋๋ค! ๐ช")
if __name__ == '__main__':
exercise_tracking_demo()
โข ์๋ฉ์ด ์ถ์ : ์ค์ฟผํธ, ๋ฐ์ง ๋ฑ
โข ์ ์ถ์ : ๋ค๋ฒจ ์ปฌ, ์๋ ํ๋ ์ค ๋ฑ
์๊ณ๊ฐ(threshold)์ ์กฐ์ ํ๋ฉด ๋ค์ํ ์ด๋์ ๋ง์ถฐ ์ฌ์ฉํ ์ ์์ด! ํฌ์ค ํธ๋ ์ด๋๋ ํผํธ๋์ค ์ฑ ๊ฐ๋ฐ์ ํ์ฉํ๋ฉด ์ข๊ฒ ์ง? ๐๏ธ
๐ ๋ฌธ์ ํด๊ฒฐ ๊ฐ์ด๋
์ฝ๋ฉํ๋ค ๋ณด๋ฉด ๋ฌธ์ ๊ฐ ์๊ธฐ๊ธฐ ๋ง๋ จ์ด์ผ. ์์ฃผ ๋ฐ์ํ๋ ๋ฌธ์ ๋ค๊ณผ ํด๊ฒฐ ๋ฐฉ๋ฒ์ ์ ๋ฆฌํด๋ดค์ด! ๐ง
์์ธ: opencv-contrib-python์ด ์ค์น๋์ง ์์๊ฑฐ๋ ๋ฒ์ ์ด ๋ง์ง ์์
ํด๊ฒฐ:
# ๊ธฐ์กด OpenCV ์ ๊ฑฐ
pip uninstall opencv-python opencv-contrib-python
# ์ต์ ๋ฒ์ ์ฌ์ค์น
pip install opencv-contrib-python
# ๋๋ ํน์ ๋ฒ์ ์ค์น
pip install opencv-contrib-python==4.5.5.64
ํด๊ฒฐ:
1๏ธโฃ ๋ค๋ฅธ ์ถ์ ์๊ณ ๋ฆฌ์ฆ ์๋: CSRT๋ ์ ํํ์ง๋ง ๋๋ฆฌ๊ณ , KCF๋ ๋น ๋ฅด์ง๋ง ๋ ์ ํํด. ์ํฉ์ ๋ง๊ฒ ์ ํ!
2๏ธโฃ ํ๋ ์ ํ์ง ๊ฐ์ : ์กฐ๋ช ์ ๋ฐ๊ฒ ํ๊ณ ๋ฐฐ๊ฒฝ์ ๋จ์ํ๊ฒ
3๏ธโฃ ROI ํ์ฅ: ์ถ์ ์์ญ์ ๋๊ฒ ์ก์์ ๊ฐ์ฒด๊ฐ ๋ฒ์ด๋์ง ์๋๋ก
4๏ธโฃ ์ฌ์ด๊ธฐํ ๋ก์ง ์ถ๊ฐ: ์ถ์ ์คํจ์ ์๋์ผ๋ก ์ฌํ์ง
ํด๊ฒฐ:
# ๋ค๋ฅธ ์นด๋ฉ๋ผ ์ธ๋ฑ์ค ์๋
for i in range(5):
cap = cv2.VideoCapture(i)
if cap.isOpened():
print(f"์นด๋ฉ๋ผ {i}๋ฒ์ด ์๋ํฉ๋๋ค!")
cap.release()
else:
print(f"์นด๋ฉ๋ผ {i}๋ฒ ์์")
# DirectShow ๋ฐฑ์๋ ์ฌ์ฉ (Windows)
cap = cv2.VideoCapture(0, cv2.CAP_DSHOW)
# V4L2 ๋ฐฑ์๋ ์ฌ์ฉ (Linux)
cap = cv2.VideoCapture(0, cv2.CAP_V4L2)
1๏ธโฃ ํ๋ ์ ํฌ๊ธฐ ์ค์ด๊ธฐ (640x480 ๊ถ์ฅ)
2๏ธโฃ MOSSE๋ KCF ๊ฐ์ ๋น ๋ฅธ ์๊ณ ๋ฆฌ์ฆ ์ฌ์ฉ
3๏ธโฃ ๋ฉํฐ์ค๋ ๋ฉ ์ ์ฉ
4๏ธโฃ GPU ๊ฐ์ ํ์ฉ (CUDA ์ง์ OpenCV ๋น๋)
ํด๊ฒฐ:
1๏ธโฃ HSV ๋ฒ์ ์กฐ์ : interactive_color_picker() ํจ์๋ก ์ต์ ๊ฐ ์ฐพ๊ธฐ
2๏ธโฃ ์กฐ๋ช ๊ฐ์ : ๊ท ์ผํ ์กฐ๋ช ์ด ์ค์ํด
3๏ธโฃ ๋ชจํด๋ก์ง ์ฐ์ฐ: ๋ ธ์ด์ฆ ์ ๊ฑฐ ๊ฐํ
# ๋ ๊ฐ๋ ฅํ ๋
ธ์ด์ฆ ์ ๊ฑฐ
kernel = np.ones((7, 7), np.uint8)
mask = cv2.morphologyEx(mask, cv2.MORPH_OPEN, kernel, iterations=2)
mask = cv2.morphologyEx(mask, cv2.MORPH_CLOSE, kernel, iterations=2)
๐ ์ถ๊ฐ ํ์ต ์๋ฃ ๋ฐ ์ฌํ ์ฃผ์
์ฌ๊ธฐ๊น์ง ๋ฐ๋ผ์๋ค๋ฉด ์ด๋ฏธ ๊ฐ์ฒด ์ถ์ ์ ๊ธฐ๋ณธ์ ๋ง์คํฐํ์ด! ๋ ๊น์ด ๊ณต๋ถํ๊ณ ์ถ๋ค๋ฉด ์ด๋ฐ ์ฃผ์ ๋ค์ ์ดํด๋ด. ๐
๐ฏ ์ฌํ ์ฃผ์ 1: ๋ฅ๋ฌ๋ ๊ธฐ๋ฐ ์ถ์
OpenCV์ ์ ํต์ ์ธ ์ถ์ ์๊ณ ๋ฆฌ์ฆ๋ณด๋ค ๋ ๊ฐ๋ ฅํ ๋ฅ๋ฌ๋ ๊ธฐ๋ฐ ๋ฐฉ๋ฒ๋ค์ด ์์ด:
โข SORT (Simple Online and Realtime Tracking)- ์นผ๋ง ํํฐ์ ํ๊ฐ๋ฆฌ์ ์๊ณ ๋ฆฌ์ฆ ์กฐํฉ
- ๋ค์ค ๊ฐ์ฒด ์ถ์ ์ ์ต์ ํ
- ์ค์๊ฐ ์ฒ๋ฆฌ ๊ฐ๋ฅ
โข DeepSORT
- SORT์ ๋ฅ๋ฌ๋ ํน์ง ์ถ์ถ ์ถ๊ฐ
- ๊ฐ๋ฆผ ํ์์ ๊ฐํจ
- ์ฌ์๋ณ(Re-identification) ๊ฐ๋ฅ
โข SiamMask
- ์์ ๋คํธ์ํฌ ๊ธฐ๋ฐ
- ํฝ์ ๋จ์ ์ ๋ฐ ์ถ์
- ์ธ๊ทธ๋ฉํ ์ด์ ๋ง์คํฌ ์ ๊ณต
# DeepSORT ์์ (๊ฐ๋จ ๋ฒ์ )
# pip install deep-sort-realtime
from deep_sort_realtime.deepsort_tracker import DeepSort
tracker = DeepSort(max_age=30)
# ๋งค ํ๋ ์๋ง๋ค
detections = [] # [[x, y, w, h, confidence], ...]
tracks = tracker.update_tracks(detections, frame=frame)
for track in tracks:
if not track.is_confirmed():
continue
track_id = track.track_id
bbox = track.to_ltrb() # left, top, right, bottom
# ์ถ์ ๊ฒฐ๊ณผ ์ฌ์ฉ...
๐ฏ ์ฌํ ์ฃผ์ 2: ๊ดํ ํ๋ฆ(Optical Flow)
ํฝ์ ๋จ์๋ก ์์ง์์ ์ถ์ ํ๋ ๊ธฐ๋ฒ์ด์ผ. ๊ฐ์ฒด ์ถ์ ๊ณผ ํจ๊ป ์ฌ์ฉํ๋ฉด ๋ ์ ํํด์ ธ!
import cv2
import numpy as np
def optical_flow_tracking():
"""
Lucas-Kanade ๊ดํ ํ๋ฆ์ ์ด์ฉํ ํน์ง์ ์ถ์
"""
video = cv2.VideoCapture(0)
# ์ฒซ ํ๋ ์ ์ฝ๊ธฐ
ret, old_frame = video.read()
old_gray = cv2.cvtColor(old_frame, cv2.COLOR_BGR2GRAY)
# ์ถ์ ํ ํน์ง์ ์ฐพ๊ธฐ
feature_params = dict(
maxCorners=100,
qualityLevel=0.3,
minDistance=7,
blockSize=7
)
p0 = cv2.goodFeaturesToTrack(old_gray, mask=None, **feature_params)
# ๊ดํ ํ๋ฆ ํ๋ผ๋ฏธํฐ
lk_params = dict(
winSize=(15, 15),
maxLevel=2,
criteria=(cv2.TERM_CRITERIA_EPS | cv2.TERM_CRITERIA_COUNT, 10, 0.03)
)
# ๊ถค์ ๊ทธ๋ฆฌ๊ธฐ์ฉ
mask = np.zeros_like(old_frame)
while True:
ret, frame = video.read()
if not ret:
break
frame_gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
# ๊ดํ ํ๋ฆ ๊ณ์ฐ
p1, st, err = cv2.calcOpticalFlowPyrLK(
old_gray, frame_gray, p0, None, **lk_params
)
# ์ข์ ์ ๋ค๋ง ์ ํ
if p1 is not None:
good_new = p1[st == 1]
good_old = p0[st == 1]
# ๊ถค์ ๊ทธ๋ฆฌ๊ธฐ
for i, (new, old) in enumerate(zip(good_new, good_old)):
a, b = new.ravel()
c, d = old.ravel()
mask = cv2.line(mask, (int(a), int(b)), (int(c), int(d)),
(0, 255, 0), 2)
frame = cv2.circle(frame, (int(a), int(b)), 5, (0, 0, 255), -1)
img = cv2.add(frame, mask)
cv2.imshow('Optical Flow Tracking', img)
# ๋ค์ ํ๋ ์ ์ค๋น
old_gray = frame_gray.copy()
p0 = good_new.reshape(-1, 1, 2)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
video.release()
cv2.destroyAllWindows()
๐ฏ ์ฌํ ์ฃผ์ 3: ์นผ๋ง ํํฐ๋ฅผ ์ด์ฉํ ์์ธก
๊ฐ์ฒด์ ๋ค์ ์์น๋ฅผ ์์ธกํด์ ์ถ์ ์ ํ๋๋ฅผ ๋์ผ ์ ์์ด!
import cv2
import numpy as np
class KalmanTracker:
"""
์นผ๋ง ํํฐ๋ฅผ ์ด์ฉํ ๊ฐ์ฒด ์์น ์์ธก ๋ฐ ์ถ์
"""
def __init__(self):
# ์นผ๋ง ํํฐ ์ด๊ธฐํ (4์ฐจ์ ์ํ: x, y, dx, dy)
self.kalman = cv2.KalmanFilter(4, 2)
self.kalman.measurementMatrix = np.array([
[1, 0, 0, 0],
[0, 1, 0, 0]
], np.float32)
self.kalman.transitionMatrix = np.array([
[1, 0, 1, 0],
[0, 1, 0, 1],
[0, 0, 1, 0],
[0, 0, 0, 1]
], np.float32)
self.kalman.processNoiseCov = np.eye(4, dtype=np.float32) * 0.03
self.kalman.measurementNoiseCov = np.eye(2, dtype=np.float32) * 0.1
def predict(self):
"""๋ค์ ์์น ์์ธก"""
prediction = self.kalman.predict()
return int(prediction[0]), int(prediction[1])
def update(self, x, y):
"""์ธก์ ๊ฐ์ผ๋ก ํํฐ ์
๋ฐ์ดํธ"""
measurement = np.array([[np.float32(x)], [np.float32(y)]])
self.kalman.correct(measurement)
def get_state(self):
"""ํ์ฌ ์ํ ๋ฐํ"""
state = self.kalman.statePost
return int(state[0]), int(state[1])
def kalman_tracking_demo():
"""์นผ๋ง ํํฐ ์ถ์ ๋ฐ๋ชจ"""
video = cv2.VideoCapture(0)
ret, frame = video.read()
# ์ถ์ ์์ญ ์ ํ
bbox = cv2.selectROI("๊ฐ์ฒด ์ ํ", frame, False)
cv2.destroyWindow("๊ฐ์ฒด ์ ํ")
# OpenCV ์ถ์ ๊ธฐ
tracker = cv2.TrackerKCF_create()
tracker.init(frame, bbox)
# ์นผ๋ง ํํฐ ์ถ์ ๊ธฐ
kalman_tracker = KalmanTracker()
# ์ด๊ธฐ ์์น
center_x = int(bbox[0] + bbox[2]/2)
center_y = int(bbox[1] + bbox[3]/2)
kalman_tracker.update(center_x, center_y)
trajectory_measured = []
trajectory_predicted = []
while True:
ret, frame = video.read()
if not ret:
break
# ์์ธก (์ธก์ ์ )
pred_x, pred_y = kalman_tracker.predict()
trajectory_predicted.append((pred_x, pred_y))
# ์ค์ ์ถ์
ok, bbox = tracker.update(frame)
if ok:
# ์ธก์ ๊ฐ
center_x = int(bbox[0] + bbox[2]/2)
center_y = int(bbox[1] + bbox[3]/2)
trajectory_measured.append((center_x, center_y))
# ์นผ๋ง ํํฐ ์
๋ฐ์ดํธ
kalman_tracker.update(center_x, center_y)
# ๋ฐ์ด๋ฉ ๋ฐ์ค
p1 = (int(bbox[0]), int(bbox[1]))
p2 = (int(bbox[0] + bbox[2]), int(bbox[1] + bbox[3]))
cv2.rectangle(frame, p1, p2, (0, 255, 0), 2)
# ์ธก์ ์์น (์ด๋ก)
cv2.circle(frame, (center_x, center_y), 5, (0, 255, 0), -1)
cv2.putText(frame, "Measured", (center_x + 10, center_y),
cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 255, 0), 2)
# ์์ธก ์์น (๋นจ๊ฐ)
cv2.circle(frame, (pred_x, pred_y), 5, (0, 0, 255), -1)
cv2.putText(frame, "Predicted", (pred_x + 10, pred_y),
cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 0, 255), 2)
# ๊ถค์ ๊ทธ๋ฆฌ๊ธฐ
for i in range(1, len(trajectory_measured)):
cv2.line(frame, trajectory_measured[i-1], trajectory_measured[i],
(0, 255, 0), 2)
for i in range(1, len(trajectory_predicted)):
cv2.line(frame, trajectory_predicted[i-1], trajectory_predicted[i],
(0, 0, 255), 1)
cv2.imshow("Kalman Filter Tracking", frame)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
video.release()
cv2.destroyAllWindows()
โข ๋ ธ์ด์ฆ๊ฐ ์๋ ์ธก์ ๊ฐ์ ๋ถ๋๋ฝ๊ฒ ๋ง๋ค์ด์ค
โข ๊ฐ์ฒด๊ฐ ์ผ์์ ์ผ๋ก ๊ฐ๋ ค์ ธ๋ ์์น๋ฅผ ์์ธกํ ์ ์์ด
โข ๋น ๋ฅธ ์์ง์์๋ ์์ ์ ์ผ๋ก ์ถ์ ๊ฐ๋ฅ
โข ์ค์๊ฐ ์ฒ๋ฆฌ์ ์ ํฉํ ๊ฒฝ๋ ์๊ณ ๋ฆฌ์ฆ!
๐ ์ค์ ํ๋ก์ ํธ ์์ด๋์ด
๋ฐฐ์ด ๊ฑธ ํ์ฉํด์ ๋ง๋ค ์ ์๋ ์ฌ๋ฏธ์๋ ํ๋ก์ ํธ๋ค์ ์๊ฐํ ๊ฒ! ํฌํธํด๋ฆฌ์ค๋ ์ฌ์ด๋ ํ๋ก์ ํธ๋ก ๋ฑ์ด์ผ. ๐ก
โข ์ฃผ์ฐจ ๊ณต๊ฐ ์ ์ ์ฌ๋ถ ์ค์๊ฐ ๋ชจ๋ํฐ๋ง
โข ๋ถ๋ฒ ์ฃผ์ฐจ ์๋ ๊ฐ์ง ๋ฐ ์๋ฆผ
โข ์ฃผ์ฐจ ์๊ฐ ์๋ ๊ณ์ฐ
โข ๋ฐ๋ณต ํ์ ์๋ ์นด์ดํ
โข ์๋ชป๋ ์์ธ ๊ต์ ํผ๋๋ฐฑ
โข ์ด๋ ๊ธฐ๋ก ๋ฐ ํต๊ณ ์ ๊ณต
โข ์ ์ ์์ง์ ํจํด ๋ถ์
โข ํํธ๋งต ์์ฑ
โข ํ์ด๋ผ์ดํธ ์๋ ํธ์ง
โข ์ด์ ํ๋ ๊ฐ์ง ๋ฐ ์๋ฆผ
โข ํ๋๋ ์ธก์
โข ์๋ ์์ ๋ นํ
โข ํ๊ท ์๋ ์ธก์
โข ๊ตํต ํผ์ก๋ ๋ถ์
โข ์ฌ๊ณ ์๋ ๊ฐ์ง
โข "CCTV ์์ ๋ถ์ ๋ฐ ๊ฐ์ฒด ์ถ์ ์๋ฃจ์ ๊ฐ๋ฐ"
โข "์ด๋ ์์ธ ๋ถ์ ์ฑ ๊ฐ๋ฐ"
โข "๋ง์ถคํ ๋น์ AI ์์คํ ๊ตฌ์ถ"
์ค๋ ฅ์ ์์ผ๋ฉด์ ์์ต๋ ์ฌ๋ฆด ์ ์๋ ์ผ์์ด์กฐ! ๐ฏ
๐ ๋ง๋ฌด๋ฆฌํ๋ฉฐ
์! ์ฌ๊ธฐ๊น์ง ์ ๋ง ๊ธด ์ฌ์ ์ด์์ด. ๊ณ ์ ๋ง์์ด! ๐
์ฐ๋ฆฌ๋ OpenCV๋ฅผ ์ด์ฉํ ๊ฐ์ฒด ์ถ์ ์ ๊ธฐ์ด๋ถํฐ ์ค์ ํ๋ก์ ํธ๊น์ง ๋ชจ๋ ๊ฑธ ๋ค๋ค๋ดค์ด. ๋จ์ผ ๊ฐ์ฒด ์ถ์ , ๋ค์ค ๊ฐ์ฒด ์ถ์ , ์์ ๊ธฐ๋ฐ ์ถ์ , ๊ทธ๋ฆฌ๊ณ ์นผ๋ง ํํฐ๋ฅผ ์ด์ฉํ ์์ธก๊น์ง! ์ด์ ๋๋ ์ถฉ๋ถํ ์ค์ ํ๋ก์ ํธ๋ฅผ ๋ง๋ค ์ ์์ ๊ฑฐ์ผ. ๐ช
๊ธฐ์ตํด์ผ ํ ํต์ฌ ํฌ์ธํธ:
1. ์ํฉ์ ๋ง๋ ์๊ณ ๋ฆฌ์ฆ ์ ํ
โข ์๋๊ฐ ์ค์ํ๋ฉด: MOSSE, KCF
โข ์ ํ๋๊ฐ ์ค์ํ๋ฉด: CSRT
โข ๊ท ํ์ด ํ์ํ๋ฉด: KCF
2. ์ฑ๋ฅ ์ต์ ํ๋ ํ์
โข ํ๋ ์ ํฌ๊ธฐ ์กฐ์
โข ROI ํ์ฉ
โข ๋ฉํฐ์ค๋ ๋ฉ
โข ํ๋ ์ ์คํต
3. ์คํจ ๋์ ์ ๋ต
โข ์ถ์ ์คํจ ๊ฐ์ง
โข ์๋ ์ฌ์ด๊ธฐํ
โข ์์ธก ์๊ณ ๋ฆฌ์ฆ ํ์ฉ
4. ์ค์ ํ๋ก์ ํธ๋ก ์ฐ์ต
โข ์์ ํ๋ก์ ํธ๋ถํฐ ์์
โข ์ ์ง์ ์ผ๋ก ๊ธฐ๋ฅ ์ถ๊ฐ
โข ํฌํธํด๋ฆฌ์ค ๊ตฌ์ถ
์ปดํจํฐ ๋น์ ์ ์ ๋ง ๋น ๋ฅด๊ฒ ๋ฐ์ ํ๋ ๋ถ์ผ์ผ. ์ค๋ ๋ฐฐ์ด ๋ด์ฉ์ด ๊ธฐ์ด๊ฐ ๋์ด์ ๋ ๊ณ ๊ธ ๊ธฐ์ ๋ค์ ๋ฐฐ์ธ ์ ์์ ๊ฑฐ์ผ. YOLO, Mask R-CNN, Transformer ๊ธฐ๋ฐ ์ถ์ ๋ฑ ํํํ ๊ฒ ์ ๋ง ๋ง์! ๐
ํน์ ๋งํ๋ ๋ถ๋ถ์ด ์๊ฑฐ๋ ๋ ๋ฐฐ์ฐ๊ณ ์ถ์ ๊ฒ ์๋ค๋ฉด, OpenCV ๊ณต์ ๋ฌธ์๋ GitHub์ ์คํ์์ค ํ๋ก์ ํธ๋ค์ ์ฐธ๊ณ ํด๋ด. ๊ทธ๋ฆฌ๊ณ ์ฌ๋ฅ๋ท ๊ฐ์ ํ๋ซํผ์์ ์ค์ ํ๋ก์ ํธ๋ฅผ ๊ฒฝํํด๋ณด๋ ๊ฒ๋ ์ ๋ง ์ข์ ๋ฐฉ๋ฒ์ด์ผ!
์, ์ด์ ๋์ ์ฐจ๋ก์ผ! ์ค๋ ๋ฐฐ์ด ๊ฑธ ๋ฐํ์ผ๋ก ๋ฉ์ง ํ๋ก์ ํธ๋ฅผ ๋ง๋ค์ด๋ด. ์์์ด ๋ฐ์ด๋ผ๊ณ , ์ผ๋จ ์ฝ๋๋ฅผ ์์ฑํ๊ณ ์คํํด๋ณด๋ ๊ฒ ๊ฐ์ฅ ์ค์ํด. ์คํจํด๋ ๊ด์ฐฎ์, ๊ทธ๊ฒ ๋ฐ๋ก ๋ฐฐ์์ ๊ณผ์ ์ด๋๊น! ๐
ํ์ดํ
! ๋๋ผ๋ฉด ์ถฉ๋ถํ ํ ์ ์์ด! ๐
๐ฏ ๋ค์ ๋จ๊ณ ์ถ์ฒ
1. ์ด ๊ธ์ ๋ชจ๋ ์์ ์ฝ๋๋ฅผ ์ง์ ์คํํด๋ณด๊ธฐ
2. ์์ ๋ง์ ํ๋ก์ ํธ ์์ด๋์ด ๊ตฌ์ํ๊ธฐ
3. GitHub์ ์ฝ๋ ์ฌ๋ฆฌ๊ณ ํฌํธํด๋ฆฌ์ค ๋ง๋ค๊ธฐ
4. ์ปค๋ฎค๋ํฐ์์ ๋ค๋ฅธ ๊ฐ๋ฐ์๋ค๊ณผ ๊ต๋ฅํ๊ธฐ
5. ์ค์ ํ๋ก์ ํธ์ ๋์ ํ๊ธฐ!
Happy Coding! ์ฆ๊ฑฐ์ด ์ฝ๋ฉ ๋์ธ์! ๐โจ
์ง๋ฌธ์ด๋ ํผ๋๋ฐฑ์ ์ธ์ ๋ ํ์์ด์์!
ํจ๊ป ์ฑ์ฅํ๋ ๊ฐ๋ฐ์๊ฐ ๋์ด์! ๐ป๐
๊ด๋ จ ํค์๋
๋๊ธ ์์ฑ
์ด ๊ธ์ ๋ํ ์ฌ๋ฌ๋ถ์ ์๊ฐ์ ๋ค๋ ค์ฃผ์ธ์
๋ก๊ทธ์ธ์ด ํ์ํฉ๋๋ค
๋๊ธ์ ์์ฑํ๋ ค๋ฉด ๋จผ์ ๋ก๊ทธ์ธํด์ฃผ์ธ์.
๋๊ธ 0
์ง์์ธ์ ์ฒ - ์ง์ ์ฌ์ฐ๊ถ ๋ณดํธ ๊ณ ์ง
์ง์ ์ฌ์ฐ๊ถ ๋ณดํธ ๊ณ ์ง
- ์ ์๊ถ ๋ฐ ์์ ๊ถ: ๋ณธ ์ปจํ ์ธ ๋ ์ฌ๋ฅ๋ท์ ๋ ์ AI ๊ธฐ์ ๋ก ์์ฑ๋์์ผ๋ฉฐ, ๋ํ๋ฏผ๊ตญ ์ ์๊ถ๋ฒ ๋ฐ ๊ตญ์ ์ ์๊ถ ํ์ฝ์ ์ํด ๋ณดํธ๋ฉ๋๋ค.
- AI ์์ฑ ์ปจํ ์ธ ์ ๋ฒ์ ์ง์: ๋ณธ AI ์์ฑ ์ปจํ ์ธ ๋ ์ฌ๋ฅ๋ท์ ์ง์ ์ฐฝ์๋ฌผ๋ก ์ธ์ ๋๋ฉฐ, ๊ด๋ จ ๋ฒ๊ท์ ๋ฐ๋ผ ์ ์๊ถ ๋ณดํธ๋ฅผ ๋ฐ์ต๋๋ค.
- ์ฌ์ฉ ์ ํ: ์ฌ๋ฅ๋ท์ ๋ช ์์ ์๋ฉด ๋์ ์์ด ๋ณธ ์ปจํ ์ธ ๋ฅผ ๋ณต์ , ์์ , ๋ฐฐํฌ, ๋๋ ์์ ์ ์ผ๋ก ํ์ฉํ๋ ํ์๋ ์๊ฒฉํ ๊ธ์ง๋ฉ๋๋ค.
- ๋ฐ์ดํฐ ์์ง ๊ธ์ง: ๋ณธ ์ปจํ ์ธ ์ ๋ํ ๋ฌด๋จ ์คํฌ๋ํ, ํฌ๋กค๋ง, ๋ฐ ์๋ํ๋ ๋ฐ์ดํฐ ์์ง์ ๋ฒ์ ์ ์ฌ์ ๋์์ด ๋ฉ๋๋ค.
- AI ํ์ต ์ ํ: ์ฌ๋ฅ๋ท์ AI ์์ฑ ์ปจํ ์ธ ๋ฅผ ํ AI ๋ชจ๋ธ ํ์ต์ ๋ฌด๋จ ์ฌ์ฉํ๋ ํ์๋ ๊ธ์ง๋๋ฉฐ, ์ด๋ ์ง์ ์ฌ์ฐ๊ถ ์นจํด๋ก ๊ฐ์ฃผ๋ฉ๋๋ค.
์์ง ๋๊ธ์ด ์์ต๋๋ค.