Datenverlust Videobearbeitung mit OpenCV2 und FFMPEG

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
Holzi
User
Beiträge: 3
Registriert: Dienstag 26. Dezember 2017, 12:40

Hallo zusammen,

ich arbeite im Moment an einem Programm, welches ein Video (mp4) in seine einzelnen Frames zerlegt, anhand von Messdaten eine Art Cursor an einer bestimmten Position in jedem Bild hinzufügt und anschließend die Einzelbilder wieder zu einem mp4 zusammenfügt. Bisher komme ich auch ganz gut zurecht mit den Modulen OpenCV2 und Pillow und eben FFMPEG. Das Programm ist auch bereits lauffähig und tut im Groben was es soll. Leider gehen mir aber immer die ersten x Sekunden des Videos verloren (5<=x<=15). Nach mehrstündiger Fehlersuche bin ich aber nicht darauf gestoßen, was diesen Verlust auslöst, mir ist aber bekannt, dass es bereits beim "Zerlegen" des Videos in Einzelbilder zu entsprechendem Datenverlust kommt (die ersten ca. 75 - 225 Frames fehlen schlichtweg). Nun zu meiner Frage: Woran könnte dies liegen und wie könnte man dies am besten beheben?

Code: Alles auswählen

def create_tempdir():
    try:
        os.mkdir('./temp/')
    except OSError as e:
        print(e)
        
def load_video(video):
    cap = cv2.VideoCapture(video)
    if not cap:
        print("Failed to load video.")
        sys.exit(1)
    fps = cap.get(cv2.CAP_PROP_FPS)
    return cap,fps

def frames_to_png(cap):
    f = 0
    while(cap.isOpened()):
        ret,frame = cap.read()
        
        if ret==True:
            
            f += 1

            # Convert cv2 image to rgb and load from numpy array
            frame = cv2.cvtColor(frame,cv2.COLOR_BGR2RGB)
            img = Image.fromarray(frame)

            # make Cursor
            img.paste(cursor,(int(200+100*math.sin(f/10.0)),int(200+100*math.cos(f/10.0))),cursor)
            

            # Convert back to bgr numpy array and write to disk
            frame = cv2.cvtColor(np.array(img), cv2.COLOR_RGB2BGR)
            cv2.imwrite('./temp/frame{}.png'.format(str(f)),frame)
        else:
            break
    cap.release()
...
def main():
    create_tempdir()
    stream, framerate = load_video(video)
   
    
    frames_to_png(stream)
    png_to_mp4(framerate)
    make_avi()
    if output_name.endswith('mp4'):
        make_mp4()
        #os.remove('{}avi'.format(output_name[:-3]))
    cleanup()
P.s: Mir ist bewusst, dass die Frage wahrscheinlich viel zu spezifisch ist, Python ist leider noch relativ neu für mich und auch nach längerem Überlegen ist es mir leider nicht möglich, die Frage zu verallgemeinern.
Scheut euch nicht auch irgendwelche Vermutungen zu äußern, ich freue mich über jeden neuen Ansatz.
Vielen Dank
Holzi
Sirius3
User
Beiträge: 17747
Registriert: Sonntag 21. Oktober 2012, 17:20

@Holzi: woher ist Dir bekannt, dass schon beim Zerlegen Frames fehlen? Hast Du Dir die Einzelbilder angeschaut? Wie sehen die nicht gezeigten Funktionen aus?
Holzi
User
Beiträge: 3
Registriert: Dienstag 26. Dezember 2017, 12:40

@Sirius, ich hab mir die Einzelbilder angeschaut und diese mit dem Video abgeglichen. Hier der ganze Code:

Code: Alles auswählen

# -*- coding: utf-8 -*-
"""
Created on Tue Dec 19 10:23:37 2017

@author: tt5496
"""


import numpy as np
import cv2
from PIL import Image, ImageEnhance
import subprocess
import os
import sys
import shutil
import argparse
import math

"""
Creates a Cursor on each Frame of the video from data using ffmpeg. Requires ffmpeg and opencv 3x. 
Supports mp4 and avi formats.
Usage: $python makeCursor.py -i video.mp4 -o newvideo.mp4 
"""


cursor = Image.open('Cursor.png')


parser = argparse.ArgumentParser(description='makeCursor.py')
parser.add_argument('-i', '--input', dest='input_name', type=str, required=True, 
                    help="Path, name and filetype of video to add Eyetracking-Cursor")
parser.add_argument('-o', '--output', dest='output_name', type=str, 
                    default='brighter.avi', 
                    help="Path, name and filetype of output file")
position = []
parsed = parser.parse_args()
input_name = parsed.input_name
output_name = parsed.output_name

if input_name.endswith('mp4') or input_name.endswith('avi'):
    video = input_name
else:
    print("This script currently supports mp4 and avi formats only.")
    sys.exit(1)

def create_tempdir():
    try:
        os.mkdir('./temp/')
    except OSError as e:
        print(e)
        
def load_video(video):
    cap = cv2.VideoCapture(video)
    if not cap:
        print("Failed to load video.")
        sys.exit(1)
    fps = cap.get(cv2.CAP_PROP_FPS)
    return cap,fps

def frames_to_png(cap):
    f = 0
    while(cap.isOpened()):
        ret,frame = cap.read()
        
        if ret==True:
            
            f += 1

            # Convert cv2 image to rgb and load from numpy array
            frame = cv2.cvtColor(frame,cv2.COLOR_BGR2RGB)
            img = Image.fromarray(frame)

            # make Cursor
            img.paste(cursor,(int(200+100*math.sin(f/10.0)),int(200+100*math.cos(f/10.0))),cursor)
            #bisher erstmal nur testweise implementiert

            # Convert back to bgr numpy array and write to disk
            frame = cv2.cvtColor(np.array(img), cv2.COLOR_RGB2BGR)
            cv2.imwrite('./temp/frame{}.png'.format(str(f)),frame)
        else:
            break
    cap.release()
def png_to_mp4(framerate):
    framerate = str(framerate)
    
    args = ["ffmpeg",
        "-framerate", framerate,
        "-r", framerate,
        "-i","./temp/frame%d.png",
        "-vcodec","png",
        "./temp/0vid.mp4"]

    try:
        p = subprocess.call(args)
    except Exception as e:
        print(e)
        print("Failed to convert pngs to mp4.")
        sys.exit(1)
def make_mp4():
    args = [
        "ffmpeg",
        "-i","{}avi".format(output_name[:-3]),
        "-b:a","128k",
        "-vcodec","mpeg4",
        "-b:v","1200k",
        "-flags","+aic+mv4",
        output_name
    ]

    try:
        p = subprocess.call(args)
    except:
        print("Failed to make mp4.")
        sys.exit(1)

def make_avi():
    args = [
        "ffmpeg",
        "-i","./temp/0vid.mp4",
        # "-i","./temp/{}wav".format(input_name[:-3]),
        "-vcodec","copy",
        "-acodec","copy",
        "{}avi".format(output_name[:-3])
    ]

    try:
        p = subprocess.call(args)
    except:
        print("Failed to make avi.")
        sys.exit(1)
def cleanup():
    try:
        shutil.rmtree('./temp')
        print("Cleanup done")
    except:
        print("Failed to clean up temp directory.")
def main():
    create_tempdir()
    stream, framerate = load_video(video)
    
    frames_to_png(stream)
    png_to_mp4(framerate)
    make_avi()
    if output_name.endswith('mp4'):
        make_mp4()
        #os.remove('{}avi'.format(output_name[:-3]))
    cleanup()


if __name__ == '__main__':
    main()


Holzi
User
Beiträge: 3
Registriert: Dienstag 26. Dezember 2017, 12:40

Hi zusammen,
leider weiß ich immer noch nicht warum die ersten paar Sekunden verloren gehen, ich habe das Programm allerdings mit anderen Videos getestet, bei denen der entsprechende Datenverlust nicht aufgetaucht ist. Könnte es also vielleicht an den Mp4 Dateien selbst liegen? Ich kann leider aus Datenschutzrechtlichen Gründen kein Video hochladen, es handelt sich um mit einem Screenrecorder aufgenommene Videos mit der ungefähren Länge 5 Minuten und 15 fps. Im anderen getesten Video, welches keinen Verlust vorwies handelte es sich um ein Video der Länge 45 Sekunden mit 24 fps.
:K
__deets__
User
Beiträge: 14536
Registriert: Mittwoch 14. Oktober 2015, 14:29

Ich behaupte mal die ganze Thematik haengt an ffmpeg oder was auch immer die OpenCV zur dekodierung verwendet. Wenn du ein Tool hast, mit dem du den Film von Anfang an sehen kannst, kannst du das ggf. nutzen, um den Film zu transkodieren, in der Hoffnung, dass da dann am Ende ein auch fuer die OpenCV vollstaending darstellbarer Film rauskommt.

Mit Python hat das allerdings erstmal nix zu tun. Was nicht heissen soll "hau ab", aber ggf. hilft es dir mehr, in spezialisierten Foren zu den Themen Videokodierung etc. zu recherchieren.
Antworten