Log in

View Full Version : Gradation Curves


ErazorTT
13th January 2019, 01:04
For one pretty hard issue I needed to tweak the levels of a clip quite heavily. After analyzing the problem at hand in Photoshop I found that I needed to do a change equivalent to what Photoshop does with its Curves (https://www.gimp.org/tutorials/Basic_Color_Curves/) setting using up to 5 anchor points with different coordinates for each of the R, G and B channels. However, it turned out that there is just no equivalent function/plugin/scipt in avisynth doing this. (At least not in high bits or using x64 avisynth. For 8 bits on 32 bits machnies this (http://forum.doom9.org/showthread.php?p=605890#post605890) might still be ok, though I could not get it running.)

So I came up with the following plugin:

ApplyGradationCurves(clip, string "lumaPoints", string "redPoints", string "greenPoints", string "bluePoints", string "curvesFile", string "plotsPath")

Compute an expression of the gradation curve through the given anchor points. Like what Photoshop and Gimp do in the Curves setting (https://www.gimp.org/tutorials/Basic_Color_Curves/).

clip =

Clip to apply the gradation curves


string "lumaPoints" =
string "redPoints" =
string "greenPoints" =
string "bluePoints" =

Pair wise points given to define the mapping from the input values and the output values. Each pair is the x and y coordinates of an anchor point through which the gradation curve goes. You must provide at least two points. The points provided should cover almost the whole range of values you want to map. The points can be given in the 8 bits representation independently of the actual clip bit depth, the curve will be scaled automatically. If given, the points have priority over the "curvesFile".


string "curvesFile" =

File containing the curves. This can be used instead of giving the anchor points using the strings "lumaPoints", "redPoints", "greenPoints", "bluePoints". Supported are Photoshop *.acv files and GIMP curve files in the "old format", these must contain anchor points. Path must be given using forward slashes "/" and not backslashes "". You need to have permission to read from there!


string "plotsPath" =

If given, plots showing the applied curves are saved at the location. a plot of the curve is saved as a Bitmap file on the location given. The path must be given using forward slashes "/" and not backslashes "". You need to have permission to write there!



Example 1: Adjust Luma directly on TV scale (the values are not compatible to the ones Photoshop shows):

ApplyGradationCurves(lumaPoints="16,16,107,127,235,235",plotsPath="C:/Users/Public/")


Example 2: Adjust Luma on PC scale such that the values of the luminosity channel can be taken directly from Photoshop. Transformation in 16 bit might be preferable.

ConvertBits(16).ColorYUV(levels="TV->PC")
ApplyGradationCurves(lumaPoints="0,0,107,127,255,255",plotsPath="C:/Users/Public/")
ColorYUV(levels="PC->TV").ConvertBits(8,dither=1)


Example 3: Adjust RGB on a YUV clip by transforming to PlanarRGB and back to YUV using 16 bit processing, to mitigate banding and rounding errors. Values can again be taken directly from the respective channels in Photoshop.

ConvertBits(16).ConvertToPlanarRGB(matrix="Rec709")
pointsR="0,0,104,127,199,255"
pointsG="0,0,104,127,218,255"
pointsB="0,0,87,127,185,255"
ApplyGradationCurve(redPoints=pointsR,greenPoints=pointsG,bluePoints=pointsB)
ConvertToYUV420(matrix="Rec709").ConvertBits(8,dither=1)


Example 4: Like 3 but loading the values from the acv file

ConvertBits(16).ConvertToPlanarRGB(matrix="Rec709")
ApplyGradationCurves(curvesFile="C:/Users/Public/exampleAcv.acv",plotsPath="C:/Users/Public/")
ConvertToYUV420(matrix="Rec709").ConvertBits(8,dither=1)


Changelog:

Jan 18, 2019: r9
- first functional release

Dec 19, 2021: r10
- fix bug in crv-file reader

Alternative and most up to date download: here (https://drive.google.com/file/d/1zPC92gH296fjqw3TsawgjGNAP5K-jG_j/view?usp=sharing)

WorBry
13th January 2019, 06:11
Do you have any intent to add support for importing Photoshop (amp, maybe acv also) and Gimp (cur) curves ?

For 8 bits on 32 bits machnies this (http://forum.doom9.org/showthread.php?p=605890#post605890) might still be ok, though I could not get it running.)


I could never get GiCoCu working properly with PS amp files and it would be nice to have an AVS plugin that does...and with high bit depth support. Only alternative (I'm aware of) is using VirtualDub Gradation Curves in combination with Loadvirtualdubplugin to import the curve co-ordinates string.

ErazorTT
13th January 2019, 13:11
I had to update the interface. The first post is updated accordingly.

Do you have any intent to add support for importing Photoshop (amp, maybe acv also) and Gimp (cur) curves ?

I would need to have definitions for those. Do you have something like that? Once I have that I can figure out how complicated I would be to implement this. In the meantime you will have to copy the values one by one for each point...

Reel.Deel
13th January 2019, 14:03
Thank you for this filter :).

I would need to have definitions for those. Do you have something like that?

Does this help: https://github.com/HomeOfVapourSynthEvolution/VapourSynth-Curve/

poisondeathray
13th January 2019, 16:16
Thanks,

I don't know if this helps, but the gradcurve port in vapoursynth, which accepts acv, amp, etc... (but like the original vdub gradation curves only accepts 8bit) is here
https://github.com/xekon/GradCurve

ErazorTT
13th January 2019, 16:46
Ok so apparently there is interest in getting the import feature included. I should be able to figure out how to implement this thanks to the sources you guys have posted.
So back to the keyboard! :)

WorBry
13th January 2019, 19:23
Thanks, that will be great !

ErazorTT
13th January 2019, 21:58
So I managed to get the ACV files going!
With GIMP however I found out that the new version exports a different file format than the old versions. Question is: Is it still worth to include the old format?

In the meantime here is a first version including the acv file reader.

Alternative download: here (https://drive.google.com/open?id=1AAAfuaQYAmeR2W_hza5BfA7OeSHymqe4)

WorBry
14th January 2019, 06:02
Great, I'll check it out tomorrow.

ErazorTT
15th January 2019, 13:10
I found that I was solving an other equation than photoshop so I changed to the spline model which photoshop uses. I need to make some more tests but things seem to work. The acv reading is also there.

Download here (https://drive.google.com/open?id=1uFHci6EL4Bn9Xfa27aKfjxSvF_Zs28Re)

tormento
15th January 2019, 20:51
Wow. Perhaps I can deal with my diving video.

ErazorTT
15th January 2019, 21:04
Found some other bugs, and have refined the interface. Using now a script for interfacing with the dll to ease the use.

First post updated!

WorBry
15th January 2019, 21:25
Now it's making more sense ;)
I'll resume testing later.

ErazorTT
15th January 2019, 21:44
Perhaps there is someone who can explain the new GIMP curves export file. I just don't get it...

ErazorTT
16th January 2019, 01:30
Ok so the old GIMP files can now also be imported. This will need some testing though. First post was updated accordingly.

ErazorTT
17th January 2019, 00:47
Found a stupid bug. New version on first post.

WorBry
18th January 2019, 04:09
On testing it appears to read PS.acv curves correctly but it's not producing expected results.

Here, a simple S-curve applied to 'RGB Channel' only.

The resulting bmp plots:

http://i.imgur.com/HLA9YaHm.png (https://imgur.com/HLA9YaH)

But applied to a greyscale ramp:

ImageReader("{Path}:/Greyscale_Grad_HD.png")
ConvertBits(16)
ConvertToYUV444(matrix="PC.709")
ApplyGradationCurves(curvesFile="{Path}:/PS_S-Curve_RGB.acv",plotsPath="{Path}:/plots/")
ConvertToYUV420().ConvertBits(8, dither=1)
#Spline36Resize(960,540).Histogram(mode="levels")
#Spline36Resize(540,960).TurnLeft().Histogram(mode="classic")
#ConvertToRGB(matrix="PC.709").Spline36Resize(680,540).HistogramRGBParade(width=0.25)


http://i.imgur.com/SxFimIqm.png (https://imgur.com/SxFimIq)

With no curve applied (omitting ApplyGradationCurves line):

http://i.imgur.com/aChDaY3m.png (https://imgur.com/aChDaY3)

Something not right there.

Edit: And applied to PlanarRGB:

ImageReader("{Path}:/Greyscale_Grad_HD.png")
ConvertBits(16)
ConvertToPlanarRGB()
ApplyGradationCurves(curvesFile="{Path}:/PS_S-Curve_RGB.acv",plotsPath="{Path}:/plots/")
ConvertToYUV420(matrix="PC.709").ConvertBits(8, dither=1)
#Spline36Resize(960,540).Histogram(mode="levels")
#Spline36Resize(540,960).TurnLeft().Histogram(mode="classic")
#ConvertToRGB(matrix="PC.709").Spline36Resize(680,540).HistogramRGBParade(width=0.25)


http://i.imgur.com/N7ZO5H0m.png (https://imgur.com/N7ZO5H0)

No curve applied:

http://i.imgur.com/R4pSwlcm.png (https://imgur.com/R4pSwlc)

But applying the same PS.acv curve via VirtualDub Gradation Curves:

ImageReader("V:\AVISynth Templates\Plugins\AVS GradationCurve\tests\Resolve_GS_Grad.png")
ConvertToRGB32()
VD_GradationCurves(1,"000001010102...very long string")
ConvertToYUV420(matrix="PC.709")
#LanczosResize(960,540).Histogram(mode="levels")
#LanczosResize(540,960).TurnLeft().Histogram(mode="classic")
#ConvertToRGB(matrix="PC.709").LanczosResize(680,540).HistogramRGBParade(width=0.25)

...produces the expected result:

http://i.imgur.com/KeHjVXum.png (https://imgur.com/KeHjVXu)

Perhaps there is someone who can explain the new GIMP curves export file. I just don't get it...

I've no idea, but personally I would find the 'new' GIMP curves file format more useful.

ErazorTT
18th January 2019, 09:07
Well in the first case you are applying a 0-255 curve to a YUV clip. Take a look at the plot.bmp, there you see that your curve extends below 16 and above 235 (is outside of the gray rectangle at the margins). You need to extend the YUV to the full range first: ColorYUV(levels="TV->PC") and then, if you want, back ColorYUV(levels="PC->TV").

Or, as you did in you second try, covert it to PlanarRGB. There of course is something going wrong as can be seen by the green mist.

ErazorTT
18th January 2019, 10:10
There was another bug in ApplyGradationCurves.avsi which led to the green mist in your test using PlanarRGB.

New version on first post!

WorBry
18th January 2019, 16:58
Well in the first case you are applying a 0-255 curve to a YUV clip. Take a look at the plot.bmp, there you see that your curve extends below 16 and above 235 (is outside of the gray rectangle at the margins). You need to extend the YUV to the full range first: ColorYUV(levels="TV->PC") and then, if you want, back ColorYUV(levels="PC->TV").

Surely I did that in the first instance on converting to YUV444(matrix="PC.709"):


ImageReader("{Path}:/Greyscale_Grad_HD.png")
ConvertBits(16)
ConvertToYUV444(matrix="PC.709")
ApplyGradationCurves(curvesFile="{Path}:/PS_S-Curve_RGB.acv",plotsPath="{Path}:/plots/")
ConvertToYUV420().ConvertBits(8, dither=1)
#Spline36Resize(960,540).Histogram(mode="levels")
#Spline36Resize(540,960).TurnLeft().Histogram(mode="classic")
#ConvertToRGB(matrix="PC.709").Spline36Resize(680,540).HistogramRGBParade(width=0.25)




Or, as you did in you second try, covert it to PlanarRGB. There of course is something going wrong as can be seen by the green mist.

The curve shape and range was also wrong.

There was another bug in ApplyGradationCurves.avsi which led to the green mist in your test using PlanarRGB.

New version on first post!

Testing new version GradationCurve_r8.7z. Same script:

ImageReader("{Path}:/Greyscale_Grad_HD.png")
ConvertBits(16)
ConvertToPlanarRGB()
ApplyGradationCurves(curvesFile="{Path}:/PS_S-Curve_RGB.acv",plotsPath="{Path}:/plots/")
ConvertToYUV420(matrix="PC.709").ConvertBits(8, dither=1)
#Spline36Resize(960,540).Histogram(mode="levels")
#Spline36Resize(540,960).TurnLeft().Histogram(mode="classic")
#ConvertToRGB(matrix="PC.709").Spline36Resize(680,540).HistogramRGBParade(width=0.25)

http://i.imgur.com/sORajMCm.png (https://imgur.com/sORajMC)

And:

ImageReader("{Path}:/Greyscale_Grad_HD.png")
ConvertBits(16)
ConvertToPlanarRGB()
ApplyGradationCurves(curvesFile="{Path}:/PS_S-Curve_RGB.acv",plotsPath="{Path}:/plots/")
ConvertToYUV420(matrix="Rec709").ConvertBits(8, dither=1)
#Spline36Resize(960,540).Histogram(mode="levels")
#Spline36Resize(540,960).TurnLeft().Histogram(mode="classic")
#ConvertToRGB(matrix="Rec709").Spline36Resize(680,540).HistogramRGBParade(width=0.25)

http://i.imgur.com/N5xhPaSm.png (https://imgur.com/N5xhPaS)

So, yes, the curve is now being applied to all three channels, not just the Green channel (so eliminating the 'green mist') but the curve shape/range is still wrong.

ErazorTT
18th January 2019, 17:12
Could you provide either the acv file or the points?

WorBry
18th January 2019, 17:27
Here's the acv file and greyscale ramp that I tested with: PS_S-Curve_RGB_acv (https://drive.google.com/file/d/1cCZMaUKRf_t0JtSovKQIDmaaMflLQmw5/view?usp=sharing)

ErazorTT
18th January 2019, 17:41
Ok thanks now I can reproduce that now. So the plot.bmp actually looks alright but the output is actually wrong. I am on it.

ErazorTT
18th January 2019, 19:28
ok there you go! New version in first post.

WorBry
18th January 2019, 20:17
Yes, that's working correctly now:

http://i.imgur.com/IH451zjm.png (https://imgur.com/IH451zj)

Thanks.

ErazorTT
18th January 2019, 20:33
awesome! Thanks for trying things out!

Wilbert
19th January 2019, 22:09
Just a remark. As license you state 'open source' on avisynth.nl. There are many open source licenses. If you mean public domain you should state it as such.

Boulder
12th December 2021, 19:39
I've been looking to test fixing the green tint issue of the extended version of Fellowship of the Ring, as per this post: https://www.avsforum.com/threads/the-lord-of-the-rings-extended.1307189/page-213#post-20844111

However, running ApplyGradationCurves(curvesFile="curves.cur") gives me an access violation pointing to line 18 of ApplyGradationCurves.avsi. Has anyone tested the plugin with a recent Avisynth+ build? I think I'm using the test27 one from the official thread now.

ErazorTT
18th December 2021, 03:01
Hey i'm the author of that.

I've been looking to test fixing the green tint issue of the extended version of Fellowship of the Ring

And actually that's exactly why I wrote this thing to start with. However its not possible to get a really good result this way. The reason is that the green tilt is actually not completly constant through out the film, but changes from scene to scene. It's very complecated to fix that. It can only be done by color-matching that version with the lower res version! I sent you a private message for more on that.


However, running ApplyGradationCurves(curvesFile="curves.cur") gives me an access violation pointing to line 18 of ApplyGradationCurves.avsi. now.
Could you send me the curve.cur file so I can test myself.

ErazorTT
19th December 2021, 02:25
Found and fixed the bug. New version pushed.

Boulder
19th December 2021, 11:06
Found and fixed the bug. New version pushed.

Thanks, will test right away :)

magiblot
30th January 2022, 16:43
Hi! Thank you for the filter.

I'm trying to apply a HSV gradation curve created with VirtualDub. I exported a .acv file and used ApplyGradationCurves(curvesFile="curves.acv"). However, the result in AviSynth looks very different from the result in VirtualDub. Am I doing anything wrong or is there anything that can be done about it?

Here are some screenshots:

Curves editor: https://i.imgur.com/smovAiZ.png
Original: https://i.imgur.com/w1tJdfr.png
VirtualDub: https://i.imgur.com/awdZcpb.png
ApplyGradationCurves: https://i.imgur.com/Qrl1mqM.png

Cheers.

EDIT: And of course, here is the .acv file: curves.acv (https://mega.nz/file/R0cGCZab#TvmXKAka2UOzdR_Rzx92vJW5rsc3kWWrKcag9xnIX6g)

ErazorTT
30th January 2022, 22:12
Well I guess its the colorspace. The channels in Avisynth are RGB or YUV but never HSV. You would need to move to HSV colorspace first, which I don't think is possible in avisynth. And the gradation curves plugin does not take care of converting the colorspace, it only applies the given curves to whatever channels the clip happens to have.

magiblot
31st January 2022, 00:52
Okay, perfect. Thanks for the explanation!

ErazorTT
31st January 2022, 23:37
For converting to HSV perhaps you could use Dogways script pack: https://github.com/Dogway/Avisynth-Scripts

The file TransformationPack.avsi provides the two functions RGB_to_HSV() and HSV_to_RGB(). So perhaps this does what you want.

magiblot
1st February 2022, 22:13
Thanks for pointing that out, I didn't know about that script! Unfortunately, it doesn't work, most likely because both filters use different ranges for the HSV channels. But it shouldn't be too difficult to port the VirtualDub filter to AviSynth.

poisondeathray
1st February 2022, 22:23
Did you try it through LoadVirtualDubPlugin ?

Also, that curves.acv doesn't load in vdub gradation curves for HSV. I think you need .amp . There is also a direct port for vapoursynth which works like the vdub plugin.

magiblot
2nd February 2022, 01:16
Hi poisondeathray, thanks for the suggestion.

I know about LoadVirtualDubPlugin, but I want to have this working on Linux. I also know about the VapourSynth port, but I stick with AviSynth.

Regarding the .acv file, it works for me, but after loading it I have to manually select the HSV colorspace and linear mode. Anyway, I used this format since it's the only one supported by both ApplyGradationCurves and Gradation Curves for VirtualDub (I think).

Cheers.

magiblot
4th February 2022, 18:39
AviSynth port done. In case anyone is interested, here it is: https://github.com/magiblot/gradation

ErazorTT
8th February 2022, 00:24
really awesome! Does it do anything GradationCurvres does?

magiblot
8th February 2022, 17:44
I haven't really checked if they work the same, but apparently it can also open acv and crv files (among others). However, it doesn't support high bit depth and it only accepts RGB32 input (for the time being). What it does support, tough, are more curve types and more colorspaces (like HSV), which is why I wanted to use that filter.

kedautinh12
28th April 2022, 14:45
gradation r50
https://github.com/magiblot/gradation/releases

rgr
26th December 2025, 23:05
gradation r50
https://github.com/magiblot/gradation/releases

Is the syntax the same as the original plugin? Is there a way to animate this function (Animate)?

rgr
21st January 2026, 01:17
Alternative and most up to date download: here (https://drive.google.com/file/d/1zPC92gH296fjqw3TsawgjGNAP5K-jG_j/view?usp=sharing)

BSSource("PXL_20241224_181006359-2 (neat).avi").trim(0,42621) # 14bit
setBT709("limited")
converttoPlanarRGB
pts=...
ApplyGradationCurves(redPoints=pts,greenPoints=pts,bluePoints=pts,plotsPath="gradation_curve.png")

Crashes until plotPath is removed.