moviepy icon indicating copy to clipboard operation
moviepy copied to clipboard

Weird aliasing problem on text border

Open synhaptein opened this issue 10 years ago • 8 comments

Basically I put a text, set a background black with an opacity of 0.3 and add it to an image with a white background.

Anyone have an idea why I got those aliasing problems (not sure if it's call like that!?) on the border of the letters?

I don't know enough about video/image processing to understand what's really going on here, but from what I understand, when the text is merged with the background, the alpha is ignored?

capture d ecran 2015-08-19 a 15 01 38

capture d ecran 2015-08-19 a 15 02 59

synhaptein avatar Aug 19 '15 19:08 synhaptein

Hard to say without your code, but the general problem I guess is that ImageMagick is bad at antialiasing. One easy fix is to generate a text with 2x size and 2x the stroke width, then downsize it by half:

txt_clip = TextClip("test text", fontsize=72, stroke_width=12, color="white",
                              stroke_color="black").resize(0.5)

Tell me if this works.

Zulko avatar Aug 20 '15 10:08 Zulko

I tried, but I get the same effect and to be clearer, there should not be a stoke on the text. What appears to be a stroke is the artifacts of the merge of 3 layers.

I don't think that there's a problem with the aliasing of the text, I think there's a problem when the text and the background is merged. But I'm not sure that I understand how it works mask vs matrix with RGB values. Is the mask the alpha channel? My guess is that when the edge of the letter is merge with the background, it ignores the alpha value of the background.

Layer 0 (White image) Layer 1 (Text background "black" with alpha value) Layer 2 (Text with alpha value on the edge of the letters... I guess?)

So when it merges Layer 2 with Layer 1, instead of merging the rgba values of Layer 2 with rgba values of Layer 1, it computes Layer 2 rgba values with rgb values of Layer 1... I don't know if it makes sense or if I'm totally wrong on this one, but it would explain the weird stroke-like effect on the edge of the letters by using solid black instead of the compute value of the merged of layer 0 and layer 1?

synhaptein avatar Aug 20 '15 17:08 synhaptein

Can you provide some code ? I'll give it a look when I have time. (I wonder if it's not something that I solved in my local version...)

Zulko avatar Aug 20 '15 18:08 Zulko

If we create a ColorClip (overlay) manually and compose the 3 layer, it fixes the problem.

screensize = (1280, 720)

background = ColorClip(screensize, (255, 255, 255), duration=0.1)
txt = TextClip("\nWeird problem with white font on transparent black background",
               method="caption",
               interline=5,
               size=(screensize[0], None),
               align="center",
               font='Times-Bold',
               kerning=1.5,
               fontsize=54,
               color='white').set_duration(0.1)
overlay = ColorClip((1280, txt.size[1]), (0, 0, 0), duration=0.1).set_opacity(0.25)

result = CompositeVideoClip([background, overlay, txt])

result.write_videofile("output.mov", codec='libx264', fps=fps, threads=8)

capture d ecran 2015-08-20 a 14 41 15

But if we use the on_color function, it creates a CompositeVideoClip of the text and a ColorClip and then get compose with the background.

screensize = (1280, 720)

background = ColorClip(screensize, (255, 255, 255), duration=0.1)
txt = TextClip("\nWeird problem with white font on transparent black background",
               method="caption",
               interline=5,
               size=(screensize[0], None),
               align="center",
               font='Times-Bold',
               kerning=1.5,
               fontsize=54,
               color='white').set_duration(0.1).on_color(col_opacity=0.25)

result = CompositeVideoClip([background, txt])

result.write_videofile("output.mov", codec='libx264', fps=fps, threads=8)

capture d ecran 2015-08-20 a 14 34 05

synhaptein avatar Aug 20 '15 18:08 synhaptein

But if I create a CompositeVideo([txt]) before the composition with the overlay and the background, I still get the same problem.

screensize = (1280, 720)

background = ColorClip(screensize, (255, 255, 255), duration=0.1)
txt = TextClip("\nWeird problem with white font on transparent black background",
               method="caption",
               interline=5,
               size=(screensize[0], None),
               align="center",
               font='Times-Bold',
               kerning=1.5,
               fontsize=54,
               color='white').set_duration(0.1)
overlay = ColorClip((1280, txt.size[1]), (0, 0, 0), duration=0.1).set_opacity(0.25)

result = CompositeVideoClip([background, overlay, CompositeVideoClip([txt])])

result.write_videofile("output.mov", codec='libx264', fps=fps, threads=8)

capture d ecran 2015-08-20 a 14 52 56

synhaptein avatar Aug 20 '15 18:08 synhaptein

Hello. I would like to add about this issue. It seems like there's a problem rendering text when it comes to nested CompositeVideoClip. Let me walk it through.

from moviepy.editor import *

screensize = (720, 460)

background = ColorClip(screensize, (244,244,244), duration=0.5)
txt = TextClip("Red",
               font='Helvetica-bold',
               fontsize=60,
               color='#1B53CB').set_pos('center').set_duration(0.5)

result = CompositeVideoClip([background, txt])

ipython_display(result,fps=25,codec='mpeg4')

When i just put a ColorClip and TextClip under one CompositeVideoClip, text renders smoothly.

screen shot 2018-04-11 at 11 44 55 am

Now, I try moving the TextClip (txt) to a "sub" CompositeClip

from moviepy.editor import *

screensize = (720, 460)

background = ColorClip(screensize, (244,244,244), duration=0.5)
txt = TextClip("Red",
               font='Helvetica-bold',
               fontsize=60,
               color='#1B53CB').set_pos('center').set_duration(0.5)

#sub-compositevidclip here
t1 = CompositeVideoClip([txt],size=screensize)

#t1 added in the main composite
result = CompositeVideoClip([background, t1])

ipython_display(result,fps=25,codec='mpeg4')

text now has weird, sharp, semi-dark border as describe in this issue:

screen shot 2018-04-11 at 11 44 33 am

It even looks worse if you make the font size smaller.

Let me know if I missed out something. Thanks

maitojepoy avatar Apr 11 '18 03:04 maitojepoy

I'm having the same issue. I should note that I'm using this instead of TextClip. Normal: image Nested CompositeVideoClip: image

TheRandomLabs avatar Apr 05 '20 02:04 TheRandomLabs

Still facing this issue.

ichitaka avatar Sep 23 '24 19:09 ichitaka

I might have the same problem. What I am thinking is that possibly, this is a problem with correctly "cutting" out the letters when applying operations to them? The letters use antialiasing, so "current" them out never really works robustly. At least, the results look pretty much like that.

@Zulko @OsaAjani can you look into this?

Also, #1395 might propose some fix that could be a starting point for fixing this bug in the project?

claell avatar Dec 09 '24 15:12 claell

Referencing my example from another issue, here: https://github.com/Zulko/moviepy/issues/2269#issuecomment-2571358998

Notice the problematic text borders around the red text:

https://github.com/user-attachments/assets/7ea5ff72-67d4-40a0-86b6-ba5b412bc9ab

I am not entirely sure whether this is the same bug or something else, but it looks pretty closely related.

claell avatar Jan 06 '25 12:01 claell

Probably mostly fixed by the #2307 pr (@claell) your problem is probably due to the fact you replace the mask of the second text, when the text antialiasing is actually achieved by his mask

OsaAjani avatar Jan 10 '25 21:01 OsaAjani

Ah, that's very possible. I was trying around a bit with the mask, and maybe due to the other bug did the mask in the wrong way while trying to overcome the transparency problem that is now fixed.

I am a newbie to moviepy. Will try to look at it in the next days. Any hint where I do things wrong is appreciated, though!

claell avatar Jan 10 '25 22:01 claell

Finally had time to revisit this. I think that your remark was right. I managed to fix this, using a different approach of masking. Thanks again for your help with this!

claell avatar Apr 18 '25 16:04 claell