Welcome to Doom9's Forum, THE in-place to be for everyone interested in DVD conversion. Before you start posting please read the forum rules. By posting to this forum you agree to abide by the rules. |
16th July 2016, 11:16 | #1 | Link |
HeartlessS Usurer
Join Date: Dec 2009
Location: Over the rainbow
Posts: 10,980
|
GamMac v1.10 - 15 June 2018
GamMac, Gamma Machine. Original idea, see here:- http://forum.doom9.org/showthread.php?t=173683
Code:
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). Source Left. Right, LockChan 0 (red) , Bot Left LockChan=1(Grn), BotRight LockChan=2((Blu) Source Left. Right, LockChan 0 (red) , Bot Left LockChan=1(Grn), BotRight LockChan=2((Blu) 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.p...94#post1825394 Last edited by StainlessS; 8th January 2019 at 03:21. |
16th July 2016, 15:14 | #3 | Link |
HeartlessS Usurer
Join Date: Dec 2009
Location: Over the rainbow
Posts: 10,980
|
Glad you like it France, dont forget to say thanx to VideoFred for his weird & whacky idea
__________________
I sometimes post sober. StainlessS@MediaFire ::: AND/OR ::: StainlessS@SendSpace "Some infinities are bigger than other infinities", but how many of them are infinitely bigger ??? |
16th July 2016, 16:24 | #4 | Link |
HeartlessS Usurer
Join Date: Dec 2009
Location: Over the rainbow
Posts: 10,980
|
And here Lenna Sjööblom
Source Left. Right, LockChan 0 (red) , Bot Left LockChan=1(Grn), BotRight LockChan=2((Blu)
__________________
I sometimes post sober. StainlessS@MediaFire ::: AND/OR ::: StainlessS@SendSpace "Some infinities are bigger than other infinities", but how many of them are infinitely bigger ??? Last edited by StainlessS; 15th June 2018 at 14:25. |
16th July 2016, 17:17 | #5 | Link |
Registered User
Join Date: Jan 2012
Location: Toulon France
Posts: 249
|
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 Last edited by Bernardd; 16th July 2016 at 17:27. |
16th July 2016, 17:58 | #6 | Link |
HeartlessS Usurer
Join Date: Dec 2009
Location: Over the rainbow
Posts: 10,980
|
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) 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:
__________________
I sometimes post sober. StainlessS@MediaFire ::: AND/OR ::: StainlessS@SendSpace "Some infinities are bigger than other infinities", but how many of them are infinitely bigger ??? Last edited by StainlessS; 15th June 2018 at 14:25. |
17th July 2016, 11:22 | #7 | Link | |
Registered User
Join Date: Dec 2004
Location: Terneuzen, Zeeland, the Netherlands, Europe, Earth, Milky Way,Universe
Posts: 689
|
Quote:
Dll version runs at real time Fred.
__________________
About 8mm film: http://www.super-8.be Film Transfer Tutorial and example clips: https://www.youtube.com/watch?v=W4QBsWXKuV8 More Example clips: http://www.vimeo.com/user678523/videos/sort:newest |
|
17th July 2016, 19:19 | #8 | Link |
HeartlessS Usurer
Join Date: Dec 2009
Location: Over the rainbow
Posts: 10,980
|
GamMac() v1.02, update. See 1st post.
Added LockChan= -3, and Verbosity args. Appearance changed a little. Probably a bit faster. EDIT: Plays the 4x stacked image of parade at about double speed on my crappy core duo, so pretty good speed.
__________________
I sometimes post sober. StainlessS@MediaFire ::: AND/OR ::: StainlessS@SendSpace "Some infinities are bigger than other infinities", but how many of them are infinitely bigger ??? Last edited by StainlessS; 17th July 2016 at 19:51. |
18th July 2016, 01:36 | #9 | Link |
Registered User
Join Date: Jan 2010
Posts: 709
|
@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?
__________________
powered by Google Translator |
18th July 2016, 01:53 | #10 | Link | |
HeartlessS Usurer
Join Date: Dec 2009
Location: Over the rainbow
Posts: 10,980
|
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 Quote:
Code:
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: 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.
__________________
I sometimes post sober. StainlessS@MediaFire ::: AND/OR ::: StainlessS@SendSpace "Some infinities are bigger than other infinities", but how many of them are infinitely bigger ??? Last edited by StainlessS; 18th July 2016 at 03:13. |
|
18th July 2016, 15:25 | #11 | Link | ||
Registered User
Join Date: Jan 2010
Posts: 709
|
Quote:
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 Quote:
Just to get the code ready for a future 16/32bit capability
__________________
powered by Google Translator Last edited by Motenai Yoda; 18th July 2016 at 15:27. |
||
18th July 2016, 16:14 | #12 | Link | |||
HeartlessS Usurer
Join Date: Dec 2009
Location: Over the rainbow
Posts: 10,980
|
Quote:
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. Quote:
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. Quote:
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.
__________________
I sometimes post sober. StainlessS@MediaFire ::: AND/OR ::: StainlessS@SendSpace "Some infinities are bigger than other infinities", but how many of them are infinitely bigger ??? Last edited by StainlessS; 18th July 2016 at 16:41. |
|||
18th July 2016, 16:55 | #13 | Link |
Registered User
Join Date: Dec 2004
Location: Terneuzen, Zeeland, the Netherlands, Europe, Earth, Milky Way,Universe
Posts: 689
|
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:
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.
__________________
About 8mm film: http://www.super-8.be Film Transfer Tutorial and example clips: https://www.youtube.com/watch?v=W4QBsWXKuV8 More Example clips: http://www.vimeo.com/user678523/videos/sort:newest Last edited by videoFred; 18th July 2016 at 21:37. |
18th July 2016, 18:03 | #14 | Link |
47.952fps@71.928Hz
Join Date: Mar 2011
Posts: 940
|
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.
__________________
Win10 (x64) build 19041 NVIDIA GeForce GTX 1060 3GB (GP106) 3071MB/GDDR5 | (r435_95-4) NTSC | DVD: R1 | BD: A AMD Ryzen 5 2600 @3.4GHz (6c/12th, I'm on AVX2 now!)
|
18th July 2016, 19:41 | #15 | Link | |
Registered User
Join Date: Jan 2010
Posts: 709
|
Quote:
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.
__________________
powered by Google Translator |
|
18th July 2016, 20:29 | #16 | Link |
HeartlessS Usurer
Join Date: Dec 2009
Location: Over the rainbow
Posts: 10,980
|
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.
__________________
I sometimes post sober. StainlessS@MediaFire ::: AND/OR ::: StainlessS@SendSpace "Some infinities are bigger than other infinities", but how many of them are infinitely bigger ??? Last edited by StainlessS; 19th July 2016 at 16:02. |
18th July 2016, 21:47 | #17 | Link | ||
Registered User
Join Date: Dec 2004
Location: Terneuzen, Zeeland, the Netherlands, Europe, Earth, Milky Way,Universe
Posts: 689
|
Quote:
Quote:
Fred.
__________________
About 8mm film: http://www.super-8.be Film Transfer Tutorial and example clips: https://www.youtube.com/watch?v=W4QBsWXKuV8 More Example clips: http://www.vimeo.com/user678523/videos/sort:newest |
||
18th July 2016, 22:18 | #18 | Link |
HeartlessS Usurer
Join Date: Dec 2009
Location: Over the rainbow
Posts: 10,980
|
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.ph...91#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.
__________________
I sometimes post sober. StainlessS@MediaFire ::: AND/OR ::: StainlessS@SendSpace "Some infinities are bigger than other infinities", but how many of them are infinitely bigger ??? |
18th July 2016, 23:18 | #19 | Link | ||
Registered User
Join Date: Dec 2004
Location: Terneuzen, Zeeland, the Netherlands, Europe, Earth, Milky Way,Universe
Posts: 689
|
Quote:
Quote:
Fred.
__________________
About 8mm film: http://www.super-8.be Film Transfer Tutorial and example clips: https://www.youtube.com/watch?v=W4QBsWXKuV8 More Example clips: http://www.vimeo.com/user678523/videos/sort:newest |
||
19th July 2016, 00:46 | #20 | Link | |
HeartlessS Usurer
Join Date: Dec 2009
Location: Over the rainbow
Posts: 10,980
|
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. Code:
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 Quote:
to match what IanB said.
__________________
I sometimes post sober. StainlessS@MediaFire ::: AND/OR ::: StainlessS@SendSpace "Some infinities are bigger than other infinities", but how many of them are infinitely bigger ??? Last edited by StainlessS; 9th January 2019 at 05:20. |
|
Tags |
color cast, correction, fade, gamma |
Thread Tools | Search this Thread |
Display Modes | |
|
|