Stretch/Scale only center of overlay image
Is it possible to stretch/scale only the center part of an overlay image? I don't mean the middle section of a video, I mean only the center part of a single image (png) that will be overlayed onto a background, such that the left and right sides are relatively unchanged, but the center of the image is stretched to fit the new size. To further explain... I have a background image with a bunch of text lines of varying length. I want to overlay an oval (actually a rounded rectangle) over some text as a highlight. Since all the text parts are different lengths, I'll either need to create a separate overlay image for each one OR create one standard overlay image and "stretch/squeeze" it to fit each section of text. I'd prefer to create only a single overlay image. The problem is, when I try to stretch/squeeze my rounded rectangle (using scale) the ends either get stretched too much or squeezed too much depending if I need to scale up or down. What I'd like to see is the ends look the same (or close to) the original overlay image and only the center part is stretched/squeezed. Is there some filter I can use instead of or in addition to "scale" that will do something like this? Below is an example that illustrates the issue using the ImageMagick "convert" command to generate the background and highlight images and ffmpeg to overlay the highlight on the background. What you'll notice is the highlight around the shortest text has the ends squeezed too much and the highlight around the longest text has the ends stretched too much. Create a background image with 4 text lines: $ convert -size 720x480 xc:black -font DejaVu-Sans -pointsize 20 -fill white -draw "text 200,100 'not scaled at all'" -draw "text 200,200 'short'" -draw "text 200,300 'middle size line'" -draw "text 200,400 'very very long line with extra words" background.png Create a rounded rectangle highlight for the overlay: $ convert -size 200x50 xc:none -fill transparent -stroke green -strokewidth 5 -draw "roundrectangle 10,5 190,45 20,20" highlight.png Overlay the highlight on each text line and "stretch/squeeze" (using scale) to fit the text width: $ ffmpeg -loop 1 -i background.png -loop 1 -i highlight.png -codec:v mpeg2video -b:v 16384k -bufsize 4096k -maxrate 30000k -filter_complex '[1:0]scale=70:in_h[o1];[1:0]scale=190:in_h[o2];[1:0]scale=430:in_h[o3];[0:0][1:0]overlay=x=180:y=70[v1];[v1][o1]overlay=x=190:y=170[v2];[v2][o2]overlay=x=182:y=270[v3];[v3][o3]overlay=x=166:y=370' -t 5 -f vob example.mpg ffmpeg version N-96725-g13dc90396d Copyright (c) 2000-2020 the FFmpeg developers built with gcc 9 (GCC) configuration: libavutil 56. 40.100 / 56. 40.100 libavcodec 58. 68.102 / 58. 68.102 libavformat 58. 38.100 / 58. 38.100 libavdevice 58. 9.103 / 58. 9.103 libavfilter 7. 75.100 / 7. 75.100 libswscale 5. 6.100 / 5. 6.100 libswresample 3. 6.100 / 3. 6.100 Input #0, png_pipe, from 'background.png': Duration: N/A, bitrate: N/A Stream #0:0: Video: png, gray(pc), 720x480, 25 fps, 25 tbr, 25 tbn, 25 tbc Input #1, png_pipe, from 'highlight.png': Duration: N/A, bitrate: N/A Stream #1:0: Video: png, pal8(pc), 200x50, 25 fps, 25 tbr, 25 tbn, 25 tbc Stream mapping: Stream #0:0 (png) -> overlay:main Stream #1:0 (png) -> scale Stream #1:0 (png) -> scale Stream #1:0 (png) -> scale Stream #1:0 (png) -> overlay:overlay overlay -> Stream #0:0 (mpeg2video) Press [q] to stop, [?] for help Output #0, vob, to 'example.mpg': Metadata: encoder : Lavf58.38.100 Stream #0:0: Video: mpeg2video (Main), yuv420p, 720x480, q=2-31, 16384 kb/s, 25 fps, 90k tbn, 25 tbc (default) Metadata: encoder : Lavc58.68.102 mpeg2video Side data: cpb: bitrate max/min/avg: 30000000/0/16384000 buffer size: 4096000 vbv_delay: N/A frame= 125 fps=0.0 q=2.0 Lsize= 378kB time=00:00:04.92 bitrate= 629.4kbits/s speed=11.9x video:373kB audio:0kB subtitle:0kB other streams:0kB global headers:0kB muxing overhead: 1.427849%
Am 13.02.2020 um 02:36 schrieb Hans Carlson:
Is it possible to stretch/scale only the center part of an overlay image?
I don't mean the middle section of a video, I mean only the center part of a single image (png) that will be overlayed onto a background, such that the left and right sides are relatively unchanged, but the center of the image is stretched to fit the new size.
Do you mean a continuous zoom like image warping? I have a few examples in my book (search for "image warping"): http://www.astro-electronic.de/FFmpeg_Book.pdf Michael
On Thu, 13 Feb 2020, Michael Koch wrote:
Do you mean a continuous zoom like image warping? I have a few examples in my book (search for "image warping"): http://www.astro-electronic.de/FFmpeg_Book.pdf
Well... maybe... but I don't think so, at least not the way it's used in your book. I ONLY want to stretch horizontally. And I want to stretch uniformly or at least the same way the scale filter does it. I don't want any inward or outward distortion effect as in your warping examples. If the displace filter can do this, I assume it depends on the equations used and I have no idea what those equations might be.
Is it possible to stretch/scale only the center part of an overlay image?
I don't mean the middle section of a video, I mean only the center part of a single image (png) that will be overlayed onto a background, such that the left and right sides are relatively unchanged, but the center of the image is stretched to fit the new size.
You will need to have three sections (two if you mirror the left or right) and stretch only the center, and do the math for positioning each one. Conceivably you could do this with one overlay image and a combination of crop and split filters, but I feel that would be unnecessarily convoluted, the positioning calculations are a headache already, at least for me. I would create separate half-circle and parallel line overlay images. Of course this wouldn’t result in an oval, but I think the elongated “pill” shape is what you’re going for anyway.
On Thu, 13 Feb 2020, Ted Park wrote:
Is it possible to stretch/scale only the center part of an overlay image?
I don't mean the middle section of a video, I mean only the center part of a single image (png) that will be overlayed onto a background, such that the left and right sides are relatively unchanged, but the center of the image is stretched to fit the new size.
You will need to have three sections (two if you mirror the left or right) and stretch only the center, and do the math for positioning each one. Conceivably you could do this with one overlay image and a combination of crop and split filters, but I feel that would be unnecessarily convoluted, the positioning calculations are a headache already, at least for me. I would create separate half-circle and parallel line overlay images. Of course this wouldn’t result in an oval, but I think the elongated “pill” shape is what you’re going for anyway.
I wouldn't be able to mirror the left/right because my "highlight" image isn't uniform... think more like circling a word or sentence by hand using a felt tip pen. It is a "pill" shape, but intended to look more "hand drawn" than uniform. I had considered the idea of splitting the image into 3 parts (as a backup plan) although I hadn't considered using a single image and crop. As it turns out this isn't quite as bad as I first thought... in fact the calculations are simple if the hstack filter is used to recombine the pieces. The raw HIGHTLIGHT.png image is 200 wide where the "ends" are each 30 wide, meaning the center section to be scaled is 140 wide. So, if I want a virtual highlight that's 300 wide, the center section needs to be: 300 - 30 - 30 = 240 ffmpeg -loop 1 -i BACKGROUND.png -loop 1 -i HIGHTLIGHT.png -complex_filter [1:0]split=3[l0][c0][r0]; [l0]crop=30:50:0:0[l]; [c0]crop=140:50:30:0,scale=240:in_h[c]; [r0]crop=30:50:170:0[r]; [l][c][r]hstack=inputs=3[overlay]; [0:0][overlay]overlay=x=200:y=100 If instead I want a virtual highlight that's only 100 wide, the center needs to be: 100 - 30 - 30 = 40 The only thing that changes is the scale amount for the center section: ffmpeg -loop 1 -i BACKGROUND.png -loop 1 -i HIGHTLIGHT.png -complex_filter [1:0]split=3[l0][c0][r0]; [l0]crop=30:50:0:0[l]; [c0]crop=140:50:30:0,scale=40:in_h[c]; [r0]crop=30:50:170:0[r]; [l][c][r]hstack=inputs=3[overlay]; [0:0][overlay]overlay=x=200:y=100 Thanks for the suggestion. Other than a ready made filter that only applies scale to part of an image I think this is probably the best I can hope for. I don't know how efficient it is, but the files I'm creating are only a few seconds long, so efficiency isn't much of a concern.
participants (3)
-
Hans Carlson -
Michael Koch -
Ted Park