当前位置: 首页 > 知识库问答 >
问题:

如何使用python和OpenCV从。yuv视频文件(YUV420)中提取帧?

丁俊智
2023-03-14

我需要读取一个yuv视频文件,从中提取单个帧,将其转换为灰度,然后计算相邻帧之间的卢卡斯·卡纳德光流。我最初使用的是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异常:

Traceback(最近的调用为last):文件“test1.py”,第6行,在prvs=cv.cvtcolor(frame1,cv.color_bgr2gray)cv2中。错误:OpenCV(4.1.2)c:\projects\opencv-python\OpenCV\modules\imgproc\src\color.cpp:182:错误:(-215:断言失败)!_src.empty()在函数'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图像来说,这是正常的还是某种分辨率问题?还有为什么没有颜色?然而,当我把它转换成灰度时,它就正常了:

原始框架是(使用YuvPlayer2.5查看):

共有1个答案

松俊美
2023-03-14

没有单一的YUV420文件格式,但许多可能的像素排序。

我创建了一个“自包含”的代码示例,用于演示读取YUV420帧。
代码示例:

  • 使用ffmpeg生成YUV420格式的合成视频。
    要执行示例,请下载(或安装)最新的稳定版本。
    对于Windows OS,可以将ffmpeg.exe放在与Python脚本相同的路径中。
  • 逐帧读取YUV420,转换为BGR,并显示每一帧。
    您不需要颜色,但它可能对测试很重要。
  • 将YUV420转换为灰度,并将每个帧显示为灰度。

YUV像素的范围是“有限范围”:

  • y范围为[16,235]。
  • u和V的范围是[16,240]。

代码如下:

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()
    null
    null
ffmpeg -y -s 640x480 -pixel_format yuv420p -i input.yuv -vcodec rawvideo -pix_fmt bgr24 input.avi
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更常见)。

  •  类似资料:
    • 我想提取原始Yuv帧从mp4剪辑使用FFMPEG。我输入。mp4告诉我视频格式是YUV420P10LE。我使用以下命令来提取帧: 以下是FFMPEG的日志:

    • 使用Camtasia创建的视频可以通过导出TechSmith智能播放器的项目在网络上共享。该视频以“H264-MPEG-4 AVC(part10)(avc1)”编解码器导出,导出还包括TechSmith智能播放器使用的其他自定义XML、JavaScript和SWF文件。 这些自定义文件也会“烧录”到视频中。例如,在文本编辑器中打开MP4视频时,可以查看XML文件的内容。这允许其他服务在上传Camt

    • 问题内容: 我是OpenCV的初学者。我想对要上传到服务器的视频帧进行一些图像处理。我只想读取可用的框架并将它们写入目录中。然后,等待视频的另一部分上载并将帧写入目录。并且,我应该等待每个帧都完全上传,然后将其写入文件。 您能告诉我如何使用OpenCV(Python)吗? 编辑1: 我编写了这段代码,用于从文件中捕获视频,而新数据将附加在文件末尾。换句话说,该文件不是完整的视频,并且另一个程序正在

    • 我有一堆从Youtube下载的视频,我想从他们中提取帧。我使用的当前命令是: 但是我还想设置-r和-t选项。我想要的fps是每个视频的fps,持续时间是他们的持续时间。我知道如果我不设置-r选项,默认值是25 fps。

    • 我有一个AVI视频,我需要处理在C++使用OpenCV。问题是OpenCV检测到的FrameRate为30,而在Matlab中,视频阅读器对相同的视频文件检测到的FrameRate为60。因此,与Matlab相比,C++只能提取一半的帧。 我尝试在C++中使用CV::VideoCapture::Set(CV::CAP_PROP_FPS)将FPS设置为60,但这并不影响它。我读到它也与视频捕获后端有