sven_x
28th September 2014, 19:45
Function to create a cumulative histogram across all frames of a clip
Similar to Virtualdubs "levels" plugin histogram, but with the following advantages:
* displays separate histograms for RGB and luma (or CMY and luma)
* adjustable speed up by choosing a factor n to process every nth frame only
(This first posting is a placeholder for the final script)
sven_x
28th September 2014, 20:12
This is the principle how it might work:
- calculate HistogramRGBLevels() (see here (http://forum.doom9.org/showpost.php?p=1570968&postcount=7)) for each nth frame of a clip
- summing up those histograms in a cumulative histogram using layers(CumulativeHistogram(last_frame),HistogramRGBLevels(current_frame),"mul")
- cropping last CumulativeHistogramm (cutting off the frame) or include a modified histogram function that shows histograms only (without frame)
Given the fact, that the used Histogram function (which can be a modified version of HistogramRGBLevels()) provides histogram graphs with black pixels on white background, a kind of cumulative histogramm can be obtained by muliplicating those histograms using layers. (With white on black, inverse multiplikation is needed instead.)
One will end up with one histogramm that contains all levels that were present across the whole clip.
The goal is to get histograms that show the modulation in each color channel of a recorded clip. This could help when restoring color of faded films (using CMY channels), where yellow and cyan are usally reduced to small levels.
When such a histogram is given, spreading of the levels can be performed more secure than it would be on the bases of one test scene only.
I just tried to put a script together, but I don't know how to use ScriptClip to get a cumulative clip (or an cumulative image, where the histogram information across the clip is gathered). Can anybody help, please?
Many thanks.
colours
28th September 2014, 21:01
This is a task that's much more easily done with an external script than trying to shoehorn Avisynth's scripting functionality to your requirements.
You can use Avisynth to do the histogram computation, dump the results to a file somehow (avs2pipemod or WriteFile or whatever is appropriate), then write a script to parse that file and add the histograms.
Alternatively, use Avisynth solely as a frame server and do the histogram computation in a separate program. (This is, incidentally, something I've done before, though I no longer have the source code or the binary.)
Edit: Just because you can do something in the Avisynth scripting language, for some very liberal definition of "can" (since clearly StainlessS's example is mostly not even the Avisynth scripting language), doesn't mean that you should. I have never been a fan of runtime scripting abuse because Avisynth is supposed to be a frame server, not anything more. Unfortunately the Avisynth Usage subforum seems to be about runtime hacks relatively often.
People like to throw around Avisynth's extensible runtime scripting functionality to demonstrate Avisynth's superiority over some alternatives, but what you really are doing is using the wrong tool for the task. This is in contrast to VapourSynth, which is also only a frame server, but is usually run in Python which is a general-purpose programming language. And I hope this doesn't sound too patronising, but of course you do general things in a general-purpose programming language; it doesn't make sense any other way. </blog>
StainlessS
28th September 2014, 22:53
Here an RT_Stats script to get RGB Channel:Level Average over a number of sample frames, took about 10 mins on my less than powerful m/c
to sample 100 frames (* chans * 256), about 77000 calls to RT_RgbChanInRange().
Note, RT_RGBChanStats can simultaneously get stats for all 3 RGB channels, something for you to try. Also, RT_Ystats can get Y stats.
Here Script:
Avisource("D:\avs\JurassicPark.avi").ConvertToRGB32()
ARR = "Hist.ARR"
RESULT = "Result.Txt"
Samples = 100
Channels = 3
RT_FileDelete(RESULT)
RT_ArrayAlloc(ARR,2,Dim1=Channels,Dim2=256) # 2 Dimensions, Type 2 = Float
GScript("""
for(Samp = 0, Samples - 1) {
n = Int(Samp * ((FrameCount - 1.0) / (Samples - 1.0)) + 0.5)
RT_DebugF("%d) Processing Frame %d",Samp,n)
for(chan=0,Channels-1) {
for(i=0,255) {
Tot = RT_ArrayGet(ARR,chan,i)
d= RT_RgbChanInRange(Last,n=n,chan=chan,lo=i,hi=i) # Population channel chan at level i, out range 0.0 -> 1.0
Tot = Tot + d # running total
RT_ArraySet(ARR,Tot,chan,i) # Update total
}
}
}
for(chan=0,Channels-1) {
for(i=0,255) {
Tot = RT_ArrayGet(ARR,chan,i) # Get Total
Tot = (Tot / Samples) * 255.0 # Average, Range 0.0 -> 255.0
RT_ArraySet(ARR,Tot,chan,i) # Update
}
}
for(i=0,255) {
chan0 = RT_ArrayGet(ARR,0,i)
chan1 = RT_ArrayGet(ARR,1,i)
chan2 = RT_ArrayGet(ARR,2,i)
S=RT_String("%3d] %6.2f %6.2f %6.2f",i,chan0,chan1,chan2)
RT_DebugF("%s",S)
RT_WriteFile(RESULT,"%s",S,Append=True)
}
""")
MessageClip("All Done")
EDITED: Added RT_FileDelete(), delete existing file
I've just used a single accumulator array, not one for each sample frame, which you could do if required, just make the sample frame Dim1 and shift
chan and level index over one place in dimensions.
Colors suggests parsing of output text file, have implemented output txt file, but could instead just parse the resultant Array file,
I've only implemented Average of each channel:Level, seemed easiest example.
Is not terribly sprightly, but may add some kind of histogram testing func and maybe some kind of histogram clip creator func in next month or so.
EDIT: Might want to chop off intro and end credits, I did not and as it samples 1st and last frames, is slanted towards black.
vBulletin® v3.8.11, Copyright ©2000-2026, vBulletin Solutions Inc.