Postprocess filter based on
Ross Thomas <ross@grinfinity.com>
Blockbaster code for Avisynth project

Description

Filter designed to reduce or eliminate DCT blocks from an enocode. DCT blocks,
also known as "dark blocks" when they appear in low-luma areas of a frame, are
ugly, distracting artifacts that MPEG encoders like to scatter liberally over 
our otherwise flawless encodes.

While the severity of the problem varies between the different versions of MPEG,
with MPEG-1 exhibiting the most DCT blocks and MPEG-4 the least, they do occur 
with all versions. MPEG-1 produces them almost anywhere there is a flat surface 
with a low detail level (such as a wall), and MPEG-2 shows them in the same
areas but less frequently (they're particularly visible at lower bitrates, as 
anyone familiar with digital satellite can testify). MPEG-4 has signficantly 
less of a problem with low detail levels, but does still produce DCT blocks, 
especially in dark areas.

(Incidentally, DCT stands for "discrete cosine transform", and is one of the 
techniques MPEG uses to do its compression. They differ from macroblocks, which
are most noticible in high-motion areas when the bitrate is insufficient to 
describe the motion accurately, and also from mosquito noise, which is an 
artifact that tends to appear around edges and areas of high contast.)

As hinted at above, the cause of these blocks seems to be a lack of detail in 
areas of the picture, which the encoder fails to "see" and so applies too much
compression. In the process what details were there are smoothed away and the
area turns into a DCT block.

The aim of this filter is to attempt to make those areas more "noticible" to 
the encoder so that it allocates more bits and thus doesn't need to compress
so much. The astute amongst you will realise this filter is, basically, 
designed to increase the bitrate (and decrease the compressibility) of your
clip. While this is considered a cardinal sin by most, there are at least two
valid reasons for doing so.

First, while the highest possible compression ratio is of course desirable,
one has to consider the cost. No-one would accept a movie with a resolution
of 120x90, even though everyone knows it would have an excellent compression
ratio. A similar effect could be achieved by smoothing the clip until it looks
like you smeared your monitor screen with vasoline, but again no-one would
accept this kind of image.

It could be argued that DCT blocks are similarly unacceptable in a good-quality
encode. Peoples' opinion on this differs greatly, but an increasing number,
myself included, are looking for a sure-fire way to get rid of them. This 
filter is my contribution to the effort.

Second, as compression technology evolves and improves it is sometimes
necessary to re-encode old movies into new, more advanced formats. Removing 
artifacts from existing movies is much more difficult than stopping them 
appearing in the first place. Thus removing DCT blocks from your encodes now 
will make it easier to re-compress your movies later.
How it works

The filter splits each frame into a series of blocks (of user-configurable 
dimensions) and checks each block in turn for the amount of detail it contains. 
If the detail level is within the defined range then the block is processed
according to the method parameter (see the Usage section below).

Usage

There are several methods that can potentially reduce or eliminate DCT blocks:
adding noise, sharpening, and blurring. These different approaches are accessed
with the method parameter, combined with a set of parameters shared by all 
methods as well as parameters specific to each one. There is an 
additional method called "show" which highlights each block that will be 
affected by the filter.


The filter can be either "noise", "dither", "sharpen", "blur" or "show".
Parameters specific to each method will be listed in the Methods section below.

Parameters common to all methods are:

Parameter     Description                                               Default

block_size    Determines the size of the blocks into which each         8
              frame is split before processing. The value represents
              both the width and height of the block, and cannot be
              less than 3.                                              
detail_min,   Determines the amount of detail that must be present in   detail_min=1,
detail_max    a block for it to be processed. This value is a           detail_max=10
              percentage, and can be between 1 and 100. It represents
              the percentage of unique brightness levels within the
              block.
              For example, if block_size is set to 8, each block 
              contains 64 pixels. If detail_min is 1 and detail_max
              is 50, a block will only be processed if it contains
              between 1 and 32 unique brightness levels.
              A setting of detail_min=1, detail_max=100 will process
              the entire frame.

luma_offset,   Luma pixels in the range 0-luma_threshold will be        luma_offset=0,
luma_threshold offset by luma_offset within processed blocks.           luma_threshold=25
               For example, if luma_threshold is 30 and luma_offset
               is -2, dark pixels (those with a luma between 0 and 30
               inclusive) will have 2 subtracted from them, making them
               slightly darker still.

strength       Specifies the strength of the sharpening, from 1-100.     25

 
Filters

"noise"

This filter adds normally distributed -- also known as Gaussian -- noise to the
clip. Testing has shown that Gaussian noise is far more suitable for this
filter's purposes than uniformly distributed noise.
With uniformly distributed noise, each possible value is as likely to occur as
any other. That is, if you generate a sequence of numbers in the range 1-100,
at any point in the sequence you are as likely to generate a 5 as a 95.
"Normally distributed" means the chance of each value occurring is not equal.
Let's say you generate normally distributed numbers with a mean of 0 and a
variance of 1 (for an explanation of these terms see the links at the end of
the paragraph). The generator can in theory spit out any number that can fit
into a double-precision floating point, but taken as a whole the numbers will
average out to zero (that's what mean=0, er, means). With these parameters about
68% of the values will be between -1 and 1, about 95% between -2 and 2, and
about 99% between -3 and 3. The probability of generating numbers that are
significantly higher or lower is very small indeed, with the probability 
getting smaller the further away from zero you get. You'd need to make billions
of Gaussian random numbers with mean 0, variance 1 before you saw, for example,
the value 9 being generated.
Gaussian noise very much tends to concentrate around the specified mean, and is
thus more "natural" than uniformly distributed noise. Most things in nature
(including spring precipitation, calorific intake, and, of course, noise)
cluster around a "normal" value, with progressively less frequent occurrances
as you get further from that norm.


"dither"

This filter is very similar to the "noise" filter, with the only difference
being this method will add the same noise to each frame of the clip, whereas
the "noise" method will add different noise to each frame. The effect of this
is hard to describe, but easy to see, so try it for yourself with a high
variance. The closest comparison I can think of is that this filter produces an
effect similar to watching the movie through speckled glass.

The reason of adding this filter is because founded when using method="noise"
that the constantly changing nature of the noise produced motion in otherwise
static areas of the frame, particularly when using a low bit rate. Hope that
using the same noise for each frame will prevent artificial motion in static
areas. This should be considered experimental.


"sharpen"

This filter applies a basic (and fast) sharpening filter to processed blocks.
In this way it "amplifies" detail already present in the block rather than
adding new noise.


"blur"

This filter applies a 3x3 blur to processed blocks. It is currently experimental,
since in theory reducing the frequency of already low-frequency blocks will not
reduce the appearance of DCT blocks. It's worth a try, though :).


"show"

This filter highlights blocks that will be processed using the specified 
block-related common parameters (block_size, detail_min, and detail_max).
It is mainly useful as a visual aid in setting the detail thresholds to 
the desired range.
