View Single Post
Old 24th June 2012, 03:21    |  Link
-Vit-
Registered User
 
Join Date: Jul 2010
Posts: 448
This version has precision and decent performance. Uses the first version of AvgAll2 for speed. Splits the clip into blocks of power-of-2 lengths (effectively treats the frame count as binary). Each block's average is calculated correctly with the simple AvgAll2 since powers of 2 blocks will always split into equal odd/even lists. Blocks are averaged together with weighted merges. Processes 100000 480p frames in around 30s. Needs GScript:
Code:
function AvgAll(clip c) {
    GScript("""
    frms = c.FrameCount()
    pow2 = 1
    totl = 0
    while (frms > 0) {
        if (frms % 2 > 0) {
            blkAvg = c.Trim(0,-pow2).AvgAll2()
            c = c.Trim(pow2,0)
            if (totl == 0) {
                avg = blkAvg
            } else {
                avg = Merge( avg, blkAvg, Float(pow2)/(totl+pow2) )
            }
            totl = totl + pow2
        }
        frms = frms / 2
        pow2 = pow2 * 2
    }
    """)
    return avg
}

function AvgAll2(clip c) { c.FrameCount() <= 1 ? c : AvgAll2( Merge(c.SelectEven(), c.SelectOdd()) ) }
Edit: The integer rounding errors from so many small merges creep in with longer clips though - there's a gradual color shift.

Edit2: So go 16-bit. Accurate, slower, 10000 frames in a minute. Needs DitherTools:
Code:
function AvgAll_16(clip c) {
    GScript("""
    c = c.Dither_convert_8_to_16() # To 16 bit
    c = c.Dither_lut16("x 0.5 *", U=3,V=3) # down to 15-bit to get faster average below
    frms = c.FrameCount()
    pow2 = 1
    totl = 0
    while (frms > 0) {
        if (frms % 2 > 0) {
            blkAvg = c.Trim(0,-pow2).AvgAll2_16()
            c = c.Trim(pow2,0)
            if (totl == 0) {
                avg = blkAvg
            } else {
                avg = Merge_16( avg, blkAvg, Float(pow2)/(totl+pow2) )
            }
            totl = totl + pow2
        }
        frms = frms / 2
        pow2 = pow2 * 2
    }
    """)
    return Dither_add16(avg,avg).DitherPost(mode=-1) # Back to 16 bit then to 8 again
}

# Same as AvgAll2 for 8-bit, but uses faster average (assumes 15-bit input values)
function AvgAll2_16(clip c) { 
    c.FrameCount() <= 1 ? c \
      : AvgAll2_16( Dither_add16(c.SelectEven(),c.SelectOdd()).Dither_lut16("x 0.5 *", U=3,V=3) )
}

# Like Avisynth native Merge but for 16-bit clips
function Merge_16(clip a, clip b, float "weight") {
    weight = default(weight, 0.5)
    mul1 = String(1.0-weight)
    a = a.Dither_lut16("x "+mul1+" *", U=3,V=3)
    mul2 = String(weight)
    b = b.Dither_lut16("x "+mul2+" *", U=3,V=3)
    return Dither_add16(a, b)
}

Last edited by -Vit-; 24th June 2012 at 04:46.
-Vit- is offline   Reply With Quote