[英]How to convert .mp4 video file to .yuv (YUV420) and vice-versa using FFmpeg and subprocess module in python?
[英]How to extract frames from a .yuv video file (YUV420) using python and openCV?
我需要读取一个 yuv 视频文件,从中提取单个帧,将其转换为灰度,然后计算相邻帧之间的 Lucas Kanade 光流。 我最初使用 mp4 视频,这是我提取单个帧的代码:
import cv2 as cv
import numpy as np
cap = cv.VideoCapture('C:\\Users\\Ann Baiju\\Project\\video_tampering_dataset\\videos\\h264_lossless\\07_forged.mp4')
ret, frame1 = cap.read()
prvs = cv.cvtColor(frame1, cv.COLOR_BGR2GRAY)
height, width, _ = frame1.shape
while(1):
ret, frame2 = cap.read()
if ret==False: break
next = cv.cvtColor(frame2, cv.COLOR_BGR2GRAY)
#Code for calculating Lucas Kanade optical flow
N=N+1
prvs = next
cap.release()
现在有些事情发生了变化,我必须使用 yuv 视频文件的数据集。 但是当我给 VideoCapture() 一个 yuv 文件时,我收到如下错误:
[IMGUTILS @ 00000078a4bee5c0] 图片大小 0x0 无效 [错误:0] 全局 C:\\projects\\opencv-python\\opencv\\modules\\videoio\\src\\cap.cpp (116) cv::VideoCapture::open VIDEOIO(CV_IMAGES) :引发 OpenCV 异常:
OpenCV(4.1.2) C:\\projects\\opencv-python\\opencv\\modules\\videoio\\src\\cap_images.cpp:253: error: (-5:Bad argument) CAP_IMAGES: can't find starting number (in the name文件):C:\\Users\\Ann Baiju\\Project\\Copy_Move_Datasets\\new original\\DERF\\hall.yuv in function 'cv::icvExtractPattern'
回溯(最近一次调用):文件“test1.py”,第 6 行,在 prvs = cv.cvtColor(frame1, cv.COLOR_BGR2GRAY) cv2.error: OpenCV(4.1.2) C:\\projects\\opencv-python\\ opencv\\modules\\imgproc\\src\\color.cpp:182: error: (-215:Assertion failed) !_src.empty() in function 'cv::cvtColor'
我该如何解决这个问题? 另外我知道 yuv 是一种原始视频文件格式,其中没有大小或 fps 信息。 有什么方法可以从文件中推断出来还是我必须手动输入该信息?
关于如何从 yuv 视频获取帧大小信息(高度和宽度)的问题,是否可以使用 FFmpeg 将 yuv 视频转换为其他格式(比如 mp4),从中获取信息,然后删除 mp4 视频和继续使用 yuv 视频? 如果是这样怎么办?
import cv2
import numpy as np
import os
import subprocess as sp
yuv_filename = 'can_0.yuv'
#flow=[]
width, height = 320, 240
file_size = os.path.getsize(yuv_filename)
n_frames = file_size // (width*height*3 // 2)
f = open(yuv_filename, 'rb')
old_yuv = np.frombuffer(f.read(width*height*3//2), dtype=np.uint8).reshape((height*3//2, width))
cv2.imshow('frame',old_yuv)
cv2.waitKey(3000)
# Convert YUV420 to Grayscale
old_gray = cv2.cvtColor(old_yuv, cv2.COLOR_YUV2GRAY_I420)
cv2.imshow('frame_gs',old_gray)
cv2.waitKey(3000)
对于 yuv 图像或某种分辨率问题,这是否正常? 还有为什么没有颜色? 但是,当我将其转换为灰度时,结果正常:
原始帧是(使用 yuvplayer 2.5 查看):
没有单一的 YUV420 文件格式,但有许多可能的像素排序。
我创建了一个“自包含”代码示例,用于演示读取 YUV420 帧。
代码示例:
ffmpeg.exe
放在与 Python 脚本相同的路径中。FFmpeg 以 I420 平面格式创建 YUV:
YYYYYY
YYYYYY
YYYYYY
YYYYYY
UUU
UUU
VVV
VVV
YUV像素的范围是“有限范围”:
这是代码:
import cv2
import numpy as np
import os
import subprocess as sp
# Build synthetic video and read binary data into memory (for testing):
#########################################################################
mp4_filename = 'input.mp4' # the mp4 is used just as reference
yuv_filename = 'input.yuv'
width, height = 640, 480
fps = 1 # 1Hz (just for testing)
# Build synthetic video, for testing (the mp4 is used just as reference):
sp.run('ffmpeg -y -f lavfi -i testsrc=size={}x{}:rate=1 -vcodec libx264 -crf 18 -t 10 {}'.format(width, height, mp4_filename))
sp.run('ffmpeg -y -f lavfi -i testsrc=size={}x{}:rate=1 -pix_fmt yuv420p -t 10 {}'.format(width, height, yuv_filename))
#########################################################################
file_size = os.path.getsize(yuv_filename)
# Number of frames: in YUV420 frame size in bytes is width*height*1.5
n_frames = file_size // (width*height*3 // 2)
# Open 'input.yuv' a binary file.
f = open(yuv_filename, 'rb')
for i in range(n_frames):
# Read Y, U and V color channels and reshape to height*1.5 x width numpy array
yuv = np.frombuffer(f.read(width*height*3//2), dtype=np.uint8).reshape((height*3//2, width))
# Convert YUV420 to BGR (for testing), applies BT.601 "Limited Range" conversion.
bgr = cv2.cvtColor(yuv, cv2.COLOR_YUV2BGR_I420)
# Convert YUV420 to Grayscale
gray = cv2.cvtColor(yuv, cv2.COLOR_YUV2GRAY_I420)
#Show RGB image and Grayscale image for testing
cv2.imshow('rgb', bgr)
cv2.waitKey(500) # Wait a 0.5 second (for testing)
cv2.imshow('gray', gray)
cv2.waitKey(500) # Wait a 0.5 second (for testing)
f.close()
cv2.destroyAllWindows()
笔记:
使用FFmpeg
将YUV420
转换为未压缩的 AVI 的示例:
.yuv
扩展名。在命令行控制台中:
ffmpeg -y -s 640x480 -pixel_format yuv420p -i input.yuv -vcodec rawvideo -pix_fmt bgr24 input.avi
在 Python 中使用subprocess
进程:
sp.run('ffmpeg -y -s {}x{} -pixel_format yuv420p -i input.yuv -vcodec rawvideo -pix_fmt bgr24 input.avi'.format(width, height))
未压缩的 AVI 视频文件将非常大(YUV 文件大小的两倍)。
如果视频质量不是最重要的,您可以使用 H.264 压缩(例如):
ffmpeg -y -s 640x480 -pixel_format yuv420p -i input.yuv -vcodec libx264 -crf 17 -pix_fmt yuv420p input.mp4
-crf 17
参数保持高质量(几乎无损)。
注意:使用 H.264 编码时文件格式.mp4
或.avi
并不重要(但使用 H.264 编码时.mp4
更为常见)。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.