[SOLVED] reading multiple images over standard input

Questions and postings pertaining to the development of ImageMagick, feature enhancements, and ImageMagick internals. ImageMagick source code and algorithms are discussed here. Usage questions which are too arcane for the normal user list should also be posted here.
Post Reply
nixscripter
Posts: 8
Joined: 2011-03-17T12:12:45-07:00
Authentication code: 8675308

[SOLVED] reading multiple images over standard input

Post by nixscripter » 2011-03-18T05:48:12-07:00

Hello.

I would like convert to be able to read more than one file from standard input on Linux. Instead of this:

Code: Select all

for i in file*;  
do
     cat file | convert - -some-transform jpeg:-
done
I would like the ability to do this:

Code: Select all

 cat file* | convert - -some-transform jpeg:- 
I want to process a stream one at a time without creating any temporary files, for use in this situation:

Code: Select all

ffmpeg input.mpg -f image2pipe -vcodec jpeg | convert - -some-transform jpeg:- | ffmpeg -f image2pipe -vcodec jpeg output.mpg
I cannot find anything about this on the mailing list or previous forum posts. If I missed something let me know.

Assuming there is not an easy current solution, I am not asking for a feature, because I assume this behavior is probably not intuitive for most users. Instead, I would like to write a custom patch for the library for my own use. Would this be difficult?
Last edited by nixscripter on 2011-03-20T06:56:31-07:00, edited 1 time in total.

User avatar
anthony
Posts: 8881
Joined: 2004-05-31T19:27:03-07:00
Authentication code: 8675308
Location: Brisbane, Australia

Re: reading multiple images over standard input

Post by anthony » 2011-03-19T04:19:25-07:00

That is very difficult. However some formats are designed to let you pipe multiple images through a pipe.
Basically the library that read the file require an actual EOF signal to mark there end. JPEG and PNG are like this.

PNM (sub-formats PBM PGM PPM PAM PFM) allows this, though it is not often used, Ghostscript for example does use it to pass multiple rasterized pages. However like JPEG they don't allow transparency.

A quick look on the net popped up this example of using ffmpeg to generate a stream of PPM images

Code: Select all

ffmpeg -i img%03d.jpg -f image2pipe -vcodec ppm - 
This seems to be the intended use of the image2pipe option. Not with JPEGs.

Note that the IM internal file format MIFF also allow this multi-image pipelines, and thus allow you to do a pipeline of multiple files. See http://www.imagemagick.org/Usage/files/#miff about the format. It is actually much like an expanded PNM format with more header information, and more colorspace options, with the ability to handle multiple depths and even an alpha channel.

For an example of using a pipelined MIFF technique see.. Programmed Layering of Images...
http://www.imagemagick.org/Usage/layers/#layer_prog

a number of existing scripts also use that same technique, including the simple script
http://www.imagemagick.org/Usage/scripts/show_colors
And a more complex script
http://www.imagemagick.org/Usage/script ... med_colors
The image created by that script is displayed at
http://www.imagemagick.org/Usage/colors_basics/#colors
Anthony Thyssen -- Webmaster for ImageMagick Example Pages
http://www.imagemagick.org/Usage/

nixscripter
Posts: 8
Joined: 2011-03-17T12:12:45-07:00
Authentication code: 8675308

Re: reading multiple images over standard input

Post by nixscripter » 2011-03-19T07:54:24-07:00

Thanks for your answer!
anthony wrote:That is very difficult. However some formats are designed to let you pipe multiple images through a pipe.
I could use another format. JPEG was just the easiest example.
Note that the IM internal file format MIFF also allow this multi-image pipelines, and thus allow you to do a pipeline of multiple files. See http://www.imagemagick.org/Usage/files/#miff about the format.
That link is dead. (Fixed - anthony)

But I like the idea. I tried to PPMs from ffmpeg (as you suggested) and then do a simple convert command to turn them all into a MIFF stream:

Code: Select all

ffmpeg -i input.mpg -f image2pipe -vcodec ppm - | convert - miff:- | convert - info:-
The right information is printed... but that is only half the work.
For an example of using a pipelined MIFF technique see.. Programmed Layering of Images...
http://www.imagemagick.org/Usage/layers/#layer_prog

a number of existing scripts also use that same technique, including the simple script
http://www.imagemagick.org/Usage/scripts/show_colors
And a more complex script
http://www.imagemagick.org/Usage/script ... med_colors
The image created by that script is displayed at
http://www.imagemagick.org/Usage/colors_basics/#colors
The thing is, all of those scripts turn the images piped in into a single image, which is then output. I would need to apply my set of transforms (convolution matrix, for example) on each of the images, and then output all of them separately, in the same order.

How can I apply a transform to all of the images that have been buffered?

User avatar
anthony
Posts: 8881
Joined: 2004-05-31T19:27:03-07:00
Authentication code: 8675308
Location: Brisbane, Australia

Re: reading multiple images over standard input

Post by anthony » 2011-03-20T01:21:14-07:00

[quote="nixscripter"
Note that the IM internal file format MIFF also allow this multi-image pipelines, and thus allow you to do a pipeline of multiple files. See http://www.imagemagick.org/Usage/file/MIFF about the format.
That link is dead.[/quote]

Sorry - fixed it above, but here it is again...
http://www.imagemagick.org/Usage/files/#miff
The thing is, all of those scripts turn the images piped in into a single image, which is then output. I would need to apply my set of transforms (convolution matrix, for example) on each of the images, and then output all of them separately, in the same order.

How can I apply a transform to all of the images that have been buffered?
They may all pipe into a command using a single image reader '-' or 'miff:-' or for you you can use 'ppm:-' However in memory all the image remain separate. Those script generally 'layer the images into one image for final output, but you don't have to do that either.

You have the images in memory, so just save them using Writing a Multi-Image Sequence
http://www.imagemagick.org/Usage/files/#adjoin
EG:

Code: Select all

   ffmpeg .... -vcodec ppm | convert - frame_%05d.jpg
will save each image as frame_00000.jpg frame_00001.jpg .... and so on
However be warned that convert will end up reading EVERY frame into memory first! so don't do it to a full movie!

If you have ffmpeg save into individual ppm (or other) image file you can then use morgify to modify each image in turn one image at a time.

WARNING: JPEG is a loosy format, saving into JPEG looses quality - saving over and over and your images will degrade significantly.
Anthony Thyssen -- Webmaster for ImageMagick Example Pages
http://www.imagemagick.org/Usage/

nixscripter
Posts: 8
Joined: 2011-03-17T12:12:45-07:00
Authentication code: 8675308

Re: reading multiple images over standard input

Post by nixscripter » 2011-03-20T06:56:08-07:00

anthony wrote: You have the images in memory, so just save them using Writing a Multi-Image Sequence
http://www.imagemagick.org/Usage/files/#adjoin
EG:

Code: Select all

   ffmpeg .... -vcodec ppm | convert - frame_%05d.jpg
will save each image as frame_00000.jpg frame_00001.jpg .... and so on
But the point is, I don't want to save them. I don't want temporary files at any point. ffmpeg can take the ppm files back in as input, and that is what I want to do.

I just tried it, and my question was answered: operators in ImageMagick seem to operate on all images by default.

For example, suppose I want to apply a convolution matrix (sharpening in this case) to every frame. This will do what I want:

Code: Select all

ffmpeg -i input.mpg -f image2pipe -vcodec ppm - | \ 
         convert - -morphology Convolve '3x3: -1, -1, -1 \
                                              -1,  9, -1 \
                                              -1, -1, -1' ppm:- | \
        ffmpeg -f image2pipe -vcodec ppm -i - output.mpg
Yes, I am aware this will use a lot of memory. That is why this machine has plenty. I'm going for speed, and it's a whole lot faster than writing it to disk.

Thanks for your help!

User avatar
anthony
Posts: 8881
Joined: 2004-05-31T19:27:03-07:00
Authentication code: 8675308
Location: Brisbane, Australia

Re: reading multiple images over standard input

Post by anthony » 2011-03-20T18:01:30-07:00

nixscripter wrote:Operators in ImageMagick seem to operate on all images by default.
Actually commands operate on all images from a single file or stream by default.

It may be posible to modify mogrify such that it only reads one image at a time from some
image streams (such as stdin for PPM (and variants) or MIFF) and process them one at a time.

Actually this would be a very useful thing. Sort of a 'stream' which is a row-by-row processing abstraction.
but at an image level of processing abstraction. 'morgrify' is the purely a file level of processing abstraction,
But perhaps it could be a image level abstraction for MIFF and PNG formats.

I'll pass this to Cristy...
Anthony Thyssen -- Webmaster for ImageMagick Example Pages
http://www.imagemagick.org/Usage/

User avatar
anthony
Posts: 8881
Joined: 2004-05-31T19:27:03-07:00
Authentication code: 8675308
Location: Brisbane, Australia

Re: [SOLVED] reading multiple images over standard input

Post by anthony » 2011-03-20T18:18:02-07:00

NOTE I just tryied something to see if it would work. but it didn't...

Code: Select all

# Input multi-image file stream (two images)
convert rose: granite: ppm:- |

# now a loop to try and read only one image at at time
while true; do
  convert -regard-warnings 'ppm:-[0]' info:
  [ $? -ne 0 ] && break
done
The result was only one image was read in, the second was not found by the next command :-(
That mean the input stream was fully read, junking the later images

I also tried to do this with the NetPBM program "pampick"

Code: Select all

convert rose: granite: ppm:- |
while true; do
  pampick 0 | convert -regard-warnings 'ppm:-[0]' info:
  [ $? -ne 0 ] && break
done
but it also seemed to also fully read the input stream, so again only one image was returned.

We need a small program to only read and write one file from the input stream, then quit. It should not read any part of the second or later file, so that the next time the program is run it can read that next part of the input stream.
Anthony Thyssen -- Webmaster for ImageMagick Example Pages
http://www.imagemagick.org/Usage/

nixscripter
Posts: 8
Joined: 2011-03-17T12:12:45-07:00
Authentication code: 8675308

Re: [SOLVED] reading multiple images over standard input

Post by nixscripter » 2011-04-03T11:38:27-07:00

I'm not sure if you are making a somewhat different point -- I think you are -- but FWIW, the ffmpeg command in my last post actually works. Apparently, standard input is "one source".

In fact, I have written a simple shell script to do an arbitrary transformation, if you put it in backslashed quote marks:

Code: Select all

#!/bin/bash
# NOTE: you need to backslash all of your quotes used for shell arg markers
#
# COPYRIGHT: none, released into the public domain by nixscripter. You're welcome.
#
infile=$1
outfile=$2
shift 2;

if [ x = x"$infile" -o x = x"$outfile" -o x = x"$*" ] ; then
    echo "Usage: $0 input-movie output-movie magick args..."
    exit 2
fi

ffmpeg -i "$infile" -f image2pipe -vcodec ppm - | eval "convert - $* ppm:-" | ffmpeg -y -f image2pipe -vcodec ppm -i - -sameq "$outfile"


User avatar
anthony
Posts: 8881
Joined: 2004-05-31T19:27:03-07:00
Authentication code: 8675308
Location: Brisbane, Australia

Re: [SOLVED] reading multiple images over standard input

Post by anthony » 2011-04-03T19:16:48-07:00

Yes that would work, though the center convert command will read into memory ALL the images from the input file stream, before writing them output again. That means it will read in that whole video as uncompressed images in memory! That is a lot of memory.

To save memory so that the command (mogrify for example) only handles one image (frame) at a time, you need something to break the input stream into separate images and process each image, one at a time!

Hmmm.. PNM format is simple enough , in a raw ppm just look a lines starting with 'P' and you found the next image (frame). I could do this in shell but only by using very fancy shell programming. It's easier in perl...

Code: Select all

  ffmeg -i "$infile" -f image2pipe -vcodec ppm -. | pnmnoraw |
    perl -e '
       sub do_cvt {       
          open(CVT, "|-") 
              or exec("convert - -flip ppm:-");
          print CVT $image;
          close CVT;
          undef $image;
       }
       while ( <> ) {
           do_cvt   if /^P/ && $image;
           $image .= $_;
       }
       do_cvt if $image;
  ' |  ffmpeg -y -f image2pipe -vcodec ppm -i -sameq "$outfile"
It works!

The perl script reads STDIN until it sees the start of the next PPM image. It then feeds the full single PPM image it has read so far into the convert command, which outputs a new single PPM to the perl's STDOUT. The script then continues to record the next image, until EOF, at which point it processes the last image it has read in.

That convert command will only be given ONE single image, and that is all. The whole perl-convert script will processes them while the ffmpeg command continues to generate them, without attempting to read ALL the images into memory first.

That means all three parts of the pipeline will be active, allowing you to process VERY VERY large sequences of images, but with each command only dealing with one image at a time.

The perl can be made more general by making it a script that takes a convert command as a argument.

Just replace the "convert ..." line and specifically the -flip part, with what ever you want!

The above can go further and replace the open-exec-close with a PerlMagick to process the read in "$image" (known as a Blob), in Perl itself, without needing to reinitialize ImageMagick for each image.
Anthony Thyssen -- Webmaster for ImageMagick Example Pages
http://www.imagemagick.org/Usage/

User avatar
anthony
Posts: 8881
Joined: 2004-05-31T19:27:03-07:00
Authentication code: 8675308
Location: Brisbane, Australia

Re: [SOLVED] reading multiple images over standard input

Post by anthony » 2011-04-07T21:24:44-07:00

I have converted that ascii-PPM image pipeline program into a script "process_ppm_pipeline"
http://www.imagemagick.org/Usage/script ... m_pipeline

As such you can do you CLUT of images like this...

Code: Select all

 ffmpeg input.mpg -f image2pipe -vcodec ppm | pnmnoraw |
   process_ppm_pipeline     -some-transform    |
   ffmpeg -f image2pipe -vcodec jpeg output.mpg

Note the "process_ppm_pipeline" script takes normal "convert" arguments, but you exclude the input read (assume ONE image is already read in) and the output image filename. You just give the options you want to use to convert the pipeline, one image at a time.
Anthony Thyssen -- Webmaster for ImageMagick Example Pages
http://www.imagemagick.org/Usage/

OrangeDog
Posts: 17
Joined: 2012-06-18T13:19:52-07:00
Authentication code: 13

Re: [SOLVED] reading multiple images over standard input

Post by OrangeDog » 2012-11-15T05:35:48-07:00

For example, suppose I want to apply a convolution matrix (sharpening in this case) to every frame.
In such a case you should really use ffmpeg's own filters - saving potentially massive amounts of time and space.

Code: Select all

ffmpeg -i input.mpg -filter:v "unsharp" output.mpg
The "unsharp" filter has various parameters to control the strength of sharpening/blurring.
http://ffmpeg.org/ffmpeg.html#unsharp

User avatar
anthony
Posts: 8881
Joined: 2004-05-31T19:27:03-07:00
Authentication code: 8675308
Location: Brisbane, Australia

Re: [SOLVED] reading multiple images over standard input

Post by anthony » 2012-11-22T23:45:55-07:00

Well you reserected a old thread... but there is news that is appropriate to this thread.

IMv7 will have features to read a single image from a input pipeline, rather than reading the whole pipeline all at once.
This means you should be able to loop over a "magick" (IMv7 version of convert) command which reads and processes each image in a pipeline before passing it on.

This should make the generation of special effects, such as credits on a active video feed, or though thing a lot easier.

Of course ImageMagick will not do sound, but as a background support for other video editors, it will make it much more versatile.
Anthony Thyssen -- Webmaster for ImageMagick Example Pages
http://www.imagemagick.org/Usage/

Post Reply