View Full Version : GamMac v1.10 - 15 June 2018
StainlessS
16th July 2016, 11:16
GamMac, Gamma Machine. Original idea, see here:- http://forum.doom9.org/showthread.php?t=173683
GamMac(), [Gamma Machine] An extraordinary Idea by VideoFred (the gent from Gent). Coded by StainlessS.
Requires CPP runtimes from VS 2008.
Home Thread:- http://forum.doom9.org/showthread.php?p=1774281#post1774281
Idea:- http://forum.doom9.org/showthread.php?t=173683
RGB Only.
Useful to correct color cast on old 8mm films.
Alters channel pixel average to match LockChan using Gamma correction. (By default alters Red and Blue channels to match Green).
Additional tweaking via RedMul, GrnMul and BluMul multipliers.
What it does(roughly):-
Firstly, RAW input channel Ranges are measured for all three channels (see RngLim).
If ALL THREE raw input ranges are less than RngLim (single color frame), then for current frame,
there is no scaling nor gamma estimation, and only linear rendering is done to output range omin -> omax.
[Channels multipliers RedMul, GrnMul and BluMul NOT applied either.]
OtherWise,
If ANY ONE channel input range is less than RngLim and Scale==2, then Scale is (for current frame) knocked down to Scale=1.
Get Channel averages, minimums, and maximums (using loTh for minimums and hiTh for maximums).
if(Scale==0 OR (loTh<0.0 AND hiTh<0.0)) then
No rescaling.
if(Scale == 1 AND (loTh>=0.0 OR hiTh>=0.0)) then
rescales averages using combined dynamic range of r,g,b ie 0.0 -> (max(redMax,grnMax,bluMax) - min(redMin,grnMin,bluMin)).
else if(Scale == 2 AND (loTh>=0.0 OR hiTh>=0.0)) then
rescales averages using separate dynamic ranges ie 0.0->(redMax-redMin), 0.0->(grnMax-grnMin), 0.0->(bluMax-bluMin).
For each channel, estimate gamma function that will remap (scaled channel average * channel multiplier) to match a particular
LockVal (chosen via LockChan) when rendered to the chosen output range specified by omin and omax.
Then renders frame using the output averages from estimated gamma with output channel minimums at omin, and maximums at omax.
GamMac(Clip c,int "LockChan"=1,int "Scale"=2,
\ Float "RedMul"=1.0,Float "GrnMul"=1.0, Float "BluMul"=1.0,
\ Float "Th"= 0.0,Float "loTh"=Th,Float "hiTh"=Th,
\ Float "LockVal"=128.0,int "RngLim"=11,Float "GamMax"=10.0,
\ Clip "dc",
\ int "x"=20,int "y"=20,int "w"=-20,int "h"=-20,
\ int "omin"=0, int "omax"=255,
\ Bool "Show"=True,int "Verbosity"=2,Bool "Coords"=false,
\ Bool "Dither=False"
\ )
LockChan Default 1(Grn). Channel for lock to Average. [range -3 -> 2]
0 ] LockVal = Scaled(RedAve)
1 ] LockVal = Scaled(GrnAve)
2 ] LockVal = Scaled(BluAve)
-1] LockVal = Use explicit LockVal arg (see below).
-2] LockVal = (Scaled(RedAve)+Scaled(GrnAve)+Scaled(BluAve))/3.0. [Mean]
-3] LockVal = Median(Scaled(RedAve),Scaled(GrnAve),Scaled(BluAve))
Where Scaled(Channel Average) depends upon RngLim, Scale, and loTh, and hiTh.
Scale, default 1 Range 0 -> 1.
There is NO SCALING DONE if ALL THREE channels range is less than RngLim, see RngLim, linear render only.
If ANY ONE channel input range is less than RngLim and Scale==2, then Scale is (for current frame) knocked down to Scale=1.
where some described for Red Channel only:-
redMin = RedChanMin(ignorePerc=loTh) # Pixel minimum for red channel, ignoring up to loTh%, ie noise.
redMax = RedChanMax(ignorePerc=hiTh) # Pixel maximum for red channel, ignoring up to hiTh%, ie noise.
redAve = RedChanAve() # Pixel average for red Channel.
redRng = redMax - redMin
inMin = min(redMin,grnMin,bluMin) # Min of minimums
inMax = max(redMax,grnMax,bluMax) # Max of maximums
0 (Scale==0 || (loTh==-1.0 && hiTh==-1.0)) # No Effect on scale.
scaledAveR = redAve
scaledAveG = grnAve
scaledAveB = bluAve
1) Scales input channel average maximum dynamic range of R,G,B, to 0.0->(ChanAve-inMin)*255.0/(inMax-inMin)
scaler = 255.0 / (inMax - inMin)
scaledAveR = min(max((RedAve - inMin) * scaler,0.0),255.0)
scaledAveG = min(max((GrnAve - inMin) * scaler,0.0),255.0)
scaledAveB = min(max((BluAve - inMin) * scaler,0.0),255.0)
2) Scales input channel average dynamic range of R & G & B, Individually, to 0.0->(ChanAve-Chan_min)*255.0/(ChanMax-ChanMin)
scalerR = 255.0 / (redMax-redMin)
scalerG = 255.0 / (grnMax-grnMin)
scalerB = 255.0 / (bluMax-bluMin)
scaledAveR = min(max((redAve - redMin) * scalerR,0.0),255.0)
scaledAveG = min(max((grnAve - grnMin) * scalerG,0.0),255.0)
scaledAveB = min(max((bluAve - bluMid) * scalerB,0.0),255.0)
RedMul, default 1.0 Red channel multiplier adjustment. [0.1 <= RedMul <= 10.0]
GrnMul, default 1.0 Green channel multiplier adjustment. [0.1 <= GrnMul <= 10.0]
BluMul, default 1.0 Blue channel multiplier adjustment. [0.1 <= BluMul <= 10.0]
Scaled averages are multiplied by their multiplier then given as args to the gamma estimator.
Allow tweaking of R,G,B channels.
Above Multipliers only shown in metrics when at least one is != 1.0 (Always shown when Verbosity=3=FULL).
Th, Default 0.00 Sets Default for loTh and hiTh. Suggest Default, 0.00(percent). [-1.0(OFF) , or 0.0 -> 1.0]
loTh, Default Th As for Ignore_low in AutoLevels, or Threshold in YPlaneMin. [-1.0, or 0.0 -> 1.0]
Percent, amount of extreme pixels (eg noise) to ignore when finding minimum R, G or B channel values.
-1.0 is OFF, input channel minimum is set to 0 as for levels(0,gamma,input_max, ... ).
If loTh >=0.0, then will scan frame looking for lowest pixel value whose cumulative sum
[including all pixels counts of lower value pixels] is greater than loTh%.
loTh, only shown in metrics if greater or equal to 0.0 ie switched ON (Always shown when Verbosity=3=FULL).
hiTh, Default Th As for Ignore_high in AutoLevels, or Threshold in YPlaneMax. [-1.0, or 0.0 -> 1.0]
Percent, amount of extreme pixels (eg noise) to ignore when finding maximum R, G or B channel values.
-1.0 is OFF, input channel maximum set to 255, as in levels(input_min,gamma,255, ... ).
If hiTh >=0.0, then will scan frame looking for highest pixel value whose cumulative sum
[including all pixels counts of higher value pixels] is greater than hiTh%.
hiTh, only shown in metrics if greater or equal to 0.0 ie switched ON (Always shown when Verbosity=3=FULL).
LockVal, default 128.0 Only used if LockChan = -1. [0.0 < LockVal < 255.0] (set via LockChan if LockChan != -1)
There is no restricted range on this (other than 0.0 < LockVal < 255.0), so if you set a stupid value,
you will likely get stupid results.
RngLim, default 11 [1 <= RngLim <= 32]
If ALL THREE RAW input channel ranges ie (ChannelMax(max(hiTh,0.0))-ChannelMin(max(loTh,0.0))) are less than RngLim then
all scaling is disabled, and remapping is linear without gamma estimation, to range omin -> omax,
ie avoid remapping of Black, White frames, or single color frames.
GamMax, default 10.0 Upper value for guess gamma [1.0 < GamMax <= 10.0]
Starting guess upper range and limit for gamma estimator (probably best left alone).
The lower guess range and limit will be set to 1.0 / GamMax, by default 0.1.
Now allowing lower limit of GamMax to go as low as almost 1.0, GamMax now usable as
a gamma correction limiting device, where correction not allowed to exceed GamMax or go lower than
its reciprocal ie 1.0/GamMax. 'G' limited flag now added to flags line in metrics, hi-lited if Gamma
limited by GamMax (limiting includes any Red,Grn,BluMul, multiplier result).
dc, default clip c. Detection clip, Must be same ColorSpace and FrameCount as source clip, no other similarities enforced.
(can be different size, denoised etc).
x,y, Both default 20. Area of dc Detect clip frame to sample when getting averages and estimating Gamma function, allows to ignore rubbish at frame edges.
w,h, Both default -20. Specified as for crop eg x=10,y=20,w=-30,h=-40, as in crop(10,20,-30,-40).
omin, default 0. Output limits for all three R, and G, and B channels. [Range 0 -> 16]
omax, default 255. [Range 235 -> 255] (extremes 16->235 allow for Studio RGB output).
May want to give yourself a little head/foot room by setting eg omin=5, omax=250, so that you leave a little room for
further manual color tweaking.
Show, default true True, show metrics info on frame.
Verbosity, default 2 0 = Only upper frame metrics Flags line only
1 = Upper frame metrics
2 = Upper + important ones. (default)
3 = Nearly Full metrics.
4 = Full Metrics except version info
5 = Full Metrics including version info
Upper frame metrics shown as eg:- (when Verbosity=5=FULL)
nnnnn] Flags:- 1SRG
R G B
RAW: 10,253 10,253 10,253
IN: 10,253 10,253 10,253
IN_AVE: 78.466 88.552 78.767
SCALED: 71.847 82.431 72.162
GAMMA: 1.135 1.000 1.123
OUTAVE: 82.431 82.422 82.451
where,
nnnnn, is the frame number.
Flags:- (Specific to current frame, can change frame to frame)
'1' = LockChan, as above, channel '1'[ScaleAveG].
Can be, '0', '1', '2' [ScaleAve Channel number LockChan=-3(median) assigns '0', '1' or '2' as appropriate]
'A'[LockChan=-2, (ScaleAveR+ScaleAveG+ScaleAveB)/3.0]
'V'[LockChan=-1, Explicit LockVal]
'S' = Scale, mode signified by color.
Greyed out. Scale = 0(No Effect). May be Greyed out if all channels Min/Max are 0,255.
White. Scale = 1[Scales input channel average maximum dynamic range of R,G,B]
Orange. Scale = 2[Scales input channel average dynamic range of R and G and B, Individually]
'R' = Limited by RngLim, mode signfied by color.
Greyed out. Not Range Limited.
Red, at least 1 channel has remapping disabled.
'G' = Correction limited by GamMax, mode signfied by color.
Greyed out. Not Range Limited.
Orange hi-lite, at least 1 channel has GamMax limited gamma correction.
RAW: Shows RAW comma separated channel minimum and maximum, eg ChannelMin(max(loTh,0.0)) and (ChannelMax(max(hiTh,0.0)),
only shown if Verbosity>=3 or, if any RAW input range is less than RngLim AND any of the RAW inputs are different
to the equivalent standard input.
IN: Shows comma separated channel minimum and maximum (dependent upon Scale, loTh, hiTh).
IN_AVE: Input channel averages.
SCALED: Scaled input averages, (dependent upon Scale, loTh, hiTh, channel minimums and maximums).
GAMMA: Estimated gamma to achieve lockval for channel. (dependent upon pretty much everything).
OUTAVE: Output channel average ie rendered result.
ALL metrics derived from the detection clip dc (Including OutAve's).
Coords, default False. If True, then shows DC clip with dotted lines showing the x,y,w,h coords plotted on frame. (All other functionality disabled).
Dither, default False. If true, then dithers output, hopefully reducing banding (will be quite a lot slower, no ASM).
Produces Below. Top Left source. Top Right default settings. Bot Left BluMul 1.1 (too much Blue). Bot right BluMul=0.95.
https://s20.postimg.cc/kvgdhxxfh/Gam_Mac_1_zps4knvzil7.png (https://postimg.cc/image/w7syzq649/)
Source Left. Right, LockChan 0 (red) , Bot Left LockChan=1(Grn), BotRight LockChan=2((Blu)
https://s20.postimg.cc/8i3jb17r1/Gam_Mac_2_zpsax99sdji.png (https://postimg.cc/image/q857w2lbt/)
Source Left. Right, LockChan 0 (red) , Bot Left LockChan=1(Grn), BotRight LockChan=2((Blu)
https://s20.postimg.cc/jj39tspdp/Gam_Mac_3_zpskzc2dmu0.png (https://postimg.cc/image/5pex4qws9/)
See MediaFire or SendSpace in sig below.
EDIT: Zip approx 1MB, incl 3 png files, avs v2.58 x86, avs+ x86 and x64 dll's + source + VS2008 project files.
EDIT: Some images and JohnMeyer Parade clip often used in this thread:- https://forum.doom9.org/showthread.php?p=1825394#post1825394
FranceBB
16th July 2016, 15:04
Tested and it works perfectly on very old sources!
Thank you very much indeed; it's a way easier to adjust colours this way!
StainlessS
16th July 2016, 15:14
Glad you like it France, dont forget to say thanx to VideoFred for his weird & whacky idea :)
StainlessS
16th July 2016, 16:24
And here Lenna Sjööblom
Source Left. Right, LockChan 0 (red) , Bot Left LockChan=1(Grn), BotRight LockChan=2((Blu)
https://s20.postimg.cc/vyzznjipp/Lenna_zpsb3ccnvcu.png (https://postimg.cc/image/p8jie3vjt/)
Bernardd
16th July 2016, 17:17
Hello StainlessS
Just a proposal for lockval : (In_Ave_0 + In_Ave_1 +In_Ave_2)/3
When i have written my script based on RGBAdapt, i have found the average of channel averages give often better result than 128.
Bernard
StainlessS
16th July 2016, 17:58
GamMac v1.01, Update as per Bernardd post #5.
Thanks Berni, could well be useful. :)
Lenna again with LockChan = -2 for TopRHS pic (which turns out to be about LockVal=128.0)
https://s20.postimg.cc/dkpgjk6f1/Lenna2_zpsi30spmpe.png (https://postimg.cc/image/b3dpcamih/)
EDIT: Fred, take a look at Bernardd LockChan= -2, should we change to -2 as default ?
Don't take decision based purely on Lenna, think that was deliberately manually screwed with, for whatever reason.
The version of Lenna originally published in a well known magazine, the feather scarf I think is nearly black,
think published version must have been altered for publication, and the above 'red' version must have come from
source picture (not altered for publication) from the photographer, and then deliberately screwed with to make red.
Think maybe above LockChan=1 or LockChan=2 is more like original shot.
EDIT: Pub, more like this:
https://s20.postimg.cc/7xt3m33wd/Lenna_Org_zpstoi1s1pl.png (https://postimg.cc/image/u9qwfh309/)
videoFred
17th July 2016, 11:22
EDIT: Fred, take a look at Bernardd LockChan= -2, should we change to -2 as default ?
Working on it.... Looks all very promising!
Dll version runs at real time :)
Fred.
StainlessS
17th July 2016, 19:19
GamMac() v1.02, update. See 1st post.
Added LockChan= -3, and Verbosity args. Appearance changed a little. Probably a bit faster.
EDIT:
Dll version runs at real time :)
Plays the 4x stacked image of parade at about double speed on my crappy core duo, so pretty good speed.
Motenai Yoda
18th July 2016, 01:36
@StainlessS it can be made faster using a downscaled (with a gamma-aware resizer) clip?
also as it can find a minimum and maximum value for each channel, will be possible to make a level adjustment right before the average gamma-aligning?
StainlessS
18th July 2016, 01:53
Yo, Yoda,
Faster aint a problem, not implemented at all like in script.
So far as I'm concerned, not possible to make much faster (all done on pixel count arrays[histograms], not clips).
(dont know how gamma aware that might be, dont see how that would be a problem except for final render,
and I dont see that as my immediate problem, if someone else wants to take this further, then be my guest please.).
Can you expand upon this please
can find a minimum and maximum value for each channel, will be possible to make a level adjustment right before the average gamma-aligning?
for your amusement, here is most of the source, excluding setup stuff.
void GamMac::CountRGB(int n,unsigned int *cntR,unsigned int *cntG,unsigned int *cntB,IScriptEnvironment* env) {
n = (n<0) ? 0 : (n>= vi.num_frames) ? vi.num_frames - 1 : n;
PVideoFrame src = child->GetFrame(n, env);
int rowsize = src->GetRowSize();
int height = src->GetHeight();
int pitch = src->GetPitch();
const BYTE *srcp= src->GetReadPtr();
memset(cntR,0,sizeof(cntR[0])*256); memset(cntG,0,sizeof(cntG[0])*256); memset(cntB,0,sizeof(cntB[0])*256);
// We process from bottom to top (weird RGB order)
if(vi.IsRGB32()) {
for(int y=height;--y>=0;) {
for(int x=rowsize;(x-=4)>=0;) {
++cntB[srcp[x+0]];
++cntG[srcp[x+1]];
++cntR[srcp[x+2]];
}
srcp += pitch;
}
} else {
for(int y=height;--y>=0;) {
for(int x=rowsize;(x-=3)>=0;) {
++cntB[srcp[x+0]];
++cntG[srcp[x+1]];
++cntR[srcp[x+2]];
}
srcp += pitch;
}
}
}
double GamMac::GuessGamma(unsigned int *cnt,double reqAve) {
double result=-1.0;
double PrevAve=-1.0;
double glo=GamLo;
double ghi=GamHi;
const unsigned int Pixels = (vi.width * vi.height);
while(glo < ghi) {
double gmid = (glo + ghi) / 2.0;
const double igam = 1.0/gmid;
__int64 acc = 0;
for(int i=256;--i>=0;) {
double v=i/255.0; // scale 0.0 -> 1.0
if (v > 0.0) { // avoid error
v = pow(v,igam);
if (v > 1.0) v = 1.0; // avoid possible overflow
else if(v < 0.0) v = 0.0;
}
v = (v * 255.0) + 0.5;
int val = int(floor(v)); // Round towards -ve infinity
if (val > 255) val = 255;
else if(val < 0) val = 0;
acc += __int64(cnt[i]) * val;
}
double ave = double(acc) / Pixels;
if(ave==reqAve||fabs(ave-PrevAve)<0.00001) {result = gmid; break;}
else if(ave<reqAve) {glo=gmid;}
else {ghi=gmid;}
PrevAve=ave;
}
return result;
}
double GamMac::ChanAve(unsigned int *cnt) {
__int64 acc=0;
for(int i=256;--i>=0;) {acc += cnt[i] * __int64(i);}
const unsigned int Pixels = (vi.width * vi.height);
return ((double)acc / Pixels);
}
void GamMac::SetGammaLut(double gamma,BYTE *lut) {
if(fabs(gamma-1.0)<0.00001) {
for(int i=256;--i>=0;lut[i]=i);
} else {
const double igam = 1.0/gamma;
for(int i=256;--i>=0;) {
double v=i/255.0; // scale 0.0 -> 1.0
if (v > 0.0) { // avoid error
v = pow(v,igam);
if (v > 1.0) v = 1.0; // avoid possible overflow
else if(v < 0.0) v = 0.0;
}
v = (v * 255.0) + 0.5;
int val = int(floor(v)); // Round towards -ve infinity
if (val > 255) val = 255;
else if(val < 0) val = 0;
lut[i] = val;
}
}
}
double GamMac::ChanAveFromLut(unsigned int *cnt,BYTE *lut) {
__int64 acc=0;
for(int i=256;--i>=0;) {
acc += __int64(cnt[i]) * lut[i];
}
const unsigned int Pixels = (vi.width * vi.height);
return ((double)acc / Pixels);
}
PVideoFrame __stdcall GamMac::GetFrame(int n, IScriptEnvironment* env) {
n = (n<0) ? 0 : (n>= vi.num_frames) ? vi.num_frames - 1 : n;
unsigned int cntR[256],cntG[256],cntB[256];
CountRGB(n,cntR,cntG,cntB,env);
double inR=ChanAve(cntR);
double inG=ChanAve(cntG);
double inB=ChanAve(cntB);
double lockval;
if(LockChan==0) {lockval=inR;}
else if(LockChan==1) {lockval=inG;}
else if(LockChan==2) {lockval=inB;}
else if(LockChan==-2) {lockval=((inR+inG+inB)/3.0);}
else if(LockChan==-3) {double mx=max(max(inR,inG),inB); double mn=min(min(inR,inG),inB); lockval=inR+inG+inB-mx-mn;}
else {lockval =LockVal;}
bool offR=(inR<MinLim || inR>MaxLim);
bool offG=(inG<MinLim || inG>MaxLim);
bool offB=(inB<MinLim || inB>MaxLim);
double gammaR=(offR)?1.0:(fabs(inR-lockval*RedMul)<0.0001)?1.0:GuessGamma(cntR,lockval*RedMul);
double gammaG=(offG)?1.0:(fabs(inG-lockval*GrnMul)<0.0001)?1.0:GuessGamma(cntG,lockval*GrnMul);
double gammaB=(offB)?1.0:(fabs(inB-lockval*BluMul)<0.0001)?1.0:GuessGamma(cntB,lockval*BluMul);
BYTE lutR[256],lutG[256],lutB[256];
SetGammaLut(gammaR,lutR);
SetGammaLut(gammaG,lutG);
SetGammaLut(gammaB,lutB);
PVideoFrame src = child->GetFrame(n, env);
PVideoFrame dst = env->NewVideoFrame(vi);
int rowsize = src->GetRowSize();
int height = src->GetHeight();
int pitch = src->GetPitch();
int dpitch = dst->GetPitch();
const BYTE *srcp= src->GetReadPtr();
BYTE *dstp = dst->GetWritePtr();
int x,y;
// We process from bottom to top (weird RGB order)
if(vi.IsRGB32()) {
for(y=height;--y>=0;) {
for(x=rowsize;(x-=4)>=0;) {
dstp[x+0] = lutB[srcp[x+0]];
dstp[x+1] = lutG[srcp[x+1]];
dstp[x+2] = lutR[srcp[x+2]];
dstp[x+3] = srcp[x+3];
}
srcp += pitch;
dstp += dpitch;
}
} else {
for(y=height;--y>=0;) {
for(x=rowsize;(x-=3)>=0;) {
dstp[x+0] = lutB[srcp[x+0]];
dstp[x+1] = lutG[srcp[x+1]];
dstp[x+2] = lutR[srcp[x+2]];
}
srcp += pitch;
dstp += dpitch;
}
}
if(Show) {
double outR=ChanAveFromLut(cntR,lutR);
double outG=ChanAveFromLut(cntG,lutG);
double outB=ChanAveFromLut(cntB,lutB);
DrawFStr(dst,0,0,"%d] \a!GamMac v%.2f\a-\n"
" \a2R \a4G \a1B\a-\n"
"IN_AVE: %7.3f : %7.3f : %7.3f\nGAMMA : %7.3f : %7.3f : %7.3f\n"
"OUTAVE: %7.3f : %7.3f : %7.3f",n,GAMAC_VER,inR,inG,inB,gammaR,gammaG,gammaB,outR,outG,outB);
if(Verbosity!=0) {
if(Verbosity==1) {
DrawFStr(dst,0,vi.height/20-2,
"Lockchan=%d LockVal=%.3f\n"
"RedMul=%.3f GrnMul=%.3f BluMul=%.3f",
LockChan,lockval,RedMul,GrnMul,BluMul);
} else {
DrawFStr(dst,0,vi.height/20-4,
"Lockchan=%d LockVal=%.3f\nGamHi=%.3f GamLo=%.3f\nMinLim=%.3f MaxLim=%.3f\n"
"RedMul=%.3f GrnMul=%.3f BluMul=%.3f",
LockChan,lockval,GamHi,GamLo,MinLim,MaxLim,RedMul,GrnMul,BluMul);
}
}
}
return dst;
}
EDIT: Missed out CountRGB, added.
EDIT:
Starting to sober up a bit, and to some extent understand what you were saying, however, we do not do any resizing and
so dont understand where Gamma Aware Resizing would come into it.
Motenai Yoda
18th July 2016, 15:25
Yo, Yoda,
Faster aint a problem, not implemented at all like in script.
So far as I'm concerned, not possible to make much faster (all done on pixel count arrays[histograms], not clips).
It can be possible feed it with a LockClip with lower dimensions to do some stuff with less pixels IIRC LaTo's AutoAdjust can permitt that, can be faster when working on hi res stuff.
Can you expand upon this please
As it find out min/max of each channel too, it can be possible align min and max to the ref channel ones
like minB=>minG and maxB=>maxG
also the averages can be easely recalculated before doing gamma stuff
[CODE]
memset(cntR,0,sizeof(cntR[0])*256);
memset(cntG,0,sizeof(cntG[0])*256);
memset(cntB,0,sizeof(cntB[0])*256);
Wasn't better to use a runtime defined value to set cntR/G/B size?
Just to get the code ready for a future 16/32bit capability
StainlessS
18th July 2016, 16:14
It can be possible feed it with a LockClip with lower dimensions to do some stuff with less pixels IIRC LaTo's AutoAdjust can permitt that, can be faster when working on hi res stuff.
As we do all work on count arrays, that is irrelevant, you would still have to access hd source to create you lo-rez lock clip, even less work to create count arrays, and less again to do later processing on arrays rather than another clip.
As said previously, I'm getting about double realtime on the Parade stack4 clip, that is at least 6x realtime speed, and on my lowly core duo 2.4Ghz, better machine would probably get ~8, maybe 10 times faster than that.
Wasn't better to use a runtime defined value to set cntR/G/B size?
Just to get the code ready for a future 16/32bit capability
To use standard stack space, must be sized at compile time.
I doubt very much if you would want to be using stack space if using 16/32 bit count array, so whole lot would need to be changed anyway to use heap [ie 16 bit, 65536*sizeof(unsigned int]). For 32 bit, would be way too big to be practical, maybe Sparce Array or something would be required.
As it find out min/max of each channel too, it can be possible align min and max to the ref channel ones
like minB=>minG and maxB=>maxG
also the averages can be easely recalculated before doing gamma stuff
Dont know if that is a good idea, what say you Fred ?
EDIT: By the way, the last version v1.02 was an almost complete re-write to use almost exclusively count arrays and luts,
so is probably somewhat faster than previous. Judging by times of posts, re-write took about 2 hours total,
and so would guess modding for 16 bit would not be such a very hard job, there is not really very much of it.
As far as Stack16 is concerned, would not bother doing that, the only other RGB Stack16 plugin that I am aware of is
my ClipBlend16() which was a bit of a mistake as I did not know that there is no support for Stack16 RGB and no
demand for such.
videoFred
18th July 2016, 16:55
Dont know if that is a good idea, what say you Fred ?
I say stretching the histogram from R, G and B before GamMac() would be a very good idea. I have done it with autolevels() and it looks like this:
http://www.super-8.be/Doom/GamMac000001_small.jpg
http://www.super-8.be/Doom/GamMac000002_small.jpg
http://www.super-8.be/Doom/GamMac000003_small.jpg
http://www.super-8.be/Doom/GamMac000004_small.jpg
http://www.super-8.be/Doom/GamMac000005_small.jpg
http://www.super-8.be/Doom/GamMac000006_small.jpg
http://www.super-8.be/Doom/GamMac000007_small.jpg
http://www.super-8.be/Doom/GamMac000008_small.jpg
Original full size:
http://www.super-8.be/Doom/GamMac000001.jpg
http://www.super-8.be/Doom/GamMac000002.jpg
http://www.super-8.be/Doom/GamMac000003.jpg
http://www.super-8.be/Doom/GamMac000004.jpg
http://www.super-8.be/Doom/GamMac000005.jpg
http://www.super-8.be/Doom/GamMac000006.jpg
http://www.super-8.be/Doom/GamMac000007.jpg
http://www.super-8.be/Doom/GamMac000008.jpg
First frame is very old regular-8 film with blue cast. All other frames are 1970's Fuji Single-8 film with green cast, as you see.
By now, I have tested GamMac() on all kinds of 8mm films. I have made a AvsPmod script with sliders for Lockchan, RedMul, GrnMul and BluMul. Imho Lochchan can stay on 1. The "Mul' settings can be used for very fine tuning.
I can give hundreds of other examples, GamMac is removing the color cast (whatever it may be) in 90% of the cases.
More specific color tuning can be done afterwards with Tweak(hue, starhue, endhue) and RGBAdjust().
But GamMac gives a very good and full automatic base to work with, thank you again StainlessS :)
Fred.
Sparktank
18th July 2016, 18:03
Wow! Now that are some mighty fine results.
This is pretty amazing stuff. Not that I have any older material to work with, but just in general this is aboslutely fascinating to see.
This looks like something that can be fun to use on movies for an entirely different viewing.
I will definitely be looking at this one. :D
Motenai Yoda
18th July 2016, 19:41
As we do all work on count arrays, that is irrelevant, you would still have to access hd source to create you lo-rez lock clip, even less work to create count arrays, and less again to do later processing on arrays rather than another clip.
Well but to create count arrays it still scan the entire frame, I was thinking not only to a low rez clip but also at a denoised one to be used as a reference like some dither stuff do.
also why don't use a find min/max/avg cicle using the accumulator directly into countRGB?
ps Level stretching can be done in gammaLut, or just before, as average values can be scaled with a plain mx+q expression.
StainlessS
18th July 2016, 20:29
Fred, where we have minR, minG, minB, maxR, maxG, maxB,
should we do levels for eg R on minR, maxR, OR, min(minR,minG,minB) and max(maxR,maxG,maxB) ?
EDIT: On levels inputs ie Levels(minimum_r, gamma, maximum_r,0,255,coring=false)
EDIT: Can you post full script for top pic (lollipop lady), I'm not getting same numbers.
EDIT: Also, can you post the original unaltered pic and what you get out of autolevels. (No idea what autolevels does, its closed source I believe).
EDIT: And which autolevels do you use (LaTo seems to refer to both autogain and autolevels, as autolevels).
EDIT: Forget above about AutoLevels, was mixing up Frustum and LaTo plugins.
videoFred
18th July 2016, 21:47
Fred, where we have minR, minG, minB, maxR, maxG, maxB,
should we do levels for eg R on minR, maxR, OR, min(minR,minG,minB) and max(maxR,maxG,maxB) ?
Simple: not trying to match min, max or whatever but straight forward levels as close as possible to 0 and 255 for each individual RGB channel. Perhaps with a small margin like 5-250 or an adjustable margin.
EDIT: Can you post full script for top pic (lollipop lady), I'm not getting same numbers.
EDIT: Also, can you post the original unaltered pic and what you get out of autolevels.
Sure, I will do this as soon as possible (probably tomorrow afternoon)
Fred.
StainlessS
18th July 2016, 22:18
I suspected that you should NOT use separate min for R G and B, and so min(minR,minG,minB) and max(maxR,maxG,maxB)
are the correct values otherwise screws up relations to each other. See by IanB here:- http://forum.doom9.org/showthread.php?p=1457091#post1457091
I will not be attempting (or will discard any attempt so far) to add in Auto Levels functionality into GamMac(), one of the reasons
is that AutoLevels does temporal sampling to avoid sudden changes as happens with ColorYUV(AutoLevels=true), so to continue to
use AutoLevels would be the best solution, and I dont want to re-invent the wheel.
I see no gain in trying to combine two plugins into one, when using first AutoLevels and then GamMac, would provide the exact same result.
Dont bother with the requested samples Fred, dont need them now.
videoFred
18th July 2016, 23:18
I suspected that you should NOT use separate min for R G and B, and so min(minR,minG,minB) and max(maxR,maxG,maxB)
are the correct values otherwise screws up relations to each other. See by IanB here:- http://forum.doom9.org/showthread.php?p=1457091#post1457091
Ok it might be not correct but it works as you can see on my examples.
I will not be attempting (or will discard any attempt so far) to add in Auto Levels functionality into GamMac(), one of the reasons
is that AutoLevels does temporal sampling to avoid sudden changes as happens with ColorYUV(AutoLevels=true), so to continue to
use AutoLevels would be the best solution, and I dont want to re-invent the wheel.
Of cource, I understand. The autolevels temporal sampling works very well, no flickering and no sudden changes.
Fred.
StainlessS
19th July 2016, 00:46
This should hopefully be of use.
All it does is pass on args to respective plugins.
Some of the AutoLevels args are not passed where it makes no sense, eg the gamma related ones.
EDIT: Ignore below, have since implemented Scale=2.
Function AutoLevelsGamMac(clip c,
\ Bool "DoAutoLevels", bool "DoGamMac",
\ int "filterRadius",int "sceneChgThresh",String "frameOverrides",
\ int "input_low",int "input_high",int "output_low",int "output_high",float "ignore",float "ignore_low",float "ignore_high",
\ int "border",int "border_l",int "border_r",int "border_t",int "border_b",bool "debug",
\ int "LockChan",Float "LockVal",Float "RedMul",Float "GrnMul", Float "BluMul",
\ Float "MinLim",Float "MaxLim",float "GamLo",Float "GamHi",Bool "Show",int "Verbosity") {
c
DoAutoLevels=Default(DoAutoLevels,True) DoGamMac=Default(DoGamMac,True)
(DoAutoLevels)
\ ? Autolevels(filterRadius=filterRadius,sceneChgThresh=sceneChgThresh,frameOverrides=frameOverrides,
\ input_low=input_low,input_high=input_high,output_low=output_low,output_high=output_high,
\ ignore=ignore,ignore_low=ignore_low,ignore_high=ignore_high,
\ border=border,border_l=border_l,border_r=border_r,border_t=border_t,border_b=border_b,
\ debug=debug)
\ : NOP
(DoGamMac)
\ ? GamMac(LockChan=LockChan,LockVal=LockVal,RedMul=RedMul,GrnMul=GrnMul,BluMul=BluMul,
\ MinLim=MinLim,MaxLim=MaxLim,GamLo=GamLo,GamHi=GamHi,
\ Show=Show,Verbosity=Verbosity)
\ : NOP
Return Last
}
#Imagesource("test_RGB_Doom.jpg",end=0) Crop(0,0,width/2,height/2) Crop(0,0,width/4*4,height/4*4)
Imagesource("G1.bmp",end=0) crop(0,0,0,-48) Spline36Resize(480,360) # Lollipop lady minus RHS and histograms
#Imagesource("G2.bmp",end=0) crop(0,0,0,-48) Spline36Resize(480,360) # Plant lady minus RHS and histograms
#Imagesource("G3.bmp",end=0) crop(0,0,0,-48) Spline36Resize(480,360) # Avenue minus RHS and histograms
#Imagesource("G4.bmp",end=0) crop(0,0,0,-48) Spline36Resize(480,360) # Walkers minus RHS and histograms
#Imagesource("G5.bmp",end=0) crop(0,0,0,-48) Spline36Resize(480,360) # Parot minus RHS and histograms
#Imagesource("G6.bmp",end=0) crop(0,0,0,-48) Spline36Resize(480,360) # Deer minus RHS and histograms
#Imagesource("G7.bmp",end=0) crop(0,0,0,-48) Spline36Resize(480,360) # Taj Mahal minus RHS and histograms
#Imagesource("G8.bmp",end=0) crop(0,0,0,-48) Spline36Resize(480,360) # Puppy minus RHS and histograms
#Avisource("1937 Lund Utah 16mm Film [Low, 360p].mp4.avi")
#Avisource("1941 Flint Michigan Parade [Low, 360p].mp4.AVI")
#Avisource("v.avi")
#A=Trim(0,99)
#B=A.BlankClip(length=1) # Test Black Frame @ 100
#C=A.BlankClip(length=1,Color=$FFFFFF) # Test White Frame @ 101
#D=Trim(100,0)
#A++B++C++D
ConvertToRGB24
ORG=Last
LockChan = 1 # Chan for lock to Ave, 0=R, 1=G, 2=B
# -1 = Use LockVal below.
# -2 = LockVal=(RedAve+GrnAve+BluAve)/3.0 for LockVal.
# -3 = LockVal=Median(RedAve,GrnAve,BluAve)
LockVal = 128 # Only valid if LockChan == -1
GamHi = 4.0 # Extreme values for guess gamma (starting guess range and limit)
GamLo = 0.25 # Extreme values for guess gamma (starting guess range and limit)
RedMul = 1.00 # Required Ave multiplier for Red Channel, applied when requesting GuessGamma(reqAve*RedMul), Even applied when LockChan=-1.
GrnMul = 1.00 # Same for Green channel. GrnMul even applies when LockChan is Green Channel, etc for chans.
BluMul = 1.0 # Same for Blue channel. Allows tinkering/fine tuning.
MinLim = 32.0 # If Original channel Ave lesser then DO NOT FIX.
MaxLim = 255.0-32.0 # If Original channel Ave greater then DO NOT FIX.
Show = true # Subtitles
Verbosity= 1 # 0=Only Upper metrics, 1(default)=Upper + important ones. 2=All metrics.
A= AutoLevelsGamMac(DoGamMac=False)
B= AutoLevelsGamMac(DoAutoLevels=false,LockChan=LockChan,LockVal=LockVal,RedMul=RedMul,GrnMul=GrnMul,BluMul=BluMul,Show=Show,Verbosity=Verbosity)
C= AutoLevelsGamMac(LockChan=LockChan,LockVal=LockVal,RedMul=RedMul,GrnMul=GrnMul,BluMul=BluMul,Show=Show,Verbosity=Verbosity)
TOP=StackHorizontal(ORG,A)
BOT=StackHorizontal(B,C)
StackVertical(TOP,BOT)
return Last
EDIT:
Ok it might be not correct but it works as you can see on my examples.
That IanB quote was from the AutoLevels thread, I assume that Frustum corrected it in later versions of AutoLevels
to match what IanB said.
Bloax
19th July 2016, 09:23
https://dl.dropboxusercontent.com/u/63152810/lenna.png
Doing some adjustment bullshit in Photoshop (https://dl.dropboxusercontent.com/u/63152810/lenna.7z) (primarily curves with a little Color Balance cheating) certainly reveals that you can do much more.
But it's good to see people making interesting things, even if I have no use for them myself being the young'un I am.
videoFred
19th July 2016, 11:49
But it's good to see people making interesting things, even if I have no use for them myself being the young'un I am.
But perhaps there are some old family films hidden somewhere at your uncles or grandfathers house, you never know :)
Fred.
udobroemme
19th July 2016, 15:12
Thank you very much for this great filter. I did a few tests with some faded prints and the results are very impressing. :thanks:
StainlessS
19th July 2016, 15:17
Ok it might be not correct but it works as you can see on my examples.
I did try in GamMaC to set levels using both individual min,max for each channel, and also chanmin=min(minR,minG,minB), chanmax=max(maxR,maxG,maxB),
and results were not terribly encouraging. Looking at AutoLevels source, I find that it converts R,G & B to Luma Y to get min, max and mean (together
with the ignore args). So, AutoLevels currently uses neither RGB min,max method mentioned. Dont know whether this change was done since the previous
IanB quote or whether always as is.
Anyway, we really dont need to be re-inventing that wheel and I am now happy to completely abandon any idea to do same in purely RGB.
Fred can you verify that you did not use any of the gamma args in AutoLevels in your tests [they are unused by default and I did not pass on gamma
related args in the AutoLevelsGamMac() stub]. EDIT: better still can you post the script for eg the Lollipop Lady [GamMac000001.jpg].
EDIT: @ Bloax, you could have gotten LockChan 2 Lenna without the metrics setting Show=false, and perhaps better
results in PhotoShop due to missing white text. (guess you just downloaded the pic and not GamMac).
StainlessS
19th July 2016, 18:43
Fred, I cocked up previous trials at the RGB prelevel thing (such is the lot of a nincompoop),
I had another go and this time a bit better.
Here v1.03Beta for you to have a play with, because I'm going t' pub.
LINK REMOVED
and the puppy pic
https://s20.postimg.cc/gu3vq0uil/Puppy_zpsgozcwht1.png (https://postimg.cc/image/q1w46q1kp/)
args added
Th, Default 0.0(off) 0.0 -> 10.0(perhaps limited to ~2.0 in non Beta). Default for MinTh and MaxTh. Suggest about 0.2(percent).
MinTh, Default Th. 0.0 -> ??? as for Ignore_low in AutoLevels, or threshold in YPlaneMin.
MaxTh, Default Th. 0.0 -> ??? as for Ignore_high in AutoLevels, or threshold in YPlaneMax.
MinMaxLock, Default True. If true, input_low and input_high set identical eg min(rmin,gmin,bmin) for R,G,B. Else set individually.
Can use instead of AutoLevels if required.
EDIT: If you (or anyone) would like to knock up a little documentation, that would be glorious :) [me hates dat]
videoFred
20th July 2016, 00:04
Fred can you verify that you did not use any of the gamma args in AutoLevels in your tests [they are unused by default and I did not pass on gamma
related args in the AutoLevelsGamMac() stub]. EDIT: better still can you post the script for eg the Lollipop Lady [GamMac000001.jpg].
Yes, I can confirm I have not used any gamma args in AutoLevels(). Do you still need my script? Because I have seen your update in the next post.
Fred.
videoFred
20th July 2016, 00:07
Here v1.03Beta for you to have a play with, because I'm going t' pub.
Thank you! Have a Belgian beer on my account :)
Will test it asap...
EDIT: If you (or anyone) would like to knock up a little documentation, that would be glorious :) [me hates dat]
I can do this, but first we must be sure to have the final version. :)
Fred.
StainlessS
20th July 2016, 00:31
I can do this, but first we must be sure to have the final version.
Fantastic, however, you also have to pick names (mine usually start out as temp or fred (not in honour of you, [but you can tell people that it is, I will not deny it])
Need full docs, way more sensible than wot I wud wryt.
Take your time, be careful, and good. May the lord be with you, and also with you. :) (no idea wot that means).
EDIT: Pick, suggest whatever arg names you want, I pretty much guarantee your suggestions are acceptable and concrete.
EDIT:
Lost my other Vape stick again, today is a very sad day, again. Sick 0' losin my Vape sticks, the world is such a dangerous place.
Stella, beer, pretty damn good. Also your Trappist, brewed by drunken clerics (very well recommended).
Belgians are the most prolific of Beer makers (high up there on drinkers too) in the world.
Motenai Yoda
20th July 2016, 14:21
I did try in GamMaC to set levels using both individual min,max for each channel, and also chanmin=min(minR,minG,minB), chanmax=max(maxR,maxG,maxB),
and results were not terribly encouraging.
Just to be sure, did you recalculate the avg values with the scale formula before guess gamma?
my suggestion was about to match a reference channel range coz other tools yet did increase global contrast using something like min(minR,minG,minB)/max(maxR,maxG,maxB), also autolevels roughly do the same but it stretch all of them to 0/255 - 16/235 not maintaining the source frame's dynamic range
also IanB was talking about don't change RGB ratios as AutoLevels is to increase global contrast without change colors or dominances.
GamMac will change those ratios anyway.
ps as gamma function is more effective on the lower part of the range than on the upper one, maybe will be better to use a different, more balanced, curve?
StainlessS
20th July 2016, 15:51
Not terribly encouraging
Basically I forgot that the thresholds were in percent, and so forgot to divide by 100.0, so results were garbage :(
did you recalculate the avg values with the scale formula before guess gamma?
No.
Yoda, discuss what is required with Fred, so far as I'm concerned it is his baby and he's the gaffer.
Source is included in the zip below (I shall not try to convert the original script to be similar to current version).
GamMac(), [Gamma Machine] An extraordinary Idea by VideoFred (the gent from Gent). Coded by StainlessS.
Home Thread:- http://forum.doom9.org/showthread.php?p=1774281#post1774281
Idea:- http://forum.doom9.org/showthread.php?t=173683
RGB Only.
Useful to correct color cast on old 8mm films.
Alters channel pixel average to match LockChan using Gamma correction. (By default alters Red and Blue channels to match Green).
Additional tweaking via RedMul, GrnMul and BluMul.
GamMac(clip c,int "LockChan"=1,Float "LockVal"=128,
\ Float "RedMul"=1.0,Float "GrnMul"=1.0, Float "BluMul"=1.0,
\ Float "MinLim"=32.0,Float "MaxLim"=255.0-32.0,float "GamLo"=0.25,Float "GamHi"=4.0,
\ Bool "Show"=false,int "Verbosity"=1
\ Float "Th"= -1.0,Float "loTh"=Th,Float "hiTh"=Th,Bool "loHiLock"=True
\ )
LockChan Default 1. Chan for lock to Ave. (0)LockVal=RedAve, (1)LockVal=GreenAve, (2)LockVal=BlueAve
-1 = Use explicit LockVal below.
-2 = LockVal=(RedAve+GrnAve+BluAve)/3.0.
-3 = LockVal=Median(RedAve,GrnAve,BluAve)
LockVal, default 128.0. Ignored if LockChan != -1.0. 0.0 < LockVal < 255.0
RedMul, default 1.0. 0.1 <= RedMul <= 10.0. Red channel adjustment.
GrnMul, default 1.0. 0.1 <= GrnMul <= 10.0. Green channel adjustment.
BluMul, default 1.0. 0.1 <= BluMul <= 10.0. Blue channel adjustment.
Above Multipliers only shown in metrics when at least one is != 1.0.
MinLim, default 32.0. 0.0 < MinLim < 255.0 If any channel average smaller than this, then no effect on channel.
MaxLim, default 255.0-32.0. MinLim < MaxLim < 255.0 If any channel average greater than this, then no effect on channel.
GamLo, default 0.25. 0.1 <= GamLo <= 10.0. Lower value for guess gamma (starting guess range and limit)
GamHi, default 4.0. GamLo < GamHi <= 10.0. Upper value for guess gamma (starting guess range and limit)
Show, default false. True, show info.
Verbosity, default 1. 0=Only Upper metrics, 1(default)=Upper + important ones. 2=Full metrics.
Th, Default -1.0(off) -1.0, or 0.0 -> 2.0. Sets Default for loTh and hiTh. Suggest about 0.0, or 0.1(percent).
loTh, Default Th. -1.0, or 0.0 -> 2.0. as for Ignore_low in AutoLevels, or Threshold in YPlaneMin.
hiTh, Default Th. -1.0, or 0.0 -> 2.0. as for Ignore_high in AutoLevels, or Threshold in YPlaneMax.
Percent, amount of extreme pixels (eg noise) to ignore when finding minimum and maximum R, G or B channel values.
-1.0 is OFF, input channel minimum is set to 0 and maximum set to 255.0, as in levels(0,gamma,255, ... ).
If loTh set to eg 0.0, then will scan frame looking for minimum accumulated channel values that have more than 0.0%
of pixels, and set input_min for that channel to that value. (Accumulated:- including values that were lower but not
of great enough number to break the threshold).
If hiTh set to eg 0.0, then will scan frame looking for maximum accumulated channel values that have more than 0.0%
of pixels, and set input_max for that channel to that value.
loTh and hiTh, only shown in metrics if greater or equal to 0.0 ie switched ON.
loHiLock, Default True. If (loHiLock==true) then input_lowR = min(rmin,gmin,bmin) ELSE input_lowR = rmin
If (loHiLock==true) then input_highR = max(rmax,gmax,bmax) ELSE input_highR = rmax
Where for Red, sort of equivalent to outR=LevelsR(input_lowR,gamma,input_highR, 0,255)
Same for other channels.
Imagesource("GreenChurch.png",end=0)
#Imagesource("Puppy.png",end=0)
#Imagesource("lennaRed.png",end=0)
#Avisource("1937 Lund Utah 16mm Film [Low, 360p].mp4.avi")
#Avisource("1941 Flint Michigan Parade [Low, 360p].mp4.AVI")
ConvertToRGB24
ORG=Last
LockChan = 1 # Chan for lock to Ave, 0=R, 1=G, 2=B
# -1 = Use LockVal below.
# -2 = LockVal=(RedAve+GrnAve+BluAve)/3.0 for LockVal.
# -3 = LockVal=Median(RedAve,GrnAve,BluAve)
LockVal = 128 # Only valid if LockChan == -1
RedMul = 1.0 # Required Ave multiplier for Red Channel, applied when requesting GuessGamma(reqAve*RedMul), Even applied when LockChan=-1.
GrnMul = 1.0 # Same for Green channel. GrnMul even applies when LockChan is Green Channel, etc for chans.
BluMul = 1.0 # Same for Blue channel. Allows tinkering/fine tuning.
Show = true # Subtitles
A=GamMac(LockChan=LockChan,LockVal=LockVal,RedMul=RedMul,GrnMul=GrnMul,BluMul=BluMul,Show=Show,Verbosity=0)
thB = 0.0
BluMulB = 0.95
B=GamMac(LockChan=LockChan,LockVal=LockVal,RedMul=RedMul,GrnMul=GrnMul,BluMul=BluMulB,Show=Show,Verbosity=1,th=thB)
thC = 0.0
BluMulC = 0.95
LoHiLockC=False
C=GamMac(LockChan=LockChan,LockVal=LockVal,RedMul=RedMul,GrnMul=GrnMul,BluMul=BluMulC,Show=Show,Verbosity=2,th=thC,LoHiLock=LoHiLockC)
TOP=StackHorizontal(ORG,A)
BOT=StackHorizontal(B,C)
StackVertical(TOP,BOT)
return Last
Produces this
https://s20.postimg.cc/ruz0v1mrh/Green_Church_zps9vcfwkvl.png (https://postimg.cc/image/569tvh5dl/)
Here v1.04, incl GreenChurch, Puppy, and red Lenna pings(990KB):- LINK REMOVED
Fred, I'm leaving totally up to you to say what your orders are, including any arg name changes or whatever,
awaiting instruction.
I can do what Yoda suggests if required (or make optional via arg if required).
StainlessS
20th July 2016, 21:03
OK, have tried to implement what Yoda was talking about.
update to DOC
GamMac(clip c,int "LockChan"=1,Float "LockVal"=128,
\ Float "RedMul"=1.0,Float "GrnMul"=1.0, Float "BluMul"=1.0,
\ Float "MinLim"=32.0,Float "MaxLim"=255.0-32.0,float "GamLo"=0.25,Float "GamHi"=4.0,
\ Bool "Show"=false,int "Verbosity"=1
\ Float "Th"= -1.0,Float "loTh"=Th,Float "hiTh"=Th,Bool "loHiLock"=True
\ bool "Scale"=true
\ )
...
Scale, default False. if Scale (and loTh and/or hiTh >= 0.0) then scales input channel averages
eg, in_scale = (Scale) ? 255.0 / (in_max - in_min) : 1.0;
where in_min = min(minR,minG,minB) and in_max = max(maxR,maxG,maxB)
Script
#Imagesource("GreenChurch.png",end=0)
Imagesource("Puppy.png",end=0)
#Imagesource("lennaRed.png",end=0)
#Avisource("1937 Lund Utah 16mm Film [Low, 360p].mp4.avi")
#Avisource("1941 Flint Michigan Parade [Low, 360p].mp4.AVI")
ConvertToRGB24
ORG=Last
LockChan = 1 # Chan for lock to Ave, 0=R, 1=G, 2=B
# -1 = Use LockVal below.
# -2 = LockVal=(RedAve+GrnAve+BluAve)/3.0 for LockVal.
# -3 = LockVal=Median(RedAve,GrnAve,BluAve)
LockVal = 128 # Only valid if LockChan == -1
RedMul = 1.0 # Required Ave multiplier for Red Channel, applied when requesting GuessGamma(reqAve*RedMul), Even applied when LockChan=-1.
GrnMul = 1.0 # Same for Green channel. GrnMul even applies when LockChan is Green Channel, etc for chans.
BluMul = 1.0 # Same for Blue channel. Allows tinkering/fine tuning.
Show = true # Subtitles
th = 0.0
A=GamMac(LockChan=LockChan,LockVal=LockVal,RedMul=RedMul,GrnMul=GrnMul,BluMul=BluMul,Show=Show,Verbosity=1,Th=Th)
B=GamMac(LockChan=LockChan,LockVal=LockVal,RedMul=RedMul,GrnMul=GrnMul,BluMul=BluMul,Show=Show,Verbosity=1,th=Th,SCALE=True)
LoHiLockC=False
C=GamMac(LockChan=LockChan,LockVal=LockVal,RedMul=RedMul,GrnMul=GrnMul,BluMul=BluMul,Show=Show,Verbosity=1,th=th,LoHiLock=LoHiLockC,SCALE=True)
TOP=StackHorizontal(ORG,A)
BOT=StackHorizontal(B,C)
StackVertical(TOP,BOT)
return Last
EDIT: Below images have full precision metrics, forgot to switch that off.
https://s20.postimg.cc/fhm6o4x31/puppy104b2c_zps5vriy6nk.png (https://postimg.cc/image/y9y1rpth5/)
Here:- LINK REMOVED
Can both Fred and Yoda check it out [not sure if its worth the bother].
here main changes
PVideoFrame __stdcall GamMac::GetFrame(int n, IScriptEnvironment* env) {
n = (n<0) ? 0 : (n>= vi.num_frames) ? vi.num_frames - 1 : n;
CountRGB(n,cntR,cntG,cntB,env);
int in_minR = (loTh>=0.0) ? ChanMin(cntR,loTh) : 0;
int in_minG = (loTh>=0.0) ? ChanMin(cntG,loTh) : 0;
int in_minB = (loTh>=0.0) ? ChanMin(cntB,loTh) : 0;
int in_maxR = (hiTh>=0.0) ? ChanMax(cntR,hiTh) : 255;
int in_maxG = (hiTh>=0.0) ? ChanMax(cntG,hiTh) : 255;
int in_maxB = (hiTh>=0.0) ? ChanMax(cntB,hiTh) : 255;
int in_min = (loTh>=0.0) ? min(min(in_minR,in_minG),in_minB) : 0;
int in_max = (hiTh>=0.0) ? max(max(in_maxR,in_maxG),in_maxB) : 255;
if(loTh>=0.0 && loHiLock) in_minR=in_minG=in_minB=in_min;
if(hiTh>=0.0 && loHiLock) in_maxR=in_maxG=in_maxB=in_max;
double inR=ChanAve(cntR);
double inG=ChanAve(cntG);
double inB=ChanAve(cntB);
double in_scale = (Scale) ? 255.0 / (in_max - in_min) : 1.0;
double scaleR = inR * in_scale;
double scaleG = inG * in_scale;
double scaleB = inB * in_scale;
double lockval;
if(LockChan==0) {lockval=scaleR;}
else if(LockChan==1) {lockval=scaleG;}
else if(LockChan==2) {lockval=scaleB;}
else if(LockChan==-2) {lockval=((scaleR+scaleG+scaleB)/3.0);}
else if(LockChan==-3) {
double mx=max(max(scaleR,scaleG),scaleB);
double mn=min(min(scaleR,scaleG),scaleB);
lockval=scaleR+scaleG+scaleB-mx-mn;
} else {
lockval =LockVal;
}
bool skipR=(inR<MinLim || inR>MaxLim);
bool skipG=(inG<MinLim || inG>MaxLim);
bool skipB=(inB<MinLim || inB>MaxLim);
bool guessR=(in_minR!=0 || in_maxR!=255 || fabs(scaleR-lockval*RedMul)>=0.00001);
bool guessG=(in_minG!=0 || in_maxG!=255 || fabs(scaleG-lockval*GrnMul)>=0.00001);
bool guessB=(in_minB!=0 || in_maxB!=255 || fabs(scaleB-lockval*BluMul)>=0.00001);
double gammaR=(skipR || !guessR)?1.0:GuessGamma(in_minR,in_maxR,cntR,lockval*RedMul);
double gammaG=(skipG || !guessG)?1.0:GuessGamma(in_minG,in_maxG,cntG,lockval*GrnMul);
double gammaB=(skipB || !guessB)?1.0:GuessGamma(in_minB,in_maxB,cntB,lockval*BluMul);
SetGammaLut(in_minR,in_maxR, gammaR,lutR);
SetGammaLut(in_minG,in_maxG, gammaG,lutG);
SetGammaLut(in_minB,in_maxB, gammaB,lutB);
...
EDIT: Or instead of
double in_scale = (Scale) ? 255.0 / (in_max - in_min) : 1.0;
double scaleR = inR * in_scale;
double scaleG = inG * in_scale;
double scaleB = inB * in_scale;
should it be
double in_scale = (Scale) ? 255.0 / (in_max - in_min) : 1.0;
double scaleR = (inR - in_min) * in_scale;
double scaleG = (inG - in_min) * in_scale;
double scaleB = (inB - in_min) * in_scale;
with above mod
https://s20.postimg.cc/6b3w0urul/puppy104b2d_zpspojskifs.png (https://postimg.cc/image/4jax5y8hl/)
Without metrics
https://s20.postimg.cc/l8cd1v531/puppy104b2e_zpstnbddabv.png (https://postimg.cc/image/sbk8hhaih/)
Think that last mod was correct, updating soon. EDIT: Damn that bottom RHS one is good (Nice one Yoda :) ).
jmac698
20th July 2016, 22:27
Nice Job, S, beautiful work! Makes faded images look brand new.
p.s. Lena is here
https://www.cs.cmu.edu/~chuck/lennapg/lenna.shtml
There is a full scan of the original, yes it was reddish and the scarf looks to be blue.
StainlessS
20th July 2016, 23:02
Thanx very much JMac, but, me gots dem all 12/53 (Marilyn) up till bout 08.
GamMac() v1.04Beta3:- LINK REMOVED
Check it out.
https://s20.postimg.cc/ql17fzszh/Lolli_zps9zyhwmre.png (https://postimg.cc/image/736k01w1l/)
https://s20.postimg.cc/5bin29j0d/G1_zpsxdyimvnj.png (https://postimg.cc/image/6dstkt1tl/)
https://s20.postimg.cc/p7emht01p/G2_zps01ibj6qw.png (https://postimg.cc/image/bdq9sr7g9/)
https://s20.postimg.cc/cu1sawad9/G4_zpsobptunax.png (https://postimg.cc/image/hspapfe61/)
https://s20.postimg.cc/vaw71pqbh/G6_zps66okw48b.png (https://postimg.cc/image/eadat1da1/)
https://s20.postimg.cc/xthw2ec1p/G7_zpsehfpphci.png (https://postimg.cc/image/rsk75bpfd/)
https://s20.postimg.cc/cl47kyxkt/G8_zpseslldvzj.png (https://postimg.org/image/w2yv0wuih/)
EDIT: Non of the above have had any of the xxxMul settings applied.
All setting same as in first image metrics.
Waiting for orders Fred, change anything ? (then beta lifted)
StainlessS
21st July 2016, 01:38
GamMac() v1.04Beta4:- LINK REMOVED
Scale changed from Bool to Int.
GamMac(), [Gamma Machine] An extraordinary Idea by VideoFred (the gent from Gent). Coded by StainlessS.
Home Thread:- http://forum.doom9.org/showthread.php?p=1774281#post1774281
Idea:- http://forum.doom9.org/showthread.php?t=173683
RGB Only.
Useful to correct color cast on old 8mm films.
Alters channel pixel average to match LockChan using Gamma correction. (By default alters Red and Blue channels to match Green).
Additional tweaking via RedMul, GrnMul and BluMul.
GamMac(clip c,int "LockChan"=1,Float "LockVal"=128,
\ Float "RedMul"=1.0,Float "GrnMul"=1.0, Float "BluMul"=1.0,
\ Float "MinLim"=32.0,Float "MaxLim"=255.0-32.0,float "GamLo"=0.25,Float "GamHi"=4.0,
\ Bool "Show"=false,int "Verbosity"=1
\ Float "Th"= -1.0,Float "loTh"=Th,Float "hiTh"=Th,Bool "loHiLock"=True,
\ int "Scale"=0
\ )
LockChan Default 1. Chan for lock to Ave. (0)LockVal=RedAve, (1)LockVal=GreenAve, (2)LockVal=BlueAve
-1 = Use explicit LockVal below.
-2 = LockVal=(RedAve+GrnAve+BluAve)/3.0.
-3 = LockVal=Median(RedAve,GrnAve,BluAve)
LockVal, default 128.0. Ignored if LockChan != -1.0. 0.0 < LockVal < 255.0
RedMul, default 1.0. 0.1 <= RedMul <= 10.0. Red channel adjustment.
GrnMul, default 1.0. 0.1 <= GrnMul <= 10.0. Green channel adjustment.
BluMul, default 1.0. 0.1 <= BluMul <= 10.0. Blue channel adjustment.
Above Multipliers only shown in metrics when at least one is != 1.0.
MinLim, default 32.0. 0.0 < MinLim < 255.0 If any channel average smaller than this, then no effect on channel.
MaxLim, default 255.0-32.0. MinLim < MaxLim < 255.0 If any channel average greater than this, then no effect on channel.
GamLo, default 0.25. 0.1 <= GamLo <= 10.0. Lower value for guess gamma (starting guess range and limit)
GamHi, default 4.0. GamLo < GamHi <= 10.0. Upper value for guess gamma (starting guess range and limit)
Show, default false. True, show info.
Verbosity, default 1. 0=Only Upper metrics, 1(default)=Upper + important ones. 2=Full metrics.
Th, Default -1.0(off) -1.0, or 0.0 -> 2.0. Sets Default for loTh and hiTh. Suggest about 0.0, or 0.1(percent).
loTh, Default Th. -1.0, or 0.0 -> 2.0. as for Ignore_low in AutoLevels, or Threshold in YPlaneMin.
hiTh, Default Th. -1.0, or 0.0 -> 2.0. as for Ignore_high in AutoLevels, or Threshold in YPlaneMax.
Percent, amount of extreme pixels (eg noise) to ignore when finding minimum and maximum R, G or B channel values.
-1.0 is OFF, input channel minimum is set to 0 and maximum set to 255.0, as in levels(0,gamma,255, ... ).
If loTh set to eg 0.0, then will scan frame looking for minimum accumulated channel values that have more than 0.0%
of pixels, and set input_min for that channel to that value. (Accumulated:- including values that were lower but not
of great enough number to break the threshold).
If hiTh set to eg 0.0, then will scan frame looking for maximum accumulated channel values that have more than 0.0%
of pixels, and set input_max for that channel to that value.
loTh and hiTh, only shown in metrics if greater or equal to 0.0 ie switched ON.
loHiLock, Default True. If (loHiLock==true) then input_lowR = min(rmin,gmin,bmin) ELSE input_lowR = rmin
If (loHiLock==true) then input_highR = max(rmax,gmax,bmax) ELSE input_highR = rmax
Where for Red, sort of equivalent to outR=LevelsR(input_lowR,gamma,input_highR, 0,255)
Same for other channels.
Scale, default 0. Range 0 -> 2. No Effect unless Scale > 0 and loTh and/or hiTh >= 0.0.
0) No Effect.
1) Scales input channel average maximum dynamic range of R,G,B, 0.0 -> 255.0
where,
in_min = min(minR,minG,minB) and in_max = max(maxR,maxG,maxB)
inR = R channel Average, inG = G channel Average, inB = B channel Average.
in_scale = 255.0 / (in_max - in_min)
scaleR = min(max((inR - in_min) * in_scale,0.0),255.0)
scaleG = min(max((inG - in_min) * in_scale,0.0),255.0)
scaleB = min(max((inB - in_min) * in_scale,0.0),255.0)
2) Scales input channel average dynamic range of R and G and B, Individually, 0.0 -> 255.0
in_scaleR = 255.0 / (in_maxR - in_minR)
in_scaleG = 255.0 / (in_maxG - in_minG)
in_scaleB = 255.0 / (in_maxB - in_minB)
scaleR = min(max((inR - in_minR) * in_scaleR,0.0),255.0)
scaleG = min(max((inG - in_minG) * in_scaleG,0.0),255.0)
scaleB = min(max((inB - in_minB) * in_scaleB,0.0),255.0)
test
#Imagesource("GreenChurch.png",end=0)
Imagesource("Puppy.png",end=0)
#Imagesource("lennaRed.png",end=0)
#Imagesource("G1.BMP",end=0) crop(0,0,0,-48) Spline36Resize(480,360)
ConvertToRGB24
ORG=Last
LockChan = 1 # Chan for lock to Ave, 0=R, 1=G, 2=B
# -1 = Use LockVal below.
# -2 = LockVal=(RedAve+GrnAve+BluAve)/3.0 for LockVal.
# -3 = LockVal=Median(RedAve,GrnAve,BluAve)
LockVal = 128 # Only valid if LockChan == -1
RedMul = 1.0 # Required Ave multiplier for Red Channel, applied when requesting GuessGamma(reqAve*RedMul), Even applied when LockChan=-1.
GrnMul = 1.0 # Same for Green channel. GrnMul even applies when LockChan is Green Channel, etc for chans.
BluMul = 1.0 # Same for Blue channel. Allows tinkering/fine tuning.
Show = true # Subtitles
th = 0.0
LoHiLockC=True Scale=0
A=GamMac(LockChan=LockChan,LockVal=LockVal,RedMul=RedMul,GrnMul=GrnMul,BluMul=BluMul,Show=Show,Verbosity=1,Th=Th,SCALE=SCALE)
LoHiLockC=False Scale=1
B=GamMac(LockChan=LockChan,LockVal=LockVal,RedMul=RedMul,GrnMul=GrnMul,BluMul=BluMul,Show=Show,Verbosity=1,th=th,LoHiLock=LoHiLockC,SCALE=Scale)
LoHiLockC=False Scale=2
C=GamMac(LockChan=LockChan,LockVal=LockVal,RedMul=RedMul,GrnMul=GrnMul,BluMul=BluMul,Show=Show,Verbosity=1,th=th,LoHiLock=LoHiLockC,SCALE=Scale)
TOP=StackHorizontal(ORG,A)
BOT=StackHorizontal(B,C)
StackVertical(TOP,BOT)
return Last
https://s20.postimg.cc/ucftzfczh/Pup_A_zps3qz6vncg.png (https://postimg.cc/image/inbubgm0p/)
Show=False
https://s20.postimg.cc/x7sx6agzh/Pup_B_zpsujd5pdki.png (https://postimg.cc/image/nahwd89dl/)
Bot RHS is new Scale=2 (prev Bot RHS puppy now on BOT LHS).
EDIT: I can probably move LoHiLock functionality into Scale, once I figure out how they 'interfere/interact' with each other.
tormento
21st July 2016, 11:20
I have some underwater diving photo, with red channel almost dead.
Is there any way to apply the script to images?
StainlessS
21st July 2016, 13:53
Not being magic, I do not know.
Have you tried it ?
EDIT:
Dont know much about the underwater thing, but think much of the red part of spectrum is absorbed by the water,
and weird things happen due to distance, the further away things would be further affected by red absorption
of the water between observer and the viewed object. There probably is no magic bullet due to the distance
from viewer thing, I guess all you can really do is try to correct for the object of main concern.
Here, just a quick knock up
Imagesource("Fish.BMP",end=0) Spline36Resize(480,360)
ConvertToRGB24
ORG=Last
LockChan = 1 # Chan for lock to Ave, 0=R, 1=G, 2=B
# -1 = Use LockVal below.
# -2 = LockVal=(RedAve+GrnAve+BluAve)/3.0 for LockVal.
# -3 = LockVal=Median(RedAve,GrnAve,BluAve)
LockVal = 128 # Only valid if LockChan == -1
RedMul = 1.0 # Required Ave multiplier for Red Channel, applied when requesting GuessGamma(reqAve*RedMul), Even applied when LockChan=-1.
GrnMul = 1.0 # Same for Green channel. GrnMul even applies when LockChan is Green Channel, etc for chans.
BluMul = 1.0 # Same for Blue channel. Allows tinkering/fine tuning.
Show = false # Subtitles
th = 0.0
LoHiLock=True Scale=0
A=GamMac(LockChan=LockChan,LockVal=LockVal,RedMul=RedMul,GrnMul=GrnMul,BluMul=BluMul,Show=Show,Verbosity=1,Th=Th,LoHiLock=LoHiLock,SCALE=SCALE)
RedMul = 0.87
LoHiLock=false
Scale=1
B=GamMac(LockChan=LockChan,LockVal=LockVal,RedMul=RedMul,GrnMul=GrnMul,BluMul=BluMul,Show=Show,Verbosity=1,th=th,LoHiLock=LoHiLock,SCALE=Scale)
Scale=2
C=GamMac(LockChan=LockChan,LockVal=LockVal,RedMul=RedMul,GrnMul=GrnMul,BluMul=BluMul,Show=Show,Verbosity=1,th=th,LoHiLock=LoHiLock,SCALE=Scale)
TOP=StackHorizontal(ORG,A)
BOT=StackHorizontal(B,C)
StackVertical(TOP,BOT)
return Last
https://s20.postimg.cc/z0vtum265/Fish_1_zpsykxzqtsi.png (https://postimg.cc/image/etie2b4op/)
https://s20.postimg.cc/o2kkcfdkt/Fish_2_zpsypemjnj9.png (https://postimg.cc/image/wxlemy2d5/)
Also does not help if you got no idea what something is supposed to look like.
Here, same pic modded via something else:- http://forum.doom9.org/showthread.php?p=1726798#post1726798
EDIT: Some more stuff here:- http://forum.doom9.org/showthread.php?t=156774
EDIT: On above pic, LoHiLock would have no effect dues to all min being 0, and all max being 255.
Also, scale 2 and 3 should produce same I think (for same reason, bottom two pics are therefore probably identical,
maybe try adjust eg bluMul a little for one of them).
shekh
21st July 2016, 15:55
I made "6-axis color" for underwater thing. Not sure if it is useful with avisynth environment.
https://gfycat.com/PaleShorttermBelugawhale
StainlessS
21st July 2016, 23:00
Shekh, that dont look anything like any beluga whale to me (dont they normally look like a dolphin wearing a crash helmet ?)
https://www.google.com/search?q=beluga+whale&biw=1280&bih=839&tbm=isch&tbo=u&source=univ&sa=X&sqi=2&ved=0ahUKEwjO6MbJxoXOAhWmDcAKHcJ8BuIQiR4IiAE&dpr=1
StainlessS
21st July 2016, 23:52
tormento,
It is possible that MinLim, or MaxLim is preventing any changes on a channel.
Try something like
MinLim=0.01
MaxLim=254.99
to disable them. Is intended to prevent attempts to modify eg black or white frames.
I'll see if I can implement some kind of indicator when channel mods are disabled due to MinLim/MaxLim.
If channel mods are disabled, then will probably see Gamma=1.0 for that channel.
videoFred
22nd July 2016, 09:20
Waiting for orders Fred, change anything ? (then beta lifted)
Sorry for the delay, I was away for a few days. Tomorrow I have time to do some testing!
Fred.
tormento
22nd July 2016, 14:47
Ok... Thanks! Will try in the next days!
videoFred
25th July 2016, 09:50
First impression GamMac() v1.04Beta4 : very very good :)
A few remarks: on complete black frames, GamMac() has the same behaviour as Autolevels(). To much correction. But I use the same trick as I did with Autolevels: adding a small 4 pixels white border on the left side of the frame, then apply GamMac(), then remove the border. Examples will follow, but I have to time right now.
Sometimes on old 8mm film there is emulsion damage. This damage can have any color. Often red or green. A green spot for example (even a small one) can mess up the GamMac() results. I assume because these spots are very bright and they are changing average lume from the green channel. This can be solved by using RemoveDirt() before GamMac(). RemoveDirt() can deal very well with these spots because they are always changing from frame to frame.
Resumed: a very good (imho the best) filter for those who are working with digitized film files (8mm, 16mm or whatever format)
It might be useful for other sources too, to fix color cast etc.. but I leave this for others to test.
A happy Fred() . :)
StainlessS
25th July 2016, 13:40
GamMac() v1.05Beta1:- LINK REMOVED
GamMac(), [Gamma Machine] An extraordinary Idea by VideoFred (the gent from Gent). Coded by StainlessS.
Home Thread:- http://forum.doom9.org/showthread.php?p=1774281#post1774281
Idea:- http://forum.doom9.org/showthread.php?t=173683
RGB Only.
Useful to correct color cast on old 8mm films.
Alters channel pixel average to match LockChan using Gamma correction. (By default alters Red and Blue channels to match Green).
Additional tweaking via RedMul, GrnMul and BluMul multipliers.
What it does(roughly):-
Gets Channel averages, minimums, and maximums (using loTh for minumums and hiTh for maximums).
if(Scale > 0 and loTh>=0.0 and hiTh>=0.0) then rescale averages using dynamic range of r,g,b [0.0 -> DynamicRange(R,G,B)]
For each channel, estimate gamma function that will remap (scaled channel average * channel multiplier) to match a particular
LockVal (chosen via LockChan). Render frame using the output averages from estimated gamma.
GamMac(clip c,int "LockChan"=1,Float "LockVal"=128,
\ Float "RedMul"=1.0,Float "GrnMul"=1.0, Float "BluMul"=1.0,
\ Float "MinLim"=10.0,Float "MaxLim"=245.0,float "GamLo"=0.1,Float "GamHi"=10.0,
\ Bool "Show"=false,int "Verbosity"=1
\ Float "Th"= -1.0,Float "loTh"=Th,Float "hiTh"=Th,
\ int "Scale"=0,
\ int "x"=0,int "y"=0,int "w"=0,int "h"=0
\ )
LockChan Default 1(Grn). Channel for lock to Average. [range -3 -> 2]
0 ] LockVal = Scaled(RedAve)
1 ] LockVal = Scaled(GreenAve)
2 ] LockVal = Scaled(BlueAve)
-1] LockVal = Use explicit LockVal arg (see below).
-2] LockVal = (Scaled(RedAve)+Scaled(GrnAve)+Scaled(BluAve))/3.0.
-3] LockVal = Median(Scaled(RedAve),Scaled(GrnAve),Scaled(BluAve))
Where Scaled(Channel Average) depends upon Scale, and loTh, and hiTh.
LockVal, default 128.0 Only used if LockChan = -1.0. [0.0 < LockVal < 255.0] (set via LockChan if LockChan != -1)
RedMul, default 1.0 Red channel multiplier adjustment. [0.1 <= RedMul <= 10.0]
GrnMul, default 1.0 Green channel multiplier adjustment. [0.1 <= GrnMul <= 10.0]
BluMul, default 1.0 Blue channel multiplier adjustment. [0.1 <= BluMul <= 10.0]
Scaled averages are multiplied by their multiplier then given as args to the gamma estimator.
Allow tweaking of R,G,B channels.
Above Multipliers only shown in metrics when at least one is != 1.0 (Always shown when Verbosity=3=FULL).
MinLim, default 10.0 If any input channel average smaller than this, then no effect on that channel. [0.0 <= MinLim <= 64.0]
MaxLim, default 245.0 If any input channel average greater than this, then no effect on that channel. [191.0 <= MaxLim <= 255.0]
Allows to skip remapping of a channel where input channel average (un-scaled) is above or below these limits.
GamLo, default 0.1 Lower value for guess gamma [0.1 <= GamLo < GamHi]
GamHi, default 10.0 Upper value for guess gamma [GamLo < GamHi <= 10.0]
Starting guess range and limits for gamma estimator (probably best left alone).
Show, default false True, show metrics info on frame.
Verbosity, default 1 0 = Only upper frame metrics
1 = Upper + important ones. (default)
2 = Nearly Full metrics.
3 = Full Metrics
Upper frame metrics shown as eg:- (when Verbosity=3=FULL)
nnnnn] Flags:- 1SL
R G B
IN: 10,253 10,253 10,253
IN_AVE: 78.466 88.552 78.767
SCALED: 71.847 82.431 72.162
GAMMA: 1.135 1.000 1.123
OUTAVE: 82.431 82.422 82.451
where,
nnnnn, is the frame number.
Flags:- (Specific to current frame, can change frame to frame)
'1' = LockChan, as above, channel '1'[ScaleAveG].
Can be, '0', '1', '2' [ScaleAve Channel number LockChan=-3(median) assigns '0', '1' or '2' as appropriate]
'A'[LockChan=-2, (ScaleAveR+ScaleAveG+ScaleAveB)/3.0]
'V'[LockChan=-1, Explicit LockVal]
'S' = Scale, mode signfied by color.
Greyed out. Scale = 0(No Effect). May be Greyed out if all channels Min/Max are 0,255.
White. Scale = 1[Scales input channel average maximum dynamic range of R,G,B]
Orange. Scale = 2[Scales input channel average dynamic range of R and G and B, Individually]
'L' = Limited by MinLim or MaxLim, mode signfied by color.
Greyed out. Not Limited
Red, at least 1 channel has remapping disabled.
IN: Shows comma separated channel minimum and maximum (dependent upon loTh, hiTh).
IN_AVE: Input channel averages.
SCALED: Scaled input averages, (dependent upon Scale, loTh, hiTh, channel minumums and maximums).
GAMMA: Estimated gamma to achieve lockval for channel. (dependent upon pretty much everything).
OUTAVE: Output channel average ie rendered result.
Th, Default -1.0(off) Sets Default for loTh and hiTh. Suggest about 0.0(percent). [-1.0, or 0.0 -> 2.0]
loTh, Default Th As for Ignore_low in AutoLevels, or Threshold in YPlaneMin. [-1.0, or 0.0 -> 2.0]
Percent, amount of extreme pixels (eg noise) to ignore when finding minimum R, G or B channel values.
-1.0 is OFF, input channel minimum is set to 0 as for levels(0,gamma,input_max, ... ).
If loTh >=0.0, then will scan frame looking for lowest pixel value whose cumlative sum
[including all pixels counts of lower value pixels] is greater than loTh%.
loTh, only shown in metrics if greater or equal to 0.0 ie switched ON (Always shown when Verbosity=3=FULL).
hiTh, Default Th As for Ignore_high in AutoLevels, or Threshold in YPlaneMax. [-1.0, or 0.0 -> 2.0]
Percent, amount of extreme pixels (eg noise) to ignore when finding maximum R, G or B channel values.
-1.0 is OFF, input channel maximum set to 255, as in levels(input_min,gamma,255, ... ).
If hiTh >=0.0, then will scan frame looking for highest pixel value whose cumlative sum
[including all pixels counts of higher value pixels] is greater than hiTh%.
hiTh, only shown in metrics if greater or equal to 0.0 ie switched ON (Always shown when Verbosity=3=FULL).
Scale, default 0 Range 0 -> 2. No Effect unless Scale > 0 and loTh and/or hiTh >= 0.0.
where described for Red Channel only:-
RedMin = Red_Channel_Minimum(ignorePerc=loTh) # Pixel minimum for red channel, ignoring up to loTh%, ie noise.
RedMax = Red_Channel_Maximum(ignorePerc=hiTh) # Pixel maximum for red channel, ignoring up to hiTh%, ie noise.
RedAve = Red_Channel_Average() # Pixel average for red Channel.
0 (Scale==0 || (loTh==-1.0 && hiTh==-1.0)) No Effect.
in_min = RedMin = GrnMin = BluMin = 0
in_max = RedMax = GrnMax = BluMax = 255
scaledAveR = RedAve
scaledAveG = GrnAve
scaledAveB = BluAve
1) Scales input channel average maximum dynamic range of R,G,B, to 0.0->(ChanAve-in_min)*255.0/(in_max-in_min+(in_max==in_min))
in_min = min(RedMin,GrnMin,BluMin)
in_max = max(RedMax,GrnMax,BluMax)
in_Rng = in_max - in_min
scaler = (in_Rng==0) ? 255.0 : 255.0 / (in_max - in_min+(in_max==in_min))
scaledAveR = min(max((RedAve - in_min) * scaler,0.0),255.0)
scaledAveG = min(max((GrnAve - in_min) * scaler,0.0),255.0)
scaledAveB = min(max((BluAve - in_min) * scaler,0.0),255.0)
2) Scales input channel average dynamic range of R & G & B, Individually, to 0.0->(ChanAve-Chan_min)*255.0/(ChanMax-ChanMin)
in_RngR = RedMax - RedMin
in_RngG = GrnMax - GrnMin
in_RngB = BluMax - BluMin
scalerR = (In_RngR==0) ? 255.0 : 255.0 / (RedMax-RedMin+(RedMax==RedMin))
scalerG = (In_RngG==0) ? 255.0 : 255.0 / (GrnMax-GrnMin+(GrnMax==GrnMin))
scalerB = (In_RngB==0) ? 255.0 : 255.0 / (BluMax-BluMin+(BluMax==BluMin))
scaledAveR = min(max((RedAve - RedMin) * scalerR,0.0),255.0)
scaledAveG = min(max((GrnAve - GrnMin) * scalerG,0.0),255.0)
scaledAveB = min(max((BluAve - BluMid) * scalerB,0.0),255.0)
x,y,w,h. All Default 0. Area of frame to sample when getting averages and estimating Gamma function, allows to ignore rubbish at frame edges.
Specified as for crop ie x=10,y=20,w=-30,h=-40, as in crop(10,20,-30,-40).
Fred, I am aware of and working on Black Frame/single color frame, problem, especially tricky if single value channel that is also lock channel.
Anyway, above most recent working version without diagnostic stuff.
https://s20.postimg.cc/ejfgwpfgd/105_B1_zpslfgxddri.png (https://postimg.cc/image/bpcbj9da1/)
EDIT: Above image (Verbosity=3 Full metrics), LockChan= -3 (Median), and in above instance red channel is the median channel and so shown in Flags as '0' red channel
for the current frame, 'S' and 'L' flags are both 'Greyed Out').
EDIT: I have to admit to a little puzzlement as to why above 'S' flag is Greyed Out when we are using Scale=1.
Well, as all channel minimums are 0, and all channel maximums are 255, there is no Scaling for this frame.
(I forgot how it works :), guess I'll havta put that in the doc. )
StainlessS
28th July 2016, 22:38
Yo Fred, here v1.06Beta1,:- LINK REMOVED
Have rearranged args to more sensible order, renamed or changed args (was necessary) and changed defaults in some cases.
If you have any problems with changes then say (although functionality may suffer if having to put back as was).
here update doc.
GamMac(), [Gamma Machine] An extraordinary Idea by VideoFred (the gent from Gent). Coded by StainlessS.
Home Thread:- http://forum.doom9.org/showthread.php?p=1774281#post1774281
Idea:- http://forum.doom9.org/showthread.php?t=173683
RGB Only.
Useful to correct color cast on old 8mm films.
Alters channel pixel average to match LockChan using Gamma correction. (By default alters Red and Blue channels to match Green).
Additional tweaking via RedMul, GrnMul and BluMul multipliers.
What it does(roughly):-
Gets Channel averages, minimums, and maximums (using loTh for minumums and hiTh for maximums).
if(Scale > 0 and loTh>=0.0 and hiTh>=0.0) then rescale averages using dynamic range of r,g,b [0.0 -> DynamicRange(R,G,B)]
For each channel, estimate gamma function that will remap (scaled channel average * channel multiplier) to match a particular
LockVal (chosen via LockChan). Render frame using the output averages from estimated gamma.
GamMac(clip c,int "LockChan"=1,int "Scale"=0,
\ Float "RedMul"=1.0,Float "GrnMul"=1.0, Float "BluMul"=1.0,
\ Float "Th"= 0.0,Float "loTh"=Th,Float "hiTh"=Th,
\ Float "LockVal"=128.0,Float "RngLim"=10.0,Float "GamMax"=10.0,
\ int "x"=0,int "y"=0,int "w"=0,int "h"=0,
\ Bool "Show"=false,int "Verbosity"=1
\ )
LockChan Default 1(Grn). Channel for lock to Average. [range -3 -> 2]
0 ] LockVal = Scaled(RedAve)
1 ] LockVal = Scaled(GreenAve)
2 ] LockVal = Scaled(BlueAve)
-1] LockVal = Use explicit LockVal arg (see below).
-2] LockVal = (Scaled(RedAve)+Scaled(GrnAve)+Scaled(BluAve))/3.0.
-3] LockVal = Median(Scaled(RedAve),Scaled(GrnAve),Scaled(BluAve))
Where Scaled(Channel Average) depends upon Scale, and loTh, and hiTh.
Scale, default 0 Range 0 -> 2. No Effect unless Scale > 0 and loTh and/or hiTh >= 0.0.
where described for Red Channel only:-
RedMin = Red_Channel_Minimum(ignorePerc=loTh) # Pixel minimum for red channel, ignoring up to loTh%, ie noise.
RedMax = Red_Channel_Maximum(ignorePerc=hiTh) # Pixel maximum for red channel, ignoring up to hiTh%, ie noise.
RedAve = Red_Channel_Average() # Pixel average for red Channel.
0 (Scale==0 || (loTh==-1.0 && hiTh==-1.0)) No Effect.
in_min = RedMin = GrnMin = BluMin = 0
in_max = RedMax = GrnMax = BluMax = 255
scaledAveR = RedAve
scaledAveG = GrnAve
scaledAveB = BluAve
1) Scales input channel average maximum dynamic range of R,G,B, to 0.0->(ChanAve-in_min)*255.0/(in_max-in_min+(in_max==in_min))
in_min = min(RedMin,GrnMin,BluMin)
in_max = max(RedMax,GrnMax,BluMax)
in_Rng = in_max - in_min
scaler = (in_Rng==0) ? 255.0 : 255.0 / (in_max - in_min)
scaledAveR = min(max((RedAve - in_min) * scaler,0.0),255.0)
scaledAveG = min(max((GrnAve - in_min) * scaler,0.0),255.0)
scaledAveB = min(max((BluAve - in_min) * scaler,0.0),255.0)
2) Scales input channel average dynamic range of R & G & B, Individually, to 0.0->(ChanAve-Chan_min)*255.0/(ChanMax-ChanMin)
in_RngR = RedMax - RedMin
in_RngG = GrnMax - GrnMin
in_RngB = BluMax - BluMin
scalerR = (In_RngR==0) ? 255.0 : 255.0 / (RedMax-RedMin)
scalerG = (In_RngG==0) ? 255.0 : 255.0 / (GrnMax-GrnMin)
scalerB = (In_RngB==0) ? 255.0 : 255.0 / (BluMax-BluMin)
scaledAveR = min(max((RedAve - RedMin) * scalerR,0.0),255.0)
scaledAveG = min(max((GrnAve - GrnMin) * scalerG,0.0),255.0)
scaledAveB = min(max((BluAve - BluMid) * scalerB,0.0),255.0)
RedMul, default 1.0 Red channel multiplier adjustment. [0.1 <= RedMul <= 10.0]
GrnMul, default 1.0 Green channel multiplier adjustment. [0.1 <= GrnMul <= 10.0]
BluMul, default 1.0 Blue channel multiplier adjustment. [0.1 <= BluMul <= 10.0]
Scaled averages are multiplied by their multiplier then given as args to the gamma estimator.
Allow tweaking of R,G,B channels.
Above Multipliers only shown in metrics when at least one is != 1.0 (Always shown when Verbosity=3=FULL).
Th, Default 0.0 Sets Default for loTh and hiTh. Suggest Default, 0.0(percent). [-1.0(OFF) , or 0.0 -> 2.0]
loTh, Default Th As for Ignore_low in AutoLevels, or Threshold in YPlaneMin. [-1.0, or 0.0 -> 2.0]
Percent, amount of extreme pixels (eg noise) to ignore when finding minimum R, G or B channel values.
-1.0 is OFF, input channel minimum is set to 0 as for levels(0,gamma,input_max, ... ).
If loTh >=0.0, then will scan frame looking for lowest pixel value whose cumlative sum
[including all pixels counts of lower value pixels] is greater than loTh%.
loTh, only shown in metrics if greater or equal to 0.0 ie switched ON (Always shown when Verbosity=3=FULL).
hiTh, Default Th As for Ignore_high in AutoLevels, or Threshold in YPlaneMax. [-1.0, or 0.0 -> 2.0]
Percent, amount of extreme pixels (eg noise) to ignore when finding maximum R, G or B channel values.
-1.0 is OFF, input channel maximum set to 255, as in levels(input_min,gamma,255, ... ).
If hiTh >=0.0, then will scan frame looking for highest pixel value whose cumlative sum
[including all pixels counts of higher value pixels] is greater than hiTh%.
hiTh, only shown in metrics if greater or equal to 0.0 ie switched ON (Always shown when Verbosity=3=FULL).
LockVal, default 128.0 Only used if LockChan = -1.0. [0.0 < LockVal < 255.0] (set via LockChan if LockChan != -1)
There is no restricted range on this (other than 0.0 < LockVal < 255.0), so if you set a stupid value,
you will likely get stupid results.
RngLim, default 10.0 If any input channel average is nearer than this to either channel minimum or channel maximum, then no effect on that channel.
[4.0 <= RngLim <= 32.0]
Allows to skip remapping of a channel where input channel average (un-scaled) is too close to either channel
minimum or maximum, ie avoid remapping of Black, White frames, or single color frames.
GamMax, default 10.0 Upper value for guess gamma [2.0 <= GamMax <= 10.0]
Starting guess upper range and limit for gamma estimator (probably best left alone).
The lower guess range and limit will be set to 1.0 / GamMax, by default 0.1.
x,y,w,h. All Default 0. Area of frame to sample when getting averages and estimating Gamma function, allows to ignore rubbish at frame edges.
Specified as for crop ie x=10,y=20,w=-30,h=-40, as in crop(10,20,-30,-40).
Show, default false True, show metrics info on frame.
Verbosity, default 1 0 = Only upper frame metrics
1 = Upper + important ones. (default)
2 = Nearly Full metrics.
3 = Full Metrics
Upper frame metrics shown as eg:- (when Verbosity=3=FULL)
nnnnn] Flags:- 1SR
R G B
IN: 10,253 10,253 10,253
IN_AVE: 78.466 88.552 78.767
SCALED: 71.847 82.431 72.162
GAMMA: 1.135 1.000 1.123
OUTAVE: 82.431 82.422 82.451
where,
nnnnn, is the frame number.
Flags:- (Specific to current frame, can change frame to frame)
'1' = LockChan, as above, channel '1'[ScaleAveG].
Can be, '0', '1', '2' [ScaleAve Channel number LockChan=-3(median) assigns '0', '1' or '2' as appropriate]
'A'[LockChan=-2, (ScaleAveR+ScaleAveG+ScaleAveB)/3.0]
'V'[LockChan=-1, Explicit LockVal]
'S' = Scale, mode signfied by color.
Greyed out. Scale = 0(No Effect).May be Greyed out if all channels Min/Max are 0,255.
White. Scale = 1[Scales input channel average maximum dynamic range of R,G,B]
Orange. Scale = 2[Scales input channel average dynamic range of R and G and B, Individually]
'R' = Limited by RngLim, mode signfied by color.
Greyed out. Not Range Limited.
Red, at least 1 channel has remapping disabled.
IN: Shows comma separated channel minimum and maximum (dependent upon Scale, loTh, hiTh).
IN_AVE: Input channel averages.
SCALED: Scaled input averages, (dependent upon Scale, loTh, hiTh, channel minumums and maximums).
GAMMA: Estimated gamma to achieve lockval for channel. (dependent upon pretty much everything).
OUTAVE: Output channel average ie rendered result.
Check it out with black / white / and single color frames (should leave without alteration).
Report any problems you may encounter. Thanx. :)
EDIT: Fred, here frame given random color ($204080),
https://s20.postimg.cc/tgnxxpsot/Blue_zpswxafoxan.png (https://postimg.cc/image/xd19tpdo9/)
Scale = 1, alters the frame but only non RngLim-ited channel, I could make it disable all channel alterations where a
single channel is RngLim-ited.
EDIT: Maybe I should disable all channel mods when RngLim triggered for Scale==0 and Scale==1, and only disable for
channels that trigger RngLim when Scale==2.
EDIT: Supposed Beluga Whale, with not much info in red channel.
https://s20.postimg.cc/qnuqdoscd/Beluga_zpsjchz2yqh.png (https://postimg.cc/image/ow1ris8zd/)
Scale=1 is same as Scale=0, due to combined R,G,B dynamic range being 0->255 (R min=0, G max=255),
whereas Scale=2 scales channels individually.
EDIT: Fred, I feel like the last Dalek in Dr Who, S01E06 (Eccelston), "where shall I get my orders now",
give me some orders now, what do you want ?
shekh
28th July 2016, 23:15
Supposed Beluga Whale
Joke? gfy gives random stupid names to uploads, it is just a coincidence to get whale or whatever :)
videoFred
29th July 2016, 09:23
Fred, I feel like the last Dalek in Dr Who, S01E06 (Eccelston), "where shall I get my orders now",
give me some orders now, what do you want ?
:) Haha Doktorrrrr it already does much more than I ever wanted.
Going to test v1.06Beta1 and report back here. Please give me a few days for this because I'm testing it on all kinds of scenes: over exposed, under exposed, blue cast, green cast etc... etc...
Fred.
StainlessS
29th July 2016, 13:59
Fred, I've had an idea to check for single color frame at beginning of CPP GetFrame(), and if single color then do no further scaling etc,
just show on upper metrics, maybe the input min and max and also averages, and flag to show single color 'No action', this would
make things much easier (this plugin is doin' my head in, too many alternative ways to do things, and each of the -ve LockChans
complicate and make it necessary to backtrack and undo metrics, would have been a lot simpler without the belated add-ons).
I'll knock up a quick function to demo single color frame detection for anybody to play with.
Probably will not update GamMac today.
StainlessS
29th July 2016, 16:15
Here first version using channel min, max and Average, not so successful as I had hoped.
Function IsSingleColorFrame(clip c,Int n,Float "Tol",Float "Th",String "Matrix",Int "X",Int "Y",Int"W",Int"H",Bool "Debug") {
# n = Frame Number, eg call with current_frame from ScriptClip (Best if RGB already)
c
myName="IsSingleColorFrame: "
Tol=Default(Tol,2.5) # Suggest about 4.0 to 8.0
Th=Default(Th,0.4) # Ingnore up to about 1 pixel in every 250 (noise), suggest 0.4.
Matrix=Default(Matrix,(Width>=1100||Height>=600)?"Rec709":"Rec601") # ConvertToRGB24
(!IsRGB)?ConvertToRGB24(Matrix=Matrix):NOP
Chan=-1 # R, and G, and B.
Flgs=$13 # RT_RgbChanMin, RT_RgbChanMax, RT_RgbChanAve.
Prefix="ISCF_" # Returned local vars name prefix.
RT_RgbChanStats(n,x=X,y=Y,W=W,h=H,threshold=Th,chan=Chan,flgs=Flgs,prefix=Prefix) # Simultaneous stats.
Result= (
\ (ISCF_Ave_0-ISCF_Min_0<=Tol || ISCF_Max_0-ISCF_Ave_0<=Tol) &&
\ (ISCF_Ave_1-ISCF_Min_1<=Tol || ISCF_Max_1-ISCF_Ave_1<=Tol) &&
\ (ISCF_Ave_2-ISCF_Min_2<=Tol || ISCF_Max_2-ISCF_Ave_2<=Tol)
\ )
(Debug)
\ ? RT_DebugF("RMin=%d RMax=%d RAve=%.3f : GMin=%d GMax=%d GAve=%.3f : BMin=%d BMax=%d BAve=%.3f : Result=%s",
\ ISCF_Min_0,ISCF_Max_0,ISCF_Ave_0,
\ ISCF_Min_1,ISCF_Max_1,ISCF_Ave_1,
\ ISCF_Min_2,ISCF_Max_2,ISCF_Ave_2,
\ Result,name=myName)
\ : NOP
Return Result
}
AviSource("D:\V\StarWars.avi") ConvertToRGB24
DEBUG=TRUE
INDICATOR=32
SSS="""
n=current_frame
T=IsSingleColorFrame(n,h=-INDICATOR,Debug=DEBUG)
(T)?crop(0,0,0,-INDICATOR):NOP
(T)?AddBorders(0,0,0,INDICATOR,$FF0055):NOP
return Last
"""
AddBorders(0,0,0,INDICATOR,$000000)
ScriptClip(SSS)
And one just using channel MinMaxDifference
Function IsSingleColorFrame(clip c,Int n,Float "Tol",Float "Th",String "Matrix",Int "X",Int "Y",Int"W",Int"H",Bool "Debug") {
# n = Frame Number, eg call with current_frame from ScriptClip (Best if RGB already)
c
myName="IsSingleColorFrame: "
Tol=Default(Tol,2.0) # Suggest about 4.0 to 8.0
Th=Default(Th,0.4) # Ingnore up to about 1 pixel in every 250 (noise), suggest 0.4.
Matrix=Default(Matrix,(Width>=1100||Height>=600)?"Rec709":"Rec601") # ConvertToRGB24
(!IsRGB)?ConvertToRGB24(Matrix=Matrix):NOP
Chan=-1 # R, and G, and B.
Flgs=$04 # RT_RgbChanMinMaxDifference
Prefix="ISCF_" # Returned local vars name prefix.
RT_RgbChanStats(n,x=X,y=Y,W=W,h=H,threshold=Th,chan=Chan,flgs=Flgs,prefix=Prefix) # Simultaneous stats.
Result= (
\ (ISCF_MinMaxDiff_0<=Tol) &&
\ (ISCF_MinMaxDiff_1<=Tol) &&
\ (ISCF_MinMaxDiff_2<=Tol)
\ )
(Debug)
\ ? RT_DebugF("%d %d %d : Result=%s",
\ ISCF_MinMaxDiff_0,
\ ISCF_MinMaxDiff_1,
\ ISCF_MinMaxDiff_2,
\ Result,name=myName)
\ : NOP
return Result
}
AviSource("D:\V\StarWars.avi") ConvertToRGB24
DEBUG=TRUE
INDICATOR=32
SSS="""
n=current_frame
T=IsSingleColorFrame(n,h=-INDICATOR,Debug=DEBUG)
(T)?crop(0,0,0,-INDICATOR):NOP
(T)?AddBorders(0,0,0,INDICATOR,$FF0055):NOP
return Last
"""
AddBorders(0,0,0,INDICATOR,$000000)
ScriptClip(SSS)
Will not be so noise tolerant.
Scripts show Red border at bottom of clip when single color frame detected.
We need more experimentation :(
Gotta catch my bus now.
dani75
30th July 2016, 18:30
http://studiotransfert.fr/Images/Beluga.jpg
videoFred
21st August 2016, 13:24
I have tested GamMac on all kinds of old 8mm footage by now.
My favorite fixed settings are:
----------------------------------
LockChan = 1
Verbosity = 1
Scale = 2
x=20, y=20, w=-20, h=-20 (to avoid border artefacts messing up the filter results)
These settings are variable, depending on the source:
----------------------------------------------------
LoTh: 0.04 is a good start point
HiTh : same as loTh
RedMul, GrnMul, Blumul: startvalue 1.00, then adjusting depending on the source.
I have here a Regular-8 reel from 1965. It was made in Greece and for some reason most of the colors are gone.
I assume this film was not well developed in the lab.
At the end result, the only colors left over are red and cyan.
With special thanks to Dr. Matthias Weisser and his family from Munich to make this film available for testing and publishing here.
GamMac is correcting the green cast very well, restoring true white:
http://www.super-8.be/Doom/Matt_Greece_001.jpg
A few frames further, the color cast changes suddenly to blue but the GamMac result stays the same
http://www.super-8.be/Doom/Matt_Greece_002.jpg
A few more GamMac examples:
http://www.super-8.be/Doom/Matt_Greece_004.jpg
http://www.super-8.be/Doom/Matt_Greece_005.jpg
This is my workflow: as you can see here I have changed the red and cyan hue after GamMac
http://www.super-8.be/Doom/Matt_Greece_006.jpg
Another example, only GamMac:
http://www.super-8.be/Doom/Matt_Greece_007.jpg
GamMac + color corrected:
http://www.super-8.be/Doom/Matt_Greece_008.jpg
And this last example is only GamMac:
http://www.super-8.be/Doom/Matt_Greece_009.jpg
And of cource special thanks to our friend StainlessS for making this wonderful rust proof filter. :p
Fred.
johnmeyer
21st August 2016, 18:12
Oh wow, I've got to try this filter!
I have been asked to re-transfer some early color film that may be used for broadcast, and this looks like the results are far better than I can do by hand. The ability to track color changes and make sensible adjustments is particularly intriguing. For me, color grading is the most time-consuming part of film transfer and restoration.
P.S. VideoFred, which version of the filter did you use for the tests you just posted?
videoFred
21st August 2016, 18:58
Oh wow, I've got to try this filter!
Yes, actualy I was waiting for a response from you because we are working with the same kind of films ;)
For me, color grading is the most time-consuming part of film transfer and restoration.
GamMac will take a lot of work out of your hands, believe me! Not only it corrects color cast, but also levels. But you will have to fine tune it sometimes as I explained above here.
P.S. VideoFred, which version of the filter did you use for the tests you just posted?
Version V1.06B1, it can be found here:
StainlessS@SendSpace (working link in StanlessS signature)
Fred.
johnmeyer
21st August 2016, 19:48
Thanks!!
StainlessS
3rd October 2016, 18:54
GamMac v1.06 Beta02, See MediaFire in sig below.
GamMac(), [Gamma Machine] An extraordinary Idea by VideoFred (the gent from Gent). Coded by StainlessS.
Home Thread:- http://forum.doom9.org/showthread.php?p=1774281#post1774281
Idea:- http://forum.doom9.org/showthread.php?t=173683
RGB Only.
Useful to correct color cast on old 8mm films.
Alters channel pixel average to match LockChan using Gamma correction. (By default alters Red and Blue channels to match Green).
Additional tweaking via RedMul, GrnMul and BluMul multipliers.
What it does(roughly):-
Gets Channel averages, minimums, and maximums (using loTh for minumums and hiTh for maximums).
if(Scale > 0 and loTh>=0.0 and hiTh>=0.0) then rescale averages using dynamic range of r,g,b [0.0 -> DynamicRange(R,G,B)]
For each channel, estimate gamma function that will remap (scaled channel average * channel multiplier) to match a particular
LockVal (chosen via LockChan). Render frame using the output averages from estimated gamma.
GamMac(Clip c,int "LockChan"=1,int "Scale"=2,
\ Float "RedMul"=1.0,Float "GrnMul"=1.0, Float "BluMul"=1.0,
\ Float "Th"= 0.04,Float "loTh"=Th,Float "hiTh"=Th,
\ Float "LockVal"=128.0,Float "RngLim"=10.0,Float "GamMax"=10.0,
\ Clip "dc",
\ int "x"=20,int "y"=20,int "w"=-20,int "h"=-20,
\ Bool "Show"=True,int "Verbosity"=1
\ )
LockChan Default 1(Grn). Channel for lock to Average. [range -3 -> 2]
0 ] LockVal = Scaled(RedAve)
1 ] LockVal = Scaled(GreenAve)
2 ] LockVal = Scaled(BlueAve)
-1] LockVal = Use explicit LockVal arg (see below).
-2] LockVal = (Scaled(RedAve)+Scaled(GrnAve)+Scaled(BluAve))/3.0.
-3] LockVal = Median(Scaled(RedAve),Scaled(GrnAve),Scaled(BluAve))
Where Scaled(Channel Average) depends upon Scale, and loTh, and hiTh.
Scale, default 2 Range 0 -> 2. No Effect unless Scale > 0 and loTh and/or hiTh >= 0.0.
where described for Red Channel only:-
RedMin = Red_Channel_Minimum(ignorePerc=loTh) # Pixel minimum for red channel, ignoring up to loTh%, ie noise.
RedMax = Red_Channel_Maximum(ignorePerc=hiTh) # Pixel maximum for red channel, ignoring up to hiTh%, ie noise.
RedAve = Red_Channel_Average() # Pixel average for red Channel.
0 (Scale==0 || (loTh==-1.0 && hiTh==-1.0)) No Effect.
in_min = RedMin = GrnMin = BluMin = 0
in_max = RedMax = GrnMax = BluMax = 255
scaledAveR = RedAve
scaledAveG = GrnAve
scaledAveB = BluAve
1) Scales input channel average maximum dynamic range of R,G,B, to 0.0->(ChanAve-in_min)*255.0/(in_max-in_min+(in_max==in_min))
in_min = min(RedMin,GrnMin,BluMin)
in_max = max(RedMax,GrnMax,BluMax)
in_Rng = in_max - in_min
scaler = (in_Rng==0) ? 255.0 : 255.0 / (in_max - in_min)
scaledAveR = min(max((RedAve - in_min) * scaler,0.0),255.0)
scaledAveG = min(max((GrnAve - in_min) * scaler,0.0),255.0)
scaledAveB = min(max((BluAve - in_min) * scaler,0.0),255.0)
2) Scales input channel average dynamic range of R & G & B, Individually, to 0.0->(ChanAve-Chan_min)*255.0/(ChanMax-ChanMin)
in_RngR = RedMax - RedMin
in_RngG = GrnMax - GrnMin
in_RngB = BluMax - BluMin
scalerR = (In_RngR==0) ? 255.0 : 255.0 / (RedMax-RedMin)
scalerG = (In_RngG==0) ? 255.0 : 255.0 / (GrnMax-GrnMin)
scalerB = (In_RngB==0) ? 255.0 : 255.0 / (BluMax-BluMin)
scaledAveR = min(max((RedAve - RedMin) * scalerR,0.0),255.0)
scaledAveG = min(max((GrnAve - GrnMin) * scalerG,0.0),255.0)
scaledAveB = min(max((BluAve - BluMid) * scalerB,0.0),255.0)
RedMul, default 1.0 Red channel multiplier adjustment. [0.1 <= RedMul <= 10.0]
GrnMul, default 1.0 Green channel multiplier adjustment. [0.1 <= GrnMul <= 10.0]
BluMul, default 1.0 Blue channel multiplier adjustment. [0.1 <= BluMul <= 10.0]
Scaled averages are multiplied by their multiplier then given as args to the gamma estimator.
Allow tweaking of R,G,B channels.
Above Multipliers only shown in metrics when at least one is != 1.0 (Always shown when Verbosity=3=FULL).
Th, Default 0.04 Sets Default for loTh and hiTh. Suggest Default, 0.04(percent). [-1.0(OFF) , or 0.0 -> 1.0]
loTh, Default Th As for Ignore_low in AutoLevels, or Threshold in YPlaneMin. [-1.0, or 0.0 -> 1.0]
Percent, amount of extreme pixels (eg noise) to ignore when finding minimum R, G or B channel values.
-1.0 is OFF, input channel minimum is set to 0 as for levels(0,gamma,input_max, ... ).
If loTh >=0.0, then will scan frame looking for lowest pixel value whose cumlative sum
[including all pixels counts of lower value pixels] is greater than loTh%.
loTh, only shown in metrics if greater or equal to 0.0 ie switched ON (Always shown when Verbosity=3=FULL).
hiTh, Default Th As for Ignore_high in AutoLevels, or Threshold in YPlaneMax. [-1.0, or 0.0 -> 1.0]
Percent, amount of extreme pixels (eg noise) to ignore when finding maximum R, G or B channel values.
-1.0 is OFF, input channel maximum set to 255, as in levels(input_min,gamma,255, ... ).
If hiTh >=0.0, then will scan frame looking for highest pixel value whose cumlative sum
[including all pixels counts of higher value pixels] is greater than hiTh%.
hiTh, only shown in metrics if greater or equal to 0.0 ie switched ON (Always shown when Verbosity=3=FULL).
LockVal, default 128.0 Only used if LockChan = -1.0. [0.0 < LockVal < 255.0] (set via LockChan if LockChan != -1)
There is no restricted range on this (other than 0.0 < LockVal < 255.0), so if you set a stupid value,
you will likely get stupid results.
RngLim, default 10.0 If any input channel average is nearer than this to either channel minimum or channel maximum, then no effect on that channel.
[4.0 <= RngLim <= 32.0]
Allows to skip remapping of a channel where input channel average (un-scaled) is too close to either channel
minimum or maximum, ie avoid remapping of Black, White frames, or single color frames.
GamMax, default 10.0 Upper value for guess gamma [2.0 <= GamMax <= 10.0]
Starting guess upper range and limit for gamma estimator (probably best left alone).
The lower guess range and limit will be set to 1.0 / GamMax, by default 0.1.
dc, default clip c. Detection clip, Must be same ColorSpace and FrameCount as source clip, no other similarities enforced.
(can be different size, denoised etc).
x,y,w,h. All Default 20. Area of dc Detect clip frame to sample when getting averages and estimating Gamma function, allows to ignore rubbish at frame edges.
Specified as for crop ie x=10,y=20,w=-30,h=-40, as in crop(10,20,-30,-40).
Show, default true True, show metrics info on frame.
Verbosity, default 1 0 = Only upper frame metrics
1 = Upper + important ones. (default)
2 = Nearly Full metrics.
3 = Full Metrics
Upper frame metrics shown as eg:- (when Verbosity=3=FULL)
nnnnn] Flags:- 1SR
R G B
IN: 10,253 10,253 10,253
IN_AVE: 78.466 88.552 78.767
SCALED: 71.847 82.431 72.162
GAMMA: 1.135 1.000 1.123
OUTAVE: 82.431 82.422 82.451
where,
nnnnn, is the frame number.
Flags:- (Specific to current frame, can change frame to frame)
'1' = LockChan, as above, channel '1'[ScaleAveG].
Can be, '0', '1', '2' [ScaleAve Channel number LockChan=-3(median) assigns '0', '1' or '2' as appropriate]
'A'[LockChan=-2, (ScaleAveR+ScaleAveG+ScaleAveB)/3.0]
'V'[LockChan=-1, Explicit LockVal]
'S' = Scale, mode signfied by color.
Greyed out. Scale = 0(No Effect).May be Greyed out if all channels Min/Max are 0,255.
White. Scale = 1[Scales input channel average maximum dynamic range of R,G,B]
Orange. Scale = 2[Scales input channel average dynamic range of R and G and B, Individually]
'R' = Limited by RngLim, mode signfied by color.
Greyed out. Not Range Limited.
Red, at least 1 channel has remapping disabled.
IN: Shows comma separated channel minimum and maximum (dependent upon Scale, loTh, hiTh).
IN_AVE: Input channel averages.
SCALED: Scaled input averages, (dependent upon Scale, loTh, hiTh, channel minumums and maximums).
GAMMA: Estimated gamma to achieve lockval for channel. (dependent upon pretty much everything).
OUTAVE: Output channel average ie rendered result.
ALL metrics derived from the detection clip dc.
Fred, Added dc (detection clip) and modified args as per orders.
The RngLim thing still dont work at all well, I'll havta fix that.
videoFred
4th October 2016, 10:27
Fred, Added dc (detection clip) and modified args as per orders.
Thank you! It is good to set x,y,w,h to 20 by default.
As you know, I already use RemoveDirt() before Gammac. So the detection clip has no use for me.. But I could try extreme settings and see what I get.
The RngLim thing still dont work at all well, I'll havta fix that.
For now, I add a small 2 to 6 pixels pure white border before Gammac to avoid over-adjusting and this works very well. :)
PS: Gammac works great on my old 1970's photos too!
http://www.super-8.be/Doom/29013.jpg
http://www.super-8.be/Doom/landscape.jpg
Fred.
StainlessS
4th October 2016, 14:24
In the words of Harry Potter, "I love magic". :)
Perhaps that's the Hogwart's Express. (at least platform 9.75)
For now, I add a small 2 to 6 pixels pure white border before Gammac to avoid over-adjusting
I'll add output r,g,b max and min targets, as currently set at 0, and 255 (should avoid above, probably
one for each min and max, not for each channel, unless that is required).
videoFred
4th October 2016, 14:51
In the words of Harry Potter, "I love magic". :)
Me too ;)
Perhaps that's the Hogwart's Express. (at least platform 9.75)
Haha, no it's the last steam engine from the Belgian Railroad. His last official ride was way back in 1966. The photo is from a 1970's steam festival.
I had to do some additional color corrections on the steam engine picture, but the landscape picture is Gammac only, I only had to do some very minor RedMul and Blumul corrections.
Fred.
StainlessS
6th October 2016, 22:47
GamMac v1.06Beta3:- LINK DELETED
Added omin, omax args. Mod to RngLim.
GamMac(), [Gamma Machine] An extraordinary Idea by VideoFred (the gent from Gent). Coded by StainlessS.
Home Thread:- http://forum.doom9.org/showthread.php?p=1774281#post1774281
Idea:- http://forum.doom9.org/showthread.php?t=173683
RGB Only.
Useful to correct color cast on old 8mm films.
Alters channel pixel average to match LockChan using Gamma correction. (By default alters Red and Blue channels to match Green).
Additional tweaking via RedMul, GrnMul and BluMul multipliers.
What it does(roughly):-
Firstly, RAW input channel Ranges are measured for all three channels (see RngLim).
If ALL THREE raw input ranges are less than RngLim (single color frame), then for current frame,
there is no scaling nor gamma estimation, and only linear rendering is done to output range omin -> omax.
OtherWise,
If ANY ONE channel input range is less than RngLim and Scale==2, then Scale is (for current frame) knocked down to Scale=1.
Get Channel averages, minimums, and maximums (using loTh for minimums and hiTh for maximums).
if(Scale==0 || loTh<0.0 a|| hiTh<0.0) then
No rescaling.
if(Scale == 1 and loTh>=0.0 and hiTh>=0.0) then
rescales averages using combined dynamic range of r,g,b ie 0.0 -> (max(redMax,grnMax,bluMax) - min(redMin,grnMin,bluMin)).
else if(Scale == 2 and loTh>=0.0 and hiTh>=0.0) then
rescales averages using separate dynamic ranges ie 0.0->(redMax-redMin), 0.0->(grnMax-grnMin), 0.0->(bluMax-bluMin).
For each channel, estimate gamma function that will remap (scaled channel average * channel multiplier) to match a particular
LockVal (chosen via LockChan) when rendered to the chosen output range specified by omin and omax.
Then renders frame using the output averages from estimated gamma with output channel minimums at omin, and maximums at omax.
GamMac(Clip c,int "LockChan"=1,int "Scale"=2,
\ Float "RedMul"=1.0,Float "GrnMul"=1.0, Float "BluMul"=1.0,
\ Float "Th"= 0.04,Float "loTh"=Th,Float "hiTh"=Th,
\ Float "LockVal"=128.0,int "RngLim"=11,Float "GamMax"=10.0,
\ Clip "dc",
\ int "x"=20,int "y"=20,int "w"=-20,int "h"=-20,
\ int "omin"=0, int "omax"=255,
\ Bool "Show"=True,int "Verbosity"=1
\ )
LockChan Default 1(Grn). Channel for lock to Average. [range -3 -> 2]
0 ] LockVal = Scaled(RedAve)
1 ] LockVal = Scaled(GreenAve)
2 ] LockVal = Scaled(BlueAve)
-1] LockVal = Use explicit LockVal arg (see below).
-2] LockVal = (Scaled(RedAve)+Scaled(GrnAve)+Scaled(BluAve))/3.0. [Mean]
-3] LockVal = Median(Scaled(RedAve),Scaled(GrnAve),Scaled(BluAve))
Where Scaled(Channel Average) depends upon RngLim, Scale, and loTh, and hiTh.
Scale, default 2 Range 0 -> 2.
There is NO SCALING DONE if ALL THREE channels range is less than RngLim, see RngLim, linear render only.
If ANY ONE channel input range is less than RngLim and Scale==2, then Scale is (for current frame) knocked down to Scale=1.
where some described for Red Channel only:-
redMin = RedChanMin(ignorePerc=loTh) # Pixel minimum for red channel, ignoring up to loTh%, ie noise.
redMax = RedChanMax(ignorePerc=hiTh) # Pixel maximum for red channel, ignoring up to hiTh%, ie noise.
redAve = RedChanAve() # Pixel average for red Channel.
redRng = redMax - redMin
inMin = min(redMin,grnMin,bluMin) # Min of minimums
inMax = max(redMax,grnMax,bluMax) # Max of maximums
0 (Scale==0 || (loTh==-1.0 && hiTh==-1.0)) # No Effect on scale.
scaledAveR = redAve
scaledAveG = grnAve
scaledAveB = bluAve
1) Scales input channel average maximum dynamic range of R,G,B, to 0.0->(ChanAve-inMin)*255.0/(inMax-inMin)
scaler = 255.0 / (inMax - inMin)
scaledAveR = min(max((RedAve - inMin) * scaler,0.0),255.0)
scaledAveG = min(max((GrnAve - inMin) * scaler,0.0),255.0)
scaledAveB = min(max((BluAve - inMin) * scaler,0.0),255.0)
2) Scales input channel average dynamic range of R & G & B, Individually, to 0.0->(ChanAve-Chan_min)*255.0/(ChanMax-ChanMin)
scalerR = 255.0 / (redMax-redMin)
scalerG = 255.0 / (grnMax-grnMin)
scalerB = 255.0 / (bluMax-bluMin)
scaledAveR = min(max((redAve - redMin) * scalerR,0.0),255.0)
scaledAveG = min(max((grnAve - grnMin) * scalerG,0.0),255.0)
scaledAveB = min(max((bluAve - bluMid) * scalerB,0.0),255.0)
RedMul, default 1.0 Red channel multiplier adjustment. [0.1 <= RedMul <= 10.0]
GrnMul, default 1.0 Green channel multiplier adjustment. [0.1 <= GrnMul <= 10.0]
BluMul, default 1.0 Blue channel multiplier adjustment. [0.1 <= BluMul <= 10.0]
Scaled averages are multiplied by their multiplier then given as args to the gamma estimator.
Allow tweaking of R,G,B channels.
Above Multipliers only shown in metrics when at least one is != 1.0 (Always shown when Verbosity=3=FULL).
Th, Default 0.04 Sets Default for loTh and hiTh. Suggest Default, 0.04(percent). [-1.0(OFF) , or 0.0 -> 1.0]
loTh, Default Th As for Ignore_low in AutoLevels, or Threshold in YPlaneMin. [-1.0, or 0.0 -> 1.0]
Percent, amount of extreme pixels (eg noise) to ignore when finding minimum R, G or B channel values.
-1.0 is OFF, input channel minimum is set to 0 as for levels(0,gamma,input_max, ... ).
If loTh >=0.0, then will scan frame looking for lowest pixel value whose cumlative sum
[including all pixels counts of lower value pixels] is greater than loTh%.
loTh, only shown in metrics if greater or equal to 0.0 ie switched ON (Always shown when Verbosity=3=FULL).
hiTh, Default Th As for Ignore_high in AutoLevels, or Threshold in YPlaneMax. [-1.0, or 0.0 -> 1.0]
Percent, amount of extreme pixels (eg noise) to ignore when finding maximum R, G or B channel values.
-1.0 is OFF, input channel maximum set to 255, as in levels(input_min,gamma,255, ... ).
If hiTh >=0.0, then will scan frame looking for highest pixel value whose cumlative sum
[including all pixels counts of higher value pixels] is greater than hiTh%.
hiTh, only shown in metrics if greater or equal to 0.0 ie switched ON (Always shown when Verbosity=3=FULL).
LockVal, default 128.0 Only used if LockChan = -1. [0.0 < LockVal < 255.0] (set via LockChan if LockChan != -1)
There is no restricted range on this (other than 0.0 < LockVal < 255.0), so if you set a stupid value,
you will likely get stupid results.
RngLim, default 11 [1 <= RngLim <= 32]
If ALL THREE RAW input channel ranges ie (ChannelMax(max(hiTh,0.0))-ChannelMin(max(loTh,0.0))) are less than RngLim then
all scaling is disabled, and remapping is linear without gamma estimation, to range omin -> omax,
ie avoid remapping of Black, White frames, or single color frames.
GamMax, default 10.0 Upper value for guess gamma [2.0 <= GamMax <= 10.0]
Starting guess upper range and limit for gamma estimator (probably best left alone).
The lower guess range and limit will be set to 1.0 / GamMax, by default 0.1.
dc, default clip c. Detection clip, Must be same ColorSpace and FrameCount as source clip, no other similarities enforced.
(can be different size, denoised etc).
x,y, Both default 20. Area of dc Detect clip frame to sample when getting averages and estimating Gamma function, allows to ignore rubbish at frame edges.
w,h, Both default -20. Specified as for crop eg x=10,y=20,w=-30,h=-40, as in crop(10,20,-30,-40).
omin, default 0. Output limits for all three R, and G, and B channels. [Range 0 -> 16]
omax, default 255. [Range 239 -> 255] (extremes 16->239 allow for Studio RGB output).
May want to give yourself a little head/foot room by setting eg omin=5, omax=250, so that you leave a little room for
further manual color tweaking.
Show, default true True, show metrics info on frame.
Verbosity, default 1 0 = Only upper frame metrics
1 = Upper + important ones. (default)
2 = Nearly Full metrics.
3 = Full Metrics
Upper frame metrics shown as eg:- (when Verbosity=3=FULL)
nnnnn] Flags:- 1SR
R G B
RAW: 10,253 10,253 10,253
IN: 10,253 10,253 10,253
IN_AVE: 78.466 88.552 78.767
SCALED: 71.847 82.431 72.162
GAMMA: 1.135 1.000 1.123
OUTAVE: 82.431 82.422 82.451
where,
nnnnn, is the frame number.
Flags:- (Specific to current frame, can change frame to frame)
'1' = LockChan, as above, channel '1'[ScaleAveG].
Can be, '0', '1', '2' [ScaleAve Channel number LockChan=-3(median) assigns '0', '1' or '2' as appropriate]
'A'[LockChan=-2, (ScaleAveR+ScaleAveG+ScaleAveB)/3.0]
'V'[LockChan=-1, Explicit LockVal]
'S' = Scale, mode signfied by color.
Greyed out. Scale = 0(No Effect). May be Greyed out if all channels Min/Max are 0,255.
White. Scale = 1[Scales input channel average maximum dynamic range of R,G,B]
Orange. Scale = 2[Scales input channel average dynamic range of R and G and B, Individually]
'R' = Limited by RngLim, mode signfied by color.
Greyed out. Not Range Limited.
Red, at least 1 channel has remapping disabled.
RAW: Shows RAW comma separated channel minimum and maximum, eg ChannelMin(max(loTh,0.0)) and (ChannelMax(max(hiTh,0.0)),
only shown if Verbosity>=3 or, if any RAW input range is less than RngLim AND any of the RAW inputs are different
to the equivalent standard input.
IN: Shows comma separated channel minimum and maximum (dependent upon Scale, loTh, hiTh).
IN_AVE: Input channel averages.
SCALED: Scaled input averages, (dependent upon Scale, loTh, hiTh, channel minumums and maximums).
GAMMA: Estimated gamma to achieve lockval for channel. (dependent upon pretty much everything).
OUTAVE: Output channel average ie rendered result.
ALL metrics derived from the detection clip dc.
Not really sure how I should process low range frames (as by RngLim), could well be discontinuities in fades.
EDIT: Fred, omin, omax obviates need for a "few pixels of black,white border" (I hope).
StainlessS
7th October 2016, 02:10
GamMac v1.06 Beta 4, new version:- LINK REMOVED
Added Coords arg.
Coords, default False. If True, then shows DC clip with dotted lines showing the x,y,w,h coords plotted on frame. (All other functionality disabled).
GamMac(), [Gamma Machine] An extraordinary Idea by VideoFred (the gent from Gent). Coded by StainlessS.
Home Thread:- http://forum.doom9.org/showthread.php?p=1774281#post1774281
Idea:- http://forum.doom9.org/showthread.php?t=173683
RGB Only.
Useful to correct color cast on old 8mm films.
Alters channel pixel average to match LockChan using Gamma correction. (By default alters Red and Blue channels to match Green).
Additional tweaking via RedMul, GrnMul and BluMul multipliers.
What it does(roughly):-
Firstly, RAW input channel Ranges are measured for all three channels (see RngLim).
If ALL THREE raw input ranges are less than RngLim (single color frame), then for current frame,
there is no scaling nor gamma estimation, and only linear rendering is done to output range omin -> omax.
[EDIT: Channel multipliers are still applied though].
OtherWise,
If ANY ONE channel input range is less than RngLim and Scale==2, then Scale is (for current frame) knocked down to Scale=1.
Get Channel averages, minimums, and maximums (using loTh for minimums and hiTh for maximums).
if(Scale==0 || loTh<0.0 || hiTh<0.0) then
EDIT: if(Scale==0 || (loTh<0.0 AND hiTh<0.0)) then
No rescaling.
if(Scale == 1 and loTh>=0.0 and hiTh>=0.0) then
if(Scale == 1 and (loTh>=0.0 OR hiTh>=0.0)) then
rescales averages using combined dynamic range of r,g,b ie 0.0 -> (max(redMax,grnMax,bluMax) - min(redMin,grnMin,bluMin)).
else if(Scale == 2 and loTh>=0.0 and hiTh>=0.0) then
else if(Scale == 2 AND (loTh>=0.0 OR hiTh>=0.0)) then
rescales averages using separate dynamic ranges ie 0.0->(redMax-redMin), 0.0->(grnMax-grnMin), 0.0->(bluMax-bluMin).
For each channel, estimate gamma function that will remap (scaled channel average * channel multiplier) to match a particular
LockVal (chosen via LockChan) when rendered to the chosen output range specified by omin and omax.
Then renders frame using the output averages from estimated gamma with output channel minimums at omin, and maximums at omax.
GamMac(Clip c,int "LockChan"=1,int "Scale"=2,
\ Float "RedMul"=1.0,Float "GrnMul"=1.0, Float "BluMul"=1.0,
\ Float "Th"= 0.04,Float "loTh"=Th,Float "hiTh"=Th,
\ Float "LockVal"=128.0,int "RngLim"=11,Float "GamMax"=10.0,
\ Clip "dc",
\ int "x"=20,int "y"=20,int "w"=-20,int "h"=-20,
\ int "omin"=0, int "omax"=255,
\ Bool "Show"=True,int "Verbosity"=1,Bool "Coords"=false
\ )
LockChan Default 1(Grn). Channel for lock to Average. [range -3 -> 2]
0 ] LockVal = Scaled(RedAve)
1 ] LockVal = Scaled(GrnAve)
2 ] LockVal = Scaled(BluAve)
-1] LockVal = Use explicit LockVal arg (see below).
-2] LockVal = (Scaled(RedAve)+Scaled(GrnAve)+Scaled(BluAve))/3.0. [Mean]
-3] LockVal = Median(Scaled(RedAve),Scaled(GrnAve),Scaled(BluAve))
Where Scaled(Channel Average) depends upon RngLim, Scale, and loTh, and hiTh.
Scale, default 2 Range 0 -> 2.
There is NO SCALING DONE if ALL THREE channels range is less than RngLim, see RngLim, linear render only.
If ANY ONE channel input range is less than RngLim and Scale==2, then Scale is (for current frame) knocked down to Scale=1.
where some described for Red Channel only:-
redMin = RedChanMin(ignorePerc=loTh) # Pixel minimum for red channel, ignoring up to loTh%, ie noise.
redMax = RedChanMax(ignorePerc=hiTh) # Pixel maximum for red channel, ignoring up to hiTh%, ie noise.
redAve = RedChanAve() # Pixel average for red Channel.
redRng = redMax - redMin
inMin = min(redMin,grnMin,bluMin) # Min of minimums
inMax = max(redMax,grnMax,bluMax) # Max of maximums
0 (Scale==0 || (loTh==-1.0 && hiTh==-1.0)) # No Effect on scale.
scaledAveR = redAve
scaledAveG = grnAve
scaledAveB = bluAve
1) Scales input channel average maximum dynamic range of R,G,B, to 0.0->(ChanAve-inMin)*255.0/(inMax-inMin)
scaler = 255.0 / (inMax - inMin)
scaledAveR = min(max((RedAve - inMin) * scaler,0.0),255.0)
scaledAveG = min(max((GrnAve - inMin) * scaler,0.0),255.0)
scaledAveB = min(max((BluAve - inMin) * scaler,0.0),255.0)
2) Scales input channel average dynamic range of R & G & B, Individually, to 0.0->(ChanAve-Chan_min)*255.0/(ChanMax-ChanMin)
scalerR = 255.0 / (redMax-redMin)
scalerG = 255.0 / (grnMax-grnMin)
scalerB = 255.0 / (bluMax-bluMin)
scaledAveR = min(max((redAve - redMin) * scalerR,0.0),255.0)
scaledAveG = min(max((grnAve - grnMin) * scalerG,0.0),255.0)
scaledAveB = min(max((bluAve - bluMid) * scalerB,0.0),255.0)
RedMul, default 1.0 Red channel multiplier adjustment. [0.1 <= RedMul <= 10.0]
GrnMul, default 1.0 Green channel multiplier adjustment. [0.1 <= GrnMul <= 10.0]
BluMul, default 1.0 Blue channel multiplier adjustment. [0.1 <= BluMul <= 10.0]
Scaled averages are multiplied by their multiplier then given as args to the gamma estimator.
Allow tweaking of R,G,B channels.
Above Multipliers only shown in metrics when at least one is != 1.0 (Always shown when Verbosity=3=FULL).
Th, Default 0.04 Sets Default for loTh and hiTh. Suggest Default, 0.04(percent). [-1.0(OFF) , or 0.0 -> 1.0]
loTh, Default Th As for Ignore_low in AutoLevels, or Threshold in YPlaneMin. [-1.0, or 0.0 -> 1.0]
Percent, amount of extreme pixels (eg noise) to ignore when finding minimum R, G or B channel values.
-1.0 is OFF, input channel minimum is set to 0 as for levels(0,gamma,input_max, ... ).
If loTh >=0.0, then will scan frame looking for lowest pixel value whose cumulative sum
[including all pixels counts of lower value pixels] is greater than loTh%.
loTh, only shown in metrics if greater or equal to 0.0 ie switched ON (Always shown when Verbosity=3=FULL).
hiTh, Default Th As for Ignore_high in AutoLevels, or Threshold in YPlaneMax. [-1.0, or 0.0 -> 1.0]
Percent, amount of extreme pixels (eg noise) to ignore when finding maximum R, G or B channel values.
-1.0 is OFF, input channel maximum set to 255, as in levels(input_min,gamma,255, ... ).
If hiTh >=0.0, then will scan frame looking for highest pixel value whose cumulative sum
[including all pixels counts of higher value pixels] is greater than hiTh%.
hiTh, only shown in metrics if greater or equal to 0.0 ie switched ON (Always shown when Verbosity=3=FULL).
LockVal, default 128.0 Only used if LockChan = -1. [0.0 < LockVal < 255.0] (set via LockChan if LockChan != -1)
There is no restricted range on this (other than 0.0 < LockVal < 255.0), so if you set a stupid value,
you will likely get stupid results.
RngLim, default 11 [1 <= RngLim <= 32]
If ALL THREE RAW input channel ranges ie (ChannelMax(max(hiTh,0.0))-ChannelMin(max(loTh,0.0))) are less than RngLim then
all scaling is disabled, and remapping is linear without gamma estimation, to range omin -> omax,
ie avoid remapping of Black, White frames, or single color frames.
GamMax, default 10.0 Upper value for guess gamma [2.0 <= GamMax <= 10.0]
Starting guess upper range and limit for gamma estimator (probably best left alone).
The lower guess range and limit will be set to 1.0 / GamMax, by default 0.1.
dc, default clip c. Detection clip, Must be same ColorSpace and FrameCount as source clip, no other similarities enforced.
(can be different size, denoised etc).
x,y, Both default 20. Area of dc Detect clip frame to sample when getting averages and estimating Gamma function, allows to ignore rubbish at frame edges.
w,h, Both default -20. Specified as for crop eg x=10,y=20,w=-30,h=-40, as in crop(10,20,-30,-40).
omin, default 0. Output limits for all three R, and G, and B channels. [Range 0 -> 16]
omax, default 255. [Range 239 -> 255] (extremes 16->239 allow for Studio RGB output).
May want to give yourself a little head/foot room by setting eg omin=5, omax=250, so that you leave a little room for
further manual color tweaking.
Show, default true True, show metrics info on frame.
Verbosity, default 1 0 = Only upper frame metrics
1 = Upper + important ones. (default)
2 = Nearly Full metrics.
3 = Full Metrics
Upper frame metrics shown as eg:- (when Verbosity=3=FULL)
nnnnn] Flags:- 1SR
R G B
RAW: 10,253 10,253 10,253
IN: 10,253 10,253 10,253
IN_AVE: 78.466 88.552 78.767
SCALED: 71.847 82.431 72.162
GAMMA: 1.135 1.000 1.123
OUTAVE: 82.431 82.422 82.451
where,
nnnnn, is the frame number.
Flags:- (Specific to current frame, can change frame to frame)
'1' = LockChan, as above, channel '1'[ScaleAveG].
Can be, '0', '1', '2' [ScaleAve Channel number LockChan=-3(median) assigns '0', '1' or '2' as appropriate]
'A'[LockChan=-2, (ScaleAveR+ScaleAveG+ScaleAveB)/3.0]
'V'[LockChan=-1, Explicit LockVal]
'S' = Scale, mode signified by color.
Greyed out. Scale = 0(No Effect). May be Greyed out if all channels Min/Max are 0,255.
White. Scale = 1[Scales input channel average maximum dynamic range of R,G,B]
Orange. Scale = 2[Scales input channel average dynamic range of R and G and B, Individually]
'R' = Limited by RngLim, mode signfied by color.
Greyed out. Not Range Limited.
Red, at least 1 channel has remapping disabled.
RAW: Shows RAW comma separated channel minimum and maximum, eg ChannelMin(max(loTh,0.0)) and (ChannelMax(max(hiTh,0.0)),
only shown if Verbosity>=3 or, if any RAW input range is less than RngLim AND any of the RAW inputs are different
to the equivalent standard input.
IN: Shows comma separated channel minimum and maximum (dependent upon Scale, loTh, hiTh).
IN_AVE: Input channel averages.
SCALED: Scaled input averages, (dependent upon Scale, loTh, hiTh, channel minimums and maximums).
GAMMA: Estimated gamma to achieve lockval for channel. (dependent upon pretty much everything).
OUTAVE: Output channel average ie rendered result.
ALL metrics derived from the detection clip dc (Including OutAve's).
Coords, default False. If True, then shows DC clip with dotted lines showing the x,y,w,h coords plotted on frame. (All other functionality disabled).
StainlessS
7th October 2016, 04:53
GamMac v1.06 Beta 5, new version:- LINK REMOVED
Negative LockChan was broken, fixed. Some metrics mainly S flag color fixed.
Previous post DOCS not changed.
EDIT:
To use coords arg and detection clip not used, (DC defaults to Last)
Return GamMac(Last,x=x,y=y,w=w,h=h,Coords=True) # Show Coords only
or with DC detection clip
Return GamMac(DC,x=x,y=y,w=w,h=h,Coords=True) # Show Coords only
# or
#Return GamMac(dc=DC,x=x,y=y,w=w,h=h,Coords=True)
EDIT:
How it looks, Verbocity=1
https://s20.postimg.cc/hhcfqen3x/pup0000_zpsxaw0pgfv.png (https://postimg.cc/image/jlwsrhoqh/)
and original with detect coords shown
https://s20.postimg.cc/5tidvuxz1/pup_Coord0000_zpsuzm6foic.png (https://postimg.cc/image/8nlj9b055/)
EDIT:
And coords shown avoiding detect on original subtitles
https://s20.postimg.cc/g4uqoipod/Coords0000_zpsy7ir1e6x.png (https://postimg.cc/image/t90b17hq1/)
And result
https://s20.postimg.cc/w4de82lq5/Miss_Coords0000_zps85k72spw.png (https://postimg.cc/image/rih9zq06x/)
johnmeyer
7th October 2016, 21:24
OK, I need to get off the sidelines and get into this game. Harry Potter magic doesn't begin to describe what I'm seeing. Amazing stuff, StainlessS!
I'm working on a complete re-write of the software for my shutterless projector transfer system, and I need to integrate this into my new workflow.
StainlessS
7th October 2016, 23:03
All, but all magic is down to Videofred, i' m just a grunt.
Videofred ain't no muggle. [EDIT: Yoda had some say so too, yo dude, Yoda for king, or maybe Pope or something].
johnmeyer
8th October 2016, 04:37
I know what VideoFred can do, and it is beyond remarkable. However, I've followed this development, and you came up with the code that makes everything work.
I hope to get to this next week, and I'll report back on what I'm able to do with it.
StainlessS
8th October 2016, 12:52
Post #1 of 2
GamMac v1.06 Beta6, New Version:- LINK REMOVED
(~998KB, Included Puppy.png, LennaRed.png, and GreenChurch.png)
Updates mainly cosmetic.
Increased number of Verbosity levels to 5 (default=2, 5=Show version info + ALL metrics, 0=show metrics Flags line only).
A few mods to docs.
Added Subs to 4 window output, optional coords shown (included avs script).
EDIT: The DC clip (detect clip) coords now changed from all white dotted lines to alternate white and black dots.
Docs
GamMac(), [Gamma Machine] An extraordinary Idea by VideoFred (the gent from Gent). Coded by StainlessS.
Home Thread:- http://forum.doom9.org/showthread.php?p=1774281#post1774281
Idea:- http://forum.doom9.org/showthread.php?t=173683
RGB Only.
Useful to correct color cast on old 8mm films.
Alters channel pixel average to match LockChan using Gamma correction. (By default alters Red and Blue channels to match Green).
Additional tweaking via RedMul, GrnMul and BluMul multipliers.
What it does(roughly):-
Firstly, RAW input channel Ranges are measured for all three channels (see RngLim).
If ALL THREE raw input ranges are less than RngLim (single color frame), then for current frame,
there is no scaling nor gamma estimation, and only linear rendering is done to output range omin -> omax.
[Channels multipliers RedMul, GrnMul and BluMul still applied though.]
OtherWise,
If ANY ONE channel input range is less than RngLim and Scale==2, then Scale is (for current frame) knocked down to Scale=1.
Get Channel averages, minimums, and maximums (using loTh for minimums and hiTh for maximums).
if(Scale==0 OR (loTh<0.0 AND hiTh<0.0)) then
No rescaling.
if(Scale == 1 AND (loTh>=0.0 OR hiTh>=0.0)) then
rescales averages using combined dynamic range of r,g,b ie 0.0 -> (max(redMax,grnMax,bluMax) - min(redMin,grnMin,bluMin)).
else if(Scale == 2 AND (loTh>=0.0 OR hiTh>=0.0)) then
rescales averages using separate dynamic ranges ie 0.0->(redMax-redMin), 0.0->(grnMax-grnMin), 0.0->(bluMax-bluMin).
For each channel, estimate gamma function that will remap (scaled channel average * channel multiplier) to match a particular
LockVal (chosen via LockChan) when rendered to the chosen output range specified by omin and omax.
Then renders frame using the output averages from estimated gamma with output channel minimums at omin, and maximums at omax.
GamMac(Clip c,int "LockChan"=1,int "Scale"=2,
\ Float "RedMul"=1.0,Float "GrnMul"=1.0, Float "BluMul"=1.0,
\ Float "Th"= 0.04,Float "loTh"=Th,Float "hiTh"=Th,
\ Float "LockVal"=128.0,int "RngLim"=11,Float "GamMax"=10.0,
\ Clip "dc",
\ int "x"=20,int "y"=20,int "w"=-20,int "h"=-20,
\ int "omin"=0, int "omax"=255,
\ Bool "Show"=True,int "Verbosity"=2,Bool "Coords"=false
\ )
LockChan Default 1(Grn). Channel for lock to Average. [range -3 -> 2]
0 ] LockVal = Scaled(RedAve)
1 ] LockVal = Scaled(GrnAve)
2 ] LockVal = Scaled(BluAve)
-1] LockVal = Use explicit LockVal arg (see below).
-2] LockVal = (Scaled(RedAve)+Scaled(GrnAve)+Scaled(BluAve))/3.0. [Mean]
-3] LockVal = Median(Scaled(RedAve),Scaled(GrnAve),Scaled(BluAve))
Where Scaled(Channel Average) depends upon RngLim, Scale, and loTh, and hiTh.
Scale, default 2 Range 0 -> 2.
There is NO SCALING DONE if ALL THREE channels range is less than RngLim, see RngLim, linear render only.
If ANY ONE channel input range is less than RngLim and Scale==2, then Scale is (for current frame) knocked down to Scale=1.
where some described for Red Channel only:-
redMin = RedChanMin(ignorePerc=loTh) # Pixel minimum for red channel, ignoring up to loTh%, ie noise.
redMax = RedChanMax(ignorePerc=hiTh) # Pixel maximum for red channel, ignoring up to hiTh%, ie noise.
redAve = RedChanAve() # Pixel average for red Channel.
redRng = redMax - redMin
inMin = min(redMin,grnMin,bluMin) # Min of minimums
inMax = max(redMax,grnMax,bluMax) # Max of maximums
0 (Scale==0 || (loTh==-1.0 && hiTh==-1.0)) # No Effect on scale.
scaledAveR = redAve
scaledAveG = grnAve
scaledAveB = bluAve
1) Scales input channel average maximum dynamic range of R,G,B, to 0.0->(ChanAve-inMin)*255.0/(inMax-inMin)
scaler = 255.0 / (inMax - inMin)
scaledAveR = min(max((RedAve - inMin) * scaler,0.0),255.0)
scaledAveG = min(max((GrnAve - inMin) * scaler,0.0),255.0)
scaledAveB = min(max((BluAve - inMin) * scaler,0.0),255.0)
2) Scales input channel average dynamic range of R & G & B, Individually, to 0.0->(ChanAve-Chan_min)*255.0/(ChanMax-ChanMin)
scalerR = 255.0 / (redMax-redMin)
scalerG = 255.0 / (grnMax-grnMin)
scalerB = 255.0 / (bluMax-bluMin)
scaledAveR = min(max((redAve - redMin) * scalerR,0.0),255.0)
scaledAveG = min(max((grnAve - grnMin) * scalerG,0.0),255.0)
scaledAveB = min(max((bluAve - bluMid) * scalerB,0.0),255.0)
RedMul, default 1.0 Red channel multiplier adjustment. [0.1 <= RedMul <= 10.0]
GrnMul, default 1.0 Green channel multiplier adjustment. [0.1 <= GrnMul <= 10.0]
BluMul, default 1.0 Blue channel multiplier adjustment. [0.1 <= BluMul <= 10.0]
Scaled averages are multiplied by their multiplier then given as args to the gamma estimator.
Allow tweaking of R,G,B channels.
Above Multipliers only shown in metrics when at least one is != 1.0 (Always shown when Verbosity=3=FULL).
Th, Default 0.04 Sets Default for loTh and hiTh. Suggest Default, 0.04(percent). [-1.0(OFF) , or 0.0 -> 1.0]
loTh, Default Th As for Ignore_low in AutoLevels, or Threshold in YPlaneMin. [-1.0, or 0.0 -> 1.0]
Percent, amount of extreme pixels (eg noise) to ignore when finding minimum R, G or B channel values.
-1.0 is OFF, input channel minimum is set to 0 as for levels(0,gamma,input_max, ... ).
If loTh >=0.0, then will scan frame looking for lowest pixel value whose cumulative sum
[including all pixels counts of lower value pixels] is greater than loTh%.
loTh, only shown in metrics if greater or equal to 0.0 ie switched ON (Always shown when Verbosity=3=FULL).
hiTh, Default Th As for Ignore_high in AutoLevels, or Threshold in YPlaneMax. [-1.0, or 0.0 -> 1.0]
Percent, amount of extreme pixels (eg noise) to ignore when finding maximum R, G or B channel values.
-1.0 is OFF, input channel maximum set to 255, as in levels(input_min,gamma,255, ... ).
If hiTh >=0.0, then will scan frame looking for highest pixel value whose cumulative sum
[including all pixels counts of higher value pixels] is greater than hiTh%.
hiTh, only shown in metrics if greater or equal to 0.0 ie switched ON (Always shown when Verbosity=3=FULL).
LockVal, default 128.0 Only used if LockChan = -1. [0.0 < LockVal < 255.0] (set via LockChan if LockChan != -1)
There is no restricted range on this (other than 0.0 < LockVal < 255.0), so if you set a stupid value,
you will likely get stupid results.
RngLim, default 11 [1 <= RngLim <= 32]
If ALL THREE RAW input channel ranges ie (ChannelMax(max(hiTh,0.0))-ChannelMin(max(loTh,0.0))) are less than RngLim then
all scaling is disabled, and remapping is linear without gamma estimation, to range omin -> omax,
ie avoid remapping of Black, White frames, or single color frames.
GamMax, default 10.0 Upper value for guess gamma [2.0 <= GamMax <= 10.0]
Starting guess upper range and limit for gamma estimator (probably best left alone).
The lower guess range and limit will be set to 1.0 / GamMax, by default 0.1.
dc, default clip c. Detection clip, Must be same ColorSpace and FrameCount as source clip, no other similarities enforced.
(can be different size, denoised etc).
x,y, Both default 20. Area of dc Detect clip frame to sample when getting averages and estimating Gamma function, allows to ignore rubbish at frame edges.
w,h, Both default -20. Specified as for crop eg x=10,y=20,w=-30,h=-40, as in crop(10,20,-30,-40).
omin, default 0. Output limits for all three R, and G, and B channels. [Range 0 -> 16]
omax, default 255. [Range 239 -> 255] (extremes 16->239 allow for Studio RGB output).
May want to give yourself a little head/foot room by setting eg omin=5, omax=250, so that you leave a little room for
further manual color tweaking.
Show, default true True, show metrics info on frame.
Verbosity, default 2 0 = Only upper frame metrics Flags line only
1 = Upper frame metrics
2 = Upper + important ones. (default)
3 = Nearly Full metrics.
4 = Full Metrics except version info
5 = Full Metrics including version info
Upper frame metrics shown as eg:- (when Verbosity=5=FULL)
nnnnn] Flags:- 1SR
R G B
RAW: 10,253 10,253 10,253
IN: 10,253 10,253 10,253
IN_AVE: 78.466 88.552 78.767
SCALED: 71.847 82.431 72.162
GAMMA: 1.135 1.000 1.123
OUTAVE: 82.431 82.422 82.451
where,
nnnnn, is the frame number.
Flags:- (Specific to current frame, can change frame to frame)
'1' = LockChan, as above, channel '1'[ScaleAveG].
Can be, '0', '1', '2' [ScaleAve Channel number LockChan=-3(median) assigns '0', '1' or '2' as appropriate]
'A'[LockChan=-2, (ScaleAveR+ScaleAveG+ScaleAveB)/3.0]
'V'[LockChan=-1, Explicit LockVal]
'S' = Scale, mode signified by color.
Greyed out. Scale = 0(No Effect). May be Greyed out if all channels Min/Max are 0,255.
White. Scale = 1[Scales input channel average maximum dynamic range of R,G,B]
Orange. Scale = 2[Scales input channel average dynamic range of R and G and B, Individually]
'R' = Limited by RngLim, mode signfied by color.
Greyed out. Not Range Limited.
Red, at least 1 channel has remapping disabled.
RAW: Shows RAW comma separated channel minimum and maximum, eg ChannelMin(max(loTh,0.0)) and (ChannelMax(max(hiTh,0.0)),
only shown if Verbosity>=3 or, if any RAW input range is less than RngLim AND any of the RAW inputs are different
to the equivalent standard input.
IN: Shows comma separated channel minimum and maximum (dependent upon Scale, loTh, hiTh).
IN_AVE: Input channel averages.
SCALED: Scaled input averages, (dependent upon Scale, loTh, hiTh, channel minimums and maximums).
GAMMA: Estimated gamma to achieve lockval for channel. (dependent upon pretty much everything).
OUTAVE: Output channel average ie rendered result.
ALL metrics derived from the detection clip dc (Including OutAve's).
Coords, default False. If True, then shows DC clip with dotted lines showing the x,y,w,h coords plotted on frame. (All other functionality disabled).
StainlessS
8th October 2016, 12:53
Post #2 of 2
Included script showing Coords
Imagesource("GreenChurch.png",end=0)
#Imagesource("Puppy.png",end=0)
#Imagesource("lennaRed.png",end=0)
ConvertToRGB24.KillAudio
#Spline36Resize(512,384)
O=Last
DC=Last
#DC=DC.Blur(1.0) # Detection Clip (uses source clip if dc not supplied, Denoised or whatever)
LockChan = 1 # Chan for lock to Ave, 0=R, 1=G, 2=B
# -1 = Use LockVal below.
# -2 = LockVal=(RedAve+GrnAve+BluAve)/3.0 for LockVal.
# -3 = LockVal=Median(RedAve,GrnAve,BluAve)
Scale=2
RedMul = 1.0 # Required Ave multiplier for Red Channel, applied when requesting GuessGamma(reqAve*RedMul), Even applied when LockChan=-1.
GrnMul = 1.0 # Same for Green channel. GrnMul even applies when LockChan is Green Channel, etc for chans.
BluMul = 1.0 # Same for Blue channel. Allows tinkering/fine tuning.
Th = 0.04
LockVal = 128.0 # Only valid if LockChan == -1
RngLim = 11
GamMax = 10.0
Show = True # Metrics
Verb = 1 # Verbocity FULL
SHOWCOORDS= True # Show Original with Coords
x =5 # Coords (for dc Detection Clip)
y =5
w=-5
h=-5
omin=5 # Output channels minimum (footroom for manual editing).
omax=250 # Output channels maximum (headroom for manual editing).
#Return GamMac(DC,x=x,y=y,w=w,h=h,Coords=True) # Show Coords only
Scale=0
A_TEXT = RT_String("Scale=%d rMul=%.2f gMul=%.2f bMul=%.2f",Scale,RedMul,GrnMul,BluMul)
A=GamMac(LockChan=LockChan,SCALE=SCALE,RedMul=RedMul,GrnMul=GrnMul,BluMul=BluMul,
\ Th=Th,LockVal=LockVal,RngLim=RngLim,GamMax=GamMax,
\ dc=DC,
\ x=x,y=y,w=w,h=h,
\ omin=omin,omax=omax,
\ Show=Show,Verbosity=Verb)
Scale=1 BluMul=1.05
B_TEXT = RT_String("Scale=%d rMul=%.2f gMul=%.2f bMul=%.2f",Scale,RedMul,GrnMul,BluMul)
B=GamMac(LockChan=LockChan,SCALE=SCALE,RedMul=RedMul,GrnMul=GrnMul,BluMul=BluMul,
\ Th=Th,LockVal=LockVal,RngLim=RngLim,GamMax=GamMax,
\ dc=DC,
\ x=x,y=y,w=w,h=h,
\ omin=omin,omax=omax,
\ Show=Show,Verbosity=Verb)
Scale=2 BluMul=0.95
C_TEXT = RT_String("Scale=%d rMul=%.2f gMul=%.2f bMul=%.2f",Scale,RedMul,GrnMul,BluMul)
C=GamMac(LockChan=LockChan,SCALE=SCALE,RedMul=RedMul,GrnMul=GrnMul,BluMul=BluMul,
\ Th=Th,LockVal=LockVal,RngLim=RngLim,GamMax=GamMax,
\ dc=DC,
\ x=x,y=y,w=w,h=h,
\ omin=omin,omax=omax,
\ Show=Show,Verbosity=Verb)
COORDS=GamMac(DC,x=x,y=y,w=w,h=h,Coords=True)
TOP=StackHorizontal(SHOWCOORDS?Sub(COORDS,"Coords Original"):Sub(O,"Original"),Sub(A,A_TEXT))
BOT=StackHorizontal(Sub(B,B_TEXT),Sub(C,C_TEXT))
StackVertical(TOP,BOT)
return Last
Function Sub(clip c,string tit) {StackVertical(c.BlankClip(height=20).ScriptClip("""Subtitle(RT_String("%d] %s",current_frame,tit))""",Args="tit",Local=true),c)}
Result
https://s20.postimg.cc/litiw2fel/coords_Plus0000_zpsolotwqys.png (https://postimg.cc/image/6a3lialq1/)
EDIT: The titles added above each frame include frame number.
EDIT: Script requires Grunt() (c) Gavino, for Args arg in Scriptclip [used by Function Sub()].
StainlessS
8th October 2016, 21:33
GamMatch() v0.00 NEW PLUGIN [based on GamMac()] :- LINK REMOVED
GamMatch(), [Gamma Matcher] A daft Idea, based upon an extraordinary Idea by VideoFred (the gent from Gent). (Daft idea and code by StainlessS).
The Idea behind the daft idea(GamMac):- http://forum.doom9.org/showthread.php?p=1774281#post1774281
Original Idea:- http://forum.doom9.org/showthread.php?t=173683
RGB Only.
Useful to correct bad color clip where there is a better color source of perhaps lower rez available.
Additional tweaking via RedMul, GrnMul and BluMul multipliers.
What it does(roughly):-
Alter bad color clip c channel minimums, maximums and averages to match dc (good color clip) by
varying Gamma
GamMatch(Clip c,clip dc,int "Scale"=2,
\ Float "RedMul"=1.0,Float "GrnMul"=1.0, Float "BluMul"=1.0,
\ Float "Th"= 0.04,Float "loTh"=Th,Float "hiTh"=Th,
\ int "RngLim"=11,Float "GamMax"=10.0,
\ int "x"=20,int "y"=20,int "w"=-20,int "h"=-20,
\ Bool "Show"=True,int "Verbosity"=2,Bool "Coords"=false
\ )
c, no default. Bad Color clip.
dc, no default. Detection clip (good color clip). Must be same ColorSpace and FrameCount as source clip, no other similarities enforced.
Scale, default 2 Range 0 -> 2.
RedMul, default 1.0 Red channel multiplier adjustment. [0.1 <= RedMul <= 10.0]
GrnMul, default 1.0 Green channel multiplier adjustment. [0.1 <= GrnMul <= 10.0]
BluMul, default 1.0 Blue channel multiplier adjustment. [0.1 <= BluMul <= 10.0]
Th, Default 0.04 Sets Default for loTh and hiTh. Suggest Default, 0.04(percent). [-1.0(OFF) , or 0.0 -> 1.0]
loTh, Default Th As for Ignore_low in AutoLevels, or Threshold in YPlaneMin. [-1.0, or 0.0 -> 1.0]
Percent, amount of extreme pixels (eg noise) to ignore when finding minimum R, G or B channel values.
-1.0 is OFF, input channel minimum is set to 0 as for levels(0,gamma,input_max, ... ).
If loTh >=0.0, then will scan frame looking for lowest pixel value whose cumulative sum
[including all pixels counts of lower value pixels] is greater than loTh%.
loTh, only shown in metrics if greater or equal to 0.0 ie switched ON (Always shown when Verbosity=3=FULL).
hiTh, Default Th As for Ignore_high in AutoLevels, or Threshold in YPlaneMax. [-1.0, or 0.0 -> 1.0]
Percent, amount of extreme pixels (eg noise) to ignore when finding maximum R, G or B channel values.
-1.0 is OFF, input channel maximum set to 255, as in levels(input_min,gamma,255, ... ).
If hiTh >=0.0, then will scan frame looking for highest pixel value whose cumulative sum
[including all pixels counts of higher value pixels] is greater than hiTh%.
hiTh, only shown in metrics if greater or equal to 0.0 ie switched ON (Always shown when Verbosity=3=FULL).
RngLim, default 11 [1 <= RngLim <= 32]
If ALL THREE RAW input channel ranges ie (ChannelMax(max(hiTh,0.0))-ChannelMin(max(loTh,0.0))) are less than RngLim then
all scaling is disabled, and remapping is linear without gamma estimation, to range omin -> omax,
ie avoid remapping of Black, White frames, or single color frames.
GamMax, default 10.0 Upper value for guess gamma [2.0 <= GamMax <= 10.0]
Starting guess upper range and limit for gamma estimator (probably best left alone).
The lower guess range and limit will be set to 1.0 / GamMax, by default 0.1.
x,y, Both default 20. Area of dc Detect clip frame to sample when getting averages and estimating Gamma function, allows to ignore rubbish at frame edges.
w,h, Both default -20. Specified as for crop eg x=10,y=20,w=-30,h=-40, as in crop(10,20,-30,-40).
Show, default true True, show metrics info on frame.
Verbosity, default 2 0 = Only upper frame metrics Flags line only
1 = Upper frame metrics
2 = Upper + important ones. (default)
3 = Nearly Full metrics.
4 = Full Metrics except version info
5 = Full Metrics including version info
Upper frame metrics shown as eg:- (when Verbosity=5=FULL)
nnnnn] Flags:- SR
R G B
DC: 4,255 3,255 2,255
DC_AVE: 92.123 128.543 132.890
RAW: 10,253 10,253 10,253
IN: 10,253 10,253 10,253
IN_AVE: 78.466 88.552 78.767
SCALED: 71.847 82.431 72.162
GAMMA: 1.135 1.000 1.123
OUTAVE: 82.431 82.422 82.451 <<< OUTAVE will read about same as DC_AVE (made up numbers)
where,
nnnnn, is the frame number.
Flags:- (Specific to current frame, can change frame to frame)
'S' = Scale, mode signified by color.
Greyed out. Scale = 0(No Effect). May be Greyed out if all channels Min/Max are 0,255.
White. Scale = 1[Scales input channel average maximum dynamic range of R,G,B]
Orange. Scale = 2[Scales input channel average dynamic range of R and G and B, Individually]
'R' = Limited by RngLim, mode signfied by color.
Greyed out. Not Range Limited.
Red, at least 1 channel has remapping disabled.
DC: Shows comma separated channel minimum and maximum of DC clip(dependent upon loTh, hiTh).
DC_AVE: DC Clip channel averages.
RAW: Shows RAW comma separated channel minimum and maximum, eg ChannelMin(max(loTh,0.0)) and (ChannelMax(max(hiTh,0.0)),
only shown if Verbosity>=3 or, if any RAW input range is less than RngLim AND any of the RAW inputs are different
to the equivalent standard input.
IN: Shows comma separated channel minimum and maximum (dependent upon Scale, loTh, hiTh).
IN_AVE: Input channel averages.
SCALED: Scaled input averages, (dependent upon Scale, loTh, hiTh, channel minimums and maximums).
GAMMA: Estimated gamma to achieve lockval for channel. (dependent upon pretty much everything).
OUTAVE: Output channel average ie rendered result.
DC and DC_AVE derived from DC (Good color clip), all others from clip c (BAD color clip, Incl OUTAVE).
Coords, default False. If True, then shows DC clip with dotted lines showing the x,y,w,h coords plotted on frame. (All other functionality disabled).
Simulated Demo
# Some good color clip
Avisource("1941 Flint Michigan Parade [Low, 360p].mp4.AVI")
ConvertToRGB24.KillAudio
DC=Last
# Simulate bad color, Input clip
RED=ShowRed(Pixel_Type="Y8").Levels( 0,0.9,255, 8 , 247,coring=false)
GRN=ShowGreen(Pixel_Type="Y8").Levels(0,1.5,255, 12, 223,coring=false)
BLU=ShowBlue(Pixel_Type="Y8").Levels( 0,2.5,255, 18, 239,coring=false)
MergeRGB(RED,GRN,BLU,pixel_Type="RGB24")
O=Last
Scale=2
RedMul = 1.0 # Required Ave multiplier for Red Channel, applied when requesting GuessGamma(reqAve*RedMul), Even applied when LockChan=-1.
GrnMul = 1.0 # Same for Green channel. GrnMul even applies when LockChan is Green Channel, etc for chans.
BluMul = 1.0 # Same for Blue channel. Allows tinkering/fine tuning.
Th = 0.04
RngLim = 11
GamMax = 10.0
Show = True # Metrics
Verb = 5 # Verbocity FULL
x =5 # Coords (for dc Detection Clip)
y =5
w=-5
h=-5
Scale=0
A_TEXT = RT_String("Scale=%d rMul=%.2f gMul=%.2f bMul=%.2f",Scale,RedMul,GrnMul,BluMul)
A=GamMatch(Last,DC,SCALE=SCALE,RedMul=RedMul,GrnMul=GrnMul,BluMul=BluMul,
\ Th=Th,RngLim=RngLim,GamMax=GamMax,
\ x=x,y=y,w=w,h=h,
\ Show=Show,Verbosity=Verb)
Scale=1
B_TEXT = RT_String("Scale=%d rMul=%.2f gMul=%.2f bMul=%.2f",Scale,RedMul,GrnMul,BluMul)
B=GamMatch(Last,DC,SCALE=SCALE,RedMul=RedMul,GrnMul=GrnMul,BluMul=BluMul,
\ Th=Th,RngLim=RngLim,GamMax=GamMax,
\ x=x,y=y,w=w,h=h,
\ Show=Show,Verbosity=Verb)
Scale=2
C_TEXT = RT_String("Scale=%d rMul=%.2f gMul=%.2f bMul=%.2f",Scale,RedMul,GrnMul,BluMul)
C=GamMatch(Last,DC,SCALE=SCALE,RedMul=RedMul,GrnMul=GrnMul,BluMul=BluMul,
\ Th=Th,RngLim=RngLim,GamMax=GamMax,
\ x=x,y=y,w=w,h=h,
\ Show=Show,Verbosity=Verb)
COORDS=GamMatch(Last,DC,x=x,y=y,w=w,h=h,Coords=True)
TOP=StackHorizontal(Sub(O,"Original (Simulated bad clip)"),Sub(COORDS,"Detect with Coords"),Sub(A,A_TEXT))
BOT=StackHorizontal(Sub(DC,"DC Detect (Good color clip)"),Sub(B,B_TEXT),Sub(C,C_TEXT))
StackVertical(TOP,BOT)
return Last
Function Sub(clip c,string tit) {StackVertical(c.BlankClip(height=20).ScriptClip("""Subtitle(RT_String("%d] %s",current_frame,tit))""",Args="tit",Local=true),c)}
result
https://s20.postimg.cc/wwg279px9/Gam_Match_zpsseitomzc.png (https://postimg.cc/image/aki9dvqt5/)
without metrics
https://s20.postimg.cc/7269hhpx9/Gam_Match_No_Metrics_zpsq0t4iyq0.png (https://postimg.cc/image/e5e4x3vcp/)
EDIT: IN: Red values a little wonky in metrics.
EDIT: Both clips should be in sync.
EDIT: The Scale=0 result does not alter minimums and maximums to match DC, hence the slightly reddish white lines on road.
super8boy
18th October 2016, 23:09
That's seriously great work. Well done. Really impressive.
How well does it work on film for which an overscan has been done?
Would the system get confused by extra information on the top and bottom of the frame + left (perforations) and right?
If that was the case, I guess one could only process say only x by y amount of pixels (say 75% of the image) correct?
If not, the only solution would be not to overscan so much, to not overscan at all or to recrop the video to 1440x1080 for example before applying Gammac.
Trying to figure out what the best workflow would be.
johnmeyer
18th October 2016, 23:33
That's seriously great work. Well done. Really impressive.
How well does it work on film for which an overscan has been done?I haven't yet had the chance to use this, but for similar situations you merely create a cropped clip and use that. You can then apply the modifications to the uncropped clip, or apply the modifications to the cropped clip and then add borders. Either way, you end up with the same sized clip as the original.
StainlessS
18th October 2016, 23:55
You can set args x,y,w,h and coord=true, to show current coords on screen for DC detect clip. Set cords =false for use.
Cropping DC would also work fine.
StainlessS
19th October 2016, 01:00
Now not mobile.
The above windowed demos did not I think cope with DC detect clip of different size to source (just for the windowed display),
I have done updated scripts some time ago, but there seemed to be little interest and so did not bother to update scripts.
Also, the published GamMatch() plug, suffered from Access Violations if not given two clips (1 was supposed to be optional),
I dont know why this occurred, from examining source I think there should have been no problem, but there was. Anyway,
made second clip non optional and problem has disappeared. (I had been testing with AVS+, perhaps problem was in some way related,
it seemed to crash before getting 'into' the plugin, so perhaps something in AVS+ was accessing optional clip when not supplied).
I shall try to update GamMatch() plug, and also demo windowed routines for both GamMac() and GamMatch(), soon.
GamMac(), lets you alter Channel averages to match one of the other channels (or optional specific value), eg faded color on aged film.
GamMatch, Allows to correct a clip that has had Levels + Gamma badly applied, to one of more channels, by using an in sync version
with good un-messed with color, but perhaps of inferior resolution.
GamMatch is unlikely to be of any use where eg Tweak or some other non RGB levels type mod has been applied, it is yet though not certain
(as nobody has responded) as to whether or not a faded hi rez clip could be fixed via a non faded DC detect clip.
(Actually, Tweak does not seem to give valid ColorSpace's in v2.6 AVS docs, just tested, does not support RGB).
StainlessS
20th October 2016, 06:47
OK, Here modded Windowed Demo script that supports different sized DC detect clip.
Avisource("1941 Flint Michigan Parade [Low, 360p].mp4.AVI")
ConvertToRGB24.KillAudio
O=Last
DC=Last
# Test DC can be different size
DC=DC.Blur(1.0).BilinearResize(320,240) # Detection Clip Can be different size(uses source clip if dc not supplied, Denoised or whatever)
LockChan = 1 # Chan for lock to Ave, 0=R, 1=G, 2=B
# -1 = Use LockVal below.
# -2 = LockVal=(RedAve+GrnAve+BluAve)/3.0 for LockVal.
# -3 = LockVal=Median(RedAve,GrnAve,BluAve)
Scale=2
RedMul = 1.0 # Required Ave multiplier for Red Channel, applied when requesting GuessGamma(reqAve*RedMul), Even applied when LockChan=-1.
GrnMul = 1.0 # Same for Green channel. GrnMul even applies when LockChan is Green Channel, etc for chans.
BluMul = 1.0 # Same for Blue channel. Allows tinkering/fine tuning.
Th = 0.01
LockVal = 128.0 # Only valid if LockChan == -1
RngLim = 11
GamMax = 10.0
Show = True # Metrics
Verb = 4 # Verbocity FULL
SHOWCOORDS=True # Show DC detect clip instead of original
x =5 # Coords (for dc Detection Clip)
y =5
w=-5
h=-5
omin=5 # Output channels minimum
omax=250 # Output channels maximum
#Return GamMac(DC,x=x,y=y,w=w,h=h,Coords=True) # Show Coords only
Scale=0
A_TEXT = RT_String("Scale=%d rMul=%.2f gMul=%.2f bMul=%.2f",Scale,RedMul,GrnMul,BluMul)
A=O.GamMac(LockChan=LockChan,SCALE=SCALE,RedMul=RedMul,GrnMul=GrnMul,BluMul=BluMul,
\ Th=Th,LockVal=LockVal,RngLim=RngLim,GamMax=GamMax,
\ dc=DC,
\ x=x,y=y,w=w,h=h,
\ omin=omin,omax=omax,
\ Show=Show,Verbosity=Verb)
Scale=1
B_TEXT = RT_String("Scale=%d rMul=%.2f gMul=%.2f bMul=%.2f",Scale,RedMul,GrnMul,BluMul)
B=O.GamMac(LockChan=LockChan,SCALE=SCALE,RedMul=RedMul,GrnMul=GrnMul,BluMul=BluMul,
\ Th=Th,LockVal=LockVal,RngLim=RngLim,GamMax=GamMax,
\ dc=DC,
\ x=x,y=y,w=w,h=h,
\ omin=omin,omax=omax,
\ Show=Show,Verbosity=Verb)
Scale=2
C_TEXT = RT_String("Scale=%d rMul=%.2f gMul=%.2f bMul=%.2f",Scale,RedMul,GrnMul,BluMul)
C=O.GamMac(LockChan=LockChan,SCALE=SCALE,RedMul=RedMul,GrnMul=GrnMul,BluMul=BluMul,
\ Th=Th,LockVal=LockVal,RngLim=RngLim,GamMax=GamMax,
\ dc=DC,
\ x=x,y=y,w=w,h=h,
\ omin=omin,omax=omax,
\ Show=Show,Verbosity=Verb)
COORDS=O.GamMac(dc=DC,x=x,y=y,w=w,h=h,Coords=True)
ODC=((SHOWCOORDS)?COORDS.Spline36Resize(width,Height):O) # Resize COORDS (Not necessarily the same sizse as source clip)
ODC_TEXT=(SHOWCOORDS)?"Detect Clip with Coords":"Original"
TOP=StackHorizontal(Sub(ODC,ODC_TEXT),Sub(A,A_TEXT))
BOT=StackHorizontal(Sub(B,B_TEXT),Sub(C,C_TEXT))
StackVertical(TOP,BOT)
return Last
Function Sub(clip c,string tit) {StackVertical(c.BlankClip(height=20).ScriptClip("""Subtitle(RT_String("%d] %s",current_frame,tit))""",Args="tit",Local=true),c)}
The script as above has created a dummy DC detect clip by Blurring(1.0) and BilinearResize(320,240)
[EDIT: Resize to test DC different size in window display, Blur for no particular reason other than to throw a spanner in the works]
The source clip is 490x360 in size.
Also, SHOWCOORDS=True, to show DC and not the original clip frame.
The Coords shown are relative to the downsize DC clip which was upsized again for display
to match the source clip size.
oMin and oMax set at 5 and 250 respectively (foot and head room for further tweaking).
Below, DC clip shows coords as dotted lines. Pixels outside of the dotted line coords are not considered when
processing the DC frame.
The Blur/Resize test line can be commented out.
https://s20.postimg.cc/bpgwx02nx/gmac1_zpsbq2vafkd.png (https://postimg.cc/image/qlfg4le2h/)
StainlessS
26th October 2016, 00:04
I guess that the nearest existing thing to GamMatch() [posted and linked a few posts earlier] is MatchHistogram() by LaTo:- http://forum.doom9.org/showthread.php?t=153196&highlight=histogram
StainlessS
27th October 2016, 16:57
New version GamMatch v0.02 (NOTE GamMatch, not this thread plugin, but a spinnoff from it).
See MediaFire in my sig below this post.
GamMatch(), [Gamma Matcher] An daft Idea, based upon an extraordinary Idea by VideoFred (the gent from Gent). (Daft idea and code by StainlessS).
The Idea behind the daft idea(GamMac):- http://forum.doom9.org/showthread.php?p=1774281#post1774281
Original Idea:- http://forum.doom9.org/showthread.php?t=173683
RGB Only.
Useful to correct bad color clip where there is a better color source of perhaps lower rez available.
Additional tweaking via RedMul, GrnMul and BluMul multipliers.
GamMatch, Allows to correct a clip that has had Levels + Gamma badly applied, to one of more channels, by using an in
sync version clip with good un-messed with color, but perhaps of inferior resolution.
GamMatch is unlikely to be of any use where eg Tweak or some other non RGB levels type mod has been applied.
What it does(roughly):-
Alter bad source color clip channel minimums, maximums and averages to match dc detect (good color) clip.
GamMatch(Clip c,clip dc,
\ Float "RedMul"=1.0,Float "GrnMul"=1.0, Float "BluMul"=1.0,
\ Float "Th"= 0.04,Float "loTh"=Th,Float "hiTh"=Th,
\ int "RngLim"=11,Float "GamMax"=10.0,
\ int "x"=20,int "y"=20,int "w"=-20,int "h"=-20,
\ Bool "Show"=True,int "Verbosity"=2,Bool "Coords"=false
\ )
c, no default. Bad Color source clip.
dc, no default. Detection clip (good color clip). Must be same ColorSpace and FrameCount as source clip, no other similarities enforced.
RedMul, default 1.0 Red channel multiplier adjustment. [0.1 <= RedMul <= 10.0]
GrnMul, default 1.0 Green channel multiplier adjustment. [0.1 <= GrnMul <= 10.0]
BluMul, default 1.0 Blue channel multiplier adjustment. [0.1 <= BluMul <= 10.0]
Th, Default 0.04 Sets Default for loTh and hiTh. Suggest Default, 0.04(percent). [-1.0(OFF) , or 0.0 -> 1.0]
loTh, Default Th As for Ignore_low in AutoLevels, or Threshold in YPlaneMin. [-1.0, or 0.0 -> 1.0]
Percent, amount of extreme pixels (eg noise) to ignore when finding minimum R, G or B channel values.
-1.0 is OFF, input channel minimum is set to 0 as for levels(0,gamma,input_max, ... ).
If loTh >=0.0, then will scan frame looking for lowest pixel value whose cumulative sum
[including all pixels counts of lower value pixels] is greater than loTh%.
loTh, only shown in metrics if greater or equal to 0.0 ie switched ON (Always shown when Verbosity=3=FULL).
hiTh, Default Th As for Ignore_high in AutoLevels, or Threshold in YPlaneMax. [-1.0, or 0.0 -> 1.0]
Percent, amount of extreme pixels (eg noise) to ignore when finding maximum R, G or B channel values.
-1.0 is OFF, input channel maximum set to 255, as in levels(input_min,gamma,255, ... ).
If hiTh >=0.0, then will scan frame looking for highest pixel value whose cumulative sum
[including all pixels counts of higher value pixels] is greater than hiTh%.
hiTh, only shown in metrics if greater or equal to 0.0 ie switched ON (Always shown when Verbosity=3=FULL).
RngLim, default 11 [1 <= RngLim <= 32]
If ALL THREE RAW input channel ranges ie (ChannelMax(max(hiTh,0.0))-ChannelMin(max(loTh,0.0))) are less than RngLim then
all scaling is disabled, and remapping is linear without gamma estimation, to range omin -> omax,
ie avoid remapping of Black, White frames, or single color frames.
GamMax, default 10.0 Upper value for guess gamma [2.0 <= GamMax <= 10.0]
Starting guess upper range and limit for gamma estimator (probably best left alone).
The lower guess range and limit will be set to 1.0 / GamMax, by default 0.1.
x,y, Both default 20. Area of dc Detect clip frame to sample when getting averages and estimating Gamma function, allows to ignore rubbish at frame edges.
w,h, Both default -20. Specified as for crop eg x=10,y=20,w=-30,h=-40, as in crop(10,20,-30,-40).
Show, default true True, show metrics info on frame.
Verbosity, default 2 0 = Only upper frame metrics Flags line only
1 = Upper frame metrics
2 = Upper + important ones. (default)
3 = Nearly Full metrics.
4 = Full Metrics except version info
5 = Full Metrics including version info
Upper frame metrics shown as eg:- (when Verbosity=5=FULL)
nnnnn] Flags:- SR
R G B
DC: 0,255 0,255 0,255
DC_AVE: 110.423 98.284 97.997
RAW: 8,247 12,223 18,239
IN: 8,247 12,223 18,239
IN_AVE: 104.545 120.037 149.821
SCALED: 103.008 130.566 152.102
GAMMA: 1.099 0.659 0.495
OUTAVE: 110.416 98.282 97.986
where,
nnnnn, is the frame number.
Flags:- (Specific to current frame, can change frame to frame)
'S' = Scale, mode signified by color.
Greyed out. Scale = 0(No Effect). May be Greyed out if all channels Min/Max are 0,255.
White. Scale = 1[Scales input channel average maximum dynamic range of R,G,B]
Orange. Scale = 2[Scales input channel average dynamic range of R and G and B, Individually]
'R' = Limited by RngLim, mode signfied by color.
Greyed out. Not Range Limited.
Red, at least 1 channel has remapping disabled.
DC: Shows comma separated channel minimum and maximum of DC clip(dependent upon loTh, hiTh).
DC_AVE: DC Clip channel averages.
RAW: Shows RAW comma separated channel minimum and maximum, eg ChannelMin(max(loTh,0.0)) and (ChannelMax(max(hiTh,0.0)),
only shown if Verbosity>=3 or, if any RAW input range is less than RngLim AND any of the RAW inputs are different
to the equivalent standard input.
IN: Shows comma separated channel minimum and maximum (dependent upon Scale, loTh, hiTh).
IN_AVE: Input channel averages.
SCALED: Scaled input averages, (dependent upon Scale, loTh, hiTh, channel minimums and maximums).
GAMMA: Estimated gamma to achieve lockval for channel. (dependent upon pretty much everything).
OUTAVE: Output channel average ie rendered result.
DC and DC_AVE derived from DC (Good color clip), all others from clip c (BAD color clip, Incl OUTAVE).
Coords, default False. If True, then shows DC clip with dotted lines showing the x,y,w,h coords plotted on frame. (All other functionality disabled).
New Demo in AVS folder, copes with different sized DC clip.
Got rid of Scale argument, does not really make sense if trying to match to another clip.
No image at the moment, Photobucket seems to be having DNS problems.
EDIT: Managed to kick my way into PhotoBucket via another route
https://s20.postimg.cc/i4fxto9dp/Gammatch_v0_zps8h9khfyf.png (https://postimg.cc/image/mqc220uwp/)
EDIT: The Demo.avs
# Some good color clip
#Avisource("F:\v\StarWars.AVI")
Avisource("1941 Flint Michigan Parade [Low, 360p].mp4.AVI")
ConvertToRGB24.KillAudio
DC=Last
# Simulate bad Input clip
RED=ShowRed(Pixel_Type="Y8").Levels( 0,0.8,255, 8,247,coring=false)
GRN=ShowGreen(Pixel_Type="Y8").Levels(0,1.5,255,12,223,coring=false)
BLU=ShowBlue(Pixel_Type="Y8").Levels( 0,2.0,255,32,239,coring=false)
MergeRGB(RED,GRN,BLU,pixel_Type="RGB24")
# Simulate DC Low res clip with good color
DC=DC.Blur(1.58).Blur(1.58).Spline36Resize(320,240) # Fake change of size for detect
O=Last
RedMul = 1.0 # Required Ave multiplier for Red Channel, applied when requesting GuessGamma(reqAve*RedMul), Even applied when LockChan=-1.
GrnMul = 1.0 # Same for Green channel. GrnMul even applies when LockChan is Green Channel, etc for chans.
BluMul = 1.0 # Same for Blue channel. Allows tinkering/fine tuning.
Th = 0.04
RngLim = 11
GamMax = 10.0
Verb = 5 # Verbocity FULL
SHOWCOORDS= False
x =5 # Coords (for dc Detection Clip)
y =5
w=-5
h=-5
A_TEXT = RT_String("OUT: rMul=%.2f gMul=%.2f bMul=%.2f",RedMul,GrnMul,BluMul)
A=O.GamMatch(DC,RedMul=RedMul,GrnMul=GrnMul,BluMul=BluMul,
\ Th=Th,RngLim=RngLim,GamMax=GamMax,
\ x=x,y=y,w=w,h=h,
\ Show=True,Verbosity=Verb)
B_TEXT = RT_String("OUT No Metrics: rMul=%.2f gMul=%.2f bMul=%.2f",RedMul,GrnMul,BluMul)
B=O.GamMatch(DC,RedMul=RedMul,GrnMul=GrnMul,BluMul=BluMul,
\ Th=Th,RngLim=RngLim,GamMax=GamMax,
\ x=x,y=y,w=w,h=h,
\ Show=False)
COORDS=O.GamMatch(DC,x=x,y=y,w=w,h=h,Coords=True).Spline36Resize(width,Height) # Resize Coords to same as bad clip for window display
ODC=((SHOWCOORDS)?COORDS:DC).Spline36Resize(width,Height) # Resize COORDS (Not necessarily the same sizse as source clip)
ODC_TEXT=(SHOWCOORDS)?"Detect Clip with Coords":"DC Detect (Match Original to this)"
TOP=StackHorizontal(Sub(O,"Original (Simulated bad clip)"),Sub(A,A_TEXT))
BOT=StackHorizontal(Sub(ODC,ODC_TEXT),Sub(B,B_TEXT))
StackVertical(TOP,BOT)
return Last
Function Sub(clip c,string tit) {StackVertical(c.BlankClip(height=20).ScriptClip("""Subtitle(RT_String("%d] %s",current_frame,tit))""",Args="tit",Local=true),c)}
juanitogan
20th January 2017, 06:20
Thank you, everyone, for this incredible GamMac tool. I was doing something very similar with ImageMagick to recover overexposed scenes, but it was generally too aggressive and lacked temporal smoothing. What GamMac accomplishes is much more sane than what I had done so far. Far faster too. In fact, your results are very close to the autoleveling tool in Paint.NET (what I consider, personally, to be the gold standard in autoleveling -- you should see what Paint.NET does with GamMac's test files).
I seem to have uncovered, however, some occasional strange sensitivity in GamMac. That, or I'm just doing it wrong. GamMac does an incredible job with much of the film I'm working with... but with some scenes, however, GamMac creates a flicker where there is otherwise none. From what I can tell, GamMac appears to be too sensitive in determining the channel min and max.
Here's a link to a 7zip of 32 frames from one of the problem scenes:
https://www.dropbox.com/s/m1p2kccy3shaixk/f1a.7z?dl=0
Note the variations in brightness and values in this mosaic:
https://www.dropbox.com/s/fl42fpzctl92qvg/f1a.jpg?dl=0
In this particular case (a 1949 film), changing the lock channel from green to red stabilizes things quite a bit... but even the red channel is not stable (see frame 18 in my test frames, t003962.png, for example). I tried most of the settings GamMac has to offer but found little effect on the stability of the channel extents -- not in any automatic way, anyhow. Thus, setting Scale=0 (to use the channel averages, which are fairly stable) is the only automatic way I have found thus far to eliminate the flicker when using GamMac. Scale=0, however, seemed less effective overall than the other settings.
One point of suspicion is that the frames with heavy dirt appear to be more at risk for wild min numbers. But, then, there are other frames with wild numbers without heavy dirt. I then suspected maybe something unseen so I looked at these frames in Paint.NET with its Levels tool. Paint.NET autolevels the frames without much variance in channel values (after you strip off the borders like I do in the AVS script; set canvas size: 704 x 472, anchor middle). Furthermore, the autoleveling I was doing through ImageMagick was stable as well. Thus, this is why I suspect the procedures used to find the channel effective extents are too sensitive in GamMac (or something like that).
I've been using johnmeyer's excellent adaption of videoFred's amazing scripts. johnmeyer's script produces far less artifacts in the wake of moving objects with my source. I've added my current test version of his script below. (Ignore the autogamma stuff--it's just something I was playing with to bring out the shadows more in home movies.)
You will see that I was testing GamMac in two places: up front just after border cropping (partly to avoid an extra color conversion), and near the end just before border application.
I must say, putting it up front is a particularly bad idea because it makes all the later filters less effective. It does, however, reveal the issue I'm getting at much more vividly up front. In other words, adding GamMac after all the other filtering tames down the flickering quite a bit but, in my opinion, this is only somewhat hiding the issue and is not a fix to it.
[[[
I can't paste the script inline--too many characters for a single post--so here it is:
https://www.dropbox.com/s/85nvmy9t29el12x/ft.avs?dl=0
]]]
p.s. My source material is from films we sent to just8mm.com. I feel the quality is fair for the price but I will be more than happy to pay twice as much for a place like CinePost next time (which I hadn't yet discovered before). Just8mm didn't frame one of the reels correctly (seen in the samples here) and the source they sent me was a DV AVI -- which would have been okay except that their telecine was running at a very bizarre 19.3-19.8-ish fps. They are obviously asleep at the wheel. I wasted a few days of my life trying to pullup the video back into source frames for processing. Hint:
ffmpeg -y -i 1.avi -vf "pullup,yadif" -vsync 0 -q:v 1 f\t%06d.png
This resulted in some barely-perceptible loss in quality in the frames "pullup" couldn't identify and that "yadif" had to correct. The real trick here was "-vsync 0"... that part took forever to find versus trying to calculate a strange fps (which always led to dupe frames here and dropped frames there) and/or trying various other pullup methods.
videoFred
20th January 2017, 10:56
I seem to have uncovered, however, some occasional strange sensitivity in GamMac.
Hello Juanitogan and welcome to this forum :)
The flickering is caused by the dirt spots and emulsion damage on your source files. Frame 3972 for example. GamMac is detecting a lot of almost pure black pixels on this one.
You can set LoTh pretty high (above 0.40) and the flickering will be almost gone.
You can also use a precleaned clip (detect) for the GamMac analysis, for example with removedirt().
Or you can clean the clip itself, before using GamMac.
PS: You need a better transfer, there is much more detail in those films than what I see on your examples.
many greetings,
Fred.
juanitogan
21st January 2017, 00:48
Hi videoFred, thank you for the welcome. I'm a fan of your digitizers. Even before seeing your work, I was tempted to build my own film scanner. I just can't justify the time with how little I would likely use it. Thank you for sharing your knowledge on that.
Thank you, also, for the loTh hint. I had tested the Th setting but had only gone 2x to 3x of default, if I recall correctly. Setting an extreme loTh does indeed work as you said it would. Apparently, the default is adequate for lighter scenes, dirt or no dirt, but darker scenes like this one require greater measures to account for dirt and other variance. Makes sense. I'll work with it more next week and see where it goes.
Yes, frame 3972 is an obvious example of how dirt affects this. That is the most extreme I have and why I included it in my sample. Yet, frame 3955 appeared to be an anomaly with no visible dirt (and I had many others like 3955). Hence, my suspicions that an algorithm somewhere can maybe be improved. Furthermore, dirt or no dirt, other applications appear to do a better job finding effective extents automatically. But that's just my two cents worth and I'll leave it to others more expert in these filters to figure that out. I hope my sample may be useful for such testing.
Yeah, I need a better transfer -- why I mentioned my experience with just8mm.com -- so others know what to expect from them (and their sister sites: 8mmtodvd.com and dvdmemories.com). This was our first trial with transferring our collection and we sent a few reels to just8mm.com. We'll be trying somewhere with better equipment as budget allows. Supposedly, most of our collection is footage of architecture in Europe, post WWII, because my grandfather was a builder with marble. Not sure when we'll get to that stuff, if ever.
johnmeyer
21st January 2017, 05:34
Yeah, I need a better transfer -- why I mentioned my experience with just8mm.com -- so others know what to expect from them (and their sister sites: 8mmtodvd.com and dvdmemories.com). This was our first trial with transferring our collection and we sent a few reels to just8mm.com. We'll be trying somewhere with better equipment as budget allows. I suggest that you put aside an hour or two to do some researching for promotions and deals on film transfer. Until a few years ago, you are correct that there was usually a big difference between the really cheap local transfer houses; the big chains (like YesVideo, which does the Costco and Walmart transfers); and the true professional labs that use a DataCine scanner.
These high-end scanners cost well over $100,000 so the labs have to charge a lot to recover that cost. A few years ago Blackmagic acquired one of the main companies in the business, and I think they reduced the prices quite a bit. That move, coupled with the natural decline in high-end film transfer business has made many labs very eager to take business such as yours. I have very often seen deals for 8mm, Super 8, and 16mm transfers at prices not much higher than those charged by small labs using Roger Evan's MovieStuff equipment which, while good, can never equal the quality of these "ultimate" transfer units.
So, start locally in NM, and if you can't find something in-state, start looking in Los Angeles where I think you may be surprised at the pricing you can get.
StainlessS
21st January 2017, 11:13
You can also use a precleaned clip (detect) for the GamMac analysis, for example with removedirt().
juanitogan, dont overlook above quote from VideoFred, you could clean the DC detect clip quite aggressively and should still produce good results.
EDIT: Even a simple Blur(1.5) or similar would calm isolated noise pixels and reduce their affect on histograms and amount of correction.
juanitogan
23rd January 2017, 07:54
Thanks for the advice all. Don't worry, though, I may not have tested loTh high enough, but I don't feel like I've overlooked much:
I've been using johnmeyer's excellent adaption of videoFred's amazing scripts. ... You will see that I was testing GamMac in two places... I must say, putting it up front is a particularly bad idea because it makes all the later filters less effective. It does, however, reveal the issue I'm getting at much more vividly up front. In other words, adding GamMac after all the other filtering tames down the flickering quite a bit...
So, yes, I'm already on top of the effects of dirt removal and such with GamMac. I also had already spent some time shopping around for a better service to get a better transfer ("twice as much" is far better than I expected to find for a wet transfer):
I will be more than happy to pay twice as much for a place like CinePost next time
I just thought there was maybe more intel I could contribute.
Thanks again, I'll keep tweaking GamMac.
videoFred
30th January 2017, 12:18
I have just discovered that GamMac also can be used as a deflicker filter, with LockChan -1 . The results are truly amazing!
Fred. :)
StainlessS
26th February 2017, 22:54
GamMac() v1.07, new version, see 1st post [Beta lifted].
v1.07, Bug fixed in GuessGamma(), previously found gamma could have been slightly nearer than result.
EDIT:
Previously implemented something like this
Function GuessGamma(clip c,float reqAveLuma,float "GamHi",Float "GamLo") { # Single Frame Clip only
Assert(c.IsYV12,"GuessGamma: Requires YV12")
gamHi = Default(GamHi,2.0) gamLo = Default(GamLo,1.0/gamHi)
Result = -1.0
ALDif=0.0001
PrevAveL = -1.0
while(GamLo < gamHi) {
gamMid = (gamLo + gamHi) / 2.0
AveL=c.Levels(0,gamMid,255,0,255,coring=false).RT_AverageLuma(0)
if(abs(AveL-PrevAveL)<=ALDif) {
Result = gamMid
gamLo = gamHi + 1.0 # Force Exit, Not getting any nearer
} else if(AveL < reqAveLuma) {
gamLo = gamMid
} else if(AveL > reqAveLuma) {
gamHi = gamMid
} else {
Result = gamMid
gamLo = gamHi + 1.0 # Force Exit, exact match
}
PrevAveL = AveL
}
Return Result
}
Now implemented something like this
Function GuessGamma(clip c,float reqAveLuma,float "GamHi",Float "GamLo") { # Single Frame Clip only
Assert(c.IsYV12,"GuessGamma: Requires YV12")
gamHi = Default(GamHi,2.0) gamLo = Default(GamLo,1.0/gamHi)
Result = -1.0
PrevAveL = -1.0
Bestgmid=GamHi
BestDif=256.0
while(GamLo < gamHi) {
gamMid = (gamLo + gamHi) / 2.0
AveL=c.Levels(0,gamMid,255,0,255,coring=false).RT_AverageLuma(0)
dif=abs(AveL-reqAveLuma)
if(dif<BestDif) {
Bestgmid=gamMid;
BestDif=dif;
}
if(abs(AveL-PrevAveL)==0.0) {
result = Bestgmid
gamLo = gamHi + 1.0 # Force Exit, Not getting any nearer
} else if(dif<0.00001 ) {
result = Bestgmid; # close enough
gamLo = gamHi + 1.0 # break
} else if(AveL>reqAveLuma) {
gamHi = gamMid
} else {
gamLo = gamMid
}
PrevAve=AveL
}
Return Result
}
EDIT: Although above is for YV12 and GamMac is for RGB.
StainlessS
28th February 2017, 03:27
GamMatch() v1.03, new version
v1.03, Bug fixed in GuessGamma(), previously found gamma could have been slightly nearer than result.
NOTE, prev posted GamMac update was posted in wrong folder, ie not available, corrected at MediaFire in Below sig (or also on SendSpace, again below).
See MediaFire link below in sig or SendSpace link.
johnmeyer
8th March 2017, 03:31
I'm late to this game, but I'm in it now.
I have to agree with everyone else: this is a pretty amazing filter.
I have a test clip I created which contains thirty-nine six-frame scenes from a big film transfer job I did a year ago. These clips are the raw capture. Normally I apply a histogram to gain the lower shadows before I feed the video to any script, but I thought it would be best to use a completely unaltered capture. Here is that clip.
Test Clip (http://www.mediafire.com/file/wdkzhv40ejn56w6/test.avi)
I tried to pick different types of issues that represent what I get when transferring old film (most of this is from the 1940s).
This is a 14.98 fps video using the DV codec. This particular DV codec (MainConcept) permits arbitrary frame rates, but still insists on setting the interlaced flag. This video is progressive, however, and you can set any script accordingly.
On about thirty of the thirty-nine scenes, the script works brilliantly. On the rest, there are some issue.
The first issue is that sometimes I get way too much contrast. Here's an example:
Input:
http://i177.photobucket.com/albums/w208/johnmeyer/Before%20Test%202_zpsre2wjgaj.png
GamMac'd
http://i177.photobucket.com/albums/w208/johnmeyer/GamMacd_zpsvcfqeyoc.jpg
I have this problem even on clips without a big chunk of brightness.
The bigger issue is that on some frames I get color that is shifted completely wrong:
Input
http://i177.photobucket.com/albums/w208/johnmeyer/Before%20Test_zpswghgkczx.png
GamMac'd
http://i177.photobucket.com/albums/w208/johnmeyer/Color%20Shift%20GamMac_zpspjwt3696.jpg
As you can see, the input clip has pretty decent color balance, but it would be nice to gain the gamma. However, GamMac turns the fireplace brick a rather unpleasant blue-green. I'm pretty sure the original was an off-white.
I guess I can play around with the various "mul" overrides, but if I have to do that, I might as well balance each scene by hand in my NLE, which is how I've been doing this for the past six years.
I've spent several hours playing around with all the variables, but haven't hit on anything that fixes either of these problems on these scenes. Even if the function can't be used in a "set it and forget it" mode, I was still hoping I could tune it for these problem scenes.
So, in summary:
1. I was hoping for something that would gain the lower (darker) part of the gamma curve, without disturbing the highlights and black point;
2. I was hoping for more consistent color correction.
I'm not complaining, and I will still be able to get lots of use out of this for certain clips.
Here is the test script I'm using. These GamMac settings are pretty close to the defaults, but I have played around with each and every variable in order to learn about the filter, and also try to get better results for the problem scenes:
O=Last
DC=Last
LockChan = -2 # Chan for lock to Ave, 0=R, 1=G, 2=B
# -1 = Use LockVal below.
# -2 = LockVal=(RedAve+GrnAve+BluAve)/3.0 for LockVal.
# -3 = LockVal=Median(RedAve,GrnAve,BluAve)
Scale=2
RedMul = 1.0 # Required Ave multiplier for Red Channel, applied when requesting GuessGamma(reqAve*RedMul), Even applied when LockChan=-1.
GrnMul = 1.0 # Same for Green channel. GrnMul even applies when LockChan is Green Channel, etc for chans.
BluMul = 1.0 # Same for Blue channel. Allows tinkering/fine tuning.
Th = 0.04
loTh = 0.04
hiTh = 0.04
LockVal = 128.0 # Only valid if LockChan == -1
RngLim = 11
GamMax = 10.0
Show = True # Metrics
Verb = 2 # Verbocity FULL
SHOWCOORDS= True # Show Original with Coords
x =20 # Coords (for dc Detection Clip)
y =20
w=-20
h=-20
omin=0 # Output channels minimum (footroom for manual editing).
omax=255 # Output channels maximum (headroom for manual editing).
source=AVISource("E:\fs.avi").KillAudio()
output=GamMac(source,LockChan=LockChan,SCALE=SCALE,RedMul=RedMul,GrnMul=GrnMul,BluMul=BluMul,
\ Th=Th,LockVal=LockVal,RngLim=RngLim,GamMax=GamMax,
\ dc=DC,loTh=loTh,hiTh=hiTh,
\ x=x,y=y,w=w,h=h,
\ omin=omin,omax=omax,
\ Show=Show,Verbosity=Verb)
#return output
#stackhorizontal(source,output)
#/*
return Interleave(
\ source
\ , output
\ )
#*/
StainlessS
8th March 2017, 07:59
Hi John, give it a bash with Scale=1.
Scale=2, scale primaries individually giving in those cases color shift.
There is probably a big min/max range difference between the primaries.
I'll get your test clip and some point but not just yet.
EDIT: I got your clip John, Nice test clip (and not too big), thanx.
EDIT: John, request:, can post any further SOURCE images in this thread as png, result can be jpegs, thanx.
EDIT: John, can you repost or PM both those source images as png please (and verify is GamMac v1.07).
johnmeyer
8th March 2017, 17:27
I have appointments this morning. Should be back at my editing computer about noon, my time (8:00 p.m. your time, I think). I'll re-post roughly the same pics (I was just copy/pasting from NLE timeline, so the only way to avoid JPEG is to go back to the source). You now have the original AVI (it was losslessly cut from the original material), so you can get to the original color and avoid the compression artifacts by using that. I don't think I included the exact frames that I used for the still shots, but you do have six frames from the same scene.
P.S. I just noticed that none of the images I posted are showing up. Photobucket must be having problems. They displayed fine last night when I previewed and then posted. I guess I'll try uploading to this site.
johnmeyer
8th March 2017, 22:10
OK, I changed the two "input" photos, in my post above, to PNG. The GamMac'd versions are still JPEG. Photobucket is working again this afternoon, after having been flaky the past 24 hours. Hopefully it will work for you.
Bernardd
9th March 2017, 10:09
Hello,
In my opinion, GamMac is a tool that allows to correct the colors according to the theory of the gray world. It seeks, in fact, the equality between the mean values of each channel.
For the images of the young children in front of the chimney, I think that the gray world theory is not adapted to this case. ColorYUV (autowhite = true) give also a green
dominant at the fireplace.
With this script, ( https://forum.doom9.org/showthread.php?p=1797799#post1797799 ) which exploits the RGBAdapt plugin, a autogain function allows you to change the colors independently of the gray world theory.
As the work is in RGB espace, this autogain reinforces light and darkness but also the colors. Its application may be a solution for scenes such as the chimney or on the beach.
Bernard
(google traduction)
videoFred
9th March 2017, 12:18
With this script, ( https://forum.doom9.org/showthread.php?p=1797799#post1797799 ) which exploits the RGBAdapt plugin, a autogain function allows you to change the colors independently of the gray world theory.
As the work is in RGB espace, this autogain reinforces light and darkness but also the colors. Its application may be a solution for scenes such as the chimney or on the beach.
Hello Bernard,
Can you show us a result of your script applied on these specific frames?
Fred.
videoFred
9th March 2017, 12:40
The first issue is that sometimes I get way too much contrast.
Hi John, this can be solved with oMin and oMax (see examples)
The bigger issue is that on some frames I get color that is shifted completely wrong
Yes, I have the same problem on some frames and I think it happens when one color is dominating.
As you can see, the input clip has pretty decent color balance, but it would be nice to gain the gamma. However, GamMac turns the fireplace brick a rather unpleasant blue-green. I'm pretty sure the original was an off-white.
On this specific frame, the red channel is dominant. When set LockChan to 0 (red) the green cast is better, but still not perfect:
http://www.super-8.be/Doom/247_test_John_Meyer000135.jpg
It needs more specific "mul" settings to be correct:
http://www.super-8.be/Doom/247_test_John_Meyer000136.jpg
I wonder if a smart guy like StainlessS can see some consistency in all these values. :confused:
Anyhow, it might be an idea to add a "auto lockchan" option. If one color is realy dominating, lockchan should lock on that color.
It's very obvious on this frame for example:
http://www.super-8.be/Doom/247_test_John_Meyer000077.jpg
But the color dominance is sometimes changing from frame to frame so I do not know if it can be done without flickering effects etc... Also, estimated gamma will be pretty high.
Fred.
Bernardd
9th March 2017, 15:05
Below three results of script
two first given with only gain_strength = 0.8
https://www.dropbox.com/s/ogj4emqu2jt1xl3/cheminee.png?dl=0
https://www.dropbox.com/s/cosk1qfjarhjreq/Plage.png?dl=0
the last given with default args gain_strength = 1.0, rpow_strength = 1.0 and bias_strength = 1.0
https://www.dropbox.com/s/57qzp5o4ck5jmsp/neige.png?dl=0
Bernard
johnmeyer
9th March 2017, 18:10
Below three results of scriptThe first two results are very, very good. The last is not good.
Do you have a list of plugins required for your script?
Hi John, this can be solved with oMin and oMax (see examples)...I thought I had tried that, but I'll go back and try again. Thanks for that help.
On this specific frame, the red channel is dominant. When set LockChan to 0 (red) the green cast is better, but still not perfect:That result looks exceptionally good. Once again, I thought I had tried that.
I don't mind too much if I have to run the script several times with different settings. I often create 2-3 versions of a given film and then line them up on the NLE timeline. I quickly scrub through the version that gives me the best result for the majority of the film, and when that fails, I switch to one of the other versions. It obviously takes more computer time, but since I can do other things while the computer cranks, it is not too much of a problem.
I'll go back and "play around" with the settings some more, now that I have these hints.
videoFred
9th March 2017, 19:17
I often create 2-3 versions of a given film and then line them up on the NLE timeline. I quickly scrub through the version that gives me the best result for the majority of the film, and when that fails, I switch to one of the other versions.
Yes, this is the way to go until we have a perfect all automatic script (probably impossible).
Have you ever tried ClipClop John? Another StainlessS idea and it works like a charm.
Fred.
videoFred
9th March 2017, 19:20
Below three results of script
I agree with John: cheminee.prg looks very, very good Bernard.
I will see if I can get your script running here.
Fred.
Bernardd
9th March 2017, 19:41
The script is based on StainlessS's RGBADapt plugin http://forum.doom9.org/showthread.php?t=170642
It need StainlessS's RT_Stats plugin http://forum.doom9.org/showthread.php?t=165479
It need Gavino's GRunT plugin http://forum.doom9.org/showthread.php?t=139337 and GScript plugin http://forum.doom9.org/showthread.php?t=147846
Bernard
StainlessS
9th March 2017, 19:56
I am chewing on it. (tis very chewy, my jaws are aching :) )
Bernardd
9th March 2017, 20:29
In my script, gain fonction uses channel MinMaxDiff values. In extraction process for these datas Rt_Stats has a Threshold arg
which is a percentage, stating how many percent of the pixels are allowed below minimum or above maximum.
For Rt_Stats default threshold value is 0.0, in my script default value is 0.10, but with 0.50 for snow scene the ouput is below.
https://www.dropbox.com/s/thuy67k2kqxo8pp/neige2.png?dl=0
Bernard
johnmeyer
9th March 2017, 21:38
Have you ever tried ClipClop John? Another StainlessS idea and it works like a charm. Fred.I am aware of it, and as he was developing it I skimmed the thread. For this particular situation, I'm not sure it would save any time compared to doing the work in my NLE (Vegas Pro) which has a built-in multi-camera capability. I can view many versions, playing all at once, and cut between them (I can even do this while playing) simply by pressing a single key on the keyboard that has been assigned to that camera. I can immediately undo anything I don't like, or can "slip" the edit point one way or the other. I can also cross-fade between cameras. This is useful in this particular situation if I want to make less obvious and less abrupt the transition between two different corrections.
StainlessS
10th March 2017, 09:44
For Rt_Stats default threshold value is 0.0, in my script default value is 0.10, but with 0.50 for snow scene the ouput is below.
RT_Stats Threshold and GamMac Th, (or individual set loTh, and hiTh) are pretty much the same thing. JFYI.
videoFred
10th March 2017, 10:30
The script is based on.......
Yes, I know. Are you sure you have posted a good working script Bernard? I'm getting GScript syntax errors on lines 82, 149, 342 and 410. Might be a copy/paste error.. Can you upload your script in one part somewhere?
Fred.
Bernardd
10th March 2017, 11:10
Fred,
in DropBox, script file
https://www.dropbox.com/s/yis4gwsdb0ditkf/RGBAdapt_AWB_Process.avs?dl=0
Bernard
videoFred
10th March 2017, 12:21
I got it working Bernardd!
I'm using it with AvsPmod so it's easy to change parameters.
I have no time now, but later I will compare the results with the GamMac results.
Perhaps we should start a new thread about your script only?
I do not want to hijack this thread.
Fred.
Bernardd
10th March 2017, 20:24
Fred,
I suggest you use the RGBAdapt v0.3 plugin 17 June 2015 thread, because my script exists through this plugin.
This of course, if my script writing teacher, Mr. StainlessS, agrees.
Bernard
StainlessS
10th March 2017, 21:19
Bernardd, it would have been a good idea right from the start to have your own thread for your awb.
Mobile
EDIT: It does deserve it.
StainlessS
14th March 2017, 14:15
OK, no real consistent way I can think of to detect if eg RED in fireplace kids romp suits is due to color cast or because its supposed to be red,
(red min is not reliable detection compared to grn, blu, min).
The GamMac 'thing', is intended to detect and correct color cast and so will produce color shift by intention.
Playing with Th can perhaps improve results some (Th of default 0.04%, intended to ignore a few noise pixels).
Setting Th, to value of 0.0 (not ignoring of a few noise pixels, detect real min,max pixels in image), to avoid over contrast'ed result.
Setting Th, to value of -1.0, sets input min=0, max=255, ie no input scaling, full input range.
Perhaps default Th should be 0.0 to detect real min,max pixel values, make user select Th to ignore when required
(what say you Fred ?, Th=0.0 is least destructive).
Here some results with non default Th.
Th= -1.0 (All 3 Scale results identical due to full range input 0->255)
https://s20.postimg.cc/51kbaej5p/Th-1_zpshd9uspff.png (https://postimg.cc/image/vze8c53sp/)
Th=0.0 (Scale=1 looking best to me, best color shift, perhaps better still with omin=0, and omax=255, bit more contrast)
https://s20.postimg.cc/s4au9kkn1/Th0_zpsqcfnrx83.png (https://postimg.cc/image/4q2uxn2pl/)
Th=-1.0 (All 3 Scale results identical due to full range input 0->255)
https://s20.postimg.cc/4rcsr24jh/Kids-_Th-1_zpslxy4mgx3.png (https://postimg.cc/image/afj3hy8vt/)
Th=0.0 (IN: is the min and max RAW: input, of any channel, for Scale=0 and 1)
https://s20.postimg.cc/ubf2xhpx9/Kids-_Th0_zps6dbsc71c.png (https://postimg.cc/image/433y845tl/)
NOTE, where Th= -1.0, all output results same (Scale dont matter), input range is 0->255, however outputs are in above case
range omin(5) -> omax(250) to allow headroom for tweak.
EDIT: Note, the fireplace image, the source fireplace seems a little pink to me (so do the kids faces).
EDIT: Above are by no means perfect, but suggest maybe that Th=0.0 should be default.
The R,G and B Mul args have not been used above, but could provide further correction where needed.
EDIT: All above using non default LockChan= -2, ie Scaled Channel Average (as in John Meyer's post).
EDIT: John, are you really capping in YUV 411, as per sample AVI (would not RGB be better, or was 411 just for post) ?
Magik Mark
8th April 2017, 05:57
Not sure if this has been answered. Can I use this in staxrip? Planning to experiment this with HD videos and see if I could still improve the image
Sent from my iPhone using Tapatalk
StainlessS
8th April 2017, 13:19
Can I use this in staxrip?
It is just an Avisynth plugin filter, assuming staxrip can use Avisynth filters, then I dont see any problem.
Sorry, no idea, never used StaxRip myself, perhaps someone else could give better answer.
Groucho2004
8th April 2017, 13:41
Sorry, no idea, never used StaxRip myself, perhaps someone else could give better answer.
I have not used it either but I do know that it uses 64 bit Avisynth only which means no, you can't use this filter with staxrip.
Magik Mark
8th April 2017, 14:23
Is it possible to recompile a 64bit version?
Thanks
StainlessS
8th April 2017, 14:34
I'll give it a go, but your gonna have to be the tester (I'm on XP32).
Magik Mark
8th April 2017, 15:01
Thanks guys [emoji106]
Sent from my iPhone using Tapatalk
Groucho2004
8th April 2017, 15:20
Is it possible to recompile a 64bit version?
Here it is (https://www.dropbox.com/sh/6kb3723po5oqd4b/AADbP8gIJ3YrHVoLU3joqJDma?dl=0) (modified source included).
Necessary source modifications:
- Latest AVS+ headers
- Entry point updated to AvisynthPluginInit3.
StainlessS
8th April 2017, 16:14
Cheers Grouchy, having trouble re-installing Platform SDK, (64bit was not installed, and keeps telling me it cant find some readme type html, then gives up with error,
the file it cant find is exactly where is says it looked so error is a mystery).
Magik Mark
9th April 2017, 00:20
Thanks for the 64bit!
I will be doing some experiment on HD sources. Just would like to clarify the ff:
1. Convert video first to RGB. Is it RGB24 or RGB 32?
2. Run GamMac
3. Convert back to YV12
Am I right?
StainlessS
9th April 2017, 00:56
Yes, GamMac works only in RGB (either flavour), and back to YV12, if that is what you require.
Magik Mark
9th April 2017, 05:21
Thanks a lot [emoji106]
Sent from my iPhone using Tapatalk
Magik Mark
11th April 2017, 00:22
Works very well and fast in staxrip. Experimented with HD videos with "green and red push", it almost cleared them away.
Is there a way to minimize the "clearing" of color cast? Movies like the matrix is intentionally greenish. However, it improves shadow detail significantly
StainlessS
11th April 2017, 01:24
Is there a way to minimize the "clearing" of color cast? Movies like the matrix is intentionally greenish.
Yep, dont use it.
The whole purpose is to correct those that are eg un-intentionally greenish, why would you be using it on non faded clips ?
Magik Mark
11th April 2017, 02:31
Well, it also improve shadow details
Sent from my iPhone using Tapatalk
StainlessS
11th April 2017, 19:03
You would get better results using some plug intended for your requirement, eg AutoLevels [EDIT: AutoAdjust] ,
HdrAgc, SmoothAdjust, or similar.
videoFred
12th April 2017, 12:19
I have done some more testings lately.
To avoid over-adjusting on problematic scenes like complete black frames, scenes with blue sky etc, I'm using a special prepared detect clip.
Here I added some pure black and pure white pixels to the detect clip. Size from the squares can be set with AvsPmod sliders.
http://www.super-8.be/Doom/GamMac_New_detect_01.jpg
http://www.super-8.be/Doom/GamMac_New_detect_02.jpg
This works very well to "soften" the Gammac adjusting on dark and/or complete black frames. And also on frames with a lot of pixels with the same color.
But when it comes to color corrections, we must use another trick. :D
This code will calculate the average color from a frame, and then invert it:
Average = baseclip.ScriptClip(""" u=round(AverageChromaU()) v=round(AverageChromaV()) BlankClip(last, color_yuv=65536*128 + 256*u + v) """).invert()
If we now make a square from it and add it to the detect clip, we get this:
http://www.super-8.be/Doom/GamMac_New_detect_05.jpg
As you see, colors are now correct and GamMac is still adusting contrast very well. With correct size settings, the colored square can stay on the detect clip on an entire clip,
even on not problematic scenes. Then the effect is negligible.
Some more examples:
http://www.super-8.be/Doom/GamMac_New_detect_03.jpg
http://www.super-8.be/Doom/GamMac_New_detect_04.jpg
And last but not least Johns legendaric fireplace frame:;)
http://www.super-8.be/Doom/GamMac_New_detect_06.jpg
As you see I'm using ScriptClip for calculating the average color. But unfortunately ScriptClip is not working in Avisynth+ when in MT mode. Do we have an alternative for ScriptClip?
Fred.
StainlessS
12th April 2017, 14:41
Average = baseclip.ScriptClip(""" u=round(AverageChromaU()) v=round(AverageChromaV()) BlankClip(last, color_yuv=65536*128 + 256*u + v) """).invert()
So both input and output are YUV, and also output same size as BaseClip ? (GamMac is RGB only).
I'll see what I can come up with, I'll leave any Invert() and resize to other filters.
EDIT: Standard 8 bit in/out only, also not gonna do a v2.5 plug, 2.6 only.
StainlessS
12th April 2017, 16:52
FredAverage, (not to be confused with RedAverage).
Avisynth v2.6 only plugin.
ColorSpace, YV12, YV16, and YV24 only.
Return clip U and V will be channel averages. Result luma Y will depend upon Y arg.
FredAverage(clip c, int "Y")
Y, Default -1 == sampled average. Otherwise (0 -> 255) Luma Y set to given Y.
Returns clip same colorspace and size as input.
EDIT: Oops, should have mentioned that U and V are sampled averages. BLUE text added.
EDIT: source code
/*
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
// FredAverage v 0.0
#include "Compiler.h"
#include <windows.h>
#include <stdio.h>
#include "avisynth.h"
class FredAverage : public GenericVideoFilter {
const int Luma;
public:
FredAverage(PClip _child,int _luma,IScriptEnvironment* env) : GenericVideoFilter(_child), Luma(_luma) {}
~FredAverage(){}
PVideoFrame __stdcall GetFrame(int n, IScriptEnvironment* env);
};
PVideoFrame __stdcall FredAverage::GetFrame(int n, IScriptEnvironment* env) {
n = (n<0) ? 0 : (n>= vi.num_frames) ? vi.num_frames - 1 : n; // range limit n
PVideoFrame src = child->GetFrame(n, env);
int x,y;
int setY = Luma;
if(setY < 0) {
const int spitch = src->GetPitch(PLANAR_Y);
const int sheight = src->GetHeight(PLANAR_Y);
const int srowsize = src->GetRowSize(PLANAR_Y);
const BYTE * srcp = src->GetReadPtr(PLANAR_Y);
__int64 acc = 0;
unsigned int sum = 0;
for(y=sheight;--y>=0;) { // sum y
for(x=srowsize;--x>=0;) {
sum += srcp[x];
}
if(sum & 0x80000000) { acc += sum; sum=0; }
srcp += spitch;
}
acc += sum;
int ysamples = srowsize * sheight;
setY = int(double(acc) / ysamples + 0.5); // y average
}
const int spitchUV = src->GetPitch(PLANAR_U);
const int sheightUV = src->GetHeight(PLANAR_U);
const int srowsizeUV = src->GetRowSize(PLANAR_U);
const BYTE * srcpU = src->GetReadPtr(PLANAR_U);
const BYTE * srcpV = src->GetReadPtr(PLANAR_V);
__int64 accU = 0,accV = 0;
unsigned int sumU = 0,sumV = 0;
for(y=sheightUV;--y>=0;) { // sum u and v
for(x=srowsizeUV;--x>=0;) {
sumU += srcpU[x];
sumV += srcpV[x];
}
if(sumU & 0x80000000) { accU += sumU; sumU=0; }
if(sumV & 0x80000000) { accV += sumV; sumV=0; }
srcpU += spitchUV;
srcpV += spitchUV;
}
accU += sumU;
accV += sumV;
int samples = srowsizeUV * sheightUV;
int aveU = int(double(accU) / samples + 0.5); // u an v averages
int aveV = int(double(accV) / samples + 0.5);
//
PVideoFrame dst = env->NewVideoFrame(vi);
const int dpitch = dst->GetPitch(PLANAR_Y);
const int dheight = dst->GetHeight(PLANAR_Y);
const int drowsize = dst->GetRowSize(PLANAR_Y);
BYTE * dstp = dst->GetWritePtr(PLANAR_Y);
for(y=dheight;--y>=0;) { // set return clip luma to setY (tested average or user set)
for(x=drowsize;--x>=0;) {
dstp[x] = setY;
}
dstp += dpitch;
}
const int dpitchUV = dst->GetPitch(PLANAR_U);
const int dheightUV = dst->GetHeight(PLANAR_U);
const int drowsizeUV= dst->GetRowSize(PLANAR_U);
BYTE * dstpU = dst->GetWritePtr(PLANAR_U);
BYTE * dstpV = dst->GetWritePtr(PLANAR_V);
for(y=dheightUV;--y>=0;) { // set return clip U and V to rounded average of source.
for(x=drowsizeUV;--x>=0;) {
dstpU[x] = aveU;
dstpV[x] = aveV;
}
dstpU += dpitchUV;
dstpV += dpitchUV;
}
//
return dst;
}
AVSValue __cdecl Create_FredAverage(AVSValue args, void* user_data, IScriptEnvironment* env) {
PClip child = args[0].AsClip();
const VideoInfo &vi = child->GetVideoInfo();
if(!(vi.IsYV12() || vi.IsYV16() || vi.IsYV24())) env->ThrowError("FredAverage: YV12, YV16 and YV24 Only");
if(vi.width==0) env->ThrowError("FredAverage: Clip has no video\n");
int y=args[1].AsInt(-1); // WAS int y=args[0].AsInt(-1);
if(y < -1 || y> 255) env->ThrowError("FredAverage: Illegal Y arg(%d)\n",y);
return new FredAverage(child,y,env);
}
/* New 2.6 requirement!!! */
// Declare and initialise server pointers static storage.
const AVS_Linkage *AVS_linkage = 0;
/* New 2.6 requirement!!! */
// DLL entry point called from LoadPlugin() to setup a user plugin.
extern "C" __declspec(dllexport) const char* __stdcall
AvisynthPluginInit3(IScriptEnvironment* env, const AVS_Linkage* const vectors) {
/* New 2.6 requirment!!! */
// Save the server pointers.
AVS_linkage = vectors;
env->AddFunction("FredAverage", "c[y]i", Create_FredAverage, 0);
return "`FredAverage' FredAverage plugin";
// A freeform name of the plugin.
}
EDIT: Attachment removed. Fixed in BLUE.
videoFred
12th April 2017, 18:58
So both input and output are YUV, and also output same size as BaseClip ? (GamMac is RGB only).
Of cource I change color space from input and detect clip to RGB before running GamMac. BaseClip is the cropped source clip as you can see in the examples. But GamMac is applied on the full size source clip.
Fred.
videoFred
12th April 2017, 19:03
FredAverage
;) Thank you very much Sir StainlessS!
Fred.
StainlessS
12th April 2017, 19:17
Fred, I made y=-1, the default to be more generally useful.
Mobile.
videoFred
12th April 2017, 19:37
Fred, I made y=-1, the default to be more generally useful.
Mobile.
It works fine in default StainlessS!
I have played with Y but I see no difference?
Fred.
StainlessS
12th April 2017, 19:52
If you set y to eg 16, then should be pretty much black result of FredAverage, but with illegal yuv combinations.
(Unless bugged).
Mobile.
Edit: OK I understand that you mean for gamac use it still works like y= 128.
StainlessS
12th April 2017, 20:24
Fred, would rgb average be preferable, instead, with/without built in invert ?
videoFred
12th April 2017, 22:07
Fred, would rgb average be preferable, instead, with/without built in invert ?
I do not know... But perhaps RGB average would be more accurate because we are working in RGB for GamMac anyhow? Build in invert would be nice too.
Fred.
StainlessS
14th April 2017, 00:42
Fred, have posted FredAverage(), as new plugin here:- https://forum.doom9.org/showthread.php?t=174520
Unfortunately, original version v0.0 was broken, removed (used args[0].AsInt(-1) instead of args[1].AsInt(-1), ie accessed clip instead of 'Y' arg).
Guess I was in too big a hurry to catch my bus ( sorry :( ).
Anyways, original attachment removed, but left [EDIT: fixed] source in-situ, perhaps of some use.
New version linked, copes with All v2.6 standard colorspaces.
videoFred
14th April 2017, 09:31
Thank you StainlessS! :thanks:
I will ask the Belgian Monks to brew a special beer for you :D
Fred.
CkJ
14th April 2017, 15:24
Original
https://i.imgbox.com/R2IZvxV2.png
Gammac
https://i.imgbox.com/pJHB7GDp.png
Gammac with FredAverage detect clip
https://i.imgbox.com/xp7I6Zav.png
I still get some chroma bugs. Is there any way to fix it? :thanks:
StainlessS
15th April 2017, 03:20
My attempt was no better than yours.
Here some of GamMac demo settings
Imagesource("Original.png",end=0)
ConvertToRGB24.KillAudio
O=Last
DC=Last
# Test DC can be different size
#DC=DC.Blur(1.0).BilinearResize(320,240) # Detection Clip Can be different size(uses source clip if dc not supplied, Denoised or whatever)
LockChan = 1 # Chan for lock to Ave, 0=R, 1=G, 2=B
# -1 = Use LockVal below.
# -2 = LockVal=(RedAve+GrnAve+BluAve)/3.0 for LockVal.
# -3 = LockVal=Median(RedAve,GrnAve,BluAve)
Scale=0
RedMul = 1.0 # Required Ave multiplier for Red Channel, applied when requesting GuessGamma(reqAve*RedMul), Even applied when LockChan=-1.
GrnMul = 1.0 # Same for Green channel. GrnMul even applies when LockChan is Green Channel, etc for chans.
BluMul = 1.0 # Same for Blue channel. Allows tinkering/fine tuning.
Th = 0.0
LockVal = 128.0 # Only valid if LockChan == -1
RngLim = 11
GamMax = 10.0
Show = True # Metrics
Verb = 5 # Verbocity FULL
SHOWCOORDS=true # Show DC detect clip instead of original
x =5 # Coords (for dc Detection Clip)
y =5
w=-5
h=-5
SZ=196
DBLK=DC.Crop(x,y,w,h).FredAverage(true).BilinearResize(SZ,SZ)
DC=DC.Overlay(DBLK,x=(Dc.Width-DBLK.Width)/2+48,y=(Dc.Height-DBLK.Height)/2+64)
omin=0 # Output channels minimum
omax=255 # Output channels maximum
https://s20.postimg.org/ktfbxg48t/Mod_zpssgegfu57.png (https://postimg.org/image/cb5vt3xq1/)
For the grassy/seaweed bits, looks to me like maybe YUV quantizer has thrown away a lot of the detail and when removing color cast, you are left
with a chroma blob. Nasty red halo too around the figure.
No idea what to do with it.
CkJ
15th April 2017, 11:22
Hi StainlessS,
I would like to use GamMac for non old 8mm films. I realized that gammac give me a better result than original if fredaverage(invert=false) detect is blue. So how can I apply GamMac only when fredaverage(invert=false) detect is blue? :thanks:
Original
https://i.imgbox.com/lXTAijjP.png
https://i.imgbox.com/D6D2Kmsn.png
https://i.imgbox.com/OCXy3haY.png
FredAverage(invert=false)
https://i.imgbox.com/zhiGSR2v.png
https://i.imgbox.com/wn4t3cnZ.png
https://i.imgbox.com/pRkOGTCj.png
GamMac
https://i.imgbox.com/pHXk5lYT.png
https://i.imgbox.com/aU1B2YD9.png
https://i.imgbox.com/Y8OvVAVW.png
StainlessS
15th April 2017, 12:17
The whole purpose of the FredAverage() plug is to inhibit GamMac() a little, and so must have Invert=true to work.
The Default of Invert=false is because that seems to be more generally useful (not for GamMac).
With Invert=false, it would probably have little effect, GamMac works already on the frame averages, and that is what FredAverage gives as result, so, probably waste of time doing that. GamMac with FredAverage(invert=false), is useless.
EDIT: You could probably replace ALMOST all of the detect clip with FredAverage(Invert=False) and find very little difference,
so long as there were some R, G, and B minimums and maximums that were close to those in the original dclip.
FredAverage(Invert=true), is actually a very good solution to provide FeedBack into the loop, to dampen
the GamMac effect, it is easily controllable via user sizing of FredAverage clip, (with maybe sliders in AvsPMod), and feedback
changes with every frame, to do similar via some additional args to GamMac would be tricky and a lot less easy to use than
Fred's solution (nice one Fred) .
CkJ
15th April 2017, 13:01
You're right, FredAverage(invert=false) is useless for GamMac. But my original meaning is not say about that. I meant if I can use FredAverage as a ConditionalFilter to apply GamMac when needed or not. If yes then how to do? :)
StainlessS
15th April 2017, 13:17
Nope, it dont do that, it just provides a clip with frame average color (or inverted), no other functionality.
No idea how you would implement some magical conditional filter that knows when a frame looks wrong.
EDIT: And your frames looked just fine to me, looked like the blueness was intentional for atmosphere .
videoFred
15th April 2017, 19:32
I have no time to show an example now, but it works much better when the result of FredAverage() is added to the detect clip as a random border, instead of a square box in the middle of the picture. I create the border by making a FredAverage clip from the source file, then resize and align the detect clip in the middle of the FredAverage clip. This way, I can create borders starting from 2 to..... pixels.
Fred.
StainlessS
16th April 2017, 16:43
I have no time to show an example now, but it works much better when the result of FredAverage() is added to the detect clip as a random border, instead of a square box in the middle of the picture.
Not sure that the above can be correct, only the area of the FredAverage clip (in relation to the detect clip area) could have any effect. But it may be preferable to see the detect clip center region rather than a square blob of color.
EDIT:
You may have to be careful if using given demo script,
[ie give dclip coords to GamMac as 0,0,0,0 if already cropped off border rubbish and replaced with FredAverage border,
otherwise GamMac will ignore dclip coords of FredAverage border].
videoFred
16th April 2017, 21:00
Not sure that the above can be correct, only the area of the FredAverage clip (in relation to the detect clip area) could have any effect. But it may be preferable to see the detect clip center region rather than a square blob of color.
Yes, I have not explained well. :o
Of cource the detect clip IS the FredAverage clip with the overlay. First, I crop the source clip to the coords I want. This is the source clip for FredAverage. Then I create the FredAverage clip. Then I resize the already cropped source clip, and overlay it (aligned to the center) over FredAverage.
Here we go:
Baseclip = dirt.crop(borderV,borderH,-borderV,-borderH,align=true).bicubicresize(newWfast,newH4)
Average= baseclip.FredAverage(invert=true)
Over = baseclip.bicubicresize(width(baseclip)-(al2)*2,height(baseclip)-(al2)*2)
Detect= overlay (Average, Over, x=al2,y=al2).converttoRGB24(matrix="rec709")
Dirt= source with Removedirt()
BorderV and borderH = coords for GamMac
NewWfast and NewH4 = I prefer a fixed size for the GamMac detect clip because my source can be very different in size. NewWfast is fixed to 608 pixels, NewH4 is calculated before in the script to have the same aspect ratio as the source.
Al2 is the width from the wanted borders, or you could say the amount of the feedback to the GamMac loop.
EDIT:
You may have to be careful if using given demo script,
[ie give dclip coords to GamMac as 0,0,0,0 if already cropped off border rubbish and replaced with FredAverage border,
otherwise GamMac will ignore dclip coords of FredAverage border].
Correct. I was aware of this. :)
Fred.
videoFred
28th April 2017, 18:28
For some strange reason FFMpeg is not opening Avisynth scripts with GamMac().
I get no FFMpeg error message: it's freezing.
The same scripts are opening fine when GamMac() is disabled.:confused:
EDIT: it' the last version of Gammac that causes the problem: vs 1.07
version 1.06B6 is running fine in FFMpeg
Fred.
StainlessS
29th April 2017, 12:24
Fred, I see you there.
Can you give script, ffmpeg command, and ffmpeg version please.
How long before freeze, straight away or some time into encode ?
videoFred
29th April 2017, 13:09
Hello StainlessS,
I will do this as soon as possible. ;)
Edit: the freeze is straight away.
Fred.
StainlessS
29th April 2017, 15:05
I'm not having any problems with it.
Here a mod I've was working on but with some debug output (dll In the DEBUGGING folder),
wiithout debugging in folder root).
Try without first, if problems then PM me link to some of the debug output.
You would need DebugView to capture debug output (from sysInternals [MicroSoft] Google it).
Here, temp link:- LINK DELETED
EDIT: Well actually just need last few hundred lines of debugging (very last line will probably tell where problem is).
videoFred
29th April 2017, 19:35
First, I'm using this simple testscript:
A = Avisource("Z:\VDP\VdP_Sp2.avi").converttoRGB24().trim(0,100)
B = A.Gammac()
B
And this ffmpeg command line:
ffmpeg -i test.avs -c:v prores -profile:v 3 -an c:\output.mov
pause
As said before, ffmpeg is freezing at the very start with GamMac v1.07, but it works fine with GamMac v1.06B6.
Now I'm going to test the GamMac 1.8beta testbuild asap.
Fred.
StainlessS
30th April 2017, 10:05
Thanks Fred, I think I know what I did wrong, silly mistake (corrected in 1.8B).
I'll have a bit more of a play and post update.
StainlessS
30th April 2017, 12:59
Fred,
Note, some of the effects of the blk/wht blocks thing could be achieved by changing Th and/or Scale.
It gives a little more info if RAW R,G,B values are shown in metrics (Verbosity>=4, the real mins/maxs) without taking
Th into consideration.
Also Note, the FLAGS (and color) on the "n] Flags:- 1SR LockVal=69.000" line show the used mode for the individual
frame (which can change because of low input range, or eg full scale input range, whether real, or improvised via
Black/White blocks)
(The Flags on post #120 show what the Blk/Wht Blocks forced).
EDIT: Blk/Wht blocks will most likely (depending upon size) force full scale input range, ie scale=0
(so Scale setting of non zero ignored and set as if scale=0 for every individual frame)
EDIT :
Scale=1 [scale all channels to Min(R,G,B) and Max(R,G,B)].
Scale=1, is exactly same as scale=0 when all channels minimums are 0, and all channels maximums are 255.
Setting Scale=1, and Th=0.0, would be to some degree self adjusting,
and would switch to showing Scale Flag as Scale=0 when Min(R,G,B)==0, and Max(R,G,B)==255, Blk,wht blocks (if big enough, Th dependent)
would always set Scale=0, for every frame, so may as well just set Scale=0 and forget about the blk,wht blocks.
In post #120, all three images use scale=2, but 2 of them use blk,wht blocks to change to scale=0, the cat image is an exception and
stays scale=2 for some reason, I would be interested to see result of scale=1 and scale=0 when Th=0.0. (and with Verbosity=4).
# -----------------
# -----------------
# -----------------
From Post #104
Perhaps default Th should be 0.0 to detect real min,max pixel values, make user select Th to ignore when required
(what say you Fred ?, Th=0.0 is least destructive).
...
EDIT: Above are by no means perfect, but suggest maybe that Th=0.0 should be default.
The R,G and B Mul args have not been used above, but could provide further correction where needed.
Permission to change default Th to 0.0 requested (If you think a good idea, see post #104 again).
EDIT: Default Th, currently 0.04%.
EDIT: Th=0.0, avoids big mistakes in eg JohnMeyer KidsInRedRomperSuits color shift (Especially for Scale=2). (user can always change to Th=0.04 if required).
If DC already denoised, then Th=0.0 is a real good idea.
EDIT: I think I'll also change valid input range of GamMax from 2.0 -> 10.0 to 1.0 < GamMax <=10.0, might be useful not just as
Guess range limiter, but also as a correction/colorshift limiter. (will likely need some experimentation to see if of any worth).
EDIT: "Matt_Greece_002.png", might look better (contrast) with 0.0 < Th.
EDIT: Have implemented GamMax limiter, 1.0 < GamMax <=10.0, and now also shows G flag on top line, hi-lited if
Gamma correction has been limited by GamMax for current frame (limited to GamMax or 1.0/GamMax).
StainlessS
30th April 2017, 16:07
Fred, see prev post.
Here, GamMac() v1.08Beta2, with new default Th=0.0, in anticipation of your acceding to my request.
Also, new valid range mod GamMax, 1.0 < GamMax <= 10.0, gamma correction limiting functionality.
Here (Beta will be lifted if you accede to my request, otherwise original Th=0.04 will be reinstated.):- LINK REMOVED
Th, Default 0.00 Sets Default for loTh and hiTh. Suggest Default, 0.00(percent). [-1.0(OFF) , or 0.0 -> 1.0]
...
GamMax, default 10.0 Upper value for guess gamma [1.0 < GamMax <= 10.0]
Starting guess upper range and limit for gamma estimator.
The lower guess range and limit will be set to 1.0 / GamMax, by default 0.1.
v1.08Beta2, Now allowing lower limit of GamMax to go as low as almost 1.0, GamMax now usable as
a gamma correction limiting device, where correction not allowed to exceed GamMax or go lower than
its reciprocal ie 1.0/GamMax. 'G' limited flag now added to flags line in metrics, hi-lited if Gamma
limited by GamMax (limiting includes any Red,Grn,BluMul, multiplier result).
...
Upper frame metrics shown as eg:- (when Verbosity=5=FULL)
nnnnn] Flags:- 1SRG
R G B
RAW: 10,253 10,253 10,253
IN: 10,253 10,253 10,253
IN_AVE: 78.466 88.552 78.767
SCALED: 71.847 82.431 72.162
GAMMA: 1.135 1.000 1.123
OUTAVE: 82.431 82.422 82.451
...
'G' = Correction limited by GamMax, mode signfied by color.
Greyed out. Not Range Limited.
Orange hi-lite, at least 1 channel has GamMax limited gamma correction.
EDIT: Individual channel gamma result is also hi=lited if GamMax limited eg for Red channels limited
GAMMA: 1.135 1.000 1.123
EDIT: LoTh and HiTh still hi-lited in metrics if not OLD default of 0.04, will fix that to hi-lited if not NEW default of 0.0, if new default accepted.
StainlessS
15th May 2017, 14:41
Bump !!!
videoFred
15th May 2017, 18:29
Bump !!!
On your head? :D
Serious, thank you for the latest update, testing it right now.
Fred.
videoFred
15th May 2017, 19:32
Here, GamMac() v1.08Beta2, with new default Th=0.0, in anticipation of your acceding to my request.
First impression: very good, leave default Th=0.0 please.
Setting Scale=1, and Th=0.0, would be to some degree self adjusting,
and would switch to showing Scale Flag as Scale=0 when Min(R,G,B)==0, and Max(R,G,B)==255, Blk,wht blocks (if big enough, Th dependent)
would always set Scale=0, for every frame, so may as well just set Scale=0 and forget about the blk,wht blocks.
Tested and confirmed! Still need FredAverage() borders on detect clip for difficult frames, examples will follow.
EDIT: is it my imagination or do I see better color correction with v.1.08.beta2?
Fred.
StainlessS
15th May 2017, 20:31
EDIT: is it my imagination or do I see better color correction with v.1.08.beta2?
Not intentional if so, I only re-arranged some stuff to try make code easier to read (other than the noted changes to Th, and GamMax limiting [which would only happen if GamMax given as lower than default 10.0]).
EDIT: If DC pre-denoised, then new default Th could well be somewhat better.
videoFred
18th May 2017, 11:19
OK, vs 1.08.beta2 is still not working with ffmpeg. Also, Gammax = 1.0 throws an error message:
Gammac: 2.0 <=Gammax <=10.0(1.000000)
Otherwise results are very good with Scale=0 and th= 0.0 :)
Fred.
StainlessS
19th May 2017, 03:35
sorry fred, doc was already fixed in post #148,
GamMax, default 10.0 Upper value for guess gamma [1.0 < GamMax <= 10.0]
ffmpeg thing, no idea yet.
EDIT: Oops, sorry fred, I had reposted 1.8Beta again instead of 1.8Beta2, fixing now.
StainlessS
19th May 2017, 18:40
Fred, Sorry, had reposted original v1.08Beta instead of 1.08Beta2, here v1.08 final with ffmpeg problem fixed (I hope).
Check out the ffmpeg thing please. (If still broken, can you post maybe about 1st 20 frames of problem source, assuming it
still hangs for the 20 frame sample).
GamMac() v1.08 new version, see first post.
v1.07, Bug fixed in GuessGamma(), previously found gamma could have been slightly nearer than result.
(The binary chop is linear, but results after Gamma mod are not, so we should track best Gamma mod).
v1.08, GuessGamma(), min,max limited to omin,omax, regression from bug introduced in 1.07.
Made GetFrame a little easier to understand (better named scalar variables)..
Correction of oMax limits, from 239->255 to 235->255, ie permissable StudioRGB range was wrong.
Plugin available from both links below this post, StainlessS@MediaFire and StainlessS@SendSpace.
videoFred
19th May 2017, 19:32
Fred, Sorry, had reposted original v1.08Beta instead of 1.08Beta2, here v1.08 final with ffmpeg problem fixed (I hope).
Check out the ffmpeg thing please.
Ffmpeg problem fixed StainlessS! :thanks:
Fred.
StainlessS
19th May 2017, 22:47
Fred, nuther screw up, find new version v1.09 on MediaFire/SendSpace.
v1.07, Bug fixed in GuessGamma(), previously found gamma could have been slightly nearer than result.
(The binary chop is linear, but results after Gamma mod are not, so we should track best Gamma mod).
v1.08, GuessGamma(), min,max limited to omin,omax, regression from bug introduced in 1.07.
Made GetFrame a little easier to understand (better named scalar variables)..
Correction of oMax limits, from 239->255 to 235->255, ie permissable StudioRGB range was wrong.
v1.09, GamMax limiting not working proper, fixed [EDIT: Not flagged in metrics properley].
RGB multipliers now not applied when RngLim limited. [EDIT: Did not make sense as was]
Hopefully better now.
videoFred
20th May 2017, 12:53
v1.09 works very fine, also with ffmpeg. It looks like scale=0 is the best setting for average use. (less heavy contrast, better detail in dark parts). Adding FredAverage() borders on detect clip is still needed, to avoid wrong color corrections on scenes with lots of blue sky etc...
Fred.
StainlessS
11th June 2017, 13:55
I've just tried GamMatch (not GamMac) out for real (a bit like ColorLike usage), and it behaved brilliantly, not perfect but way better
than anticipated. For the clips in question, the good color clip had some sections missing compared with bad color clip
(although constant/similar scenes), where I just used a single frame with GoodColorOneFrame.Loop(BadColor.FrameCount,0,0) to match
framecounts of clips. A daft idea that worked out quite well :) (although was a lot of hand editing).
EDIT: The good color clip also had a substantial vivid color logo which when edited out via DC coords had no real effect on the fix's.
StainlessS
25th July 2017, 14:39
Fred, nice little mod to previously posted Sub() function to subtitle overhead text on frame.
Prev func always used ScriptClip to put FrameNumber of frame, and in four window stack, would call scriptclip 4 times, one
for each window, here below optional, and only calls scriptclip where required. Can use FrameNo just on eg Top LHS
frame and not on others, so only one scriptclip call. Also, adds back audio now, as BlankClip first used clip in stack, we
were losing audio, probably did not notice due to not rendering 4 window stack result.
script
# Stack Overhead Subtitle Text, with optional FrameNumber shown
Function Sub(clip c,string Tit,Bool "ShowFrameNo",int "first_frame", int "last_frame",string "font",float "size",int "text_color",
\ int "halo_color",int "align",int "spc",float "font_width",float "font_angle") {
/* http://forum.doom9.org/showthread.php?p=1813402#post1813402
Title bar is Round(size+2) pixels hi (default 20).
Dont use align=4,5,6, better use 1,2,3,7,8,or 9.
*/
ShowFrameNo=Default(ShowFrameNo,False)
first_frame=Default(first_frame,0) last_frame=Default(last_frame,c.FrameCount-1)
font=default(font,"Ariel") size=Default(size,18.0)
text_color=Default(text_color,$00FFFF00) halo_color=Default(halo_color,$00000000)
align=default(align,7) spc=Default(spc,0)
font_width=Default(font_width,0) font_angle=Default(font_angle,0.0)
c.BlankClip(height=round(size+2.0))
NSFN=(!ShowFrameNo) ? "" : RT_String(""" %s"),first_frame=%d,last_frame=%d,font="%s",size=%.3f,text_color=$%X,halo_color=$%X,
\ align=%d,spc=%d,font_width=%.3f,font_angle=%.3f)""",
\ Tit,first_frame,last_frame,font,size,text_color,halo_color,align,spc,font_width,font_angle)
(ShowFrameNo)
\ ? ScriptClip("""Subtitle(String(current_frame,"%.f]"""+NSFN)
\ : Subtitle(Tit,first_frame=first_frame,last_frame=last_frame,font=font,size=size,text_color=text_color,
\ halo_color=halo_color,align=align,spc=spc,font_width=font_width,font_angle=font_angle)
Return StackVertical(c).AudioDubEx(c)
}
Anyways, handy for showing sample frames, and without damaging contents due to titling.
EDIT: If you must protect your work, instead of damaging with overlayed text, chop some off, and work on whats left
and showing overhead text,
so anybody else can just chop off overhead text and repeat what was done. (by default overhead text banner is 20 pixels tall)
EDIT:
And RtSub(), similar but using RT_Subtitle (faster, especially using ShowFrameNo).
# Stack Overhead RT_Subtitle Text, with optional FrameNumber shown.
Function RtSub(clip c,string Tit, Bool "ShowFrameNo") {
c.BlankClip(height=20)
(Default(ShowFrameNo,False)) ? ScriptClip("""RT_Subtitle("%d] %s",current_frame,""""+Tit+"""")""") : RT_Subtitle("%s",Tit)
Return StackVertical(c).AudioDubEx(c)
}
videoFred
27th July 2017, 13:05
Thank you StainlessS ;)
Fred
StainlessS
22nd August 2017, 21:49
Here, attempt at implementing Dithering, not sure if I've done it correctly or not.
v1.10Beta:- LINK REMOVED
Someone wanna try it out, has not had much testing, and no idea if removes banding.
Will likely not be able to do anything for several days.
Added, arg to end of args list, ie Bool "Dither"=False.
~Not sure that I've understood how it is implemented in AVS v2.6 standard Levels (took as example).
Took - 127.5 in BLUE as some kind of combined subtract by 0.5 (in standard 8 bit range) and/or some kind of dither centering.
EDIT: Yep, think now some kind of dither centering. [EDIT: dither Biasing, ie dither both + and -, instead of just +)
void GamMac::SetDitherMap(int in_min,int in_max,int out_min,int out_max,double gamma,BYTE *map) {
DPRINTF(("SetDitherMap IN"))
const int scale_in_min = in_min * 256;
const int scale_in_max = in_max * 256;
const double orng = ((double)out_max)-out_min;
const double round = 0.5 + out_min;
const int divisor = scale_in_max - scale_in_min + (scale_in_max == scale_in_min);
const double igam = 1.0/gamma;
for(int i=(256*256);--i>=0;) {
double v = double(i - scale_in_min - 127.5) / divisor;
v = pow(min(max(v, 0.0), 1.0), igam);
v = (v * orng) + round;
int val = int(floor(v)); // Round towards -ve infinity
if (val > out_max) val = out_max;
else if(val < out_min) val = out_min;
map[i] = val;
}
DPRINTF(("SetDitherMap OUT"))
}
the Dithering
if(Dither && !raw_AllBad) {
if(vi.IsRGB32()) {
for(y=height;--y>=0;) {
const int _y = (y << 4) & 0xf0;
for(x=vi.width;--x>=0;) {
const int xx=x*4;
const int _dither = ditherMap[(x&0x0f)|_y];
dstp[xx+0] = map[2][srcp[xx+0]<<8 | _dither ];
dstp[xx+1] = map[1][srcp[xx+1]<<8 | _dither ];
dstp[xx+2] = map[0][srcp[xx+2]<<8 | _dither ];
dstp[xx+3] = srcp[xx+3]; // copy Alpha
}
srcp += pitch;
dstp += dpitch;
}
} else {
for(y=height;--y>=0;) {
const int _y = (y << 4) & 0xf0;
for(x=vi.width;--x>=0;) {
const int xx=x*3;
const int _dither = ditherMap[(x&0x0f)|_y];
dstp[xx+0] = map[2][srcp[xx+0]<<8 | _dither ];
dstp[xx+1] = map[1][srcp[xx+1]<<8 | _dither ];
dstp[xx+2] = map[0][srcp[xx+2]<<8 | _dither ];
}
srcp += pitch;
dstp += dpitch;
}
}
} else {
if(vi.IsRGB32()) {
for(y=height;--y>=0;) {
for(x=rowsize;(x-=4)>=0;) {
dstp[x+0] = lut[2][srcp[x+0]];
dstp[x+1] = lut[1][srcp[x+1]];
dstp[x+2] = lut[0][srcp[x+2]];
dstp[x+3] = srcp[x+3]; // copy Alpha
}
srcp += pitch;
dstp += dpitch;
}
} else {
for(y=height;--y>=0;) {
for(x=rowsize;(x-=3)>=0;) {
dstp[x+0] = lut[2][srcp[x+0]];
dstp[x+1] = lut[1][srcp[x+1]];
dstp[x+2] = lut[0][srcp[x+2]];
}
srcp += pitch;
dstp += dpitch;
}
}
}
If someone tries it out, say if gets rid of banding, thanx.
EDIT: lut[256] is 8 bit, map[65536] is 16 bit dither.
EDIT: Finding gamma etc all done in 8 bit, only final rendering done via dither map[]'s, dither will likely be considerably slower,
has to be done [EDIT: map build] for all three channels and at every frame, not only once in constructor, as in eg Levels.
EDIT: Just tried with AVSMeter, on JohnMeyer Parade clip, single clip (ie not multi-stacked), and with metrics OFF.
Dither=False = 150FPS
Dither=True = 30FPS
On 2.4GHz Core2 Quad (~25% CPU, 1 core @~100.0%, either way).
EDIT: Seems to be doing something at least, but I dont have anything exhibiting banding, that I'm aware of.
Top=no dither, 2nd=dither, bot=difference:2nd-Top amplified
https://s20.postimg.cc/fvjfmuxa5/Flag.jpg (https://postimg.cc/image/8sbk78ruh/)
Or frame 0,
https://s20.postimg.cc/7ejxbxsl9/Opening.jpg (https://postimg.cc/image/of2tkm5mh/)
FranceBB
24th August 2017, 01:21
If I feed GamMac v1.10 Beta with an 8bit RGB input, it works, but if I try to feed it with 16bit stacked (Dither Tool) or 16bit interleave (HDR Core), it doesn't work.
I think you should add a few parameters, like in f3kdb:
input_mode=1 (stacked) 2 (interleave)
input_depth=8 (8bit) 16 (16 bit)
output_mode=1 (stacked) 2 (interleave)
output_depth=8 (8bit) 16 (16 bit)
Actually, afaik, GamMac supports GamMac(Dither=true) or GamMac(Dither=false), which is quite limiting because it accepts 8bit RGB only (no 16bit input) and outputs 8bit only (no 16bit output), so, even thought it does its calcs in 16bit, an 8bit output would nullify almost any advantage (and bring banding back).
Oh, of course, Dither Tool is the most common way to get 16bit (stacked) in Avisynth and pretty much no one uses HDR Core (16bit interleave), so I wouldn't spend time trying to support it. I think that something like:
input_depth=8 (8bit) 16 (16 bit stacked)
output_depth=8 (8bit) 16 (16 bit stacked)
would be more than enough.
Oh, and by the way, thank you for supporting XP.
Comparison between GamMac with Dither=true and Dither=false
http://thumbsnap.com/i/dJ5O136Y.png?0823
EDIT: Crap, imgur converted it to jpg...
EDIT2: Used thumbsnap, which seems to preserve png.
StainlessS
24th August 2017, 20:30
Sorry, I use neither AVS+ nor dither stuff, and dont have any immediate intention of changing that.
The only intent of using dither here, is to not create any banding as a result of GamMac processing,
anyone is welcome to do a 8/16bit in/out mod, there is not really too much code in it really.
(As it currently stands, I did a pretty much complete re-write in about 2 hours [a few months back],
so should not prove too much a challenge).
Oh, and by the way, thank you for supporting XP.
Yep, supporting XP is of paramount importance to me, mostly cos thats what I use :)
EDIT: The full source is supplied in the 1.10beta zip, I might want to make a small change or two but nothing too drastic.
EDIT: Any color (rather than gray) banding example ??? [EDIT: Banding created by GamMac, not banding previously present]
EDIT: Post all three samples, Pre-GamMac, NoDither result, and Dither result. (png please)
EDIT: So far as I know, nobody supports 16 bit Stacked RGB, (well except for my ClipBlend16 which was a mistake as I did not
know that nobody else supports stack16 RGB).
Somebody say if they know otherwise.
EDIT: For Pre-GamMac sample, please use one of below if adding titles, so can crop off text.
Function Sub(clip c,string Tit,Bool "ShowFrameNo",int "first_frame", int "last_frame",string "font",float "size",int "text_color",
\ int "halo_color",int "align",int "spc",float "font_width",float "font_angle",Int "BackColor") {
/*
Stack Overhead Subtitle Text, with optional FrameNumber shown
http://forum.doom9.org/showthread.php?p=1813402#post1813402
Title bar is Round(size+2) pixels hi (default 20).
Dont use align=4,5,6, better use 1,2,3,7,8,or 9.
*/
ShowFrameNo=Default(ShowFrameNo,False) first_frame=Default(first_frame,0) last_frame=Default(last_frame,c.FrameCount-1)
font=default(font,"Ariel") size=Default(size,18.0) text_color=Default(text_color,$00FFFF00)
halo_color=Default(halo_color,$00000000) align=default(align,7) spc=Default(spc,0)
font_width=Default(font_width,0) font_angle=Default(font_angle,0.0) BackColor=Default(BackColor,$00000000)
c.BlankClip(height=round(size+2.0),Color=BackColor)
(ShowFrameNo)
\ ? ScriptClip("""Subtitle(String(current_frame,"%.0f] ")+"""+Chr(34)+Tit+Chr(34)+String(first_frame,",first_frame=%.0f")+
\ String(last_frame,",last_frame=%.0f,font=")+Chr(34)+font+Chr(34)+String(size,",size=%.3f")+String(text_color,",text_color=%.0f")+
\ String(halo_color,",halo_color=%.0f")+String(align,",align=%.0f")+String(spc,",spc=%.0f")+String(font_width,",font_width=%.3f")+
\ String(font_angle,",font_angle=%.3f)"))
\ : Subtitle(Tit,first_frame=first_frame,last_frame=last_frame,font=font,size=size,text_color=text_color,halo_color=halo_color,align=align,
\ spc=spc,font_width=font_width,font_angle=font_angle)
Return StackVertical(c).AudioDubEx(c)
}
or
# Stack Overhead RT_Subtitle Text, with optional FrameNumber shown.
Function RtSub(clip c,string Tit, Bool "ShowFrameNo") {
c.BlankClip(height=20)
(Default(ShowFrameNo,False)) ? ScriptClip("""RT_Subtitle("%d] %s",current_frame,""""+Tit+"""")""") : RT_Subtitle("%s",Tit)
Return StackVertical(c).AudioDubEx(c)
}
StainlessS
7th September 2017, 20:46
Sub() from post #160 and above post #164, updated (added some more Subtitle args, requires RT_Stats).
EDIT: Added First_frame, Last_Frame args.
StainlessS
8th September 2017, 02:56
Answering post from GamMac predecessor thread:- https://forum.doom9.org/showthread.php?p=1817786#post1817786
Will be easier all around (until you become familiar with Avisyth) to convert mp4 to AVI.
CLIP_To_UT_YV12_AVI.cmd (requires Ut_video Codec installed, and FFMPeg, somewhere)
setlocal
REM Where to Find ffmpeg
set FFMPEG="C:\BIN\ffmpeg.exe"
REM Where to get input file, No terminating Backslash, "." = current directory (ie same as dir .bat file)
set INDIR="."
REM Where to place output file, No terminating Backslash. "." would be same as .bat file
set OUTDIR="D:"
FOR %%A IN (*3gp *.h264 *.vob *.wmv *.asf *.mpg *.m2v *.avi *.flv *.mov *.mp4 *.m4v *.RAM *.RM *.mkv *.TS *.y4m *.yuv *.webm) DO (
%FFMPEG% -i "%INDIR%\%%A" -vcodec utvideo -acodec pcm_s16le "%OUTDIR%\%%~nxA.AVI"
)
Pause
It dont like spaces in file names.
Using, GamMac v1.10Beta from post #164 (and slightly modded script)
Avisource("clip.mp4.avi")
ConvertToRGB24.KillAudio
#Spline36Resize(512,384)
O=Last
DC=Last
#DC=DC.Blur(1.0) # Detection Clip (uses source clip if dc not supplied, Denoised or whatever)
#DC=DC.BilinearResize(320,240) # Test DC not same size as source
LockChan = 1 # Chan for lock to Ave, 0=R, 1=G, 2=B
# -1 = Use LockVal below.
# -2 = LockVal=(RedAve+GrnAve+BluAve)/3.0 for LockVal.
# -3 = LockVal=Median(RedAve,GrnAve,BluAve)
Scale=2
RedMul = 1.0 # Required Ave multiplier for Red Channel, applied when requesting GuessGamma(reqAve*RedMul), Even applied when LockChan=-1.
GrnMul = 1.0 # Same for Green channel. GrnMul even applies when LockChan is Green Channel, etc for chans.
BluMul = 1.0 # Same for Blue channel. Allows tinkering/fine tuning.
Th = 0.0
LockVal = 128.0 # Only valid if LockChan == -1
RngLim = 11
GamMax = 10.0
Show = True # Metrics
Verb = 5 # Verbocity FULL
SHOWCOORDS= True # Show Original with Coords
DITHER=FALSE
x =5 # Coords (for dc Detection Clip)
y =5
w=-5
h=-5
omin=5 # Output channels minimum (footroom for manual editing).
omax=250 # Output channels maximum (headroom for manual editing).
#Return GamMac(DC,x=x,y=y,w=w,h=h,Coords=True) # Show Coords only
Scale=0
A_TEXT = RT_String("Scale=%d rMul=%.2f gMul=%.2f bMul=%.2f",Scale,RedMul,GrnMul,BluMul)
A=GamMac(LockChan=LockChan,SCALE=SCALE,RedMul=RedMul,GrnMul=GrnMul,BluMul=BluMul,
\ Th=Th,LockVal=LockVal,RngLim=RngLim,GamMax=GamMax,
\ dc=DC,
\ x=x,y=y,w=w,h=h,
\ omin=omin,omax=omax,
\ Show=Show,Verbosity=Verb,dither=DITHER)
Scale=1 BluMul=1.0
B_TEXT = RT_String("Scale=%d rMul=%.2f gMul=%.2f bMul=%.2f",Scale,RedMul,GrnMul,BluMul)
B=GamMac(LockChan=LockChan,SCALE=SCALE,RedMul=RedMul,GrnMul=GrnMul,BluMul=BluMul,
\ Th=Th,LockVal=LockVal,RngLim=RngLim,GamMax=GamMax,
\ dc=DC,
\ x=x,y=y,w=w,h=h,
\ omin=omin,omax=omax,
\ Show=Show,Verbosity=Verb,dither=DITHER)
Scale=2 BluMul=1.0
C_TEXT = RT_String("Scale=%d rMul=%.2f gMul=%.2f bMul=%.2f",Scale,RedMul,GrnMul,BluMul)
C=GamMac(LockChan=LockChan,SCALE=SCALE,RedMul=RedMul,GrnMul=GrnMul,BluMul=BluMul,
\ Th=Th,LockVal=LockVal,RngLim=RngLim,GamMax=GamMax,
\ dc=DC,
\ x=x,y=y,w=w,h=h,
\ omin=omin,omax=omax,
\ Show=Show,Verbosity=Verb,dither=DITHER)
COORDS=O.GamMac(dc=DC,x=x,y=y,w=w,h=h,Coords=True)
ODC=((SHOWCOORDS)?COORDS.Spline36Resize(width,Height):O) # Resize COORDS (Not necessarily the same sizse as source clip)
ODC_TEXT=(SHOWCOORDS)?"Detect Clip with Coords":"Original"
TOP=StackHorizontal(Sub(ODC,ODC_TEXT),Sub(A,A_TEXT))
BOT=StackHorizontal(Sub(B,B_TEXT),Sub(C,C_TEXT))
StackVertical(TOP,BOT)
return Last
# Stack Overhead Subtitle Text, with optional FrameNumber shown
Function Sub(clip c,string Tit,Bool "ShowFrameNo",int "first_frame", int "last_frame",string "font",float "size",int "text_color",
\ int "halo_color",int "align",int "spc",float "font_width",float "font_angle") {
/* http://forum.doom9.org/showthread.php?p=1813402#post1813402
Title bar is Round(size+2) pixels hi (default 20).
Dont use align=4,5,6, better use 1,2,3,7,8,or 9.
*/
ShowFrameNo=Default(ShowFrameNo,False)
first_frame=Default(first_frame,0) last_frame=Default(last_frame,c.FrameCount-1)
font=default(font,"Ariel") size=Default(size,18.0)
text_color=Default(text_color,$00FFFF00) halo_color=Default(halo_color,$00000000)
align=default(align,7) spc=Default(spc,0)
font_width=Default(font_width,0) font_angle=Default(font_angle,0.0)
c.BlankClip(height=round(size+2.0))
NSFN=(!ShowFrameNo) ? "" : RT_String(""" %s"),first_frame=%d,last_frame=%d,font="%s",size=%.3f,text_color=$%X,halo_color=$%X,
\ align=%d,spc=%d,font_width=%.3f,font_angle=%.3f)""",
\ Tit,first_frame,last_frame,font,size,text_color,halo_color,align,spc,font_width,font_angle)
(ShowFrameNo)
\ ? ScriptClip("""Subtitle(String(current_frame,"%.f]"""+NSFN)
\ : Subtitle(Tit,first_frame=first_frame,last_frame=last_frame,font=font,size=size,text_color=text_color,
\ halo_color=halo_color,align=align,spc=spc,font_width=font_width,font_angle=font_angle)
Return StackVertical(c).AudioDubEx(c)
}
StainlessS
9th September 2017, 13:44
Post #164, removed external requirements from Sub() Function. Added BackColor arg.
Function Sub(clip c,string Tit,Bool "ShowFrameNo",int "first_frame", int "last_frame",string "font",float "size",int "text_color",
\ int "halo_color",int "align",int "spc",float "font_width",float "font_angle",Int "BackColor") {
/*
Stack Overhead Subtitle Text, with optional FrameNumber shown
http://forum.doom9.org/showthread.php?p=1813402#post1813402
Title bar is Round(size+2) pixels hi (default 20).
Dont use align=4,5,6, better use 1,2,3,7,8,or 9.
*/
ShowFrameNo=Default(ShowFrameNo,False) first_frame=Default(first_frame,0) last_frame=Default(last_frame,c.FrameCount-1)
font=default(font,"Ariel") size=Default(size,18.0) text_color=Default(text_color,$00FFFF00)
halo_color=Default(halo_color,$00000000) align=default(align,7) spc=Default(spc,0)
font_width=Default(font_width,0) font_angle=Default(font_angle,0.0) BackColor=Default(BackColor,$00000000)
c.BlankClip(height=round(size+2.0),Color=BackColor)
(ShowFrameNo)
\ ? ScriptClip("""Subtitle(String(current_frame,"%.0f] ")+"""+Chr(34)+Tit+Chr(34)+String(first_frame,",first_frame=%.0f")+
\ String(last_frame,",last_frame=%.0f,font=")+Chr(34)+font+Chr(34)+String(size,",size=%.3f")+String(text_color,",text_color=%.0f")+
\ String(halo_color,",halo_color=%.0f")+String(align,",align=%.0f")+String(spc,",spc=%.0f")+String(font_width,",font_width=%.3f")+
\ String(font_angle,",font_angle=%.3f)"))
\ : Subtitle(Tit,first_frame=first_frame,last_frame=last_frame,font=font,size=size,text_color=text_color,halo_color=halo_color,align=align,
\ spc=spc,font_width=font_width,font_angle=font_angle)
Return StackVertical(c).AudioDubEx(c)
}
johnmeyer
13th September 2017, 19:25
I have a big film transfer project and figured it is time to finally add GamMac to my restoration script. I'm using the 5/19/2017 version of GamMac.
The problem is flicker. I saw the earlier post in this thread about flicker and have tried all the th, loTh, and hiTh settings, but they don't do enough. My "solution" at this point is to move the Deflicker plugin to the very end of my restoration chain. That seems to calm things down enough that I can proceed with this project.
These are the GamMac overrides that I feed to GamMac in both my film restoration script, and with the GamMac.avs script that comes with the plugin:
#GamMac Parameters
LockChan = 0
LockVal = 128.0
Th = 0.1
Scale = 1
RedMul = 1.0
GrnMul = 1.0
BluMul = 1.0
LockChan and Scale are the only two I have altered (I got better results working off the red channel).
Here is a link to a short test file that generates a fair amount of flicker on two different scenes:
Test Clip (https://www.mediafire.com/file/v6nw8126bwct1d5/GamMac%20Flicker%20Problems.avi)
I am probably missing some obvious setting.
StainlessS
14th September 2017, 00:39
John, LemMotlow seems less that enthused by the thing, perhaps also seek advise there.
Suggest that some kind of blur involved and also try whatever thresh, after that probably best guy is the guy, ie Frederick.
I've already stated that I aint got no idea when it comes to color correction, Ich bin ein shitbag @ der color correction.
For those that dont speak perfect high German, I aint too good.
johnmeyer
14th September 2017, 01:04
StainlessS,
I think you may have gotten the wrong impression from my last post. To be clear: I am totally enthused by GamMac, and spent quite a bit of time today incorporating it into my film restoration script as a permanent replacement for the lousy auto-color I had before. No auto color is going to work all the time but, from my perspective, du bist ein wunderkind when it comes to auto color correction. This is the best auto-color plugin I've used.
I am still going to do two restorations: one with auto-color correction and one without, and then skim through the 5-10 hours of footage and cut between the two, as needed, using Vegas' multi-cam function. Every element of movie film restoration requires occasional manual overrides, and this is no exception. All I was hoping for was a way to diminish the amount of flicker I was getting, especially on scenes with moving specular highlights, like the harsh reflections of the moving water in the swimming pool. Other scenes have little or no flicker.
Maybe VideoFred has some ideas. I tried to read through all the posts he has made about his use of GamMac, but I may have missed a few things.
StainlessS
14th September 2017, 01:27
Sorry John. been having to deal with people (well drunk scum much like me) in local boozer.
If flickering, then suggest Blur or denoise DC clip, should work well.
With Scale=2, any single extreme pixel could cause flicker, Blur would negate effect.
Scale=2 is extreme measure anyway, can produce good results but if noise pixels can also produce flicker.
Sorry, when I'm sober, I skim read and so sometimes make mistakes in understanding (crap eyes, hate reading), when drunk,
I hate it less, but still dont see any better (kinda used to it, expect it, and so less of a prob, however no fewer mistakes).
Fred will keep you right, I feel sure of that.
The guy from Gent is a gent from Gent, (almost poetic) and his name is Fred the Poet. :)
(Come on, Fred and Gent, some ammo there for one or two Limericks).
Gone to bed John, I'll see you in my deams :), ta ta.
I have weird screwed up nasty dreams, and John, you are in all of them, go figure.
[I do wish RaffRiff would appear more in my dreams, (or at all), I'd love to give him a good slap, wipe that smug grin off of him face].
'Time for bed' said Florence, 'Boing' said Zebedee.
johnmeyer
14th September 2017, 02:30
Wow, sounds like you were on quite a pub crawl.
I'll try the blur or denoise on the clip, although it is already denoised via MDegrain and RemoveDirt, so the grain and dirt should not be the issue. As I said above, I think it has something to do with the specular highlights on the snow and swimming pool water. Other scene are pretty stable. I provided that 5-second clip (which has NOT been denoised) to see if perhaps it would provide a clue about what is going on.
Limericks are my favorite. I'l use your excellent opening line:
There once was a fine gent from Gent,
Whose passion was usually spent,
On film and restoring,
Which no one found boring,
Especially StainlessS from Kent.Please move to Kent so my limerick makes sense.
Now I'll really be in your head. (heh, heh ...)
videoFred
14th September 2017, 11:21
The guy from Gent is a gent form Gent, (almost poetic) and his name is Fred the Poet. :)
(Come on, Fred and Gent, some ammo there for one or two Limericks).
Haha working on it..... :p
videoFred
14th September 2017, 11:38
StainlessS,
This is the best auto-color plugin I've used.
Yes it is, I'm using it all the time now. Actualy it's a auto-levels plugin but because it works on R,G and B indiviual it's correcting colors too.
All I was hoping for was a way to diminish the amount of flicker I was getting, especially on scenes with moving specular highlights, like the harsh reflections of the moving water in the swimming pool. Other scenes have little or no flicker.
Maybe VideoFred has some ideas. I tried to read through all the posts he has made about his use of GamMac, but I may have missed a few things.
I have solved this completely by creating a modified "detect" clip. On this clip, I have added a colored border. That color is created with FredAverage(). Another StainlessS brew :)
I'm not at home now, but I will post a few examples as soon as possible.
In the mean time, can you upload a few problematic scenes John?
Fred.
johnmeyer
14th September 2017, 15:03
...
I have solved this completely by creating a modified "detect" clip. On this clip, I have added a colored border. That color is created with FredAverage(). Another StainlessS brew :) ...
In the mean time, can you upload a few problematic scenes John?
Fred.I did provide a link in #168 to a five second clip. Here is that link again:
Test Clip (https://www.mediafire.com/file/v6nw8126bwct1d5/GamMac%20Flicker%20Problems.avi)
I'll look and try to find the FredAverage() code and colored border. I did know that you were adding some sort of border, much as you did in your earlier scripts to keep Autolevel() from being fooled. However, I don't think I've seen your code for this particular fix. I'm pretty sure that my problem is the same as what you have already solved, so I'll try to, once again, duplicate your work.
[edit] I just found your original Average() code, but can't yet get it to work. It simply gives me a perfectly gray box, no matter what the input. I'm in YV12 colorspace at the point in the clip where I used it.
Average = baseclip.ScriptClip(""" u=round(AverageChromaU()) v=round(AverageChromaV()) BlankClip(last, color_yuv=65536*128 + 256*u + v) """).invert()
I'll keep on working, although the Deflicker got me to the point where I can finish the current project, and I have a deadline, so I may not get back to this right away.
[edit2]Looks like FredAverage() is gone from StainlessS Sendspace downloads. I'll see if I can come up with something on my own. Your idea is a good one, but I can't get any of the code to work, and the custom DLL is gone.
StainlessS
14th September 2017, 17:15
FredAverage upped to SendSpace, is always available on MediaFire (next to SendSpace link). SendSpace packages disappear
if not downloaded for 30 days.
x64 bit version available via Groucho2004 repository.
johnmeyer
14th September 2017, 18:35
Ah, you know I never noticed that they were two separate links. Perhaps the ::: should be and "or". I did see the 64-bit Groucho2004 version, but am not yet running AVISynth on my 64-bit O/S.
Thanks!
StainlessS
14th September 2017, 19:58
Ahem :)
https://forum.doom9.org/showthread.php?p=1743237#post1743237
Added "AND/OR" between links as suggested, thank you.
The x64 comment was for anyone interested.
johnmeyer
14th September 2017, 22:05
Ahem :)
https://forum.doom9.org/showthread.php?p=1743237#post1743237
Well, some people can be taught ... apparently, I am not one of them.
StainlessS
5th October 2017, 09:00
Anybody object to my removing Beta from v1.10 ?, then can update first post to that version with dithering.
Anybody any problems, anybody tried it ?
fenomeno83
9th October 2017, 16:48
hi,..i've tried your filter..VERY NICE for correct image colors...
basically I use this script in my photos
image = ImageReader("1.jpg")
image = ConvertToYV12(image)
image = Levels(image,0, 1.1, 255, 0, 255)
image = HDRAGC(image,corrector=0.8,protect=1,reducer=1.5,coeff_gain=1.0,min_gain=1.0)
##GamMac section
image = ConvertToRGB(image)
image = GamMaC(image, show=false)
image = ConvertToYV12(image)
image = Autolevels(image)
image = Tweak(image,0.0,1.0,-5.0,1.0)
image = ConvertToRGB(image)
--sharpener
--denoiser
ImageWriter(image,"1.jpg",0,0,"bmp)
GamMac correct general colors in most cases, like this.
original: https://ibb.co/d4BKvb
filtered using previous script: https://ibb.co/dUexFb
in that case it do a very good work..
here another example:
original: https://ibb.co/n92dMG
filtered: https://ibb.co/nvXv1G
in that case, filter "fails"
raffriff42
12th November 2017, 04:34
The thing I don't understand here is how to keep the settings stable. I would like the color corrections not to change within a scene or an entire video. Is that possible? Besides copying the numbers off the screen in Show mode and hard-coding them in the script?
(If not, I wonder if a second clip argument - a reference clip - could be added. The automagic would work from the reference, which might be a selected freeze frame from the video. To keep the "old" behavior, the reference would default to the source clip 'C')
StainlessS
12th November 2017, 05:08
Raff, all mods are based off the (EDIT: 2nd clip] DC detection clip, so I guess that you could use Freeze frame.
However, suggest maybe take a peek at GamMatch (rather than GamMac), I used it a little while ago Freeze Frame with quite good results.
(still in this thread), see post #159:- https://forum.doom9.org/showpost.php?p=1809358
With a couple of images:- https://forum.doom9.org/showpost.php?p=1784010
https://s20.postimg.cc/i4fxto9dp/Gammatch_v0_zps8h9khfyf.png (https://postimg.cc/image/mqc220uwp/)
dll via MediaFire below.
raffriff42
12th November 2017, 05:39
DC clip! *smacks forehead*
Thanks, will look into GamMatch too.
StainlessS
12th November 2017, 20:38
Raff sorry, I think maybe I got fixated on GamMatch due to the FreezeFrame stuff, perhaps GamMac is the one you need with DC clip.
(I re-read your question).
GamMatch is for where you have a hi rez clip with bad color and a low rez clip with good color, color of hi rez clip is amended to match the low rez clip.
EDIT: The above GamMatch 4 window pic above, the good color clip is actually a bit reddish, we could probably have got better result if correcting for the the redness of the good color clip via GamMac, and correct the (simulated) bad clip to match that modified result.
(I just happened to have that clip handy when doing the test).
Yanak
25th November 2017, 18:48
Hello StainlessS,
I done some tests using the DC function and the output seems always similar to when i only apply gammac with default settings on my video, without using DC with a reference clip i mean.
Simplified test i done :
Good=LSMASHVideoSource("H:\good.mp4", format = "YUV420P8").converttoRGB24.trim(5,13979)
Bad=FFVideoSource("H:\bad.mkv", colorspace = "YUV420P8", cachefile = "H:\TEMP\bad_temp\bad.ffindex").converttoRGB24.trim(956,14930)
Gammac( Bad, dc= Good, x=40,y=40,w=-40,h=-100, show=true, coords=false)
( Using last avs+ x64 version with gammac x64 from Groucho2004 )
Both clips are the same content, the "Bad" one have a higher resolution and better details that were preserved on the video but have wrong colors, kinda washed out, the "good" clip is a bit lower resolution with correct colors and a bit less tiny details + some "scratches" on the bottom part.
Made a test using Gammatch inside MP_Pipeline using those 2 same clips ( Gammatch only exists in x86 version so i needed Mp_Pipeleine to test quickly ) and the result is really great there, the good colors are transposed correctly for most of the footage, some portions will need a little manual tweaking but overall the result out of the box is impressive.
Could use it for the testings and i am really impressed by the results, but won't be able to use it for the things i planned to do as i won't be able to pass some variables I'll need for other plugins between the x64 and x86 modules inside MP_Pipeline, but unless i understood something incorrectly i should be able to achieve more or less the same results using DC with a reference clip in Gammac, yet using Gammac i can not find out why it does not seems to use the good clip as reference and the result is the same as using only gammac in "basic mode" without a reference DC clip.
I'm probably doing something wrong but i have no idea anymore now, maybe you or raffriff42 who seems to have used this recently will have some tips using DC clip.
As for Gammac itself (without using a DC clip) i will have to recover some others old family videos and test this deeply but the results examples posted in this thread are really nice, can't wait to start messing with this when i'll have the materials and some free time, great work done on this, thanks a lot for all those nice tools.
Thank you.
StainlessS
25th November 2017, 20:04
GamMatch is the one you want, I think.
GamMac will not match src clip to dc, it will mod (when eg LockChan=1[grn]) r, and b gamma of dc to match gamma g of dc, and then apply same
mods to the src clip (also mins and maxs depending upon scale).
GamMatch, matches gamma, min and max, of src g to match dc g, same with other channels.
I'll see if I can knock up quick a 64 bit GamMatch.
EDIT: In GamMac, the only function of DC is to avoid noise in source clip, eg where DC = blurred source, will avoid noisy extremes in histograms.
For GamMatch, DC is expected to be a better color version of the source clip (although probably lower resolution).
StainlessS
25th November 2017, 21:40
GamMatch, v0.04, x86 (avs26 only) + x64:- http://www.mediafire.com/file/lirgshavcaa03rz/GamMatch_v0.04_dll_20171125.zip
No functional difference in v0.04 to v0.03, compiled with VS 2008 rather than VS ToolKit 2003.
Give it a whirl and shout if probs.
Yanak
25th November 2017, 23:24
Just tested the x64 and it does the job perfectly, runs a bit slower than the x86 dll inside MP_Pipeline, 3mn59s vs 3mn09s for the x86 inside MP_Pipeline on the footage tested but not a problem, it does the job and will allow me to use other plugins on it, that's what matters, thank you so much for this and for the quick answer.
It's private footage so i cannot share examples but the result is just bluffing, will only need a little tweaking on one scene maybe and it will be absolutely perfect.
You made my day StainlessS :)
For GamMac i understand a bit better now, thanks for the explanation, i first thought GamMatch was a kind of lighter sub-function version.
I hopefully will test GamMac soon too, I have in plan to grab some old family videos i saw long time ago, hopefully they are still around and will be able to put my hands on them one of those days.
For one in particular i remember seeing it some years ago and it had a kind of reddish tint so I'll experiment with GamMac, I'm pretty sure there is still a few camera pictures taken on this same event, last time they shown them to me the colors were not altered on the pictures.
I'll have to experiment and look deeper into Gammac but there is probably a way to take one or some of the camera pictures as reference to correct the colors of the tinted videos scenes, probably using DC with one of the pictures having the more accurate colors might bring very nice results on this footage. Can't wait to try that.
Thanks again for the quick release of the x64 DLL and for those nice tools you provide StainlessS, like i said you made my day with this, i'm bluffed by the result.
StainlessS
25th November 2017, 23:47
Glad you like it Yanak :)
After the EDIT in post #185, I decided to try this script out with JohnMeyer's Parade clip (which is a bit reddish).
# Some good-ish color clip
Avisource("1941 Flint Michigan Parade [Low, 360p].mp4.AVI") # This is a bit reddish
ConvertToRGB24.KillAudio
ORG=Last
# Simulate bad color Input clip
RED=ShowRed(Pixel_Type="Y8").Levels( 0,0.8,255, 8,247,coring=false)
GRN=ShowGreen(Pixel_Type="Y8").Levels(0,1.5,255,12,223,coring=false)
BLU=ShowBlue(Pixel_Type="Y8").Levels( 0,2.0,255,32,239,coring=false)
MergeRGB(RED,GRN,BLU,pixel_Type="RGB24")
BAD=Last
# Simulate DC Low res clip with good-ish color (but naturally a bit red)
DC=ORG.Blur(1.58).Blur(1.58).Spline36Resize(320,240) # Fake change of size for detect, and blurred (for no real reason)
FDC=DC.GamMac(Th=0.0,Show=false) # Fixed color cast in DC clip
FINAL=BAD.GamMatch(FDC,Th=0.0,Show=False)
TOP=StackHorizontal(TSub(BAD,"BadColor source. (Simulated bad clip)",true),
\ TSub(DC.Spline36Resize(width,Height),"DC Simulated Low res with original RED color cast"))
BOT=StackHorizontal(TSub(FDC.Spline36Resize(width,Height),"DC Low rez with RED color cast FIXED by GamMac"),
\ TSub(FINAL,"BadColor.GamMatch(DC.GamMac)"))
StackVertical(TOP,BOT)
return Last.trim(2678,-1)
# Stack Overhead Subtitle Text, with optional FrameNumber shown.
Function TSub(clip c,string Tit,Bool "ShowFrameNo"){
c.BlankClip(height=20)
(Default(ShowFrameNo,False))?ScriptClip("""Subtitle(String(current_frame,"%.f] """+Tit+""""))"""):Subtitle(Tit)
Return StackVertical(c).AudioDubEx(c)
}
EDIT: Minor script mod.
https://s20.postimg.cc/u9y9n3pv1/Gam_Gam.png (https://postimages.cc/)
We create a simulated bad color source clip, and also a low res DC version of original source.
We correct the slight red color cast in the simulated low res DC clip.
And match the simulated bad color source clip to the cast fixed low rez DC clip.
Works quite well.
EDIT: In post #183 image, we did not correct the red cast in DC clip.
EDIT: Post #165 (at top of post) should have read post #185, thanx Yanak :)
Yanak
26th November 2017, 00:00
I bookmarked this for when i'll be able to put my hands on the footage + pictures, never seen the video with correct colors, only the few pictures and this was many years ago, will be a blast to see it with the colors restored and red tint removed.
Thanks a lot for all this StainlessS.
PS: i don't think it is in post #165, but i'll explore the thread tomorrow to find it, thanks again.
Edit : seeing it now, result looks really nice, I hope i can get such results when i'll try, you guys are magicians making dreams come true ;)
Might browse archive.org tomorrow for some old 8mm videos having reddish tints so i can start to test this before getting my footage as this might take a bit of time, i'll be able to experiment ^^
Thank you again.
StainlessS
26th November 2017, 00:28
Yanak, here some images (used in GamMac thread):- http://www.mediafire.com/file/rdk5du4h3c114z4/GamMacSubs.zip
EDIT: ~6.5MB
EDIT: And JohnMeyer Parade clip used in above test:- https://forum.doom9.org/showthread.php?p=1774154#post1774154
Yanak
26th November 2017, 00:50
Perfect, i know what i will do of my Sunday now ^^
Thanks a lot for all this.
Yanak
27th November 2017, 22:41
Done some testings with the pictures you put at my disposal and the videos linked on youtube too, thanks again for that. Then looked into archive.org for some bad 16mm footage and ended up on this one : https://archive.org/details/AfterTheFire_201611
It caught my attention for the red tint mixed on a fire scene... left me wondering how GamMac will deal with this, the result is here :
https://streamable.com/jv12x
( Video can be downloaded with a right click on the streaming player, as long as you stay under the streaming recommendations for your footage it is not reencoded at all there, just the sent video+audio remuxed and it keeps some of the metadata too, but 720p only there, might be useful for some others;) )
I was left like o_O , wow ! I was really not expecting something like this.
https://s14.postimg.org/4yo3lgdwx/904797_Restore_Test2512.jpg
Middle video is mostly default settings with increased x,y,w,h parameters, left one is a bit more custom settings but nothing polished.
Did not have enough time until now to push a lot with fine tuning and do trials with all the numerous settings the tool offers, still have to learn the effects of some of them and do deep testings,
Just deeintrelaced the video downloaded from archive.org and done some testings quickly, then horizontally stacked and downscaled to 720p to upload it on the hosting site.
Some other screenshots from this same footage ( downscaled for posting in the forum) :
https://s14.postimg.org/q8bpwb1xd/911795_New_File3001448.jpg
https://s14.postimg.org/spnh3ktjl/582366_New_File3003209.jpg
https://s14.postimg.org/o3rcv8fq9/496853_New_File3008556.jpg
https://s14.postimg.org/9xbm00ckx/498255_New_File3041574.jpg
It's far from perfect as i did not spent too much time on this yet, will play more with this when i have free time to burn but it's impressive already, I have to say that I did not had high hopes for the fire scene in particular but it left me amazed.
Impressed by the almost raw results out of the box the tool gives, with some fine tuning and tweaking it could end up really nice. Thanks for this nice tool StainlessS, really !
I also have a question for the Master Guru VideoFred please :
I made some tests on some other footage using FredAverage plugin ( x64 one, thanks to Groucho2004 ) and followed your suggested method of adding borders overlay on a reference video.
My question is can you give a tip on the size of the borders to use please ?
I made tests with 2,4,10 and 20px borders on footage close to 480p, but don't know yet what will be the more appropriate depending the resolution input, i mean very low 360/480p , or 720p for example, if you have any hint on this please, Thanks in advance.
Thanks guys.
videoFred
28th November 2017, 16:20
Well... a 20 pixels "FredAverage" border on the detect clip for GamMac is always a good start value.
Do you use AvsPmod Yanak? In AvsPmod you can add sliders for all needed GamMac parameters. This makes it easy to find the best settings.
You can also add a slider for the "FredAverage" borders. (With some smart scripting hehe) :D
Fred.
Yanak
28th November 2017, 17:23
Thank you VideoFred, I will keep this in mind and see how it goes starting with around 20px and adjust from there.
I do use AvsPmod yes, created user sliders maybe once or twice only, not something i use much in this program, will probably have to create a few for GamMac as it will help a lot to test the different parameters and fine tuning indeed, thanks a lot for the tip.
As for a FredAverage border side with a slider it can be handy too, will create a variable value just for the borders and see if i can turn it into a slider.
For now mostly testing things on various footage i collect from the web, for testing and training, your guides are really helpful btw, thanks for sharing your knowledge, don't know when i'll be able to put my hands on the footage i have in mind ( and then will have to contact someone i know to do the transfer film>digital ), not in a hurry anyways, I can only hope i can achieve something half good as you do with the video examples you show us and it will be nice already.
Thank again for the tips.
StainlessS
28th November 2017, 17:45
JFYI, a Blur of DC=DC.Blur(0.2) or thereabouts (0.1 -> 0.25) seems sufficient to mitigate any light flickering produced due to light noise in DC clip.
Yanak
28th November 2017, 18:19
Good to know, thanks for the info StainlessS, will include this on my tests and see how it goes.
Thanks.
Aktan
21st February 2018, 15:34
Hey StainlessS, I tried to do a x64 compile of GamMac_v1.09_dll_20170519, and I got it to compile fine after fixing the char * problems (was complaining it needed to be char const *), but when running with just default values, I get an access violation with this simple script:
LoadPlugin("GamMac.dll")
AVISource("sourceNewmid.avi")
AssumeTFF()
ConvertToRGB32()
GamMac()
Any idea what is going on?
Edit: Source is a YUY2 clip
Edit 2: I'm on AVS+ 0.1 r2574
Edit 3: I tracked it down to line 747 in GamMac.cpp. Really seems like AVS+ doesn't like AVSValue defined in the Create method (just like the Median filter). If I return the newly create object directly, it works fine. Maybe someone else with better C++ knowledge knows what's going on?
Groucho2004
21st February 2018, 17:00
By the way, there is a 64 bit version of GamMac (https://forum.doom9.org/showthread.php?t=173259). I didn't encounter any problems converting it to 64 bit.
Aktan
21st February 2018, 17:02
By the way, there is a 64 bit version of GamMac (https://forum.doom9.org/showthread.php?t=173259). I didn't encounter any problems converting it to 64 bit.
:thanks: I'll try that one instead. Maybe it's me using VS Community 2017? I really have no idea...
StainlessS
22nd February 2018, 11:32
Aktan, can you post a response after trying G2K4 x64 compile, thanx.
pinterf
22nd February 2018, 12:45
Edit 3: I tracked it down to line 747 in GamMac.cpp. Really seems like AVS+ doesn't like AVSValue defined in the Create method (just like the Median filter). If I return the newly create object directly, it works fine. Maybe someone else with better C++ knowledge knows what's going on?
I suppose the avisynth header comes from the old 2.5 'baked code' times. No wonder it is incompatible with a 64 bit avs+ environment.
(In general I can see no reason for keeping this obsolate avisynth header file in any project. I'm using header file and stuff from the avs+ project (surprise :) ), which are compatible with classic avs 2.6 filters but one can still use it in avs+, use the new color spaces, check for modern processor features and get a painless 64 bit option)
Groucho2004
22nd February 2018, 13:57
I suppose the avisynth header comes from the old 2.5 'baked code' times. No wonder it is incompatible with a 64 bit avs+ environment.That's probably it. I automatically update to AVS+ headers when I convert a plug to 64 bit so this potential issue didn't even enter my mind. :)
StainlessS
22nd February 2018, 15:01
Yip, the original GamMac header was version 3, v2.58 compatible (RGB only), not surprising that it crashes.
I'll do a version with VS2008 project for v2.5, v2.6 x86, and x64, later two with latest avs+ headers.
Aktan
22nd February 2018, 15:06
Aktan, can you post a response after trying G2K4 x64 compile, thanx.
G2K4 x64 compile is fine :thanks:
I suppose the avisynth header comes from the old 2.5 'baked code' times. No wonder it is incompatible with a 64 bit avs+ environment.
(In general I can see no reason for keeping this obsolate avisynth header file in any project. I'm using header file and stuff from the avs+ project (surprise :) ), which are compatible with classic avs 2.6 filters but one can still use it in avs+, use the new color spaces, check for modern processor features and get a painless 64 bit option)
What's stopping me from using the newer header is that I needed to change more of the source file, aka learn about the new methods and change them, and I was a bit too lazy to do that, lol. Unless I don't need to change it and I can just drop it in... then I had no idea!
StainlessS
22nd February 2018, 16:03
Need Also in source directory:-
Avisynth+ v2.6 AVISYNTH_INTERFACE_VERSION=6 (latest available) Named as Avisynth.h
Also need additional Avisynth+ headers somewhere in an AVS directory,
AVS
alignment.h
avisynth.h
capi.h
config.h
cpuid.h
minmax.h
types.h
win.h
and point Menu/Tools/Options/Projects and Solutions/VC Directories/ :Include Files: Win32 and x64, to the parent directory containing the AVS directory. [EDITED: in bold]
Above for VS2008, probably not much different for other compilers.
Aktan
22nd February 2018, 16:11
Need Also in source directory:-
Avisynth+ v2.6 AVISYNTH_INTERFACE_VERSION=6 (latest available) Named as Avisynth.h
Also need additional Avisynth+ headers somewhere in an AVS directory,
AVS
alignment.h
avisynth.h
capi.h
config.h
cpuid.h
minmax.h
types.h
win.h
and point Menu/Tools/Options/Projects and Solutions/VC Directories/ :Include Files: Win32 and x64, to containing AVS directory.
Above for VS2008, probably not much different for other compilers.
:thanks: I remember you said this too in the Median thread. You've motivated me to try it out, lol.
StainlessS
22nd February 2018, 17:41
Sorry, think I got that wrong, need point to the directory that contains the AVS directory, not AVS itself.
Only got to do it once, then are good for all projects, just need to update avs+ headers when updated.
Aktan
22nd February 2018, 17:45
Sorry, think I got that wrong, need point to the directory that contains the AVS directory, not AVS itself.
Only got to do it once, then are good for all projects, just need to update avs+ headers when updated.
Yea I figured it out. I got it to compile. I still needed to change "AvisynthPluginInit2" to "AvisynthPluginInit3" and change varies "pointer to char" to "pointer to const char". Now to test it! Seems later VS are a lot more strict.
Edit: On a side note, at first I got the headers from the master branch from pinterf's fork of AVS+ (a mistake, I know) and had to fix a bunch of void problems. To my surprise, the MT branch had these void errors already fixed. I was surprised since Groucho2004's avisynth header that I got from his compiled x64 also had the void problems.
Edit 2: The compiled DLL works! \o/
StainlessS
22nd February 2018, 18:22
Here something from WaterMark2 plug, which I'm doing a bit on [Just ignore/remove the DPRINTF() lines.]
// The following function is the function that actually registers the filter in AviSynth
// It is called automatically, when the plugin is loaded to see which functions this filter contains.
#ifdef AVISYNTH_PLUGIN_25
extern "C" __declspec(dllexport) const char* __stdcall AvisynthPluginInit2(IScriptEnvironment* env) {
DPRINTF("AvisynthPluginInit2::AddFunction(Watermark2::Create)")
#else
/* New 2.6 requirement!!! */
// Declare and initialise server pointers static storage.
const AVS_Linkage *AVS_linkage = 0;
/* New 2.6 requirement!!! */
// DLL entry point called from LoadPlugin() to setup a user plugin.
extern "C" __declspec(dllexport) const char* __stdcall
AvisynthPluginInit3(IScriptEnvironment* env, const AVS_Linkage* const vectors) {
DPRINTF("AvisynthPluginInit3::AddFunction(Watermark2::Create)")
/* New 2.6 requirment!!! */
// Save the server pointers.
AVS_linkage = vectors;
#endif
env->AddFunction("Watermark2", "c[watermark]c[displace]i[light]i[depth]i[softEdge]b[lightFrom]s",Watermark2::Create,0);
// The AddFunction has the following paramters:
// AddFunction(Filtername , Arguments, Function to call,0);
// Arguments is a string that defines the types and optional nicknames of the arguments for you filter.
// c - Video Clip
// i - Integer number
// f - Float number
// s - String
// b - boolean
// . - Any type (dot)
// Array Specifiers
// i* - Integer Array, zero or more
// i+ - Integer Array, one or more
// .* - Any type Array, zero or more
// .+ - Any type Array, one or more
// Etc
#ifdef AVISYNTH_PLUGIN_25
DPRINTF("AvisynthPluginInit2: Exiting to Avisynth")
#else
DPRINTF("AvisynthPluginInit3: Exiting to Avisynth")
#endif
return "`Watermark2 plugin' Watermark2 plugin";
// A freeform name of the plugin.
}
Need AVISYNTH_PLUGIN_25 defined for avs v2.58, otherwise avs/avs+ v2.6.
EDIT: Also, #includes either "Avisynth25.h" or "Avisynth.h" (avs+) based on AVISYNTH_PLUGIN_25.
Aktan
22nd February 2018, 18:25
Here something from WaterMark2 plug, which I'm doing a bit on [Just ignore the DPRINTF() lines.]
<snip code>
Need AVISYNTH_PLUGIN_25 defined for avs v2.58, otherwise avs/avs+ v2.6.
:thanks:
JoeSuper8
3rd June 2018, 17:39
I have read this thread but do not understand how best to use FredAverage with GamMac. I am familiar with Avisynth.
Could someone please post a working GamMac script incorporating FredAverage? Or a working FredAverage script if it has to be done separately? I was reading that a detect clip has to be made?
StainlessS
3rd June 2018, 18:57
Well, I dont actually use FredAverage(), maybe Fred could provide some help.
Fred tends to use AvsPMod with sliders, I dont like AvsPMod, as it changes my scripts and I've gotta keep changing them back again.
I would suggest using Scale=1 or Scale=0, rather than the more aggressive (and perhaps overly correcting) Scale=2.
In addition, using noise processed DC detect clip [ or Eg blur(0.2)] will reduce any flickering and over correction due to 'Sparkles' in the source clip.
Here, a function collection for applying multiple FredAverage dampening settings to multiple ranges in a clip, although I've no real idea if of any use,
Fred seems to have fixed his original clip (using original script function attempt) and not had further need to use again.
Here:- https://forum.doom9.org/showthread.php?p=1831521#post1831521
EDIT: PostImage.org has killed a lot of my site images, they changed the filehost name from PostImage.org to PostImage.cc,
and many (maybe all) now are invisible, I've fixed some in several threads today.
EDIT: result of above mentioned FredAverage dampening scripts.
Showing at bottom of frame, [top downwards] FredAverage Dampening Bar[100% dampened], metrics, and the real frame Average.
EDIT: Where 100% dampening, the Dampening bar is a photo negative invert of the real frame average.
GamMac processes just the image and dampening bar [which dampens GamMac effect] the metrics and real average bar are added just for display purposes.
https://s20.postimg.cc/4knv8suul/Fred_DB_DBar.jpg (https://postimages.cc/)
videoFred
4th June 2018, 18:41
I was reading that a detect clip has to be made?
Yes, a detect clip with colored borders and the color of these borders is created by FredAverage().
It's just the average color on frame level, reversed (to make it difficult haha)
Serious, I got this idea from someone here on the Forum (was it Martin?) who has made a very simple but very effective auto white script.
So, in short: if you create a 'detect' clip with FredAverage() borders, it will soften the Gammac effect. Specifically on scenes with a lot of blue sky.
On those scenes, all auto white algorithms will fail. They all create ugly brown colors.
PS: The option to use a detect clip is included in Gammac()
PS2: like I showed here, but with borders instead of a square box.
https://forum.doom9.org/showthread.php?p=1803528#post1803528
And that was before FredAverage, but it's the same principle.
StainlessS was so kind to create FredAverage(), because Scriptclip was not working in Avisynth+ MT modus.
You will also see two tiny square boxes, one white, one black.
They are softening the auto levels effect from Gammac() on very problematic scenes.
Scenes with colored noise for example.
Fred.
johnmeyer
5th June 2018, 00:35
Thanks Fred! I never did quite get GamMac to work. Hopefully these hints will get me to the finish line.
Yanak
14th June 2018, 13:31
Hello StainlessS,
I tried to self compile GamMatch 0.4 in VS2017 and I'm not sure if it's important or not but i get some "C4244 (https://msdn.microsoft.com/en-us/library/2d7604yb.aspx)" warnings about possible loss of data :
https://i.imgur.com/beEMb0N.png
The x64 dll compiles fine despites those warnings and after a few quick tests it seems to work correctly ( and getting a nice speed boost according to avsmeter which was my primary goal when trying this ).
Probably not a big deal but i'd better ask in case in can lead to some errors.
Thanks a lot.
PS: GamMac and GamMatch do an amazing job on videos or even static images, i finally could put my hands on a old family video and a bunch of photographies that were taken the same day, not all is digitalized yet and the transfer of the video i get for now is not really in high quality, will need to find a better way or bring this to some professionals for the transfer but i don't like much the idea of giving private stuff like this so I'll see in the next months, when I'll have gathered more videos how i can achieve something better, i'm not in a hurry so it's not a problem at all.
Still experimenting with this when i have a few hours to kill and having good results on static pictures too, quite amazed by the results out of the box, a big thank you for those nice tools :)
StainlessS
15th June 2018, 15:21
GamMac v1.10 (beta removed), see first post.
Zip approx 1MB, incl 3 png files, avs v2.58 x86, avs+ x86 and x64 dll's + source + VS2008 project files.
Changed default Scale from 2 to 1 (default was a little too severe).
@Yanak, the warnings you mention, are pretty much all down to string lengths in DDigit source, and can safely be ignored as no Avisynth string
is likely to be more than 2GB in size. Fixed DDigit source so as not to give warnings. (about 4 Warnings, + another warning in GamMac args conversion from float to double to float)
EDIT: Fixed all of the PostImage file host images in thread (or I hope so), which got broken some weeks ago due to PostImage changes in filename URL's. [Only mine, I cant fix anybody elses].
Yanak
15th June 2018, 22:17
Thanks Stainless,
too late to try it tonight but i'll compile it tomorrow using the new DDigit from GamMac and run a few tests to compare speed. I had no idea if this could lead to problems, now i manage to compile stuff myself but coding is still a very long way to go :p
As for the postimage links broken, i fell you man... I also have to do it, already had to change all my pics links not long ago from hostingpics.net to postimage since hostingpics will cease activity after something like 8 years hosting my pics there... changed all my forum pics to postimage as it looked good but now I'll have to do this again :/ pain in the rear ...
Thanks a lot for the quick fix, the nice tools and work put on all this :)
StainlessS
16th June 2018, 10:41
You will also need update the other files, not just DDigit.cpp, had to make a few small changes in connection with convert for
x64 and also because of implementing resource file stuff.
Make sure that you have project preprocessor defines set in Preprocesor and also Resource,
'AVISYNTH_PLUGIN_25' if compiling for avs v2.58
And also for avs+ x64, add '_WIN64' (do not delete the 'WIN32' entry) to both C/CPP/Preprocessor/ & Resources/General/ Preprocessor Definitions.
Yanak
17th June 2018, 08:04
Hi,
I use my own solution template ( same one i used for watermark2 plugin ) where i just compile for avisynth+ x64, for GamMatch 0.0.4 i just replaced the DDigit files and updated the compiler file, also had already the resources and versions infos done in my template but updated it (https://i.imgur.com/V3RQnqD.png) and used the infos you provided in yours to credit you more properly than before :) .
Tested GamMatch quickly and it seems to do the job and gain a few FPS already, but will try to do like for WaterMark2 (https://forum.doom9.org/showthread.php?t=163870&page=4) and try to boost a bit more the performances by training it a bit using PGO, might take a few days since i'm a bit busy with other stuff but I'll post the results here, might serve some others.
Haven't touched GamMac itself for now, the version i use until now is the one released by Groucho2k4, but it's now on my to do list when i will be done with GamMatch ( not sure if you will also port some of the changed code done on GamMac to GamMatch or it the things you modified are not code shared between the 2 plugins that does not need to be modified btw )
Again thanks a lot for all this.
JoeSuper8
22nd June 2018, 16:03
Thanks Fred and StainlessS!
I am going through the scripts linked by StainlessS https://forum.doom9.org/showthread.php?p=1831521#post1831521
I noticed two issues that I am having:
1. The text color of the FredFun metrics affects the dampening and resulting colors of the image in the comparison mode, as well as the rectangle colors at the bottom. I changed the color from the default to white and the colors of the image and topmost of three rectangles' color changed in windows 3 and 4 (the bottom half of the screen).
2. By setting FredFun show metrics to false, the dampening effect disappeared, the bottom rectangles disappeared, and the image matched window 2. Setting FINAL to True in FredDB.avs had the same effect where there is no more dampening effect, even if Show was set to True.
StainlessS
22nd June 2018, 20:35
I'll take a peek when I get home.
EDIT: Sure sounds like something is terribly wrong.
EDIT: Might have to wait until tomorrow, I'm a bit dead on my feet.
StainlessS
26th June 2018, 12:11
@ Fred,
I've been thinkin bout it a bit, and seems to me that the FredAverge(Invert=true) with overlay thing will
not perform as ideally required.
Firstly, if (as mostly expected) we are using LockChan=1 ie lock to Green channel, then DC green channel
average will be 'tickled' towards 127.5, (where green channel would not normally be touched when LockChan=1
and FredAverage not used), so green channel is actually changed where it would not normally be.
Is it intentional that FredAverage thing modify green channel when using LockChan==1 ???
(I presume that intent is to only dampen R and B modification when Lockchan==1).
EDIT: @ JoeSuper8, sorry for delay, have some difficulty getting time to fix this prob, and also a bit stuck as to how to.
(FredAverage thing will probably have to go and be replaced with something else, arg to GamMac).
EDIT: -ve LockChan complicates things further, kind of wish that they had not been implemented in the first place.
EDIT: Also, does FredAverage dampen only work [EDIT: nearly] properley when LockChan==1, my head hurts :(
(Green channel pays greatest contribution to luma value, ~59%)
EDIT: Take your time Fred, not expecting any immediate answer here :)
Yanak
27th June 2018, 17:08
Took me way longer than expected to test a few things, thanks to Open Office who crashed and never was able to re-open the sheet i had with alll stats collected after many tests... all lost while almost finished...
Anyways, results for this script : https://pastebin.com/AQLQ7AJS
Original GamMatch x64 :
FPS (min | max | average): 16.41 | 22.65 | 22.47
Time (elapsed): 00:05:20.426
Recompiled GamMatch x64 :
FPS (min | max | average): 20.66 | 31.33 | 31.10
Time (elapsed): 00:03:51.531
GamMatch_x64 (Not GamMac!) Dll download + source and solution for VS2017:
https://www67.zippyshare.com/v/5hOp8j4P/file.html
PGO don't bring very much here, Intel compiler can bring a very little plus, from 0.08 to 0.12 FPS on average only for this synthetic test script, but it's not worth it... maybe while activating some specific instructions for recent CPU's it could gain a bit more but I have only a Ivy Bridge CPU so...
Anyways quit happy with the boost, will need to find time to do all those tests again with GamMac_x64 and compare with Groucho's released x64 dll, i doubt there is any gain to get there, Groucho2k4 releases are quite optimized for what i could test before, probably will wait until you make some changes to your code before putting my head again into this :p
videoFred
27th June 2018, 20:35
@ Fred,
I've been thinkin bout it a bit, and seems to me that the FredAverge(Invert=true) with overlay thing will
not perform as ideally required.
Perhaps not ideal but I was looking for a solution for this problem:
https://forum.doom9.org/showthread.php?p=1803528#post1803528
Is it intentional that FredAverage thing modify green channel when using LockChan==1 ???
(I presume that intent is to only dampen R and B modification when Lockchan==1).
No, not intentional, I was only looking for a solution for the R and B channels. I wanted less red and more blue.
Did not realize was a green channel modification too. Anyhow, it looks good by eye :D
Fred.
StainlessS
28th June 2018, 05:18
OK, F, I'll try get something working, dont hold your breath, (also try fix the original cause thing too).
color
13th July 2018, 21:27
I try to save the script to GaMac.avsi but then I can not open the Avspmod. It says it wrong with the file on line 9, then it crash. Or am I doing it wrong?
StainlessS
14th July 2018, 02:20
It says it wrong with the file
Well at a guess, maybe should use avs not avsi (avsi for autoload plugins dir), maybe avsi messes up AvsPMod.
Imagesource("GreenChurch.png",end=0)
#Imagesource("Puppy.png",end=0)
#Imagesource("lennaRed.png",end=0)
ConvertToRGB24.KillAudio
#Spline36Resize(512,384)
O=Last
DC=Last
# LINE 9 is empty
#DC=DC.Blur(1.0) # Detection Clip (uses source clip if dc not supplied, Denoised or whatever)
#DC=DC.BilinearResize(320,240) # Test DC not same size as source
...
Is the line 9 an AvsPMod line number ?
Does it play in eg MPC-HC or VDub2 ?
Is it script supplied with GamMac_x86_x64_v1.10_dll_20180615 ? [as the snippet in code block above]
What is the exact error message ?
videoFred
14th July 2018, 10:07
Well at a guess, maybe should use avs not avsi (avsi for autoload plugins dir), maybe avsi messes up AvsPMod.
AvsPmod works fine with .avsi, so it must be something else.
Still holding my breath :p
Fred.
color
14th July 2018, 16:30
Well at a guess, maybe should use avs not avsi (avsi for autoload plugins dir), maybe avsi messes up AvsPMod.
Imagesource("GreenChurch.png",end=0)
#Imagesource("Puppy.png",end=0)
#Imagesource("lennaRed.png",end=0)
ConvertToRGB24.KillAudio
#Spline36Resize(512,384)
O=Last
DC=Last
# LINE 9 is empty
#DC=DC.Blur(1.0) # Detection Clip (uses source clip if dc not supplied, Denoised or whatever)
#DC=DC.BilinearResize(320,240) # Test DC not same size as source
...
Is the line 9 an AvsPMod line number ?
Does it play in eg MPC-HC or VDub2 ?
Is it script supplied with GamMac_x86_x64_v1.10_dll_20180615 ? [as the snippet in code block above]
What is the exact error message ?
Oh, the dll....I must have missed to read the first post. I went to your plugin page and there it was. Okey It works. Thank youl. :)
lollo2
20th July 2018, 18:26
Newbie to video restoration, I have a question on GamMatch: why the plugin allows only to mask edges in reference video?
I need to match two video sequences, both having black borders (differing in size) on the edges and "vhs noise" (differing in size) on the bottom.
I thought that for GamMatch it would be better to work with the images exactly in the same position and then I shifted one of the 2, without
removing the noise at the bottom.
I used then the x/y/w/h options of GamMatch to remove borders and noise in reference video.
For a better behaviour of GamMatch, should I also remove noise and borders in the video to be matched, or the algorithm does not care? (in my
experiments I do not see a difference, but I may be wrong)
Thanks!
StainlessS
21st July 2018, 10:42
NOTE, From Post #66 (where GamMatch first appeared),
DC and DC_AVE derived from DC (Good color clip), all others from clip c (BAD color clip, Incl OUTAVE).
Having both clips spatially aligned is not absolutely necessary.
GamMatch only makes histograms similar, so cropping off borders (from both clips) stops those regions from producing messed up histograms.
A little noise reduction on detect clip [maybe eg Blur(0.2) would do], would also stop hi/lo 'sparkles' from taking part in DC histogram.
Best crop Source clip borders, to produce better histogram, but can use the x,y,w,h coords option (or crop, either would do), to eg avoid
some logo on DC clip that is not present in Source clip.
Have successfully used DC single frame (FreezeFrame) to match source clip to that single frame. (Where missing DC frames
compared to Source, but entailed lots of hand editing in script).
EDIT: Me also loves this little demo using both GamMac and GamMatch:- https://forum.doom9.org/showpost.php?p=1825391&postcount=190
https://s20.postimg.cc/u9y9n3pv1/Gam_Gam.png (https://postimages.cc/)
EDIT: And the original version without color cast correction via GamMac (result a bit red as original DC clip):
https://s20.postimg.cc/i4fxto9dp/Gammatch_v0_zps8h9khfyf.png (https://postimg.cc/image/mqc220uwp/)
lollo2
21st July 2018, 13:20
Thanks for your reply!
Having both clips spatially aligned is not absolutely necessary
Right, sorry. I aligned the two clips because I have to replace in a video a bad sequence with a good sequence; I align and then "gammatch"
the good to the bad; I learned now I can do first the "gammatch" without impact.
Best crop Source clip borders, to produce better histogram ...
Not sure I understand everyting here, I conclude that is better to crop (mask) also the video to be matched (Source)
... Where missing DC frames compared to Source, but entailed lots of hand editing in script).
Yes! The Source is a capture from a damaged tape (lots of missing/inserted frames); DC is a capture of the same program from another
tape (GamMatch needed because different "look").
Matching DC frame by frame to Source to make GamMatch efficient was a nightmare.
In addition, I had to replace damaged frames in DC (i.e. big portion of the frame is white or black) causing GamMatch to fail, with a duplicate
of a good frame; another nightmare.
But the final overall result is good: thanks for your GamMatch plugin!
I also compared GamMatch versus MatchHistogram versus HistogramAdjust versus a Manual Brightness and Contrast Tweak and, in my case,
GamMatch produces the best results (I was not able to include ColourLike in the bench because I always have a Stack Overflow error)
StainlessS
21st July 2018, 14:05
Best crop Source clip borders, to produce better histogram ...
Not sure I understand everyting here, I conclude that is better to crop (mask) also the video to be matched (Source)
I just meant that there are two histograms to consider, ie the DC dectection clip, and of the source clip, if source clip has lots
of eg black border, then the histogram is already screwed up, need to remove borders from source clip histogram, ie crop them off.
You can if necessary AddBorders() back again. [EDIT: with resulting borders being probably a better even black than original].
JFYI, Masking is not the same as cropping.
lollo2
21st July 2018, 14:14
Clear explaination. Thanks!
lollo2
21st July 2018, 16:01
The results I obtained, FYI
original is the original damaged video
in replace_sequence I replaced the image from a clean video
in replace_sequence_gammatch I used GamMatch on clean video and then replaced the image
clean video is vhs, while damaged video is s-vhs (little little bit more details)
https://s6.postimg.cc/lb867su3l/example1.jpg (https://postimg.cc/image/5czghnzvh/)
https://s6.postimg.cc/cg7bxad0x/example2.jpg (https://postimg.cc/image/3xxvsy6i5/)
StainlessS
21st July 2018, 16:17
Not sure what you are telling me.
You seem to swap and change description,
Which one is the source that will be modified, and which is the good color clip (DC) which will be used to adjust source.
Judging by provided upper images, I'm guessin' that what you describe as Original is actually the DC clip, and Replace_Sequence is actually the Source clip.
With above interpretation, Note, that white crud at top of upper samples LEFT image (DC clip), will be making the result a little too light. [unless cropping off or using coords on that frame, is it damaged all through video ?].
EDIT: OK, I think I understood correctly.
'Replace_Sequence' frame [MIDDLE frame] is modified to color match 'Original' [LEFT frame] {hopefully not using cruddy area of Original} and then replaces the original 'Original' damage frame. 'Replace_Sequence_Gamatch', [RIGHT frame] is the color matched frame [MIDDLE frame, matched to LEFT frame] used to repair the damaged frame in the source clip.
lollo2
21st July 2018, 16:41
I apologize: I was not clear, but you understood correctly.
The names and the videos I used are of the final files after replacement and eventually GamMatch operations.
original = damaged video = DC - this is the damaged file where I want to replace a sequence
replace_sequence = Source - this is at the same time the result of the replacement without using GamMatch
replace_sequence_gammatch = GamMatch output - this is at the same time the result of the replacement and the usage of GmaMatch
DC is unchanged in the comparison image, but it has been modified in the script to match frame by frame Source and to remove the
bad frames as the one you mentioned for proper GamMatch operations.
StainlessS
21st July 2018, 17:01
I thinks we gots it, thanx Commander Straker :)
lollo2
21st July 2018, 17:21
I thinks he thanks you because your plugin makes his face looking similar to my reference ;-)
https://s6.postimg.cc/f02yrpdj5/comp2.jpg (https://postimg.cc/image/b3pmvpsjh/)
lollo2
23rd July 2018, 11:31
In addition to color match, there is another reason why I prefer GamMatch.
As told, I have bad frames that I have to replace with previous good frame (video_ref_seq_ria_sos)
HistogramAdjust and MatchHistogram match the color of the reference (in the left portion, the color of the face tend to be similar to the color of
the hair); it is ok, but it does not work in my case.
GamMatch, with its different approach, shows better results in my case.
I hope this could be of some utility for somebody else...
https://s6.postimg.cc/fbph1pam9/comp3.jpg (https://postimg.cc/image/e9faj5rst/)
JoeSuper8
26th July 2018, 04:53
Thanks StainlessS for looking into those color bar issues.
Fred in the meantime, are there any additional instructions on how to use a detect clip with gammac?
I could not successfully follow your post from last year on the detect clip: https://forum.doom9.org/showthread.php?p=1803528#post1803528
videoFred
26th July 2018, 16:16
I could not successfully follow your post from last year on the detect clip: https://forum.doom9.org/showthread.php?p=1803528#post1803528
??? What could you not follow?
Fred.
Zetti
5th August 2018, 13:10
This should hopefully be of use.
All it does is pass on args to respective plugins.
Some of the AutoLevels args are not passed where it makes no sense, eg the gamma related ones.
Function AutoLevelsGamMac(clip c,
\ Bool "DoAutoLevels", bool "DoGamMac",
\ int "filterRadius",int "sceneChgThresh",String "frameOverrides",
\ int "input_low",int "input_high",int "output_low",int "output_high",float "ignore",float "ignore_low",float "ignore_high",
\ int "border",int "border_l",int "border_r",int "border_t",int "border_b",bool "debug",
\ int "LockChan",Float "LockVal",Float "RedMul",Float "GrnMul", Float "BluMul",
\ Float "MinLim",Float "MaxLim",float "GamLo",Float "GamHi",Bool "Show",int "Verbosity") {
c
DoAutoLevels=Default(DoAutoLevels,True) DoGamMac=Default(DoGamMac,True)
(DoAutoLevels)
\ ? Autolevels(filterRadius=filterRadius,sceneChgThresh=sceneChgThresh,frameOverrides=frameOverrides,
\ input_low=input_low,input_high=input_high,output_low=output_low,output_high=output_high,
\ ignore=ignore,ignore_low=ignore_low,ignore_high=ignore_high,
\ border=border,border_l=border_l,border_r=border_r,border_t=border_t,border_b=border_b,
\ debug=debug)
\ : NOP
(DoGamMac)
\ ? GamMac(LockChan=LockChan,LockVal=LockVal,RedMul=RedMul,GrnMul=GrnMul,BluMul=BluMul,
\ MinLim=MinLim,MaxLim=MaxLim,GamLo=GamLo,GamHi=GamHi,
\ Show=Show,Verbosity=Verbosity)
\ : NOP
Return Last
}
#Imagesource("test_RGB_Doom.jpg",end=0) Crop(0,0,width/2,height/2) Crop(0,0,width/4*4,height/4*4)
Imagesource("G1.bmp",end=0) crop(0,0,0,-48) Spline36Resize(480,360) # Lollipop lady minus RHS and histograms
#Imagesource("G2.bmp",end=0) crop(0,0,0,-48) Spline36Resize(480,360) # Plant lady minus RHS and histograms
#Imagesource("G3.bmp",end=0) crop(0,0,0,-48) Spline36Resize(480,360) # Avenue minus RHS and histograms
#Imagesource("G4.bmp",end=0) crop(0,0,0,-48) Spline36Resize(480,360) # Walkers minus RHS and histograms
#Imagesource("G5.bmp",end=0) crop(0,0,0,-48) Spline36Resize(480,360) # Parot minus RHS and histograms
#Imagesource("G6.bmp",end=0) crop(0,0,0,-48) Spline36Resize(480,360) # Deer minus RHS and histograms
#Imagesource("G7.bmp",end=0) crop(0,0,0,-48) Spline36Resize(480,360) # Taj Mahal minus RHS and histograms
#Imagesource("G8.bmp",end=0) crop(0,0,0,-48) Spline36Resize(480,360) # Puppy minus RHS and histograms
#Avisource("1937 Lund Utah 16mm Film [Low, 360p].mp4.avi")
#Avisource("1941 Flint Michigan Parade [Low, 360p].mp4.AVI")
#Avisource("v.avi")
#A=Trim(0,99)
#B=A.BlankClip(length=1) # Test Black Frame @ 100
#C=A.BlankClip(length=1,Color=$FFFFFF) # Test White Frame @ 101
#D=Trim(100,0)
#A++B++C++D
ConvertToRGB24
ORG=Last
LockChan = 1 # Chan for lock to Ave, 0=R, 1=G, 2=B
# -1 = Use LockVal below.
# -2 = LockVal=(RedAve+GrnAve+BluAve)/3.0 for LockVal.
# -3 = LockVal=Median(RedAve,GrnAve,BluAve)
LockVal = 128 # Only valid if LockChan == -1
GamHi = 4.0 # Extreme values for guess gamma (starting guess range and limit)
GamLo = 0.25 # Extreme values for guess gamma (starting guess range and limit)
RedMul = 1.00 # Required Ave multiplier for Red Channel, applied when requesting GuessGamma(reqAve*RedMul), Even applied when LockChan=-1.
GrnMul = 1.00 # Same for Green channel. GrnMul even applies when LockChan is Green Channel, etc for chans.
BluMul = 1.0 # Same for Blue channel. Allows tinkering/fine tuning.
MinLim = 32.0 # If Original channel Ave lesser then DO NOT FIX.
MaxLim = 255.0-32.0 # If Original channel Ave greater then DO NOT FIX.
Show = true # Subtitles
Verbosity= 1 # 0=Only Upper metrics, 1(default)=Upper + important ones. 2=All metrics.
A= AutoLevelsGamMac(DoGamMac=False)
B= AutoLevelsGamMac(DoAutoLevels=false,LockChan=LockChan,LockVal=LockVal,RedMul=RedMul,GrnMul=GrnMul,BluMul=BluMul,Show=Show,Verbosity=Verbosity)
C= AutoLevelsGamMac(LockChan=LockChan,LockVal=LockVal,RedMul=RedMul,GrnMul=GrnMul,BluMul=BluMul,Show=Show,Verbosity=Verbosity)
TOP=StackHorizontal(ORG,A)
BOT=StackHorizontal(B,C)
StackVertical(TOP,BOT)
return Last
EDIT:
That IanB quote was from the AutoLevels thread, I assume that Frustum corrected it in later versions of AutoLevels
to match what IanB said.
Is this the only setting AutoLevelsGamMac() or is there more settings i can't see??
StainlessS
5th August 2018, 13:17
That was prior to Scale=2 setting, try GamMac(Scale=2).
EDIT: Was implemented in this post:- https://forum.doom9.org/showthread.php?p=1774775#post1774775
Zetti
5th August 2018, 13:32
Thanks for info.
I will try it.
Zetti
5th August 2018, 15:34
I like the result with GamMac(Scale=2)
But i hope i have understand it right, that i can limit the colors with RedMul, GrnMul and BluMul
Like this way GamMac(Scale=2, BluMul=0.9,Show=false)
StainlessS
5th August 2018, 16:02
You can reduce blue content as in your example, but maybe Scale=2 is not the right one for the job, try Scale=1.
Scale = 2 is a little ferocious, and modifies each channel separately (each chan min and max), whereas Scale = 1,
finds minimum_of_any_Channel(min) and maximum_of_any_Channel(max), and uses those.
Scale=1 is safest, but sometimes dont look as good.
EDIT: Scale=0, uses 0 and 255 for all input mins/maxs.
Zetti
5th August 2018, 16:17
Thanks now can i see the last details for now, that's good.
GamMac is a good new toy.
johnmeyer
20th August 2018, 01:40
I finally got around to upgrading my film script to include GamMac & FredAverage. I pre-grade my film in Vegas by roughly correcting colors and gamma on each section of film, but my goal is to the let GamMac do the final adjustments, scene-by-scene, on both color and gamma.
Here is one frame showing the results. I know what the colors should be because I grew up there fifty years ago, and the colors of the wall and green coach are now absolutely perfect. Also note the color corrections on the white trim on the door in the background and the white wrapping paper he is holding. Very nice, StainlessS & VideoFred:
https://forum.doom9.org/attachment.php?attachmentid=16457&stc=1&d=1534723997
I've copied below the variables I've used, along with the relevant sections of the script showing how I'm calling GamMac and FredAverage.
With that as background, I have one question:
How to I globally increase the gamma (brightness) a little? The only way I see to do this is to increase the three RGB "Mul" values from 1.0 to a higher value, and to avoid adding a color shift, make sure that all three have the same value. Is there a better way than this to get GamMac to make the result slightly brighter in the midtones without changing the darkest or brightest pixels, and without upsetting the color correction?
.....
Here are the relevant GamMac and FredAverage parameters that I'm using:
#GamMac Parameters
LockChan = 1 #(0=red channel)
LockVal = 128.0 #default 128 -- Used when LockChan = -1 (for flicker)
Scale = 2 #Fred recommended 2 instead of 1
RedMul = 1.1
GrnMul = 1.1
BluMul = 1.1
Th = 0.1
GMx = 0
GMy = 0
GMw = 0
GMh = 0
LOTH = 0.20
HITH = 0.20
OMIN = 5 #limiting the output a little bit makes it a little 'softer' to look at
OMAX = 250
Al2 = 20
autolev_bord1 = 50
borderV=10 borderH=10
And here are the lines where I call each function:
Baseclip = PreBorderFrame.crop(borderV,borderH,-borderV,-borderH,align=true).bicubicresize(W,H)
blank_black = Blankclip(baseclip, width=autolev_bord1,height=autolev_bord1)
blank_white= Blankclip(baseclip, width=autolev_bord1,height=autolev_bord1, color=$FFFFFF)
Average= baseclip.FredAverage().invert()
over1 = overlay(baseclip,blank_black, x=40,y=300)
over2 = overlay (over1,blank_white, x=160, y=300) \
.bicubicresize(width(baseclip)-(al2)*2,height(baseclip)-(al2)*2)
Detect = (al2 >1) ? overlay (Average, over2,x=al2,y=al2) \
.converttoRGB24(matrix="rec709") : over2.converttoRGB24(matrix="rec709")
result1= PreBorderFrame.ConvertToRGB24.GamMac(verbosity=4,DC=Detect,Show=True, \
LockChan=LockChan, Th=Th, LockVal=LockVal, Scale=Scale, RedMul=RedMul,\
GrnMul=GrnMul, BluMul=BluMul, loTh=LOTH,hiTh=HITH,oMin=OMIN,oMax=OMAX,\
x=GMx,y=GMy,w=GMw,h=GMh).converttoYV12().deflicker().addborders(X,0,0,0,$FFFFFF) \
.addborders(0,0,X2,0,$000000).autolevels(filterRadius=2).crop(X,0,-X2,-0) \
.addborders(bord_left+in_bord_left, bord_top+in_bord_top, \
bord_right+in_bord_right, bord_bot+in_bord_bot)
StainlessS
20th August 2018, 05:28
You have done it exactly the way I would have suggested.
(I guess that you could add your own stub function with float JohnGamma arg, and adjust all three channels as per that arg).
The Reason that I added the multiplier (redmul etc) args was to counteract some unintended colorshift.
for(i=0;i<3;++i) {
reqAve[i]= lockval*rgbMul[i];
...
}
Above, GuessGamma() would try find gamma function that produces equivalent to reqAve[] (required channel average), where
lockval is either a fixed setting of gotten from average of one of the channels (or eg median of all three) .
Perhaps there should have been an additive setting instead of (or as well as) the multiplicative ones.
johnmeyer
20th August 2018, 05:56
StainlessS,
No need to change anything or add more variables. I just wanted to make sure I wasn't missing some obvious setting.
johnmeyer
20th August 2018, 17:38
Well, I still need an answer to my original question. It turns out that the three "Mul" settings don't actually change gamma, at least not how I have always defined that term. A gamma curve should change the luma of the pixels in the middle of the luma range while leaving the really bright and really dark pixels relatively unchanged. However, by changing the usual 1.0 settings to 1.1, as follows:
RedMul = 1.1
GrnMul = 1.1
BluMul = 1.1
I ended up with my blacks getting washed out, with the floor going from about 5 to 10 (on a 0-100 scale). You can see the effect in my NLE, along with the waveform display of the result:
Before
https://forum.doom9.org/attachment.php?attachmentid=16461&stc=1&d=1534782860
After
https://forum.doom9.org/attachment.php?attachmentid=16462&stc=1&d=1534782968
So, I'm still looking to find a way for the "Gam" in GamMac to work like a real gamma function. For the time being, I have it working just fine by returning the three values above to 1.0. Even if I can't use it to control gamma, it is still amazingly useful as an automated color corrector.
Danette
6th January 2019, 00:50
Would like to try this but, can't get past an initial error from the avsi file.
It reports a script error on line 1, column 9.
I'm sure it's something basic/simple. Of course, a dll would solve so many application errors such as this. Can anyone point me in the right direction? Trying to apply it from AvsPmod.
StainlessS
6th January 2019, 01:30
Which script (Post it) and what error message ?
EDIT: This is current script in GamMac v1.10 (and it aint an avsi, DONT PUT IN Plugins)
Imagesource("GreenChurch.png",end=0)
#Imagesource("Puppy.png",end=0)
#Imagesource("lennaRed.png",end=0)
ConvertToRGB24.KillAudio
#Spline36Resize(512,384)
O=Last
DC=Last
#DC=DC.Blur(1.0) # Detection Clip (uses source clip if dc not supplied, Denoised or whatever)
#DC=DC.BilinearResize(320,240) # Test DC not same size as source
LockChan = 1 # Chan for lock to Ave, 0=R, 1=G, 2=B
# -1 = Use LockVal below.
# -2 = LockVal=(RedAve+GrnAve+BluAve)/3.0 for LockVal.
# -3 = LockVal=Median(RedAve,GrnAve,BluAve)
Scale=1
RedMul = 1.0 # Required Ave multiplier for Red Channel, applied when requesting GuessGamma(reqAve*RedMul), Even applied when LockChan=-1.
GrnMul = 1.0 # Same for Green channel. GrnMul even applies when LockChan is Green Channel, etc for chans.
BluMul = 1.0 # Same for Blue channel. Allows tinkering/fine tuning.
Th = 0.0
LockVal = 128.0 # Only valid if LockChan == -1
RngLim = 11
GamMax = 10.0
Show = True # Metrics
Verb = 5 # Verbocity FULL
SHOWCOORDS= True # Show Original with Coords
DITHER=FALSE
x =5 # Coords (for dc Detection Clip)
y =5
w=-5
h=-5
omin=5 # Output channels minimum (footroom for manual editing).
omax=250 # Output channels maximum (headroom for manual editing).
#Return GamMac(DC,x=x,y=y,w=w,h=h,Coords=True) # Show Coords only
Scale=0
A_TEXT = RT_String("Scale=%d rMul=%.2f gMul=%.2f bMul=%.2f",Scale,RedMul,GrnMul,BluMul)
A=GamMac(LockChan=LockChan,SCALE=SCALE,RedMul=RedMul,GrnMul=GrnMul,BluMul=BluMul,
\ Th=Th,LockVal=LockVal,RngLim=RngLim,GamMax=GamMax,
\ dc=DC,
\ x=x,y=y,w=w,h=h,
\ omin=omin,omax=omax,
\ Show=Show,Verbosity=Verb,dither=DITHER)
Scale=1 BluMul=1.05
B_TEXT = RT_String("Scale=%d rMul=%.2f gMul=%.2f bMul=%.2f",Scale,RedMul,GrnMul,BluMul)
B=GamMac(LockChan=LockChan,SCALE=SCALE,RedMul=RedMul,GrnMul=GrnMul,BluMul=BluMul,
\ Th=Th,LockVal=LockVal,RngLim=RngLim,GamMax=GamMax,
\ dc=DC,
\ x=x,y=y,w=w,h=h,
\ omin=omin,omax=omax,
\ Show=Show,Verbosity=Verb,dither=DITHER)
Scale=2 BluMul=0.95
C_TEXT = RT_String("Scale=%d rMul=%.2f gMul=%.2f bMul=%.2f",Scale,RedMul,GrnMul,BluMul)
C=GamMac(LockChan=LockChan,SCALE=SCALE,RedMul=RedMul,GrnMul=GrnMul,BluMul=BluMul,
\ Th=Th,LockVal=LockVal,RngLim=RngLim,GamMax=GamMax,
\ dc=DC,
\ x=x,y=y,w=w,h=h,
\ omin=omin,omax=omax,
\ Show=Show,Verbosity=Verb,dither=DITHER)
COORDS=O.GamMac(dc=DC,x=x,y=y,w=w,h=h,Coords=True)
ODC=((SHOWCOORDS)?COORDS.Spline36Resize(width,Height):O) # Resize COORDS (Not necessarily the same sizse as source clip)
ODC_TEXT=(SHOWCOORDS)?"Detect Clip with Coords":"Original"
TOP=StackHorizontal(TSub(ODC,ODC_TEXT,true),TSub(A,A_TEXT))
BOT=StackHorizontal(TSub(B,B_TEXT),TSub(C,C_TEXT))
StackVertical(TOP,BOT)
return Last
# Stack Overhead Subtitle Text, with optional FrameNumber shown.
Function TSub(clip c,string Tit,Bool "ShowFrameNo"){
c.BlankClip(height=20)
(Default(ShowFrameNo,False))?ScriptClip("""Subtitle(String(current_frame,"%.f] """+Tit+""""))"""):Subtitle(Tit)
Return StackVertical(c).AudioDubEx(c)
}
NOTE, for some reason W7 (probably later too) dont work properley without a path, so try change
Imagesource("GreenChurch.png",end=0)
To
Imagesource(".\GreenChurch.png",end=0) # Current directory
or
Imagesource("D:\SomeFolder\GreenChurch.png",end=0)
Danette
8th January 2019, 02:13
Which script (Post it) and what error message ?
EDIT: This is current script in GamMac v1.10 (and it aint an avsi, DONT PUT IN Plugins)
Oh, I thought it was an avsi script. I'll give it a try. So, I just place it under my other script? Where do I get the image files?
StainlessS
8th January 2019, 02:57
I posted this:- http://www.mediafire.com/file/rdk5du4h3c114z4/GamMacSubs.zip/file
somewhere in the thread.
EDIT: Was posted here:- https://forum.doom9.org/showthread.php?p=1825394#post1825394
Above also links to JohnMeyer parade clip.
Danette
8th January 2019, 15:26
I posted this:- http://www.mediafire.com/file/rdk5du4h3c114z4/GamMacSubs.zip/file
somewhere in the thread.
EDIT: Was posted here:- https://forum.doom9.org/showthread.php?p=1825394#post1825394
Above also links to JohnMeyer parade clip.
Thanks. I was almost there and then it stumbled on what I suspect is a compatibility issue. It wouldn't recognize GamMac or RT_String. Is this not compatible with Avisynth+?
StainlessS
8th January 2019, 16:01
RT_String is part of RT_Stats. (See meidafire in sig below this post)
Current GamMac has dll for avs/+ v2.60 x86 and x64. (loadPlugin or put in plugins dir)
EDIT: Also, GamMatch, is a different plugin to GamMac.
Danette
8th January 2019, 22:01
RT_String is part of RT_Stats. (See meidafire in sig below this post)
Current GamMac has dll for avs/+ v2.60 x86 and x64. (loadPlugin or put in plugins dir)
EDIT: Also, GamMatch, is a different plugin to GamMac.
Thanks. That pulled it all together.
I'm not used to working in RGB. Everything I've done is in YUV. For YUV, I find that the filter "WhiteBalance" is exceptional. However, the image results with your analytical tool may be superior.
So, what filter(s) do you use to apply the results of your output?
StainlessS
9th January 2019, 04:46
Some filters only make sense in RGB.
So, what filter(s) do you use to apply the results of your output?
Have you tried ConvertToYV12 at end of script.
Danette
9th January 2019, 06:05
Some filters only make sense in RGB.
Have you tried ConvertToYV12 at end of script.
I agree, but have not done so as yet, so I'm not familiar with them. Which RGB filters have you found most useful for applying the results of your GamMac tool?
Ultimately, I do convert to YV12 for x264 purposes, but my understanding is that it is the least useful in dealing with colors..
StainlessS
10th January 2019, 11:12
Which RGB filters have you found most useful for applying the results of your GamMac tool?
Not sure that uderstand what you mean there, GamMac is the filter for applying GamMac results to an RGB clip.
ConvertToYV12 is used at end of script so as to use YV12 and better lossy compression for encode.
Danette
10th January 2019, 21:31
Not sure that uderstand what you mean there, GamMac is the filter for applying GamMac results to an RGB clip.
ConvertToYV12 is used at end of script so as to use YV12 and better lossy compression for encode.
The issue may be that I'm simply not applying it correctly. I have the video source in the script and then I have the GamMac script below that with the final ConverttoYV12 at the end. When I run the avs cotaining this layout, in VirtualDub (for example), the only thing that appears are the many images of the particular image selected from the video stream. These are the same images that appear in AvsPmod with the values for each image.
I thought your script was designed to provide the values that would then be applied to a filter that would be used to process the video. Your note, above, seems to indicate that this script alone should be processing it but, as I indicated, there is no processing going on when applied.
StainlessS
10th January 2019, 23:02
Ok, I understand, you have no idea about scripting,
after this line,
C=GamMac(LockChan=LockChan,SCALE=SCALE,RedMul=RedMul,GrnMul=GrnMul,BluMul=BluMul,
\ Th=Th,LockVal=LockVal,RngLim=RngLim,GamMax=GamMax,
\ dc=DC,
\ x=x,y=y,w=w,h=h,
\ omin=omin,omax=omax,
\ Show=Show,Verbosity=Verb,dither=DITHER)
add return C.ConvertToYV12
(Also set Show=false in config near begining of script.)
Mobile:
Danette
10th January 2019, 23:36
Ok, I understand, you have no idea about scripting,
after this line,
C=GamMac(LockChan=LockChan,SCALE=SCALE,RedMul=RedMul,GrnMul=GrnMul,BluMul=BluMul,
\ Th=Th,LockVal=LockVal,RngLim=RngLim,GamMax=GamMax,
\ dc=DC,
\ x=x,y=y,w=w,h=h,
\ omin=omin,omax=omax,
\ Show=Show,Verbosity=Verb,dither=DITHER)
add return C.ConvertToYV12
(Also set Show=false in config near begining of script.)
Mobile:
LOL!!! You're certainly right about my scripting abilities. I looked through your and Bernard's discussions and almost fell asleep!
Anyway, I tried your recommendations and still have only a single image that results from the script with no video processing ability..
I switched out True for False as you suggested and created the following at the end:
C=GamMac(LockChan=LockChan,SCALE=SCALE,RedMul=RedMul,GrnMul=GrnMul,BluMul=BluMul,
\ Th=Th,LockVal=LockVal,RngLim=RngLim,GamMax=GamMax,
\ dc=DC,
\ x=x,y=y,w=w,h=h,
\ omin=omin,omax=omax,
\ Show=Show,Verbosity=Verb,dither=DITHER)
return C.ConvertToYV12()
The "C.ConvertToYV12()" replacing this script:
COORDS=O.GamMac(dc=DC,x=x,y=y,w=w,h=h,Coords=True)
ODC=((SHOWCOORDS)?COORDS.Spline36Resize(width,Height):O) # Resize COORDS (Not necessarily the same sizse as source clip)
ODC_TEXT=(SHOWCOORDS)?"Detect Clip with Coords":"Original"
TOP=StackHorizontal(TSub(ODC,ODC_TEXT,true),TSub(A,A_TEXT))
BOT=StackHorizontal(TSub(B,B_TEXT),TSub(C,C_TEXT))
StackVertical(TOP,BOT)
return Last
# Stack Overhead Subtitle Text, with optional FrameNumber shown.
Function TSub(clip c,string Tit,Bool "ShowFrameNo"){
c.BlankClip(height=20)
(Default(ShowFrameNo,False))?ScriptClip("""Subtitle(String(current_frame,"%.f] """+Tit+""""))"""):Subtitle(Tit)
Return StackVertical(c).AudioDubEx(c)
}
If I understand you correctly.
StainlessS
11th January 2019, 00:18
only a single image that results from the script with no video processing ability
Again, I'm wondering what that means.
C is the result of GamMac filter, whatever you want to do, do it to C,
eg
C=Gammac(... etc)
C=C.FlipHorizontal # or whatever
return C.ConvertToYV12
You need to spend some time learning to script, or choose some other video processing app.
EDIT: In the MediaFire link in my sig below this post, in the DATA folder, there is a compressed help (*.chm file for v2.60)
which you can put on a hotkey (create a shortcut, Properties, and add a Shortcut key).
You can access each and every file via the HTML table of files (so you dont have to wander around in circles,
never knowing if you have read everything).
https://i.postimg.cc/k2mHvBWt/chm.png (https://postimg.cc/k2mHvBWt)
Danette
11th January 2019, 00:56
Again, I'm wondering what that means.
I fed exactly what I posted into VirtualDub and the only output is a single frame, not the source video.
You need to spend some time learning to script, or choose some other video processing app.
Not quite true, but true if I want to be able to use this code. Time is the most precious resource and mine is far more productive placed elsewhere, which is the choice I’ve made. I was looking for a canned application without having to delve into the minutiae. I have to remind my chemists all the time that it’s good to understand the detail, but making it valued by the many, requires converting that detail into the practical.
EDIT: In the MediaFire link in my sig below this post, in the DATA folder, there is a compressed help (*.chm file for v2.60)
which you can put on a hotkey (create a shortcut, Properties, and add a Shortcut key).
You can access each and every file via the HTML table of files (so you dont have to wander around in circles,
never knowing if you have read everything).
https://i.postimg.cc/k2mHvBWt/chm.png (https://postimg.cc/k2mHvBWt)
Thanks for attempting to help, but it’s a little too much for my end result. I’ll stay with “WhiteBalance”, which may be only slightly inferior.
StainlessS
11th January 2019, 12:02
output is a single frame, not the source video.
Yeh well as the input to the script in zip is a single frame, then that is not so surprising, if you want to process a video then feed it a video.
modified a bit
Imagesource(".\GreenChurch.png",end=0) # SINGLE FRAME (end=0)
#Imagesource(".\Puppy.png",end=0)
#Imagesource(".\lennaRed.png",end=0)
#Avisource(".\SomeVideo.avi") # Video Clip
ConvertToRGB24.KillAudio
DC=Last
DC=DC.Blur(0.2) # Detection Clip (uses source clip if dc not supplied, Denoised or whatever)
LockChan = 1 # Chan for lock to Ave, 0=R, 1=G, 2=B
# -1 = Use LockVal below.
# -2 = LockVal=(RedAve+GrnAve+BluAve)/3.0 for LockVal.
# -3 = LockVal=Median(RedAve,GrnAve,BluAve)
Th = 0.0
LockVal = 128.0 # Only valid if LockChan == -1
Show = True # Metrics
Verb = 5 # Verbocity FULL
DITHER=FALSE
x =0 # Coords (for dc Detection Clip)
y =0
w=-0
h=-0
omin=0 # Output channels minimum (footroom for manual editing).
omax=255 # Output channels maximum (headroom for manual editing).
#Return GamMac(DC,x=x,y=y,w=w,h=h,Coords=True) # Show Coords only
Scale=2
RedMul=1.0
GrnMul=1.0
BluMul=0.95
C=GamMac(LockChan=LockChan,SCALE=SCALE,RedMul=RedMul,GrnMul=GrnMul,BluMul=BluMul,
\ Th=Th,LockVal=LockVal,
\ dc=DC,
\ x=x,y=y,w=w,h=h,
\ omin=omin,omax=omax,
\ Show=Show,Verbosity=Verb,dither=DITHER)
#C=C.FlipHorizontal # or whatever
return C.ConvertToYV12
Danette
12th January 2019, 00:33
Yeh well as the input to the script in zip is a single frame, then that is not so surprising, if you want to process a video then feed it a video.
Thanks, @StainlessS. It was, as you said in a previous post, a lack of in-depth understanding of the script functioning. I had both the AVIsource and Imagesource listed, thinking the script needed to reference the image to identify the needed changes. I removed the imagesource and it works fine.
Unfortunately, GamMac doesn't do nearly as good a job as the WhiteBalance filter ...in my case. I will keep it in mind, though, as it does provide much better balance than the original source and may be better than the WhiteBalance filter in other video that I will be restoring.
StainlessS
12th January 2019, 10:29
EDIT:
This lot are all intended to be user configured,
LockChan = 1 # Chan for lock to Ave, 0=R, 1=G, 2=B
# -1 = Use LockVal below.
# -2 = LockVal=(RedAve+GrnAve+BluAve)/3.0 for LockVal.
# -3 = LockVal=Median(RedAve,GrnAve,BluAve)
Th = 0.0
LockVal = 128.0 # Only valid if LockChan == -1
Show = True # Metrics
Verb = 5 # Verbocity FULL
DITHER=FALSE
x =0 # Coords (for dc Detection Clip)
y =0
w=-0
h=-0
omin=0 # Output channels minimum (footroom for manual editing).
omax=255 # Output channels maximum (headroom for manual editing).
#Return GamMac(DC,x=x,y=y,w=w,h=h,Coords=True) # Show Coords only
Scale=2
RedMul=1.0
GrnMul=1.0
BluMul=0.95
Scale=2, is a very ferocious setting,
you could also try eg Scale=1 (or Scale=0), and recommend change BluMul=1.0 (0.95 was specific to the Church image result which is too blue).
EDIT: You could also try Bernardd's automatic White Balance script:- https://forum.doom9.org/showthread.php?p=1861382#post1861382
Danette
13th January 2019, 00:21
EDIT:
This lot are all intended to be user configured,
Scale=2, is a very ferocious setting,
you could also try eg Scale=1 (or Scale=0), and recommend change BluMul=1.0 (0.95 was specific to the Church image result which is too blue).
EDIT: You could also try Bernardd's automatic White Balance script:- https://forum.doom9.org/showthread.php?p=1861382#post1861382
Thanks for pointing those variables out. I played with them a little today, but saw no changes between scale=0 or scale=2 (and more). Same thing with the BluMul. Also took a look at Bernard’s white balance. since it's in avs form, I'll give it a try.
I think I’m settled on WhiteBalance. I find that setting the black RGB values initially to 0 and adjusting only the white RGB settings, I can get into the right ballpark. Then, using Histogram(levels) and adjusting the black R&B values to center the graphs, I can easily get what I find to be excellent color balance that I just can’t beat with any number of tweakings in many different color adjusters, such as GamMac, ColorYUV, AWB, Tweak, HDRAGC as well as several Vdub filters.
Taurus
13th January 2019, 16:25
I played with them a little today, but saw no changes between scale=0 or scale=2 (and more). Same thing with the BluMul....
If you cant see any differences between scales 0 -> 2
and/or BluMul you must be blind or your gammac script simply does not work...:D
Please post you entire script.
Because for me even subtile changes from the defaults are altering the output sometimes in dramatical ways.
Danette
14th January 2019, 00:21
If you cant see any differences between scales 0 -> 2
and/or BluMul you must be blind or your gammac script simply does not work...:D
Please post you entire script.
Because for me even subtile changes from the defaults are altering the output sometimes in dramatical ways.
Below is the script. When I change the BluMul, I can see the 1st quadrant change. However, the 4th quadrant does not. Nor does any quadrant change when I change the scale to 0, 1 or 2.
AVISource("C:\Users\Main\Desktop\Videos\Home Movies\1995-05-14 To 1996-01.avi")
Trim(209006,226575).FadeIn(60) + Trim(226679,237540).FadeOut2(60)
ConvertToRGB24.KillAudio
#Spline36Resize(512,384)
O=Last
DC=Last
#DC=DC.Blur(1.0) # Detection Clip (uses source clip if dc not supplied, Denoised or whatever)
#DC=DC.BilinearResize(320,240) # Test DC not same size as source
LockChan = 1 # Chan for lock to Ave, 0=R, 1=G, 2=B
# -1 = Use LockVal below.
# -2 = LockVal=(RedAve+GrnAve+BluAve)/3.0 for LockVal.
# -3 = LockVal=Median(RedAve,GrnAve,BluAve)
Scale=1
RedMul = 1.0 # Required Ave multiplier for Red Channel, applied when requesting GuessGamma(reqAve*RedMul), Even applied when LockChan=-1.
GrnMul = 1.0 # Same for Green channel. GrnMul even applies when LockChan is Green Channel, etc for chans.
BluMul = 1.0 # Same for Blue channel. Allows tinkering/fine tuning.
Th = 0.0
LockVal = 128.0 # Only valid if LockChan == -1
RngLim = 11
GamMax = 10.0
Show = True # Metrics
Verb = 5 # Verbocity FULL
SHOWCOORDS= True # Show Original with Coords
DITHER=FALSE
x =5 # Coords (for dc Detection Clip)
y =5
w=-5
h=-5
omin=5 # Output channels minimum (footroom for manual editing).
omax=250 # Output channels maximum (headroom for manual editing).
#Return GamMac(DC,x=x,y=y,w=w,h=h,Coords=True) # Show Coords only
Scale=0
A_TEXT = RT_String("Scale=%d rMul=%.2f gMul=%.2f bMul=%.2f",Scale,RedMul,GrnMul,BluMul)
A=GamMac(LockChan=LockChan,SCALE=SCALE,RedMul=RedMul,GrnMul=GrnMul,BluMul=BluMul,
\ Th=Th,LockVal=LockVal,RngLim=RngLim,GamMax=GamMax,
\ dc=DC,
\ x=x,y=y,w=w,h=h,
\ omin=omin,omax=omax,
\ Show=Show,Verbosity=Verb,dither=DITHER)
Scale=1 BluMul=1.05
B_TEXT = RT_String("Scale=%d rMul=%.2f gMul=%.2f bMul=%.2f",Scale,RedMul,GrnMul,BluMul)
B=GamMac(LockChan=LockChan,SCALE=SCALE,RedMul=RedMul,GrnMul=GrnMul,BluMul=BluMul,
\ Th=Th,LockVal=LockVal,RngLim=RngLim,GamMax=GamMax,
\ dc=DC,
\ x=x,y=y,w=w,h=h,
\ omin=omin,omax=omax,
\ Show=Show,Verbosity=Verb,dither=DITHER)
Scale=2 BluMul=0.95
C_TEXT = RT_String("Scale=%d rMul=%.2f gMul=%.2f bMul=%.2f",Scale,RedMul,GrnMul,BluMul)
C=GamMac(LockChan=LockChan,SCALE=SCALE,RedMul=RedMul,GrnMul=GrnMul,BluMul=BluMul,
\ Th=Th,LockVal=LockVal,RngLim=RngLim,GamMax=GamMax,
\ dc=DC,
\ x=x,y=y,w=w,h=h,
\ omin=omin,omax=omax,
\ Show=Show,Verbosity=Verb,dither=DITHER)
COORDS=O.GamMac(dc=DC,x=x,y=y,w=w,h=h,Coords=True)
ODC=((SHOWCOORDS)?COORDS.Spline36Resize(width,Height):O) # Resize COORDS (Not necessarily the same sizse as source clip)
ODC_TEXT=(SHOWCOORDS)?"Detect Clip with Coords":"Original"
TOP=StackHorizontal(TSub(ODC,ODC_TEXT,true),TSub(A,A_TEXT))
BOT=StackHorizontal(TSub(B,B_TEXT),TSub(C,C_TEXT))
StackVertical(TOP,BOT)
return Last
# Stack Overhead Subtitle Text, with optional FrameNumber shown.
Function TSub(clip c,string Tit,Bool "ShowFrameNo"){
c.BlankClip(height=20)
(Default(ShowFrameNo,False))?ScriptClip("""Subtitle(String(current_frame,"%.f] """+Tit+""""))"""):Subtitle(Tit)
Return StackVertical(c).AudioDubEx(c)
}
StainlessS
14th January 2019, 13:42
Couple of comment suggestions,
DC=DC.Blur(0.2) # Denoise Detection Clip [ avoid 'sparkles', prevent a few high/low extreme pixels from affecting histogram extremes too much ]
x =0 # Coords (for dc Detection Clip) [ if you have no need to avoid crud/noise around edges of DC clip ]
y =0
w=-0
h=-0
omin=0 # Output channels minimum (footroom for manual editing). [ If no need for extra user modification 'footroom/headroom', ie no further manual tweaking required ]
omax=255 # Output channels maximum (headroom for manual editing).
henryperu77
19th July 2019, 07:11
Please could someone help me to recover the natural colors of this cartoon? what settings should i use in GamMac ?
https://rej.lib.rochester.edu/files/original/a7ec3d07203006f17bf4dc6353a2772e.mp4
https://i.postimg.cc/ZBTTdKNP/beatles-film.jpg (https://postimg.cc/ZBTTdKNP)
Bernardd
19th July 2019, 09:13
Have you try RGBAdapt with this automatic help ? See post https://forum.doom9.org/showpost.php?p=1878904&postcount=52
henryperu77
19th July 2019, 09:34
Have you try RGBAdapt with this automatic help ? See post https://forum.doom9.org/showpost.php?p=1878904&postcount=52
Please could you explain how i can use it?
Bernardd
19th July 2019, 11:34
Have you try to upload the compressed file and read the documentation ? Can you precise your problem ?
henryperu77
19th July 2019, 14:22
Have you try to upload the compressed file and read the documentation ? Can you precise your problem ?
i want an example how to use it on a .avs
Bernardd
19th July 2019, 15:20
Here is Gammac Thread, i have posted answer on this thread https://forum.doom9.org/showpost.php?p=1879641&postcount=53
domb84
1st January 2025, 23:46
Hi, appreciate this is an old thread but this is exactly what I'm looking for to restore some old 8mm film. Is there a vapoursynth equivalent? I can't seem to find anything that will do as good a job as this would.
StainlessS
2nd January 2025, 11:51
I'm not aware of a vapoursynth equivalent, I believe that Selur sometimes does such magic.
EDIT: Although it may be more involved than a simple conversion.
real.finder
16th March 2025, 12:42
PlanarRGB not supported? I get weird color with it, also RGB48 (HBD RGB) supported? seems work
StainlessS
16th March 2025, 15:04
Supports only standard Avs 2.6 colorspaces, sorry.
StainlessS
16th March 2025, 16:36
@r.f
I seem to recall that you are a bit handy in scripting :)
maybe you can simulate GamMac requirement using this post
https://forum.doom9.org/showthread.php?p=1774190#post1774190
From thread that prompted GamMac
GSCript("""
Function ChanAve(clip c,int chan,int "n") {
# RT_ChanAve is colorspace agnostic, returns number of channels.
# Local vars result default Prefixed "RCA_", default chan0 local var = RCA_Ave_0. Chan 0=Red/Y, 1=Grn/U, 2=Blue/V
nChannels=c.RT_ChanAve(n=Default(n,0)) # nChannels unused
Return (chan==0)?RCA_Ave_0:(chan==1)?RCA_Ave_1:RCA_Ave_2
}
Function GuessGamma(clip c,int Chan,int "n",float "reqAve",Float "GamLo",float "GamHi",Bool "Debug") {
# Chan, 0=Red/Y, 1=Grn/U, 2=Blue/V
n=min(max(Default(n,0),0),c.FrameCount-1) c=c.Trim(n,-1)
reqAve=Default(reqAve,128.0) gamLo = Default(GamLo,1.0/4.0) gamHi = Default(GamHi,4.0) Debug=Default(Debug,true)
Result = -1.0 ADif=0.0001 PrevAve = -1.0
while(GamLo < GamHi) {
gamMid = (gamLo + gamHi) / 2.0
Ave = c.Levels(0,gamMid,255,0,255,coring=false).ChanAve(chan,0)
(Debug)?RT_DebugF("Chan=%d gamLo=%f : gamHi=%f : GamMid=%f : Ave=%f",chan,gamLo,gamHi,gamMid,Ave):NOP
if(abs(Ave-PrevAve)<=ADif) {Result = gamMid gamLo = gamHi + 1.0} # Force Exit, Not getting any nearer
else if(Ave < reqAve) {gamLo = gamMid}
else if(Ave > reqAve) {gamHi = gamMid}
PrevAve = Ave
}
Return Result
}
Function GamMac(clip c,int n,int "LockChan",Float "LockVal",
\ Float "RedMul",Float "GrnMul", Float "BluMul",
\ Float "MinLim",Float "MaxLim",float "GamLo",Float "GamHi",Bool "Show",int "Verbosity") {
n=min(max(n,0),c.FrameCount-1)
LockChan=Default(LockChan,1) # Default Green, 0 = Red, 1=Green, 2=Blue. -1=Use LockVal ALL channels. -2 use (RedAve+GrnAve+BluAVE)/3.0 for LockVal.
MinLim=Default(MinLim,32.0) MaxLim=Default(MaxLim,255.0-32.0) Show=Default(Show,False) Verbosity=Default(Verbosity,1)
Assert(LockChan>=-3 && LockChan<=3,"GamMac: LockChan -3 -> 2 Only")
LockVal=(LockChan>=0)?0.0:Float(Default(LockVal,128.0))
RedMul=Default(RedMul,1.0) GrnMul=Default(GrnMul,1.0) BluMul=Default(BluMul,1.0)
c=c.Trim(n,-1) cR=c.ShowRed cG=c.ShowGreen cB=c.ShowBlue
c.RT_ChanAve(n=0,Prefix="In_") # Simultaneous get all three averages
LockVal =
\ (LockChan==0) ? In_Ave_0:
\ (LockChan==1) ? In_Ave_1:
\ (LockChan==2) ? In_Ave_2:
\ (LockChan==-2) ? (In_Ave_0+In_Ave_1+In_Ave_2)/3.0:
\ (LockChan==-3) ? (In_Ave_0+In_Ave_1+In_Ave_2)-Max(In_Ave_0,In_Ave_1,In_Ave_2)-Min(In_Ave_0,In_Ave_1,In_Ave_2) :
\ LockVal
OffR=(In_Ave_0<MinLim || In_Ave_0>MaxLim)
OffG=(In_Ave_1<MinLim || In_Ave_1>MaxLim)
OffB=(In_Ave_2<MinLim || In_Ave_2>MaxLim)
gammaR = (OFFR)?1.0:(abs(In_Ave_0-LockVal*RedMul) < 0.0001)?1.0:cR.GuessGamma(0,reqAve=LockVal*RedMul,GamLo=GamLo,GamHi=GamHi)
gammaG = (OFFG)?1.0:(abs(In_Ave_1-LockVal*GrnMul) < 0.0001)?1.0:cG.GuessGamma(1,reqAve=LockVal*GrnMul,GamLo=GamLo,GamHi=GamHi)
gammaB = (OFFB)?1.0:(abs(In_Ave_2-LockVal*BluMul) < 0.0001)?1.0:cB.GuessGamma(2,reqAve=LockVal*BluMul,GamLo=GamLo,GamHi=GamHi)
fixedR = (Abs(gammaR-1.0)<0.0001)?cR:cR.Levels(0,gammaR,255,0,255,coring=false)
fixedG = (Abs(gammaG-1.0)<0.0001)?cG:cG.Levels(0,gammaG,255,0,255,coring=false)
fixedB = (Abs(gammaB-1.0)<0.0001)?cB:cB.Levels(0,gammaB,255,0,255,coring=false)
MergeRGB(fixedR,fixedG,fixedB)
if(Show) {
RT_ChanAve(n=0,Prefix="Out_") # Simultaneous get all three averages
RT_Subtitle("%d] \a!GamMac v0.00\a-\n" +
\ " \a2R \a4G \a1B\a-\n" +
\ "IN_AVE: %7.3f : %7.3f : %7.3f\n" +
\ "GAMMA : %7.3f : %7.3f : %7.3f\n" +
\ "OUTAVE: %7.3f : %7.3f : %7.3f",
\ n,In_Ave_0,In_Ave_1,In_Ave_2,
\ gammaR,gammaG,gammaB,
\ Out_Ave_0,Out_Ave_1,Out_Ave_2)
(Verbosity==1)
\ ? RT_Subtitle("Lockchan=%d LockVal=%.3f\nRedMul=%.3f GrnMul=%.3f BluMul=%.3f",LockChan,LockVal,RedMul,GrnMul,BluMul,align=1)
\ : (Verbosity!=0)
\ ? RT_Subtitle("Lockchan=%d LockVal=%.3f\nGamHi=%.3f GamLo=%.3f\nMinLim=%.3f MaxLim=%.3f\nRedMul=%.3f GrnMul=%.3f BluMul=%.3f",
\ LockChan,LockVal,GamHi,GamLo,MinLim,MaxLim,RedMul,GrnMul,BluMul,align=1)
\ : NOP
}
Return Last
}
""") # End of GScript
Imagesource("test_RGB_Doom.jpg",end=0)
Crop(0,0,width/2,height/2)
Crop(0,0,width/4*4,height/4*4)
#Avisource("1937 Lund Utah 16mm Film [Low, 360p].mp4.avi")
#Avisource("1941 Flint Michigan Parade [Low, 360p].mp4.AVI")
#Avisource("v.avi")
#A=Trim(0,99)
#B=A.BlankClip(length=1) # Test Black Frame @ 100
#C=A.BlankClip(length=1,Color=$FFFFFF) # Test White Frame @ 101
#D=Trim(100,0)
#A++B++C++D
ConvertToRGB32
ORG=Last
LockChan = 1 # Chan for lock to Ave, 0=R, 1=G, 2=B
# -1 = Use LockVal below.
# -2 = LockVal=(RedAve+GrnAve+BluAve)/3.0 for LockVal.
# -3 = LockVal=Median(RedAve,GrnAve,BluAve)
LockVal = 128.0 # Only valid if LockChan == -1
GamHi = 4.0 # Extreme values for guess gamma (starting guess range and limit)
GamLo = 0.25 # Extreme values for guess gamma (starting guess range and limit)
RedMul = 1.00 # Required Ave multiplier for Red Channel, applied when requesting GuessGamma(reqAve*RedMul), Even applied when LockChan=-1.
GrnMul = 1.00 # Same for Green channel. GrnMul even applies when LockChan is Green Channel, etc for chans.
BluMul = 1.00 # Same for Blue channel. Allows tinkering/fine tuning.
MinLim = 32.0 # If Original channel Ave lesser then DO NOT FIX.
MaxLim = 255.0-32.0 # If Original channel Ave greater then DO NOT FIX.
Show = true # Subtitles
Verbosity = 1 # 0=Only Upper metrics, 1(default)=Upper + important ones. 2=All metrics.
A=ScriptClip("GamMac(Last,current_frame,LockChan,LockVal,RedMul,GrnMul,BluMul,MinLim,MaxLim,GamLo,GamHi,Show,Verbosity)",
\ args="LockChan,LockVal,RedMul,GrnMul,BluMul,MinLim,MaxLim,GamLo,GamHi,Show,Verbosity")
BluMul=1.1
B=ScriptClip("GamMac(Last,current_frame,LockChan,LockVal,RedMul,GrnMul,BluMul,MinLim,MaxLim,GamLo,GamHi,Show,Verbosity)",
\ args="LockChan,LockVal,GamHi,GamLo,RedMul,GrnMul,BluMul,MinLim,MaxLim,Show,Verbosity")
BluMul=0.9
C=ScriptClip("GamMac(Last,current_frame,LockChan,LockVal,RedMul,GrnMul,BluMul,MinLim,MaxLim,GamLo,GamHi,Show,Verbosity)",
\ args="LockChan,LockVal,RedMul,GrnMul,BluMul,MinLim,MaxLim,GamLo,GamHi,Show,Verbosity")
TOP=StackHorizontal(ORG,A)
BOT=StackHorizontal(B,C)
StackVertical(TOP,BOT)
return Last
real.finder
16th March 2025, 18:31
Supports only standard Avs 2.6 colorspaces, sorry.
that unfortunate
@r.f
I seem to recall that you are a bit handy in scripting :)
maybe you can simulate GamMac requirement using this post
https://forum.doom9.org/showthread.php?p=1774190#post1774190
From thread that prompted GamMac
GSCript("""
...
return Last
well, I didn't do any serious avs filtering last few years, but I will try play with it, anyway, I don't think updating GamMac to work with PlanarRGB will be that hard, maybe even HBD also not hard from the script version of GamMac
anyway, maybe it's a good idea if https://forum.doom9.org/showthread.php?p=1862059 get update to work with YUV and HBD since GamMac will never get a real YUV Support, but GamMac maybe need HBD even if GamMatch get HBD because I think if we Match HBD clip with non-HBD one we will get non-HBD
StainlessS
16th March 2025, 19:27
I didn't do any serious avs filtering last few years
Dont think I've done much/any coding (c++) since start of covid, and I'm much busy doing other things of late.
I would really have to finalize RT_stats thingy first, and with about 170 different functions, its a very daunting prospect updating for HBD and new Avs+ stuff.
VideoMilk78
17th March 2025, 01:02
I don't think updating GamMac to work with PlanarRGB will be that hard, maybe even HBD also not hard from the script version of GamMac
I've been in the works of building an HDR super 8 scanner and once it's done I would be delighted to help test.
real.finder
17th March 2025, 07:14
Dont think I've done much/any coding (c++) since start of covid, and I'm much busy doing other things of late.
I would really have to finalize RT_stats thingy first, and with about 170 different functions, its a very daunting prospect updating for HBD and new Avs+ stuff.
RT_stats indeed need avs+ love :)
well, right now I don't feel like reinvent the wheel, maybe later but in any case I dont think I got VideoFred and your expertise in film Stuff
anyway, for now I used johnmeyer script https://forum.doom9.org/showthread.php?p=1849353#post1849353 as a base with my settings of AutoAdjust and Merge at last (since AutoAdjust sometimes can make some mistakes and Merge can make them less annoying, also it will help with the lack of HBD in GamMac now)
SetFilterMTMode("AutoAdjust", 3,true) #AutoAdjust will not work well with avs+ MT Prefetch without this (IIRC it will show some random corrupt images)
...
some 16bit YUV clip
a=last
ConvertToStacked
AutoAdjust(external_clip=a.Crop(32,32,-32,-32).blur(1.53).Convertbits(8),input_tv=false,output_tv=false,auto_gain=true,auto_balance=true,threads_count=0,gain_mode=1,use_interp=false,high_bitdepth=true) #I have hate and love felling with AutoAdjust since it's close source :angry:
ConvertFromStacked
ColorYUV(levels="PC->TV")
ConvertBits(8)
LoadPlugin("FredAverage_x64.dll")
Average= Blur(1.58).FredAverage().invert()
blank_black = Blankclip(last, width=50,height=50)
blank_white= Blankclip(last, width=50,height=50, color=$FFFFFF)
over1 = overlay(last,blank_black, x=40,y=300)
over2 = overlay (over1,blank_white, x=160, y=300)
ConvertToRGB24(matrix="Rec709", interlaced=false)
GamMac(RedMul=1.1,GrnMul=1.1,BluMul=1.1,Th=0.1,x=0,y=0,w=0,h=0,LOTH=0.20,HITH=0.20,OMIN=5,OMAX=250,show=false,dc=overlay (Average, over2,x=20,y=20).ConvertToRGB24(matrix="Rec709", interlaced=false))
ConvertToYUV420(matrix="Rec709", interlaced=false).ConvertBits(16)
Merge(last,a)
before
https://i.postimg.cc/1fcbwKvK/og.png (https://postimg.cc/1fcbwKvK)
after
https://i.postimg.cc/NKsS4rVv/Untitled.png (https://postimg.cc/NKsS4rVv)
FranceBB
17th March 2025, 09:58
I've been in the works of building an HDR super 8 scanner and once it's done I would be delighted to help test.
Another person from this forum, chmars, tried to do exactly that a few years ago (July 2021) (https://forum.doom9.net/showthread.php?p=1939068). What he did back then was recording the Super 8 in Slog3 HDR with a Sony FS7.
Examples here (left is Slog3 HDR, right is BT709 SDR with the LUT applied): Img1 (https://i.imgur.com/x7gIQRL.png) - Img2 (https://i.imgur.com/LtvYUVr.png) - Img3 (https://i.imgur.com/UZNv189.png) - Img4 (https://i.imgur.com/DbyJiqe.png)
Waveform: Img5 (https://i.imgur.com/Qb1WMID.png) - Curve: Img6 (https://i.imgur.com/eXo5eGp.png)
Back then we went on talking about Super 8 and whether it was worth even capturing in a totally logarithmic curve like Slog3. Here's the quote from that time:
back when 8mm / Super 8 were a thing I wasn't even born and I don't really know much about their technology and how many stops the cameras had at the time, but I wouldn't be surprised if they turned out to have less than 6 stops (so less than the standard 100 nits SDR)...
The reasoning being that I've seen a few Super 8 footages recorded in various conditions. I mean, projected in real life, not the BT709 captures. I remember a scene in one of them made by a friend of mine (another encoder like me, now retired) at the beach in which there was a big rock in the water. The recording was from the back of the rock, so probably a zoom of some sort from the shore, and while the top of the rock was well lit, the bottom was in the dark and the shadows had no details at all, I mean, blacks looked completely clipped out. So... the question is: is it actually worth recording Super 8 reels in HDR in a totally logarithmic curve like Slog3 or is it completely useless as those cameras had less than 6 stops and therefore couldn't even fill the 100 nits of the regular BT709?
VideoMilk78
17th March 2025, 19:26
Another person from this forum, chmars, tried to do exactly that a few years ago (July 2021) (https://forum.doom9.net/showthread.php?p=1939068). What he did back then was recording the Super 8 in Slog3 HDR with a Sony FS7.
Examples here (left is Slog3 HDR, right is BT709 SDR with the LUT applied): Img1 (https://i.imgur.com/x7gIQRL.png) - Img2 (https://i.imgur.com/LtvYUVr.png) - Img3 (https://i.imgur.com/UZNv189.png) - Img4 (https://i.imgur.com/DbyJiqe.png)
Waveform: Img5 (https://i.imgur.com/Qb1WMID.png) - Curve: Img6 (https://i.imgur.com/eXo5eGp.png)
Back then we went on talking about Super 8 and whether it was worth even capturing in a totally logarithmic curve like Slog3. Here's the quote from that time:
The reasoning being that I've seen a few Super 8 footages recorded in various conditions. I mean, projected in real life, not the BT709 captures. I remember a scene in one of them made by a friend of mine (another encoder like me, now retired) at the beach in which there was a big rock in the water. The recording was from the back of the rock, so probably a zoom of some sort from the shore, and while the top of the rock was well lit, the bottom was in the dark and the shadows had no details at all, I mean, blacks looked completely clipped out. So... the question is: is it actually worth recording Super 8 reels in HDR in a totally logarithmic curve like Slog3 or is it completely useless as those cameras had less than 6 stops and therefore couldn't even fill the 100 nits of the regular BT709?
If you capture a single 12 bit or whatever image of course it won't look better. Mine takes two different pictures at different exposures and merges them, VideoFred did this as well and his results (aside from the dnr :p) are astounding.
johnmeyer
17th March 2025, 21:41
I have done a lot of film transfers, and contributed quite a bit to VideoFred's three main threads about his film transfer system and subsequent AVISynth restoration scripts. Unlike the person posting above, I am old enough to know about film, and even have the Super 8 camera I used in the early 1960s which I brought out of mothballs in 2003 to film a wedding.
Several important things to know about film. First, not all film is the same. Some, like Kodachrome, are incredibly dense. This is done so that when you put the film in front of a 600 watt projection bulb, the black come across as black on the screen, and not some gray, murky mess.
The second thing is that the gamma curve is completely different from video, but also from one emulsion to the next. You have to build some sort of transfer curve so the video looks right. If you can really do true HDR, with multiple exposures that you then merge together, then that should produce a marvelous result. However, you also need to get the job done. My biggest transfer job involved over 200 reels of film, most of then 7" (400 feet). By the time I did the cleaning, splicing, transfer, and restoration, it took me several months of work. Most of those reels were 16mm which I transferred using an Eiki 16mm projector that I turned into a transfer system. Using some proprietary software, I was able to do the transfers at the projector's full 24 fps speed. This meant the transfer went really fast. By contrast, my 8mm and Super 8 transfer are done on one of Roger Evan's original Workprinters. His original MovieStuff invention operates at about 8 fps. Let me tell you, it is a real slog trying to get through dozens of reels when it takes an hour or more to transfer one reel.
So, if you are going to scan Super 8 film, you absolutely positively need to invent a system which can ingest film at a fast speed or you will have to get your grandchildren to finish the project.:)
VideoMilk78
20th March 2025, 20:40
If you can really do true HDR, with multiple exposures that you then merge together, then that should produce a marvelous result.
So, if you are going to scan Super 8 film, you absolutely positively need to invent a system which can ingest film at a fast speed or you will have to get your grandchildren to finish the project.:)
My current design is a mix of open source projects and I will be doing multiple exposures and merging. It uses an UV led to detect sprockets and right now I have gotten up to 16 fps.
johnmeyer
20th March 2025, 23:58
My current design is a mix of open source projects and I will be doing multiple exposures and merging. It uses an UV led to detect sprockets and right now I have gotten up to 16 fps.That sounds VERY impressive. Best of luck with the transfers.
VideoMilk78
21st March 2025, 02:15
Thank you! I don't know if you still transfer film but my project will be open source when I feel it's complete.
Edit: 16 fps is not going to be the normal and won't be HDR, the highest I've gotten with 2 exposures is 10fps
johnmeyer
21st March 2025, 17:10
I experimented with 2-transfer HDR when I first was asked to transfer Polavision, Polaroid's instant-development movie film from the late 1970s and early 1980s. It has all sorts of strange artifacts including not only a vertical lenticular stripe (from how the instant-development emulsion works), and also massive chemical stains from having the film sit in its dried development for half a century, but also unbelievable high contrast.
I simply transferred it twice, lined up the two transfers in my NLE (Vegas), and composited the two together. It worked really well, but was a massive amount of work. Your approach of capturing the same image twice while the frame is stationary in your "gate" makes a lot of sense, especially if you can actually change the illumination, rather than simply changing the sensitivity of the sensor.
I'll be very interested in seeing the result of your efforts, especially on Kodachrome film which is also quite dense (although not even close to Polavision).
VideoMilk78
21st March 2025, 18:26
Changing the illumination is the goal, I'll start by just adjusting the sensor as that is the most common thing and will be easier to set up. Right now I'm designing a sphere light source with control similar to frank vines lighting source.
Emulgator
21st March 2025, 23:18
A few years ago I got my light source here (well, hyperspectral into near Infrared wasn' t a thing back then), but CRI98 within human-visible light was.
https://store.yujiintl.com/collections/hyperspectral-led-technology
They sold individually matched COBs then, I settled for an active emission area 10x6mm one and mounted it on a PAR16 size Alu disc (sorry I can not find these back now)
P.S. Found something close:
https://store.yujiintl.com/products/yujileds-cri-95-full-spectrum-350nm-1000nm-3-6w-led-smd-with-base-pcb
Blankmedia
25th March 2025, 05:04
Gammac gammac gammac colors correction after midnight. - ABBA (probably)
I just read all that thread in the last few days and wanted to thank you all. It's indeed amazing.
Is using autolevels on each chanel still useful? Videofred recomanded that at Somme point. Or is the scaling taking care of it?
Jenyok
5th April 2025, 05:47
@r.f
I seem to recall that you are a bit handy in scripting :)
maybe you can simulate GamMac requirement using this post
https://forum.doom9.org/showthread.php?p=1774190#post1774190
From thread that prompted GamMac
GSCript("""
Function ChanAve(clip c,int chan,int "n")
{
# RT_ChanAve is colorspace agnostic, returns number of channels.
# Local vars result default Prefixed "RCA_", default chan0 local var = RCA_Ave_0. Chan 0=Red/Y, 1=Grn/U, 2=Blue/V
nChannels=c.RT_ChanAve(n=Default(n,0)) # nChannels unused
Return (chan==0)?RCA_Ave_0:(chan==1)?RCA_Ave_1:RCA_Ave_2
}
Function GuessGamma(clip c,int Chan,int "n",float "reqAve",Float "GamLo",float "GamHi",Bool "Debug")
{
# Chan, 0=Red/Y, 1=Grn/U, 2=Blue/V
n=min(max(Default(n,0),0),c.FrameCount-1) c=c.Trim(n,-1)
reqAve=Default(reqAve,128.0) gamLo = Default(GamLo,1.0/4.0) gamHi = Default(GamHi,4.0) Debug=Default(Debug,true)
Result = -1.0 ADif=0.0001 PrevAve = -1.0
while(GamLo < GamHi) {
gamMid = (gamLo + gamHi) / 2.0
Ave = c.Levels(0,gamMid,255,0,255,coring=false).ChanAve(chan,0)
(Debug)?RT_DebugF("Chan=%d gamLo=%f : gamHi=%f : GamMid=%f : Ave=%f",chan,gamLo,gamHi,gamMid,Ave):NOP
if(abs(Ave-PrevAve)<=ADif) {Result = gamMid gamLo = gamHi + 1.0} # Force Exit, Not getting any nearer
else if(Ave < reqAve) {gamLo = gamMid}
else if(Ave > reqAve) {gamHi = gamMid}
PrevAve = Ave
}
Return Result
}
Function GamMac(clip c,int n,int "LockChan",Float "LockVal",
\ Float "RedMul",Float "GrnMul", Float "BluMul",
\ Float "MinLim",Float "MaxLim",float "GamLo",Float "GamHi",Bool "Show",int "Verbosity")
{
n=min(max(n,0),c.FrameCount-1)
LockChan=Default(LockChan,1) # Default Green, 0 = Red, 1=Green, 2=Blue. -1=Use LockVal ALL channels. -2 use (RedAve+GrnAve+BluAVE)/3.0 for LockVal.
MinLim=Default(MinLim,32.0)
MaxLim=Default(MaxLim,255.0-32.0)
Show=Default(Show,False)
Verbosity=Default(Verbosity,1)
Assert(LockChan>=-3 && LockChan<=3,"GamMac: LockChan -3 -> 2 Only")
LockVal=(LockChan>=0)?0.0:Float(Default(LockVal,128.0))
RedMul=Default(RedMul,1.0)
GrnMul=Default(GrnMul,1.0)
BluMul=Default(BluMul,1.0)
c=c.Trim(n,-1)
cR=c.ShowRed
cG=c.ShowGreen
cB=c.ShowBlue
c.RT_ChanAve(n=0,Prefix="In_") # Simultaneous get all three averages
LockVal =
\ (LockChan==0) ? In_Ave_0:
\ (LockChan==1) ? In_Ave_1:
\ (LockChan==2) ? In_Ave_2:
\ (LockChan==-2) ? (In_Ave_0+In_Ave_1+In_Ave_2)/3.0:
\ (LockChan==-3) ? (In_Ave_0+In_Ave_1+In_Ave_2)-Max(In_Ave_0,In_Ave_1,In_Ave_2)-Min(In_Ave_0,In_Ave_1,In_Ave_2) :
\ LockVal
OffR=(In_Ave_0<MinLim || In_Ave_0>MaxLim)
OffG=(In_Ave_1<MinLim || In_Ave_1>MaxLim)
OffB=(In_Ave_2<MinLim || In_Ave_2>MaxLim)
gammaR = (OFFR)?1.0:(abs(In_Ave_0-LockVal*RedMul) < 0.0001)?1.0:cR.GuessGamma(0,reqAve=LockVal*RedMul,GamLo=GamLo,GamHi=GamHi)
gammaG = (OFFG)?1.0:(abs(In_Ave_1-LockVal*GrnMul) < 0.0001)?1.0:cG.GuessGamma(1,reqAve=LockVal*GrnMul,GamLo=GamLo,GamHi=GamHi)
gammaB = (OFFB)?1.0:(abs(In_Ave_2-LockVal*BluMul) < 0.0001)?1.0:cB.GuessGamma(2,reqAve=LockVal*BluMul,GamLo=GamLo,GamHi=GamHi)
fixedR = (Abs(gammaR-1.0)<0.0001)?cR:cR.Levels(0,gammaR,255,0,255,coring=false)
fixedG = (Abs(gammaG-1.0)<0.0001)?cG:cG.Levels(0,gammaG,255,0,255,coring=false)
fixedB = (Abs(gammaB-1.0)<0.0001)?cB:cB.Levels(0,gammaB,255,0,255,coring=false)
MergeRGB(fixedR,fixedG,fixedB)
if(Show) {
RT_ChanAve(n=0,Prefix="Out_") # Simultaneous get all three averages
RT_Subtitle("%d] \a!GamMac v0.00\a-\n" +
\ " \a2R \a4G \a1B\a-\n" +
\ "IN_AVE: %7.3f : %7.3f : %7.3f\n" +
\ "GAMMA : %7.3f : %7.3f : %7.3f\n" +
\ "OUTAVE: %7.3f : %7.3f : %7.3f",
\ n,In_Ave_0,In_Ave_1,In_Ave_2,
\ gammaR,gammaG,gammaB,
\ Out_Ave_0,Out_Ave_1,Out_Ave_2)
(Verbosity==1)
\ ? RT_Subtitle("Lockchan=%d LockVal=%.3f\nRedMul=%.3f GrnMul=%.3f BluMul=%.3f",LockChan,LockVal,RedMul,GrnMul,BluMul,align=1)
\ : (Verbosity!=0)
\ ? RT_Subtitle("Lockchan=%d LockVal=%.3f\nGamHi=%.3f GamLo=%.3f\nMinLim=%.3f MaxLim=%.3f\nRedMul=%.3f GrnMul=%.3f BluMul=%.3f",
\ LockChan,LockVal,GamHi,GamLo,MinLim,MaxLim,RedMul,GrnMul,BluMul,align=1)
\ : NOP
}
Return Last
}
""") # End of GScript
Imagesource("test_RGB_Doom.jpg",end=0)
Crop(0,0,width/2,height/2)
Crop(0,0,width/4*4,height/4*4)
#Avisource("1937 Lund Utah 16mm Film [Low, 360p].mp4.avi")
#Avisource("1941 Flint Michigan Parade [Low, 360p].mp4.AVI")
#Avisource("v.avi")
#A=Trim(0,99)
#B=A.BlankClip(length=1) # Test Black Frame @ 100
#C=A.BlankClip(length=1,Color=$FFFFFF) # Test White Frame @ 101
#D=Trim(100,0)
#A++B++C++D
ConvertToRGB32
ORG=Last
LockChan = 1 # Chan for lock to Ave, 0=R, 1=G, 2=B
# -1 = Use LockVal below.
# -2 = LockVal=(RedAve+GrnAve+BluAve)/3.0 for LockVal.
# -3 = LockVal=Median(RedAve,GrnAve,BluAve)
LockVal = 128.0 # Only valid if LockChan == -1
GamHi = 4.0 # Extreme values for guess gamma (starting guess range and limit)
GamLo = 0.25 # Extreme values for guess gamma (starting guess range and limit)
RedMul = 1.00 # Required Ave multiplier for Red Channel, applied when requesting GuessGamma(reqAve*RedMul), Even applied when LockChan=-1.
GrnMul = 1.00 # Same for Green channel. GrnMul even applies when LockChan is Green Channel, etc for chans.
BluMul = 1.00 # Same for Blue channel. Allows tinkering/fine tuning.
MinLim = 32.0 # If Original channel Ave lesser then DO NOT FIX.
MaxLim = 255.0-32.0 # If Original channel Ave greater then DO NOT FIX.
Show = true # Subtitles
Verbosity = 1 # 0=Only Upper metrics, 1(default)=Upper + important ones. 2=All metrics.
A=ScriptClip("GamMac(Last,current_frame,LockChan,LockVal,RedMul,GrnMul,BluMul,MinLim,MaxLim,GamLo,GamHi,Show,Verbosity)",
\ args="LockChan,LockVal,RedMul,GrnMul,BluMul,MinLim,MaxLim,GamLo,GamHi,Show,Verbosity")
BluMul=1.1
B=ScriptClip("GamMac(Last,current_frame,LockChan,LockVal,RedMul,GrnMul,BluMul,MinLim,MaxLim,GamLo,GamHi,Show,Verbosity)",
\ args="LockChan,LockVal,GamHi,GamLo,RedMul,GrnMul,BluMul,MinLim,MaxLim,Show,Verbosity")
BluMul=0.9
C=ScriptClip("GamMac(Last,current_frame,LockChan,LockVal,RedMul,GrnMul,BluMul,MinLim,MaxLim,GamLo,GamHi,Show,Verbosity)",
\ args="LockChan,LockVal,RedMul,GrnMul,BluMul,MinLim,MaxLim,GamLo,GamHi,Show,Verbosity")
TOP=StackHorizontal(ORG,A)
BOT=StackHorizontal(B,C)
StackVertical(TOP,BOT)
return Last
.
StainlessS,
Some questions to you.
.
function GamMac()
has THREE undefined variables (no any value at variable):
In_Ave_0,
In_Ave_1,
In_Ave_2
which are used in calculation variable LockVal .
Is it correct ?
.
May be need does so ?
.
In_Ave_0 = ChanAve(n=0)
In_Ave_1 = ChanAve(n=1)
In_Ave_2 = ChanAve(n=2)
.
StainlessS
5th April 2025, 12:42
from RT_Stats.txt
**************************************************
*** General Clip Functions Colorspace agnostic ***
**************************************************
RT_ChanAve(clip c,int "n"=current_Frame,string "Prefix"=RCA_")
Sets channel averages for clip c frame n, as local variables, 0.0 -> 255.0. RGB24/32, YUY2, Planar.
Returns the number of channels in clip ie 3 unless Y8 where returns 1.
Default Prefix is "RCA_" so for YV12, would return 3 (3 channels) and set
YUV
RCA_Ave_0 = Luma Ave
RCA_Ave_1 = U Ave
RCA_Ave_2 = V Ave.
RGB,
RCA_Ave_0 = Red Ave
RCA_Ave_1 = Grn Ave
RCA_Ave_2 = Blue Ave.
Y8
RCA_Ave_2 = Luma Ave
RCA_Ave_2 = 128
RCA_Ave_3 = 128,
NOTE, No support for alpha channel of RGB32, although could be added if anybody thought it useful.(returns num of channels = 3)
The line
c.RT_ChanAve(n=0,Prefix="In_") # Simultaneous get all three averages
Sets all variables using prefix "In_" rather than default "RCA_"
So instead of
RGB,
RCA_Ave_0 = Red Ave
RCA_Ave_1 = Grn Ave
RCA_Ave_2 = Blue Ave.
sets (all three vars as local variables)
RGB,
In_Ave_0 = Red Ave
In_Ave_1 = Grn Ave
In_Ave_2 = Blue Ave.
the actual return value from RT_ChanAve on RGB would be 3, ie three channel variables set.
EDIT:
.
May be need does so ?
.
In_Ave_0 = ChanAve(n=0)
In_Ave_1 = ChanAve(n=1)
In_Ave_2 = ChanAve(n=2)
.
No, n is the frame number arg to RT_ChanAve(), default current_frame.
vBulletin® v3.8.11, Copyright ©2000-2026, vBulletin Solutions Inc.