Stretch/Scale only center of overlay image

classic Classic list List threaded Threaded
5 messages Options
Reply | Threaded
Open this post in threaded view
|

Stretch/Scale only center of overlay image

Hans Carlson-2
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%
_______________________________________________
ffmpeg-user mailing list
[hidden email]
https://ffmpeg.org/mailman/listinfo/ffmpeg-user

To unsubscribe, visit link above, or email
[hidden email] with subject "unsubscribe".
Reply | Threaded
Open this post in threaded view
|

Re: Stretch/Scale only center of overlay image

Michael Koch
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

_______________________________________________
ffmpeg-user mailing list
[hidden email]
https://ffmpeg.org/mailman/listinfo/ffmpeg-user

To unsubscribe, visit link above, or email
[hidden email] with subject "unsubscribe".
Reply | Threaded
Open this post in threaded view
|

Re: Stretch/Scale only center of overlay image

kumowoon1025
In reply to this post by Hans Carlson-2
> 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.
_______________________________________________
ffmpeg-user mailing list
[hidden email]
https://ffmpeg.org/mailman/listinfo/ffmpeg-user

To unsubscribe, visit link above, or email
[hidden email] with subject "unsubscribe".
Reply | Threaded
Open this post in threaded view
|

Re: Stretch/Scale only center of overlay image

Hans Carlson-2
In reply to this post by Michael Koch
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.
_______________________________________________
ffmpeg-user mailing list
[hidden email]
https://ffmpeg.org/mailman/listinfo/ffmpeg-user

To unsubscribe, visit link above, or email
[hidden email] with subject "unsubscribe".
Reply | Threaded
Open this post in threaded view
|

Re: Stretch/Scale only center of overlay image

Hans Carlson-2
In reply to this post by kumowoon1025
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.
_______________________________________________
ffmpeg-user mailing list
[hidden email]
https://ffmpeg.org/mailman/listinfo/ffmpeg-user

To unsubscribe, visit link above, or email
[hidden email] with subject "unsubscribe".