تشخیص حرکت با OpenCV و پایتون

آموزش ساخت سیستم تشخیص حرکت با OpenCV و پایتون - پردازش ویدئو و شناسایی اشیاء متحرک

۴ دقیقه مطالعه
فهرست مطالب
این مطلب از سایت tool.hamidvalad.ir گرفته شده است

تشخیص حرکت با OpenCV

تشخیص حرکت یکی از آن مفاهیمی است که شاید در ظاهر ساده به نظر برسد اما در عمل یکی از پایه‌های اصلی بسیاری از سیستم‌های هوشمند امروزی است. هر زمان اسم دوربین امنیتی، سیستم تشخیص ورود، ردیابی حیوانات خانگی، تحلیل رفتار مشتری، یا حتی پردازش ویدئوهای ورزشی به میان می‌آید، در پشت پرده یک الگوریتم تشخیص حرکت وجود دارد که تغییرات صحنه را بررسی کرده و مشخص می‌کند چه چیزی در حال جابه‌جایی است. در این پروژه قصد داریم با استفاده از پایتون و کتابخانه قدرتمند OpenCV یک نمونه واقعی و کاربردی از سیستم تشخیص حرکت بسازیم؛ سیستمی که ویدیو را فریم به فریم بررسی می‌کند، تغییرات را تشخیص می‌دهد و دور بخش‌هایی که حرکت رخ داده یک باکس مشخص رسم می‌کند.

این پروژه برای افرادی که تازه وارد دنیای Computer Vision شده‌اند یک شروع فوق‌العاده است، چون هم ساختارش خیلی پیچیده نیست و هم از مهم‌ترین مفاهیم پردازش تصویر استفاده می‌کند. در کنار این، خروجی یک ویدیو قابل پخش و واقعی است که کاربر می‌تواند نتیجه نهایی را به‌صورت ملموس مشاهده کند. همین موضوع باعث می‌شود یادگیری نه فقط آموزشی بلکه کاربردی و تجربی باشد. برای اجرای این پروژه تنها به سه کتابخانه نیاز داریم: OpenCV برای پردازش تصویر و ویدیو، NumPy برای کار با ماتریس‌ها و ساخت kernel عملیات Erosion، و OS برای بررسی وجود فایل ورودی. برای نصب کتابخانه‌ها کافی است از دستور pip install opencv-python numpy استفاده کنیم.

ایده اصلی پروژه این است که ابتدا ویدیو بارگذاری می‌شود و سپس با استفاده از تکنیک Background Subtraction تغییرات صحنه تحلیل می‌شود. ما در این پروژه از روش KNN استفاده کرده‌ایم که نسبت به تغییرات نور و سایه‌ها مقاوم‌تر است و به‌خوبی می‌تواند محیط را فریم به فریم یاد بگیرد. سپس برای حذف نویزها و نقاط پراکنده، از عملیات Erosion استفاده می‌کنیم. در نهایت اگر حرکتی وجود داشته باشد، با استفاده از bounding box آن را مشخص کرده و فریم پردازش‌شده را در یک فایل خروجی ذخیره می‌کنیم.

کد کامل پروژه

import cv2
import numpy as np
import os

# ------------------ تنظیمات اصلی ------------------
input_video = "home_dog.mp4"
output_video = "output_eroded.mp4"

# چک کردن وجود فایل ورودی
if not os.path.exists(input_video):
    print(f"❌ فایل {input_video} پیدا نشد!")
    exit()

# ------------------ باز کردن ویدیو ------------------
video_cap = cv2.VideoCapture(input_video)
if not video_cap.isOpened():
    print("❌ امکان باز کردن ویدیو وجود ندارد.")
    exit()

# ------------------ مشخصات ویدیو ------------------
frame_w = int(video_cap.get(cv2.CAP_PROP_FRAME_WIDTH)) // 2
frame_h = int(video_cap.get(cv2.CAP_PROP_FRAME_HEIGHT)) // 2
fps = int(video_cap.get(cv2.CAP_PROP_FPS))

# ------------------ ساخت VideoWriter ------------------
video_out = cv2.VideoWriter(
    output_video,
    cv2.VideoWriter_fourcc(*"mp4v"),
    fps,
    (frame_w, frame_h)
)

# Background Subtractor - روش KNN
bg_sub = cv2.createBackgroundSubtractorKNN(history=6000)

# Kernel برای Erosion
kernel = np.ones((5, 5), np.uint8)

red = (0, 0, 255)

print("🎥 پردازش ویدیو شروع شد...")

# ------------------ پردازش فریم‌ها ------------------
while True:
    ret, frame = video_cap.read()
    if not ret:
        break

    # تشخیص حرکت با کم کردن پس‌زمینه
    fg_mask = bg_sub.apply(frame)

    # حذف نویز با Erosion
    fg_mask_erode = cv2.erode(fg_mask, kernel)

    # پیدا کردن پیکسل‌های متحرک
    motion_area = cv2.findNonZero(fg_mask_erode)

    # اگر حرکتی دیده شد → باکس بکش
    if motion_area is not None:
        x, y, w, h = cv2.boundingRect(motion_area)
        cv2.rectangle(frame, (x, y), (x + w, y + h), red, 3)

    # تغییر اندازه خروجی
    frame_resized = cv2.resize(frame, (frame_w, frame_h))

    # نوشتن در ویدیو
    video_out.write(frame_resized)

# ------------------ بستن فایل‌ها ------------------
video_cap.release()
video_out.release()

print(f"✅ پردازش تمام شد! ویدیو ذخیره شد → {output_video}")
print("🔥 فایل آماده پخش است.")

نکات مهم کد

استفاده از KNN برای تشخیص پس‌زمینه
یکی از مهم‌ترین بخش‌های پروژه استفاده از KNN به‌عنوان روش تشخیص پس‌زمینه است. این روش برخلاف Gaussian ساده، پایداری بیشتری دارد و به مرور زمان صحنه را یاد می‌گیرد. همین موضوع باعث می‌شود خطاهای ناشی از تغییر نور، سایه‌ها یا افت کیفیت تصویر تا حد زیادی کمتر شود.

عملیات Erosion برای حذف نویز
استفاده از Erosion هم اهمیت زیادی دارد. بدون این مرحله، ماسکی که از بک‌گراند سابترکشن تولید می‌شود معمولاً پر از نقاط پراکنده و نویزهای کوچک است. Erosion باعث می‌شود این نقاط حذف شوند و فقط بخش‌هایی باقی بماند که واقعاً حرکت مهمی داشته‌اند.

بهینه‌سازی اندازه ویدیو
کاهش اندازه خروجی ویدیو نیز به بهبود سرعت و کاهش حجم خروجی کمک می‌کند. نصف کردن ابعاد باعث می‌شود پردازش سریع‌تر انجام شود، مخصوصاً اگر سیستم سخت‌افزاری ضعیف‌تری داشته باشد.

بررسی وجود فایل ورودی
نکته دیگر این است که قبل از شروع پردازش، وجود فایل ورودی بررسی می‌شود تا کاربر با خطاهای ناگهانی روبه‌رو نشود.

مدیریت حافظه و منابع
کد به درستی از متدهای release() برای آزادسازی منابع استفاده می‌کند که از leak شدن حافظه جلوگیری می‌کند.

پارامترهای بهینه KNN
مقدار history=6000 باعث می‌شود مدل حافظه بلندمدت‌تری از صحنه داشته باشد و در تشخیص حرکت پایدارتر عمل کند.

نتیجه‌گیری

این پروژه نمونه‌ای ساده اما بسیار کاربردی از تشخیص حرکت است؛ پروژه‌ای که علاوه بر یادگیری مفاهیم پایه، خروجی ملموس و حرفه‌ای نیز تولید می‌کند. این تمرین می‌تواند پایه‌ای برای پروژه‌های پیشرفته‌تر مثل تشخیص چهره، ردیابی اشیا، ساخت سیستم امنیتی هوشمند یا تحلیل‌های تصویری باشد.

اگر کاربر بخواهد می‌تواند همین کد را گسترش دهد و امکاناتی مثل ذخیره لحظه حرکت، ارسال هشدار، یا اتصال به دوربین زنده را به آن اضافه کند. پردازش تصویر دنیای بسیار جذابی دارد و این پروژه یکی از بهترین نقطه‌های شروع برای ورود به آن است.

این کد نه تنها برای اهداف آموزشی مناسب است، بلکه می‌تواند به عنوان هسته اصلی سیستم‌های نظارتی ساده مورد استفاده قرار گیرد. ترکیب تکنیک‌های به کار رفته در این پروژه - Background Subtraction با KNN، عملیات مورفولوژیکی Erosion و رسم bounding box - یک پایه محکم برای ساخت برنامه‌های پیچیده‌تر تشخیص حرکت فراهم می‌کند.