Advertisement
torchlight

Inpainting experiments in Avisynth

Feb 3rd, 2015
572
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. /* Inpainting experiments in Avisynth
  2. Dependencies:
  3. Avisynth+ (or wrap all the ifs and whiles in GScript blocks)
  4. CLExpr
  5. Dither tools
  6. MaskTools v2
  7. RgTools
  8. VariableBlur
  9. */
  10.  
  11. /* first, we have Gaussian blur functions.
  12. these use three box filters for large variance and fall back to binomial blur and/or a three-tap
  13. kernel. expect slowness and also note that the speed is not necessarily continuous wrt variance or
  14. sigma. they should still be faster than GaussianBlur though (not that you have a choice if you're
  15. doing 16-bit). */
  16.  
  17. function blur_var(clip c,float "var")
  18. {
  19.     if (var <= 0) {return c}
  20.     while (var >= 4)
  21.     {
  22.         r = floor(sqrt(var))
  23.         w = 2*r-1
  24.         c = (r == 2) ? c.removegrain(20,0,0) : c.averageblur(r-1)
  25.         c = (r == 2) ? c.removegrain(20,0,0) : c.averageblur(r-1)
  26.         c = (r == 2) ? c.removegrain(20,0,0) : c.averageblur(r-1)
  27.         var = var - (w*w-1)/4
  28.     }
  29.     if (var >= 0.5)
  30.     {
  31.         fvar = floor(var*2)*0.5
  32.         c = c.binomialblur(fvar)
  33.         var = var - fvar
  34.     }
  35.     return c.blur(log(1-var)/log(0.5)) # why is this logarithmic? :avisynth:
  36. }
  37.  
  38. function blur_var16(clip c,float "var")
  39. {
  40.     if (var <= 0) {return c}
  41.     while (var >= 4)
  42.     {
  43.         r = floor(sqrt(var))
  44.         w = 2*r-1
  45.         c = (r == 2) ? c.Dither_removegrain16(20,0,0) : c.Dither_box_filter16(radius=r,u=2,v=2)
  46.         c = (r == 2) ? c.Dither_removegrain16(20,0,0) : c.Dither_box_filter16(radius=r,u=2,v=2)
  47.         c = (r == 2) ? c.Dither_removegrain16(20,0,0) : c.Dither_box_filter16(radius=r,u=2,v=2)
  48.         var = var - (w*w-1)/4
  49.     }
  50.     while (var >= 0.5)
  51.     {
  52.         c = c.Dither_removegrain16(11,0,0)
  53.         var = var - 0.5
  54.     }
  55.     a = " "+string(var*0.5)
  56.     b = " "+string(1-var)
  57.     return c.dither_resize16(c.width(),c.height()/2,kernel="impulse"+a+b+a,fh=-1,fv=-1,u=2,v=2)
  58. }
  59.  
  60. function blur_sigma(clip c,float sigma)
  61. {
  62.         return blur_var(c,sigma*sigma)
  63. }
  64.  
  65. function blur_sigma16(clip c,float sigma)
  66. {
  67.     return blur_var16(c,sigma*sigma)
  68. }
  69.  
  70. /* this is for merging clips with a binary mask, which avoids the 255/256 error when using mt_merge.
  71. (this error is actually very significant when trying to do in-painting with only 8-bit precision.)
  72. it's also a bit slower than mt_merge (4000-ish fps versus 7000-ish fps on SD) but durr. */
  73. function binarymerge(clip a,clip b,clip mask,int "y",int "u",int "v",string "chroma")
  74. {
  75.     aa = mt_logic(mask,a,mode="andn",y=y,u=u,v=v,chroma=chroma) # recall that andn has the input arguments "switched"
  76.     bb = mt_logic(mask,b,mode="and",y=y,u=u,v=v,chroma=chroma)
  77.     mt_logic(aa,bb,mode="or",y=y,u=u,v=v,chroma=chroma)
  78. }
  79.  
  80. /* now, the actual inpainting filters.
  81. the 8-bit filter is actually quite bad because the blurring itself already loses a lot of precision,
  82. and then the dynamic range expansion in removing the alpha channel makes the error even worse. could
  83. probably be mitigated by using some form of dithering, but :effort: and that might still look bad.
  84.  
  85. for all intents and purposes, the 16-bit filter should be considered the only working version. it
  86. works identically, just with a lot less rounding error. note that the "binary mask" for the 16-bit
  87. version should have values 0 and 65535, not 0 and 255*256.
  88.  
  89. in either version, if the area to be inpainted is too large and sigma is too small, the resulting
  90. frames will have black patches near the centre of the inpainting regions. raise sigma if that
  91. happens. */
  92.  
  93. function inpaint(clip src,clip mask,float sigma,int n,int "y")
  94. {
  95.     c = binarymerge(src,src.mt_lut(y=0),mask)
  96.     alpha = mask.mt_invert()
  97.     for (i=n, 1, -1)
  98.     {
  99.         s = sigma*i/n
  100.         c = binarymerge(src,c.blur_sigma(s),mask)
  101.         alpha = binarymerge(mask.mt_invert(),alpha.blur_sigma(s),mask)
  102.         c = mt_lutxy(c,alpha,"y 100 < x x y / 255 * round ?")
  103.         alpha = alpha.mt_binarize(99,mode="255 x")
  104.     }
  105.     return mt_lutxy(c,alpha,"x y / 255 * round",y=y).mergechroma(src)
  106. }
  107.  
  108. function inpaint16(clip src,clip mask,float sigma,int n,int "y")
  109. { # src/mask are stacked 16-bit clips
  110.     c = binarymerge(src,src.mt_lut(y=0),mask)
  111.     alpha = mask.mt_invert()
  112.     for (i=n, 1, -1)
  113.     {
  114.         s = sigma*i/n
  115.         c = binarymerge(src,c.blur_sigma16(s),mask)
  116.         alpha = binarymerge(mask.mt_invert(),alpha.blur_sigma16(s),mask)
  117.         c = cl_exprxy(c,alpha,"y 25600 < x x y / 65535 * round ?",lsb=true)
  118.         alpha = alpha.cl_expr("x 25600 < x 65535 ?",lsb=true)
  119.     }
  120.     return cl_exprxy(c,alpha,"x y / 65535 * round",y=y,lsb=true).mergechroma(src)
  121. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement