Конвертируйте видео RGB в видео в оттенках серого для уменьшения размера файла - PullRequest
3 голосов
/ 27 января 2020

Я создаю Цветное видео (RGB) с использованием OpenCV в моем приложении, и сгенерированный видеофайл должен быть загружен на сервер. Размер цветного видеофайла достаточно велик, чтобы создать узкое место при загрузке на сервер в текущей доступной полосе пропускания. Итак, я попытался уменьшить размер файла, преобразовав его в видео в градациях серого в opencv. Ниже приведена реализация моей текущей работы в OpenCV:

cap = cv2.VideoCapture(RGB_video_filepath)
    fps = cap.get(cv2.CAP_PROP_FPS)
    print("Input Video FPS: ".format(fps))
    outputfilepath = "gray_video_output.avi"

    mjpg_forcc = cv2.VideoWriter_fourcc('M', 'J', 'P', 'G')
    divx_forcc = cv2.VideoWriter_fourcc(*'DIVX')
    xvid_forcc = cv2.VideoWriter_fourcc(*'XVID')
    fmpp4_codec = cv2.VideoWriter_fourcc('F','M','P','4')
    mp4v_codec = cv2.VideoWriter_fourcc(*'MP4V')
    vid_writer = cv2.VideoWriter(outputfilepath, mjpg_codec, 2, (640, 480), 0)

    while cv2.waitKey(1) < 0:
        # get frame from the video
        hasFrame, frame = cap.read()


        # Stop the program if reached end of video
        if not hasFrame:
            print("Done processing !!!")
            print("Output file is stored as ", outputfilepath)
            break

        gray_frame = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
        vid_writer.write(gray_frame)
        print("Frame shape: {} {}".format(frame_count, frame.shape))
        cv2.imshow("Camera frame", frame)
        cv2.waitKey(1)

    print("Total frames: {}".format(frame_count))
    vid_writer.release()
    cap.release()

Используя вышеуказанный рабочий процесс, я создал видео в масштабе GREY, но обнаружил, что размеры видеофайлов практически одинаковы (размер видеофайла RGB: 25 МБ, Размер видео в оттенках серого: 23 МБ.

После копания в OpenCV я обнаружил, что OpenCV копирует кадр в градациях серого (один канал) 3 раза и записывает в видео как 3 канала , хотя OpenCV использует FFMPEG для записи видеофайлов в ОС Linux.

Я попытался преобразовать тот же видеофайл RGB в видеофайл в градациях серого, используя FFMPEG , как показано ниже:

ffmpeg -i inputvideofile -vf hue=s=0 outputvideofile

Здесь я сохранил пустой канал Hue и насыщенности и удивительно RGB видеофайл (25 МБ) преобразуется в оттенки серого с уменьшенным размером файла до 6 МБ.

** I Любопытно узнать, сможем ли мы добиться уменьшения размера видеофайла путем преобразования RGB в шкалу серого с использованием OpenCV на лету? **

Любая помощь / обновление приветствуется. Спасибо !!

1 Ответ

2 голосов
/ 27 января 2020

OpenCV использует FFMPEG. Попробуйте следующий код, чтобы сохранить массив numpy каждого кадра в виде видео, используя ffmpeg- python и сравнить размер.

import numpy as np
import cv2
import ffmpeg

def save_video(cap,saving_file_name,fps=33.0):

    if cap.isOpened():
        ret, frame = cap.read()
        if ret:
            i_width,i_height = frame.shape[1],frame.shape[0]

    process = (
    ffmpeg
        .input('pipe:',format='rawvideo', pix_fmt='rgb24',s='{}x{}'.format(i_width,i_height))
        .output(saved_video_file_name,pix_fmt='yuv420p',vcodec='libx264',r=fps,crf=37)
        .overwrite_output()
        .run_async(pipe_stdin=True)
    )

    return process

if __name__=='__main__':

    cap = cv2.VideoCapture(0,cv2.CAP_DSHOW)
    cap.set(3,1920)
    cap.set(4,1080)
    saved_video_file_name = 'output.avi'
    process = save_video(cap,saved_video_file_name)

    while(cap.isOpened()):
        ret, frame = cap.read()
        if ret==True:
            frame = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) # Convert frame/img to gray
            frame = cv2.flip(frame,0)
            process.stdin.write(
                cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
                    .astype(np.uint8)
                    .tobytes()
                    )

            cv2.imshow('frame',frame)
            if cv2.waitKey(1) & 0xFF == ord('q'):
                process.stdin.close()
                process.wait()
                cap.release()
                cv2.destroyAllWindows()
                break
        else:
            process.stdin.close()
            process.wait()
            cap.release()
            cv2.destroyAllWindows()
            break
...