-
Notifications
You must be signed in to change notification settings - Fork 8
CAMBI
akarin.Cambi(clip clip[, int window_size = 63, float topk = 0.6, float tvi_threshold = 0.019, bint scores = False, float scaling = 1.0/window_size])
Computes the CAMBI banding score as CAMBI
frame property. Unlike VapourSynth-VMAF, this filter is online (no need to batch process the whole video) and provides raw cambi scores (when scores == True
).
-
clip
: Clip to calculate CAMBI score. Only Gray/YUV format with integer sample type of 8/10-bit depth (subsampling can be arbitrary as cambi only uses the Y channel.) -
window_size
(min: 15, max: 127, default: 63): Window size to compute CAMBI. (default: 63 corresponds to ~1 degree at 4K resolution and 1.5H) -
topk
(min: 0.0001, max: 1.0, default: 0.6): Ratio of pixels for the spatial pooling computation. -
tvi_threshold
(min: 0.0001, max: 1.0, default: 0.019): Visibilty threshold for luminanceΔL < tvi_threshold*L_mean
for BT.1886. -
scores
(default: False): if True, for scale i (0 <= i < 5), the GRAYS c-score frame will be stored as frame property"CAMBI_SCALE%d" % i
. -
scaling
: scaling factor used to normalize the c-scores for each scale returned whenscores=True
.
src = core.lsmas.LWLibavSource(filename) # 8-bit or 10-bit YUV/Gray video supported
cambi = src.akarin.Cambi(scores=True) # scores=True makes it output per-scale c-score maps in addition to the per-frame CAMBI score
cambi.text.FrameProps("CAMBI").set_output(10)
for i in range(5):
scale = cambi.std.PropToClip('CAMBI_SCALE%d' % i)
scale.set_output(11+i)
Scale i c-score will be a GRAYS clip with width = src8.width / 2i, and similarly for height.
scale-1 is probably best used as a banding artefact mask.
In case you do want to batch process the whole clip and find the top CAMBI score frames, you can use this cambi.vpy
script:
from vapoursynth import core
log_file = 'cambi.log'
cambi = core.lsmas.LWLibavSource(filename).akarin.Cambi() # no need to set scores=True here.
def append_cambi(n, f):
with open(log_file, 'a') as fo:
fo.write('%d %.4f\n' % (n, f.props['CAMBI']))
return cambi
core.std.FrameEval(cambi, append_cambi, cambi).set_output()
And then run the script with vspipe -p cambi.vpy -a filename=INPUT.m2ts .
.
Then you can sort the output file cambi.log
based on the 2nd column (i.e. sort -nr -k2,2 cambi.log
if you are using Unix sort.) The first column will be the corresponding frame number.
The cambi algorithm is very sensitive to dithering in the input, and it has a very rudimentary 2x2 lowpass dedither filter built-in if the input is 8-bit (it won't apply dedither to 10-bit inputs). However, if the output c-score map looks very much like a dither pattern, you should perform dedither first and apply Cambi to the 10-bit dedithered clip instead.