View Full Version : ConditionalMT - conditional functions for MT
MysteryX
22nd April 2017, 23:57
I needed ConditionalFilter but it didn't work with Avisynth+ MT. No problem. Here's ConditionalMT: a library with a subset of conditional features that is fully compatible with MT mode.
Currently supported: ConditionalFilterMT, and all standard expression functions, but no arguments or parameters.
https://github.com/mysteryx93/ConditionalMT
This code was copy/pasted from Avisynth+ core and then edited, so thanks to whoever wrote it. It requires Visual C++ Runtime 2017.
Cheers!
MysteryX
24th April 2017, 01:29
Arggg... I got a problem. This doesn't work well with 16-bit.
The same image will have AverageLuma at 5.2 in 8-bit, 80.97 in 12-bit and 1147.2 in 16-bit. I'll need to normalize the output values. It seems I simply have to divide the result by 220 internally for 16-bit -- but is that always the case? Perhaps if we're working in YUV, but then in RGB, it depends whether we're in TV or PC range.
8-bit: 5.23
10-bit: 31.47 / 5.23 = 6,02
12-bit: 80.87 / 5.23 = 15,46
14-bit: 289.16 / 5.23 = 55,29
16-bit: 1147.24 / 5.23 = 219,31 (220)
32-bit: ...
I spent half an hour trying to figure out the math to get the right multiplication factors for each bit-depth, and still haven't figured it out. Someone knows the answer?
https://s17.postimg.org/xr9rb9fhr/Math_Challenge.png
raffriff42
24th April 2017, 03:09
In general, scale the 8-bit values by 2^(bits-8) - so 4x for 10-bit, 256x for 16-bit.
With the special cases minimum=0, maximum=(2^bits)-1, so 10-bit max=1023, 16-bit max=65535
The BT.601 reference doc lists some equivalents: 16(8) = 64(10) and 235(8) = 940(10)
I extrapolate that to mean 16(8) = 4096(16) and 235(8) = 60160(16)
In AVS+ , 32-bit float seems to be working in the 0.0~255.0 range...
EDIT wrong; see my next post
So to answer the challenge... I don't know. Are your readings relative to TV-black?
Simple rescaling of your results gives: bits mult avg avg/mult
8bit 1 5.23 5.23
10bit 4 31.47 7.87
12bit 16 80.87 5.05
14bit 64 289.16 4.52
16bit 256 1147.24 4.48
MysteryX
24th April 2017, 03:40
So to answer the challenge... I don't know. Are your readings relative to TV-black?
It is whatever AverageLuma returns -- not sure how it handles TV vs PC ranges internally.
This math challenge is much more complex than it seems.
Might as well let Pinterf fix it and then copy/paste his solution :P
raffriff42
24th April 2017, 12:25
Confirming my earlier guesses, bits mult avg avg/mult
8bit 1 71.321 71.321
10bit 4 285.284 71.321
16bit 256 18258.150 71.321
...except 32bit float is 0.0~1.0: 71.3209 / 255.0 = 0.27969
https://www.dropbox.com/s/hdv1408iy1w2fe0/AverageLuma-test-b08.jpg?raw=1 https://www.dropbox.com/s/b6jikjpkvdq55x4/AverageLuma-test-b10.jpg?raw=1
https://www.dropbox.com/s/efnaq6g32pcfbu3/AverageLuma-test-b16.jpg?raw=1 https://www.dropbox.com/s/mqk88lhgevkgtag/AverageLuma-test-b32.jpg?raw=1
Here is my script:## (AVS+)
AviSource("...")
ConvertToYUV420
BicubicResize(Width/2, Height/2) ## for the forum only
ConvertBits(X) ## change as required
ScriptClip(Last, "Subtitle(String(Last.AverageLuma), align=2)")
return Info.vdubFMEDIT why explicit "Last" in ScriptClip? See here (http://forum.doom9.org/showthread.php?t=168698).
As a bonus, here is my handy filter for viewing anything (that I have tested to date) in VDFM:# http://avisynth.nl/images/Utils-r41.avsi
##################################
### make changes needed to display on vdubFM (VirtualDub FilterMod) (AVS+)
## vdubFM does not currently support all AVS+ color spaces;
## this filter does minimally-destructive translation
##
## per docs, vdubFM accepts:
## 10-bit 422 (v210)
## 16-bit 422, 444, 420 [planar]
## 16-bit RGBA
##
## @ version 1.1 raffriff42 2017-04-29
##
function vdubFM(clip C)
{
return (C.IsY8) ? C
\ : (C.IsYUY2) ? C
\ : (C.IsYV12) ? C
\ : (C.IsYV24) ? C
\ : (C.IsRGB24) ? C
\ : (C.IsRGB32) ? C
\ : (C.IsRGB)
\ ? (C.BitsPerComponent==8)
\ ? C.ConvertToRGB32
\ : C.ConvertBits(16).ConvertToRGB64
\ : (C.BitsPerComponent==8)
\ ? C.RemoveAlphaPlane.ConvertToYV24
\ : C.RemoveAlphaPlane.ConvertBits(16).ConvertToYV16
}
pinterf
24th April 2017, 13:01
Arggg... I got a problem. This doesn't work well with 16-bit.
The same image will have AverageLuma at 5.2 in 8-bit, 80.97 in 12-bit and 1147.2 in 16-bit. I'll need to normalize the output values. It seems I simply have to divide the result by 220 internally for 16-bit -- but is that always the case? Perhaps if we're working in YUV, but then in RGB, it depends whether we're in TV or PC range.
8-bit: 5.23
10-bit: 31.47 / 5.23 = 6,02
12-bit: 80.87 / 5.23 = 15,46
14-bit: 289.16 / 5.23 = 55,29
16-bit: 1147.24 / 5.23 = 219,31 (220)
32-bit: ...
I spent half an hour trying to figure out the math to get the right multiplication factors for each bit-depth, and still haven't figured it out. Someone knows the answer?
I see that you copypasted the old 8 bit conditional_functions code on your github. You are probably doing statistics on individual bytes of the 16 and 32 bit representation of pixels.
MysteryX
24th April 2017, 16:42
I see that you copypasted the old 8 bit conditional_functions code on your github. You are probably doing statistics on individual bytes of the 16 and 32 bit representation of pixels.
It's impossible for an average of individual bytes to give a result higher than 256, so that is not the answer.
pinterf
24th April 2017, 19:48
But if you sum up rowsize x height bytes and divide by width x height everything can happen. I won't spend time on checking why a bad code fails but this can be a reason.
StainlessS
24th April 2017, 23:08
But if you sum up rowsize x height bytes and divide by width x height everything can happen. I won't spend time on checking why a bad code fails but this can be a reason.
Arh, now it becomes clear what the puzzle was, did not even consider someone would try to average non aligned bit strings as numbers.
EDIT: Even that/my description is not good, dont know how to describe it.
MysteryX
24th April 2017, 23:41
The problem isn't with my code.
ColorBarsHD()
ConvertBits(14)
ScriptClip(last, "Subtitle(String(AverageLuma()))")
ConvertBits(8)
This returns 6653
StainlessS
24th April 2017, 23:56
ColorbarsHD(Pixel_type="YV24").killaudio
ScriptClip(last, "Subtitle(String(AverageLuma()))")
Shows 103.955742
6653.0 / (2^(14-8)) = 103.953125
EDIT: I would expect it to return ~ 103.xxx no matter how many bits involved, but I have no idea how AVS+ processes non 8 bit colorspaces.
MysteryX
25th April 2017, 00:05
6653 / (2^(14-8)) = 103.953125
This might be the answer to the question I asked :D You're the first to answer correctly. You just won a trip to Hawaii!
AVS+ doesn't currently normalize values, but it needs to, using the above formula.
StainlessS
25th April 2017, 00:12
AVS+ doesn't currently normalize values, but it needs to, using the above formula.
Absolutely, you cant have a gazillion different code paths dependent upon colorspace bits involved.
EDIT: Although I would have no idea what to do if RAW Float ColorSpace average was more than 1.0, or god forbid, less than 0.0.
(Just limit I guess)
I guess I misunderstood what was going on, I know nothing whatever of AVS+ additional bit-age colorspaces.
You coming with me to Hawaii, heard that its tickets for two :)
EDIT: I did not understand what the puzzle was (did not look at it too hard), but RaffRiff42 already got it correct
in post #3 [mult column = (2 ^ (bits - 8)) ], guess RaffRiff is gonna take you to the big island :(
MysteryX
25th April 2017, 04:06
6653.0 / (2^(14-8)) = 103.953125
Unfortunately this is not the right answer as we're in a 0-220 range, not 0-255.
Since the Hawaii trips have already been purchased, I'm afraid both of you will have to refund it.
289.16 / (2^(14-8)) gives 4.52 instead of 5.23
raffriff42
25th April 2017, 04:19
I believe this code gives perfect conversions between all bit depths.
EDIT updated version (interface changes only) here (http://avisynth.nl/images/Utils-r41.avsi).
#ConvertBits(14)
#ConvertBits(32)
global fs_in=fs(BitsPerComponent)
global fs_out=fs(8)
ScriptClip(Last, """
Subtitle("adjusted AverageLuma = "+scs(fs_in, fs_out, Last.AverageLuma), align=2)
""")
Info
ConvertBits(8)
return Last
#######################################
### return integer fullscale value for given bit depth
function fs(int bits)
{
return (bits==8) ? 255
\ : (bits==10) ? 1023
\ : (bits==12) ? 4095
\ : (bits==14) ? 16383
\ : (bits==16) ? 65535
\ : (bits==32) ? 1
\ : Assert(false,
\ "fs: 'bits' not one of (8|10|12|14|16|32)")
}
#######################################
### return TV-black level for given bit depth
function bs(int bits)
{
return (bits==8) ? 16
\ : (bits==10) ? 64
\ : (bits==12) ? 256
\ : (bits==14) ? 1024
\ : (bits==16) ? 4096
\ : (bits==32) ? 16.0/255.0
\ : Assert(false,
\ "bs: 'bits' not one of (8|10|12|14|16|32)")
}
#######################################
### scale a value from one fullscale value to another;
### handle special case of 32 bit float
### (returns float)
function sc(int fs_in, int fs_out, float f)
{
fin = Float( (fs_in==1) ? 256.0/255.0 : fs_in+1 )
fout = Float( (fs_out==1) ? 256.0/255.0 : fs_out+1 )
return (fs_in==fs_out) ? f : f * fout / fin
}
#######################################
### scale a value from one fullscale value to another, clipping to legal range
### (returns int for int formats, float for float)
function scx(int fs_in, int fs_out, float f)
{
fr = Min(Max(0, sc(fs_in, fs_out, f)), fs_out)
return (fs_out==1) ? fr : Round(fr)
}
#######################################
### scale a value from one fullscale value to another; string result
### (handy for MaskTools work)
function scs(int fs_in, int fs_out, float f, int "decimals")
{
decimals = Min(Max(0, Default(decimals, 4)), 8)
return String(sc(fs_in, fs_out, f), "%0."+String(decimals)+"f")
}
MysteryX
25th April 2017, 04:38
Because luma is in the 36-255 range, we need to divide 16-bit by 220 instead of 256. You still don't seem to be taking that into consideration.
MysteryX
25th April 2017, 05:17
This still isn't it...
31.47 / (2^(10-8) / 256 * 220) gives 9.15 (3.4375x)
80.87 / (2^(12-8) / 256 * 220) gives 5.88 (13.75x)
289.16 / (2^(14-8) / 256 * 220) gives 5.26 (55x)
1147.24 / (2^(16-8) / 256 * 220) gives 5.21 (220x)
raffriff42
25th April 2017, 06:59
Divide by 220? No. Did you try the script I posted?
StainlessS
25th April 2017, 08:45
220,
235-16+1 = 220 = Number of Y levels @ TV Range.
Looks like MX wants to do equivalent to Coring at each conversion (me really hates dat idea).
Presumably there is some kind of PC Range type thing too.
Methinks AverageLuma(), should return 0.0->255.0 (as forever documented), perhaps extended args version, or totally new UnCookedAverageLuma() [or whatever] could return non 8 bit ColorSpace values.
TheFluff
25th April 2017, 16:52
https://github.com/sekrit-twc/zimg/blob/master/src/zimg/depth/quantize.h
raffriff42
25th April 2017, 18:53
https://github.com/sekrit-twc/zimg/blob/master/src/zimg/depth/quantize.hSo zimg says 235 (16+219) @ 10 bits = (4*16 + 4*219) = (64 + 876) = 940.
That is the result (940) I get above (https://forum.doom9.org/showthread.php?p=1804992#post1804992), except I don't return black level offset separately
(information easily gotten with a simple lookup - 4*16 is always 4*16)
vBulletin® v3.8.11, Copyright ©2000-2026, vBulletin Solutions Inc.