3

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.

Mody
  • 33
  • 5
  • Most tools will decompress and recompress your JPGs, so you will lose some quality. ImageMagick can make your grid combination using convert with append. But ImageMagick will decompress and recompress your JPG as mentioned above. – fmw42 Jan 20 '20 at 00:11
  • I seem to remember libvips works by splitting up the image, compressing macroblocks separately, and merging the data back together. You might find something useful in its source code. https://libvips.github.io/libvips/ – Brad Jan 20 '20 at 01:52
  • @Brad sorry, libvips will decompress and recompress, like ImageMagick. – jcupitt Jan 20 '20 at 04:26
  • 1
    I found this interesting patch to jpegtran -- it adds lossless append of two jpg images: https://puhuri.iki.fi/src/libjpeg/ You might be able to work something up out of that. – jcupitt Jan 20 '20 at 04:27
  • @jcupitt Lol, and like magic, you stop by this thread. :-) Yeah, my suggestion was not that they use libvips directly, but that they see how you were doing your macroblock reassembly in JPEG. Is my recollection correct in that you're doing compression on each block separately and then reassembling? – Brad Jan 20 '20 at 05:00
  • @jcupitt That looks great and exactly like what you'd need to solve this, but it's not clear to me how to get that functionality into jpegtran. How can you apply the patch? – Mody Jan 20 '20 at 06:41
  • Hey @Brad, yes, libvips processes JPG images a chunk at a time, but it still decompresses and recompresses. It's able to do the decompress and recompress in parallel -- that's the (supposed) benefit. – jcupitt Jan 20 '20 at 10:44

2 Answers2

3

You can do that with ImageMagick. However, it will decompress and recompress your jpg files. You will lose some quality.

Unix Syntax for IM 6:

convert \
\( 0.jpg 1.jpg +append \) \
\( 2.jpg 3.jpg +append \) \
\( 4.jpg 5.jpg +append \) \
-append \
mona_lisa.jpg


If using Windows remove the \ from the parentheses and replace the end of line \ with ^.

If using IM 7, replace convert with magick.

fmw42
  • 46,825
  • 10
  • 62
  • 80
1

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

jcupitt
  • 10,213
  • 2
  • 23
  • 39