خبر و ترفند روز

خبر و ترفند های روز را اینجا بخوانید!

نحوه پیاده‌سازی تثبیت‌کننده ویدیوی بلادرنگ با استفاده از OpenCV

از این تکنیک برای اعمال ریاضیات هوشمندانه در ویدیوهای خود و کاهش لرزش استفاده کنید.

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

هدف اصلی تثبیت کننده ویدیو تخمین حرکت دوربین بین فریم های متوالی است. سپس این فرآیند می تواند تبدیل های مناسب را برای تراز کردن فریم ها اعمال کند. این حرکت درک شده را به حداقل می رساند.

تنظیم محیط

با ایجاد یک محیط مجازی شروع کنید تا مطمئن شوید بسته هایی که برای اجرای برنامه نصب می کنید با بسته های موجود تضاد ندارند. سپس این دستور ترمینال را برای نصب کتابخانه های مورد نیاز اجرا کنید:

pip install opencv-python numpy

این دستور کتابخانه های NumPy و OpenCV را نصب می کند. NumPy ابزارهایی را برای کارهای عددی فراهم می کند در حالی که OpenCV با وظایف بینایی رایانه سروکار دارد.

کد منبع کامل در یک مخزن GitHub موجود است.

واردات کتابخانه های مورد نیاز و تعریف سه کارکرد حیاتی

یک فایل پایتون جدید ایجاد کنید و نام دلخواه خود را به آن بدهید. کتابخانه های NumPy و OpenCV را در ابتدای اسکریپت وارد کنید.

import numpy as np
import cv2

وارد کردن این کتابخانه ها به شما امکان می دهد از توابع آنها در کد خود استفاده کنید.

در مرحله بعد، سه عملکرد را تعریف کنید که برای فرآیند تثبیت بسیار مهم هستند.

تابع محاسبه_حرکت_میانگین

یک تابع ایجاد کنید و نام آن را account_moving_average بگذارید. این تابع میانگین متحرک یک منحنی معین را با استفاده از شعاع مشخص شده شما محاسبه می کند. از یک عملیات کانولوشن با اندازه پنجره مشخص و یک هسته یکنواخت استفاده می کند. این میانگین متحرک به هموار کردن نوسانات در مسیر کمک می کند.

def calculate_moving_average(curve, radius):
    # Calculate the moving average of a curve using a given radius
    window_size = 2 * radius + 1
    kernel = np.ones(window_size) / window_size
    curve_padded = np.lib.pad(curve, (radius, radius), 'edge')
    smoothed_curve = np.convolve(curve_padded, kernel, mode='same')
    smoothed_curve = smoothed_curve[radius:-radius]
    return smoothed_curve

تابع یک منحنی صاف برمی گرداند. به کاهش نویز و نوسانات در منحنی کمک می کند. این کار را با میانگین گیری مقادیر درون پنجره کشویی انجام می دهد.

مطلب مرتبط:   نحوه ایجاد یک RSS Reader ساده با SvelteKit

تابع smooth_trajectory

یک تابع دیگر ایجاد کنید و نام آن را smooth_trajectory بگذارید. این تابع میانگین متحرک را در هر بعد از مسیر اعمال می کند. با ایجاد یک کپی هموار از مسیر اصلی به این امر دست خواهد یافت. این باعث بهبود بیشتر پایداری ویدیو می شود.

def smooth_trajectory(trajectory):
    # Smooth the trajectory using moving average on each dimension
    smoothed_trajectory = np.copy(trajectory)

    for i in range(3):
        smoothed_trajectory[:, i] = calculate_moving_average(
            trajectory[:, i],
            radius=SMOOTHING_RADIUS
        )

    return smoothed_trajectory

تابع smooth_trajectory یک مسیر صاف شده را برمی گرداند.

تابع fix_border

یک تابع نهایی ایجاد کنید و نام آن را fix_border بگذارید. این تابع با اعمال یک چرخش و تغییر مقیاس، مرز قاب را ثابت می کند. قاب ورودی را می گیرد، شکل آن را محاسبه می کند، یک ماتریس تبدیل ایجاد می کند و تبدیل را روی قاب اعمال می کند. در نهایت فریم ثابت را برمی گرداند.

def fix_border(frame):
    # Fix the frame border by applying rotation and scaling transformation
    frame_shape = frame.shape
   
    matrix = cv2.getRotationMatrix2D(
        (frame_shape[1] / 2, frame_shape[0] / 2),
        0,
        1.04
    )

    frame = cv2.warpAffine(frame, matrix, (frame_shape[1], frame_shape[0]))
    return frame

تابع fix_border تضمین می‌کند که فریم‌های تثبیت‌شده هیچ گونه آرتیفکت حاشیه‌ای ناشی از فرآیند تثبیت ندارند.

راه اندازی تثبیت ویدئو و گرفتن ورودی

با تنظیم شعاعی که تابع هموارسازی مسیر استفاده می کند، شروع کنید.

SMOOTHING_RADIUS = 50

سپس، از مسیر ویدیویی ویدیویی لرزان که می‌خواهید تثبیت کنید عبور کنید.

# Open the input video file
# Replace the path with 0 to use your webcam
cap = cv2.VideoCapture('inputvid.mp4')

ویژگی های ویدیوی لرزان را دریافت کنید:

num_frames = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))
width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
fps = cap.get(cv2.CAP_PROP_FPS)

فرمت خروجی را تنظیم کنید. این فرمتی است که برنامه ویدیوی تثبیت شده را با آن ذخیره می کند. می توانید از هر فرمت ویدیویی رایجی که دوست دارید استفاده کنید.

fourcc = cv2.VideoWriter_fourcc(*'mp4v')

در نهایت، نویسنده ویدیو را مقداردهی اولیه کنید:

out = cv2.VideoWriter('video_out.mp4', fourcc, fps, (2 * width, height))

پسوند نام فایلی که به برنامه نویس ویدیو ارسال می کنید باید با نامی باشد که در فرمت خروجی تنظیم کرده اید.

خواندن و پردازش فریم ها

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

مطلب مرتبط:   چگونه با عکس های غذای خود یک ویدیوی استاپ موشن ایجاد کنیم

با خواندن فریم اول شروع کنید.

_, prev_frame = cap.read()
prev_gray = cv2.cvtColor(prev_frame, cv2.COLOR_BGR2GRAY)

سپس آرایه تبدیل را مقداردهی اولیه کنید. اطلاعات مربوط به هر فریم را ذخیره می کند.

transforms = np.zeros((num_frames - 1, 3), np.float32)

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

for i in range(num_frames - 2):
    # Calculate optical flow between consecutive frames
    prev_points = cv2.goodFeaturesToTrack(
        prev_gray,
        maxCorners=200,
        qualityLevel=0.01,
        minDistance=30,
        blockSize=3
    )

    success, curr_frame = cap.read()

    if not success:
        break

    curr_gray = cv2.cvtColor(curr_frame, cv2.COLOR_BGR2GRAY)

    curr_points, status, err = cv2.calcOpticalFlowPyrLK(
        prev_gray,
        curr_gray,
        prev_points,
        None
    )

    assert prev_points.shape == curr_points.shape
    idx = np.where(status == 1)[0]
    prev_points = prev_points[idx]
    curr_points = curr_points[idx]

    # Estimate affine transformation between the points
    matrix, _ = cv2.estimateAffine2D(prev_points, curr_points)
    translation_x = matrix[0, 2]
    translation_y = matrix[1, 2]
    rotation_angle = np.arctan2(matrix[1, 0], matrix[0, 0])
    transforms[i] = [translation_x, translation_y, rotation_angle]
    prev_gray = curr_gray

حلقه روی هر فریم (به جز آخرین فریم) برای محاسبه تبدیل ها تکرار می شود. جریان نوری بین فریم های متوالی را با استفاده از روش لوکاس-کاناد محاسبه می کند. cv2.goodFeaturesToTrack نقاط ویژگی را در قاب قبلی prev_gray تشخیص می دهد. سپس، cv2.calcOpticalFlowPyrLK این نقاط را در فریم فعلی curr_gray ردیابی می کند.

فقط نقاط با وضعیت 1 (نشان دهنده ردیابی موفق) به تخمین ماتریس تبدیل افین کمک می کنند. کد، متغیر prev_gray را با فریم مقیاس خاکستری فعلی برای تکرار بعدی به روز می کند.

هموارسازی مسیر

برای دستیابی به یک نتیجه پایدار، باید مسیر به دست آمده از تحولات را هموار کنید.

# Calculate the trajectory by cumulatively summing the transformations
trajectory = np.cumsum(transforms, axis=0)

# Smooth the trajectory using moving average
smoothed_trajectory = smooth_trajectory(trajectory)

# Calculate the difference between the smoothed and original trajectory
difference = smoothed_trajectory - trajectory

# Add the difference back to the original transformations to obtain smooth
# transformations
transforms_smooth = transforms + difference

کد بالا مسیر حرکت دوربین را محاسبه کرده و آن را صاف می کند.

تثبیت و نوشتن قاب ها

مرحله آخر تثبیت فریم ها و نوشتن فیلم تثبیت شده در یک فایل خروجی است.

با تنظیم مجدد ضبط ویدیو شروع کنید. این اطمینان حاصل می کند که عملیات آینده از ابتدای ویدیو خوانده می شود.

cap.set(cv2.CAP_PROP_POS_FRAMES, 0)

سپس با پردازش هر فریم ویدیو را تثبیت کنید.

# Process each frame and stabilize the video
for i in range(num_frames - 2):
    success, frame = cap.read()

    if not success:
        break

    translation_x = transforms_smooth[i, 0]
    translation_y = transforms_smooth[i, 1]
    rotation_angle = transforms_smooth[i, 2]

    # Create the transformation matrix for stabilization
    transformation_matrix = np.zeros((2, 3), np.float32)
    transformation_matrix[0, 0] = np.cos(rotation_angle)
    transformation_matrix[0, 1] = -np.sin(rotation_angle)
    transformation_matrix[1, 0] = np.sin(rotation_angle)
    transformation_matrix[1, 1] = np.cos(rotation_angle)
    transformation_matrix[0, 2] = translation_x
    transformation_matrix[1, 2] = translation_y

    # Apply the transformation to stabilize the frame
    frame_stabilized = cv2.warpAffine(
        frame,
        transformation_matrix,
        (width, height)
    )

    # Fix the border of the stabilized frame
    frame_stabilized = fix_border(frame_stabilized)

    # Concatenate the original and stabilized frames side by side
    frame_out = cv2.hconcat([frame, frame_stabilized])

    # Resize the frame if its width exceeds 1920 pixels
    if frame_out.shape[1] > 1920:
        frame_out = cv2.resize(
            frame_out,
            (frame_out.shape[1] // 2, frame_out.shape[0] // 2)
        )

    # Display the before and after frames
    cv2.imshow("Before and After", frame_out)
    cv2.waitKey(10)

    # Write the frame to the output video file
    out.write(frame_out)

کد بالا با استفاده از تبدیل های محاسبه شده، از جمله تنظیمات ترجمه و چرخش، هر فریم را تثبیت می کند. سپس فریم های تثبیت شده را با فریم های اصلی ترکیب می کند تا مقایسه ای ارائه دهد.

مطلب مرتبط:   نحوه استفاده از گره های RayCast2D برای تشخیص خط دید در گودو

انتشار فیلم ضبط و نویسنده

با آزاد کردن اشیاء ضبط ویدیو و نویسنده، برنامه را نهایی کنید.

# Release the video capture and writer, and close any open windows
cap.release()
out.release()
cv2.destroyAllWindows()

این کد همچنین تمامی پنجره های باز را می بندد.

خروجی نهایی برنامه

خروجی برنامه چیزی شبیه به این خواهد بود:

خروجی تثبیت کننده ویدئو در Pycharm IDE

و در اینجا نمونه ای از ویدئوی تثبیت شده است:

خروجی مقایسه بین فیلم لرزان و تثبیت شده را نشان می دهد.

قابلیت های OpenCV را کاوش کنید

شما می توانید OpenCV را در بسیاری از زمینه هایی که شامل بینایی کامپیوتری هستند، اعمال کنید. این به این دلیل است که طیف گسترده ای از عملکردها را ارائه می دهد. شما باید توانایی های آن را با کار بر روی پروژه های بیشتری که شامل بینایی کامپیوتری می شوند، کشف کنید. این شما را با مفاهیم جدید آشنا می کند و زمینه های جدیدی را برای تحقیق در مورد آنها به شما می دهد.