View Full Version : AviSynth+ thread Vol.2
DTL
12th September 2021, 20:51
it's simply gamma aware resampling, many alternatives.
also resampling under linear light introduces way more ringing and I don't actually consider it "HQ"
The amount of ringing depends both on source and used at resampling process 'conditioning' filter. One of the reason to have content for final distribution be 'conditioned' against ringing in linear domain - the use of simple and non consumer-adjustable filter at displaying (ideal LPF - sinc).
Also at the new dark age of very different HDR-TFs it allow to prepare content once and use any HDR (SDR) TF for compression and expanding of bitdepth without preparation special version 'conditioned' for each TF. Also may be made formats convertors more simple and cheap without putting more evil in the spectrum. Like Any_input_TF->Linear->Any_output_TF without re-conditioning.
It is good to consider moving pictures data in TF-domain (like old gamma of newer more advanced HDR TFs) as compressed (it is really sort of bitdepth compression not very great for SDR but about 3:1 for HDR) and not attempt to make processing in this compressed form. As well as typically user can not perform MPEG-domain compressed data resize because it will damage data and make non-decodable. Same is with TF-compressed data - any resize will make data damaged and lower the quality of decoded form.
It was reply to old enough post but I hope in the progress of Avisynth development (and in the dark age of different HDR TFs + SDR) the more attention will be put to the moving pictures data processing and the possible spectrum-changing operations will be performed in linear domain.
qyot27
13th September 2021, 01:13
I think I found another discrepancy. Using the color presets from here (http://avisynth.nl/index.php/Color_presets) I cannot get the same results in Blankclip; it returns a different color.
Blankclip(width=132, height=152, color=$9400D3, pixel_type="rgb24") # color_darkviolet
I know it worked in the past but have not needed a colored blankclip in a while.
I'm pretty sure I know what happened, since 3.7.0 is fine, and so is both pixel_type="rgbp" by itself as well as followed by ConvertToRGB24(), or using pixel_type="rgb32" and then RemoveAlphaPlane().
In the meantime, you can work around it by shifting the last value inward: $94D300
qyot27
13th September 2021, 07:44
Okay, it *should* be fixed on git now.
Reel.Deel
13th September 2021, 07:51
Thanks qyot27. I'll wait for the next test release and report back if it's still troublesome.
pinterf
13th September 2021, 08:41
Just tested the new build and the shift is still there. It is not as drastic as before but with opacity < 1 it shifts the overlay image by 6 pixels to the left. Now the shift is consistent, before it would change depending on the opacity value.
Are you sure, there is a shift? It seemed to be a mod8 issue: the rightmost pixels in the line (1-7 pixels, depending on the width) were not processed; 10-16 bits and 32 bit formats are affected.
Reel.Deel
13th September 2021, 09:17
Are you sure, there is a shift? It seemed to be a mod8 issue: the rightmost pixels in the line (1-7 pixels, depending on the width) were not processed; 10-16 bits and 32 bit formats are affected.
Yes, just double checked.
https://i.ibb.co/61MQbNT/overlaybug.png (https://imgbb.com/)
The shift here is 6 pixels. Image is an animated png, hope you can see it correctly.
pinterf
13th September 2021, 09:26
Yes, just double checked.
https://i.ibb.co/61MQbNT/overlaybug.png (https://imgbb.com/)
The shift here is 6 pixels. Image is an animated png, hope you can see it correctly.
Width is 270 but only 264 pixels were processed (264 modulo 8 = 0). The rightmost 6 pixels were omitted.
Reel.Deel
13th September 2021, 09:29
Width is 270 but only 264 pixels were processed (264 modulo 8 = 0). The rightmost 6 pixels were omitted.
Ahh I see what you're saying now. Did not look close enough, sorry. No more shift, just pixels being omitted. That's not intended behavior, is it?
Edit:
Fixed on git. I'm gonna build another test later on today.
Thanks pinterf. I'll test again whenever it gets released. Just FYI, I've not been stockpiling these bugs and just waiting for you to return :D. I discovered them recently when I was testing my OverlayPlus script.
pinterf
13th September 2021, 09:32
Ahh I see what you're saying now. Did not look close enough, sorry. No more shift, just pixels being omitted. That's not intended behavior, is it?
Fixed on git. I'm gonna build another test later on today.
Dogway
13th September 2021, 09:50
Can chroma motion search be improved by feeding normalized chroma planes or is mvtools already doing it internally?
Also is the string line carriage working correctly on Linux or other systems (to Windows)? I suspect this (https://forum.doom9.org/showthread.php?p=1952076#post1952076) might be a bug related to it.
pinterf
13th September 2021, 10:04
Can chroma motion search be improved by feeding normalized chroma planes or is mvtools already doing it internally?
Planes are processed as they are received, no normalization occurs. From the docs: adjust the luma:chroma ratio
scaleCSAD
Fine tune chroma part weight in SAD calculation (since 2.7.18.22)
Possible values for luma:chroma SAD ratio
-2: 4:0.5
-1: 4:1
0: 4:2 (default, same as the native ratio for YV12)
1: 4:4
2: 4:8
Also is the string line carriage working correctly on Linux or other systems (to Windows)? I suspect this (https://forum.doom9.org/showthread.php?p=1952076#post1952076) might be a bug related to it.
Expr treats space, CR, LF and TAB as allowed separators within an expression string. (in 3.7.0 only space was allowed).
I need more info to reproduce it.
Dogway
13th September 2021, 10:17
Ah thank you. Guess I can do something like this to chroma:
ExtractU().expr(" x range_half - range_max cmax cmin - / * abs 6 *")
Will check if it improves matters.
I will investigate for the other issue.
Dogway
13th September 2021, 11:02
Why is not possible to Eval arrays? is there a way to do this?
function ArrayAdd( int_array a, int_array b) {
as = ArraySize(a)-1
bs = ArraySize(b)-1
na = ""
for (i = 0, as, 1) {
cm = i != as ? "," : ""
na = na + String(Eval(Format("a[{i}]"))) + cm
}
Eval("["+na+"]") }
Also I'm required to set argument to 'int_array' since val_array will not parse ints (didn't test other types)
pinterf
13th September 2021, 11:06
Missing "return"?
real.finder
13th September 2021, 11:25
Dogway, keep in mind that script array only "'*': zero or more" while plugins can be "'+': one or more" and "'*': zero or more" start read from https://github.com/AviSynth/AviSynthPlus/issues/226#issuecomment-910076325 and I think you made this for bm3d, and bm3d is + array one
there are suggestion to add + array to script function https://github.com/AviSynth/AviSynthPlus/issues/226#issuecomment-910186715 but I think pinterf still wait for better name https://github.com/AviSynth/AviSynthPlus/issues/226#issuecomment-910230404
Dogway
13th September 2021, 11:34
Nevermind, just made it:
function ArrayAdd( int_array a, int_array b) {
as = ArraySize(a)-1
bs = ArraySize(b)-1
na = ""
for (i = 0, as+bs+1, 1) {
o = i - as - 1
cm = i != as+bs+1 ? "," : ""
na = na + ( i > as ? String(Eval(Format("b[{o}]"))) : \
String(Eval(Format("a[{i}]")))) + cm
}
Eval("["+na+"]") }
Still doesn't work with val_array though
EDIT: apparently the example here (https://github.com/AviSynth/AviSynthPlus/blob/47b6141ac27fc5c33cb4186695cca88b6961b3c8/distrib/Readme/readme.txt#L338) was working at some point, but now it doesn't.
Function Summa(array "x", array "y", int "N")
{
sum = 0.0
FOR(i=0,N-1) {
sum = sum + x[i] * y[i]
}
return sum
}
pinterf
13th September 2021, 12:15
This syntax is working for me
Function Summa(float_array "x", float_array "y", int "N")
{
sum = 0.0
FOR(i=0,N-1) {
sum = sum + x[i] * y[i]
}
return sum
}
Function Summa2(val_array "x", val_array "y", int "N")
{
sum = 0.0
FOR(i=0,N-1) {
sum = sum + x[i] * y[i]
}
return sum
}
ColorBarsHD()
subTitle(String(Summa([1,2],[3,5],2)) + " " + String(Summa2(x=[1,2],y=[3,5],n=2)))
pinterf
13th September 2021, 12:30
And this syntax is valid a well:
(untyped arrays can appear only as named parameters in this example)
function ArrayAdd( int_array a, int_array b) {
as = ArraySize(a)-1
bs = ArraySize(b)-1
na = ""
for (i = 0, as+bs+1, 1) {
o = i - as - 1
cm = i != as+bs+1 ? "," : ""
na = na + ( i > as ? String(Eval(Format("b[{o}]"))) : \
String(Eval(Format("a[{i}]")))) + cm
}
return Eval("["+na+"]")
}
function ArrayAddNamed( val_array "a", val_array "b") {
as = ArraySize(a)-1
bs = ArraySize(b)-1
na = ""
for (i = 0, as+bs+1, 1) {
o = i - as - 1
cm = i != as+bs+1 ? "," : ""
na = na + ( i > as ? String(Eval(Format("b[{o}]"))) : \
String(Eval(Format("a[{i}]")))) + cm
}
return Eval("["+na+"]")
}
ColorBarsHD()
a1 = ArrayAdd([1,2],[4,5,6])
a2 = ArrayAddNamed(a=[11,12],b=[14,15,16])
s = "Unnamed, typed arrays:"
for(i=0,ArraySize(a1)-1) {
s = s + " " + String(a1[i])
}
s = s + " Named params, val_array: "
for(i=0,ArraySize(a2)-1) {
s = s + " " + String(a2[i])
}
SubTitle(s)
Dogway
13th September 2021, 12:30
oh, you have to declare the argument, ok, strange but that did the trick thank you.
pinterf
14th September 2021, 15:58
Avisynth+ 3.7.1 test build 14 (20210914) (https://drive.google.com/uc?export=download&id=1f1tfB40Ny0rZcmBApSiulFl6ndfpta4z)
Since last test build:
20210914 WIP
------------
- New: script functions now supports avisynth function array signature '+' (one or more) with _nz type suffix.
Previously only '*' style (zero or more) was supported by the original naming.
E.g.: val_array -> .* val_array_nz -> .+, int_array -> i* int_array_nz -> i+
Others: bool_array_nz, float_array_nz, string_array_nz, clip_array_nz, func_array_nz.
- Fix: Overlay "blend" 10+ bit clips and "opacity"<1 would leave rightmost non-mod8 (10-16 bit format) or non-mod4 (32 bit format) pixels unprocessed.
- Fix BlankClip rgb24 color part swap (regression in 3.7.1 test builds)
DTL
14th September 2021, 16:45
Based on note in https://tech.ebu.ch/docs/techreview/trev_304-rec601_bbc.pdf
More satisfactory was the consideration of chrominance filtering which recognized the need for
sharp-cut filters at all conversions except the last one. This allowed the bandwidth needed for
chroma-key and other processing to be retained through the system; however, the inclusion of a
slow roll-off in the composite coder for analogue broadcasts or in the picture monitor for direct
component signals avoided the dreadful chrominance ringing that would otherwise occur.
It looks current ConvertToRGB() and all other chroma-upsampling Convert() like from 4:2:0 and 4:2:2 to 4:4:4 need to be supplemented with additional option like 'in-between' conversion or 'last/display' conversion. Or may be at least Convert() filter documentation need to be supplemented with this feature of digital sampled moving pictures systems design (from rec.601 and may be up to latest HDR).
I sometime use ConvertToRGB24() before checking output result in VirtualDub and it creates some distorted output because for 'last' conversion the UV planes need to be filtered with some low-pass slow-roll-off filter to fix posible colour-difference source of ringing.
Or special function need to be used for 'monitor conversion to RGB' like (pseudo-functions)
u_plane=ExtractU()
v_plane=ExtractV()
u_plane=Blur(u_plane,some_param) or GeneralConvolution(u_plane,some_param) or special ColourDifferenceLastMonitorProc(u_plane)
v_plane=Blur(v_plane,some_param) or GeneralConvolution(v_plane,some_param) or special ColourDifferenceLastMonitorProc(v_plane)
yuv_back=CombinePlanes(last,u_plane,v_plane)
ConvertToRGB(yuv_back)
LigH
15th September 2021, 10:28
Do you mean something like the "coring" parameter of some AviSynth functions (disabling the clamping to TV scale in YUV modes)?
DTL
15th September 2021, 12:37
Do you mean something like the "coring" parameter of some AviSynth functions (disabling the clamping to TV scale in YUV modes)?
I made example of working conversion functions to show the difference in the post https://forum.doom9.org/showthread.php?p=1952273#post1952273 .
Also the post https://forum.doom9.org/showthread.php?p=1952213#post1952213 have link to updated hand-drawing schematic of different sub-sampled to 4:4:4 decoding - for final/control displaying and for intermediate processing.
Because the exact 'anti-ringing' filter in display/final transform looks like not standard-defined it also possible to have 'colour-sharpness' adjustment at 422(420)ToRGB transform to make adjustments between 'film-looking' with smooth transients and 'video-look' with peaked/overshooted.
In that example I use UserDefined2ResizeMT() with src_left !=0 to enable filter-processing (convolution with kernel) without actual resizing of UV channels.
DTL
17th September 2021, 10:22
Oh - again some (minor) complain for Avisynth resampler:
LoadPlugin("fmtcavs.dll")
ColorBarsHD(9600,1000, pixel_type="YV24")
ConvertBits(16) # YUV 444 16
Crop(0,0,9600,500)
AddBorders(300,300,300,300)
GaussResize(width/10,height/10, p=10)
SincResize(last.width*4, last.height*4, taps=16)
#fmtc_resample(w=last.width*4, h=last.height*4, kernel="sinc", taps=16)
ConvertBits(8)
Levels(0,1,20,0,255).Crop(1000,0,width-1000, height).ConvertToRGB24(matrix="PC.709")
It produces additional (and colored) ringing-like lines (though it constant not-faded amplitude and different frequency) from the very edges of the frame.
Image: https://i3.imageban.ru/out/2021/09/17/0097b84914ff6256cd2288d58ca4e007.png
When trying to process in 'linear light' and convert to and from modern highly-non-linear TFs like HDR the bug significally increases in amplitude.
The kernel's response between SincResize and fmtc(sinc) checked and looks like equal. So I assume it is another issue with edge-workarounds in the avisynth's resampler.
The fmtc(sinc) frame edges is clear (there is some minor ringing from the useful data transitions but it correct).
SincLin2ResizeMT in jpsdr's plugin also affected - same resampler core.
LanczosResize(taps=16) output clear.
pinterf
17th September 2021, 14:45
It produces additional (and colored) ringing-like lines (though it constant not-faded amplitude and different frequency) from the very edges of the frame.
Image: https://i3.imageban.ru/out/2021/09/17/0097b84914ff6256cd2288d58ca4e007.png
The kernel's response between SincResize and fmtc(sinc) checked and looks like equal. So I assume it is another issue with edge-workarounds in the avisynth's resampler.
Those lines are independent from the bit depth. Unfortunately I don't really even know what to look for.
DTL
17th September 2021, 15:29
The top and bottom buggy lines exist only if top and bottom 'borders' (in the AddBorders()) < 320 (320 few lines, 300 and less full number). If it is 'edge computational bug of pure sinc' it should disappear with moving to SincLin2 weighting of the edge of sinc kernel - but it only shifts buggy lines a bit. Also it absent with fmtc resampler without sinc kernel modification.
With 'borders' 300 it starts (around colour patches) from taps=11, no with taps=12, taps=13 yes, 15 yes - more height, taps=18 - yes, moves to the edges of frame.
With SincResizeMT with possibly extended taps value (to 100..150) it looks dissappear after taps >35..40 (when the edges of kernel fades below some max abs value). Also Lanczos weighting have much more suppression of the wider parts of sinc kernel edges so it do not appear.
So it looks interconnected with 'edges of sinc features' but in fmtc it possibly have workaround (for edges of frame processing) for any taps value and without kernel additional weighting. Though fmtc(sinc) do have 'standard sinc edge issue' in any position inside frame - as shown in https://forum.doom9.org/showthread.php?p=1950633#post1950633 .
It looks the buggy lines depends on distance between useful data and buffer border. If useful data is closer about taps*2 from buffer edge - there is a chance of bug (may be also in some range of taps param like 11..30). So as temporal workaround it may be recommended to pad useful buffer with borders >2*taps size. And crop after processing.
Addition: I test at different CPU and Win10 and the script above (borders '300' and taps 16) produces much smaller number of bright buggy lines.
Image: https://i4.imageban.ru/out/2021/09/18/07c0cf04d5f8fa3ed7f4026c2093b402.png
It looks depends on memory or CPU SIMD. Though at my old home CPU (about Core-2 6400) I tried SetMaxCPU('none') and it changes nothing.
I make temporal workaround function for auto-padding and cropping:
Function SafeSincResize(clip c, int width, int height, int taps)
{
xratio = width/c.width
yratio = height/c.height
tt=2*taps
c=AddBorders(c,tt,tt,tt,tt)
c=SincResize(c, c.width*xratio, c.height*yratio, taps=taps)
return Crop(c,tt*xratio,tt*yratio,width,height)
}
Same should work with SincLin2ResizeMT(). Though the source must have some black borders already to not introduce additional stepping with AddBorders(color=black).
qyot27
23rd September 2021, 21:48
Okay, so I'm going to need those of you that are really invested in the particulars of the color representation in AviSynth+ to test this for me, as I don't have nearly the amount of samples needed for this:
FFmpeg (https://www.mediafire.com/file/ig4oqq4i9lfs8cu/ffmpeg_r103791%252B10.7z/file)
mpv (https://www.mediafire.com/file/hp1n6zhvqevieop/mpv_r49201.7z/file)
This build of FFmpeg has a patch (https://github.com/qyot27/FFmpeg/commit/2771580eae058a642384ef02187620afb7787663) that reads some of the frame properties from AviSynth+ and populates them in what I hope is the correct fashion. The mpv build is provided because it's more comfortable than ffplay, and because unlike ffplay, it doesn't require additional filtering steps to work on the additional information (read: mpv knows the script is outputting HDR and can tonemap it automatically for SDR displays if that's how you have it set up).
Will require one of the test builds pinterf provided from after April, since there had been a bug in 3.7.0 (and probably the earlier versions that were also inside interface version 8) preventing the C interface from accessing frame properties; if you use 3.7.0, it will crash*. You'll also need a source filter that sets frame properties (I used the test build of ffms3000); propSetInt does work to force the properties to a given value, but that's artificial and I want more real-world examples just in case there's a problem with how the equivalencies between the frame props and FFmpeg's color enums were set up.
*this will be resolved in the final version of the patch, since it's going to require bumping to interface version 9 just to make the detection in FFmpeg work correctly (but bumping to version 9 should probably go hand in hand with more new API functions and a way of future-proofing against bugs like this).
What frame properties is it reading?
_FieldBased (the one that doesn't have to do with color; people interested in interlaced video, take note of this one)
_ChromaLocation
_Primaries
_Transfer
_Matrix
_ColorRange
I used the LG New York HDR UHD 4K Demo (https://4kmedia.org/lg-new-york-hdr-uhd-4k-demo/) for verifying that mpv with the patch can pick up and use the information instead of seeing the script as BT.709. But there's obviously a lot more entries under all those different frame properties, and I have no clue if the way I set this up actually can handle all of them the way they're ostensibly supposed to (admittedly, some of that is also up to the source filters setting the correct value and the other filters in the script not screwing it up somehow, but making sure the script->libavformat chain works as intended is the goal here). I also didn't have any interlaced content on hand to really test the field detection on.
pinterf
24th September 2021, 11:59
The top and bottom buggy lines exist only if top and bottom 'borders' (in the AddBorders()) < 320 (320 few lines, 300 and less full number). If it is 'edge computational bug of pure sinc' it should disappear with moving to SincLin2 weighting of the edge of sinc kernel - but it only shifts buggy lines a bit. Also it absent with fmtc resampler without sinc kernel modification.
With 'borders' 300 it starts (around colour patches) from taps=11, no with taps=12, taps=13 yes, 15 yes - more height, taps=18 - yes, moves to the edges of frame.
...
In last days I spent quite a few hours on the topic and feeling now what the problem is. The relevant part is basically untouched since 2002. It is a new part for me so I need more knowledge gathering on my side.
btw this is what they implemented: http://avisynth.nl/index.php/Resampling
pinterf
24th September 2021, 12:26
Meanwhile.
Avisynth+ 3.7.1 test build 17 (20210924) (https://drive.google.com/uc?export=download&id=1XUtEI5qL0NPy85v3gDYHHh75w828G7dq)
20210924 WIP
------------
- Expr: allow x.framePropName syntax (Akarin's idea)
Where x is the usual clip identifier letter, and after the . is the name of the frame property.
Nonexistent or non-number frame properties return with 0.0 value
Example (increasing brightness until frame nunmber 255)
ColorbarsHD()
ScriptClip("""propset("medi", current_frame)""")
expr("x.medi","","")
- More checks on array parameters in user defined functions.
Array-typed parameters with "name" have the value "Undefined" when they are not passed.
Note: but the value is defined and is a zero-sized array if the parameter is unnamed, like in other Avisynth functions.
Special thanks to real.finder for not allowing me to be too lazy :)
DTL
24th September 2021, 13:34
btw this is what they implemented: http://avisynth.nl/index.php/Resampling
It is described 'common theory' of resampling. Also it is even not very good calls different kernels only as 'different resamplers' - Avisynth have only one resampler engine and it accepts different kernels (named *Resize()) at creation of 'resampling program' for the resampling engine.
Also it have a direct 'bugs' like
"The resampling kernel, sinc(x), is symmetric. That is, sinc(x) = sinc(-x). This means that the samples s(n*T) and s(-n*T) will contribute equally to s(0)."
The main and very important property of sinc(x) that it =1 at sinc(0) and =0 at the all other integer n*pi. That practically means that _samples_ of the data are _independent_ . So no sample of 1D sinc processing do not contribute anything to s(0) (and also to any other sample). But _all_ samples (in theory) contribute to any interpolated (new calculated) samples in-between original input samples. Because in-between sinc(x) !=0.
And all this nice properties of sinc works only for 1D tansform and not work as nice for attempt of 2D processing with rectangular sampling grid because sinc (distance_to_diagonal(angled)_samples*pi) !=0 (and the jinc() is too).
Also it have almost nothing about Gibbs phenomenon and working against ringing. Only mention about sometime ringing occur.
Also that 'common theory' applied to infinite size of buffer (theoretical) and may be not lists the issues with real buffers of non-infinite size at all. Processing these real buffers require special workarounds for resample engines to create less distorted results (at the edges and at some distance from the edge (typical ~=size of kernel, filter support, etc). Part of these workarounds looks like implemented in the 'create resampling program' and part may be in the resampler engine.
"untouched since 2002. "
Now with large dynamic range of HDR and much more curved HDR transfer functions even small bugs at the LSBs of 16bit become highly visible if trying to process HDR in linear and convert back to HDR transfer. With old 8bit and SDR transfers most of small amplitude bugs was about invisible.
FranceBB
24th September 2021, 16:01
mpv (https://www.mediafire.com/file/hp1n6zhvqevieop/mpv_r49201.7z/file)
Remember the DNX120 green field issue (https://forum.doom9.org/showthread.php?t=182885)?
Well, I'm glad you compiled a new build of MPV 'cause with your build I could check again and it is actually fixed: https://i.imgur.com/0PGbiB0.png
Cheers ;)
What frame properties is it reading?
_FieldBased (the one that doesn't have to do with color; people interested in interlaced video, take note of this one)
_ChromaLocation
_Primaries
_Transfer
_Matrix
_ColorRange
This is a game changer!! Thank you so much for improving metadata passthrough from Avisynth! I really really really appreciate it!
Testing now but if it works it's gonna make my life so much easier, thank you!! :D
Dogway
24th September 2021, 16:02
pinterf, is it possible to add atan2 to expr. Currently I'm using the convoluted method of ternaries which is very slow, this will come useful for cylindrical color spaces:
atan2
"x 0 > y x / atan A@ x 0 < y 0 >= & A pi + x 0 < y 0 < & A pi - x 0 == y 0 > pi 0.5 * y 0 < pi -0.5 * 0 0 ? ? ? ? ? ?"
Reel.Deel
24th September 2021, 19:25
pinterf, is it possible to add atan2 to expr.
+1 on that request. I'm currently using Gavino's method:
function atan2(string y, string x) {
# Returns an expression for atan2(y, x) (in range 0-360), corresponding to
# (x == 0 ? (y > 0 ? 90 : (y < 0 ? 270 : 0)) : atan(y/x)*180/pi + (x < 0 ? 180 : (y < 0 ? 360 : 0)))
# Form of expression chosen to evaluate atan() once only.
return "("+x+" == 0 ? ("+y+" > 0 ? 90 : ("+y+" < 0 ? 270 : 0)) : " +
\ "atan(("+y+")/("+x+"))*180/pi + " +
\ "("+x+" < 0 ? 180 : ("+y+" < 0 ? 360 : 0)))"
}
pinterf
25th September 2021, 09:00
pinterf, is it possible to add atan2 to expr. Currently I'm using the convoluted method of ternaries which is very slow, this will come useful for cylindrical color spaces:
atan2
"x 0 > y x / atan A@ x 0 < y 0 >= & A pi + x 0 < y 0 < & A pi - x 0 == y 0 > pi 0.5 * y 0 < pi -0.5 * 0 0 ? ? ? ? ? ?"
Probably I could make it work but note that 'atan' will keep being slow because expressions containing trigonometric functions have zero SIMD acceleration, they are executed as plain C interpreted code. Akarin implemented sin and cos acceleration lately for VapourSynth which I have not yet imported into Avisynth.
tormento
25th September 2021, 11:20
Probably I could make it work but note that 'atan' will keep being slow because expressions containing trigonometric functions have zero SIMD acceleration, they are executed as plain C interpreted code. Akarin implemented sin and cos acceleration lately for VapourSynth which I have not yet imported into Avisynth.
Can't you use Taylor series? Usually with 5/6 terms you have very good approximation.
pinterf
25th September 2021, 12:02
Yes of course this is the way how other functions are implemented. And one should specify the allowed input range and the max error on valid inputs. As it was documented on sin and cos implementations.
wonkey_monkey
25th September 2021, 12:14
pinterf, is it possible to add atan2 to expr. Currently I'm using the convoluted method of ternaries which is very slow, this will come useful for cylindrical color spaces:
atan2
"x 0 > y x / atan A@ x 0 < y 0 >= & A pi + x 0 < y 0 < & A pi - x 0 == y 0 > pi 0.5 * y 0 < pi -0.5 * 0 0 ? ? ? ? ? ?"
Is that a work in progress? It seems to have a few bugs and oddities.
tormento
25th September 2021, 12:23
As it was documented on sin and cos implementations.
And being tan the ratio of them…
Dogway
25th September 2021, 13:09
@wonkey_monkey: It's supposed to be final (for 32-bit). I took the atan2() from Wikipedia example.
# Opposing RGB. Like HSV but with opposing warm and cool axis: Luma-RED/GREEN-YELLOW/BLUE
# https://graphics.stanford.edu/~boulos/papers/orgb_sig.pdf
function RGB_to_oRGB (clip RGB, bool fulls) {
bi = BitsPerComponent(RGB)
fs = Default (fulls, false)
# R'G'B' to L'C'C' to
LCC = [ 0.298967, 0.586421, 0.114612, \
0.500000, 0.500000, -1.000000, \
0.866000, -0.866000, 0.000000]
LCC = MatrixClip(RGB,MatrixTranspose(LCC),"YUV")
R = ExtractR(RGB)
L = ExtractY(LCC)
C1 = ExtractU(LCC)
C2 = ExtractV(LCC)
G = Expr(C2, C1, R, ex_dlut(Format("x 0 > y x / atan A@ x 0 < y 0 >= & A pi + x 0 < y 0 < & A pi - x 0 == y 0 > pi 0.5 * y 0 < pi -0.5 * 0 0 ? ? ? ? ? ?
O@ pi 0.333333 * < O 1.5 * O pi 0.333333 * >= pi O >= & pi 0.5 * O 0.75 * + 0.785398163 - 0 ? ? O - z * y * "), bi, fs), optSingleMode=false)
B = Expr(C1, C2, R, ex_dlut(Format("x 0 > y x / atan A@ x 0 < y 0 >= & A pi + x 0 < y 0 < & A pi - x 0 == y 0 > pi 0.5 * y 0 < pi -0.5 * 0 0 ? ? ? ? ? ?
O@ pi 0.333333 * < O 1.5 * O pi 0.333333 * >= pi O >= & pi 0.5 * O 0.75 * + 0.785398163 - 0 ? ? O - z * x * "), bi, fs), optSingleMode=false)
CombinePlanes(L, G, B, planes="YUV") }
function oRGB_to_RGB (clip oRGB, bool fulls) {
bi = BitsPerComponent(oRGB)
fs = Default (fulls, false)
R = ExtractY(oRGB)
G = ExtractU(oRGB)
B = ExtractV(oRGB)
# L'C'C' to R'G'B'
RGB = [ 1.0, 0.11461199820041656, 0.7433336973190308, \
1.0, 0.11461199820041656, -0.4114006757736206, \
1.0, -0.8853879570960999, 0.16596652567386627]
# Evaluating for atan2(C2,C1) since Expr lacks the operator
G = Expr(B, G, R, ex_dlut(Format("x 0 > y x / atan A@ x 0 < y 0 >= & A pi + x 0 < y 0 < & A pi - x 0 == y 0 > pi 0.5 * y 0 < pi -0.5 * 0 0 ? ? ? ? ? ?
O@ pi 0.5 * < O 0.666666 * O pi 0.5 * >= pi O >= & pi 0.333333 * O 1.333333 * + 2.094395102 - 0 ? ? O + y * z /"), bi, fs), optSingleMode=false)
B = Expr(G, B, R, ex_dlut(Format("x 0 > y x / atan A@ x 0 < y 0 >= & A pi + x 0 < y 0 < & A pi - x 0 == y 0 > pi 0.5 * y 0 < pi -0.5 * 0 0 ? ? ? ? ? ?
O@ pi 0.5 * < O 0.666666 * O pi 0.5 * >= pi O >= & pi 0.333333 * O 1.333333 * + 2.094395102 - 0 ? ? O + x * z /"), bi, fs), optSingleMode=false)
MatrixClip(CombinePlanes(R, G, B, planes="RGB"),MatrixTranspose(RGB),"RGB") }
HSV doesn't use atan2() (but other cylindrical models do)
function RGB_to_HSV (clip R, clip G, clip B, bool fulls) {
bi = BitsPerComponent(R)
fs = Default (fulls, false)
V = Expr(R, G, B, "x y max z max", optSingleMode=false) # Lightness Hexcone
S = Expr(R, G, B, V, "a 0 == 0 a x y min z min - a / ?", optSingleMode=true) # Hexagonal Chroma
H = Expr(R, G, B, V, "a x y min z min - N@
0 == 0
x a == y z - N / % 6
y a == z x - N / 2 +
z a == x y - N / 4 + 0 ? ? ? ? 60 360 / *", optSingleMode=true)
CombinePlanes(H, S, V, planes="RGB") }
function RGB_to_HSV2 (clip R, clip G, clip B, bool fulls) {
bi = BitsPerComponent(R)
fs = Default (fulls, false)
V = Expr(R, G, B, "x y max z max", optSingleMode=false)
S = Expr(R, G, B, V, "a x y min z min - a /", optSingleMode=true)
H = Expr(R, G, B, V, S, "a x - a x y min z min M@ - / R^
a y - a M - / G^
a z - a M - / B^
b 0 == 0
x a == Rm@ y M == & 5 B +
Rm y M != & 1 G -
y a == Gm@ z M == & 1 R +
Gm z M != & 3 B -
Rm 3 G + 5 R - ? ? ? ? ? ? 60 360 / *", optSingleMode=true)
CombinePlanes(H, S, V, planes="RGB") }
function HSV_to_RGB (clip H, clip S, clip V, bool fulls) {
bi = BitsPerComponent(H)
fs = Default (fulls, false)
fix = "1 +"
Hu = " x "+fix+" 360 60 / * "
Ch = " y z * "
X = " 1 H % 2 1 - abs - C * "
m = " z C - " # addition to the end
R = Expr(H, S, V, Hu+" H@ 0 == 0 H 1 < "+Ch+" C@ H 2 < "+X+" X@ H 4 < 0 H 5 < X C ? ? ? ? ? "+m+" +", optSingleMode=false)
G = Expr(H, S, V, Hu+" H@ 0 == 0 "+Ch+" C^ H 1 < "+X+" X@ H 3 < C H 4 < X H 6 < 0 0 ? ? ? ? ? "+m+" +", optSingleMode=false)
B = Expr(H, S, V, Hu+" H@ 2 < 0 "+Ch+" C^ H 3 < "+X+" X@ H 5 < C H 6 < X 0 ? ? ? ? "+m+" +", optSingleMode=false)
CombinePlanes(R, G, B, planes="RGB") }
function HSV_to_RGB2 (clip H, clip S, clip V, bool fulls) {
bi = BitsPerComponent(H)
fs = Default (fulls, false)
# pr = Expr(H, "x 60 / floor")
# se = Expr(H, pr, "x y -")
# a = Expr(S, V, "1 x - y *")
# b = Expr(S, V, se, "1 x z * - y *")
# c = Expr(S, V, se, "1 x 1 z - * - y *")
pr = " x 60 360 / * floor "
se = " x P - "
a = " 1 y - z * "
b = " 1 y SE * - z * "
c = " 1 y 1 "+se+" SE@ - * - z * "
R = Expr(H, S, V, pr+" P@ 0 == P 5 == or z P 4 == "+c+" P 1 == "+b+a+" ? ? ? ", optSingleMode=false)
G = Expr(H, S, V, pr+" P@ 0 == "+c+" P 1 == P 2 == or z P 3 == "+b+a+" ? ? ? ", optSingleMode=false)
B = Expr(H, S, V, pr+" P@ 0 == P 1 == or "+a+" P 2 == "+c+" P 5 == "+b+" z ? ? ? ", optSingleMode=false)
CombinePlanes(R, B, G, planes="RGB") }
EDIT: continued here (https://forum.doom9.org/showthread.php?p=1953120#post1953120).
real.finder
27th September 2021, 07:42
since avs+ has array since 3.6, isn't better to add vs ShufflePlanes? or at least update CombinePlanes to make it support arrays same as ShufflePlanes
pinterf
27th September 2021, 10:02
+1 on that request. I'm currently using Gavino's method:
standard atan2 returns the range of -Pi..+Pi, I'm gonna keep that convention.
EDIT: new build with atan2
Avisynth+ 3.7.1 test build 18 (20210927) (https://drive.google.com/uc?export=download&id=13-lNFkFHkRg4-mwE2uCI16UbpyrE_REp)
pinterf
28th September 2021, 14:19
Avisynth+ 3.7.1 test build 19 (20210928) (https://drive.google.com/uc?export=download&id=1PjSi1wK1ChTpLvvSv42xdufCQe5fTqml)
Expr sin and cos SIMD implementation ported from VapourSynth. Thanks to Akarin for adding the feature.
(The internals of Expr source code has been changed significantly since I have ported Expr many years ago. Now only the basic sin and cos logic and instruction order was ported.)
height =240
BlankClip(width=360, height=height * 2, pixel_type = "YV24")
sin_cos = "cos"
c1=expr(Format("sx 180 / pi * {sin_cos} {height} * {height} + sy < 255 0 ?"),"","", optSSE2=true, optAvx2=true ).SubTitle("AVX2")
c2=expr(Format("sx 180 / pi * {sin_cos} {height} * {height} + sy < 255 0 ?"),"","", optSSE2=true, optAvx2=false ).SubTitle("SSE2")
c3=expr(Format("sx 180 / pi * {sin_cos} {height} * {height} + sy < 255 0 ?"),"","", optSSE2=false, optAvx2=false ).SubTitle("C")
c11=expr(Format("sx 180 / pi * {sin_cos} {height} * {height} + sy < 255 0 ?"),"","", optSSE2=true, optAvx2=true, optsingleMode=true).SubTitle("AVX2 SingleMode")
c12=expr(Format("sx 180 / pi * {sin_cos} {height} * {height} + sy < 255 0 ?"),"","", optSSE2=true, optAvx2=false, optsingleMode=true).SubTitle("SSE2 SingleMode")
Interleave(c1,c2,c3,c11,c12)
You can expect speed ratios something like this (one clip, Y8 and w/o SubTitle)
5160 fps (AVX2)
2282 fps (SSE2)
220 fps (C)
3711 fps (AVX2 single mode)
1703 fps (SSE2 single mode)
FranceBB
28th September 2021, 15:26
Wow new version again. I can't keep up with those eheheheh
Downloaded now, thanks ferenc, as always! :)
Dogway
28th September 2021, 16:42
Thanks a lot! but what do I do now with my Taylor series?! lol
tormento
28th September 2021, 20:34
Thanks a lot! but what do I do now with my Taylor series?! lol
Perhaps they are faster! Never lose hope! :D
Reel.Deel
29th September 2021, 10:04
@pinterf
Thank you for the updates and adding atan2 to Expr.
I was looking in the "readme_history", is there any plans to add topleft chroma placement to the convert functions?
On the side note, I just discovered the Text filter and noticed some differences to FreeSub, I think they way the Text filter handles alpha value in text_color and halo_color may be incorrect or inconsistent. I can prepare a script showing the problem if you'd like.
FranceBB
29th September 2021, 10:22
s there any plans to add topleft chroma placement to the convert functions?
+1
That would be useful, given the widespread use of 4:2:0 Type 2 nowadays. It would actually allow me to send the avs straight to x265 rather than going through FFmpeg to convert first...
Reel.Deel
29th September 2021, 10:33
+1
That would be useful, given the widespread use of 4:2:0 Type 2 nowadays. It would actually allow me to send the avs straight to x265 rather than going through FFmpeg to convert first...
There's already 3 plugins that support topleft (type 2) chroma placement :p so you can already do that. But seeing how the convert functions already support "Rec2020" and "PC.2020" matrix I think it would be logical to also support the corresponding chroma placement.
pinterf
29th September 2021, 11:07
Isn't top left the same as DV?
Reel.Deel
29th September 2021, 12:08
Isn't top left the same as DV?
I'm not sure, all I know is that chromaloc type 1 is known as mpeg1, center, or jpeg and chromaloc type 0 is known as mpeg2 or left.
Here's page 430/31 from Recommendation ITU-T H.265:
https://i.ibb.co/0CTXy4Q/page430.png (https://ibb.co/y6tRFvV)
https://i.ibb.co/TKmRLfX/page431.png (https://ibb.co/0BhZt7N)
vBulletin® v3.8.11, Copyright ©2000-2026, vBulletin Solutions Inc.