首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >如何使用python和.yuv从.yuv视频文件(YUV420)中提取帧?

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

Stack Overflow用户
提问于 2020-03-16 11:07:46
回答 1查看 10.3K关注 0票数 1

我需要读取一个yuv视频文件,从其中提取单个帧,将其转换为灰度,然后计算相邻帧之间的Lucas Kanade光流。我最初使用的是mp4视频,这是我提取单个帧的代码:

代码语言:javascript
运行
复制
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视频文件。但是,当我将一个yuv文件提供给VideoCapture()时,我得到的错误如下:

IMGUTILS @00000078a4be5c0图片大小0x0无效错误:0全局C:\projects\opencv-python\opencv\modules\videoio\src\cap.cpp (116) cv:视频捕获::open(CV_IMAGES):引发OpenCV异常:

C:\projects\opencv-python\opencv\modules\videoio\src\cap_images.cpp:253:错误:(-5:坏参数) CAP_IMAGES:找不到(文件名):C:\Users\Ann Baiju\Project\Copy_Move_Datasets\new original\DERF\hall.yuv函数'cv::icvExtractPattern‘

追溯(最近一次调用):File "test1.py",第6行,在prvs = cv.cvtColor(frame1,cv.COLOR_BGR2GRAY) cv2中。错误: OpenCV(4.1.2) OpenCV错误:(-215:断言失败) !_src.empty()在函数'cv::cvtColor‘中

我该怎么解决这个问题?另外,我知道yuv是一个原始的视频文件格式,没有大小或fps信息在其中。有什么方法可以从文件中推断出吗?还是我必须手动输入该信息?

关于我的问题,如何从yuv视频中获取帧大小信息(高度和宽度),是否可以使用FFmpeg将yuv视频转换为其他格式(比如FFmpeg),从它获取信息,然后删除mp4视频,并继续使用yuv视频?如果是这样的话,怎么做呢?

代码语言:javascript
运行
复制
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映像是:

这对于一张yuv图像还是某种分辨率问题是正常的?还有为什么没有颜色?然而,当我将其转换为灰度时,它就会正常:

原始帧(使用yuvplayer 2.5查看)如下:

EN

回答 1

Stack Overflow用户

发布于 2020-03-16 18:09:39

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

我创建了一个“自包含”代码示例,演示如何读取YUV420框架。

代码示例:

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

FFmpeg以I420平面格式创建YUV:

YYYYYY

YYYYYY

YYYYYY

YYYYYY

UUU

UUU

VVV

VVV

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

  • Y值是16,235。
  • U和V的范围是16,240。

以下是代码:

代码语言:javascript
运行
复制
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()

注意:

  • 您的YUV420文件很有可能不是I420格式的“有限范围”格式。

更新:

使用YUV420YUV420转换为未压缩的AVI的示例:

  • 输入文件必须具有.yuv扩展名。

在命令行控制台中:

代码语言:javascript
运行
复制
ffmpeg -y -s 640x480 -pixel_format yuv420p -i input.yuv -vcodec rawvideo -pix_fmt bgr24 input.avi

在Python中使用subprocess

代码语言:javascript
运行
复制
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更常见)。
票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/60704826

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档