Search code examples
image-processingffmpegjpegcrop

Merge a sequence of JPEG images into a grid losslessly with FFmpeg


I have a sequence of images that are blocks of a larger image, which together make up the whole image. The blocks are the result of splitting the original image along evenly spaced horizontal and vertical lines, so they don't have weird dimensions.

Is there a way to combine them with FFmpeg (or something else like ImageMagick) without re-encoding the images?

This answer suggests the hstack or vstack FFmpeg filter, but my image blocks aren't necessarily the full width or the full height of the original image.


Like this:

Six blocks of differing sizes in a 3-row, 2-column grid

Perhaps this could be achieved with multiple FFmpeg commands using hstack or vstack (I'd prefer just one command though). Or with a complex filter?


e.g. Mona Lisa split into six distinct blocks, then arranged together


Edit: I tried using filter_complex with FFmpeg:

ffmpeg -i 0.jpg -i 1.jpg -i 2.jpg -i 3.jpg -i 4.jpg -i 5.jpg \
-filter_complex "[0][1]hstack=inputs=2[row 0]; \
                 [2][3]hstack=inputs=2[row 1]; 
                 [4][5]hstack=inputs=2[row 2]; 
                 [row 0][row 1][row 2]vstack=inputs=3[out]" \
-map "[out]" -c copy out.jpg

but it can't filter and copy streams at the same time.


Solution

  • I found an interesting patch from 2010 against libjpeg which adds this feature to jpegtran. It won't split blocks, so your images will need to be multiples of 8 or even 16 pixels in each axis.

    Unfortunately it's against the libjpeg 6b as distributed for ubuntu10. This includes some patches from 8d and doesn't really correspond neatly to any official libjpeg version (as far as I can see).

    You need to download the ubuntu10.04 sources, extract their libjpeg, and patch that. The steps are:

    wget http://old-releases.ubuntu.com/releases/releases/10.04/release/source/ubuntu-10.04-src-1.iso
    

    Now open that ISO and pull out the files from ubuntu/pool/main/libj/libjpeg6b. Archive Manager can do this, perhaps there's some scriptable tool as well.

    Now run:

    # original sources
    tar xf libjpeg6b_6b.orig.tar.gz
    cd jpeg-6b
    
    # apply ubuntu patches
    zcat ../libjpeg6b_6b-15ubuntu1.diff.gz | patch
    
    # apply jpegtran patches
    patch < ../append-jpeg6b.patch
    
    ./configure
    make
    sudo make install
    

    That will install the modified jpegtran to /usr/local.

    Given 0.jpg and 1.jpg:

    enter image description here

    You can run it like this:

    jpegtran -appright 1.jpg 0.jpg > join.jpg
    

    To make:

    enter image description here