Как извлечь кадры из видеофайла .yuv (YUV420), используя python и openCV? - PullRequest
1 голос
/ 16 марта 2020

Мне нужно прочитать видеофайл 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. Но когда я передаю yuv-файл в VideoCapture (), я получаю сообщение об ошибке следующим образом:

[IMGUTILS @ 00000078a4bee5c0] Размер изображения 0x0 недопустим [ОШИБКА: 0] global C: \ projects \ opencv- python \ opencv \ modules \ videoio \ src \ cap. cpp (116) cv :: VideoCapture :: open VIDEOIO (CV_IMAGES): повышенное исключение OpenCV:

OpenCV (4.1.2) 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'

Traceback (последний вызов был последним): файл "test1.py", строка 6, в prvs = cv.cvtColor (frame1, cv.COLOR_BGR2GRAY) cv2.error: OpenCV (4.1.2) C: \ projects \ opencv-python \ opencv \ modules \ imgproc \ src \ color. cpp: 182: ошибка: (-215: утверждение не выполнено)! _Sr c .empty () в функции 'cv :: cvtColor'

Как мне решить эту проблему? Также я понимаю, что yuv - это необработанный формат видеофайла, в котором нет информации о размере или fps. Есть ли какой-то способ, которым это может быть выведено из файла, или мне нужно вручную вводить эту информацию?

Относительно моего вопроса о том, как получить информацию о размере кадра (высоте и ширине) из видео yuv, можно ли преобразовать видео yuv в другой формат (скажем, mp4) с помощью FFmpeg, получить из него информацию, а затем удалить видео 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: yuv frame

Это нормально для Изображение или какая-то проблема с разрешением? И почему нет цвета? Однако когда я конвертирую его в оттенки серого, он получается нормальным:

grayscale frame

Исходный кадр (при просмотре с помощью yuvplayer 2.5):

original frame

1 Ответ

1 голос
/ 16 марта 2020

Не существует единого формата файла YUV420, но возможно много упорядочения пикселей.

Я создал «автономный» пример кода, который демонстрирует чтение кадров YUV420.
Пример кода:

  • Генерирует синтезированное c видео в формате YUV420 с использованием FFmpeg .
    Для выполнения примера загрузите (или установите) последнюю стабильную версию.
    Для Windows ОС вы можете поместить ffmpeg.exe в тот же путь, что и скрипт Python.
  • Читайте кадр за кадром YUV420, конвертируйте в BGR и отображайте каждый кадр.
    Цвет вам не нужен, но он может быть важен для тестирования.
  • Преобразование YUV420 в оттенки серого и отображение каждого кадра в оттенках серого.

FFmpeg создает YUV в плоском формате I420:

YYYYYY
YYYYYY
YYYYYY
YYYYYY
UUU
UUU
VVV
VVV

Диапазон пикселей 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()

Примечание:

  • Скорее всего, ваш файл YUV420 не в формате I420, "ограниченный диапазон".

Обновление:

Пример преобразования YUV420 в несжатый AVI с использованием FFmpeg:

  • Входной файл должен быть с .yuv расширение.

В консоли командной строки:

ffmpeg -y -s 640x480 -pixel_format yuv420p -i input.yuv -vcodec rawvideo -pix_fmt bgr24 input.avi

Использование subprocess в Python:

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 поддерживает высокое качество (почти без потерь).
    Примечание. Формат файла .mp4 или .avi не важен при использовании кодирования H.264 (но .mp4 чаще встречается при использовании кодировки H.264).

...