Welcome to Doom9's Forum, THE inplace 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. 
19th July 2011, 08:58  #1  Link 
Registered User
Join Date: Jan 2006
Posts: 1,862

Findtweak histogram matcher
This script finds the equivalent tweak statement to match two images. It's useful if there's a known transformation which is constant for the whole clips, such as two captures of the same video with different procamp settings.
It currently has a lot of problems and I'm open to comments. Code:
#findtweak 0.1 by jmac #Find brightness and contrast transformation #requires masktools. Doesn't work on real clips due to clipping. Crashes on monocolored clips. #Two clips must be geometrically aligned. Will be confused by gamma. #works by partitioning the clips into dim and bright pixels #By using two measurements between original and tweaked you can find contrast and brightness blankclip(length=99,width=64,pixel_type="YV12") a=mt_lutspa(last,mode="absolute",expr="x 16 +")#ramp 1679, avg=47.5 b=a.tweak(bright=15,cont=2.0,coring=false)#31157, avg=94 cont=findtweak(a,b,0) bright=findtweak(a,b,1) stackhorizontal(b,a.tweak(bright=bright,cont=cont)) subtitle("Cont="+string(cont)) subtitle(y=20," Bright="+string(bright)) function findtweak(clip a, clip b, int parm){ current_frame=0 ma=a.averageluma mb=b.averageluma x1=trueavg(a,"<=",ma) x2=trueavg(a,">",ma) y1=trueavg(b,"<=",mb) y2=trueavg(b,">",mb) #in the test clip, looking for true avg of 31.5 (1647), but half the pixels are 0 (or 1) #upper half is avg=63.5 (4879) #tweaked values gives 62,127 k=(y2y1)/(x2x1) b=(y116)(x116)*k parm==0?k:b } function trueavg(clip a, string op, float luma){ #Return average of all pixels op luma *while ignoring others in the calculation* #Do this by finding avg(x op luma ? x:1)avg(x op luma ? x:0) etc. current_frame=0 m0=mt_lut(a,expr="x "+string(luma)+" "+op+" x 0 ?").averageluma m1=mt_lut(a,expr="x "+string(luma)+" "+op+" x 1 ?").averageluma m0/(m1m0) } 
19th July 2011, 10:36  #2  Link 
Avisynth language lover
Join Date: Dec 2007
Location: Spain
Posts: 3,423

I think your trueavg function is wrong.
It seems to me it returns (total luma of pixels meeting condition)/(no of pixels not meeting condition). I think it should be Code:
function trueavg(clip a, string op, float luma){ current_frame=0 m0=mt_lut(a,expr="x "+string(luma)+" "+op+" x 0 ?").averageluma m1=mt_lut(a,expr="x "+string(luma)+" "+op+" 1 0 ?").averageluma m0/m1 } 
19th July 2011, 17:33  #3  Link  
Registered User
Join Date: Jan 2006
Posts: 1,862

Good point. I was finding sum/n/maskedcount/n and if half the pixels are masked I get sum/n*2=trueavg so in testing if gives the right answer (in any case the pixels are partitioned in half). You are just finding unmaskedcount/n which is direct (sum/n/unmaskedcount/n=sum/unmaskedcount=trueavg)
e.g. if you have Quote:


2nd February 2017, 03:09  #4  Link 
HeartlessS Usurer
Join Date: Dec 2009
Location: Over the rainbow
Posts: 10,436

Moved here from this thread: http://forum.doom9.org/showthread.ph...56#post1795556
JMac698, Been playing with your FindTweak(), was driving me nuts trying to figure it out, finally twigged that the initial test conversion was done with Tweak(...,coring=false) and result was for Tweak(...,coring=true) [which accounts for all of the seemingly wrong numbers in comments, which refer to input Y values after reduction by 16 due to coring]. Was very perplexing having Tweak(bright=15,cont=2.0,coring=false) and Tweak(bright=31,cont=2.0) coming out identical, until I realized was due the default coring=true [I know it looks obvious there, but comparing result clip variable of first with second some distance away kind of obscured it]. Anyways, thought it might be a good idea to point that out in the thread, save someone else going bananas. Also would need some modification to work (at all) with RGB as suggested in your above post [EDIT: in above linked thread]. EDIT: Not to mention that RGB does not directly work with Tweak anyway, would need conversion to eg Y8 and would then suffer from the coring stuff. EDIT: I also tried with Gavino suggested mod and got identical results to your script. EDIT: Could YPlaneMedian be in some way of use in your script ? Implemented as YPlaneMin(Threshold=50.0), Lowest pixel value whose cumulative population (including population of all lower value pixels) is greater than 50.0%. EDIT: Your script with some debug stuff left in, perhaps of use if you plan to mod the script. Code:
# findtweak 0.1 by jmac, https://forum.doom9.org/showthread.php?t=161960 # Find brightness and contrast transformation # requires masktools. Doesn't work on real clips due to clipping. Crashes on monocolored clips. # Two clips must be geometrically aligned. Will be confused by gamma. # works by partitioning the clips into dim and bright pixels # By using two measurements between original and tweaked you can find contrast and brightness blankclip(length=99,width=64,pixel_type="YV12") a=mt_lutspa(last,mode="absolute",expr="x 16 +",chroma="128") #ramp 1679, avg=47.5 RT_DebugF("A) YMin=%d YMax=%d YAve=%f",a.RT_YPlaneMin(0),a.RT_YPlaneMax(0),a.RT_AverageLuma(0)) # 16,79,47.5 b=a.tweak(bright=15,cont=2.0,coring=false) #31157, avg=94 RT_DebugF("B) YMin=%d YMax=%d YAve=%f",b.RT_YPlaneMin(0),b.RT_YPlaneMax(0),b.RT_AverageLuma(0)) # 47,173,110.0 cont=findtweak(a,b,0) bright=findtweak(a,b,1) stackhorizontal(b,a.tweak(bright=bright,cont=cont)) subtitle("Cont="+string(cont)) subtitle(y=20," Bright="+string(bright)) function findtweak(clip a, clip b, int parm){ current_frame=0 ma=a.averageluma mb=b.averageluma x1=trueavg(a,"<=",ma) x2=trueavg(a,">",ma) y1=trueavg(b,"<=",mb) y2=trueavg(b,">",mb) #in the test clip, looking for true avg of 31.5 (1647), but half the pixels are 0 (or 1) #upper half is avg=63.5 (4879) #tweaked values gives 62,127 k=(y2y1)/(x2x1) b=(y116)(x116)*k RT_DebugF("X1=%f X2=%f Y1=%f Y2=%f K=%f B=%f",x1,x2,y1,y2,k,b) parm==0?k:b } function trueavg(clip a, string op, float luma){ #Return average of all pixels op luma *while ignoring others in the calculation* #Do this by finding avg(x op luma ? x:1)avg(x op luma ? x:0) etc. current_frame=0 m0=mt_lut(a,expr="x "+string(luma)+" "+op+" x 0 ?").averageluma m1=mt_lut(a,expr="x "+string(luma)+" "+op+" x 1 ?").averageluma RT_DebugF("Op='%s' M0=%f M1=%f : m0/(m1m0)=%f",op,m0,m1, m0/(m1m0)) m0/(m1m0) # Gavino Mod # m1=mt_lut(a,expr="x "+string(luma)+" "+op+" 1 0 ?").averageluma # RT_DebugF("Op='%s' M0=%f M1=%f : m0/m1=%f",op,m0,m1, m0/m1) m0/m1 } Code:
00000003 0.40231544 [3640] RT_DebugF: A) YMin=16 YMax=79 YAve=47.500000 00000004 0.40702322 [3640] RT_DebugF: B) YMin=47 YMax=173 YAve=110.000000 00000005 0.41002613 [3640] RT_DebugF: Op='<=' M0=15.750000 M1=16.250000 : m0/(m1m0)=31.500000 00000006 0.41226628 [3640] RT_DebugF: Op='>' M0=31.750000 M1=32.250000 : m0/(m1m0)=63.500000 00000007 0.41454145 [3640] RT_DebugF: Op='<=' M0=39.000000 M1=39.500000 : m0/(m1m0)=78.000000 00000008 0.41686803 [3640] RT_DebugF: Op='>' M0=71.000000 M1=71.500000 : m0/(m1m0)=142.000000 00000009 0.41699862 [3640] RT_DebugF: X1=31.500000 X2=63.500000 Y1=78.000000 Y2=142.000000 K=2.000000 B=31.000000 REPEATED: 00000005 0.41002613 [3640] RT_DebugF: Op='<=' M0=15.750000 M1=16.250000 : m0/(m1m0)=31.500000 00000006 0.41226628 [3640] RT_DebugF: Op='>' M0=31.750000 M1=32.250000 : m0/(m1m0)=63.500000 00000007 0.41454145 [3640] RT_DebugF: Op='<=' M0=39.000000 M1=39.500000 : m0/(m1m0)=78.000000 00000008 0.41686803 [3640] RT_DebugF: Op='>' M0=71.000000 M1=71.500000 : m0/(m1m0)=142.000000 00000009 0.41699862 [3640] RT_DebugF: X1=31.500000 X2=63.500000 Y1=78.000000 Y2=142.000000 K=2.000000 B=31.000000
__________________
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; 2nd February 2017 at 04:07. 
3rd February 2017, 23:32  #6  Link 
Registered User
Join Date: Jan 2006
Posts: 1,862

@stainlessS
Thanks for pointing that out. I really need to finish this. Also I realized I couldn't do this in rgb afterwards, but perhaps it could be done in saturation domain as well. @vcmohan I have a specific purpose in mind for this. It's not just for matching, but matching under a particular model, that is the classical analog tint/sat/bright/cont model. A very particular use is matching two recordings with different procamp settings. I looked at the datasheets of some decoder chips and tested this, and found the digital model. Besides matching captures, you can of course find the best constrained match with old video edited sources. I'm assuming the edit equipment of the time used this model. There were some other ones I read about for primitive colour grading at the time. They were based on simple mixing models (multiplies) in certain transformed domains (like y pb pbr, rgb, etc.). 
Thread Tools  Search this Thread 
Display Modes  

