如何在OpenCV中从YUV文件读取帧?
image-processing
opencv
6
0

如何在OpenCV中从YUV文件读取帧?

参考资料:
Stack Overflow
收藏
评论
共 3 个回答
高赞 时间 活跃

更新这里有一个更新版本的代码: https : //github.com/chelyaev/opencv-yuv

我正在发布一些代码,这些代码将读取单个 YUV 4:2:0平面图像文件。您可以将其直接应用于大多数YUV文件(只需继续读取同一FILE对象)。 例外是在处理带有头文件的YUV文件时(通常,它们的扩展名为*.y4m )。如果要处理此类文件,则有两种选择:

  1. 在使用下面的代码之前,编写您自己的函数以使用FILE对象中的头数据
  2. 从* .y4m图像中剥离标题(使用ffmpeg或类似工具)。我最喜欢此选项,因为它是最简单的。

它也不适用于任何其他形式的YUV格式(非平面,不同的色度抽取)。正如@Stephane所指出的,有许多这样的格式(而且大多数格式没有任何可识别的标头),这可能就是为什么OpenCV不开箱即用地支持它们的原因。

但是与他们合作非常简单:

  • 从图像及其尺寸开始(读取YUV文件时需要)
  • 将亮度和色度读取为3个单独的图像
  • 将色度图像放大2倍,以补偿色度抽取。 请注意 ,实际上几种补偿色度抽取的方法。升采样只是最简单的
  • 合并为YUV图像。如果需要RGB,则可以使用cvCvtColor

最后,代码:

IplImage * 
cvLoadImageYUV(FILE *fin, int w, int h)
{
    assert(fin);

    IplImage *py      = cvCreateImage(cvSize(w,    h), IPL_DEPTH_8U, 1);
    IplImage *pu      = cvCreateImage(cvSize(w/2,h/2), IPL_DEPTH_8U, 1);
    IplImage *pv      = cvCreateImage(cvSize(w/2,h/2), IPL_DEPTH_8U, 1);
    IplImage *pu_big  = cvCreateImage(cvSize(w,    h), IPL_DEPTH_8U, 1);
    IplImage *pv_big  = cvCreateImage(cvSize(w,    h), IPL_DEPTH_8U, 1);
    IplImage *image   = cvCreateImage(cvSize(w,    h), IPL_DEPTH_8U, 3);
    IplImage *result  = NULL;

    assert(py);
    assert(pu);
    assert(pv);
    assert(pu_big);
    assert(pv_big);
    assert(image);

    for (int i = 0; i < w*h; ++i)
    {
        int j = fgetc(fin);
        if (j < 0)
            goto cleanup;
        py->imageData[i] = (unsigned char) j;
    }

    for (int i = 0; i < w*h/4; ++i)
    {
        int j = fgetc(fin);
        if (j < 0)
            goto cleanup;
        pu->imageData[i] = (unsigned char) j;
    }

    for (int i = 0; i < w*h/4; ++i)
    {
        int j = fgetc(fin);
        if (j < 0)
            goto cleanup;
        pv->imageData[i] = (unsigned char) j;
    }

    cvResize(pu, pu_big, CV_INTER_NN);
    cvResize(pv, pv_big, CV_INTER_NN);
    cvMerge(py, pu_big, pv_big, NULL, image);

    result = image;

cleanup:
    cvReleaseImage(&pu);
    cvReleaseImage(&pv);

    cvReleaseImage(&py);
    cvReleaseImage(&pu_big);
    cvReleaseImage(&pv_big);

    if (result == NULL)
        cvReleaseImage(&image);

    return result;
}
收藏
评论

我写了一个非常简单的python代码,从二进制文件中读取YUV NV21流。

import cv2
import numpy as np

class VideoCaptureYUV:
    def __init__(self, filename, size):
        self.height, self.width = size
        self.frame_len = self.width * self.height * 3 / 2
        self.f = open(filename, 'rb')
        self.shape = (int(self.height*1.5), self.width)

    def read_raw(self):
        try:
            raw = self.f.read(self.frame_len)
            yuv = np.frombuffer(raw, dtype=np.uint8)
            yuv = yuv.reshape(self.shape)
        except Exception as e:
            print str(e)
            return False, None
        return True, yuv

    def read(self):
        ret, yuv = self.read_raw()
        if not ret:
            return ret, yuv
        bgr = cv2.cvtColor(yuv, cv2.COLOR_YUV2BGR_NV21)
        return ret, bgr


if __name__ == "__main__":
    #filename = "data/20171214180916RGB.yuv"
    filename = "data/20171214180916IR.yuv"
    size = (480, 640)
    cap = VideoCaptureYUV(filename, size)

    while 1:
        ret, frame = cap.read()
        if ret:
            cv2.imshow("frame", frame)
            cv2.waitKey(30)
        else:
            break
收藏
评论

如前所述,有很多类型的YUV格式:

http://www.fourcc.org/yuv.php

在OpenCV中从YUV格式转换为RGB非常简单:

  1. 为该框架数据创建一个适当大小的一维OpenCV Mat
  2. 为具有所需尺寸和3个通道的RGB数据创建一个空的Mat
  3. 最后,使用正确的转换标志枚举,使用cvtColor在两个Mats之间进行转换

这是YV12格式的YUV缓冲区的示例:

Mat mYUV(height + height/2, width, CV_8UC1, (void*) frameData);
Mat mRGB(height, width, CV_8UC3);
cvtColor(mYUV, mRGB, CV_YUV2RGB_YV12, 3);

关键技巧是转换之前定义RGB Mat的尺寸。

收藏
评论
新手导航
  • 社区规范
  • 提出问题
  • 进行投票
  • 个人资料
  • 优化问题
  • 回答问题

关于我们

常见问题

内容许可

联系我们

@2020 AskGo
京ICP备20001863号