View Single Post
Old 6th September 2014, 04:02   #4  |  Link
raffriff42
Retried Guesser
 
raffriff42's Avatar
 
Join Date: Jun 2012
Posts: 1,373
Re: motion, agree, the artifacts are most objectionable when there is little movement. I like to temporally-blur the carp out of anything that's not moving very much.

Re: alternating frames, I think if you look closely, the pattern will become more complex than a b a b. The nature of aliasing is the injection of random frequencies (spatial and temporal) into the desired signal. The only way to (partly, with luck) get rid of them is the aforementioned "blurring the carp out of it," with a mask of some type to hide the worst artifacts this creates.

I've got a script, posted below, that I think is a pretty good compromise between speed and quality, erring on the side of speed. The mask is alright, but there is room for improvement in the smoothing department.

Among smoothers, TemporalSoften is the speed king, but it can be very blurry. If the mask is working well, the blurriness is fairly well hidden. There is a selection of smoothers available in this script, including your MVTools code.

I checked it on a variety of footage, in addition to the footage you supplied. The default look is a bit soft overall, with occasional unwanted motion blur. Acceptable maybe, if you don't look at it too critically. (EDIT added wrapper function DeMoire42)
Code:
## requires MaskTools
## requires RemoveGrain
## requires FFT3DFilter, if strength=4-5 
## requires MVTools2, if strength=6

######## final output size
out_wid=1280 #1680
out_hgt=720 #1050

######## intermediate size, pre crop/letterbox (set per source below)
#size_wid=
#size_hgt=

AviSource("D:\VideoProjects\raw\mgs3motion uty7-2.avi")
#Info ## 512x448, 29.97
size_wid=1152 #1870
size_hgt=720 #1050

ConvertToYV12(matrix="Rec709", chromaresample="spline16")
#return Last

DeMoire42(strength=2, showmask=0>0)

#[[ choose one output resizer:
#return Spline36Resize(size_wid, size_hgt).UUSize(out_wid, out_hgt) ## (sharper)
return BilinearResize(size_wid, size_hgt).UUSize(out_wid, out_hgt) ## (slightly faster)
#return BilinearResize(size_wid, size_hgt) ## (don't letterbox)
#return Last ## (don't resize or letterbox)
#]]

#######################################
### Decreases certain aliasing artifacts, such as 
##  moire and shimmer; masked spatial & temporal smoothing.
##
## @ strength - main argument: "smoother" chooser
##                   1,2,3 = TemporalSoften (fast)
##                     4,5 = FFT3D         (slow)
##                       6 = MVTools
##                       0 = bypass
##                   (default 2)
## @ grnsens  - mask sensitivity to "grain": (0.0 to 10.0, default 1.0)
##                   (more grain sensitivity = softer output)
## @ mmlo     - motion mask "lo" threshold (0 to 11, default 10)
##                   (max "motion" where mask=0)
## @ mmhi     - motion mask "hi" threshold (12 to 99, default 60)
##                   (min "motion" where mask=255)
## @ subsamp  - if true, mask created from half-sized source
##                   (broader mask, also much faster)
##                   (default true if source width>600)
## @ expand   - mask expand (0 to 5, default 0)
## @ avgflashframes - if true, do mask frame averaging
##              (set to true for sources with lots of duplicate frames)
## @ sharpen  -  final sharpening: -1 to +1; default 0 
## @ showmask -  if true, make mask visible for tuning
##
## @version 0.42 raffriff42 6-Sep-2014
##
function DeMoire42(clip C, int "strength", float "grnsens", 
\                  int "mmlo", int "mmhi", bool "subsamp", 
\                  int "expand", bool "avgflashframes", 
\                  float "sharpen", bool "showmask")
{
    strength = Default(strength, 2)
    grnsens  = Min(Max(0.1, Float(Default(grnsens, 1.0))), 10.0) 
    mmlo     = Min(Max(0, Default(mmlo, 10)), 11)
    mmhi     = Min(Max(5, Default(mmhi, 60)), 99)
    subsamp  = Default(subsamp, C.Width>600)
    expand   = Default(expand, 0)
    avg      = Default(avgflashframes, false)
    sharpen  = Float(Min(Max(-1, Default(sharpen, 0)), 1))
    showmask = Default(showmask, false)

    S = (strength <1) ? C
    \ : (strength==1) ? C.TemporalSoften(1, 191, 191, 250, 2).Blim(0.6-sharpen)
    \ : (strength==3) ? C.TemporalSoften(3, 191, 191, 250, 2).Blim(1.0-sharpen)
    \ : (strength==4) ? C.AAff3d_10(temporal_size=4, sigma=29.0, sharpen=sharpen+0.5)
    \ : (strength==5) ? C.AAff3d_10(temporal_size=5, sigma=59.0, sharpen=sharpen+0.5)
    \ : (strength >5) ? C.mm_aa(bidi_comp=false).Blim(0.0-sharpen)
    \ : C.TemporalSoften(2, 191, 191, 250, 2).Blim(1.5-sharpen)
    #return S

    M = C.UUMoireMask5(mmlo, mmhi, grnsens, 
    \       subsamp, expand, avg)
    #return M

    return (strength<1) ? C
    \    : (showmask)   ? C.UUVisualMask(M, mode="luma")
    \    : C.mt_merge(S, M)
}

# http://avisynth.org.ru/fft3dfilter/fft3dfilter.html
#######################################
### FFT 3D antialising: decreases certain aliasing artifacts, 
##  such as moire and shimmer; spatial & temporal smoothing. 
##
## @ temporal_size: default 5; try 1-4 for faster processing 
##            0 - all previous frames (switch Kalman filter mode);
##            1 - only current frame (spatial 2D Wiener filter);
##            2 - previous and current frame (3D Wiener filter);
##            3 - previous, current and next frame (3D Wiener filter)
##            4 - two previous, current and next frame (3D Wiener filter)
##            5 - two previous, current and two next frames (3D Wiener filter)
##           -1 - sharpen only (2D);
##
## @ sigma - given noise value (float>0, default=12)
##
## @ sharpen - sharpening strength; good values about 0.3 to 1.0; 
##            negative values results in reverse effect.
##            (default=0.5 - slight sharpening)
##
## suggested settings: 
##   AAff3d_10()       ## aka AAff3d_10b strong
##   AAff3d_10(4, 10)  ## aka AAff3d_10c less strong
##   AAff3d_10(4, 2.2) ## slightly soft
##
function AAff3d_10(clip C, int "temporal_size", float "sigma", float "sharpen")
{
    Assert(Defined(C) && IsClip(C), 
    \     "AAff3d_10: invalid clip argument")
    Assert(C.IsYV12 || C.IsYUY2, 
    \     "AAff3d_10: invalid source format")
    sigma   = Float(Default(sigma, 12))
    sigma4  = sigma+20 ## given noise value at lowest frequencies
    
    sharpen = Float(Default(sharpen, 0.5))
    
    temporal_size = Default(temporal_size, 5)
    Assert((-2<temporal_size && 6>temporal_size),
    \     "AAff3d_10: invalid temporal_size argument")

    ## bw, bh - block width, height
    blksiz = 24
    ## ow, oh - overlap width, height
    ovrlap =  8 ## blksiz / 3

    C ## Last=C
    FFT3DFilter(sigma=sigma, sigma4=sigma4, bw=blksiz, bh=blksiz, 
    \           bt=temporal_size, ow=ovrlap, oh=ovrlap, sharpen=sharpen, 
    \           ncpu=2)
}

#requires MVTools2
#######################################
## @ Seedmanc, rr42 modded as a function
## http://forum.doom9.org/showthread.php?p=1691533#post1691533
##
function mm_aa(clip C, bool "bidi_comp")
{
    C ## Last=C
    bidi_comp = Default(bidi_comp, false)

    super = MSuper(pel=2, chroma=false) 
    backward_vectors = MAnalyse(super, isb=true, blksize=8, overlap=2, search=4, 
    \           truemotion=true, chroma=false, temporal=true, badsad=1000) 
    forward_vectors  = MAnalyse(super, isb=false, blksize=16, blksizev=8, 
    \           overlap=0, overlapv=2, search=4, truemotion=false, chroma=false,
    \           temporal=true, badsad=1000) 
    backward_compensation = MCompensate(super, backward_vectors, thSCD1=600)
    forward_compensation  = MCompensate(super, forward_vectors, thSCD1=400)  

    AA = (bidi_comp)
    \ ? merge(
    \       merge(
    \           forward_compensation, 
    \           backward_compensation).sharpen(0.2),
    \           0.67)
    \ : merge(backward_compensation) 
    return AA
} 

#requires RemoveGrain
#requires MaskTools2
##################################
### create mask from areas with "grain" (heavy random pixel activity)
##
## @ grnsens - sensitivity to "grain": (0.0 to 10.0, default 1.3)
## @ expand  - call mt_expand (0 to 5, default 3)
##
function UUGrainMask42(clip C, float "grnsens", int "expand")
{
    Assert(C.IsYUV, "source must be YUV") 

    grnsens = Min(Max(0.1, Float(Default(grnsens, 1.3))), 10.0) 
    expand  = Default(expand, 3)

    R = C.RemoveGrain(5, 0, 0) 
    \    .mt_lut(
    \       "x 127 - abs 8 * 32 - ", 
    \       u=-128, v=-128) 

    M = R.mt_lutxy(
    \       R.Blur(1.0).TemporalSoften(1, 191, 191, 250, 2),
    \       "x y - abs "+String(grnsens / 2.0 * 3.0)+" * ",
    \       u=-128, v=-128) 
    \    .mt_expandx(expand, 0.0)

    return M
}

#requires MaskTools2
#######################################
### create a mask for aliasing/moire/twinkle reduction
##
## @ mmlo    - motion mask "lo" threshold (0 to 11, default 0)
##                   (max "motion" where mask=0)
## @ mmhi    - motion mask "hi" threshold (12 to 99, default 5)
##                   (min "motion" where mask=255)
## @ grnsens - grain mask sensitivity (0.0 to 10.0, default 1.3)
##                   (more grain sensitivity = softer output)
## @ subsamp - if true, work with source 'C' half-sized 
##                   (broader mask, also 40% faster processing)
## @ expand  - call mt_expand (0 to 5, default 3)
## @ avgflashframes - if true, do mask frame averaging; about 10-15% slower
##                   (set to true for sources with lots of duplicate frames)
##
function UUMoireMask5(clip C, int "mmlo", int "mmhi", float "grnsens",
\                     bool "subsamp", int "expand", bool "avgflashframes")
{
    mmlo    = Min(Max(0, Default(mmlo, 0)), 11)
    mmhi    = Min(Max(5, Default(mmhi, 5)), 99)
    expand  = Min(Max(0, Default(expand, 0)),  5)
    grnsens = Float(Min(Max(0.1, Default(grnsens, 1.3)), 10))
    subsamp = Default(subsamp, false)
    avg     = Default(avgflashframes, false)

    S = (subsamp==false) ? C
    \ : C.BilinearResize(C.Width/2, C.Height/2)

    GM = S.UUGrainMask42(grnsens, expand)
    #return GM.BilinearResize(C.Width, C.Height)  

    MM = S.mt_motion(thy1=mmlo, thy2=mmhi, tht=100)
    \     .mt_inpand(u=-128, v=-128)
    \     .TemporalSoften(2, 191, 191, 250, 2)
    #return MM.BilinearResize(C.Width, C.Height)  

    MM = (avg==false) ? MM
    \  : MM.ConditionalFilter(
    \           MM.UUSlip(-1, MM), MM, "AverageLuma", "<", "16")
    M  = mt_logic(GM, MM.Invert, mode="min").Blur(1.0)

    return (subsamp==false) ? M
    \ : M.BilinearResize(C.Width, C.Height)  
}

# see also: Dither\mt_xxpand_multi.avsi
#requires MaskTools2
#######################################
### variable mt_expand with blur
## @ width - 0 to 5
##
function mt_expandx(clip C, int width, float "blur")
{
    b = Float(Min(Max(0, Default(blur, 0.3)), 1))

    M = C.mt_inflate
    M = (width<0) ? M : M.mt_expand.Blur(b)
    M = (width<1) ? M : M.mt_expand.Blur(b)
    M = (width<2) ? M : M.mt_expand.Blur(b)
    M = (width<3) ? M : M.mt_expand.Blur(b)
    M = (width<4) ? M : M.mt_expand.Blur(b)

    return M.Grayscale
}

##################################
### show mask overlay for visualization
##
## @ mode ("add"|"luma") default "add"
##
function UUVisualMask(clip C, clip M, String "mode", float "opacity")
{
    mode    = Default(mode, "add")
    opacity = Float(Default(opacity, 0.7))

    return (StrCmpi(mode,"luma")==0) 
    \ ? C.Overlay(M, mode="Luma", opacity=0.6*opacity) 
    \ : C.Overlay(M, mode="Add",  opacity=0.9*opacity)
}

#######################################
### constrained arguments to Blur
function Blim(clip C, float a) {
    return C.Blur(Min(Max(-0.99, a), 1.55))
}

#######################################
### "slip" a clip in time.
##
## @ C - clip to be advanced or delayed 
## @ offset - if positive, clip is advanced;
##            if negative, clip is delayed
## @ P - clip to be used for padding (default = BlankClip) 
##
function UUSlip(clip C, int offset, clip "P")
{
    lenTrim = (offset > 0) ? offset : 0
    lenPad  = (offset < 0) ? -offset : 0

    P = IsClip(P) ? P : BlankClip(C)

    C = (lenPad==0) ? C 
    \ : P.Trim(0, -lenPad) + C

    C = (lenTrim==0) ? C 
    \ : C.Trim(lenTrim, 0) + P.Trim(P.Framecount-lenTrim, -lenTrim) 

    return C
}

##################################
### crop or add borders to ensure clip is a certain size
#
function UUSize(clip C, int wid, int hgt, int "mod")
{
    mod = Max(1, Default(mod, 2))

    bdrWid = (wid - C.Width)
    bdrHgt = (hgt - C.Height)

    bdrLt = Abs(Round(Float(bdrWid) / 2.0))
    bdrLt = Sign(bdrWid) * (bdrLt + (bdrLt % mod))
    
    bdrTp = Abs(Round(Float(bdrHgt) / 2.0)) 
    bdrTp = Sign(bdrHgt) * (bdrTp + (bdrTp % mod))
    
    bdrRt = (bdrWid - bdrLt) 
    bdrBt = (bdrHgt - bdrTp)

    C = (bdrLt>0 || bdrTp>0 || bdrRt>0 || bdrBt>0) 
    \ ? C.AddBorders(
          \ ((bdrLt>0) ? bdrLt : 0), 
          \ ((bdrTp>0) ? bdrTp : 0), 
          \ ((bdrRt>0) ? bdrRt : 0), 
          \ ((bdrBt>0) ? bdrBt : 0))
    \ : C

    C = (bdrLt<0 || bdrTp<0 || bdrRt<0 || bdrBt<0)
    \ ? C.Crop(
          \ ((bdrLt<0) ? -bdrLt : 0), 
          \ ((bdrTp<0) ? -bdrTp : 0), 
          \ ((bdrRt<0) ?  bdrRt : wid), 
          \ ((bdrBt<0) ?  bdrBt : hgt))
    \ : C

    return C
}

__END__

Last edited by raffriff42; 6th September 2014 at 14:22. Reason: wrapper function DeMoire42
raffriff42 is offline   Reply With Quote