关于YUV420p到YUV444p

关于YUV420p到YUV444p

在项目中遇到一个问题,需要将YUV420p的视频转化为YUV444p的格式,在开始时使用了FFmpeg的命令如下:

ffmpeg -y -s 480x270 -pix_fmt yuv420p -i xx.yuv -f rawvideo -s 480x270 -pix_fmt yuv444p xx-yuv444.yuv

先说结论,上面的命令是正确的,可以将yuv420p正确的转为yuv444p格式。 问题出现在,我怀疑了上面的命令是不是正确。

于是我有了下面的操作,使用OpenCV看一下转化出来的YUV444p是不是对的啊? 而由于python不能直接读取yuv格式的图像,
所以我需要先以二进制读入文件,参考yuv420p利用OpenCV的读取办法,我写了yuv444p的读取代码。

import numpy as np
import cv2

def read_yuv420p_frame(file_name, dims):
    with open(file_name, "rb") as f:
        h, w = dims
        buffer = f.read(int(h * w * 3 / 2))
        img = np.frombuffer(buffer, dtype=np.uint8).reshape((int(h * 1.5), w))
        return img


def read_yuv444p_frame(file_name, dims):
    with open(file_name, "rb") as f:
        h, w = dims
        buffer = f.read(h * w * 3)
        img = np.frombuffer(buffer, dtype=np.uint8).reshape((h, w, 3))
        return img

yuv420p_file_path = "yuv420p.yuv"
yuv444p_file_path = "yuv444p.yuv"

yuv420p_img = read_yuv420p_frame(yuv420p_file_path, (h, w))
yuv444p_img = read_yuv444p_frame(yuv444p_file_path, (h, w))

cv2.imwrite("yuv420p-to-bgr.png", cv2.cvtColor(yuv420p_img, cv2.COLOR_YUV2BGR_I420))
cv2.imwrite("yuv444p-to-bgr.png", cv2.cvtColor(yuv444p_img, cv2.COLOR_YUV2BGR))

很不幸,虽然yuv420p的代码读取正确,但是yuv444p的代码读取有问题。它的结果变成了这样

在这里插入图片描述

为了验证是不是读取的问题,我写了下面的代码,手动将YUV420p转为YUV444p

def convert_yuv420p_to_yuv444p(yuv420p_img, dims):
    # By filling
    img = yuv420p_img.flatten()
    h, w = dims

    U = img[h * w : h * w + (h * w) // 4]
    V = img[h * w + (h * w) // 4 : ]
    U = U.repeat(2).reshape((2, (h * w) // 4)).repeat((2, 2), axis=0).flatten()
    V = V.repeat(2).reshape((2, (h * w) // 4)).repeat((2, 2), axis=0).flatten()
    img = img[: h * w]

    img = np.append(img, U)
    img = np.append(img, V)

    return img.reshape((h, w, 3))

发现还是不对,于是为了进一步验证我手动转化YUV420p到YUV444p是不是有问题,我构造了一个YUV420p的数据(24个Y数据,6个U和6个V),参考wiki
上的图像,最后发现,输出的形状对不上,换句话说reshape写的有问题!

所以正确的代码应该如下,注意最后的输出格式

import numpy as np
import cv2

def read_yuv420p_frame(file_name, dims):
    with open(file_name, "rb") as f:
        h, w = dims
        buffer = f.read(int(h * w * 3 / 2))
        img = np.frombuffer(buffer, dtype=np.uint8).reshape((int(h * 1.5), w))
        return img


def read_yuv444p_frame(file_name, dims):
    with open(file_name, "rb") as f:
        h, w = dims
        buffer = f.read(h * w * 3)
        img = np.frombuffer(buffer, dtype=np.uint8).reshape((3, h, w)).transpose((1, 2, 0))
        return img

def convert_yuv420p_to_yuv444p(yuv420p_img, dims):
    # By filling
    img = yuv420p_img.flatten()
    h, w = dims

    U = img[h * w : h * w + (h * w) // 4]
    V = img[h * w + (h * w) // 4 : ]
    U = U.repeat(2).reshape((2, (h * w) // 4)).repeat((2, 2), axis=0).flatten()
    V = V.repeat(2).reshape((2, (h * w) // 4)).repeat((2, 2), axis=0).flatten()
    img = img[: h * w]

    img = np.append(img, U)
    img = np.append(img, V)

    return img.reshape((3, h, w)).transpose((1, 2, 0))

yuv420p_file_path = "yuv420p.yuv"
yuv444p_file_path = "yuv444p.yuv"

yuv420p_img = read_yuv420p_frame(yuv420p_file_path, (h, w))
yuv444p_img = read_yuv444p_frame(yuv444p_file_path, (h, w))

cv2.imwrite("yuv420p-to-bgr.png", cv2.cvtColor(yuv420p_img, cv2.COLOR_YUV2BGR_I420))
cv2.imwrite("yuv444p-to-bgr.png", cv2.cvtColor(yuv444p_img, cv2.COLOR_YUV2BGR))

此外,在这里记录一下,有一个部分处理的不好,YUV视频提取帧,做的十分暴力,结合python脚本和下面的命令,逐帧提取。

ffmpeg -s widthxheight -i input.yuv -c:v rawvideo -filter:v select="between(n\, 0\, 1)" out.yuv
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值