Color on edges of text/masks/etc

The colors on edges of text and masks and other things don’t look right.

Here’s three examples that have been zoomed-in on: a mask ellipse, text with white outline, and text with transparent outline. Why are there dark pixels here?

I could give many more examples. The second row is some random gradients made in GIMP that give some indication of what I think these pixels should look like.

(This might be related to Incorrect behavior of Opacity filter with dissolve transition which I replied to a few weeks ago.)

Any help would be appreciated, this has been driving me crazy for a while.

bug.mlt (8.0 KB)

Full-size pictures

I have only taken a look at the text so far and reproduced it with Text: Simple with 0 outline on a red color clip. We are using Qt QPainter for that, and I tinkered around with the API and docs but could not figure out a way to change it yet. I found this related post in the web search, and it links to a number of similar bug reports and posts. Curious thing is looking at your picture is you can see some pink pixels which is the white blending properly with the red, but further away from the inside of the text, it goes dark. Those appear to be black translucent pixels blending with the background.
I get similar result when I put a Crop: Circle filter with red on a white color clip (Shotcut 20.09.13 uses Qt for Crop: Circle):

Upon switching to version 20.02, which uses WebKit for Crop: Circle, I get a similar result:

Using the same version white Text: HTML on a red clip:

So, it appears WebKit has this same behavior as QPainter. Even changing the HTML body background color to opaque red so there is no alpha-compositing outside WebKit:

I suspect internally these things draw against a transparent black background regardless of the foreground color before blending layers. And some pixels of the background become translucent as some side effect (not just anti-aliasing because similar happened when I turned that off).Then, these translucent black pixels blend with the background color.

This happens even with the “Size, Position & Rotate” filter.

One interesting phenomenon is that the errors always happen in the horizontal direction, even if you rotate afterwards. This makes me wonder if the bug’s as simple as a misindexed array somewhere (assuming pixel information is stored as [y * width + x]).

For example, here’s “Crop: Circle” with red on teal:

The left side of the circle has two kinds of stripes. They’re both transitions from teal to red, but the outside one passes through white-gray while the inside one passes through black-gray. A circle made in GIMP has the transition from teal to red passing through gray-gray.

The top side of the circle looks better but it’s still not right. The pixels seem to alternate, one being too light and the next being too dark. You can see this clearly when comparing it to the GIMP circle.

I did the other color pairs as well:


Why do the different combinations transition through these particular shades of gray, does that give us a clue as to what’s going on?

Here is “Mask: Simple Shape” ellipse with some softness rather than a hard edge.

The pattern holds again, pixels alternate from too light to too dark in the horizontal direction. This is hard to see on the top edge, which mostly matches the gradient made with GIMP. But the right edge is a different story, with the alternating light and dark bands being clearly visible.

I figured out that there are a few reasons why this occurs and is different than GIMP: colorspace conversion, chroma subsampling, and non-linear color processing. The reasons combine to worsen the result.

  1. Start with a test project consisting only of RGB sources and filters. Here is mine
    shotcut bug 21255.mlt (8.8 KB)
  2. Export it with preset FFV1 but in the Other tab change pix_fmt=bgr0 to export it as RGB.
  3. Use VLC to playback the result and export frames as PNG.
    Do not use Shotcut with Video Zoom scope as the player converts everything to YUV 4:2:0 for more effecient playback through OpenGL.
  4. Open the PNG and zoom in.
    Do not use Shotcut’s File > Export Frame… because that comes from the player

For the ellipse made using Mask: Simple Shape
No unwanted colors (this filter is not anti-aliased and only provides softness.)

Repeat the above procedure with pix_fmt=yuv444p and mlt_image_format=rgb24 (colorspace conversion with no chroma subsampling):

Still looks perfect because we told MLT to render to RGB instead of YUV 4:2:2, and the colorspace conversion is fairly accurate with no chroma subsampling.

Repeat the above with FFV1 defaults (pix_fmt=yuv422p and mlt_image_format=yuv422):

Here we start to get miscolored pixels because the chroma data is half the resolution (horizontal only) of the luma. We use FFmpeg libswscale for colorspace conversion, and we have tweaked its flags extensively. Upon decoding for playback it must do some interpolation on the chroma, and when colors with gamma mix it produces dark artifacts like this as explained in the following articles:

Repeat the above procedure using pix_fmt=yuv420p:
The situation is worse because now the chroma resolution is half the luma’s both vertically and horizontally.

Nearly all video is delivered as yuv420p and lossy compression gets thrown on top. You cannot really compare real world lossy compressed, chroma subsampled video with lossless RGB images. We do have plans to move to a linear color processing pipeline when we also increase the bitdepth > 8-bit, but that is going to be a lot of work that will take most of 2021. GIMP already uses linear color processing when GEGL is being used.

If you want to start looking at Shotcut’s images through a microscope, do not use its player and export as lossless RGB. This thread is now reduced to lack of linear color processing.

1 Like

Here is another fun experiment. Shotcut has a hidden GPU (OpenGL via Movit) processing mode that does linear color processing, and in this mode Shotcut’s player can display the OpenGL texture from the processing as long as there are no CPU-based filters used. Thus the File > Export Frame is not a down-sampled output.
Here is a red capital O from Text: Rich composited over cyan color clip using 2 video tracks (make sure the filter is not selected when using Export Frame):

Now, I change the background color of Text: Rich to the cyan color, and this forces Qt Painter to do the compositing:


Okay, thanks for the explanation. I wasn’t familiar with pix_fmt, etc.

This topic was automatically closed 182 days after the last reply. New replies are no longer allowed.