Anti-Dithering Filter

This is an archive of a topic from NESdev BBS, taken in mid-October 2019 before a server upgrade.
View original topic
Anti-Dithering Filter
by on (#182784)
I'm not 100% sure what SNES emulator is still under development, if any at all, but it'd be really sweet if Higan or SNES9x could have an Anti Dithering filter.

Attached is an example of what this filter would do for games with Dithering in them. Jurassic Park is pictured, as it makes heavy use of dithering in the grass and shadows.

Fusion and NESTopia already have such filters.
In the menu screenshot attached, I show how to activate these filters in NEStopia and Fusion.
In NESTopia's case, I show how to configure the NTSC filter so that it eliminates most composite artifacts and keep the image as sharp as possible.
It seems to me that the Fusion CVBS filter is set up like that to begin with, so didn't need such tweaking. (and doesn't have tweaking options)

I'm not a dev, I don't know any coding languages. It also seems strange to me that Sega and NES emulators have such capabilities while the SNES emulators lack them. : (
These are the best video game consoles ever! One of them shouldn't be lacking such an important feature.
Re: Anti-Dithering Filter
by on (#182785)
I seem to remember one of them has an TV emulation filter (maybe snes9x). That should have a similar effect of blurring out dither.

EDIT, I'm wrong, that filter only seems to darken every other scanline. No blurring effect.
Re: Anti-Dithering Filter
by on (#182786)
As far as I can tell, your proposed anti-dither filter is just a [1 1]/2 convolution applied horizontally over the whole 256x224-pixel picture. I've attached an example of what that filter would do to the title screen of RHDE, an NES game whose title screen uses lots of dithering. It does an OK job with the 50:50 dithered areas, but the text at bottom becomes a blur-fest.
Attachment:
rhde-blur11filter8.png
rhde-blur11filter8.png [ 15.15 KiB | Viewed 4504 times ]

GIMP operations applied to right side:
  1. Transform into power domain (Colors > Levels, gamma=0.50)
  2. Low-pass filter (Filters > Generic > Convolution Matrix, matrix = [0 0 1 1 0]/2)
  3. Transform back into voltage domain (Colors > Levels, gamma=2.00)

A practical anti-dithering filter would need a feature to disable the dithering in areas with strong vertical edges. Do you want me to try to cook one of those up in GIMP so that byuu and other emulator developers have something to work with?
Re: Anti-Dithering Filter
by on (#182787)
I did anyway. It's sort of complicated to describe in GIMP but should be practical to do with SIMD intrinsics or pixel shaders.

Create edge mask using the Sobel gradient detector:
  1. Duplicate into new layer
  2. Colors > Desaturate (Luminosity)
  3. Filters > Generic > Convolution Matrix [[-1 0 1][-2 0 2][-1 0 1]], offset 128
  4. Create new layer filled with #808080
  5. Change layer's blending mode from Normal to Difference
  6. Layer > Merge Down
  7. Filters > Generic > Convolution Matrix [[1 2 1]]/4
  8. Colors > Threshold (50)

Now blur the image:
  1. Duplicate into new layer
  2. Colors > Levels, gamma .5
  3. Filters > Generic > Convolution Matrix [-1 2 6 2 -1]/8
  4. Colors > Levels, gamma 2
  5. Add alpha channel

And merge the images:
  1. Select all white pixels in the mask layer
  2. Switch to the blur layer and delete those pixels

The result keeps large flat areas flat, and it preserves most edges (except the 'm' in my name).
Re: Anti-Dithering Filter
by on (#182790)
Blargg's NTSC filter has several parameters; in particular one for "sharpness". SNES9X has Blargg's filter but unfortunately doesn't appear to expose any parameters for it. This is what it could look like with the sharpness turned down:
Attachment:
jurassic_park_blargg_ntsc.png
jurassic_park_blargg_ntsc.png [ 159.3 KiB | Viewed 4465 times ]


Personally, I'd try to start with Blargg's NTSC filter with the sharpness down, if you can find an emulator that gives you the option. Any horizontal blurring of the image will generally reduce the appearance of dither.

The Fusion emulator for Sega consoles has a "TV mode" but it looks like a very simple horizontal blend rather than an attempt at accurate signal emulation, i.e. making something that looks "good" rather than trying to match the original.

PimpUigi wrote:
I'm not a dev, I don't know any coding languages. It also seems strange to me that Sega and NES emulators have such capabilities while the SNES emulators lack them.

I think in the case of Genesis/MegaDrive the "flagship" game Sonic has very prominent waterfalls in its first and second level that look a lot different with no filtering than they do on the real thing. (Some info here.)

In the case of NES, it might be just because it's the system with the most emulators. You have a lot of options for NES. :P
Re: Anti-Dithering Filter
by on (#182793)
BizHawk seems to support custom filter shaders, though the collection included with the program seems a bit small.

Libretro has a large collection of filters too: https://github.com/libretro/common-shaders

I don't have a Libretro emulator running, but I suspect one of those NTSC "gauss" filters might be close to what you want? (If not, there's a lot of filters in there you could try.)
Re: Anti-Dithering Filter
by on (#182800)
PimpUigi wrote:
It also seems strange to me that Sega and NES emulators have such capabilities while the SNES emulators lack them.

Probably because most SNES games put much less emphasis on dithering than Genesis or NES games due to having more color palette entries.

tepples wrote:
I did anyway. It's sort of complicated to describe in GIMP but should be practical to do with SIMD intrinsics or pixel shaders.

I'm not sure what most of this is, but I find it interesting that in the shot you posted how some of the spots are dithered while others aren't, even if they're the same size. It sounds like to me you're doing blending and various GPU accelerated stuff, but it seems to me the best way to blend dithered areas would be to look for a pattern of alternating pixels, where you'd look at the first pixel, and then the third, and if it's the same, get the color of the second pixel and average it together and make the three pixels that color. From then on check every pixel, checking the color of odd pixels against the first one and the color of even pixels against the second one. If the colors match, replace the pixel with the blended color. If they don't, stop the search and go back to step one. This would work by rows, so checkerboard and vertical line patterns would work, but not horizontal line patterns, but you never see those anyway. I'm sure this would have to be done by the CPU, but with how powerful they are nowadays, I'm sure it wouldn't matter.
Re: Anti-Dithering Filter
by on (#182801)
Here's two simple shaders for BizHawk (put them in BizHawk's "Shaders" folder and select the CGP from Config > Display > Scaling Filter > User).

horizontal_filter is a [ 1 2 1 ] convolution (blend each pixel with half of each neighbouring pixel)

horizontal_filter_hires is a [ 1 1 2 2 1 1 ] convolution (similar but with doubled width)

Jurassic Park has double resolution, so it needs the hires version. The result looks like this:
Attachment:
horizontal_filter_hires.png
horizontal_filter_hires.png [ 43.37 KiB | Viewed 4426 times ]


Again, not "accurate" to the original, IMO, but it seems similar to the "TV" filter in Fusion.
Re: Anti-Dithering Filter
by on (#182832)
rainwarrior wrote:
The Fusion emulator for Sega consoles has a "TV mode" but it looks like a very simple horizontal blend rather than an attempt at accurate signal emulation, i.e. making something that looks "good" rather than trying to match the original.

With Fusion setup the way I showed in the attached configuration screenshot in the first post, and my PC connected my 34 inch CRT HDTV via HDMI, it is virtually indistinguishable from my Sega Genesis connected via composite when switching back and forth to look for differences.

The only difference really, is that colors are *slightly* muted via Composite vs. Fusion over HDMI, but I can actually adjust that via the TV's service menu. (which can adjust the color settings per input)
My CRT HDTV doesn't display scanlines, and I dislike scanlines anyway.
Re: Anti-Dithering Filter
by on (#182836)
These shaders already exist. https://filthypants.blogspot.com/2013/0 ... aders.html

MDAPT tries to detect parts of the image to work on and leave the others alone rather than blurring the whole scene. It's in the libretro shader pack (as is CBOD, which is also covered on the linked page).
Re: Anti-Dithering Filter
by on (#182851)
tepples wrote:
(used sobel gradient to detect edges, then blur anything that isn't an edge)

If you want to target dithering specifically, I'm thinking it would be better to try to detect dither, rather than reject edges.

Dithered pixels should be a neighbourhood of "high low high" or "low high low", as opposed to monotonically increasing (an "edge") or flat.

So maybe:
1. Apply a median filter that is 3 pixels wide.
2. Create the filter mask to operate anywhere the pixel does not match the median.
3. Use a [ 1 2 1 ] convolution filter to blur each "dithered" pixel with its two neighbours.

Result:
Attachment:
rhde_median_dither.png
rhde_median_dither.png [ 11.59 KiB | Viewed 4320 times ]


GIMP doesn't directly have a median filter (it sort of does as "despeckle") but here's a python example. I filtered the RGB channels separately, but you might take a different approach to do a shared median test. Areas containing 3 different colours in a row are a casualty here.


Edit: Python scripts were later disallowed on this forum. Uploading a ZIP with what I think was the original script.
Re: Anti-Dithering Filter
by on (#182852)
PimpUigi wrote:
rainwarrior wrote:
The Fusion emulator for Sega consoles has a "TV mode" but it looks like a very simple horizontal blend rather than an attempt at accurate signal emulation, i.e. making something that looks "good" rather than trying to match the original.

With Fusion setup the way I showed in the attached configuration screenshot in the first post, and my PC connected my 34 inch CRT HDTV via HDMI, it is virtually indistinguishable from my Sega Genesis connected via composite when switching back and forth to look for differences.

What I meant specifically is that it doesn't seem to do any emulation of the colour artifacts which I was used to seeing on my CRT back when I had a Genesis. The easiest example of this is a "rainbow" pattern on Sonic's waterfalls that are missing here. (This article I linked earlier has a really good photograph of this.) I don't know if every TV does the same thing, but mine did.

I don't know precisely what Fusion's filters are doing, as it doesn't appear to be open source, so it's really hard to speculate. As far as I can tell, the "RF" and "CVBS" TV filters appear to blend rows of 3 and 2 pixels respectively, before any upscaling, which I don't think accurately models any particular analog signal process, but it is a horizontal blur that does reduce the appearance of dither (and it's common for some kind of horizontal blur to occur in the real thing).

Anyhow, no emulation is perfect. If you like what you see, then you should use it. I don't really consider NTSC artifacts and scanlines to be the "best" way to experience things; I'm just saying that if hardware accuracy is your goal then the way to get there is probably through NTSC signal emulation. Filters designed to target just dither specifically are an artificial thing that don't really relate to the hardware.
Re: Anti-Dithering Filter
by on (#182858)
In 320px mode, the Genesis VDP's dot clock is ~6.712 MHz, and an alternating dark and light pattern would oscillate at half that (~3.356 MHz). But this is very close to the NTSC chroma subcarrier frequency (~3.580 MHz) and thus well within the conventional 3.0-4.2 MHz chroma band. Thus the TV interprets the signal as rainbows repeating every 30 horizontal pixels.


Exact values: NTSC color burst is 315/88 MHz, and Genesis 320px mode dot clock is 15/8 times color burst
Re: Anti-Dithering Filter
by on (#182859)
rainwarrior wrote:
Areas containing 3 different colours in a row are a casualty here.

Thought of an alternative to the median test. If you consider dither to be an alternation of 2 colours only, then the test for whether to apply dither blend can simply be whether the left neighbour is the same as the right neighbour. (This is more restricted than the median approach, as it avoids all 3 colour cases.)

This approach would fail on Sonic waterfalls, though, since they don't meet that definition of dither. Depends what you're trying to accomplish.

In the attached example, note there's less corruption of the "furniture fight" text overlaid on the red "rhde":
Attachment:
2colour_dither.png
2colour_dither.png [ 10.55 KiB | Viewed 4279 times ]



Edit: Python scripts were later disallowed on this forum. Uploading a ZIP with what I think was the original script.