Cách triển khai Ổn định video theo thời gian thực bằng OpenCV
Ổn định video là một kỹ thuật làm giảm chuyển động và rung lắc không mong muốn trong cảnh quay video. Chụp cầm tay, rung và chuyển động đều có thể khiến máy ảnh chuyển động không ổn định. Tính năng ổn định video giúp video trông mượt mà hơn.
Mục tiêu chính của ổn định video là ước tính chuyển động của máy ảnh giữa các khung hình liên tiếp. Sau đó, quy trình có thể áp dụng các phép biến đổi thích hợp để căn chỉnh các khung. Điều này giảm thiểu chuyển động nhận thức.
Mục Lục
Thiết lập môi trường của bạn
Bắt đầu bằng cách tạo một môi trường ảo để đảm bảo các gói bạn cài đặt để chạy chương trình không xung đột với các gói hiện có. Sau đó chạy lệnh đầu cuối này để cài đặt các thư viện cần thiết:
pip install opencv-python numpy
Lệnh này cài đặt các thư viện NumPy và OpenCV. NumPy cung cấp các công cụ cho các tác vụ số trong khi OpenCV xử lý các tác vụ thị giác máy tính.
Nhập các thư viện cần thiết và xác định ba chức năng quan trọng
Tạo một tệp Python mới và đặt tên cho nó theo ý thích của bạn. Nhập thư viện NumPy và OpenCV vào đầu tập lệnh.
import numpy as np
import cv2
Việc nhập các thư viện này sẽ cho phép bạn sử dụng các chức năng của chúng trong mã của mình.
Tiếp theo, xác định ba chức năng sẽ rất quan trọng cho quá trình ổn định.
Hàm tính toán_moving_average
Tạo một chức năng và đặt tên cho nó tính toán_moving_average. Hàm này sẽ tính toán đường trung bình động của một đường cong đã cho bằng cách sử dụng bán kính mà bạn chỉ định. Nó sử dụng thao tác tích chập với kích thước cửa sổ được chỉ định và hạt nhân đồng nhất. Đường trung bình động này giúp làm phẳng các dao động trong quỹ đạo.
def calculate_moving_average(curve, 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
Hàm trả về một đường cong mượt mà. Nó giúp giảm tiếng ồn và dao động trong đường cong. Nó thực hiện điều này bằng cách tính trung bình các giá trị trong cửa sổ trượt.
Hàm smooth_trajectory
Tạo một chức năng khác và đặt tên cho nó smooth_trajectory. Hàm này sẽ áp dụng đường trung bình động trên mỗi chiều của quỹ đạo. Nó sẽ đạt được điều này bằng cách tạo ra một bản sao mượt mà của quỹ đạo ban đầu. Điều này sẽ cải thiện hơn nữa tính ổn định của video.
def smooth_trajectory(trajectory):
smoothed_trajectory = np.copy(trajectory) for i in range(3):
smoothed_trajectory[:, i] = calculate_moving_average(
trajectory[:, i],
radius=SMOOTHING_RADIUS
)
return smoothed_trajectory
Các smooth_trajectory chức năng trả về một quỹ đạo trơn tru.
Hàm fix_border
Tạo một chức năng cuối cùng và đặt tên cho nó sửa_biên. Chức năng này sẽ cố định đường viền của khung bằng cách áp dụng phép biến đổi xoay và chia tỷ lệ. Nó lấy khung đầu vào, tính toán hình dạng của nó, xây dựng ma trận biến đổi và áp dụng phép biến đổi cho khung. Cuối cùng, nó trả về khung cố định.
def fix_border(frame):
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
Các sửa_biên chức năng đảm bảo rằng các khung ổn định không có bất kỳ giả tạo đường viền nào do quá trình ổn định gây ra.
Khởi tạo ổn định video và lấy đầu vào
Bắt đầu bằng cách đặt bán kính mà chức năng làm mịn quỹ đạo sẽ sử dụng.
SMOOTHING_RADIUS = 50
Sau đó, chuyển vào đường dẫn video của video bị rung mà bạn muốn ổn định.
cap = cv2.VideoCapture('inputvid.mp4')
Nhận các thuộc tính của video bị rung:
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)
Đặt định dạng đầu ra. Đây là định dạng mà chương trình sẽ lưu video ổn định. Bạn có thể sử dụng bất kỳ định dạng video phổ biến nào mà bạn thích.
fourcc = cv2.VideoWriter_fourcc(*'mp4v')
Cuối cùng, khởi tạo trình ghi video:
out = cv2.VideoWriter('video_out.mp4', fourcc, fps, (2 * width, height))
Phần mở rộng của tên tệp bạn chuyển đến trình ghi video phải giống với phần mở rộng bạn đặt ở định dạng đầu ra.
Đọc và xử lý khung
Bước đầu tiên để xử lý video bị rung bắt đầu từ đây. Nó liên quan đến việc đọc các khung hình từ video đầu vào, tính toán các phép biến đổi và điền vào mảng các phép biến đổi.
Bắt đầu bằng cách đọc khung đầu tiên.
_, prev_frame = cap.read()
prev_gray = cv2.cvtColor(prev_frame, cv2.COLOR_BGR2GRAY)
Sau đó khởi tạo mảng chuyển đổi. Nó sẽ lưu trữ thông tin cho từng khung hình.
transforms = np.zeros((num_frames - 1, 3), np.float32)
Cuối cùng, bạn cần tính toán luồng quang giữa các khung hình liên tiếp. Sau đó, ước tính phép biến đổi affine giữa các điểm.
for i in range(num_frames - 2):
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]
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
Vòng lặp lặp lại trên mỗi khung hình (ngoại trừ khung hình cuối cùng) để tính toán các phép biến đổi. Nó tính toán luồng quang giữa các khung liên tiếp bằng phương pháp Lucas-Kanade. cv2.goodFeaturesToTrack phát hiện các điểm đặc trưng trong khung hình trước đó prev_gray. Sau đó, cv2.calcOpticalFlowPyrLK theo dõi những điểm này trong khung hình hiện tại curr_gray.
Chỉ những điểm có trạng thái 1 (biểu thị theo dõi thành công) mới giúp ước tính ma trận biến đổi affine. Mã cập nhật các prev_gray biến với khung thang độ xám hiện tại cho lần lặp lại tiếp theo.
Làm mịn quỹ đạo
Bạn cần làm phẳng quỹ đạo thu được từ các phép biến đổi để đạt được kết quả ổn định.
trajectory = np.cumsum(transforms, axis=0)
smoothed_trajectory = smooth_trajectory(trajectory)
difference = smoothed_trajectory - trajectory
transforms_smooth = transforms + difference
Đoạn mã trên tính toán quỹ đạo của chuyển động camera và làm mịn nó.
Ổn định và ghi khung
Bước cuối cùng là ổn định khung hình và ghi video ổn định vào tệp đầu ra.
Bắt đầu bằng cách đặt lại quay video. Điều này đảm bảo các hoạt động trong tương lai sẽ đọc từ đầu video.
cap.set(cv2.CAP_PROP_POS_FRAMES, 0)
Sau đó ổn định video bằng cách xử lý từng khung hình.
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]
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
frame_stabilized = cv2.warpAffine(
frame,
transformation_matrix,
(width, height)
)
frame_stabilized = fix_border(frame_stabilized)
frame_out = cv2.hconcat([frame, frame_stabilized])
if frame_out.shape[1] > 1920:
frame_out = cv2.resize(
frame_out,
(frame_out.shape[1] // 2, frame_out.shape[0] // 2)
)
cv2.imshow("Before and After", frame_out)
cv2.waitKey(10)
out.write(frame_out)
Đoạn mã trên ổn định từng khung hình bằng cách sử dụng các phép biến đổi được tính toán, bao gồm các điều chỉnh dịch chuyển và xoay. Sau đó, nó kết hợp các khung ổn định với các khung ban đầu để so sánh.
Phát hành Video Capture và Writer
Hoàn thiện chương trình bằng cách giải phóng các đối tượng ghi và ghi video.
cap.release()
out.release()
cv2.destroyAllWindows()
Mã này cũng đóng mọi cửa sổ đang mở.
Đầu ra chương trình cuối cùng
Đầu ra của chương trình sẽ giống như thế này:
Và đây là một ví dụ về video ổn định:
Đầu ra hiển thị sự so sánh giữa video bị rung và video ổn định.
Khám phá các khả năng của OpenCV
Bạn có thể áp dụng OpenCV trong nhiều lĩnh vực liên quan đến thị giác máy tính. Điều này là do nó cung cấp một loạt các chức năng. Bạn nên khám phá khả năng của nó bằng cách thực hiện nhiều dự án hơn liên quan đến thị giác máy tính. Điều này sẽ giới thiệu cho bạn các khái niệm mới và cung cấp cho bạn các lĩnh vực mới để nghiên cứu.