-
-
Notifications
You must be signed in to change notification settings - Fork 12
/
QTGMC.avsi
1262 lines (1110 loc) · 96.9 KB
/
QTGMC.avsi
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
#-------------------------------------------------------------------#
# #
# QTGMC 3.33 by Vit, 2012 #
# QTGMC 3.34d mod by Dogway 2015 #
# QTGMC 3.382s mod by A.SONY 2021, based on 3.34d #
# QTGMC 3.63 mix mod by Dogway 2021, based on 3.382s #
# #
# A high quality deinterlacer using motion-compensated temporal #
# smoothing, with a range of features for quality and convenience #
# Originally based on TempGaussMC_beta2 by Didée #
# #
#-------------------------------------------------------------------#
#
# Full documentation is in the 'QTGMC' html file that may comes with this script, or even better see avisynth wiki
#
# --- LATEST CHANGES ---
#
# v3.63mx
# - re-add bomt var
# - add Refinemotion to presets
#
# v3.62mx
# - Revised chroma processing for vinverses and blurs
# - Filled missing 'fulls'
# - Cut redundant args (thanks real.finder)
# - Tweaked some defaults based on zorr's zopti findings (more on this coming)
#
# v3.61mx
# - EdiExtPre removed, UseEdiExt become int parameter, 0=false, 1=true, 2=same as old UseEdiExt+EdiExtPre
#
# v3.60mx
# - Update to latest ExTools
# - Added 'fulls' to ConvertBits()
# - Replaced blurs with ex_GaussianBlur()
# - Some Expr optimizations
# - Add back deleted Precise arg, typo
# - Add back UV=3 to tmax and tmin, typo
# - Removed bomt var
# - Remove keep_tv_range limiter
# - 32-bit support is Work In Progress
#
# v3.51mx
# - Replaced vinverse() with ex_vinverse() for custem arg
# - Removed Dither tools related arguments
#
# v3.50mx
# - Replaced masktools2 with Expr calls via ExTools pack wrappers (except mt_merge)
# - Merged redundant expressions
# - Replaced blurs and medians with ExTools equivalents
# - Replaced Vinverse_avsi() with ex_vinverse() (HBD) and vinverse() (8bit)
# - Removed Dither support
# - Reverted from neo_ to vanilla fft3d and dfttest (sameish or faster)
# - Formatting and small optimizations
#
# v3.382s
# - fix for n16 family
#
# v3.380s based on v3.34d (mod) by Dogway
# - Added Refinemotion Option for more accurate denoising.
#
# v3.378s
# - added tr0=-2 same as -1 but with Vinverse_avsi
# - added EdiExtPre to use Vinverse_avsi with UseEdiExt
#
# v3.377s
# - added n16d (same as lsbd but use 16bit avs+ HBD)
# - added FastMA, use 8bit in Motion Analysing clip for faster Motion Analysis when using HBD Inputs
# - added ESearchP, using ErazorTT Suggestion for SearchParam for hex and umh
#
# v3.376s
# - fix keep_tv_range in avs+
#
# v3.375s
# - new EdiMode modes "BWDIF+NNEDI3" and "BWDIF+EEDI3" (need moded Vinverse_avsi)
# - fix RepYadif EdiMode for non YUY2 clip (it was same as Yadif)
#
# v3.371s
# - use sh_Bob
# - support sh_GetUserGlobalIMT (set_plugins_threads) and sh_GetUserGlobalIMTint (set_plugins_threads_int) and sh_GetUserGlobalIMTbool (set_plugins_threads_bool)
# - fix threads parameters bugs
#
# v3.368s
# - bug fix (thanks to missuse)
# - make it work with original mvtools2 (for manolito)
# - add keep_tv_range bool
# - add device_type and device_id
#
# v3.365s
# - support neo_FFT3D and neo_dfttest
#
# v3.363s
# - some changes in LUT things
#
# v3.362s
# - some changes for avs+ and avs neo, need IsAvsNeo(), IsAvsPlus() and AvsPlusVersionNumber(), they are in SMDegrain v3.1.2.101s or up
#
# v3.361s
# - update to masktools 2.2.17, use expr in avs+ (for speed up and less RAM usage)
#
# v3.358s
# - new n16 bool (avs+ faster replacement for lsb), and tr2=6
#
# v3.357s
# - high bit depth now basically work in avs+
#
# v3.354s
# - added optional chikuzen PlanarTools for YUY2 using nonyuy2clipin/nonyuy2clipout in AnimeIVTC() v2.20
#
# v3.353s
# - added ndjamena suggestion for maximum temporal radius
# - added DftDither to controle dfttest dither Parameter
#
# v3.352s
# - added UseEdiExt
# - added tr0=-1 to use the EdiExt clip (if there is no EdiExt clip then it will not work)
# - rep0 now will be 0 if tr0 < 1
#
# v3.347s
# - fix SourceMatch (bug after new YUY2 method, thanks to ndjamena for report it)
#
# v3.346s
# - EEDI3+NNEDI3 bug fix by ndjamena
# - Renamed DftThreads parameter to FftThreads, to set the ncpu argument of FFT3DFilter (from VS)
# - FFT3DFilter will work now in YUY2, use it with Denoiser="fft3df" (or use NoisePreset)
#
# v3.345s
# - work with SH_KNLMeansCL now to process chroma too
#
# v3.343s
# - edit in ChromaEdi
# - others
#
# v3.34s (mod) 2016 12 18 (ravewulf idea in another way)
# - Added yadifmod2 (if you need old one use it like this EdiMode="cYadif" or EdiMode="RepcYadif")
# - fast and clean up YUY2 (will work in x64 now, no need to SSETools)
#
# v3.33s (mod) 2016 12 06
# - Add TR2=4 and TR2=5
# - add TV_range bool and dither_luma_rebuild (from SMDegrain) Str and Amp
# - for avsplus now QTGMC_Bob is ready for any 420, not only yv12
#
# v3.33s (mod) 2016 04 11
# - Add KNLMeansCL as another Denoiser to NoiseProcess
# - others
#
# v3.33s (mod) 2016 01 19
# - make QTGMC_deflate/QTGMC_inflate work with YUY2 using masktool2 for avs 2.60
#
# v3.33s (mod) 2015 10 23
# - revert to QTGMC_deflate/QTGMC_inflate quoted from Dogway
#
# v3.33s (mod) 2015 9 10
# - fix Multiple QTGMC Calls
# - others fix
#
# v3.33s (mod) 2015 8 6
# - some changes in bob to speed up
#
# v3.33s (mod) 2015 8 4
# - fix bug in YUY2 with SourceMatch
# - add slice=false to ditherpost to avoid artefacts
#
# v3.33s (mod)
# - fix bob chroma
# - work with new masktool2 for avs 2.60 in YUY2
#
# v3.33d (mod)
# - Added 32 bit precision option through the lsbd (for dfttest and knlmeanscl) and lsb (mdegrain) options.
# - optimized some mask handling a bit as originally suggested by Vit
# - others
#
# v3.33
# - 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
# - Bug fix for the fact that Bob always outputs a BFF clip regardless of field order of input (thanks ajp_anton)
# - Improved generation of noise (NoiseDeint="Generate") for noise bypass / EZKeepGrain
# - Minor change to denoising
#
# v3.32
# - Bugfix with shutter blur and ChromaMotion (thanks Heaud)
# - Tweaked vector recalculation for shutter motion blur
# - Changed defaults for TR2 when using source-match
# - Minor bugfix with SLMode/SLRad on pass-through settings
#
# --- REQUIREMENTS ---
#
# Input colorspaces: YV12, YUY2, others as plugins supports
#
# Core plugins:
# MVTools2 (2.7.45 or above)
# MaskTools2 (2.2.26 or above)
# NNEDI3 (0.9.4.59 or above)
# RgTools (1.2 or above)
# Vinverse
#
# Core scripts:
# Zs_RF_Shared (1.154 or above) (for sh_Bob)
# ExTools (5.5 or above)
#
# Additional plugins and scripts:
# NNEDI2, NNEDI, EEDI3, EEDI2, TDeInt - if selected directly or via a source-match preset
# yadifmod2 (0.2.7 or above) - for Preset="Ultra Fast" or if selected directly
# FFT3DFilter - if selected for noise processing
# dfttest (1.9.6 or above) - if selected for noise processing
# 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
# 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
# KNLMeansCL - if selected for noise processing
# AddGrainC - if NoiseDeint="Generate" selected for noise bypass
# chikuzen PlanarTools - if you work with YUY2 source (not necessarily required but may improve speed)
# BWDIF and vinverse() or ex_vinverse() - for EdiMode modes "BWDIF+NNEDI3" and "BWDIF+EEDI3"
# --- GETTING STARTED ---
#
# Install AviSynth and ensure you have at least the core plugins listed in the requirements section above. Put them in the plugins autoload folder.
# To use QTGMC write a script like this:
# YourSource("yourfile") # DGDecode_mpeg2source, FFVideoSource, AviSource, whatever your source requires
# QTGMC( Preset="Slow" )
# SelectEven() # Add this line to keep original frame rate, leave it out for smoother doubled frame rate
#
# Save this script with an ".avs" extension. You can now use it as an AVI source for encoding.
#
# The "Preset" used selects sensible settings for a given encoding speed. Choose a preset from:
# "Placebo", "Very Slow", "Slower", "Slow", "Medium", "Fast", "Faster", "Very Fast", "Super Fast", "Ultra Fast" & "Draft"
# The default preset is "Slower"
# 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)
# For much faster speeds read the full documentation, the section on 'Multi-threading'
#
# There are many settings for tweaking the script, full details in the main documentation. You can display settings currently being used with "ShowSettings":
# QTGMC( Preset="Slow", ShowSettings=true )
#
#
# Note, If coming from an old version:
# Setting BT has been replaced by setting NoiseTR
# Setting DetailRestore has been renamed to GrainRestore
# Setting MotionBlur has been renamed to ShutterBlur
# Setting MBlurLimit has been renamed to SBlurLimit
# Setting NoiseBypass has been renamed to NoiseProcess
#
function QTGMC( clip Input, string "Preset", int "TR0", int "TR1", int "TR2", int "Rep0", int "Rep1", int "Rep2", string "EdiMode", bool "RepChroma", \
int "NNSize", int "NNeurons", int "EdiQual", int "EdiMaxD", string "ChromaEdi", clip "EdiExt", float "Sharpness", \
int "SMode", int "SLMode", int "SLRad", int "SOvs", float "SVThin", int "Sbb", int "SrchClipPP", int "SubPel", int "SubPelInterp", \
int "BlockSize", int "Overlap", int "Search", int "SearchParam", int "PelSearch", bool "ChromaMotion", bool "TrueMotion", int "Lambda", \
int "LSAD", int "PNew", int "PLevel", bool "GlobalMotion", int "DCT", int "ThSAD1", int "ThSAD2", int "ThSCD1", int "ThSCD2", \
int "SourceMatch", string "MatchPreset", string "MatchEdi", string "MatchPreset2", string "MatchEdi2", int "MatchTR2", \
float "MatchEnhance", int "Lossless", int "NoiseProcess", float "EZDenoise", float "EZKeepGrain", string "NoisePreset", string "Denoiser", \
bool "DenoiseMC", int "NoiseTR", float "Sigma", bool "ChromaNoise", val "ShowNoise", float "GrainRestore", \
float "NoiseRestore", string "NoiseDeint", bool "StabilizeNoise", int "InputType", float "ProgSADMask", int "FPSDivisor", \
int "ShutterBlur", float "ShutterAngleSrc", float "ShutterAngleOut", int "SBlurLimit", bool "Border", bool "Precise", string "Tuning", \
bool "ShowSettings", string "GlobalNames", string "PrevGlobals", int "ForceTR", int "UseEdiExt", \
float "Str", float "Amp", bool "tv_range", bool "n16", bool "n16d", String "device_type", int "device_id", int "Threads", bool "Refinemotion", bool "fulls" )
{
# EdiMode="RepcYadif"/"cYadif" require the Yadif plugin, which doesn't autoload. Typically the calling script would load it.
#---------------------------------------
# Presets
n16 = Default( n16, false)
n16d = Default( n16d, false)
UseEdiExt = Default( useEdiExt, 0)
fs = Default( fulls, false)
Str = Default( Str, 3.0 )
Amp = Default( Amp, 0.0625 )
TV_range = Default( TV_range, !(Isrgb(input)))
Assert(IsVersionOrGreater(3,5,0), "Update AviSynth+ version")
Assert(!(!Defined(EdiExt) && UseEdiExt > 0), "UseEdiExt need EdiExt to work")
bi = Input.BitsPerComponent()
bi8 = bi == 8
# Select presets / tuning
Preset = Default( Preset, "Slower" )
pNum = (Preset == "Placebo" ) ? 0 : \
(Preset == "Very Slow" ) ? 1 : \
(Preset == "Slower" ) ? 2 : \
(Preset == "Slow" ) ? 3 : \
(Preset == "Medium" ) ? 4 : \
(Preset == "Fast" ) ? 5 : \
(Preset == "Faster" ) ? 6 : \
(Preset == "Very Fast" ) ? 7 : \
(Preset == "Super Fast" ) ? 8 : \
(Preset == "Ultra Fast" ) ? 9 : \
(Preset == "Draft" ) ? 10 : 11
Assert( pNum < 11, "'Preset' choice is invalid" )
mpNum1 = (!Defined(MatchPreset)) ? ((pNum + 3 <= 9) ? (pNum + 3) : 9) : \
(MatchPreset == "Placebo" ) ? 0 : \
(MatchPreset == "Very Slow" ) ? 1 : \
(MatchPreset == "Slower" ) ? 2 : \
(MatchPreset == "Slow" ) ? 3 : \
(MatchPreset == "Medium" ) ? 4 : \
(MatchPreset == "Fast" ) ? 5 : \
(MatchPreset == "Faster" ) ? 6 : \
(MatchPreset == "Very Fast" ) ? 7 : \
(MatchPreset == "Super Fast" ) ? 8 : \
(MatchPreset == "Ultra Fast" ) ? 9 : \
(MatchPreset == "Draft" ) ? 10 : 11
Assert( mpNum1 < 10, "'MatchPreset' choice is invalid/unsupported" )
MatchPreset = Select( mpNum1, "Placebo", "Very Slow", "Slower", "Slow", "Medium", "Fast", "Faster", "Very Fast", "Super Fast", "Ultra Fast", "Draft" )
mpNum2 = (!Defined(MatchPreset2)) ? ((mpNum1 + 2 <= 9) ? (mpNum1 + 2) : 9) : \
(MatchPreset2 == "Placebo" ) ? 0 : \
(MatchPreset2 == "Very Slow" ) ? 1 : \
(MatchPreset2 == "Slower" ) ? 2 : \
(MatchPreset2 == "Slow" ) ? 3 : \
(MatchPreset2 == "Medium" ) ? 4 : \
(MatchPreset2 == "Fast" ) ? 5 : \
(MatchPreset2 == "Faster" ) ? 6 : \
(MatchPreset2 == "Very Fast" ) ? 7 : \
(MatchPreset2 == "Super Fast") ? 8 : \
(MatchPreset2 == "Ultra Fast") ? 9 : \
(MatchPreset2 == "Draft" ) ? 10 : 11
Assert( mpNum2 < 10, "'MatchPreset2' choice is invalid/unsupported" )
MatchPreset2 = Select( mpNum2, "Placebo", "Very Slow", "Slower", "Slow", "Medium", "Fast", "Faster", "Very Fast", "Super Fast", "Ultra Fast", "Draft" )
NoisePreset = Default( NoisePreset, "Fast" )
npNum = (NoisePreset == "Slower" ) ? 0 : \
(NoisePreset == "Slow" ) ? 1 : \
(NoisePreset == "Medium" ) ? 2 : \
(NoisePreset == "Fast" ) ? 3 : \
(NoisePreset == "Faster" ) ? 4 : 5
Assert( npNum < 5, "'NoisePreset' choice is invalid" )
Tuning = Default( Tuning, "None" )
tNum = (Tuning == "None" ) ? 0 : \
(Tuning == "DV-SD" ) ? 1 : \
(Tuning == "DV-HD" ) ? 2 : 3
Assert( tNum < 3, "'Tuning' choice is invalid" )
# Tunings only affect blocksize in this version
bs = Select( tNum, 16, 16, 32 )
bs2 = (bs >= 16) ? 32 : bs * 2
# Very Very Super Ultra
# Preset groups: Placebo Slow Slower Slow Medium Fast Faster Fast Fast Fast Draft
TR0 = Default( TR0, Select( pNum, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 0 ) )
TR1 = Default( TR1, Select( pNum, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1 ) )
TR2X = Default( TR2, Select( pNum, 3, 2, 1, 1, 1, 0, 0, 0, 0, 0, 0 ) )
Rep0 = Defined(Rep0) ? Rep0 : TR0 < 1 ? 0 : Undefined()
Rep0 = Default( Rep0, Select( pNum, 4, 4, 4, 4, 3, 3, 0, 0, 0, 0, 0 ) )
Rep1 = Default( Rep1, Select( pNum, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ) )
Rep2 = Default( Rep2, Select( pNum, 4, 4, 4, 4, 4, 4, 4, 4, 3, 3, 0 ) )
EdiMode = Default( EdiMode, Select( pNum, "NNEDI3", "NNEDI3", "NNEDI3", "NNEDI3", "NNEDI3", "NNEDI3", "NNEDI3", "NNEDI3", "NNEDI3", "RepYadif","Bob" ) )
NNSize = Default( NNSize, Select( pNum, 1, 1, 1, 1, 5, 5, 4, 4, 4, 4, 4 ) )
NNeurons = Default( NNeurons, Select( pNum, 2, 2, 1, 1, 1, 0, 0, 0, 0, 0, 0 ) )
EdiQual = Default( EdiQual, Select( pNum, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ) )
EdiMaxD = Default( EdiMaxD, Select( pNum, 12, 10, 8, 7, 7, 6, 6, 5, 4, 4, 4 ) )
SMode = Default( SMode, Select( pNum, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0 ) )
SLModeX = Default( SLMode, Select( pNum, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0 ) )
SLRad = Default( SLRad, Select( pNum, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ) )
Sbb = Default( Sbb, Select( pNum, 3, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0 ) )
SrchClipPP = Default( SrchClipPP, Select( pNum, 3, 3, 3, 3, 3, 2, 2, 2, 1, 1, 0 ) )
SubPel = Default( SubPel, Select( pNum, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1 ) )
Blocksize = Default( Blocksize, Select( pNum, bs, bs, bs, bs, bs, bs, bs2, bs2, bs2, bs2, bs2 ) )
bs = Blocksize
sr = max(1,bs / 8)
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 ) )
Search = Default( Search, Select( pNum, 5, 4, 4, 4, 4, 4, 4, 4, 0, 0, 0 ) )
SearchParam = Default( SearchParam, Select( pNum, sr, sr, sr, sr, sr, sr, sr, sr, sr, sr, sr ) )
PelSearch = Default( PelSearch, Select( pNum, bs<16?6:1, 15, 2, 2, 2, 2, 2, 2, 2, 2, 2 ) )
ChromaMotion = Default( ChromaMotion, Select( pNum, true, true, true, false, false, false, false, false, false, false, false ) )
Precise = Default( Precise, Select( pNum, true, true, false, false, false, false, false, false, false, false, false ) )
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 ) )
Refinemotion = Default( Refinemotion, Select( pNum, true, true, false, false, false, false, false, false, false, false, false ) )
# Noise presets Slower Slow Medium Fast Faster
Denoiser = Default( Denoiser, Select( npNum, "dfttest", "dfttest", "dfttest", "fft3df", "fft3df" ) )
DenoiseMC = Default( DenoiseMC, Select( npNum, true, true, false, false, false ) )
NoiseTR = Default( NoiseTR, Select( npNum, 2, 1, 1, 1, 0 ) )
NoiseDeint = Default( NoiseDeint, Select( npNum, "Generate","Bob", "", "", "" ) )
StabilizeNoise = Default( StabilizeNoise, Select( npNum, true, true, true, false, false ) )
# 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
SourceMatch = Default( SourceMatch, 0 )
MatchNNSize = NNSize
MatchNNeurons = NNeurons
MatchEdiMaxD = EdiMaxD
MatchEdiQual = EdiQual
# However, can use a faster initial interpolation when using source-match allowing the basic source-match step to "correct" it with higher quality settings
Assert( SourceMatch == 0 || mpNum1 >= pNum, "'MatchPreset' cannot use a slower setting than 'Preset'" )
# Very Very Super Ultra
# Basic source-match presets Placebo Slow Slower Slow Medium Fast Faster Fast Fast Fast
NNSize = (SourceMatch == 0) ? NNSize : Select( mpNum1, 1, 1, 1, 1, 5, 5, 4, 4, 4, 4 )
NNeurons = (SourceMatch == 0) ? NNeurons : Select( mpNum1, 2, 2, 1, 1, 1, 0, 0, 0, 0, 0 )
EdiMaxD = (SourceMatch == 0) ? EdiMaxD : Select( mpNum1, 12, 10, 8, 7, 7, 6, 6, 5, 4, 4 )
EdiQual = (SourceMatch == 0) ? EdiQual : Select( mpNum1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 )
TempEdi = EdiMode # Main interpolation is actually done by basic-source match step when enabled, so a little swap and wriggle is needed
EdiMode = (SourceMatch == 0) ? EdiMode : Default( MatchEdi, ((mpNum1 < 9) ? EdiMode : "Yadif") ) # Force Yadif for "Ultra Fast" basic source match
MatchEdi = TempEdi
# Very Very Super Ultra
# Refined source-match presets Placebo Slow Slower Slow Medium Fast Faster Fast Fast Fast
MatchEdi2 = Default( MatchEdi2, Select( mpNum2, "NNEDI3", "NNEDI3", "NNEDI3", "NNEDI3", "NNEDI3", "NNEDI3", "NNEDI3", "NNEDI3", "TDeint", "" ) )
MatchNNSize2 = Select( mpNum2, 1, 1, 1, 1, 5, 5, 4, 4, 4, 4 )
MatchNNeurons2 = Select( mpNum2, 2, 2, 1, 1, 1, 0, 0, 0, 0, 0 )
MatchEdiMaxD2 = Select( mpNum2, 12, 10, 8, 7, 7, 6, 6, 5, 4, 4 )
MatchEdiQual2 = Select( mpNum2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 )
#---------------------------------------
# Settings
# Core and Interpolation defaults
TR2 = (SourceMatch > 0) ? Default(TR2, ((TR2X == 0) ? 1 : TR2X)) : TR2X # ***TR2 defaults always at least 1 when using source-match***
RepChroma = Default( RepChroma, true )
Threads = Default( Threads, sh_GetUserGlobalIMTint(true) )
bomt = Threads != 1
ChromaEdi = Default( ChromaEdi, "" )
NNeurons = (EdiMode == "NNEDI2" && NNeurons > 2) ? 2 : NNeurons # Smaller range for NNeurons in NNEDI2 (which calls it nsize)
EdiQual = (EdiMode == "EEDI3+NNEDI3" || EdiMode == "NNEDI3" || EdiMode == "BWDIF+NNEDI3" || EdiMode == "BWDIF+EEDI3") && EdiQual > 2 ? 2 : EdiQual # Smaller range for EdiQual in NNEDI3
# Source-match / lossless defaults
MatchTR1 = TR1
MatchTR2 = Default( MatchTR2, 1 )
MatchEnhance = Default( MatchEnhance, 0.5 )
Lossless = Default( Lossless, 0 )
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" )
# Sharpness defaults. Sharpness default is always 1.0 (0.2 with source-match), but adjusted to give roughly same sharpness for all settings
SMode = (Defined(Sharpness) && Sharpness == 0.0) ? 0 : SMode
SLMode = (SourceMatch > 0) ? Default(SLMode, 0) : SLModeX # ***Sharpness limiting disabled by default for source-match***
SLMode = (SLRad <= 0) ? 0 : SLMode
spatialSL = (SLMode == 1 || SLMode == 3)
temporalSL = (SLMode == 2 || SLMode == 4)
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
sharpMul = (temporalSL) ? 2 : (spatialSL) ? 1.5 : 1 # Adjust sharpness based on other settings
sharpAdj = Sharpness * (sharpMul * (0.2 + TR1*0.15 + TR2*0.25) + ((SMode == 1) ? 0.1 : 0)) # [This needs a bit more refinement]
Sbb = (SMode == 0) ? 0 : Sbb
SOvs = Default( SOvs, 0 )
SVThin = Default( SVThin, 0.0 )
# Noise processing settings
Assert( !Defined(EZDenoise) || EZDenoise <= 0.0 || !Defined(EZKeepGrain) || EZKeepGrain <= 0.0, "QTGMC: EZDenoise and EZKeepGrain cannot be used together" )
NoiseProcess = Defined(NoiseProcess) ? NoiseProcess : \
(Defined(EZDenoise) && EZDenoise > 0.0) ? 1 : \
(Defined(EZKeepGrain) && EZKeepGrain > 0.0) ? 2 : \
(Preset == "Placebo" || Preset == "Very Slow") ? 2 : 0
GrainRestore = Defined(GrainRestore) ? GrainRestore : \
(Defined(EZDenoise) && EZDenoise > 0.0) ? 0.0 : \
(Defined(EZKeepGrain) && EZKeepGrain > 0.0) ? 0.3 * sqrt(EZKeepGrain) : \
Select( NoiseProcess, 0.0, 0.7, 0.3 )
NoiseRestore = Defined(NoiseRestore) ? NoiseRestore : \
(Defined(EZDenoise) && EZDenoise > 0.0) ? 0.0 : \
(Defined(EZKeepGrain) && EZKeepGrain > 0.0) ? 0.1 * sqrt(EZKeepGrain) : \
Select( NoiseProcess, 0.0, 0.3, 0.1 )
Sigma = Defined(Sigma) ? Sigma : \
(Defined(EZDenoise) && EZDenoise > 0.0) ? EZDenoise : \
(Defined(EZKeepGrain) && EZKeepGrain > 0.0) ? 4.0 * EZKeepGrain : 2.0
ChromaNoise = Default( ChromaNoise, false )
ShowNoise = Default( ShowNoise, 0.0 )
ShowNoise = IsBool( ShowNoise ) ? (ShowNoise ? 10.0 : 0.0) : ShowNoise
NoiseProcess = (ShowNoise > 0.0) ? 2 : NoiseProcess
NoiseRestore = (ShowNoise > 0.0) ? 1.0 : NoiseRestore
NoiseTR = (NoiseProcess == 0) ? 0 : NoiseTR
GrainRestore = (NoiseProcess == 0) ? 0.0 : GrainRestore
NoiseRestore = (NoiseProcess == 0) ? 0.0 : NoiseRestore
totalRestore = GrainRestore + NoiseRestore
StabilizeNoise = (totalRestore <= 0) ? false : StabilizeNoise
noiseTD = Select( NoiseTR, 1, 3, 5 )
noiseCentre = ex_bs((Denoiser == "dfttest") ? 128 : 128.5, 8, bi, fulls=fs)
# MVTools settings
SubPelInterp = Default( SubPelInterp, 2 )
TrueMotion = Default( TrueMotion, false )
GlobalMotion = Default( GlobalMotion, true )
Lambda = Default( Lambda, ((TrueMotion) ? 1000 : 100 ) * (BlockSize*BlockSize)/(8*8) )
LSAD = Default( LSAD, (TrueMotion) ? 1200 : 400 )
PNew = Default( PNew, (TrueMotion) ? 50 : 25 )
PLevel = Default( PLevel, (TrueMotion) ? 1 : 0 )
DCT = Default( DCT, 0 )
ThSAD1 = Default( ThSAD1, 10 * 8*8 )
ThSAD2 = Default( ThSAD2, 4 * 8*8 )
ThSCD1 = Default( ThSCD1, 180 )
ThSCD2 = Default( ThSCD2, 98 )
# Motion blur settings
FPSDivisor = Default( FPSDivisor, 1 )
ShutterBlur = Default( ShutterBlur, 0 )
ShutterAngleSrc = Default( ShutterAngleSrc, 180 )
ShutterAngleOut = Default( ShutterAngleOut, 180 )
SBlurLimit = Default( SBlurLimit, 4 )
ShutterBlur = (ShutterAngleOut * FPSDivisor == ShutterAngleSrc) ? 0 : ShutterBlur # If motion blur output is same as input
# Miscellaneous
InputType = Default( InputType, 0 )
Border = Default( Border, false )
ShowSettings = Default( ShowSettings, false )
GlobalNames = Default( GlobalNames, "QTGMC" )
PrevGlobals = Default( PrevGlobals, "Replace" )
ForceTR = Default( ForceTR, 0 )
ReplaceGlobals = (PrevGlobals == "Replace" || PrevGlobals == "Reuse") # If reusing existing globals put them back afterwards - simplifies logic later
ReuseGlobals = (PrevGlobals == "Reuse")
ProgSADMask = (InputType != 2 && InputType != 3) ? 0.0 : ProgSADMask
# RefineMotion Defaults (Beware 8x8 blocks blur out output in QTGMC)
halfoverlap = Overlap/2
halfblksize = BlockSize/2
halfthSAD = round(thSAD2/2)
# Get maximum temporal radius needed
maxTR = (temporalSL) ? SLRad : 0
maxTR = max(MatchTR2, TR1, TR2, NoiseTR, maxTR)
maxTR = (ProgSADMask > 0.0 || StabilizeNoise || ShutterBlur > 0) ? (maxTR > 1 ? maxTR : 1) : maxTR
maxTR = max(ForceTR, MaxTR)
#---------------------------------------
# Pre-Processing
w = Input.Width()
h = Input.Height()
yuy2 = Input.IsYUY2()
eps = 0.0001
# Reverse "field" dominance for progressive repair mode 3 (only difference from mode 2)
compl = (InputType == 3) ? Input.ComplementParity() : Input
# Pad vertically during processing (to prevent artefacts at top & bottom edges)
clip = (Border) ? compl.PointResize( w,h+8, 0,-4,0,h+8+eps ) : compl
h = (Border) ? h+8 : h
# Calculate padding needed for MVTools super clips to avoid crashes [fixed in latest MVTools, but keeping this code for a while]
hpad = w - (Int((w - Overlap) / (Blocksize - Overlap)) * (Blocksize - Overlap) + Overlap)
vpad = h - (Int((h - Overlap) / (Blocksize - Overlap)) * (Blocksize - Overlap) + Overlap)
hpad = (hpad > 8) ? hpad : 8 # But match default padding if possible
vpad = (vpad > 8) ? vpad : 8
#---------------------------------------
# Motion Analysis
CMmt = ChromaMotion ? 3 : 1
CMts = ChromaMotion ? 255 : 0
CMrg = ChromaMotion ? 12 : -1
# >>> Planar YUY2 for motion analysis, interleaved whilst blurring search clip
planarClip = yuy2 ? clip.nonyuy2clipin(true) : clip
# Bob the input as a starting point for motion search clip
bobbed = (InputType == 0) ? UseEdiExt > 0 ? isyuy2(EdiExt) ? EdiExt.nonyuy2clipin(true) : EdiExt : planarClip.sh_Bob( 0,0.5 ) : \
(InputType == 1) ? planarClip : \
planarClip.ex_boxblur( 0, 1, "weighted", UV=CMmt)
bobbed = (InputType == 0) && UseEdiExt > 1 ? bi8 ? bobbed.vinverse(uv=CMmt) : bobbed.ex_vinverse(uv=CMmt,fulls=fs) : bobbed
# If required, get any existing global clips with a matching "GlobalNames" setting. Unmatched values get NOP (= 0)
srchClip = QTGMC_GetUserGlobal( GlobalNames, "srchClip", ReuseGlobals )
srchSuper = QTGMC_GetUserGlobal( GlobalNames, "srchSuper", ReuseGlobals )
bVec1 = QTGMC_GetUserGlobal( GlobalNames, "bVec1", ReuseGlobals )
fVec1 = QTGMC_GetUserGlobal( GlobalNames, "fVec1", ReuseGlobals )
bVec2 = QTGMC_GetUserGlobal( GlobalNames, "bVec2", ReuseGlobals )
fVec2 = QTGMC_GetUserGlobal( GlobalNames, "fVec2", ReuseGlobals )
bVec3 = QTGMC_GetUserGlobal( GlobalNames, "bVec3", ReuseGlobals )
fVec3 = QTGMC_GetUserGlobal( GlobalNames, "fVec3", ReuseGlobals )
bVec4 = QTGMC_GetUserGlobal( GlobalNames, "bVec4", ReuseGlobals )
fVec4 = QTGMC_GetUserGlobal( GlobalNames, "fVec4", ReuseGlobals )
bVec5 = QTGMC_GetUserGlobal( GlobalNames, "bVec5", ReuseGlobals )
fVec5 = QTGMC_GetUserGlobal( GlobalNames, "fVec5", ReuseGlobals )
bVec6 = QTGMC_GetUserGlobal( GlobalNames, "bVec6", ReuseGlobals )
fVec6 = QTGMC_GetUserGlobal( GlobalNames, "fVec6", ReuseGlobals )
srchcheck = IsClip(srchClip)
# The bobbed clip will shimmer due to being derived from alternating fields. Temporally smooth over the neighboring frames using a binomial kernel. Binomial
# 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.
# These kernels are approximately Gaussian kernels, which work well as a prefilter before motion analysis (hence the original name for this script)
# Create linear weightings of neighbors first -2 -1 0 1 2
ts1 = (!srchcheck && TR0 > 0) ? bobbed.TemporalSoften( 1, 255, CMts, 28, 2 ) : nop() # 0.00 0.33 0.33 0.33 0.00
ts2 = (!srchcheck && TR0 > 1) ? bobbed.TemporalSoften( 2, 255, CMts, 28, 2 ) : nop() # 0.20 0.20 0.20 0.20 0.20
# Combine linear weightings to give binomial weightings - TR0=0: (1), TR0=1: (1:2:1), TR0=2: (1:4:6:4:1) # * uh! this is more like (1:3:12:3:1)
domtr02 = TR0 == -2 && !(InputType == 0 && UseEdiExt > 1)
domtr01 = TR0 == -1 && !(InputType == 0 && UseEdiExt > 1)
binomial0 = srchcheck ? nop() : \
domtr02 && Defined(EdiExt) ? isyuy2(EdiExt) ? bi8 ? EdiExt.nonyuy2clipin(true).vinverse(uv=CMmt) : EdiExt.nonyuy2clipin(true).ex_vinverse(uv=CMmt,fulls=fs) : \
bi8 ? EdiExt.vinverse(uv=CMmt) : EdiExt.ex_vinverse(uv=CMmt,fulls=fs) : TR0 == -2 ? bobbed : \
domtr01 && Defined(EdiExt) ? isyuy2(EdiExt) ? EdiExt.nonyuy2clipin(true) : EdiExt : TR0 == -1 ? bobbed : \
(TR0 == 0) ? bobbed : \
(TR0 == 1) ? (ChromaMotion ? ts1.Merge( bobbed, 0.25 ) : ts1.MergeLuma( bobbed, 0.25 )) : \
ex_lutxyz(ts1,ts2,bobbed,"x 0.562625 * y 0.312375 * z 0.125001 * + +", UV=CMmt)
# Remove areas of difference between temporal blurred motion search clip and bob that are not due to bob-shimmer - removes general motion blur
repair0 = (srchcheck || Rep0 == 0) ? binomial0 : binomial0.QTGMC_KeepOnlyBobShimmerFixes( bobbed, Rep0, (RepChroma && ChromaMotion), fs )
# 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
# a slight change in an edge from frame to frame will give a high SAD due to the higher contrast of edges
spatialBlur = (SrchClipPP == 0 || srchcheck) ? nop() : \
(SrchClipPP == 1) ? repair0.ex_GaussianBlur(1.875, UV=CMmt) : \
repair0.ex_GaussianBlur(1.925, UV=CMmt)
spatialBlur = (SrchClipPP > 1 && IsClip(spatialBlur)) ? (ChromaMotion ? spatialBlur.Merge( repair0, 0.1 ) : spatialBlur.MergeLuma( repair0, 0.1 )) : spatialBlur
tweaked = (SrchClipPP > 1 && !srchcheck) ? ex_lutxy( repair0, bobbed, "y x 3 scalef - x 3 scalef + clip", UV=CMmt, fulls=fs ) : nop()
srchClip = srchcheck ? srchClip : \
(SrchClipPP == 0) ? repair0 : \
(SrchClipPP < 3) ? spatialBlur : \
spatialBlur.ex_lutxy( tweaked, "x 7 scalef + y < x 2 scalef + x 7 scalef - y > x 2 scalef - x 0.510001 * y 0.490001 * + ? ?", UV=CMmt, fulls=fs )
srchClip = tv_range && !srchcheck ? srchClip.ex_Luma_Rebuild(S0=Str, c=Amp, uv=CMmt, tv_range=tv_range, fulls=fs) : srchClip
srchClip = bi8 ? srchClip : srchClip.ConvertBits(8,dither=-1,fulls=fs)
# Calculate forward and backward motion vectors from motion search clip
srchSuper = IsClip(srchSuper) ? srchSuper : \
(maxTR > 0) ? srchClip.MSuper( pel=SubPel, sharp=SubPelInterp, hpad=hpad, vpad=vpad, chroma=ChromaMotion, mt=bomt ) : nop()
bVec6c = IsClip(bVec6)
bVec6 = bVec6c ? bVec6 : \
(maxTR > 5) ? srchSuper.MAnalyse( isb=true, delta=6, blksize=BlockSize, overlap=Overlap, search=Search, searchparam=SearchParam, \
pelsearch=PelSearch, truemotion=TrueMotion, lambda=Lambda, lsad=LSAD, pnew=PNew, plevel=PLevel, \
global=GlobalMotion, DCT=DCT, chroma=ChromaMotion, badSAD=3200, mt=bomt ) : nop()
bVec6 = bVec6c || !RefineMotion || !(maxTR > 5) ? bVec6 : srchSuper.MRecalculate(bVec6, overlap=halfoverlap, blksize=halfblksize, thSAD=halfthSAD, DCT=DCT, \
chroma=ChromaMotion, truemotion=TrueMotion, search=Search, \
searchparam=SearchParam, lambda=Lambda, pnew=PNew, mt=bomt)
bVec5c = IsClip(bVec5)
bVec5 = bVec5c ? bVec5 : \
(maxTR > 4) ? srchSuper.MAnalyse( isb=true, delta=5, blksize=BlockSize, overlap=Overlap, search=Search, searchparam=SearchParam, \
pelsearch=PelSearch, truemotion=TrueMotion, lambda=Lambda, lsad=LSAD, pnew=PNew, plevel=PLevel, \
global=GlobalMotion, DCT=DCT, chroma=ChromaMotion, badSAD=3200, mt=bomt ) : nop()
bVec5 = bVec5c || !RefineMotion || !(maxTR > 4) ? bVec5 : srchSuper.MRecalculate(bVec5, overlap=halfoverlap, blksize=halfblksize, thSAD=halfthSAD, DCT=DCT, \
chroma=ChromaMotion, truemotion=TrueMotion, search=Search, \
searchparam=SearchParam, lambda=Lambda, pnew=PNew, mt=bomt)
bVec4c = IsClip(bVec4)
bVec4 = bVec4c ? bVec4 : \
(maxTR > 3) ? srchSuper.MAnalyse( isb=true, delta=4, blksize=BlockSize, overlap=Overlap, search=Search, searchparam=SearchParam, \
pelsearch=PelSearch, truemotion=TrueMotion, lambda=Lambda, lsad=LSAD, pnew=PNew, plevel=PLevel, \
global=GlobalMotion, DCT=DCT, chroma=ChromaMotion, badSAD=3200, mt=bomt ) : nop()
bVec4 = bVec4c || !RefineMotion || !(maxTR > 3) ? bVec4 :srchSuper.MRecalculate(bVec4, overlap=halfoverlap, blksize=halfblksize, thSAD=halfthSAD, DCT=DCT, \
chroma=ChromaMotion, truemotion=TrueMotion, search=Search, \
searchparam=SearchParam, lambda=Lambda, pnew=PNew, mt=bomt)
bVec3c = IsClip(bVec3)
bVec3 = bVec3c ? bVec3 : \
(maxTR > 2) ? srchSuper.MAnalyse( isb=true, delta=3, blksize=BlockSize, overlap=Overlap, search=Search, searchparam=SearchParam, \
pelsearch=PelSearch, truemotion=TrueMotion, lambda=Lambda, lsad=LSAD, pnew=PNew, plevel=PLevel, \
global=GlobalMotion, DCT=DCT, chroma=ChromaMotion, badSAD=3200, mt=bomt ) : nop()
bVec3 = bVec3c || !RefineMotion || !(maxTR > 2) ? bVec3 : srchSuper.MRecalculate(bVec3, overlap=halfoverlap, blksize=halfblksize, thSAD=halfthSAD, DCT=DCT, \
chroma=ChromaMotion, truemotion=TrueMotion, search=Search, \
searchparam=SearchParam, lambda=Lambda, pnew=PNew, mt=bomt)
bVec2c = IsClip(bVec2)
bVec2 = bVec2c ? bVec2 : \
(maxTR > 1) ? srchSuper.MAnalyse( isb=true, delta=2, blksize=BlockSize, overlap=Overlap, search=Search, searchparam=SearchParam, \
pelsearch=PelSearch, truemotion=TrueMotion, lambda=Lambda, lsad=LSAD, pnew=PNew, plevel=PLevel, \
global=GlobalMotion, DCT=DCT, chroma=ChromaMotion, badSAD=3200, mt=bomt ) : nop()
bVec2 = bVec2c || !RefineMotion || !(maxTR > 1) ? bVec2 : srchSuper.MRecalculate(bVec2, overlap=halfoverlap, blksize=halfblksize, thSAD=halfthSAD, DCT=DCT, \
chroma=ChromaMotion, truemotion=TrueMotion, search=Search, \
searchparam=SearchParam, lambda=Lambda, pnew=PNew, mt=bomt)
bVec1c = IsClip(bVec1)
bVec1 = bVec1c ? bVec1 : \
(maxTR > 0) ? srchSuper.MAnalyse( isb=true, delta=1, blksize=BlockSize, overlap=Overlap, search=Search, searchparam=SearchParam, \
pelsearch=PelSearch, truemotion=TrueMotion, lambda=Lambda, lsad=LSAD, pnew=PNew, plevel=PLevel, \
global=GlobalMotion, DCT=DCT, chroma=ChromaMotion, badSAD=3200, mt=bomt ) : nop()
bVec1 = bVec1c || !RefineMotion || !(maxTR > 0) ? bVec1 : srchSuper.MRecalculate(bVec1, overlap=halfoverlap, blksize=halfblksize, thSAD=halfthSAD, DCT=DCT, \
chroma=ChromaMotion, truemotion=TrueMotion, search=Search, \
searchparam=SearchParam, lambda=Lambda, pnew=PNew, mt=bomt)
fVec1c = IsClip(fVec1)
fVec1 = fVec1c ? fVec1 : \
(maxTR > 0) ? srchSuper.MAnalyse( isb=false, delta=1, blksize=BlockSize, overlap=Overlap, search=Search, searchparam=SearchParam, \
pelsearch=PelSearch, truemotion=TrueMotion, lambda=Lambda, lsad=LSAD, pnew=PNew, plevel=PLevel, \
global=GlobalMotion, DCT=DCT, chroma=ChromaMotion, badSAD=3200, mt=bomt ) : nop()
fVec1 = fVec1c || !RefineMotion || !(maxTR > 0) ? fVec1 : srchSuper.MRecalculate(fVec1, overlap=halfoverlap, blksize=halfblksize, thSAD=halfthSAD, DCT=DCT, \
chroma=ChromaMotion, truemotion=TrueMotion, search=Search, \
searchparam=SearchParam, lambda=Lambda, pnew=PNew, mt=bomt)
fVec2c = IsClip(fVec2)
fVec2 = fVec2c ? fVec2 : \
(maxTR > 1) ? srchSuper.MAnalyse( isb=false, delta=2, blksize=BlockSize, overlap=Overlap, search=Search, searchparam=SearchParam, \
pelsearch=PelSearch, truemotion=TrueMotion, lambda=Lambda, lsad=LSAD, pnew=PNew, plevel=PLevel, \
global=GlobalMotion, DCT=DCT, chroma=ChromaMotion, badSAD=3200, mt=bomt ) : nop()
fVec2 = fVec2c || !RefineMotion || !(maxTR > 1) ? fVec2 : srchSuper.MRecalculate(fVec2, overlap=halfoverlap, blksize=halfblksize, thSAD=halfthSAD, DCT=DCT, \
chroma=ChromaMotion, truemotion=TrueMotion, search=Search, \
searchparam=SearchParam, lambda=Lambda, pnew=PNew, mt=bomt)
fVec3c = IsClip(fVec3)
fVec3 = fVec3c ? fVec3 : \
(maxTR > 2) ? srchSuper.MAnalyse( isb=false, delta=3, blksize=BlockSize, overlap=Overlap, search=Search, searchparam=SearchParam, \
pelsearch=PelSearch, truemotion=TrueMotion, lambda=Lambda, lsad=LSAD, pnew=PNew, plevel=PLevel, \
global=GlobalMotion, DCT=DCT, chroma=ChromaMotion, badSAD=3200, mt=bomt ) : nop()
fVec3 = fVec3c || !RefineMotion || !(maxTR > 2) ? fVec3 : srchSuper.MRecalculate(fVec3, overlap=halfoverlap, blksize=halfblksize, thSAD=halfthSAD, DCT=DCT, \
chroma=ChromaMotion, truemotion=TrueMotion, search=Search, \
searchparam=SearchParam, lambda=Lambda, pnew=PNew, mt=bomt)
fVec4c = IsClip(fVec4)
fVec4 = fVec4c ? fVec4 : \
(maxTR > 3) ? srchSuper.MAnalyse( isb=false, delta=4, blksize=BlockSize, overlap=Overlap, search=Search, searchparam=SearchParam, \
pelsearch=PelSearch, truemotion=TrueMotion, lambda=Lambda, lsad=LSAD, pnew=PNew, plevel=PLevel, \
global=GlobalMotion, DCT=DCT, chroma=ChromaMotion, badSAD=3200, mt=bomt ) : nop()
fVec4 = fVec4c || !RefineMotion || !(maxTR > 3) ? fVec4 : srchSuper.MRecalculate(fVec4, overlap=halfoverlap, blksize=halfblksize, thSAD=halfthSAD, DCT=DCT, \
chroma=ChromaMotion, truemotion=TrueMotion, search=Search, \
searchparam=SearchParam, lambda=Lambda, pnew=PNew, mt=bomt)
fVec5c = IsClip(fVec5)
fVec5 = fVec5c ? fVec5 : \
(maxTR > 4) ? srchSuper.MAnalyse( isb=false, delta=5, blksize=BlockSize, overlap=Overlap, search=Search, searchparam=SearchParam, \
pelsearch=PelSearch, truemotion=TrueMotion, lambda=Lambda, lsad=LSAD, pnew=PNew, plevel=PLevel, \
global=GlobalMotion, DCT=DCT, chroma=ChromaMotion, badSAD=3200, mt=bomt ) : nop()
fVec5 = fVec5c || !RefineMotion || !(maxTR > 4) ? fVec5 : srchSuper.MRecalculate(fVec5, overlap=halfoverlap, blksize=halfblksize, thSAD=halfthSAD, DCT=DCT, \
chroma=ChromaMotion, truemotion=TrueMotion, search=Search, \
searchparam=SearchParam, lambda=Lambda, pnew=PNew, mt=bomt)
fVec6c = IsClip(fVec6)
fVec6 = fVec6c ? fVec6 : \
(maxTR > 5) ? srchSuper.MAnalyse( isb=false, delta=6, blksize=BlockSize, overlap=Overlap, search=Search, searchparam=SearchParam, \
pelsearch=PelSearch, truemotion=TrueMotion, lambda=Lambda, lsad=LSAD, pnew=PNew, plevel=PLevel, \
global=GlobalMotion, DCT=DCT, chroma=ChromaMotion, badSAD=3200, mt=bomt ) : nop()
fVec6 = fVec6c || !RefineMotion || !(maxTR > 5) ? fVec6 : srchSuper.MRecalculate(fVec6, overlap=halfoverlap, blksize=halfblksize, thSAD=halfthSAD, DCT=DCT, \
chroma=ChromaMotion, truemotion=TrueMotion, search=Search, \
searchparam=SearchParam, lambda=Lambda, pnew=PNew, mt=bomt)
# Expose search clip, motion search super clip and motion vectors to calling script through globals
QTGMC_SetUserGlobal( GlobalNames, "srchClip", srchClip, ReplaceGlobals )
QTGMC_SetUserGlobal( GlobalNames, "srchSuper", srchSuper, ReplaceGlobals )
QTGMC_SetUserGlobal( GlobalNames, "bVec1", bVec1, ReplaceGlobals )
QTGMC_SetUserGlobal( GlobalNames, "fVec1", fVec1, ReplaceGlobals )
QTGMC_SetUserGlobal( GlobalNames, "bVec2", bVec2, ReplaceGlobals )
QTGMC_SetUserGlobal( GlobalNames, "fVec2", fVec2, ReplaceGlobals )
QTGMC_SetUserGlobal( GlobalNames, "bVec3", bVec3, ReplaceGlobals )
QTGMC_SetUserGlobal( GlobalNames, "fVec3", fVec3, ReplaceGlobals )
QTGMC_SetUserGlobal( GlobalNames, "bVec4", bVec4, ReplaceGlobals )
QTGMC_SetUserGlobal( GlobalNames, "fVec4", fVec4, ReplaceGlobals )
QTGMC_SetUserGlobal( GlobalNames, "bVec5", bVec5, ReplaceGlobals )
QTGMC_SetUserGlobal( GlobalNames, "fVec5", fVec5, ReplaceGlobals )
QTGMC_SetUserGlobal( GlobalNames, "bVec6", bVec6, ReplaceGlobals )
QTGMC_SetUserGlobal( GlobalNames, "fVec6", fVec6, ReplaceGlobals )
#---------------------------------------
# Noise Processing
# >>>> Interleaved YUY2 for denoising, planar whilst pre-motion compensating
# Expand fields to full frame size before extracting noise (allows use of motion vectors which are frame-sized)
fullClip = (NoiseProcess == 0) ? nop() : \
(InputType > 0) ? clip : \
clip.sh_Bob( 0, 1.0 )
fullClip = (yuy2 && NoiseTR > 0) ? fullClip.nonyuy2clipin(true) : fullClip
fullSuper = (NoiseTR > 0) ? fullClip.MSuper( pel=SubPel, levels=1, hpad=hpad, vpad=vpad, chroma=ChromaNoise, mt=bomt ) : nop() #TEST chroma OK?
# Create a motion compensated temporal window around current frame and use to guide denoisers
noiseWindow = (NoiseProcess == 0) ? nop() : \
(!DenoiseMC) ? fullClip : \
(NoiseTR == 0) ? fullClip : \
(NoiseTR == 1) ? Interleave( fullClip.MCompensate( fullSuper, fVec1, thSCD1=ThSCD1,thSCD2=ThSCD2, mt=bomt ), \
fullClip, \
fullClip.MCompensate( fullSuper, bVec1, thSCD1=ThSCD1,thSCD2=ThSCD2, mt=bomt ) ) : \
Interleave( fullClip.MCompensate( fullSuper, fVec2, thSCD1=ThSCD1,thSCD2=ThSCD2, mt=bomt ), \
fullClip.MCompensate( fullSuper, fVec1, thSCD1=ThSCD1,thSCD2=ThSCD2, mt=bomt ), \
fullClip, \
fullClip.MCompensate( fullSuper, bVec1, thSCD1=ThSCD1,thSCD2=ThSCD2, mt=bomt ), \
fullClip.MCompensate( fullSuper, bVec2, thSCD1=ThSCD1,thSCD2=ThSCD2, mt=bomt ) )
noiseWindow = yuy2 && (Denoiser == "fft3df") && NoiseTR > 0 ? noiseWindow.nonyuy2clipout(true) : noiseWindow
noiseWindow = (NoiseProcess != 0) && n16d ? noiseWindow.ConvertBits(16,fulls=fs) : noiseWindow
dnWindow = (NoiseProcess == 0) ? nop() : \
(Denoiser == "dfttest") ? noiseWindow.dfttest( Y=true, U=ChromaNoise, V=ChromaNoise, sigma=Sigma*4, tbsize=noiseTD, threads=1, Dither=1 ) : \
(Denoiser == "KNLMeansCL") ? noiseWindow.ex_KNLMeansCL(Chroma=ChromaNoise, a=2, d=NoiseTR, h=Sigma, device_type=device_type, device_id=device_id ) : \
noiseWindow.FFT3DFilter( sigma=Sigma, bt=noiseTD, ncpu=Threads, plane=ChromaNoise ? 3 : 0)
dnwindow = (Denoiser == "KNLMeansCL" || Denoiser == "dfttest") && (NoiseProcess != 0) && yuy2 ? dnWindow.nonyuy2clipout(true) : dnWindow
dnwindow = (NoiseProcess != 0) && n16d ? dnwindow.ConvertBits(bi,dither=-1,fulls=fs) : dnwindow
# Rework denoised clip to match source format - various code paths here: discard the motion compensation window, discard doubled lines (from point resize)
# 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)
denoised = (NoiseProcess == 0) ? nop() : \
(!DenoiseMC) ? ((InputType > 0) ? dnWindow : dnWindow.SeparateFields().SelectEvery( 4, 0,3 ).Weave()) : \
(InputType > 0) ? ((NoiseTR == 0) ? dnWindow : dnWindow.SelectEvery( noiseTD, NoiseTR )) : \
dnWindow.SeparateFields().SelectEvery( noiseTD*4, NoiseTR*2,NoiseTR*6+3 ).Weave()
# >>>> Switch to planar YUY2 for noise bypass
CNmt1 = ChromaNoise ? 3 : 1
CNmt2 = ChromaNoise ? 3 : 2
CNmt128 = ChromaNoise ? 3 : 128
# Get actual noise from difference. Then 'deinterlace' where we have weaved noise - create the missing lines of noise in various ways
planarDenoised = (NoiseProcess == 0) ? nop() : yuy2 ? denoised.nonyuy2clipin(true) : denoised
noise = (totalRestore > 0.0) ? ex_makediff( planarClip, planarDenoised, UV=CNmt1, fulls=fs ) : nop()
deintNoise = (NoiseProcess == 0 || totalRestore == 0.0) ? nop() : \
(InputType != 0) ? noise : \
(NoiseDeint == "Bob") ? noise.sh_Bob( 0,0.5 ) : \
(NoiseDeint == "Generate") ? noise.QTGMC_Generate2ndFieldNoise( denoised, ChromaNoise, fs) : \
noise.DoubleWeave()
# Motion-compensated stabilization of generated noise
noiseSuper = (StabilizeNoise) ? deintNoise.MSuper( pel=SubPel, sharp=SubPelInterp, levels=1, hpad=hpad, vpad=vpad, chroma=ChromaNoise, mt=bomt ) : nop()
mcNoise = (StabilizeNoise) ? deintNoise.MCompensate( noiseSuper, bVec1, thSCD1=ThSCD1, thSCD2=ThSCD2, mt=bomt ) : nop()
finalNoise = (StabilizeNoise) ? ex_lutxy( deintNoise, mcNoise, "x range_half - abs y range_half - abs > x y ? 0.600001 * x y + 0.200001 * +", UV=CNmt1, fulls=fs ) : deintNoise
# 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
innerClip = (NoiseProcess == 1) ? denoised : clip
#---------------------------------------
# Interpolation
# >>>> Interleaved YUY2 for interpolation
# Support badly deinterlaced progressive content - drop half the fields and reweave to get 1/2fps interlaced stream appropriate for QTGMC processing
ediInput = (InputType == 2 || InputType == 3) ? innerClip.SeparateFields().SelectEvery(4,0,3).Weave() : innerClip
# Create interpolated image as starting point for output
edi1 = Defined(EdiExt) ? EdiExt.PointResize( w,h, 0,(EdiExt.Height()-h)/2, -0,h+eps ) : \
QTGMC_Interpolate( ediInput, InputType, EdiMode, NNSize, NNeurons, EdiQual, EdiMaxD, Threads, bobbed, ChromaEdi, fulls=fs )
# >>>> Switch to planar YUY2 during next step - remains planar until very end of script except blurring for back blending & SVThin
# 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
inputTypeBlend = (ProgSADMask > 0.0) ? MMask( srchClip, bVec1, kind=1, ml=ProgSADMask ) : nop()
edi = (InputType != 2 && InputType != 3) ? (!yuy2 ? edi1 : edi1.nonyuy2clipin(true)) : \
(ProgSADMask <= 0.0) ? (!yuy2 ? edi1.MergeChroma( innerClip ) : edi1.MergeChroma( innerClip ).nonyuy2clipin(true)) : \
(!yuy2 ? mt_merge( innerClip, edi1, inputTypeBlend, U=2,V=2 ) : \
mt_merge( innerClip.nonyuy2clipin(true), edi1.nonyuy2clipin(true), inputTypeBlend, U=2,V=2 ))
# Get the max/min value for each pixel over neighboring motion-compensated frames - used for temporal sharpness limiting
ediSuper = (TR1 > 0 || temporalSL) ? edi.MSuper( pel=SubPel, sharp=SubPelInterp, levels=1, hpad=hpad, vpad=vpad, mt=bomt ) : nop()
bComp1 = (temporalSL) ? edi.MCompensate( ediSuper, bVec1, thSCD1=ThSCD1,thSCD2=ThSCD2, mt=bomt ) : nop()
fComp1 = (temporalSL) ? edi.MCompensate( ediSuper, fVec1, thSCD1=ThSCD1,thSCD2=ThSCD2, mt=bomt ) : nop()
tMax = (temporalSL) ? edi.ex_lutxyz( fComp1, bComp1, "x y max z max", UV=3, fulls=fs ) : nop()
tMin = (temporalSL) ? edi.ex_lutxyz( fComp1, bComp1, "x y min z min", UV=3, fulls=fs ) : nop()
bComp3 = (SLRad > 1 && temporalSL) ? edi.MCompensate( ediSuper, bVec3, thSCD1=ThSCD1,thSCD2=ThSCD2, mt=bomt ) : nop()
fComp3 = (SLRad > 1 && temporalSL) ? edi.MCompensate( ediSuper, fVec3, thSCD1=ThSCD1,thSCD2=ThSCD2, mt=bomt ) : nop()
tMax = (SLRad > 1 && temporalSL) ? tMax.ex_lutxyz( fComp3, bComp3, "x y max z max", UV=3, fulls=fs ) : tMax
tMin = (SLRad > 1 && temporalSL) ? tMin.ex_lutxyz( fComp3, bComp3, "x y min z min", UV=3, fulls=fs ) : tMin
sMDegnl = n16 ? ", out16=n16" : ""
#---------------------------------------
# Create basic output
# Use motion vectors to blur interpolated image (edi) with motion-compensated previous and next frames. As above, this is done to remove shimmer from
# alternate frames so the same binomial kernels are used. However, by using motion-compensated smoothing this time we avoid motion blur. The use of
# MDegrain1 (motion compensated) rather than TemporalSmooth makes the weightings *look* different, but they evaluate to the same values
# Create linear weightings of neighbors first -2 -1 0 1 2
degrain1 = (TR1 > 0) ? Eval("edi.MDegrain1( ediSuper, bVec1,fVec1, thSAD=ThSAD1, thSCD1=ThSCD1,thSCD2=ThSCD2,mt=bomt" + sMDegnl + ")") : nop() # 0.00 0.33 0.33 0.33 0.00
degrain2 = (TR1 > 1) ? Eval("edi.MDegrain1( ediSuper, bVec2,fVec2, thSAD=ThSAD1, thSCD1=ThSCD1,thSCD2=ThSCD2,mt=bomt" + sMDegnl + ")") : nop() # 0.33 0.00 0.33 0.00 0.33
degrain1 = (TR1 > 0) ? n16 ? degrain1.ConvertBits(8,dither=-1,fulls=fs) : degrain1 : degrain1
degrain2 = (TR1 > 1) ? n16 ? degrain2.ConvertBits(8,dither=-1,fulls=fs) : degrain2 : degrain2
# Combine linear weightings to give binomial weightings - TR1=0: (1), TR1=1: (1:2:1), TR1=2: (1:4:6:4:1) # * uh! this is more like (1:3:12:3:1)
binomial1 = (TR1 == 0) ? edi : \
(TR1 == 1) ? degrain1.Merge( edi, 0.25 ) : \
ex_lutxyz(degrain1,degrain2,edi,"x 0.750001 * y 0.187501 * z 0.062501 * + +", UV=3)
# Remove areas of difference between smoothed image and interpolated image that are not bob-shimmer fixes: repairs residual motion blur from temporal smooth
repair1 = (Rep1 == 0) ? binomial1 : binomial1.QTGMC_KeepOnlyBobShimmerFixes( edi, Rep1, RepChroma, fs )
# Apply source match - use difference between output and source to succesively refine output [extracted to function to clarify main code path]
match = (SourceMatch == 0) ? repair1 : \
repair1.QTGMC_ApplySourceMatch( InputType, ediInput, bVec1,fVec1, bVec2,fVec2, SubPel, SubPelInterp, hpad, vpad, \
ThSAD1, ThSCD1, ThSCD2, SourceMatch, MatchTR1, MatchEdi, MatchNNSize, MatchNNeurons, \
MatchEdiQual, MatchEdiMaxD, MatchTR2, MatchEdi2, MatchNNSize2, MatchNNeurons2, MatchEdiQual2, \
MatchEdiMaxD2, MatchEnhance, Threads, n16, bomt, fs )
# Lossless=2 - after preparing an interpolated, de-shimmered clip, restore the original source fields into it and clean up any artefacts.
# 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.
# However, it can introduce minor combing. This setting is best used together with source-match (it's effectively the final source-match stage).
lossed1 = (Lossless == 2) ? QTGMC_MakeLossless( match, innerClip, InputType, fs ) : match
#---------------------------------------
# Resharpen / retouch output (rework resharp and sharpLimit1 and 2 to skip chroma and add a final chroma recovery option?)
# Resharpen to counteract temporal blurs. Little sharpening needed for source-match mode since it has already recovered sharpness from source
vresharp1 = (SMode == 2) ? Merge( lossed1.mt_expand( mode="vertical", U=3,V=3 ), lossed1.mt_inpand( mode="vertical", U=3,V=3 ) ) : nop()
vresharp = (Precise && SMode == 2) ? vresharp1.ex_lutxy( lossed1, "x y < x 1 scalef + x y > x 1 scalef - x ? ?", UV=3, fulls=fs ) : vresharp1 # Precise mode: reduce tiny overshoot
resharp = (SMode == 0) ? lossed1 : \
(SMode == 1) ? lossed1.ex_lutxy( lossed1.RemoveGrain( 12 ), "x dup y - "+ string(sharpAdj) + " * +", UV=3, fulls=fs ) : \
lossed1.ex_lutxy( vresharp.RemoveGrain( 12 ), "x dup y - "+ string(sharpAdj) + " * +", UV=3, fulls=fs )
# Slightly thin down 1-pixel high horizontal edges that have been widened into neigboring field lines by the interpolator
SVThinSc = SVThin * 6.0
vertMedD = (SVthin > 0.0) ? ex_lutxy( lossed1, lossed1.ex_median(mode="vertical", UV=1), Format("y x - {SVThinSc} * range_half +"), clamp_float=true, UV=1, fulls=fs ) : nop()
vertMedD = (SVthin > 0.0) ? (vertMedD.ex_boxblur( 1, 0, "weighted", UV=1 )) : nop()
thin = (SVthin > 0.0) ? ex_lutxyz( vertMedD, vertMedD.RemoveGrain( 12, -1 ), resharp, "y range_half - abs x range_half - abs > y range_half ? z + range_half -", UV=2, fulls=fs ) : resharp
# Back blend the blurred difference between sharpened & unsharpened clip, before (1st) sharpness limiting (Sbb == 1,3). A small fidelity improvement
backBlend1 = (Sbb != 1 && Sbb != 3) ? thin : \
thin.ex_makediff( ex_makediff( thin, lossed1, UV=1, fulls=fs ).ex_GaussianBlur(1.35, UV=1), UV=2, fulls=fs )
# Limit over-sharpening by clamping to neighboring (spatial or temporal) min/max values in original
# Occurs here (before final temporal smooth) if SLMode == 1,2. This location will restrict sharpness more, but any artefacts introduced will be smoothed
sharpLimit1 = (SLMode == 1) ? backBlend1.Repair( ((SLrad <= 1) ? edi : backBlend1.Repair( edi, 12, 12 )), 1, 1 ) : \
(SLMode == 2) ? backBlend1.ex_clamp( tMax, tMin, Sovs,Sovs, UV=3, fulls=fs ) : \
backBlend1
# Back blend the blurred difference between sharpened & unsharpened clip, after (1st) sharpness limiting (Sbb == 2,3). A small fidelity improvement
backBlend2 = (Sbb < 2) ? sharpLimit1 : \
sharpLimit1.ex_makediff( ex_makediff( sharpLimit1, lossed1, UV=1, fulls=fs ).ex_GaussianBlur(1.35, UV=1), UV=2, fulls=fs )
# Add back any extracted noise, prior to final temporal smooth - this will restore detail that was removed as "noise" without restoring the noise itself
# Average luma of FFT3DFilter extracted noise is 128.5, so deal with that too
addNoise1 = (GrainRestore <= 0.0) ? backBlend2 : \
backBlend2.ex_lutxy( finalNoise, Format("y {noiseCentre} - {GrainRestore} * x +"), UV=CNmt2, fulls=fs )
# Final light linear temporal smooth for denoising
stableSuper = (TR2 > 0) ? addNoise1.MSuper( pel=SubPel, sharp=SubPelInterp, levels=1, hpad=hpad, vpad=vpad, mt=bomt ) : nop()
stable = (TR2 == 0) ? addNoise1 : \
(TR2 == 1) ? Eval("addNoise1.MDegrain1( stableSuper, bVec1,fVec1, thSAD=ThSAD2, thSCD1=ThSCD1,thSCD2=ThSCD2,mt=bomt" + sMDegnl + ")") : \
(TR2 == 2) ? Eval("addNoise1.MDegrain2( stableSuper, bVec1,fVec1, bVec2,fVec2, thSAD=ThSAD2, thSCD1=ThSCD1,thSCD2=ThSCD2,mt=bomt" + sMDegnl + ")") : \
(TR2 == 3) ? Eval("addNoise1.MDegrain3( stableSuper, bVec1,fVec1, bVec2,fVec2, bVec3,fVec3, thSAD=ThSAD2, thSCD1=ThSCD1,thSCD2=ThSCD2,mt=bomt" + sMDegnl + ")") : \
(TR2 == 4) ? Eval("addNoise1.MDegrain4( stableSuper, bVec1,fVec1, bVec2,fVec2, bVec3,fVec3, bVec4,fVec4, thSAD=ThSAD2, thSCD1=ThSCD1,thSCD2=ThSCD2,mt=bomt" + sMDegnl + ")") : \
(TR2 == 5) ? Eval("addNoise1.MDegrain5( stableSuper, bVec1,fVec1, bVec2,fVec2, bVec3,fVec3, bVec4,fVec4, bVec5,fVec5, thSAD=ThSAD2, thSCD1=ThSCD1,thSCD2=ThSCD2,mt=bomt" + sMDegnl + ")") : \
Eval("addNoise1.MDegrain6( stableSuper, bVec1,fVec1, bVec2,fVec2, bVec3,fVec3, bVec4,fVec4, bVec5,fVec5, bVec6,fVec6, thSAD=ThSAD2, thSCD1=ThSCD1,thSCD2=ThSCD2,mt=bomt" + sMDegnl + ")")
stable = (TR2 > 0) ? n16 ? stable.ConvertBits(8,dither=-1,fulls=fs) : stable : stable
# Remove areas of difference between final output & basic interpolated image that are not bob-shimmer fixes: repairs motion blur caused by temporal smooth
repair2 = (Rep2 == 0) ? stable : stable.QTGMC_KeepOnlyBobShimmerFixes( edi, Rep2, RepChroma, fs )
# Limit over-sharpening by clamping to neighboring (spatial or temporal) min/max values in original
# Occurs here (after final temporal smooth) if SLMode == 3,4. Allows more sharpening here, but more prone to introducing minor artefacts
sharpLimit2 = (SLMode == 3) ? repair2.Repair( ((SLrad <= 1) ? edi : repair2.Repair( edi, 12, 12 )), 1, 1 ) : \
(SLMode == 4) ? repair2.ex_clamp( tMax,tMin, Sovs,Sovs, UV=3, fulls=fs ) : \
repair2
# 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
# properly lossless, but this will retain source artefacts and cause some combing (where the smoothed deinterlace doesn't quite match the source)
lossed2 = (Lossless == 1) ? QTGMC_MakeLossless( sharpLimit2, innerClip, InputType, fs ) : sharpLimit2
# Add back any extracted noise, after final temporal smooth. This will appear as noise/grain in the output
# Average luma of FFT3DFilter extracted noise is 128.5, so deal with that too
addNoise2 = (NoiseRestore <= 0.0) ? lossed2 : \
lossed2.ex_lutxy( finalNoise, Format("y {noiseCentre} - {NoiseRestore} * 0 range_max clip x +"), UV=CNmt2, fulls=fs )
#---------------------------------------
# Post-Processing
# Shutter motion blur - get level of blur depending on output framerate and blur already in source
blurLevel = (ShutterAngleOut * FPSDivisor - ShutterAngleSrc) * 100.0 / 360.0
Assert( blurLevel >= 0, "Cannot reduce motion blur already in source: increase ShutterAngleOut or FPSDivisor" )
Assert( blurLevel <= 200, "Exceeded maximum motion blur level: decrease ShutterAngleOut or FPSDivisor" )
# ShutterBlur mode 2,3 - get finer resolution motion vectors to reduce blur "bleeding" into static areas
rBlockDivide = Select( ShutterBlur, 1, 1, 2, 4 )
rBlockSize = BlockSize / rBlockDivide
rOverlap = Overlap / rBlockDivide
rBlockSize = (rBlockSize < 4) ? 4 : rBlockSize
rOverlap = (rOverlap < 2) ? 2 : rOverlap
rBlockDivide = BlockSize / rBlockSize
rLambda = Lambda / (rBlockDivide * rBlockDivide)
sbBVec1 = (ShutterBlur > 1) ? srchSuper.MRecalculate( bVec1, thSAD=ThSAD1, blksize=rBlockSize, overlap=rOverlap, search=Search, searchparam=SearchParam, \
truemotion=TrueMotion, lambda=Lambda, pnew=PNew, DCT=DCT, chroma=ChromaMotion, mt=bomt ) : bVec1
sbFVec1 = (ShutterBlur > 1) ? srchSuper.MRecalculate( fVec1, thSAD=ThSAD1, blksize=rBlockSize, overlap=rOverlap, search=Search, searchparam=SearchParam, \
truemotion=TrueMotion, lambda=Lambda, pnew=PNew, DCT=DCT, chroma=ChromaMotion, mt=bomt ) : fVec1
# Shutter motion blur - use MFlowBlur to blur along motion vectors
sblurSuper = (ShutterBlur > 0) ? addNoise2.MSuper( pel=SubPel, sharp=SubPelInterp, levels=1, hpad=hpad, vpad=vpad, mt=bomt ) : nop()
sblur = (ShutterBlur > 0) ? addNoise2.MFlowBlur( sblurSuper, sbBVec1, sbFVec1, blur=blurLevel, thSCD1=ThSCD1,thSCD2=ThSCD2 ) : nop()
# 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
sbMotionMask = (ShutterBlur > 0 && SBlurLimit > 0) ? MMask( srchClip, bVec1, kind=0, ml=SBlurLimit ) : nop()
sblurred = (ShutterBlur == 0) ? addNoise2 : \
(SBlurLimit == 0) ? sblur : \
mt_merge( addNoise2, sblur, sbMotionMask, U=3,V=3 )
# Reduce frame rate
decimated = (FPSDivisor != 1) ? sblurred.SelectEvery( FPSDivisor, 0 ) : sblurred
# Crop off temporary vertical padding
cropped = Border ? decimated.Crop( 0, 4, -0, -4, true ) : decimated
h = Border ? h-8 : h
# Show output of choice + settings
# >>>> Restore YUY2 to interleaved
output = (ShowNoise == 0.0) ? cropped : finalNoise.ex_lut( "x range_half - " + string(ShowNoise) + " * range_half +", clamp_float=true, UV=CNmt128, fulls=fs )
output = yuy2 ? output.nonyuy2clipout(true) : output
return (ShowSettings == false) ? output : \
output.Subtitle( "TR0=" + string(TR0) + " | TR1=" + string(TR1) + " | TR2=" + string(TR2) + " | Rep0=" + string(Rep0) + " | Rep1=" + string(Rep1) + \
" | Rep2=" + string(Rep2) + " | RepChroma=" + string(RepChroma) + "\nEdiMode='" + EdiMode + "' | NNSize=" + string(NNSize) + " | NNeurons=" + \
string(NNeurons) + " | EdiQual=" + string(EdiQual) + " | EdiMaxD=" + string(EdiMaxD) + " | ChromaEdi='" + ChromaEdi + "' | Threads=" + \
string(Threads) + "\nSharpness=" + string(Sharpness, "%.2f") + " | SMode=" + string(SMode) + " | SLMode=" + string(SLMode) + " | SLRad=" + \
string(SLRad) + " | SOvs=" + string(SOvs) + " | SVThin=" + string(SVThin, "%.2f") + " | Sbb=" + string(Sbb) + "\nSrchClipPP=" + string(SrchClipPP) + \
" | SubPel=" + string(SubPel) + " | SubPelInterp=" + string(SubPelInterp) + " | BlockSize=" + string(BlockSize) + " | Overlap=" + string(Overlap) + \
"\nSearch=" + string(Search) + " | SearchParam=" + string(SearchParam) + " | PelSearch=" + string(PelSearch) + " | ChromaMotion=" + \
string(ChromaMotion) + " | TrueMotion=" + string(TrueMotion) + "\nLambda=" + string(Lambda) + " | LSAD=" + string(LSAD) + " | PNew=" + string(PNew) + \
" | PLevel=" + string(PLevel) + " | GlobalMotion=" + string(GlobalMotion) + " | DCT=" + string(DCT) + "\nThSAD1=" + string(ThSAD1) + " | ThSAD2=" + \
string(ThSAD2) + " | ThSCD1=" + string(ThSCD1) + " | ThSCD2=" + string(ThSCD2) + "\nSourceMatch=" + string(SourceMatch) + " | MatchPreset='" + \
MatchPreset + "' | MatchEdi='" + MatchEdi + "'\nMatchPreset2='" + MatchPreset2 + "' | MatchEdi2='" + MatchEdi2 + "' | MatchTR2=" + string(MatchTR2) + \
" | MatchEnhance=" + string(MatchEnhance, "%.2f") + " | Lossless=" + string(Lossless) + "\nNoiseProcess=" + string(NoiseProcess) + " | Denoiser='" + \
Denoiser + "' | DenoiseMC=" + string(DenoiseMC) + " | NoiseTR=" + string(NoiseTR) + " | Sigma=" + \
string(Sigma, "%.2f") + "\nChromaNoise=" + string(ChromaNoise) + " | ShowNoise=" + string(ShowNoise, "%.2f") + " | GrainRestore=" + \
string(GrainRestore, "%.2f") + " | NoiseRestore=" + string(NoiseRestore, "%.2f") + "\nNoiseDeint='" + NoiseDeint + "' | StabilizeNoise=" + \
string(StabilizeNoise) + " | InputType=" + string(InputType) + " | ProgSADMask=" + string(ProgSADMask, "%.2f") + "\nFPSDivisor=" + \
string(FPSDivisor) + " | ShutterBlur=" + string(ShutterBlur) + " | ShutterAngleSrc=" + string(ShutterAngleSrc, "%.2f") + " | ShutterAngleOut=" + \
string(ShutterAngleOut, "%.2f") + " | SBlurLimit=" + string(SBlurLimit) + "\nBorder=" + string(Border) + " | Precise=" + string(Precise) + \
"\nPreset='" + Preset + "' | Tuning='" + Tuning + "' | GlobalNames='" + GlobalNames + "' | PrevGlobals='" + PrevGlobals + "' | ForceTR=" + \
string(ForceTR), font="Lucida Console", size=11, lsp=12 )
}
#---------------------------------------
# Helpers
# 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
# 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
function QTGMC_Interpolate( clip Input, int InputType, string EdiMode, int NNSize, int NNeurons, int EdiQual, int EdiMaxD, int Threads, clip "Fallback", \
string "ChromaEdi", bool "fulls" )
{
# >>>> YUY2 is interleaved here
ChromaEdi = Default( ChromaEdi, "" )
CEed = (ChromaEdi == "")