user10425333
user10425333

Reputation:

How to combine 2 images with ffmpeg?

I have 2 images which I'd like to place one on top of the other. I made this line:

ffmpeg -i "C:\image_1.jpg" -i "C:\image_2.jpg" -q:v 1 -filter_complex "[0:v]scale=800:-1[v0];[v0][1:v]vstack" C:\combined.jpg

and it works when they have the same resolution 800x800 and when the resolution of the first one is smaller than image_2.

Is it possible to add some mathematics instead of 800 to make this line suitable for any type of resolutions when the first one is bigger or the second is bigger (width and height separately)?

I want to find a maximal dimension and scale another image to it preserving aspect ratio. If the aspect ratio of 2 images is not the same fill the holes with plain white (255,255,255).

I suppose the mathematics should be like this:

w1, h1 - width and height of the 1st img
w2, h2 - width and height of the 2st img
w1', h1', w2', h2' - width and height of resulted images

if w1 max{w1, h1, w2, h2} -> if w2/h2>=1 -> w2'=w1; h2'=h2*w2'/w2
if w1 max{w1, h1, w2, h2} -> if w2/h2<1  -> h2'=w1; w2'=w2*h2'/h2

if h1 max{w1, h1, w2, h2} -> if w2/h2>=1 -> w2'=h1; h2'=h2*w2'/w2
if h1 max{w1, h1, w2, h2} -> if w2/h2<1  -> h2'=h1; w2'=w2*h2'/h2

if w2 max{w1, h1, w2, h2} -> if w1/h1>=1 -> w1'=w2; h1'=h1*w1'/w1
if w2 max{w1, h1, w2, h2} -> if w1/h1<1  -> h1'=w2; w1'=w1*h1'/h1

if h2 max{w1, h1, w2, h2} -> if w1/h1>=1 -> w1'=h2; h1'=h1*w1'/w1
if h2 max{w1, h1, w2, h2} -> if w1/h1<1  -> h1'=h2; w1'=w1*h1'/h1

Example 1 Example 2

If the two images i1 and i2 are 800x800 and - 436x800 resp: the combined image will be 800x1600.

If the two images i1 and i2 are 300x400 and 200x500 resp: max(300,400,200,500)=500; 300x400 -> (300*500/400=375)x500 ; 200x500 -> 200x500. Align the smallest one (200x500) to center, fill the gaps (2 gaps: (375-200)/2=88) with white (255,255,255).

Upvotes: 1

Views: 1609

Answers (1)

Gyan
Gyan

Reputation: 93329

Use

ffmpeg -i image_0.jpg -i image_1.jpg -filter_complex
       "sws_flags=bicubic;
        color=c=white:4x4,format=yuvj444p,trim=end_frame=1,split=2[c0][c1];
        [0][1]scale2ref='if(gte(max(main_w,main_h),max(iw,ih)),main_w,if(gte(main_w,main_h),iw,oh*mdar))':
                        'if(gte(max(main_w,main_h),max(iw,ih)),main_h,if(gte(main_w,main_h),ow/mdar,ih))'[0max][1ref];
        [1ref][0max]scale2ref='if(gte(max(main_w,main_h),max(iw,ih)),main_w,if(gte(main_w,main_h),iw,oh*mdar))':
                        'if(gte(max(main_w,main_h),max(iw,ih)),main_h,if(gte(main_w,main_h),ow/mdar,ih))'[1max][0max];
        [c0][0max]scale2ref[c0max][0max];[c1][1max]scale2ref[c1max][1max];[c0max][c1max]scale2ref='if(gte(main_w,iw),main_w,iw)':main_h[c0max][c1max];
        [c1max][c0max]scale2ref='if(gte(main_w,iw),main_w,iw)':main_h[c1max][c0max];
        [c0max][0max]overlay=format=auto:x=(W-w)/2:y=(H-h)/2[0f];[c1max][1max]overlay=format=auto:x=(W-w)/2:y=(H-h)/2[1f];
        [0f][1f]vstack,setsar=1"  out.jpg

This will scale the image with the smaller dimensions proportionally to match the largest dimension of both the inputs. Then the resized images are overlaid on a canvas of the same width and finally stacked.


Old answer

You'll need to use the scale2ref filter, twice.

ffmpeg -i image1 -i image2 -filter_complex
       "[0][1]scale2ref=w='max(iw,main_w)':h=ow/mdar[0max][1ref];
        [1ref][0max]scale2ref=w='max(iw,main_w)':h=ow/mdar[1max][0max];
        [0max][1max]vstack" -q:v 1 combined.jpg

Upvotes: 3

Related Questions