Как прочитать кадр из файла YUV в OpenCV? - PullRequest
9 голосов
/ 09 февраля 2010

Как прочитать кадр из файла YUV в OpenCV?

Ответы [ 5 ]

6 голосов
/ 14 декабря 2017

Я написал очень простой код на 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
5 голосов
/ 30 мая 2015

Как уже упоминалось, существует МНОГО типов форматов YUV:

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

Преобразовать в RGB из формата YUV в OpenCV очень просто:

  1. Создание одномерного мата OpenCV соответствующего размера для данных этого кадра
  2. Создание пустого мата для данных RGB с требуемым измерением И с 3 каналами
  3. Наконец, используйте cvtColor для преобразования между двумя циновками, используя правильный флаг преобразования enum

Вот пример буфера YUV в формате YV12 :

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 до того, как вы конвертируете.

3 голосов
/ 02 февраля 2011

ОБНОВЛЕНИЕ есть более новая версия кода здесь: 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;
}
0 голосов
/ 29 января 2015

Я столкнулся с той же проблемой. Мое решение 1. прочитать один кадр yuv (например, I420) в строковый объект "yuv". 2. преобразовать фрейм yuv в формат BGR24. Я использую libyuv, чтобы сделать это. Легко написать оболочку Python для функций libyuv. теперь вы получаете другой строковый объект "bgr" в формате BGR24. 3. используйте numpy.fromstring, чтобы получить объект изображения из строкового объекта "bgr". вам нужно изменить форму объекта изображения.

Ниже приведен простой просмотрщик yuv для справки.

import cv2
# below is the extension wrapper for libyuv
import yuvtorgb
import numpy as np

f = open('i420_cif.yuv', 'rb')

w = 352
h = 288
size = 352*288*3/2

while True:
    try:
        yuv = f.read(size)
    except:
        break
    if len(yuv) != size:
        f.seek(0, 0)
        continue

    bgr = yuvtorgb.i420_to_bgr24(yuv, w, h)

    img = np.fromstring(bgr, dtype=np.uint8)
    img.shape = h,w,3

    cv2.imshow('img', img)

    if cv2.waitKey(50) & 0xFF == ord('q'):
        break

cv2.destroyAllWindows()
0 голосов
/ 02 февраля 2011

Я не думаю, что это возможно сделать, по крайней мере, с текущей версией. Конечно, это не будет так сложно сделать, но это не такая интересная функция, как:

  • OpenCV обычно работает с потоком веб-камеры в формате RGB или с закодированными файлами, которые непосредственно декодируются в RGB для отображения;
  • OpenCV предназначен для Computer Vision, где YUV является менее распространенным форматом, чем, например, в сообществе программистов;
  • Есть много разных форматов YUV, что потребовало бы много работы для их реализации.

Преобразования все еще возможны, однако, с использованием cvCvtColor(), что означает, что он в любом случае представляет интерес.

...