ویژگی‌های رابط کاربری در OpenCV

شروع کار با ویدیوها

۵ دقیقه مطالعهOpenCV 5.xبه‌روزرسانی:

هدف#

  • یادگیری خواندن، نمایش و ذخیره ویدیو.
  • یادگیری دریافت ویدیو از دوربین و نمایش آن.
  • با این توابع آشنا خواهید شد: ()cv.VideoCapture، ()cv.VideoWriter

دریافت ویدیو از دوربین#

اغلب اوقات، ما نیاز داریم جریان زنده تصویر (Live Stream) را از دوربین ضبط کنیم. کتابخانه OpenCV رابط بسیار ساده‌ای برای این کار فراهم می‌کند. بیایید ویدیویی از دوربین دریافت کنیم (من از وب‌کم داخلی لپ‌تاپم استفاده می‌کنم)، آن را به ویدیوی خاکستری (Grayscale) تبدیل کرده و نمایش دهیم؛ یک کار ساده برای شروع.

برای دریافت ویدیو، ابتدا باید یک شیء از نوع VideoCapture بسازید. آرگومان آن می‌تواند اندیس دستگاه (Device Index) یا نام فایل ویدیویی باشد. اندیس دستگاه فقط عددی است که مشخص می‌کند کدام دوربین مد نظر است. معمولاً یک دوربین متصل است (مانند مورد من)، بنابراین من به سادگی مقدار 0 (یا 1-) را ارسال می‌کنم. می‌توانید با ارسال عدد 1 دوربین دوم را انتخاب کنید و به همین ترتیب. پس از آن، می‌توانید فریم به فریم ویدیو را دریافت کنید. اما در انتها، فراموش نکنید که شیء دریافت تصویر را آزاد (release) کنید.

import numpy as np
import cv2 as cv

cap = cv.VideoCapture(0)
if not cap.isOpened():
    print("Cannot open camera")
    exit()
while True:
    # Capture frame-by-frame
    ret, frame = cap.read()

    # if frame is read correctly ret is True
    if not ret:
        print("Can't receive frame (stream end?). Exiting ...")
        break
    # Our operations on the frame come here
    gray = cv.cvtColor(frame, cv.COLOR_BGR2GRAY)
    # Display the resulting frame
    cv.imshow('frame', gray)
    if cv.waitKey(1) == ord('q'):
        break

# When everything done, release the capture
cap.release()
cv.destroyAllWindows()

متد ()cap.read یک مقدار بولی (True/False) برمی‌گرداند. اگر فریم به درستی خوانده شود، مقدار آن True خواهد بود. بنابراین می‌توانید با بررسی این مقدار بازگشتی، رسیدن به پایان ویدیو را متوجه شوید.

گاهی اوقات، ممکن است cap دریافت ویدیو را به درستی مقداردهی اولیه نکرده باشد. در این حالت، این کد خطا نشان می‌دهد. می‌توانید با متد ()cap.isOpened بررسی کنید که آیا مقداردهی شده است یا خیر. اگر مقدار True باشد، همه چیز آماده است؛ در غیر این صورت آن را با استفاده از ()cap.open باز کنید.

همچنین می‌توانید با استفاده از متد (cap.get(propId به برخی ویژگی‌های این ویدیو دسترسی داشته باشید، که در آن propId عددی بین 0 تا 18 است. هر عدد نشان‌دهنده یکی از ویژگی‌های ویدیو است (در صورتی که برای آن ویدیو قابل اعمال باشد). جزئیات کامل را می‌توان در اینجا مشاهده کرد: ()cv::VideoCapture::get. برخی از این مقادیر را می‌توان با استفاده از (cap.set(propId, value تغییر داد. مقدار value همان مقدار جدیدی است که می‌خواهید تنظیم کنید.

به عنوان مثال، می‌توانم عرض و ارتفاع فریم را با (cap.get(cv.CAP_PROP_FRAME_WIDTH و (cap.get(cv.CAP_PROP_FRAME_HEIGHT بررسی کنم. به طور پیش‌فرض مقدار 640x480 را به من می‌دهد. اما من می‌خواهم آن را به 320x240 تغییر دهم. کافی است از ret = cap.set(cv.CAP_PROP_FRAME_WIDTH,320) و ret = cap.set(cv.CAP_PROP_FRAME_HEIGHT,240) استفاده کنید.

پخش ویدیو از فایل#

پخش ویدیو از یک فایل مشابه دریافت آن از دوربین است، تنها کافی است اندیس دوربین را به نام فایل ویدیو تغییر دهید. همچنین هنگام نمایش فریم، زمان مناسبی را برای ()cv.waitKey در نظر بگیرید. اگر زمان بیش از حد کم باشد، ویدیو بسیار سریع پخش خواهد شد و اگر بیش از حد زیاد باشد، ویدیو با سرعت آهسته حرکت خواهد کرد (در واقع، به همین روش می‌توانید ویدیوها را در حالت اسلوموشن نمایش دهید). مقدار ۲۵ میلی‌ثانیه در شرایط عادی مناسب خواهد بود.

import numpy as np
import cv2 as cv

cap = cv.VideoCapture('vtest.avi')

while cap.isOpened():
    ret, frame = cap.read()

    # if frame is read correctly ret is True
    if not ret:
        print("Can't receive frame (stream end?). Exiting ...")
        break
    gray = cv.cvtColor(frame, cv.COLOR_BGR2GRAY)

    cv.imshow('frame', gray)
    if cv.waitKey(1) == ord('q'):
        break

cap.release()
cv.destroyAllWindows()

ذخیره یک ویدیو#

بنابراین ما یک ویدیو را ضبط کرده و آن را فریم به فریم پردازش می‌کنیم، و می‌خواهیم آن ویدیو را ذخیره کنیم. برای تصاویر، این کار بسیار ساده است: فقط از ()cv.imwrite استفاده می‌کنیم. در اینجا، کمی کار بیشتری لازم است.

این بار ما یک شیء VideoWriter ایجاد می‌کنیم. باید نام فایل خروجی را مشخص کنیم (مثلاً: output.avi). سپس باید کد FourCC را تعیین کنیم (جزئیات در پاراگراف بعدی). سپس تعداد فریم در ثانیه (fps) و اندازه فریم باید ارسال شوند. و آخرین مورد فلگ isColor است. اگر True باشد، انکودر انتظار فریم رنگی دارد، در غیر این صورت با فریم در مقیاس خاکستری کار می‌کند.

کد FourCC یک شناسه ۴ بایتی است که برای مشخص کردن کدک ویدیویی استفاده می‌شود. فهرست کدهای موجود را می‌توان در fourcc.org یافت. این کد وابسته به پلتفرم است. کدک‌های زیر برای من به خوبی کار می‌کنند:

  • در فدورا: DIVX, XVID, MJPG, X264, WMV1, WMV2. (کدک XVID ترجیح داده می‌شود. کدک MJPG منجر به حجم زیاد ویدیو می‌شود. کدک X264 حجم بسیار پایینی تولید می‌کند)
  • در ویندوز: DIVX (موارد بیشتر باید تست و افزوده شوند)
  • در OSX (مک): MJPG (.mp4), DIVX (.avi), X264 (.mkv).

کد FourCC به صورت ('cv.VideoWriter_fourcc('M','J','P','G یا (*'cv.VideoWriter_fourcc(*'MJPG برای MJPG ارسال می‌شود.

کد زیر تصویر را از دوربین دریافت کرده، هر فریم را در راستای عمودی معکوس (flip) می‌کند و ویدیو را ذخیره می‌نماید.

import numpy as np
import cv2 as cv

cap = cv.VideoCapture(0)

# Get camera frame resolution
frame_width = int(cap.get(cv.CAP_PROP_FRAME_WIDTH))
frame_height = int(cap.get(cv.CAP_PROP_FRAME_HEIGHT))

# Define the codec and create VideoWriter object
fourcc = cv.VideoWriter_fourcc(*'XVID')
out = cv.VideoWriter('output.avi', fourcc, 20.0, (frame_width, frame_height))

while cap.isOpened():
    ret, frame = cap.read()
    if not ret:
        print("Can't receive frame (stream end?). Exiting ...")
        break
    frame = cv.flip(frame, 0)

    # write the flipped frame
    out.write(frame)

    cv.imshow('frame', frame)
    if cv.waitKey(1) == ord('q'):
        break

# Release everything if job is finished
cap.release()
out.release()
cv.destroyAllWindows()