Guest User

QTGMC 3.33s for avs 2.60

a guest
Apr 11th, 2016
666
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. #-------------------------------------------------------------------#
  2. #                                                                   #
  3. #                    QTGMC 3.33, by Vit, 2012                       #
  4. #                                                                   #
  5. #   A high quality deinterlacer using motion-compensated temporal   #
  6. #  smoothing, with a range of features for quality and convenience  #
  7. #          Originally based on TempGaussMC_beta2 by Didée           #
  8. #                                                                   #
  9. #-------------------------------------------------------------------#
  10. #
  11. # Full documentation is in the 'QTGMC' html file that comes with this script
  12. #
  13. # --- LATEST CHANGES ---
  14. #
  15. # v3.33s (mod) 2016 04 11
  16. # - Add KNLMeansCL as another Denoiser to NoiseProcess
  17. # - others
  18. #
  19. # v3.33s (mod) 2016 01 19
  20. # - make QTGMC_deflate/QTGMC_inflate work with YUY2 using masktool2 for avs 2.60
  21. #
  22. # v3.33s (mod) 2015 10 23
  23. # - revert to QTGMC_deflate/QTGMC_inflate quoted from Dogway
  24. #
  25. # v3.33s (mod) 2015 9 10
  26. # - fix Multiple QTGMC Calls
  27. # - others fix
  28. #
  29. # v3.33s (mod) 2015 8 6
  30. # - some changes in bob to speed up
  31. #
  32. # v3.33s (mod) 2015 8 4
  33. # - fix bug in YUY2 with SourceMatch
  34. # - add slice=false to ditherpost to avoid artefacts
  35. #
  36. # v3.33s (mod)
  37. # - fix bob chroma
  38. # - work with new masktool2 for avs 2.60 in YUY2
  39. #
  40. # v3.33d (mod)
  41. # - Added 32 bit precision option through the lsbd (for dfttest and knlmeanscl) and lsb (mdegrain) options.
  42. # - optimized some mask handling a bit as originally suggested by Vit
  43. # - others
  44. #
  45. # v3.33
  46. # - Increased maximum value for Rep0, Rep1 and Rep2 to 7 (from 5). Higher values help with flicker on static detail, potential for minor motion blur
  47. # - Bug fix for the fact that Bob always outputs a BFF clip regardless of field order of input (thanks ajp_anton)
  48. # - Improved generation of noise (NoiseDeint="Generate") for noise bypass / EZKeepGrain
  49. # - Minor change to denoising
  50. #
  51. # v3.32
  52. # - Bugfix with shutter blur and ChromaMotion (thanks Heaud)
  53. # - Tweaked vector recalculation for shutter motion blur
  54. # - Changed defaults for TR2 when using source-match
  55. # - Minor bugfix with SLMode/SLRad on pass-through settings
  56. #
  57. # --- REQUIREMENTS ---
  58. #
  59. # Input colorspaces: YV12, YUY2
  60. #
  61. # Core plugins:
  62. #   MVTools2 (2.6.0.5 or above)
  63. #   MaskTools v2 (recommend 2.0a48 or above)
  64. #   NNEDI3 (recommend 0.9.4 or above for speed)
  65. #   RemoveGrain + Repair (several versions of this plugin, use the SSE2 dlls from the file called "RemoveGrain-1.0.rar". Don't use the SSE3 versions )
  66. #   SSE2Tools for YUY2 support (from the earlier 0.9 version of RemoveGrain, use only SSE2Tools.dll from this version. Don't use the SSE3 version)
  67. #
  68. # Additional plugins:
  69. #   NNEDI2, NNEDI, EEDI3, EEDI2, TDeInt - if selected directly or via a source-match preset
  70. #   Yadif - for Preset="Ultra Fast" or if selected directly (cannot be autoloaded, must be loaded in the calling script)
  71. #   VerticalCleaner - for SVThin or Lossless modes
  72. #   FFT3DFilter - if selected for noise processing
  73. #   dfttest - if selected for noise processing
  74. #       For FFT3DFilter & ddftest you also need the FFTW3 library (FFTW.org). On Windows the file needed for both is libfftw3f-3.dll. However, for FFT3DFilter
  75. #       the file needs to be called FFTW3.dll, so you will need two copies and rename one. On Windows put the files in your System32 or SysWow64 folder
  76. #   AddGrainC - if NoiseDeint="Generate" selected for noise bypass
  77.  
  78.  
  79. # --- GETTING STARTED ---
  80. #
  81. # Install AviSynth and ensure you have at least the core plugins listed in the requirements section above. Put them in the plugins autoload folder.
  82. # To use QTGMC write a script like this:
  83. #   YourSource("yourfile")   # DGDecode_mpeg2source, FFVideoSource, AviSource, whatever your source requires
  84. #   QTGMC( Preset="Slow" )
  85. #   SelectEven()             # Add this line to keep original frame rate, leave it out for smoother doubled frame rate
  86. #
  87. # Save this script with an ".avs" extension. You can now use it as an AVI source for encoding.
  88. #
  89. # The "Preset" used selects sensible settings for a given encoding speed. Choose a preset from:
  90. #   "Placebo", "Very Slow", "Slower", "Slow", "Medium", "Fast", "Faster", "Very Fast", "Super Fast", "Ultra Fast" & "Draft"
  91. # The default preset is "Slower"
  92. # Don't be obsessed with using slower settings as the differences can be small. HD material benefits little from extreme settings (and will be very slow)
  93. # For much faster speeds read the full documentation, the section on 'Multi-threading'
  94. #
  95. # There are many settings for tweaking the script, full details in the main documentation. You can display settings currently being used with "ShowSettings":
  96. #   QTGMC( Preset="Slow", ShowSettings=true )
  97.  
  98.  
  99. function QTGMC( clip Input, string "Preset", int "TR0", int "TR1", int "TR2", int "Rep0", int "Rep1", int "Rep2", string "EdiMode", bool "RepChroma", \
  100.                     int "NNSize", int "NNeurons", int "EdiQual", int "EdiMaxD", string "ChromaEdi", int "EdiThreads", clip "EdiExt", float "Sharpness", \
  101.                     int "SMode", int "SLMode", int "SLRad", int "SOvs", float "SVThin", int "Sbb", int "SrchClipPP", int "SubPel", int "SubPelInterp", \
  102.                     int "BlockSize", int "Overlap", int "Search", int "SearchParam", int "PelSearch", bool "ChromaMotion", bool "TrueMotion", int "Lambda", \
  103.                     int "LSAD", int "PNew", int "PLevel", bool "GlobalMotion", int "DCT", int "ThSAD1", int "ThSAD2", int "ThSCD1", int "ThSCD2", \
  104.                     int "SourceMatch", string "MatchPreset", string "MatchEdi", string "MatchPreset2", string "MatchEdi2", int "MatchTR2", \
  105.                     float "MatchEnhance", int "Lossless", int "NoiseProcess", float "EZDenoise", float "EZKeepGrain", string "NoisePreset", string "Denoiser", \
  106.                     int "DftThreads", bool "DenoiseMC", int "NoiseTR", float "Sigma", bool "ChromaNoise", val "ShowNoise", float "GrainRestore", \
  107.                     float "NoiseRestore", string "NoiseDeint", bool "StabilizeNoise", int "InputType", float "ProgSADMask", int "FPSDivisor", \
  108.                     int "ShutterBlur", float "ShutterAngleSrc", float "ShutterAngleOut", int "SBlurLimit", bool "Border", bool "Precise", string "Tuning", \
  109.                     bool "ShowSettings", string "GlobalNames", string "PrevGlobals", int "ForceTR", \
  110.                     val "BT", val "DetailRestore", val "MotionBlur", val "MBlurLimit", val "NoiseBypass", bool "lsbd", bool "lsb" )
  111. {
  112.     # The preset "Ultra Fast" & EdiMode="RepYadif"/"Yadif" require the Yadif plugin, which doesn't autoload. Typically the calling script would load it.
  113.     # To have this script load Yadif put it's full path in string below (e.g. "C:\Plugins\Yadif.dll"). Use empty string ("") if calling script will load Yadif
  114.     YadifPath = "" # Or just enter "yadif.dll" if Yadif is placed in the system path (e.g. windows\system32)
  115.  
  116.     # Temporary Warnings
  117.     Assert( !defined(BT),            "QTGMC: Setting BT has been replaced by setting NoiseTR" )
  118.     Assert( !defined(DetailRestore), "QTGMC: Setting DetailRestore has been renamed to GrainRestore" )
  119.     Assert( !defined(MotionBlur),    "QTGMC: Setting MotionBlur has been renamed to ShutterBlur" )
  120.     Assert( !defined(MBlurLimit),    "QTGMC: Setting MBlurLimit has been renamed to SBlurLimit" )
  121.     Assert( !defined(NoiseBypass),   "QTGMC: Setting NoiseBypass has been renamed to NoiseProcess" )
  122.  
  123.     #---------------------------------------
  124.     # Presets
  125. lsbd=default(lsbd, false)
  126. lsb=default(lsb, false)
  127.     # Select presets / tuning
  128.     Preset = default( Preset, "Slower" )
  129.     pNum = (Preset == "Placebo"   ) ? 0 : \
  130.            (Preset == "Very Slow" ) ? 1 : \
  131.            (Preset == "Slower"    ) ? 2 : \
  132.            (Preset == "Slow"      ) ? 3 : \
  133.            (Preset == "Medium"    ) ? 4 : \
  134.            (Preset == "Fast"      ) ? 5 : \
  135.            (Preset == "Faster"    ) ? 6 : \
  136.            (Preset == "Very Fast" ) ? 7 : \
  137.            (Preset == "Super Fast") ? 8 : \
  138.            (Preset == "Ultra Fast") ? 9 : \
  139.            (Preset == "Draft"     ) ? 10 : 11
  140.     Assert( pNum  < 11, "'Preset' choice is invalid" )
  141.  
  142.     mpNum1 = (!defined(MatchPreset))       ? ((pNum + 3 <= 9) ? (pNum + 3) : 9) : \
  143.              (MatchPreset == "Placebo"   ) ? 0 : \
  144.              (MatchPreset == "Very Slow" ) ? 1 : \
  145.              (MatchPreset == "Slower"    ) ? 2 : \
  146.              (MatchPreset == "Slow"      ) ? 3 : \
  147.              (MatchPreset == "Medium"    ) ? 4 : \
  148.              (MatchPreset == "Fast"      ) ? 5 : \
  149.              (MatchPreset == "Faster"    ) ? 6 : \
  150.              (MatchPreset == "Very Fast" ) ? 7 : \
  151.              (MatchPreset == "Super Fast") ? 8 : \
  152.              (MatchPreset == "Ultra Fast") ? 9 : \
  153.              (MatchPreset == "Draft"     ) ? 10 : 11
  154.     Assert( mpNum1 < 10, "'MatchPreset' choice is invalid/unsupported" )
  155.     MatchPreset = Select( mpNum1, "Placebo", "Very Slow", "Slower", "Slow", "Medium", "Fast", "Faster", "Very Fast", "Super Fast", "Ultra Fast", "Draft" )
  156.  
  157.     mpNum2 = (!defined(MatchPreset2))       ? ((mpNum1 + 2 <= 9) ? (mpNum1 + 2) : 9) : \
  158.              (MatchPreset2 == "Placebo"   ) ? 0 : \
  159.              (MatchPreset2 == "Very Slow" ) ? 1 : \
  160.              (MatchPreset2 == "Slower"    ) ? 2 : \
  161.              (MatchPreset2 == "Slow"      ) ? 3 : \
  162.              (MatchPreset2 == "Medium"    ) ? 4 : \
  163.              (MatchPreset2 == "Fast"      ) ? 5 : \
  164.              (MatchPreset2 == "Faster"    ) ? 6 : \
  165.              (MatchPreset2 == "Very Fast" ) ? 7 : \
  166.              (MatchPreset2 == "Super Fast") ? 8 : \
  167.              (MatchPreset2 == "Ultra Fast") ? 9 : \
  168.              (MatchPreset2 == "Draft"     ) ? 10 : 11
  169.     Assert( mpNum2 < 10, "'MatchPreset2' choice is invalid/unsupported" )
  170.     MatchPreset2 = Select( mpNum2, "Placebo", "Very Slow", "Slower", "Slow", "Medium", "Fast", "Faster", "Very Fast", "Super Fast", "Ultra Fast", "Draft" )
  171.  
  172.     NoisePreset = default( NoisePreset, "Fast" )
  173.     npNum = (NoisePreset == "Slower" ) ? 0 : \
  174.             (NoisePreset == "Slow"   ) ? 1 : \
  175.             (NoisePreset == "Medium" ) ? 2 : \
  176.             (NoisePreset == "Fast"   ) ? 3 : \
  177.             (NoisePreset == "Faster" ) ? 4 : 5
  178.     Assert( npNum < 5, "'NoisePreset' choice is invalid" )
  179.  
  180.     Tuning = default( Tuning, "None" )
  181.     tNum = (Tuning == "None"  ) ? 0 : \
  182.            (Tuning == "DV-SD" ) ? 1 : \
  183.            (Tuning == "DV-HD" ) ? 2 : 3
  184.     Assert( tNum < 3, "'Tuning' choice is invalid" )
  185.  
  186.     # Tunings only affect blocksize in this version
  187.     bs = Select( tNum,  16, 16, 32 )
  188.     bs2 = (bs >= 16) ? 32 : bs * 2
  189.  
  190.     #                                                               Very                                                        Very      Super      Ultra
  191.     # Preset groups:                                     Placebo    Slow      Slower    Slow      Medium    Fast      Faster    Fast      Fast       Fast       Draft
  192.     TR0          = default( TR0,          Select( pNum,  2,         2,        2,        2,        2,        2,        1,        1,        1,         1,         1      ) )
  193.     TR1          = default( TR1,          Select( pNum,  2,         2,        2,        1,        1,        1,        1,        1,        1,         1,         1      ) )
  194.     TR2X         = default( TR2,          Select( pNum,  3,         2,        1,        1,        1,        0,        0,        0,        0,         0,         0      ) )
  195.     Rep0         = default( Rep0,         Select( pNum,  4,         4,        4,        4,        3,        3,        0,        0,        0,         0,         0      ) )
  196.     Rep1         = default( Rep1,         Select( pNum,  0,         0,        0,        0,        0,        0,        0,        0,        0,         0,         0      ) )
  197.     Rep2         = default( Rep2,         Select( pNum,  4,         4,        4,        4,        4,        4,        4,        4,        3,         3,         0      ) )
  198.     EdiMode      = default( EdiMode,      Select( pNum, "NNEDI3",  "NNEDI3", "NNEDI3", "NNEDI3", "NNEDI3", "NNEDI3", "NNEDI3", "NNEDI3", "NNEDI3",  "RepYadif","Bob"   ) )
  199.     NNSize       = default( NNSize,       Select( pNum,  1,         1,        1,        1,        5,        5,        4,        4,        4,         4,         4      ) )
  200.     NNeurons     = default( NNeurons,     Select( pNum,  2,         2,        1,        1,        1,        0,        0,        0,        0,         0,         0      ) )
  201.     EdiQual      = default( EdiQual,      Select( pNum,  1,         1,        1,        1,        1,        1,        1,        1,        1,         1,         1      ) )
  202.     EdiMaxD      = default( EdiMaxD,      Select( pNum,  12,        10,       8,        7,        7,        6,        6,        5,        4,         4,         4      ) )
  203.     SMode        = default( SMode,        Select( pNum,  2,         2,        2,        2,        2,        2,        2,        2,        2,         2,         0      ) )
  204.     SLModeX      = default( SLMode,       Select( pNum,  2,         2,        2,        2,        2,        2,        2,        2,        0,         0,         0      ) )
  205.     SLRad        = default( SLRad,        Select( pNum,  3,         1,        1,        1,        1,        1,        1,        1,        1,         1,         1      ) )
  206.     Sbb          = default( Sbb,          Select( pNum,  3,         1,        1,        0,        0,        0,        0,        0,        0,         0,         0      ) )
  207.     SrchClipPP   = default( SrchClipPP,   Select( pNum,  3,         3,        3,        3,        3,        2,        2,        2,        1,         1,         0      ) )
  208.     SubPel       = default( SubPel,       Select( pNum,  2,         2,        2,        2,        1,        1,        1,        1,        1,         1,         1      ) )
  209.     Blocksize    = default( Blocksize,    Select( pNum,  bs,        bs,       bs,       bs,       bs,       bs,       bs2,      bs2,      bs2,       bs2,       bs2    ) )
  210.     bs = Blocksize
  211.     Overlap      = default( Overlap,      Select( pNum,  bs/2,      bs/2,     bs/2,     bs/2,     bs/2,     bs/2,     bs/2,     bs/4,     bs/4,      bs/4,      bs/4   ) )
  212.     Search       = default( Search,       Select( pNum,  5,         4,        4,        4,        4,        4,        4,        4,        0,         0,         0      ) )
  213.     SearchParam  = default( SearchParam,  Select( pNum,  2,         2,        2,        2,        2,        2,        2,        1,        1,         1,         1      ) )
  214.     PelSearch    = default( PelSearch,    Select( pNum,  2,         2,        2,        2,        1,        1,        1,        1,        1,         1,         1      ) )
  215.     ChromaMotion = default( ChromaMotion, Select( pNum,  true,      true,     true,     false,    false,    false,    false,    false,    false,     false,     false  ) )
  216.     Precise      = default( Precise,      Select( pNum,  true,      true,     false,    false,    false,    false,    false,    false,    false,     false,     false  ) )
  217.     ProgSADMask  = default( ProgSADMask,  Select( pNum,  10.0,      10.0,     10.0,     10.0,     10.0,     0.0,      0.0,      0.0,      0.0,       0.0,       0.0    ) )
  218.  
  219.     # Noise presets                                           Slower     Slow       Medium     Fast       Faster
  220.     Denoiser       = default( Denoiser,       Select( npNum, "dfttest", "dfttest", "dfttest", "fft3df",  "fft3df" ) )
  221.     DenoiseMC      = default( DenoiseMC,      Select( npNum,  true,      true,      false,     false,     false   ) )
  222.     NoiseTR        = default( NoiseTR,        Select( npNum,  2,         1,         1,         1,         0       ) )
  223.     NoiseDeint     = default( NoiseDeint,     Select( npNum, "Generate","Bob",      "",        "",        ""      ) )
  224.     StabilizeNoise = default( StabilizeNoise, Select( npNum,  true,      true,      true,      false,     false   ) )
  225.  
  226.     # The basic source-match step corrects and re-runs the interpolation of the input clip. So it initialy uses same interpolation settings as the main preset
  227.     SourceMatch   = default( SourceMatch, 0 )
  228.     MatchNNSize   = NNSize
  229.     MatchNNeurons = NNeurons
  230.     MatchEdiMaxD  = EdiMaxD
  231.     MatchEdiQual  = EdiQual
  232.  
  233.     # However, can use a faster initial interpolation when using source-match allowing the basic source-match step to "correct" it with higher quality settings
  234.     Assert( SourceMatch == 0 || mpNum1 >= pNum, "'MatchPreset' cannot use a slower setting than 'Preset'" )
  235.     #                                                                    Very                                                        Very      Super     Ultra
  236.     # Basic source-match presets                                Placebo  Slow      Slower    Slow      Medium    Fast      Faster    Fast      Fast      Fast
  237.     NNSize   = (SourceMatch == 0) ? NNSize   : Select( mpNum1,  1,       1,        1,        1,        5,        5,        4,        4,        4,        4     )
  238.     NNeurons = (SourceMatch == 0) ? NNeurons : Select( mpNum1,  2,       2,        1,        1,        1,        0,        0,        0,        0,        0     )
  239.     EdiMaxD  = (SourceMatch == 0) ? EdiMaxD  : Select( mpNum1,  12,      10,       8,        7,        7,        6,        6,        5,        4,        4     )
  240.     EdiQual  = (SourceMatch == 0) ? EdiQual  : Select( mpNum1,  1,       1,        1,        1,        1,        1,        1,        1,        1,        1     )
  241.     TempEdi  = EdiMode # Main interpolation is actually done by basic-source match step when enabled, so a little swap and wriggle is needed
  242.     EdiMode  = (SourceMatch == 0) ? EdiMode  : default( MatchEdi, ((mpNum1 < 9) ?  EdiMode : "Yadif") ) # Force Yadif for "Ultra Fast" basic source match
  243.     MatchEdi = TempEdi
  244.  
  245.     #                                                          Very                                                        Very      Super     Ultra
  246.     # Refined source-match presets                   Placebo   Slow      Slower    Slow      Medium    Fast      Faster    Fast      Fast      Fast
  247.     MatchEdi2 = default( MatchEdi2, Select( mpNum2, "NNEDI3", "NNEDI3", "NNEDI3", "NNEDI3", "NNEDI3", "NNEDI3", "NNEDI3", "NNEDI3", "TDeint",  ""    ) )
  248.     MatchNNSize2                  = Select( mpNum2,  1,        1,        1,        1,        5,        5,        4,        4,        4,        4     )
  249.     MatchNNeurons2                = Select( mpNum2,  2,        2,        1,        1,        1,        0,        0,        0,        0,        0     )
  250.     MatchEdiMaxD2                 = Select( mpNum2,  12,       10,       8,        7,        7,        6,        6,        5,        4,        4     )
  251.     MatchEdiQual2                 = Select( mpNum2,  1,        1,        1,        1,        1,        1,        1,        1,        1,        1     )
  252.  
  253.  
  254.     #---------------------------------------
  255.     # Settings
  256.  
  257.     # Core and Interpolation defaults
  258.     TR2        = (SourceMatch > 0) ? default(TR2, ((TR2X == 0) ? 1 : TR2X)) : TR2X  # ***TR2 defaults always at least 1 when using source-match***
  259.     RepChroma  = default( RepChroma,  true )
  260.     EdiThreads = default( EdiThreads, 0    )
  261.     ChromaEdi  = default( ChromaEdi,  ""   )
  262.     NNeurons   = (EdiMode == "NNEDI2" && NNeurons > 2) ? 2 : NNeurons # Smaller range for NNeurons in NNEDI2 (which calls it nsize)
  263.     EdiQual    = (EdiMode == "NNEDI3" && EdiQual > 2 ) ? 2 : EdiQual  # Smaller range for EdiQual in NNEDI3
  264.     ((FindStr( EdiMode, "Yadif" ) != 0 || FindStr( MatchEdi, "Yadif" ) != 0 || FindStr( MatchEdi2, "Yadif" ) != 0  ) && YadifPath != "") ? \
  265.         Load_Stdcall_Plugin( YadifPath ) : NOP() # Load Yadif as required
  266.  
  267.     # Source-match / lossless defaults
  268.     MatchTR1     = TR1
  269.     MatchTR2     = default( MatchTR2,     1   )
  270.     MatchEnhance = default( MatchEnhance, 0.5 )
  271.     Lossless     = default( Lossless,     0   )
  272.     Assert( Lossless <= 2, "Lossless setting only supports mode 1 ('true lossless') and mode 2 ('fake lossless') - see documentation in script and consider source-match settings" )
  273.  
  274.     # Sharpness defaults. Sharpness default is always 1.0 (0.2 with source-match), but adjusted to give roughly same sharpness for all settings
  275.     SMode      = (defined(Sharpness) && Sharpness == 0.0) ? 0 : SMode
  276.     SLMode     = (SourceMatch > 0) ? default(SLMode, 0) : SLModeX  # ***Sharpness limiting disabled by default for source-match***
  277.     SLMode     = (SLRad <= 0)      ? 0 : SLMode
  278.     spatialSL  = (SLMode == 1 || SLMode == 3)
  279.     temporalSL = (SLMode == 2 || SLMode == 4)
  280.     Sharpness  = default( Sharpness, (SMode == 0) ? 0.0 : ((SourceMatch > 0) ? 0.2 : 1.0) )      # Default sharpness is 1.0, or 0.2 if using source-match
  281.     sharpMul   = (temporalSL) ? 2 : (spatialSL) ? 1.5 : 1                                        # Adjust sharpness based on other settings
  282.     sharpAdj   = Sharpness * (sharpMul * (0.2 + TR1*0.15 + TR2*0.25) + ((SMode == 1) ? 0.1 : 0)) # [This needs a bit more refinement]
  283.     Sbb        = (SMode == 0) ? 0 : Sbb
  284.     SOvs       = default( SOvs,   0   )
  285.     SVThin     = default( SVThin, 0.0 )
  286.  
  287.     # Noise processing settings
  288.     Assert( !defined(EZDenoise) || EZDenoise <= 0.0 || !defined(EZKeepGrain) || EZKeepGrain <= 0.0, "QTGMC: EZDenoise and EZKeepGrain cannot be used together" )
  289.     NoiseProcess = defined(NoiseProcess) ? NoiseProcess : \
  290.                    (defined(EZDenoise)   && EZDenoise   > 0.0)    ? 1 : \
  291.                    (defined(EZKeepGrain) && EZKeepGrain > 0.0)    ? 2 : \
  292.                    (Preset == "Placebo" || Preset == "Very Slow") ? 2 : 0
  293.     GrainRestore = defined(GrainRestore) ? GrainRestore : \
  294.                    (defined(EZDenoise)   && EZDenoise   > 0.0) ? 0.0 : \
  295.                    (defined(EZKeepGrain) && EZKeepGrain > 0.0) ? 0.3 * sqrt(EZKeepGrain) : \
  296.                                                                 Select( NoiseProcess, 0.0, 0.7, 0.3 )
  297.     NoiseRestore = defined(NoiseRestore) ? NoiseRestore : \
  298.                    (defined(EZDenoise)   && EZDenoise   > 0.0) ? 0.0 : \
  299.                    (defined(EZKeepGrain) && EZKeepGrain > 0.0) ? 0.1 * sqrt(EZKeepGrain) : \
  300.                                                                 Select( NoiseProcess, 0.0, 0.3, 0.1 )
  301.     Sigma        = defined(Sigma)       ? Sigma : \
  302.                    (defined(EZDenoise)   && EZDenoise   > 0.0) ? EZDenoise : \
  303.                    (defined(EZKeepGrain) && EZKeepGrain > 0.0) ? 4.0 * EZKeepGrain : 2.0
  304.     DftThreads   = default( DftThreads, EdiThreads )
  305.     ChromaNoise  = default( ChromaNoise, false )
  306.     ShowNoise    = default( ShowNoise, 0.0 )
  307.     ShowNoise    = IsBool( ShowNoise ) ? (ShowNoise ? 10.0 : 0.0) : ShowNoise
  308.     NoiseProcess = (ShowNoise > 0.0)   ? 2   : NoiseProcess
  309.     NoiseRestore = (ShowNoise > 0.0)   ? 1.0 : NoiseRestore
  310.     NoiseTR      = (NoiseProcess == 0) ? 0   : NoiseTR
  311.     GrainRestore = (NoiseProcess == 0) ? 0.0 : GrainRestore
  312.     NoiseRestore = (NoiseProcess == 0) ? 0.0 : NoiseRestore
  313.     totalRestore = GrainRestore + NoiseRestore
  314.     StabilizeNoise = (totalRestore <= 0) ? false : StabilizeNoise
  315.     noiseTD  = Select( NoiseTR, 1, 3, 5 )
  316.     noiseCentre = (Denoiser == "dfttest") ? "128" : "128.5"
  317.  
  318.     # MVTools settings
  319.     SubPelInterp = default( SubPelInterp, 2     )
  320.     TrueMotion   = default( TrueMotion,   false )
  321.     GlobalMotion = default( GlobalMotion, true  )
  322.     Lambda       = default( Lambda, ((TrueMotion) ? 1000 : 100 ) * (BlockSize*BlockSize)/(8*8) )
  323.     LSAD         = default( LSAD,    (TrueMotion) ? 1200 : 400 )
  324.     PNew         = default( PNew,    (TrueMotion) ? 50   : 25  )
  325.     PLevel       = default( PLevel,  (TrueMotion) ? 1    : 0   )
  326.     DCT          = default( DCT,     0          )
  327.     ThSAD1       = default( ThSAD1,  10 * 8*8   )
  328.     ThSAD2       = default( ThSAD2,   4 * 8*8   )
  329.     ThSCD1       = default( ThSCD1,  180        )
  330.     ThSCD2       = default( ThSCD2,  98         )
  331.  
  332.     # Motion blur settings
  333.     FPSDivisor  = default( FPSDivisor, 1 )
  334.     ShutterBlur = default( ShutterBlur, 0 )
  335.     ShutterAngleSrc = default( ShutterAngleSrc, 180 )
  336.     ShutterAngleOut = default( ShutterAngleOut, 180 )
  337.     SBlurLimit  = default( SBlurLimit, 4 )
  338.     ShutterBlur = (ShutterAngleOut * FPSDivisor == ShutterAngleSrc) ? 0 : ShutterBlur  # If motion blur output is same as input
  339.  
  340.     # Miscellaneous
  341.     InputType      = default( InputType,     0        )
  342.     Border         = default( Border,        false    )
  343.     ShowSettings   = default( ShowSettings,  false    )
  344.     GlobalNames    = default( GlobalNames,  "QTGMC"   )
  345.     PrevGlobals    = default( PrevGlobals,  "Replace" )
  346.     ForceTR        = default( ForceTR,       0        )
  347.     ReplaceGlobals = (PrevGlobals == "Replace" || PrevGlobals == "Reuse") # If reusing existing globals put them back afterwards - simplifies logic later
  348.     ReuseGlobals   = (PrevGlobals == "Reuse")
  349.     ProgSADMask    = (InputType != 2 && InputType != 3) ? 0.0 : ProgSADMask
  350.     rgBlur         = (Precise) ? 11 : 12
  351.  
  352.     # Get maximum temporal radius needed
  353.     maxTR = (temporalSL)       ? SLRad : 0
  354.     maxTR = (MatchTR2 > maxTR) ? MatchTR2 : maxTR
  355.     maxTR = (TR1 > maxTR)      ? TR1 : maxTR
  356.     maxTR = (TR2 > maxTR)      ? TR2 : maxTR
  357.     maxTR = (NoiseTR > maxTR)  ? NoiseTR : maxTR
  358.     maxTR = (ProgSADMask > 0.0 || StabilizeNoise || ShutterBlur > 0) ? (maxTR > 1 ? maxTR : 1) : maxTR
  359.     maxTR = (ForceTR > MaxTR)  ? ForceTR : maxTR
  360.  
  361.  
  362.     #---------------------------------------
  363.     # Pre-Processing
  364.  
  365.     w = Input.Width()
  366.     h = Input.Height()
  367.     yuy2 = Input.IsYUY2()
  368.     epsilon = 0.0001
  369.  
  370.     # Reverse "field" dominance for progressive repair mode 3 (only difference from mode 2)
  371.     compl = (InputType == 3) ? Input.ComplementParity() : Input
  372.  
  373.     # Pad vertically during processing (to prevent artefacts at top & bottom edges)
  374.     clip = (Border) ? compl.PointResize( w,h+8, 0,-4,0,h+8+epsilon ) : compl
  375.     h = (Border) ? h+8 : h
  376.  
  377.     # Calculate padding needed for MVTools super clips to avoid crashes [fixed in latest MVTools, but keeping this code for a while]
  378.     hpad = w - (Int((w - Overlap) / (Blocksize - Overlap)) * (Blocksize - Overlap) + Overlap)
  379.     vpad = h - (Int((h - Overlap) / (Blocksize - Overlap)) * (Blocksize - Overlap) + Overlap)
  380.     hpad = (hpad > 8) ? hpad : 8 # But match default padding if possible
  381.     vpad = (vpad > 8) ? vpad : 8
  382.  
  383.  
  384.     #---------------------------------------
  385.     # Motion Analysis
  386.  
  387.     # >>> Planar YUY2 for motion analysis, interleaved whilst blurring search clip
  388.     planarClip = yuy2 ? clip.interleaved2planar() : clip
  389.  
  390.     # Bob the input as a starting point for motion search clip
  391.     bobbed = (InputType == 0) ? planarClip.QTGMC_Bob( 0,0.5 ) : \
  392.              (InputType == 1) ? planarClip : \
  393.                                 planarClip.Blur( 0,1 )
  394.  
  395.     # If required, get any existing global clips with a matching "GlobalNames" setting. Unmatched values get NOP (= 0)
  396.     srchClip  = QTGMC_GetUserGlobal( GlobalNames, "srchClip",  ReuseGlobals )
  397.     srchSuper = QTGMC_GetUserGlobal( GlobalNames, "srchSuper", ReuseGlobals )
  398.     bVec1     = QTGMC_GetUserGlobal( GlobalNames, "bVec1",     ReuseGlobals )
  399.     fVec1     = QTGMC_GetUserGlobal( GlobalNames, "fVec1",     ReuseGlobals )
  400.     bVec2     = QTGMC_GetUserGlobal( GlobalNames, "bVec2",     ReuseGlobals )
  401.     fVec2     = QTGMC_GetUserGlobal( GlobalNames, "fVec2",     ReuseGlobals )
  402.     bVec3     = QTGMC_GetUserGlobal( GlobalNames, "bVec3",     ReuseGlobals )
  403.     fVec3     = QTGMC_GetUserGlobal( GlobalNames, "fVec3",     ReuseGlobals )
  404.  
  405.     CMmt = ChromaMotion ? 3   :  1
  406.     CMts = ChromaMotion ? 255 :  0
  407.     CMrg = ChromaMotion ? 12  : -1
  408.  
  409.     # The bobbed clip will shimmer due to being derived from alternating fields. Temporally smooth over the neighboring frames using a binomial kernel. Binomial
  410.     # kernels give equal weight to even and odd frames and hence average away the shimmer. The two kernels used are [1 2 1] and [1 4 6 4 1] for radius 1 and 2.
  411.     # These kernels are approximately Gaussian kernels, which work well as a prefilter before motion analysis (hence the original name for this script)
  412.     # Create linear weightings of neighbors first                                                 -2    -1     0    1     2
  413.     ts1 = (!IsClip(srchClip) && TR0 > 0) ? !yuy2 ? bobbed.TemporalSoften( 1, 255,CMts, 28, 2 ) : \
  414.      bobbed.planar2interleaved().TemporalSoften( 1, 255,CMts, 28, 2 ).interleaved2planar() : NOP()  # 0.00  0.33  0.33  0.33  0.00
  415.     ts2 = (!IsClip(srchClip) && TR0 > 1) ? !yuy2 ? bobbed.TemporalSoften( 2, 255,CMts, 28, 2 ) : \
  416.      bobbed.planar2interleaved().TemporalSoften( 2, 255,CMts, 28, 2 ).interleaved2planar() : NOP()  # 0.20  0.20  0.20  0.20  0.20
  417.  
  418.     # Combine linear weightings to give binomial weightings - TR0=0: (1), TR0=1: (1:2:1), TR0=2: (1:4:6:4:1)
  419.     binomial0 = IsClip(srchClip) ? NOP() : \
  420.                 (TR0 == 0)       ? bobbed : \
  421.                 (TR0 == 1)       ? (ChromaMotion ? ts1.Merge( bobbed, 0.25 ) : !yuy2 ? ts1.MergeLuma( bobbed, 0.25 ) : \
  422.                                    ts1.planar2interleaved().MergeLuma( bobbed.planar2interleaved(), 0.25 ).interleaved2planar()) : \
  423.                                    (ChromaMotion ? ts1.Merge( ts2, 0.357 ).Merge( bobbed, 0.125 ) : !yuy2 ? ts1.MergeLuma( ts2, 0.357 ).MergeLuma( bobbed, 0.125 ) : \
  424.                                    ts1.planar2interleaved().MergeLuma( ts2.planar2interleaved(), 0.357 ).MergeLuma( bobbed.planar2interleaved(), 0.125 ).interleaved2planar())
  425.  
  426.     # Remove areas of difference between temporal blurred motion search clip and bob that are not due to bob-shimmer - removes general motion blur
  427.     repair0 = (IsClip(srchClip) || Rep0 == 0) ? binomial0 : binomial0.QTGMC_KeepOnlyBobShimmerFixes( bobbed, Rep0, (RepChroma && ChromaMotion) )
  428.  
  429.     # Blur image and soften edges to assist in motion matching of edge blocks. Blocks are matched by SAD (sum of absolute differences between blocks), but even
  430.     # a slight change in an edge from frame to frame will give a high SAD due to the higher contrast of edges
  431.     spatialBlur = (IsClip(srchClip) || SrchClipPP == 0) ? NOP() : \
  432.                   (!yuy2 && SrchClipPP == 1) ? repair0.BilinearResize( w/2, h/2 ).RemoveGrain( 12,CMrg, planar=true ).BilinearResize( w, h ) : \
  433.                   (!yuy2)                    ? repair0.RemoveGrain( 12,CMrg, planar=true ).GaussResize( w,h, 0,0, w+epsilon,h+epsilon, p=2 ) : \
  434.                                                repair0.RemoveGrain( 12,CMrg, planar=true ).planar2interleaved().GaussResize( w,h, 0,0, w+epsilon,h+epsilon, p=2 ).interleaved2planar()
  435.     spatialBlur = (IsClip(spatialBlur) && SrchClipPP > 1) ? (ChromaMotion ? spatialBlur.Merge( repair0, 0.1 ) : spatialBlur.MergeLuma( repair0, 0.1 )) : spatialBlur
  436.     tweluin26 = (!IsClip(srchClip) && SrchClipPP > 1) ? yuy2 ? mt_lutxy( repair0.planar2interleaved().ConvertToYV16(), bobbed.planar2interleaved().ConvertToYV16(), "x 3 + y < x 3 + x 3 - y > x 3 - y ? ?", U=CMmt,V=CMmt ).ConvertToYUY2().interleaved2planar() : nop() : nop()
  437.     tweaked     = (!IsClip(srchClip) && SrchClipPP > 1) ? !yuy2 ? mt_lutxy( repair0, bobbed, "x 3 + y < x 3 + x 3 - y > x 3 - y ? ?", U=CMmt,V=CMmt ) : tweluin26 : NOP()
  438.     srchClip    = IsClip(srchClip)  ? srchClip : \
  439.                   (SrchClipPP == 0) ? repair0 : \
  440.                   (SrchClipPP < 3)  ? spatialBlur : \
  441.                                       yuy2 ? spatialBlur.planar2interleaved().ConvertToYV16().mt_lutxy( tweaked.planar2interleaved().ConvertToYV16(), \
  442.     "x 7 + y < x 2 + x 7 - y > x 2 - x 51 * y 49 * + 100 / ? ?", U=CMmt,V=CMmt ).ConvertToYUY2().interleaved2planar() : \
  443.     spatialBlur.mt_lutxy( tweaked, "x 7 + y < x 2 + x 7 - y > x 2 - x 51 * y 49 * + 100 / ? ?", U=CMmt,V=CMmt )
  444.     # Calculate forward and backward motion vectors from motion search clip
  445.     srchSuper = IsClip(srchSuper) ? srchSuper : \
  446.                 (maxTR > 0)       ? srchClip.MSuper( pel=SubPel, sharp=SubPelInterp, hpad=hpad, vpad=vpad, chroma=ChromaMotion, planar=true ) : NOP()
  447.     bVec3 = IsClip(bVec3) ? bVec3 : \
  448.             (maxTR > 2)   ? srchSuper.MAnalyse( isb=true,  delta=3, blksize=BlockSize, overlap=Overlap, search=Search, searchparam=SearchParam, \
  449.                                                 pelsearch=PelSearch, truemotion=TrueMotion, lambda=Lambda, lsad=LSAD, pnew=PNew, plevel=PLevel, \
  450.                                                 global=GlobalMotion, DCT=DCT, chroma=ChromaMotion ) : NOP()
  451.     bVec2 = IsClip(bVec2) ? bVec2 : \
  452.             (maxTR > 1)   ? srchSuper.MAnalyse( isb=true,  delta=2, blksize=BlockSize, overlap=Overlap, search=Search, searchparam=SearchParam, \
  453.                                                 pelsearch=PelSearch, truemotion=TrueMotion, lambda=Lambda, lsad=LSAD, pnew=PNew, plevel=PLevel, \
  454.                                                 global=GlobalMotion, DCT=DCT, chroma=ChromaMotion ) : NOP()
  455.     bVec1 = IsClip(bVec1) ? bVec1 : \
  456.             (maxTR > 0)   ? srchSuper.MAnalyse( isb=true,  delta=1, blksize=BlockSize, overlap=Overlap, search=Search, searchparam=SearchParam, \
  457.                                                 pelsearch=PelSearch, truemotion=TrueMotion, lambda=Lambda, lsad=LSAD, pnew=PNew, plevel=PLevel, \
  458.                                                 global=GlobalMotion, DCT=DCT, chroma=ChromaMotion ) : NOP()
  459.     fVec1 = IsClip(fVec1) ? fVec1 : \
  460.             (maxTR > 0)   ? srchSuper.MAnalyse( isb=false, delta=1, blksize=BlockSize, overlap=Overlap, search=Search, searchparam=SearchParam, \
  461.                                                 pelsearch=PelSearch, truemotion=TrueMotion, lambda=Lambda, lsad=LSAD, pnew=PNew, plevel=PLevel, \
  462.                                                 global=GlobalMotion, DCT=DCT, chroma=ChromaMotion ) : NOP()
  463.     fVec2 = IsClip(fVec2) ? fVec2 : \
  464.             (maxTR > 1)   ? srchSuper.MAnalyse( isb=false, delta=2, blksize=BlockSize, overlap=Overlap, search=Search, searchparam=SearchParam, \
  465.                                                 pelsearch=PelSearch, truemotion=TrueMotion, lambda=Lambda, lsad=LSAD, pnew=PNew, plevel=PLevel, \
  466.                                                 global=GlobalMotion, DCT=DCT, chroma=ChromaMotion ) : NOP()
  467.     fVec3 = IsClip(fVec3) ? fVec3 : \
  468.             (maxTR > 2)   ? srchSuper.MAnalyse( isb=false, delta=3, blksize=BlockSize, overlap=Overlap, search=Search, searchparam=SearchParam, \
  469.                                                 pelsearch=PelSearch, truemotion=TrueMotion, lambda=Lambda, lsad=LSAD, pnew=PNew, plevel=PLevel, \
  470.                                                 global=GlobalMotion, DCT=DCT, chroma=ChromaMotion ) : NOP()
  471.  
  472.     # Expose search clip, motion search super clip and motion vectors to calling script through globals
  473.     QTGMC_SetUserGlobal( GlobalNames, "srchClip",  srchClip,  ReplaceGlobals )
  474.     QTGMC_SetUserGlobal( GlobalNames, "srchSuper", srchSuper, ReplaceGlobals )
  475.     QTGMC_SetUserGlobal( GlobalNames, "bVec1",     bVec1,     ReplaceGlobals )
  476.     QTGMC_SetUserGlobal( GlobalNames, "fVec1",     fVec1,     ReplaceGlobals )
  477.     QTGMC_SetUserGlobal( GlobalNames, "bVec2",     bVec2,     ReplaceGlobals )
  478.     QTGMC_SetUserGlobal( GlobalNames, "fVec2",     fVec2,     ReplaceGlobals )
  479.     QTGMC_SetUserGlobal( GlobalNames, "bVec3",     bVec3,     ReplaceGlobals )
  480.     QTGMC_SetUserGlobal( GlobalNames, "fVec3",     fVec3,     ReplaceGlobals )
  481.  
  482.  
  483.     #---------------------------------------
  484.     # Noise Processing
  485.  
  486.     # >>>> Interleaved YUY2 for denoising, planar whilst pre-motion compensating
  487.  
  488.     # Expand fields to full frame size before extracting noise (allows use of motion vectors which are frame-sized)
  489.     fullClip  = (NoiseProcess == 0) ? NOP() : \
  490.                 (InputType > 0)     ? clip : \
  491.                                       clip.QTGMC_Bob( 0,1.0 )
  492.     fullClip  = (yuy2 && NoiseTR > 0) ? fullClip.interleaved2planar() : fullClip
  493.     fullSuper = (NoiseTR > 0)         ? fullClip.MSuper( pel=SubPel, levels=1, hpad=hpad, vpad=vpad, chroma=ChromaNoise, planar=true ) : NOP() #TEST chroma OK?
  494.  
  495.     # Create a motion compensated temporal window around current frame and use to guide denoisers
  496.     noiseWindow = (NoiseProcess == 0) ? NOP() : \
  497.                   (!DenoiseMC)        ? fullClip : \
  498.                   (NoiseTR == 0)      ? fullClip : \
  499.                   (NoiseTR == 1)      ? Interleave( fullClip.MCompensate( fullSuper, fVec1, thSCD1=ThSCD1,thSCD2=ThSCD2, planar=true ), \
  500.                                                     fullClip, \
  501.                                                     fullClip.MCompensate( fullSuper, bVec1, thSCD1=ThSCD1,thSCD2=ThSCD2, planar=true ) ) : \
  502.                                         Interleave( fullClip.MCompensate( fullSuper, fVec2, thSCD1=ThSCD1,thSCD2=ThSCD2, planar=true ), \
  503.                                                     fullClip.MCompensate( fullSuper, fVec1, thSCD1=ThSCD1,thSCD2=ThSCD2, planar=true ), \
  504.                                                     fullClip, \
  505.                                                     fullClip.MCompensate( fullSuper, bVec1, thSCD1=ThSCD1,thSCD2=ThSCD2, planar=true ), \
  506.                                                     fullClip.MCompensate( fullSuper, bVec2, thSCD1=ThSCD1,thSCD2=ThSCD2, planar=true ) )
  507.     noiseWindow = yuy2 && (Denoiser == "KNLMeansCL") ? NoiseTR > 0 ? noiseWindow.planar2interleaved().ConvertToYV16() : noiseWindow.ConvertToYV16() : (yuy2 && NoiseTR > 0) ? noiseWindow.planar2interleaved() : noiseWindow
  508.     dnWindow = (NoiseProcess == 0)      ? NOP() : \
  509.                (Denoiser == "dfttest")  ? noiseWindow.dfttest( Y=true, U=ChromaNoise, V=ChromaNoise, sigma=Sigma*4, tbsize=noiseTD, threads=DftThreads, lsb=lsbd ) : \
  510.             (Denoiser == "KNLMeansCL")  ? KNLMeansCL( lsbd ? noiseWindow.Dither_convert_8_to_16() : noiseWindow, d=NoiseTR, h=Sigma, lsb_inout=lsbd, device_type="GPU") : \
  511.                                           noiseWindow.FFT3DFilter( plane=(ChromaNoise ? 4 : 0), sigma=Sigma, bt=noiseTD )
  512.     dnwindow =    (Denoiser == "dfttest") && (NoiseProcess != 0) && lsbd ? yuy2 ? dnWindow.ConvertToYV16().ditherpost(mode=6, U=ChromaNoise?3:2, V=ChromaNoise?3:2, slice=false).ConvertToYUY2() : dnWindow.ditherpost(mode=6, U=ChromaNoise?3:2, V=ChromaNoise?3:2, slice=false) : dnWindow
  513.     dnwindow = (Denoiser == "KNLMeansCL") && (NoiseProcess != 0) ? lsbd ? yuy2 ? dnWindow.ditherpost(mode=6, U=ChromaNoise?3:2, V=ChromaNoise?3:2, slice=false).ConvertToYUY2()                    : dnWindow.ditherpost(mode=6, U=ChromaNoise?3:2, V=ChromaNoise?3:2, slice=false) : yuy2 ? dnWindow.ConvertToYUY2() : dnWindow : dnWindow
  514.     # Rework denoised clip to match source format - various code paths here: discard the motion compensation window, discard doubled lines (from point resize)
  515.     # Also reweave to get interlaced noise if source was interlaced (could keep the full frame of noise, but it will be poor quality from the point resize)
  516.     denoised = (NoiseProcess == 0) ? NOP() : \
  517.                (!DenoiseMC)        ? ((InputType > 0) ? dnWindow : dnWindow.SeparateFields().SelectEvery( 4, 0,3 ).Weave()) : \
  518.                (InputType > 0)     ? ((NoiseTR == 0)  ? dnWindow : dnWindow.SelectEvery( noiseTD, NoiseTR )) : \
  519.                                      dnWindow.SeparateFields().SelectEvery( noiseTD*4, NoiseTR*2,NoiseTR*6+3 ).Weave()
  520.  
  521.     # >>>> Switch to planar YUY2 for noise bypass
  522.  
  523.     CNmt1   = ChromaNoise ? 3 : 1
  524.     CNmt2   = ChromaNoise ? 3 : 2
  525.     CNmt128 = ChromaNoise ? 3 : -128
  526.  
  527.     # Get actual noise from difference. Then 'deinterlace' where we have weaved noise - create the missing lines of noise in various ways
  528.     noise = (totalRestore > 0.0)  ? yuy2 ? mt_makediff( clip.ConvertToYV16(), denoised.ConvertToYV16(), U=CNmt1,V=CNmt1 ).ConvertToYUY2().interleaved2planar() : \
  529.     mt_makediff( Clip, denoised, U=CNmt1,V=CNmt1 ) : NOP()
  530.     deintNoise = (NoiseProcess == 0 || totalRestore == 0.0) ? NOP() : \
  531.                  (InputType != 0)                           ? noise : \
  532.                  (NoiseDeint == "Bob")                      ? noise.QTGMC_Bob( 0,0.5 ) : \
  533.                  (NoiseDeint == "Generate")                 ? noise.QTGMC_Generate2ndFieldNoise( denoised, ChromaNoise ) : \
  534.                                                               noise.DoubleWeave()
  535.     # Motion-compensated stabilization of generated noise
  536.     noiseSuper = (StabilizeNoise) ? deintNoise.MSuper( pel=SubPel, sharp=SubPelInterp, levels=1, hpad=hpad, vpad=vpad, chroma=ChromaNoise, planar=true ) : NOP()
  537.     mcNoise    = (StabilizeNoise) ? deintNoise.MCompensate( noiseSuper, bVec1, thSCD1=ThSCD1,thSCD2=ThSCD2, planar=true ) : NOP()
  538.     finalNoise = (StabilizeNoise) ? yuy2 ? mt_lutxy( deintNoise.planar2interleaved().ConvertToYV16(), mcNoise.planar2interleaved().ConvertToYV16(), \
  539.                             "x 128 - abs y 128 - abs > x y ? 0.6 * x y + 0.2 * +", U=CNmt1,V=CNmt1 ).ConvertToYUY2().interleaved2planar() : \
  540.                            mt_lutxy( deintNoise, mcNoise, "x 128 - abs y 128 - abs > x y ? 0.6 * x y + 0.2 * +", U=CNmt1,V=CNmt1 ) : deintNoise
  541.  
  542.     # If NoiseProcess=1 denoise input clip. If NoiseProcess=2 leave noise in the clip and let the temporal blurs "denoise" it for a stronger effect
  543.     innerClip = (NoiseProcess == 1) ? denoised : clip
  544.  
  545.  
  546.     #---------------------------------------
  547.     # Interpolation
  548.  
  549.     # >>>> Interleaved YUY2 for interpolation
  550.  
  551.     # Support badly deinterlaced progressive content - drop half the fields and reweave to get 1/2fps interlaced stream appropriate for QTGMC processing
  552.     ediInput = (InputType == 2 || InputType == 3) ? innerClip.SeparateFields().SelectEvery(4,0,3).Weave() : innerClip
  553.  
  554.     # Create interpolated image as starting point for output
  555.     edi1 = defined(EdiExt) ? EdiExt.PointResize( w,h, 0,(EdiExt.Height()-h)/2, -0,h+epsilon ) : \
  556.                              QTGMC_Interpolate( ediInput, InputType, EdiMode, NNSize, NNeurons, EdiQual, EdiMaxD, EdiThreads, \
  557.                                                 yuy2 ? bobbed.planar2interleaved() : bobbed, ChromaEdi )
  558.  
  559.     # >>>> Switch to planar YUY2 during next step - remains planar until very end of script except blurring for back blending & SVThin
  560.  
  561.     # InputType=2,3: use motion mask to blend luma between original clip & reweaved clip based on ProgSADMask setting. Use chroma from original clip in any case
  562.     inputTypeBlend = (ProgSADMask > 0.0) ? MMask( srchClip, bVec1, kind=1, ml=ProgSADMask, planar=true ) : NOP()
  563.     edi = (InputType != 2 && InputType != 3) ? (!yuy2 ? edi1 : edi1.interleaved2planar()) :\
  564.           (ProgSADMask <= 0.0)               ? (!yuy2 ? edi1.MergeChroma( innerClip ) : edi1.MergeChroma( innerClip ).interleaved2planar()) : \
  565.                                                (!yuy2 ? mt_merge( innerClip, edi1, inputTypeBlend, U=2,V=2 ) : \
  566.                                                         mt_merge( innerClip.ConvertToYV16(), edi1.ConvertToYV16(), inputTypeBlend.planar2interleaved().ConvertToYV16(), U=2,V=2 ).ConvertToYUY2().interleaved2planar())
  567.  
  568.     # Get the max/min value for each pixel over neighboring motion-compensated frames - used for temporal sharpness limiting
  569.     ediSuper = (TR1 > 0 || temporalSL)   ? edi.MSuper( pel=SubPel, sharp=SubPelInterp, levels=1, hpad=hpad, vpad=vpad, planar=true ) : NOP()
  570.     bComp1   = (temporalSL)              ? edi.MCompensate( ediSuper, bVec1, thSCD1=ThSCD1,thSCD2=ThSCD2, planar=true ) : NOP()
  571.     fComp1   = (temporalSL)              ? edi.MCompensate( ediSuper, fVec1, thSCD1=ThSCD1,thSCD2=ThSCD2, planar=true ) : NOP()
  572.     tMax     = (temporalSL)              ? yuy2 ? edi.planar2interleaved().ConvertToYV16().mt_logic( fComp1.planar2interleaved().ConvertToYV16(), "max", \
  573.     U=3,V=3 ).mt_logic( bComp1.planar2interleaved().ConvertToYV16(), "max", U=3,V=3 ).ConvertToYUY2().interleaved2planar() : edi.mt_logic( fComp1, "max", U=3,V=3 ).mt_logic( bComp1, "max", U=3,V=3 )    : NOP()
  574.     tMin     = (temporalSL)              ? yuy2 ? edi.planar2interleaved().ConvertToYV16().mt_logic( fComp1.planar2interleaved().ConvertToYV16(), "min", \
  575.     U=3,V=3 ).mt_logic( bComp1.planar2interleaved().ConvertToYV16(), "min", U=3,V=3 ).ConvertToYUY2().interleaved2planar() : edi.mt_logic( fComp1, "min", U=3,V=3 ).mt_logic( bComp1, "min", U=3,V=3 )    : NOP()
  576.     bComp3   = (SLRad > 1 && temporalSL) ? edi.MCompensate( ediSuper, bVec3, thSCD1=ThSCD1,thSCD2=ThSCD2, planar=true ) : NOP()
  577.     fComp3   = (SLRad > 1 && temporalSL) ? edi.MCompensate( ediSuper, fVec3, thSCD1=ThSCD1,thSCD2=ThSCD2, planar=true ) : NOP()
  578.     tMax     = (SLRad > 1 && temporalSL) ? yuy2 ? tMax.planar2interleaved().ConvertToYV16().mt_logic( fComp3.planar2interleaved().ConvertToYV16(), "max", \
  579.     U=3,V=3 ).mt_logic( bComp3.planar2interleaved().ConvertToYV16(), "max", U=3,V=3 ).ConvertToYUY2().interleaved2planar() : tMax.mt_logic( fComp3, "max", U=3,V=3 ).mt_logic( bComp3, "max", U=3,V=3 )   : tMax
  580.     tMin     = (SLRad > 1 && temporalSL) ? yuy2 ? tMin.planar2interleaved().ConvertToYV16().mt_logic( fComp3.planar2interleaved().ConvertToYV16(), "min", \
  581.     U=3,V=3 ).mt_logic( bComp3.planar2interleaved().ConvertToYV16(), "min", U=3,V=3 ).ConvertToYUY2().interleaved2planar() : tMin.mt_logic( fComp3, "min", U=3,V=3 ).mt_logic( bComp3, "min", U=3,V=3 )   : tMin
  582.  
  583.  
  584.     #---------------------------------------
  585.     # Create basic output
  586.  
  587.     # Use motion vectors to blur interpolated image (edi) with motion-compensated previous and next frames. As above, this is done to remove shimmer from
  588.     # alternate frames so the same binomial kernels are used. However, by using motion-compensated smoothing this time we avoid motion blur. The use of
  589.     # MDegrain1 (motion compensated) rather than TemporalSmooth makes the weightings *look* different, but they evaluate to the same values
  590.     # Create linear weightings of neighbors first                                                                                             -2    -1     0    1     2
  591.     degrain1 = (TR1 > 0) ? edi.MDegrain1( ediSuper, bVec1,fVec1, thSAD=ThSAD1, thSCD1=ThSCD1,thSCD2=ThSCD2, planar=true, lsb=lsb) : NOP()  # 0.00  0.33  0.33  0.33  0.00
  592.     degrain2 = (TR1 > 1) ? edi.MDegrain1( ediSuper, bVec2,fVec2, thSAD=ThSAD1, thSCD1=ThSCD1,thSCD2=ThSCD2, planar=true, lsb=lsb) : NOP()  # 0.33  0.00  0.33  0.00  0.33
  593.     degrain1 = (TR1 > 0) && lsb ? yuy2 ? degrain1.planar2interleaved().ConvertToYV16().ditherpost(mode=6, slice=false).ConvertToYUY2().interleaved2planar() : degrain1.ditherpost(mode=6, slice=false) : degrain1
  594.     degrain2 = (TR1 > 1) && lsb ? yuy2 ? degrain2.planar2interleaved().ConvertToYV16().ditherpost(mode=6, slice=false).ConvertToYUY2().interleaved2planar() : degrain2.ditherpost(mode=6, slice=false) : degrain2
  595.  
  596.     # Combine linear weightings to give binomial weightings - TR1=0: (1), TR1=1: (1:2:1), TR1=2: (1:4:6:4:1)
  597.     binomial1 = (TR1 == 0) ? edi : \
  598.                 (TR1 == 1) ? degrain1.Merge( edi, 0.25 ) : \
  599.                              degrain1.Merge( degrain2, 0.2 ).Merge( edi, 0.0625 )
  600.  
  601.     # Remove areas of difference between smoothed image and interpolated image that are not bob-shimmer fixes: repairs residual motion blur from temporal smooth
  602.     repair1 = (Rep1 == 0) ? binomial1 : binomial1.QTGMC_KeepOnlyBobShimmerFixes( edi, Rep1, RepChroma )
  603.  
  604.     # Apply source match - use difference between output and source to succesively refine output [extracted to function to clarify main code path]
  605.     match = (SourceMatch == 0) ? repair1 : \
  606.                                  repair1.QTGMC_ApplySourceMatch( InputType, ediInput, bVec1,fVec1, bVec2,fVec2, SubPel, SubPelInterp, hpad, vpad, \
  607.                                                                  ThSAD1, ThSCD1, ThSCD2, SourceMatch, MatchTR1, MatchEdi, MatchNNSize, MatchNNeurons, \
  608.                                                                  MatchEdiQual, MatchEdiMaxD, MatchTR2, MatchEdi2, MatchNNSize2, MatchNNeurons2, MatchEdiQual2, \
  609.                                                                  MatchEdiMaxD2, MatchEnhance, EdiThreads, lsb )
  610.  
  611.     # Lossless=2 - after preparing an interpolated, de-shimmered clip, restore the original source fields into it and clean up any artefacts.
  612.     # This mode will not give a true lossless result because the resharpening and final temporal smooth are still to come, but it will add further detail.
  613.     # However, it can introduce minor combing. This setting is best used together with source-match (it's effectively the final source-match stage).
  614.     lossed1 = (Lossless == 2) ? QTGMC_MakeLossless( match, innerClip, InputType ) : match
  615.  
  616.  
  617.     #---------------------------------------
  618.     # Resharpen / retouch output
  619.  
  620.     # Resharpen to counteract temporal blurs. Little sharpening needed for source-match mode since it has already recovered sharpness from source
  621.     vresharp1 = (SMode == 2) ? yuy2 ? Merge( lossed1.planar2interleaved().ConvertToYV16().mt_expand( mode="vertical", U=3,V=3 ), \
  622.     lossed1.planar2interleaved().ConvertToYV16().mt_inpand( mode="vertical", U=3,V=3 ) ).ConvertToYUY2().interleaved2planar() : \
  623.     Merge( lossed1.mt_expand( mode="vertical", U=3,V=3 ), lossed1.mt_inpand( mode="vertical", U=3,V=3 ) ) : NOP()
  624.     vresharp  = (Precise && SMode == 2) ? yuy2 ? vresharp1.planar2interleaved().ConvertToYV16().mt_lutxy( lossed1.planar2interleaved().ConvertToYV16(), \
  625.     "x y < x 1 + x y > x 1 - x ? ?", U=3,V=3 ).ConvertToYUY2().interleaved2planar() : vresharp1.mt_lutxy( lossed1, "x y < x 1 + x y > x 1 - x ? ?", U=3,V=3 ) : vresharp1 # Precise mode: reduce tiny overshoot
  626.     resharp   = (SMode == 0) ? lossed1 : \
  627.                 (SMode == 1) ? yuy2 ? lossed1.planar2interleaved().ConvertToYV16().mt_lutxy( lossed1.RemoveGrain( rgBlur, planar=true ).planar2interleaved().ConvertToYV16(),  \
  628.     "x x y - "+ string(sharpAdj) + " * +", U=3,V=3 ).ConvertToYUY2().interleaved2planar() : lossed1.mt_lutxy( lossed1.RemoveGrain( rgBlur, planar=true ),  "x x y - "+ string(sharpAdj) + " * +", U=3,V=3 ) : \
  629.                                yuy2 ? lossed1.planar2interleaved().ConvertToYV16().mt_lutxy( vresharp.RemoveGrain( rgBlur, planar=true ).planar2interleaved().ConvertToYV16(), \
  630.     "x x y - "+ string(sharpAdj) + " * +", U=3,V=3 ).ConvertToYUY2().interleaved2planar() : lossed1.mt_lutxy( vresharp.RemoveGrain( rgBlur, planar=true ), "x x y - "+ string(sharpAdj) + " * +", U=3,V=3 )
  631.  
  632.     # Slightly thin down 1-pixel high horizontal edges that have been widened into neigboring field lines by the interpolator
  633.     SVThinSc = SVThin * 6.0
  634.     vertMedD = (SVthin > 0.0) ? yuy2 ? mt_lutxy( lossed1.planar2interleaved().ConvertToYV16(), lossed1.VerticalCleaner( mode=1, modeU=-1, modeV=-1, planar=true ).planar2interleaved().ConvertToYV16(), \
  635.     "y x - " + string(SVThinSc) + " * 128 +", U=1,V=1 ).ConvertToYUY2().interleaved2planar() : mt_lutxy( lossed1, lossed1.VerticalCleaner( mode=1, modeU=-1, modeV=-1, planar=true ), "y x - " + string(SVThinSc) + " * 128 +", U=1,V=1 ) : NOP()
  636.     vertMedD = (SVthin > 0.0) ? (!yuy2 ? vertMedD.Blur( 1,0 ) : vertMedD.planar2interleaved().Blur( 1,0 ).interleaved2planar()) : NOP()
  637.     neighborD = (SVthin > 0.0) ? yuy2 ? mt_lutxy( vertMedD.planar2interleaved().ConvertToYV16(), vertMedD.RemoveGrain( rgBlur,-1, planar=true ).planar2interleaved().ConvertToYV16(), \
  638.     "y 128 - abs x 128 - abs > y 128 ?" ).ConvertToYUY2().interleaved2planar() : mt_lutxy( vertMedD, vertMedD.RemoveGrain( rgBlur,-1, planar=true ), "y 128 - abs x 128 - abs > y 128 ?" ) : NOP()
  639.     thin      = (SVthin > 0.0) ? yuy2 ? resharp.planar2interleaved().ConvertToYV16().mt_adddiff( neighborD.planar2interleaved().ConvertToYV16(), U=2,V=2 ).ConvertToYUY2().interleaved2planar() : resharp.mt_adddiff( neighborD, U=2,V=2 ) : resharp
  640.  
  641.     # Back blend the blurred difference between sharpened & unsharpened clip, before (1st) sharpness limiting (Sbb == 1,3). A small fidelity improvement
  642.     backBlend1 = (Sbb != 1 && Sbb != 3) ? thin : \
  643.                  !yuy2 ? thin.mt_makediff( mt_makediff( thin, lossed1, U=1,V=1 ).RemoveGrain( 12, -1, planar=true ) \
  644.                              .GaussResize( w,h, 0,0, w+epsilon,h+epsilon, p=5 ), U=2,V=2 ) : \
  645.                          thin.planar2interleaved().ConvertToYV16().mt_makediff( mt_makediff( thin.planar2interleaved().ConvertToYV16(), lossed1.planar2interleaved().ConvertToYV16(), U=1,V=1 ).ConvertToYUY2().interleaved2planar().RemoveGrain( 12, -1, planar=true ) \
  646.                              .planar2interleaved().GaussResize( w,h, 0,0, w+epsilon,h+epsilon, p=5 ).ConvertToYV16(), U=2,V=2 ).ConvertToYUY2().interleaved2planar()
  647.  
  648.     # Limit over-sharpening by clamping to neighboring (spatial or temporal) min/max values in original
  649.     # Occurs here (before final temporal smooth) if SLMode == 1,2. This location will restrict sharpness more, but any artefacts introduced will be smoothed
  650.     sharpLimit1 = (SLMode == 1) ? backBlend1.Repair( ((SLrad <= 1) ? edi : backBlend1.Repair( edi, 12, planar=true )), 1, planar=true ) : \
  651.                   (SLMode == 2) ? yuy2 ? backBlend1.planar2interleaved().ConvertToYV16().mt_clamp( tMax.planar2interleaved().ConvertToYV16(),tMin.planar2interleaved().ConvertToYV16(), Sovs,Sovs, U=3,V=3 ).ConvertToYUY2().interleaved2planar() : backBlend1.mt_clamp( tMax,tMin, Sovs,Sovs, U=3,V=3 ) : \
  652.                                   backBlend1
  653.  
  654.     # Back blend the blurred difference between sharpened & unsharpened clip, after (1st) sharpness limiting (Sbb == 2,3). A small fidelity improvement
  655.     backBlend2 = (Sbb < 2) ? sharpLimit1 : \
  656.                  !yuy2     ? sharpLimit1.mt_makediff( mt_makediff( sharpLimit1, lossed1, U=1,V=1 ).RemoveGrain( 12, -1, planar=true ) \
  657.                                         .GaussResize( w,h, 0,0, w+epsilon,h+epsilon, p=5 ), U=2,V=2 ) : \
  658.                              sharpLimit1.planar2interleaved().ConvertToYV16().mt_makediff( mt_makediff( sharpLimit1.planar2interleaved().ConvertToYV16(), lossed1.planar2interleaved().ConvertToYV16(), U=1,V=1 ).ConvertToYUY2().interleaved2planar().RemoveGrain( 12, -1, planar=true ) \
  659.                                         .planar2interleaved().GaussResize( w,h, 0,0, w+epsilon,h+epsilon, p=5 ).ConvertToYV16(), U=2,V=2 ).ConvertToYUY2().interleaved2planar()
  660.  
  661.     # Add back any extracted noise, prior to final temporal smooth - this will restore detail that was removed as "noise" without restoring the noise itself
  662.     # Average luma of FFT3DFilter extracted noise is 128.5, so deal with that too
  663.     addNoise1 = (GrainRestore <= 0.0) ? backBlend2 : \
  664.         yuy2 ? backBlend2.planar2interleaved().ConvertToYV16().mt_adddiff( finalNoise.planar2interleaved().ConvertToYV16().mt_lut( "x " + noiseCentre + " - " + string(GrainRestore) + " * 128 +", U=CNmt1,V=CNmt1 ), U=CNmt2,V=CNmt2 ).ConvertToYUY2().interleaved2planar() : \
  665.         backBlend2.mt_adddiff( finalNoise.mt_lut( "x " + noiseCentre + " - " + string(GrainRestore) + " * 128 +", U=CNmt1,V=CNmt1 ), U=CNmt2,V=CNmt2 )
  666.  
  667.     # Final light linear temporal smooth for denoising
  668.     stableSuper = (TR2 > 0) ? addNoise1.MSuper( pel=SubPel, sharp=SubPelInterp, levels=1, hpad=hpad, vpad=vpad, planar=true ) : NOP()
  669.     stable  = (TR2 == 0) ? addNoise1 : \
  670.               (TR2 == 1) ? addNoise1.MDegrain1( stableSuper, bVec1,fVec1,                           thSAD=ThSAD2, thSCD1=ThSCD1,thSCD2=ThSCD2, planar=true, lsb=lsb ) : \
  671.               (TR2 == 2) ? addNoise1.MDegrain2( stableSuper, bVec1,fVec1, bVec2,fVec2,              thSAD=ThSAD2, thSCD1=ThSCD1,thSCD2=ThSCD2, planar=true, lsb=lsb ) : \
  672.                            addNoise1.MDegrain3( stableSuper, bVec1,fVec1, bVec2,fVec2, bVec3,fVec3, thSAD=ThSAD2, thSCD1=ThSCD1,thSCD2=ThSCD2, planar=true, lsb=lsb )
  673.     stable  = (TR2 > 0) && lsb ? yuy2 ? stable.planar2interleaved().ConvertToYV16().ditherpost(mode=6, slice=false).ConvertToYUY2().interleaved2planar() : stable.ditherpost(mode=6, slice=false) : stable
  674.  
  675.     # Remove areas of difference between final output & basic interpolated image that are not bob-shimmer fixes: repairs motion blur caused by temporal smooth
  676.     repair2 = (Rep2 == 0) ? stable : stable.QTGMC_KeepOnlyBobShimmerFixes( edi, Rep2, RepChroma )
  677.  
  678.     # Limit over-sharpening by clamping to neighboring (spatial or temporal) min/max values in original
  679.     # Occurs here (after final temporal smooth) if SLMode == 3,4. Allows more sharpening here, but more prone to introducing minor artefacts
  680.     sharpLimit2 = (SLMode == 3) ? repair2.Repair( ((SLrad <= 1) ? edi : repair2.Repair( edi, 12, planar=true )), 1, planar=true ) : \
  681.                   (SLMode == 4) ? yuy2 ? repair2.planar2interleaved().ConvertToYV16().mt_clamp( tMax.planar2interleaved().ConvertToYV16(),tMin.planar2interleaved().ConvertToYV16(), Sovs,Sovs, U=3,V=3 ).ConvertToYUY2().interleaved2planar() : repair2.mt_clamp( tMax,tMin, Sovs,Sovs, U=3,V=3 ) : \
  682.                                   repair2
  683.  
  684.     # Lossless=1 - inject source fields into result and clean up inevitable artefacts. Provided NoiseRestore=0.0 or 1.0, this mode will make the script result
  685.     # properly lossless, but this will retain source artefacts and cause some combing (where the smoothed deinterlace doesn't quite match the source)
  686.     lossed2 = (Lossless == 1) ? QTGMC_MakeLossless( sharpLimit2, innerClip, InputType ) : sharpLimit2
  687.  
  688.     # Add back any extracted noise, after final temporal smooth. This will appear as noise/grain in the output
  689.     # Average luma of FFT3DFilter extracted noise is 128.5, so deal with that too
  690.     addNoise2 = (NoiseRestore <= 0.0) ? lossed2 : \
  691.         yuy2 ? lossed2.planar2interleaved().ConvertToYV16().mt_adddiff( finalNoise.planar2interleaved().ConvertToYV16().mt_lut( "x " + noiseCentre + " - " + string(NoiseRestore) + " * 128 +", U=CNmt1,V=CNmt1 ), U=CNmt2,V=CNmt2 ).ConvertToYUY2().interleaved2planar() : \
  692.         lossed2.mt_adddiff( finalNoise.mt_lut( "x " + noiseCentre + " - " + string(NoiseRestore) + " * 128 +", U=CNmt1,V=CNmt1 ), U=CNmt2,V=CNmt2 )
  693.  
  694.  
  695.     #---------------------------------------
  696.     # Post-Processing
  697.  
  698.     # Shutter motion blur - get level of blur depending on output framerate and blur already in source
  699.     blurLevel = (ShutterAngleOut * FPSDivisor - ShutterAngleSrc) * 100.0 / 360.0
  700.     Assert( blurLevel >= 0, "Cannot reduce motion blur already in source: increase ShutterAngleOut or FPSDivisor" )
  701.     Assert( blurLevel <= 200, "Exceeded maximum motion blur level: decrease ShutterAngleOut or FPSDivisor" )
  702.  
  703.     # ShutterBlur mode 2,3 - get finer resolution motion vectors to reduce blur "bleeding" into static areas
  704.     rBlockDivide = Select( ShutterBlur, 1, 1, 2, 4 )
  705.     rBlockSize = BlockSize / rBlockDivide
  706.     rOverlap   = Overlap   / rBlockDivide
  707.     rBlockSize = (rBlockSize < 4) ? 4 : rBlockSize
  708.     rOverlap   = (rOverlap   < 2) ? 2 : rOverlap
  709.     rBlockDivide = BlockSize / rBlockSize
  710.     rLambda = Lambda / (rBlockDivide * rBlockDivide)
  711.     sbBVec1 = (ShutterBlur > 1) ? srchSuper.MRecalculate( bVec1, thSAD=ThSAD1, blksize=rBlockSize, overlap=rOverlap, search=Search, searchparam=SearchParam, \
  712.                                                           truemotion=TrueMotion, lambda=Lambda, pnew=PNew, DCT=DCT, chroma=ChromaMotion ) : bVec1
  713.     sbFVec1 = (ShutterBlur > 1) ? srchSuper.MRecalculate( fVec1, thSAD=ThSAD1, blksize=rBlockSize, overlap=rOverlap, search=Search, searchparam=SearchParam, \
  714.                                                           truemotion=TrueMotion, lambda=Lambda, pnew=PNew, DCT=DCT, chroma=ChromaMotion ) : fVec1
  715.  
  716.     # Shutter motion blur - use MFlowBlur to blur along motion vectors
  717.     sblurSuper = (ShutterBlur > 0) ? addNoise2.MSuper( pel=SubPel, sharp=SubPelInterp, levels=1, hpad=hpad, vpad=vpad, planar=true ) : NOP()
  718.     sblur =      (ShutterBlur > 0) ? addNoise2.MFlowBlur( sblurSuper, sbBVec1, sbFVec1, blur=blurLevel, thSCD1=ThSCD1,thSCD2=ThSCD2, planar=true ) : NOP()
  719.  
  720.     # Shutter motion blur - use motion mask to reduce blurring in areas of low motion - also helps reduce blur "bleeding" into static areas, then select blur type
  721.     sbMotionMask = (ShutterBlur > 0 && SBlurLimit > 0) ? MMask( srchClip, bVec1, kind=0, ml=SBlurLimit, planar=true ) : NOP()
  722.     sblurred     = (ShutterBlur == 0) ? addNoise2 : \
  723.                    (SBlurLimit == 0)  ? sblur : \
  724.                                         yuy2 ? mt_merge( addNoise2.planar2interleaved().ConvertToYV16(), sblur.planar2interleaved().ConvertToYV16(), sbMotionMask.planar2interleaved().ConvertToYV16(), U=3,V=3 ).ConvertToYUY2().interleaved2planar() : \
  725.                                         mt_merge( addNoise2, sblur, sbMotionMask, U=3,V=3 )
  726.     # Reduce frame rate
  727.     decimated = (FPSDivisor != 1) ? sblurred.SelectEvery( FPSDivisor, 0 ) : sblurred
  728.  
  729.     # Crop off temporary vertical padding
  730.     cropped = Border ? decimated.Crop( 0, 4, -0, -4 ) : decimated
  731.     h = Border ? h-8 : h
  732.  
  733.     # Show output of choice + settings
  734.     # >>>> Restore YUY2 to interleaved
  735.     output = (ShowNoise == 0.0) ? cropped : yuy2 ? finalNoise.planar2interleaved().ConvertToYV16().mt_lut( "x 128 - " + string(ShowNoise) + " * 128 +", U=CNmt128,V=CNmt128 ).ConvertToYUY2().interleaved2planar() : \
  736.     finalNoise.mt_lut( "x 128 - " + string(ShowNoise) + " * 128 +", U=CNmt128,V=CNmt128 )
  737.     output = yuy2 ? output.planar2interleaved() : output
  738.     return (ShowSettings == false) ? output : \
  739.         output.Subtitle( "TR0=" + string(TR0) + " | TR1=" + string(TR1) + " | TR2=" + string(TR2) + " | Rep0=" + string(Rep0) + " | Rep1=" + string(Rep1) + \
  740.         " | Rep2=" + string(Rep2) + " | RepChroma=" + string(RepChroma) + "\nEdiMode='" + EdiMode + "' | NNSize=" + string(NNSize) + " | NNeurons=" + \
  741.         string(NNeurons) + " | EdiQual=" + string(EdiQual) + " | EdiMaxD=" + string(EdiMaxD) + " | ChromaEdi='" + ChromaEdi + "' | EdiThreads=" + \
  742.         string(EdiThreads) + "\nSharpness=" + string(Sharpness, "%.2f") + " | SMode=" + string(SMode) + " | SLMode=" + string(SLMode) + " | SLRad=" + \
  743.         string(SLRad) + " | SOvs=" + string(SOvs) + " | SVThin=" + string(SVThin, "%.2f") + " | Sbb=" + string(Sbb) + "\nSrchClipPP=" + string(SrchClipPP) + \
  744.         " | SubPel=" + string(SubPel) + " | SubPelInterp=" + string(SubPelInterp) + " | BlockSize=" + string(BlockSize) + " | Overlap=" + string(Overlap) + \
  745.         "\nSearch=" + string(Search) + " | SearchParam=" + string(SearchParam) + " | PelSearch=" + string(PelSearch) + " | ChromaMotion=" + \
  746.         string(ChromaMotion) + " | TrueMotion=" + string(TrueMotion) + "\nLambda=" + string(Lambda) + " | LSAD=" + string(LSAD) + " | PNew=" + string(PNew) + \
  747.         " | PLevel=" + string(PLevel) + " | GlobalMotion=" + string(GlobalMotion) + " | DCT=" + string(DCT) + "\nThSAD1=" + string(ThSAD1) + " | ThSAD2=" + \
  748.         string(ThSAD2) + " | ThSCD1=" + string(ThSCD1) + " | ThSCD2=" + string(ThSCD2) + "\nSourceMatch=" + string(SourceMatch) + " | MatchPreset='" + \
  749.         MatchPreset + "' | MatchEdi='" + MatchEdi + "'\nMatchPreset2='" + MatchPreset2 + "' | MatchEdi2='" + MatchEdi2 + "' | MatchTR2=" + string(MatchTR2) + \
  750.         " | MatchEnhance=" + string(MatchEnhance, "%.2f") + " | Lossless=" + string(Lossless) + "\nNoiseProcess=" + string(NoiseProcess) + " | Denoiser='" + \
  751.         Denoiser + "' | DftThreads=" + string(DftThreads) + " | DenoiseMC=" + string(DenoiseMC) + " | NoiseTR=" + string(NoiseTR) + " | Sigma=" + \
  752.         string(Sigma, "%.2f") + "\nChromaNoise=" + string(ChromaNoise) + " | ShowNoise=" + string(ShowNoise, "%.2f") + " | GrainRestore=" + \
  753.         string(GrainRestore, "%.2f") + " | NoiseRestore=" + string(NoiseRestore, "%.2f") + "\nNoiseDeint='" + NoiseDeint + "' | StabilizeNoise=" + \
  754.         string(StabilizeNoise) + " | InputType=" + string(InputType) + " | ProgSADMask=" + string(ProgSADMask, "%.2f") + "\nFPSDivisor=" + \
  755.         string(FPSDivisor) + " | ShutterBlur=" + string(ShutterBlur) + " | ShutterAngleSrc=" + string(ShutterAngleSrc, "%.2f") + " | ShutterAngleOut=" + \
  756.         string(ShutterAngleOut, "%.2f") + " | SBlurLimit=" + string(SBlurLimit) + "\nBorder=" + string(Border) + " | Precise=" + string(Precise) + \
  757.         "\nPreset='" + Preset + "' | Tuning='" + Tuning + "' | GlobalNames='" + GlobalNames + "' | PrevGlobals='" + PrevGlobals + "' | ForceTR=" + \
  758.         string(ForceTR), font="Lucida Console", size=11, lsp=12 )
  759. }
  760.  
  761.  
  762. #---------------------------------------
  763. # Helpers
  764.  
  765. # Same as Bob, but keeps the field order the same.
  766. function QTGMC_Bob(clip cp, float "b", float "c", int "height" )
  767. {
  768.   h = Default(height, cp.Height)
  769.   w = cp.Width
  770.   shift = GetParity(cp) ? 0.25 : -0.25
  771.  
  772.   yv12c = IsYV12(cp) ? true : false
  773.  
  774.   yv12c ? cp.SeparateFields() : nop()
  775.  
  776.   oeven=yv12c ? SelectEven() : nop()
  777.   oodd=yv12c ? SelectOdd() : nop()
  778.  
  779.   even=yv12c ? oeven.ConvertToY8.BicubicResize(w, h, b, c, 0, shift, w, Height()).AssumeFrameBased() : nop()
  780.   odd=yv12c ? oodd.ConvertToY8.BicubicResize(w, h, b, c, 0, -shift, w, Height()).AssumeFrameBased() : nop()
  781.  
  782.   evenChr=yv12c ? Interleave(oeven.UToY8, oeven.VToY8).BicubicResize(w/2, h/2, b, c, 0, shift, w/2, Height()/2).AssumeFrameBased() : nop()
  783.   oddChr=yv12c ? Interleave(oodd.UToY8, oodd.VToY8).BicubicResize(w/2, h/2, b, c, 0, -shift, w/2, Height()/2).AssumeFrameBased() : nop()
  784.  
  785.   yv12c ? YToUV(Interleave(evenChr.SelectEven(), oddChr.SelectEven()),Interleave(evenChr.SelectOdd(), oddChr.SelectOdd()),Interleave(even, odd)) : cp.Bob( b,c, h )
  786.   GetParity(cp) ? AssumeTFF() : AssumeBFF()
  787. }
  788.  
  789.  
  790. # Interpolate input clip using method given in EdiMode. Use Fallback or Bob as result if mode not in list. If ChromaEdi string if set then interpolate chroma
  791. # separately with that method (only really useful for EEDIx). The function is used as main algorithm starting point and for first two source-match stages
  792. function QTGMC_Interpolate( clip Input, int InputType, string EdiMode, int NNSize, int NNeurons, int EdiQual, int EdiMaxD, int EdiThreads, clip "Fallback", \
  793.                             string "ChromaEdi" )
  794. {
  795.     # >>>> YUY2 is interleaved here
  796.  
  797.     ChromaEdi = default( ChromaEdi, "" )
  798.     CEed = (ChromaEdi == "")
  799.  
  800.     interp = (InputType == 1)            ? Input : \
  801.              (EdiMode == "NNEDI3")       ? Input.NNEDI3( field=-2, nsize=NNSize, nns=NNeurons, qual=EdiQual, threads=EdiThreads, U=CEed,V=CEed ) : \
  802.              (EdiMode == "NNEDI2")       ? Input.NNEDI2( field=-2, nsize=NNeurons, qual=EdiQual, threads=EdiThreads, U=CEed,V=CEed ) : \
  803.              (EdiMode == "NNEDI")        ? Input.NNEDI( field=-2, U=CEed,V=CEed ) : \
  804.              (EdiMode == "EEDI3+NNEDI3") ? Input.EEDI3( field=-2, mdis=EdiMaxD, threads=EdiThreads, U=CEed,V=CEed, \
  805.                                                         sclip=Input.NNEDI3( field=-2, nsize=NNSize, nns=NNeurons, qual=EdiQual, threads=EdiThreads, U=CEed,V=CEed ) ) : \
  806.              (EdiMode == "EEDI3")        ? Input.EEDI3( field=-2, mdis=EdiMaxD, threads=EdiThreads, U=CEed,V=CEed ) : \
  807.              (EdiMode == "EEDI2")        ? Input.SeparateFields().EEDI2( field=-2, maxd=EdiMaxD ) : \
  808.              (EdiMode == "Yadif")        ? Input.Yadif( mode=3 ) : \
  809.              (EdiMode == "TDeint")       ? Input.TDeInt( mode=1 ) : \
  810.              (EdiMode == "RepYadif")     ? isyuy2(Input) ? Repair( Input.Yadif( mode=3 ).interleaved2planar(), default( Fallback, Input.QTGMC_Bob( 0,0.5 ) ).interleaved2planar(), 2, 0, Planar=true ).planar2interleaved() : \
  811.                                                    Repair( Input.Yadif( mode=3 ), default( Fallback, Input.QTGMC_Bob( 0,0.5 ) ), 2, 0 ) : \
  812.                                            default( Fallback, Input.QTGMC_Bob( 0,0.5 ) )
  813.  
  814.     interpuv = (InputType == 1)        ? NOP() : \
  815.                (ChromaEdi == "NNEDI3") ? Input.NNEDI3( field=-2, nsize=4, nns=0, qual=1, threads=EdiThreads, Y=false ) : \
  816.                (ChromaEdi == "Yadif")  ? Input.Yadif( mode=3 ) : \
  817.                (ChromaEdi == "Bob")    ? Input.QTGMC_Bob( 0,0.5 ) : \
  818.                                          NOP()
  819.  
  820.     return (!IsClip(interpuv)) ? interp : interp.MergeChroma( interpuv )
  821. }
  822.  
  823.  
  824. # Functions (from original TGMC) used instead of mt_xxflate with similar operation but a somewhat stronger result. Originally added for speed, they are
  825. # no longer faster due to improvements in masktools. Difference (visual and speed) is small so may be reverted in a later version.
  826. function QTGMC_inflate( clip c, int "Y", int "U", int "V" )
  827. {
  828.     # >>>> YUY2 is planar here
  829.     mtY =default( Y, 3 )
  830.     mtU =default( U, 1 )
  831.     mtV =default( V, 1 )
  832.     rgY = (mtY == 3) ? 20 : -1
  833.     rgU = (mtU == 3) ? 20 : -1
  834.     rgV = (mtV == 3) ? 20 : -1
  835.     yuy2=Isyuy2(c)
  836.     rg  = c.RemoveGrain( rgY, rgU, rgV, planar=true )
  837.     c   = yuy2 ?  c.planar2interleaved().ConvertToYV16() : c
  838.     rg  = yuy2 ? rg.planar2interleaved().ConvertToYV16() : rg
  839.     yuy2 ? mt_logic( c, rg, "max", Y=mtY,U=mtU,V=mtV ).ConvertToYUY2().interleaved2planar() : mt_logic( c, rg, "max", Y=mtY,U=mtU,V=mtV )
  840. }
  841.  
  842. function QTGMC_deflate( clip c, int "Y", int "U", int "V" )
  843. {
  844.     # >>>> YUY2 is planar here
  845.     mtY =default( Y, 3 )
  846.     mtU =default( U, 1 )
  847.     mtV =default( V, 1 )
  848.     rgY = (mtY == 3) ? 20 : -1
  849.     rgU = (mtU == 3) ? 20 : -1
  850.     rgV = (mtV == 3) ? 20 : -1
  851.     yuy2=Isyuy2(c)
  852.     rg  = c.RemoveGrain( rgY, rgU, rgV, planar=true )
  853.     c   = yuy2 ?  c.planar2interleaved().ConvertToYV16() : c
  854.     rg  = yuy2 ? rg.planar2interleaved().ConvertToYV16() : rg
  855.     yuy2 ? mt_logic( c, rg, "min", Y=mtY,U=mtU,V=mtV ).ConvertToYUY2().interleaved2planar() : mt_logic( c, rg, "min", Y=mtY,U=mtU,V=mtV )
  856. }
  857.  
  858. # Helper function: Compare processed clip with reference clip: only allow thin, horizontal areas of difference, i.e. bob shimmer fixes
  859. # Rough algorithm: Get difference, deflate vertically by a couple of pixels or so, then inflate again. Thin regions will be removed
  860. #                  by this process. Restore remaining areas of difference back to as they were in reference clip.
  861. function QTGMC_KeepOnlyBobShimmerFixes( clip Input, clip Ref, int Rep, bool Chroma )
  862. {
  863.     # >>>> YUY2 is planar here
  864.  
  865.     # ed is the erosion distance - how much to deflate then reflate to remove thin areas of interest: 0 = minimum to 6 = maximum
  866.     # od is over-dilation level  - extra inflation to ensure areas to restore back are fully caught:  0 = none to 3 = one full pixel
  867.     # If Rep < 10, then ed = Rep and od = 0, otherwise ed = 10s digit and od = 1s digit (nasty method, but kept for compatibility with original TGMC)
  868.     Rep    = default( Rep,    1    )
  869.     Chroma = default( Chroma, true )
  870.     ed = (Rep < 10) ? Rep : Rep / 10
  871.     od = (Rep < 10) ? 0   : Rep % 10
  872.     RCrg  = Chroma ? 3 : 1
  873.     RCrgo = Chroma ? 3 : 2
  874.  
  875.     diff = mt_makediff(Isyuy2(Input) ? Ref.planar2interleaved().ConvertToYV16() : Ref, Isyuy2(Input) ? Input.planar2interleaved().ConvertToYV16() : Input, U=3,V=3 )
  876.  
  877.     # Areas of positive difference                                                                # ed = 0 1 2 3 4 5 6 7
  878.     choke1 =                        diff.  mt_inpand( mode="vertical", U=RCrg,V=RCrg )            #      x x x x x x x x    1 pixel   \
  879.     choke1 = (ed > 2)             ? choke1.mt_inpand( mode="vertical", U=RCrg,V=RCrg ) : choke1   #      . . . x x x x x    1 pixel    |  Deflate to remove thin areas
  880.     choke1 = (ed > 5)             ? choke1.mt_inpand( mode="vertical", U=RCrg,V=RCrg ) : choke1   #      . . . . . . x x    1 pixel   /
  881.     choke1 = Isyv16(choke1) && Isyuy2(Input) ? choke1.ConvertToYUY2().interleaved2planar() : choke1
  882.     choke1 = (ed % 3 != 0)        ? choke1.QTGMC_deflate( U=RCrg,V=RCrg )              : choke1   #      . x x . x x . x    A bit more deflate & some horizonal effect
  883.     choke1 = (ed == 2 || ed == 5) ? choke1.RemoveGrain( 4, planar=true )               : choke1   #      . . x . . x . .    Local median
  884.                                                                                                                      
  885.     choke1 = Isyuy2(choke1) ? choke1.planar2interleaved().ConvertToYV16() : choke1
  886.     choke1 =                        choke1.mt_expand( mode="vertical", U=RCrg,V=RCrg )            #      x x x x x x x x    1 pixel  \
  887.     choke1 = (ed > 1)             ? choke1.mt_expand( mode="vertical", U=RCrg,V=RCrg ) : choke1   #      . . x x x x x x    1 pixel   | Reflate again
  888.     choke1 = (ed > 4)             ? choke1.mt_expand( mode="vertical", U=RCrg,V=RCrg ) : choke1   #      . . . . . x x x    1 pixel  /
  889.  
  890.     # Over-dilation - extra reflation up to about 1 pixel
  891.     choke1 = (od == 0)            ? choke1 : \
  892.              (od == 1)            ? Isyv16(choke1) && Isyuy2(Input) ? choke1.ConvertToYUY2().interleaved2planar().QTGMC_inflate( U=RCrg,V=RCrg ).planar2interleaved().ConvertToYV16() : choke1.QTGMC_inflate( U=RCrg,V=RCrg ) : \
  893.              (od == 2)            ? Isyv16(choke1) && Isyuy2(Input) ? choke1.ConvertToYUY2().interleaved2planar().QTGMC_inflate( U=RCrg,V=RCrg ).QTGMC_inflate( U=RCrg,V=RCrg ).planar2interleaved().ConvertToYV16() : choke1.QTGMC_inflate( U=RCrg,V=RCrg ).QTGMC_inflate( U=RCrg,V=RCrg ) : \
  894.                                     choke1.mt_expand ( U=RCrg,V=RCrg )
  895.  
  896.     # Areas of negative difference (similar to above)
  897.     choke2 =                        diff.  mt_expand( mode="vertical", U=RCrg,V=RCrg )        
  898.     choke2 = (ed > 2)             ? choke2.mt_expand( mode="vertical", U=RCrg,V=RCrg ) : choke2
  899.     choke2 = (ed > 5)             ? choke2.mt_expand( mode="vertical", U=RCrg,V=RCrg ) : choke2
  900.     choke2 = Isyv16(choke2) && Isyuy2(Input) ? choke2.ConvertToYUY2().interleaved2planar() : choke2
  901.     choke2 = (ed % 3 != 0)        ? choke2.QTGMC_inflate( U=RCrg,V=RCrg )              : choke2
  902.     choke2 = (ed == 2 || ed == 5) ? choke2.RemoveGrain( 4, planar=true )               : choke2
  903.     choke2 = Isyuy2(choke2) ? choke2.planar2interleaved().ConvertToYV16() : choke2
  904.     choke2 =                        choke2.mt_inpand( mode="vertical", U=RCrg,V=RCrg )
  905.     choke2 = (ed > 1)             ? choke2.mt_inpand( mode="vertical", U=RCrg,V=RCrg ) : choke2
  906.     choke2 = (ed > 4)             ? choke2.mt_inpand( mode="vertical", U=RCrg,V=RCrg ) : choke2
  907.     choke2 = (od == 0)            ? choke2 : \
  908.              (od == 1)            ? Isyv16(choke2) && Isyuy2(Input) ? choke2.ConvertToYUY2().interleaved2planar().QTGMC_deflate( U=RCrg,V=RCrg ).planar2interleaved().ConvertToYV16() : choke2.QTGMC_deflate( U=RCrg,V=RCrg )  : \
  909.              (od == 2)            ? Isyv16(choke2) && Isyuy2(Input) ? choke2.ConvertToYUY2().interleaved2planar().QTGMC_deflate( U=RCrg,V=RCrg ).QTGMC_deflate( U=RCrg,V=RCrg ).planar2interleaved().ConvertToYV16() : choke2.QTGMC_deflate( U=RCrg,V=RCrg ).QTGMC_deflate( U=RCrg,V=RCrg ) : \
  910.                                     choke2.mt_inpand ( U=RCrg,V=RCrg )
  911.  
  912.     # Combine above areas to find those areas of difference to restore
  913.     restore = diff.mt_lutxy( choke1, "x 129 < x y 128 < 128 y ? ?", U=RCrg,V=RCrg ).mt_lutxy( choke2, "x 127 > x y 128 > 128 y ? ?", U=RCrg,V=RCrg )
  914.     fin4ret = Isyuy2(Input) ? Input.planar2interleaved().ConvertToYV16().mt_adddiff( restore, U=RCrgo,V=RCrgo ) : Input.mt_adddiff( restore, U=RCrgo,V=RCrgo )
  915.     return Isyuy2(Input) ? fin4ret.ConvertToYUY2().interleaved2planar() : fin4ret
  916. }
  917.  
  918.  
  919. # Given noise extracted from an interlaced source (i.e. the noise is interlaced), generate "progressive" noise with a new "field" of noise injected. The new
  920. # noise is centered on a weighted local average and uses the difference between local min & max as an estimate of local variance
  921. # YUY2 clip input is planar, but must pass interleaved version of clip to setup noise
  922. function QTGMC_Generate2ndFieldNoise( clip Input, clip InterleavedClip, bool "ChromaNoise" )
  923. {
  924.     # >>>> YUY2 is planar here. Noise is generated (AddGrainC) interleaved, but immediately made planar
  925.     ChromaNoise = default( ChromaNoise, false )
  926.     CNmt1 = ChromaNoise ? 3 : 1
  927.     origNoise = Input.SeparateFields()
  928.     origNoise = Isyuy2(Input) ? origNoise.planar2interleaved().ConvertToYV16() : origNoise
  929.     noiseMax  = origNoise.mt_expand( mode="square", U=CNmt1,V=CNmt1 ).mt_expand( mode="horizontal", U=CNmt1,V=CNmt1 )
  930.     noiseMin  = origNoise.mt_inpand( mode="square", U=CNmt1,V=CNmt1 ).mt_inpand( mode="horizontal", U=CNmt1,V=CNmt1 )
  931.     random    = BlankClip( InterleavedClip.SeparateFields(), color_yuv=$808080 ).AddGrainC( var=1800, uvar=ChromaNoise ? 1800 : 0 )
  932.     random    = InterleavedClip.IsYUY2() ? random.ConvertToYV16() : random
  933.     varRandom = mt_makediff( noiseMax, noiseMin, U=CNmt1,V=CNmt1 ).mt_lutxy( random, "x 128 - y * 256 / 128 +", U=CNmt1,V=CNmt1)
  934.     newNoise  = noiseMin.mt_adddiff( varRandom, U=CNmt1,V=CNmt1 )
  935.     return Isyuy2(Input) ? Interleave( origNoise, newNoise ).ConvertToYUY2().interleaved2planar().Weave() : Interleave( origNoise, newNoise ).Weave()
  936. }
  937.  
  938.  
  939. # Insert the source lines into the result to create a true lossless output. However, the other lines in the result have had considerable processing and won't
  940. # exactly match source lines. There will be some slight residual combing. Use vertical medians to clean a little of this away
  941. function QTGMC_MakeLossless( clip Input, clip Source, int InputType )
  942. {
  943.     Assert( InputType != 1, "Lossless modes are incompatible with InputType=1" )
  944.  
  945.     # >>>> YUY2: 'Input' is planar, 'Source' is interleaved (changed to planar here for processing) - returns planar result
  946.  
  947.     # Weave the source fields and the "new" fields that have generated in the input
  948.     srcFields1 = (InputType == 0) ? Source.SeparateFields() : Source.SeparateFields().SelectEvery( 4, 0,3 )
  949.     srcFields  = Source.IsYUY2() ? srcFields1.interleaved2planar() : srcFields1
  950.     newFields  = Input.SeparateFields().SelectEvery( 4, 1,2 )
  951.     processed  = Interleave( srcFields, newFields ).SelectEvery(4, 0,1,3,2 ).Weave()
  952.  
  953.     # Clean some of the artefacts caused by the above - creating a second version of the "new" fields
  954.     vertMedian  = processed.VerticalCleaner( mode=1, planar=true )
  955.     vertMedDiff = mt_makediff( Isyuy2(Source) ? processed.planar2interleaved().ConvertToYV16() : \
  956.     processed, Isyuy2(Source) ? vertMedian.planar2interleaved().ConvertToYV16() : vertMedian, U=3,V=3 )
  957.     vertMedDiff = Isyv16(vertMedDiff) && Isyuy2(Source) ? vertMedDiff.ConvertToYUY2().interleaved2planar() : vertMedDiff
  958.     vmNewDiff1  = vertMedDiff.SeparateFields().SelectEvery( 4, 1,2 )
  959.     vmNewDiff2  = vmNewDiff1.VerticalCleaner( mode=1, planar=true )
  960.     vmNewDiff2  = Isyuy2(vmNewDiff2) ? vmNewDiff2.planar2interleaved().ConvertToYV16().mt_lutxy( vmNewDiff1.planar2interleaved().ConvertToYV16(), \
  961.     "x 128 - y 128 - * 0 < 128 x 128 - abs y 128 - abs < x y ? ?", U=3,V=3 ) : \
  962.     vmNewDiff2.mt_lutxy( vmNewDiff1, "x 128 - y 128 - * 0 < 128 x 128 - abs y 128 - abs < x y ? ?", U=3,V=3 )
  963.     vmNewDiff2  = Isyv16(vmNewDiff2) && Isyuy2(Source) ? vmNewDiff2.ConvertToYUY2().interleaved2planar() : vmNewDiff2
  964.     vmNewDiff3  = vmNewDiff2.Repair( vmNewDiff2.RemoveGrain( 2, planar=true ), 1, planar=true )
  965.  
  966.     # Reweave final result
  967.     newfd = Isyuy2(Source) ? newFields.planar2interleaved().ConvertToYV16().mt_makediff( vmNewDiff3.planar2interleaved().ConvertToYV16(), U=3,V=3 ).ConvertToYUY2().interleaved2planar() : \
  968.     newFields.mt_makediff( vmNewDiff3, U=3,V=3 )
  969.     return Interleave( srcFields, newfd).SelectEvery( 4, 0,1,3,2 ).Weave()
  970. }
  971.  
  972.  
  973. # Source-match, a three stage process that takes the difference between deinterlaced input and the original interlaced source, to shift the input more towards
  974. # the source without introducing shimmer. All other arguments defined in main script
  975. function QTGMC_ApplySourceMatch( clip Deinterlace, int InputType, val Source, val bVec1, val fVec1, val bVec2, val fVec2, \
  976.                                  int SubPel, int SubPelInterp, int hpad, int vpad, int ThSAD1, int ThSCD1, int ThSCD2, int SourceMatch, \
  977.                                  int MatchTR1, string MatchEdi, int MatchNNSize, int MatchNNeurons, int MatchEdiQual, int MatchEdiMaxD,\
  978.                                  int MatchTR2, string MatchEdi2, int MatchNNSize2, int MatchNNeurons2, int MatchEdiQual2, int MatchEdiMaxD2, \
  979.                                  float MatchEnhance, int EdiThreads, bool lsb )
  980. {
  981.     # >>>> YUY2: 'Deinterlace' is planar, 'Source' is interleaved (changed to planar here for all processing except interpolation) - returns planar result
  982.     yuy2 = Source.IsYUY2()
  983.     Source = yuy2 ? Source.interleaved2planar() : Source
  984.  
  985.     # Basic source-match. Find difference between source clip & equivalent fields in interpolated/smoothed clip (called the "error" in formula below). Ideally
  986.     # there should be no difference, we want the fields in the output to be as close as possible to the source whilst remaining shimmer-free. So adjust the
  987.     # *source* in such a way that smoothing it will give a result closer to the unadjusted source. Then rerun the interpolation (edi) and binomial smooth with
  988.     # this new source. Result will still be shimmer-free and closer to the original source.
  989.     # Formula used for correction is P0' = P0 + (P0-P1)/(k+S(1-k)), where P0 is original image, P1 is the 1st attempt at interpolation/smoothing , P0' is the
  990.     # revised image to use as new source for interpolation/smoothing, k is the weighting given to the current frame in the smooth, and S is a factor indicating
  991.     # "temporal similarity" of the error from frame to frame, i.e. S = average over all pixels of [neighbor frame error / current frame error] . Decreasing
  992.     # S will make the result sharper, sensible range is about -0.25 to 1.0. Empirically, S=0.5 is effective [will do deeper analysis later]
  993.     errorTemporalSimilarity = 0.5  # S in formula described above
  994.     errorAdjust1   = Select( MatchTR1, 1.0, 2.0 / (1.0 + errorTemporalSimilarity), 8.0 / (3.0 + 5.0 * errorTemporalSimilarity) )
  995.     match1Clip     = (SourceMatch < 1 || InputType == 1) ? Deinterlace : Deinterlace.SeparateFields().SelectEvery( 4, 0,3 ).Weave()
  996.     match1Update   = (SourceMatch < 1 || MatchTR1 == 0) \
  997.                         ? Source : yuy2 ? mt_lutxy( Source.planar2interleaved().ConvertToYV16(), match1Clip.planar2interleaved().ConvertToYV16(), "x " + string(errorAdjust1 + 1) + " * y " + string(errorAdjust1) + " * -", U=3,V=3 ).ConvertToYUY2().interleaved2planar() : \
  998.                         mt_lutxy( Source, match1Clip, "x " + string(errorAdjust1 + 1) + " * y " + string(errorAdjust1) + " * -", U=3,V=3 )
  999.     match1Edi      = (SourceMatch == 0) ? NOP() : \
  1000.                      !yuy2 ? match1Update.QTGMC_Interpolate( InputType, MatchEdi, MatchNNSize, MatchNNeurons, MatchEdiQual, MatchEdiMaxD, EdiThreads ) : \
  1001.                              match1Update.planar2interleaved() \
  1002.                                          .QTGMC_Interpolate( InputType, MatchEdi, MatchNNSize, MatchNNeurons, MatchEdiQual, MatchEdiMaxD, EdiThreads ) \
  1003.                                          .interleaved2planar()
  1004.     match1Super    = (SourceMatch > 0 && MatchTR1 > 0) ? match1Edi.MSuper( pel=SubPel, sharp=SubPelInterp, levels=1, hpad=hpad, vpad=vpad, planar=true ) : NOP()
  1005.     match1Degrain1 = (SourceMatch > 0 && MatchTR1 > 0) ? match1Edi.MDegrain1( match1Super, bVec1,fVec1, thSAD=ThSAD1, thSCD1=ThSCD1,thSCD2=ThSCD2, planar=true, lsb=lsb ) : NOP()
  1006.     match1Degrain2 = (SourceMatch > 0 && MatchTR1 > 1) ? match1Edi.MDegrain1( match1Super, bVec2,fVec2, thSAD=ThSAD1, thSCD1=ThSCD1,thSCD2=ThSCD2, planar=true, lsb=lsb ) : NOP()
  1007.     match1Degrain1 = (SourceMatch > 0 && MatchTR1 > 0) && lsb ? yuy2 ? match1Degrain1.planar2interleaved().ConvertToYV16().ditherpost(mode=6, slice=false).ConvertToYUY2().interleaved2planar() : match1Degrain1.ditherpost(mode=6, slice=false) : match1Degrain1
  1008.     match1Degrain2 = (SourceMatch > 0 && MatchTR1 > 1) && lsb ? yuy2 ? match1Degrain2.planar2interleaved().ConvertToYV16().ditherpost(mode=6, slice=false).ConvertToYUY2().interleaved2planar() : match1Degrain2.ditherpost(mode=6, slice=false) : match1Degrain2
  1009.     match1         = (SourceMatch < 1) ? Deinterlace : \
  1010.                      (MatchTR1 == 0)   ? match1Edi : \
  1011.                      (MatchTR1 == 1)   ? match1Degrain1.Merge( match1Edi, 0.25 ) : \
  1012.                                          match1Degrain1.Merge( match1Degrain2, 0.2 ).Merge( match1Edi, 0.0625 )
  1013.  
  1014.     # Enhance effect of source-match stages 2 & 3 by sharpening clip prior to refinement (source-match tends to underestimate so this will leave result sharper)
  1015.     malu26 = (SourceMatch > 1 && MatchEnhance > 0.0) ? yuy2 ? match1.planar2interleaved().ConvertToYV16().mt_lutxy( match1.RemoveGrain( 12, planar=true ).planar2interleaved().ConvertToYV16(), \
  1016.     "x x y - "+ string(MatchEnhance) + " * +", U=3,V=3 ).ConvertToYUY2().interleaved2planar() : nop() : nop()
  1017.     match1Shp = (SourceMatch > 1 && MatchEnhance > 0.0) ? !yuy2 ? match1.mt_lutxy( match1.RemoveGrain( 12 ), "x x y - "+ string(MatchEnhance) + " * +", U=3,V=3 ) : malu26 : match1
  1018.  
  1019.     # Source-match refinement. Find difference between source clip & equivalent fields in (updated) interpolated/smoothed clip. Interpolate & binomially smooth
  1020.     # this difference then add it back to output. Helps restore differences that the basic match missed. However, as this pass works on a difference rather than
  1021.     # the source image it can be prone to occasional artefacts (difference images are not ideal for interpolation). In fact a lower quality interpolation such
  1022.     # as a simple bob often performs nearly as well as advanced, slower methods (e.g. NNEDI3)
  1023.     match2Clip     = (SourceMatch < 2 || InputType == 1) ? match1Shp : match1Shp.SeparateFields().SelectEvery( 4, 0,3 ).Weave()
  1024.     matchdifyuyin26= (SourceMatch > 1) ? yuy2 ? mt_makediff( Source.planar2interleaved().ConvertToYV16(), match2Clip.planar2interleaved().ConvertToYV16(), U=3,V=3 ).ConvertToYUY2().interleaved2planar() : nop() : nop()
  1025.     match2Diff     = (SourceMatch > 1) ? !yuy2 ? mt_makediff( Source, match2Clip, U=3,V=3 ) : matchdifyuyin26 : NOP()
  1026.     match2Edi      = (SourceMatch <= 1) ? NOP() : \
  1027.                      !yuy2 ? match2Diff.QTGMC_Interpolate( InputType, MatchEdi2, MatchNNSize2, MatchNNeurons2, MatchEdiQual2, MatchEdiMaxD2, EdiThreads ) : \
  1028.                              match2Diff.planar2interleaved() \
  1029.                                        .QTGMC_Interpolate( InputType, MatchEdi2, MatchNNSize2, MatchNNeurons2, MatchEdiQual2, MatchEdiMaxD2, EdiThreads ) \
  1030.                                        .interleaved2planar()
  1031.     match2Super    = (SourceMatch > 1 && MatchTR2 > 0) ? match2Edi.MSuper( pel=SubPel, sharp=SubPelInterp, levels=1, hpad=hpad, vpad=vpad, planar=true ) : NOP()
  1032.     match2Degrain1 = (SourceMatch > 1 && MatchTR2 > 0) ? match2Edi.MDegrain1( match2Super, bVec1,fVec1, thSAD=ThSAD1, thSCD1=ThSCD1,thSCD2=ThSCD2, planar=true, lsb=lsb ) : NOP()
  1033.     match2Degrain2 = (SourceMatch > 1 && MatchTR2 > 1) ? match2Edi.MDegrain1( match2Super, bVec2,fVec2, thSAD=ThSAD1, thSCD1=ThSCD1,thSCD2=ThSCD2, planar=true, lsb=lsb ) : NOP()
  1034.     match2Degrain1 = (SourceMatch > 1 && MatchTR2 > 0) && lsb ? yuy2 ? match2Degrain1.planar2interleaved().ConvertToYV16().ditherpost(mode=6, slice=false).ConvertToYUY2().interleaved2planar() : match2Degrain1.ditherpost(mode=6, slice=false) : match2Degrain1
  1035.     match2Degrain2 = (SourceMatch > 1 && MatchTR2 > 1) && lsb ? yuy2 ? match2Degrain2.planar2interleaved().ConvertToYV16().ditherpost(mode=6, slice=false).ConvertToYUY2().interleaved2planar() : match2Degrain2.ditherpost(mode=6, slice=false) : match2Degrain2
  1036.     match2         = (SourceMatch < 2) ? match1 : \
  1037.                      (MatchTR2 == 0)   ? match2Edi : \
  1038.                      (MatchTR2 == 1)   ? match2Degrain1.Merge( match2Edi, 0.25 ) : \
  1039.                                          match2Degrain1.Merge( match2Degrain2, 0.2 ).Merge( match2Edi, 0.0625 )
  1040.  
  1041.     # Source-match second refinement - correct error introduced in the refined difference by temporal smoothing. Similar to error correction from basic step
  1042.     errorAdjust2   = Select( MatchTR2, 1.0, 2.0 / (1.0 + errorTemporalSimilarity), 8.0 / (3.0 + 5.0 * errorTemporalSimilarity) )
  1043.     matlutin26 = !(SourceMatch < 3 || MatchTR2 == 0) ? yuy2 ? mt_lutxy( match2Edi.planar2interleaved().ConvertToYV16(), match2.planar2interleaved().ConvertToYV16(), \
  1044.     "x " + string(errorAdjust2 + 1) + " * y " + string(errorAdjust2) + " * -", U=3,V=3 ).ConvertToYUY2().interleaved2planar() : nop() : nop()
  1045.     match3Update   = (SourceMatch < 3 || MatchTR2 == 0) \
  1046.                          ? match2Edi : !yuy2 ? mt_lutxy( match2Edi, match2, "x " + string(errorAdjust2 + 1) + " * y " + string(errorAdjust2) + " * -", U=3,V=3 ) : matlutin26
  1047.     match3Super    = (SourceMatch > 2 && MatchTR2 > 0) ? match3Update.MSuper( pel=SubPel, sharp=SubPelInterp, levels=1, hpad=hpad, vpad=vpad, planar=true ) : NOP()
  1048.     match3Degrain1 = (SourceMatch > 2 && MatchTR2 > 0) ? match3Update.MDegrain1( match3Super, bVec1,fVec1, thSAD=ThSAD1, thSCD1=ThSCD1,thSCD2=ThSCD2, planar=true, lsb=lsb ) : NOP()
  1049.     match3Degrain2 = (SourceMatch > 2 && MatchTR2 > 1) ? match3Update.MDegrain1( match3Super, bVec2,fVec2, thSAD=ThSAD1, thSCD1=ThSCD1,thSCD2=ThSCD2, planar=true, lsb=lsb ) : NOP()
  1050.     match3Degrain1 = (SourceMatch > 2 && MatchTR2 > 0) && lsb ? yuy2 ? match3Degrain1.planar2interleaved().ConvertToYV16().ditherpost(mode=6, slice=false).ConvertToYUY2().interleaved2planar() : match3Degrain1.ditherpost(mode=6, slice=false) : match3Degrain1
  1051.     match3Degrain2 = (SourceMatch > 2 && MatchTR2 > 1) && lsb ? yuy2 ? match3Degrain2.planar2interleaved().ConvertToYV16().ditherpost(mode=6, slice=false).ConvertToYUY2().interleaved2planar() : match3Degrain2.ditherpost(mode=6, slice=false) : match3Degrain2
  1052.     match3         = (SourceMatch < 3) ? match2 : \
  1053.                      (MatchTR2 == 0)   ? match3Update : \
  1054.                      (MatchTR2 == 1)   ? match3Degrain1.Merge( match3Update, 0.25 ) : \
  1055.                                          match3Degrain1.Merge( match3Degrain2, 0.2 ).Merge( match3Update, 0.0625 )
  1056.  
  1057.     # Apply difference calculated in source-match refinement
  1058.     return (SourceMatch < 2) ? match1 : yuy2 ? match1Shp.planar2interleaved().ConvertToYV16().mt_adddiff( match3.planar2interleaved().ConvertToYV16(), U=3,V=3 ).ConvertToYUY2().interleaved2planar() : \
  1059.     match1Shp.mt_adddiff( match3, U=3,V=3 )
  1060. }
  1061.  
  1062.  
  1063. # Set global variable called "Prefix_Name" to "Value". Throws exception if global already exists unless Replace=true, in which case the global is overwritten
  1064. function QTGMC_SetUserGlobal( string Prefix, string Name, val Value, bool "Replace" )
  1065. {
  1066.     Replace = default( Replace, false )
  1067.     globalName = Prefix + "_" + Name
  1068.  
  1069.     # Tricky logic to check global: enter catch block if Replace=true *or* globalName doesn't exist (i.e. need to set the global), the exception is not rethrown
  1070.     # Not entering catch block means that Replace=false and global exists - so it throws an exception back to AviSynth
  1071.     try { Assert( !Replace && defined(Eval(globalName)) ) }
  1072.     catch (e)
  1073.     {
  1074.         Eval( "global " + globalName + " = Value" )
  1075.         Replace = true
  1076.     }
  1077.     Assert( Replace, """Multiple calls to QTGMC, set PrevGlobals="Replace" or read documentation on 'Multiple QTGMC Calls'""" )
  1078. }
  1079.  
  1080. # Return value of global variable called "Prefix_Name". Returns NOP() if it doesn't exist or Reuse is false
  1081. function QTGMC_GetUserGlobal( string Prefix, string Name, bool "Reuse" )
  1082. {
  1083.     Reuse = default( Reuse, false )
  1084.     globalName = Prefix + "_" + Name
  1085.  
  1086.     try       { ret = Reuse ? Eval( globalName ) : NOP() }
  1087.     catch (e) { ret = NOP() }
  1088.     return ret
  1089. }
RAW Paste Data

Adblocker detected! Please consider disabling it...

We've detected AdBlock Plus or some other adblocking software preventing Pastebin.com from fully loading.

We don't have any obnoxious sound, or popup ads, we actively block these annoying types of ads!

Please add Pastebin.com to your ad blocker whitelist or disable your adblocking software.

×