Copyright © 2020 EoE & Nephren
A VapourSynth plugin for averaging clips together.
Early release, not all features are tested. Please report any issues either here, or in EoE's dms (See bottom)
vs-average is a VapourSynth plugin for averaging multiple clips together. The general idea is to be able to take multiple sources of the same video, and average them together, to negate effects of lossy compression. The plugin can also be effective for temporal blurring.
Sample Type & Bits Per Sample:
- Mean: 8, 10, 12, 16 and 32 bit integer, 16 and 32 bit float.
- Median: All integer formats (8..32), only 32 bit float. (f16 will be added in a later commit)
Color Family: Gray, RGB, YUV or YCoCg.
Sub-Sampling: any.
Note that the input format must be the same for all inputted clips.
Mean will set the output pixel to the average (or mean) of the input pixels from each clip.
average.Mean(clip[] clips[, int output_depth=clips[0].format.bits_per_sample], int preset, float[] multipliers)
-
clips:
List of clips to be processed. Must be the of the same format, length, fps, ect. -
output_depth:
Bitdepth of the output. Will default to the same asclips[0]
.
Only 8, 16 or 32 bit is supported.
Since all calculations are done interally as f64s, it's far more efficient to input your sources as 8 bit, and return as 16 bit with the increased precision. In the case that you want to directly output the clip returned byMean
, I'd suggest you return a 16 bit clip, and dither down usingresize.Point
or similar, even for 16 -> 8 bit, due to an internal rounding error. Significant improvements can be observed over returning a higher bitdepth clip, and dithering down, than a lower bitdepth clip. For this same reason, returning a 10 or 12 bit clip is not supported (And also because I'm lazy). For more information, see the comments inmean.rs
. -
preset:
Integer based preset value for per frame type weightings. See below for how this works. Currently only one preset is implemented. Any other inputs than the ones stated below (or none) will be interpreted asmultipliers=[0, 0, 0]
(no weighting).- Reverse (default) x264/5 based ip/pb qp offset ratios. (
--ipratio 1.4 --pbratio 1.3
). Works for other encoders/ratios as well (though may be less effective)
Equivalent tomultipliers=[1.82, 1.3, 1.0]
- Reverse (default) x264/5 based ip/pb qp offset ratios. (
-
multipliers:
I, P and B frame multipliers, for per frame weighting. Useful for when you wantaverage.Mean
to favour I frames. Can be used to (simply) reverse higher b and p frame quantization. As an example, if you only wanted I and P frames to be selected for averaging, you could usemultipliers=[1, 1, 0]
. Differences with larger amounts of clips when usingpreset=1
are negligable, but do exist, so it might be worth leaving on. It may also be worth increasing the I and P frame multipliers by a small amount frompreset=1
, especially if fast motion interpolation algorithms were used on sources, thereby further decreasing the quality of P and B frames.
Median will set the output pixel to the Median (middle value of the sorted data) of the input pixels from each clip.
average.Median(clip[] clips])
- clips:
List of clips to be processed. Must be the of the same format, length, fps, ect.
Note that since Median
does not define an output_depth
parameter, any input of an even number of clips (where the average of the middle two valeus is taken to be the mean) will likely induce another (though smaller) rounding error. I'll fix this at some point too.
- Take the Mean of 3, 8 bit input clips, and output as 16 bit.
clips = [clip_a, clip_b, clip_c]
mean = core.average.Mean(clips, output_depth=16)
- Take the Median of 3 clips.
clips = [clip_a, clip_b, clip_c]
mean = core.average.Median(clips)
- Simple temporal blur
# add an extra frame to the start of our clip so it's one frame behind
slow_clip = clip[0] + clip
# drop the first frame of our clip so it's one frame ahead
fast_clip = clip[1:]
# average our slow, original, and fast clips together to get a temporal blur.
temporal_blur = core.average.Mean([slow_clip, clip, fast_clip], output_depth=16)
cargo build --release
-
Q: Why did you implement support for 16 bit floats?
A: Mainly because if the end user wanted to work in floats, and had 8 bit sources, f16s are far smaller in memory usage, and are implemented on all not-under-a-rock CPUs since the cavemen were around circa 2009. Further processing can be done in 32 bit. For more information, seemean.rs
or contact me on Discord (See below). -
Q: How fast is
vs-average
?
A: Pretty fast,vs-average
implements multithreading in the default build, allowing for a huge throughput. In fact, the main bottlenecks I've noticed is drive latency (Observed up to ~100MiB/s sustained random reads), and decode speed (decoding 11 AVC bitstreams isn't easy). For fastest speeds with multiple clips, I'd suggest using something akin to dgdecodenv for decoding acceleration via CUDA, and all source files on one (or multiple) SSDs.Note that all my tests have been performed using
lsmas.LWLibavSource
to index and decode souce files, on an R9 3900x with 32GiB of ram. -
Q: Do you plan to write more useless plugins?
A: Yup, rust is pretty cool, vapoursynth-rs is brilliant, and I'm full of dumb ideas :^)
- EoE
- Discord:
End of Eternity#6292
- Discord:
- Nephren
- Discord:
Rin-go#8647
- Discord: