Code: Select all
y-strength=6:y-origin-tune=1:y-patch-size=7:y-range=3:y-frame-count=2:y-prefilter=0
Code: Select all
y-strength=y:y-origin-tune=y:y-patch-size=y:y-range=y:y-frame-count=y:y-prefilter=y:
cb-strength=c:cb-origin-tune=c:cb-patch-size=c:cb-range=c:cb-frame-count=c:cb-prefilter=c:
cr-strength=c:cr-origin-tune=c:cr-patch-size=c:cr-range=c:cr-frame-count=c:cr-prefilter=c
NLMeans was committed as revision 6216: https://trac.handbrake.fr/changeset/6216. A number of small updates and fixes were made since, and threading was added in revision 6397: https://trac.handbrake.fr/changeset/6397. Performance is greatly improved.
The original patch was CLI only, enabled with --nlmeans and optionally, --nlmeans-tune. Current HandBrake also provides full GUI support.
--nlmeans is the same as --nlmeans="medium" (with or without --nlmeans-tune="none"), or 6:1:7:3:2:0, as of revision 7402: https://trac.handbrake.fr/changeset/7402. The initial NLMeans implementation and HandBrake release versions 0.10.x previously used 8:1:7:3:2:0, as does this document.
As of release version 0.10.x and development version 7402 (2015-08-17):
Code: Select all
none film animation
ultralight 1.5:1:7:3:2:0 1.5:0.9:7:3:2:0:2.4 2.5:0.15:5:7:2:0:2.00
light 3.0:1:7:3:2:0 3.0:0.8:7:3:2:0:4.0 3.0:0.15:5:7:3:0:2.25
medium 6.0:1:7:3:2:0 6.0:0.8:7:3:2:0:8.0 5.0:0.15:5:7:4:0:4.00
strong 10:1:7:3:2:0 8.0:0.6:7:3:2:0:10 10:0.15:5:7:4:0:8.00
grain
ultralight 0.0:0.9:7:3:2:0:2.4 (same as 0:0:0:0:0:0:2.4:0.9:7:3:2:0)
light 0.0:0.8:7:3:2:0:3.5 (same as 0:0:0:0:0:0:3.5:0.8:7:3:2:0)
medium 0.0:0.8:7:3:2:0:6.0 (same as 0:0:0:0:0:0:6.0:0.8:7:3:2:0)
strong 0.0:0.6:7:3:2:0:8.0 (same as 0:0:0:0:0:0:8.0:0.6:7:3:2:0)
high motion
ultralight 1.5:0.9:7:3:2:0:2.40:0.9:7:5:1:0
light 3.0:0.9:7:3:2:0:3.25:0.8:7:5:1:0
medium 6.0:0.8:7:3:2:0:6.00:0.7:7:5:1:0
strong 8.0:0.6:7:3:2:0:6.75:0.5:7:5:1:0
Summary
NLMeans is a denoise filter that produces higher quality output than HandBrake's old one (hqdn3d).
Unlike hqdn3d, which reduces noise via lowpass filtering (removal of high frequency information), NLMeans achieves its result by averaging multiple patches of similar pixels together; the similarities remain and variance (usually noise) is attenuated. This method does a good job of reducing unwanted noise without clobbering the high frequency range, restoring the appearance of structure and detail found in the original source.
Thanks to Dr. Dirk Farin for his GPL implementation of NLMeans for ffmpeg http://dirk-farin.net/projects/nlmeans/index.html, the basis for this work.
Presets and tunes
The four strength presets are ultralight, light, medium, and strong.
- Ultralight does its best to remove a small amount of noise without substantially affecting the look of the original picture.
- The others are fairly self explanatory.
The five tunes are film, grain, highmotion, animation, and none (or omitted).
- Film is suitable for all normal / live action content and removes slightly more chroma noise than luma noise.
- Grain passes the luma completely untouched and is nearly identical to film concerning chroma, only slightly weaker on account of leaving the luma noise. The appearance of grain is well preserved when used in conjunction with x264's grain tune. For a very slight grain reduction, try film on ultralight.
- Highmotion employs spatial-only filtering for the chroma channels in order to avoid color smearing between frames with very high motion (something which only becomes an issue at very strong settings) and is otherwise identical to film.
- Animation is good for cel animation and tries harder to remove artifacts around edges while preserving their overall fidelity.
- None uses equal strength for luma and chroma, and does not make any special adjustments for different types of content.
For the CLI, presets are specified e.g., --nlmeans="medium" --nlmeans-tune="film". Custom (numeric) settings may be passed to --nlmeans, in which case --nlmeans-tune is ignored. Failure to specify any setting to --nlmeans uses the original filter default, 8:1:7:3:2:0.
Custom parameters
Everything below is concerning custom settings and is only useful for advanced tweaking. Use the preset system, use the preset system, use the preset system, and be happy. Unless of course, you have a really difficult source and know what you're doing.
The default parameters are equivalent to --nlmeans="8:1:7:3:2:0". The six parameters are:
Strength
Origin Weight
Patch Size (context width)
Range (spatial search window width)
Frames (temporal search depth)
Prefilter Mode
Extended syntax for discrete channel parameters is available. Simply append additional parameters to target the additional channels in order Y, Cb, Cr. Parameter values cascade, e.g. to target both chroma channels equally, it is sufficient to specify values for Cb's parameters. To target all channels, specify Y only.
Code: Select all
Extended syntax in detail:
--nlmeans="lumaY_strength : lumaY_origin_tune : lumaY_patch_size : lumaY_range : lumaY_frames : lumaY_prefilter :
chromaB_strength : chromaB_origin_tune : chromaB_patch_size : chromaB_range : chromaB_frames : chromaB_prefilter :
chromaR_strength : chromaR_origin_tune : chromaR_patch_size : chromaR_range : chromaR_frames : chromaR_prefilter"
The following are equivalent:
--nlmeans="8:1:7:3:2:0"
--nlmeans="8:1:7:3:2:0:8:1:7:3:2:0"
--nlmeans="8:1:7:3:2:0:8:1:7:3:2:0:8:1:7:3:2:0"
The following disable processing of the Cr channel:
--nlmeans="8:1:7:3:2:0:8:1:7:3:2:0:0:0:0:0:0:0"
--nlmeans="8:1:7:3:2:0:8:1:7:3:2:0:0"
The following disables processing of the Y channel and
specifies the default settings for both Cb and Cr:
--nlmeans="0:0:0:0:0:0:8:1:7:3:2:0"
Controls how much noise is removed. Higher values produce smoother images. Values between 3 and 10 are usually appropriate. An initial value between 6 and 8 is recommended.
In the original NLMeans algorithm and this implementation, strength (technically, "averaging weight decay") is not constant, meaning that other settings also have considerable influence the amount of noise removed. Be mindful of this, especially when widening your search range; a reduction in overall strength may be needed to compensate.
Origin Weight. 0.00 to 1.00, default: 1.00.
For every search, there is the case where the patch of pixels being compared to is the same as the source. This parameter adjusts the amount of influence that single comparison has on the overall result. Higher values promote the origin patch and lower values reduce its influence.
Most sources benefit from a slight reduction from the default value of 1, which will likely be lower in the future, once I've tested enough material to make an informed decision on what that value should be.
Try values between 0.50 for noisier inputs and 1.00 for cleaner inputs. Lower values for animation can significantly reduce artifacts around edges; try values between 0.15 and 0.50. Most importantly, tune this parameter last. Lower values may result in smoother video, so be sure to revisit the strength parameter.
Patch Size. Odd number, default: 7.
Sets the dimensions of the patches to be compared. Sane values are odd numbers 3 through 9. The default, 7, produces a patch size of 7x7 or 49 pixels. Likewise, 5 produces a patch size of 5x5 or 25 pixels, and 3 produces a patch size of 3x3 or 9 pixels. A value of 1 is usually not very beneficial, and values too large will reduce fine detail.
Search Range. Odd number, default: 3.
Sets the dimensions of the spatial search window. Sane values are odd numbers 3 through 31, typically 3, 5, or 7.
Each patch is compared against many others. This parameter restricts how many others to an area surrounding the original patch, rather than search the entire frame. A range of 3 creates a 3x3 window, yielding 9 patch comparisons. With a 7x7 patch size, that's 441 pixel comparisons.
Use extreme caution with values higher than about 15, as the computation required increases exponentially. A 15x15 search window with 7x7 patch size must compare more than 11,000 pixels per patch. At 31x31, the number skyrockets to over 49,000 and speed is expressed in minutes per frame.
Frames. 1 to 32, default: 2.
How many video frames to compare against, also known as temporal filtering. Sane values for normal content are 1 to 3. Animation may benefit from higher values, not usually more than about 10. Very high values will produce visible ghosting.
Prefilter Mode. Enum, default: 0 (off).
Selects type of prefiltering to use for weight analysis: mean or median, each with two kernel sizes. The prefiltered image is only used for analysis and is not applied to the output (unless passthru is specified).
Prefiltering can dramatically improve the decisions NLMeans makes during weight analysis. By referencing a partially denoised copy of the original image, the algorithm can form a better opinion about what is detail and what is noise. This is especially useful for very noisy sources and usually commands a reduction in overall strength (for luma say, from 6-8 to 3 when using the mean 3x3 filter), since brute force is no longer needed to remove most of the noise. I've observed quality improvements upwards of 20% when used appropriately.
A minor side-effect of prefiltering is that ultra-fine detail may be slightly attenuated. The reduce strength modes (256, 512), which can be combined, may limit this effect. Regardless, prefiltering is not recommended for animation.
The edge boost mode (1024) is useful for bringing back blurred edges in the prefiltered image (still not recommended for animation). Passthru mode (2048) skips NLMeans filtering and outputs the prefiltered image instead.
Prefilter modes are:
(0) Off
(1) Mean 3x3 filter
(2) Mean 5x5 filter
(4) Median 3x3 filter
(8) Median 5x5 filter
(256) Reduce strength by 25%
(512) Reduce strength by 50%
(1024) Edge boost
(2048) Passthru
To use multiple modes together, simply add their values. For example: to prefilter using the mean 3x3 filter at 50% strength and recover some lost edge detail using edge boost, use mode 1537 (1 + 512 + 1024). To see what that prefilter looks like without any additional processing, enable passthru for a final mode of 3585 (1537 + 2048). In conjunction with the default settings, this would look something like --nlmeans="8:1:7:3:2:1537" or --nlmeans="8:1:7:3:2:3585".
The default settings are pretty good for film and similar sources. A good workflow for tweaking is:
1. Start with the defaults or an educated guess.
2. Adjust strength. Moderate reduction in noise is recommended; strong settings out of the gate may impair this workflow.
3. Decrease patch size if fine detail is lost (assuming your initial strength is reasonable). Increase patch size if coarse or splotchy noise is present (values beyond 9 are not typically recommended).
4. Increase search range slightly to potentially increase quality. This is especially useful for sources with repetitive features. Stop when quality diminishes or performance becomes too poor.
5. Decrease strength to compensate for increased search range.
6. For animation or low motion, experiment by adding more temporal frames. Decrease range, strength to compensate.
7. When everything looks pretty great, tune the origin weight and make a final overall strength adjustment (decrease slightly for lower origin weight).
8. If the source is somewhat troublesome and the output still shows some areas where noise isn't removed efficiently, try enabling the prefilter and lowering strength some.
Custom parameters examples
Here are some settings I've had success with and some comparison to hqdn3d. Video only, RF 18.
Code: Select all
Baseball (cartoon), 720x480, heavy grain:
Off: - 5.58 Mbit/s
Medium: hqdn3d 7:7:7:5:5:5 4.07 Mbit/s hqdn3d strong preset is entirely inadequate here
Medium: hqdn3d 25:9:9:5:5:5 1.92 Mbit/s smooth but muddy, edges are smeared/streaked
* Medium: nlmeans 5.25:0.15:5:25:1:0 2.13 Mbit/s maximum useful range, excellent but very slow
* Medium: nlmeans 5.25:0.15:3:17:6:0 2.40 Mbit/s smaller patch size and 6 frames, minor ghosting, good but slow
* Strong: nlmeans 10.0:0.15:5:7:10:0 1.16 Mbit/s zero noise, very fine texture is lost but edges are excellent
Code: Select all
Oven (film), 1920x1040, moderate grain with bad chroma:
Off: - 36.40 Mbit/s
Medium: hqdn3d 4:19:19:4:4:4 24.82 Mbit/s sacrifices detail and still compresses poorly
Medium: nlmeans 8.00:1.00:7:3:2:0 13.75 Mbit/s default looks good
* Medium: nlmeans 4.65:0.85:7:3:3:0 14.39 Mbit/s slightly better fine detail
* Medium: nlmeans 4.65:0.85:7:3:3:1 11.87 Mbit/s prefiltering dramatically improves chroma
Medium: nlmeans 4.65:0.85:7:3:3:2 11.44 Mbit/s only slightly more efficient than prefilter=1
Code: Select all
Remote (film), 1920x1040, moderate grain with bad chroma:
Off: - 24.51 Mbit/s
Medium: hqdn3d 4:19:19:4:4:4 7.26 Mbit/s chroma bleed and artifacts, luma not too bad
Medium: nlmeans 8.00:1.00:7:3:2:0 7.14 Mbit/s default looks good
* Medium: nlmeans 4.65:0.85:7:3:3:0 6.79 Mbit/s looks pretty great
* Medium: nlmeans 3.00:0.85:5:3:3:0:
4.65:0.85:7:3:3:1:
3.25:0.85:7:3:3:0 7.32 Mbit/s discrete channel tuning yields best result
Code: Select all
Whip (film), 1920x804, over-compressed heavy grain, mixed motion:
Off: - 29.10 Mbit/s
Light: hqdn3d 4.5:3:3:2:3:3 18.49 Mbit/s light, many noticeable artifacts
* Light: nlmeans 2.25:0.60:7:3:2:0 18.69 Mbit/s retains a pleasing, even fine grain while removing artifacts
Medium: hqdn3d 11:8:8:4:5:5 10.45 Mbit/s strong, smooth with ugly artifacts
Medium: nlmeans 8.00:1.00:7:3:2:0 10.30 Mbit/s default pretty good, far fewer artifacts
* Medium: nlmeans 6.00:0.60:7:3:2:0 10.83 Mbit/s quite amazing and very fast, still some artifacts
* Medium: nlmeans 3.00:0.60:7:3:2:1 10.65 Mbit/s prefiltering eliminates all artifacts
Code: Select all
Dale (mobile), 1920x1080, blotchy chroma noise:
Off: - 21.31 Mbit/s
Light: hqdn3d 3:2:2:2:3:3 17.43 Mbit/s source lacks high frequencies, lowpass not too bad
* Light: nlmeans 2.75:0.90:5:5:2:0 13.52 Mbit/s better
Code: Select all
Basement (film), 1920x800, clean, very light grain, low motion:
Off: - 14.77 Mbit/s
Light: hqdn3d 2:1:1:2:3:3 10.58 Mbit/s hqdn3d weak preset, slightly smoother than source
Light: nlmeans 1.50:1.00:3:7:2:0 8.39 Mbit/s visually similar to hqdn3d, 43% better compression
* Light: nlmeans 1.15:0.80:3:7:2:0 10.28 Mbit/s nearly identical to source, 30% better compression
Code: Select all
Franklin (dslr), 1920x1080, clean:
Off: - 10.65 Mbit/s
Medium: hqdn3d 3:2:2:2:3:3 5.05 Mbit/s less pleasing but still good
* Medium: nlmeans 8.00:1.00:7:3:2:0 4.64 Mbit/s better at similar bitrate
Code: Select all
Jon (dslr), 1920x1080, sensitivity and compression noise:
Off: - 10.93 Mbit/s
Medium: hqdn3d 3:2:2:2:3:3 5.88 Mbit/s looks good but leaves artifacts around edges
* Medium: hqdn3d 2:1:1:2:3:3
+ nlmeans 1.50:0.80:7:3:1:0 5.65 Mbit/s nlmeans cleans up hqdn3d artifacts
Performance
The default settings yield roughly 3 frames per second for 1920x1080p24 and 15 frames per second for 720x480p24 on a 3.33 GHz Intel Xeon processor. The quick-and-dirty parameter string "12:1:7:3:1:0" yields 5 fps for 1920x1080p24 and 28 fps for 720x480p24.
NLMeans is now threaded thanks to JohnAStebbins. Performance increases of 3-9x over the above figures seem typical.
Conclusion
As you can see, in addition to removing unpleasant artifacts, intelligent removal of noise can have very positive effects on bitrate.
Going forward, hqdn3d is mostly useful for sources where the noise is restricted to high frequency data, such as the output of certain mobile devices and DSLRs. In such cases, a simple lowpass does the job with only a slight loss in overall fidelity. In almost every other common case, hqdn3d will not retain enough detail to be truly pleasing. NLMeans is far superior in this regard and every other, except speed.
Future improvement
While quite advanced, the algorithm has minor quirks that provide some room for improvement.
- Replacing the current strength metric with one that takes patch size, search range, and temporal depth into account would create more consistency between settings and improve usability.
- Optimizing to not recalculate patch difference weight(b,a) where weight(a,b) has already been calculated could provide up to 2x speed improvement.
- Maintaining a covariance matrix would provide a method for disposing of calculations deviating far enough from the mean to lower quality, solving the mild problem of cumulative error associated with the algorithm's weight system. Prefiltering partially solves this problem for noisier sources.
- Replacing the semi-exhaustive search window with a more intelligent, predictive search would potentially increase performance and quality.
Update 2014-05-24: Add more example sources and settings, update list of potential improvements, clarify some sections, fix some typos.
Update 2014-05-26: Add example images plus additional sources and settings, update patch to latest version, fix some typos.
Update 2014-05-27: Add more example images, update patch to latest version.
Update 2014-05-31: Add prefilter examples, update patch to latest version.
Update 2014-06-01: Add example of discrete channel parameters, update patch to latest version, improve example parameters readability, fix some typos.
Update 2014-06-08: Add preset and tune info, update patch to latest version.
Update 2014-06-10: Update patch to latest version (cosmetics only).
Update 2014-06-12: Update patch to latest version (minor bug fixes).
Update 2014-06-14: Update patch to latest version (minor bug fixes).
Update 2014-06-19: Update patch to commit version: https://trac.handbrake.fr/changeset/6216.
Update 2014-09-17: Official name is now NLMeans (nlmeans). Update and clarify some sections and add notes about threading committed as revision 6397: https://trac.handbrake.fr/changeset/6397.
Update 2015-01-24: Replaced remote images with inline attachments, and attached all available examples (including YUV and hqdn3d comparisons) as a tarball.
Update 2015-08-17: Add notes about --nlmeans with no parameters as of revision 7402: https://trac.handbrake.fr/changeset/7402.
Update 2015-08-17: Add current presets and tunes parameters mapping.
Update 2017-06-16: Update to reflect parameter settings mapping for HandBrake 1.0.0 and later.