imageio / imageio-ffmpeg

FFMPEG wrapper for Python
BSD 2-Clause "Simplified" License
221 stars 50 forks source link

ValueError: Input must be >= 1-d #100

Closed sugizo closed 4 months ago

sugizo commented 4 months ago

objective have image filter effect

code

from imageio_ffmpeg import read_frames, write_frames
import numpy as np

def flipud(image):
    return np.flipud(image)

video_file= 'audio_video.mp4'
output = 'flipud.mp4'

reader = read_frames(video_file)
meta = reader.__next__()

writer = write_frames(output, audio_path = video_file,
                      fps = meta['fps'], size = meta['size'],
                      input_params = ['-y'],
                      output_params = ['-r', '60'] )
writer.send(None)

for frame in reader:
    filter = flipud(frame)
    writer.send(filter)

writer.close()

result

ValueError                                Traceback (most recent call last)
[<ipython-input-9-bbea65de4cbe>](https://localhost:8080/#) in <cell line: 12>()
     11 
     12 for frame in reader:
---> 13     filter = flipud(frame)
     14     writer.send(filter)
     15 

1 frames
[/usr/local/lib/python3.10/dist-packages/numpy/lib/twodim_base.py](https://localhost:8080/#) in flipud(m)
    152     m = asanyarray(m)
    153     if m.ndim < 1:
--> 154         raise ValueError("Input must be >= 1-d.")
    155     return m[::-1, ...]
    156 

ValueError: Input must be >= 1-d.
WARNING:imageio_ffmpeg:No frames have been written; the written video is invalid.

any idea how to face this error ?

best regards

almarklein commented 4 months ago

The frames that are yielded are bytes objects. You need to convert them to a numpy array first.

The size is the meta dict can help with that. With .reshape(meta.size[1], meta.size[0], -1) you convert an rgb or rgba image. For grayscale you can leave out the -1 (it adds the color-dimension, whit whatever size is needed to get the total number of elements matching).

When sending the frames, it can accept a numpy array, but it needs to be contiguous, you can use np.ascontiguousarray() for that, which is a no-op if it's already contiguous.

So without testing it, (something like) this should work:

import numpy as np
for frame in reader:
    image = np.frombuffer(frame, np.uint8).reshape(meta.size[1], meta.size[0], -1)
    flipped = np.ascontiguousarray(np.flipud(image))
    writer.send(flipped)
sugizo commented 4 months ago

code

from imageio_ffmpeg import read_frames, write_frames
import numpy as np

input_file = 'audio_video.mp4'
output_file = 'flipud.mp4'
audio_file = 'audio_video.mp4' # audio or video file

reader = read_frames(input_file)
meta = reader.__next__()

writer = write_frames(output_file, audio_path = audio_file,
                      size = meta['size'], fps = meta['fps'],
                      input_params = ['-y', ],
                      output_params = ['-r', '60', ] )
writer.send(None)

for frame in reader:
    image = np.frombuffer(frame, np.uint8).reshape(meta.size[1], meta.size[0], -1)
    flipped = np.ascontiguousarray(np.flipud(image) )
    writer.send(flipped)

writer.close()

result

WARNING:imageio_ffmpeg:No frames have been written; the written video is invalid.
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
[<ipython-input-7-915cb117e138>](https://localhost:8080/#) in <cell line: 14>()
     13 
     14 for frame in reader:
---> 15     image = np.frombuffer(frame, np.uint8).reshape(meta.size[1], meta.size[0], -1)
     16     flipped = np.ascontiguousarray(np.flipud(image))
     17     writer.send(flipped)

AttributeError: 'dict' object has no attribute 'size'

best regards

almarklein commented 4 months ago

Ah, I should've said meta['size'] :)