VideoHelp Forum
+ Reply to Thread
Results 1 to 10 of 10
Thread
  1. Member hydra3333's Avatar
    Join Date
    Oct 2009
    Location
    Australia
    Search Comp PM
    Hello.

    Over at doom9 (I do not have an account there), there is a lovely avisynth+ procedure which tries to restore some detail back into a clip which had been processed by Spotless, i.e. usually used on "spotty/dirty" sources.

    The thread over on doom9 : https://forum.doom9.org/showthread.php?t=182831
    The code over on doom9 : https://forum.doom9.org/showthread.php?p=1946031#post1946031
    I turned a slight variation of this code into a function: https://forum.doom9.org/showthread.php?p=1947717#post1947717 so perhaps I did something wrong.

    I guess my source must be too terrible (it is, actually) and/or I'm using the wrong settings for Spotless and DeltaRestore (very likely that too).

    The input clip for the function, just to try-it-out, (after a some initial filtering) is attached (54Mb).
    Initial filtering:
    Code:
    Deblock_QED(quant1=24, quant2=26, aOff1=1, aOff2=1, bOff1=2, bOff2=2, uv=3)
    cropbottom(16)
    ReduceFlicker(strength=3,aggressive=True)
    bob(-.2,.6) # to roughly double-framerate deinterlace
    SRestore(frate=19.5,dclip=denoised_clip,speed=5,thresh=28,cache=20)
    ReduceFlicker(strength=3,aggressive=True).ReduceFlicker(strength=3,aggressive=True)
    AssumeFPS(18) # Super8 camera framerate

    I had hoped for "hair restoration" per the attached screenshot but alas to no avail.
    Image
    [Attachment 60122 - Click to enlarge]


    The Spotless/DeltaRestore settings I used (these below are for a wrapper function, but get passed through to SDR_Spotless_DeltaRestore):
    Code:
    	do_Spotless_DeltaRestore=True, sdr_RETURN_DEBUG_STACKED=True, sdr_RETURN_DEBUG_INTERLEAVED=False, \
    		sdr_RadT=3, sdr_BlkSz=12, sdr_OLap=6, sdr_Chroma=True, sdr_Pel=2, sdr_Tm=False, sdr_ThSAD=10000, sdr_ThSAD2=10000, \
    		sdr_Slog=True, sdr_Slog_border=80, \
    		sdr_Sharpen=True, sdr_Usharp_strength=80, sdr_Usharp_radius=5, sdr_Usharp_th=1, \
    		sdr_Rgr=False, \
    		sdr_use_RiskyBlur=True, \
    Has anyone used Spotless/DeltaRestore and may be willing to provide hints ?

    Thank you.

    Code:
    Function SDR_Spotless_DeltaRestore(		clip	"source", \
    										bool	"RETURN_DEBUG_STACKED", \
    										bool	"RETURN_DEBUG_INTERLEAVED", \
    										int		"txt_sz", \
    										bool	"do_sharpen", \
    										bool	"Slog", \
    										int		"Slog_border", \
    										bool	"Rgr", \
    										int		"Rgr_val1", \
    										int		"Rgr_val2", \
    										int		"Usharp_strength", \
    										int		"Usharp_radius", \
    										int		"Usharp_th", \
    										int		"BlkSz", \
    										int		"OLap", \
    										bool	"Chroma", \
    										int		"Pel", \
    										bool	"Tm", \
    										float	"Bblur", \
    										int		"ThSAD", \
    										int		"ThSAD2", \
    										int		"RadT", \
    										float	"dark2Brt", \
    										float	"dark2BrtLimit", \
    										bool	"use_RiskyBlur", \
    										int		"darkmask_binarize", \
    										int		"edgemask_binarize" \
    									) {
    	# ##############################################################################################
    	#
    	# NOTE: THIS FUNCTION IS 8-bit ONLY
    	#
    	#	On terrible Super8 sources, SDR_Spotless_DeltaRestore never made any difference to things
    	#	like hair etc and very little noticable difference to most of the other stuff.
    	#	That Super8 source is just so bad that the cost of SDR_Spotless_DeltaRestore is not worth it
    	#
    	#	Hence after testing, I choose to not use SDR_Spotless_DeltaRestore on "bad" Super8 sources.
    	#	Oh well, perhaps on "better" sources it will be great.
    	#
    	# ##############################################################################################
    	#
    	#	Dependencies:
    	#		AviSynth+ >= v3.70
    	#		Zs_RF_Shared.avsi
    	#		Utils-r41.avsi (perhaps)
    	#		masktools2.dll
    	#		mvtools2.dll
    	#		UnsharpMask_avsi.avsi
    	#		FastBlur.dll
    	#		Spotless (copy of function v1.07 included below)
    	#		I wish: GBlur (I could not find an x64 version)
    	#
    	# ##############################################################################################
    	#
    	/* Description :
    		per			https://forum.doom9.org/showthread.php?t=182831
    		per v1.0	https://forum.doom9.org/showthread.php?p=1946030#post1946030
    		per			https://forum.doom9.org/showthread.php?p=1947717#post1947717
    
    	Function_SDR_Spotless_DeltaRestore (SpotLess107+Delta Restore) 1.0
    
    	Script intended to clean and sharpen digitalized film.
    	Can optionally restore grain after cleaning.
    	Sharpening and denoising are basic. Please see doom9 forum, VideoFred's and JohnMeyer's scripts and posts fore more knowlege. (VideoFred's sharp-blur-sharp-blur-sharp trick). Please share improvements!
    
    	Functions: SpotLess107:StainlessS, Delta Restore:Zorr, Restore Grain:real.finder. Huge Thanks !
    	Script: chmars - 17/06/2021 - some parts copied here and there, thank to solutions given by doom9 forum users.
    	Thread: https://forum.doom9.org/showthread.php?t=182831
    	Spotless thread, last versions: https://forum.doom9.org/showthread.php?t=181777
    	Lots of informaions on film capture/restoration: https://forum.doom9.org/showthread.php?t=144271
    
    	Script tested on HD 4:2:2 10bits sources with Avisynth+370_x64
            !                   !                  !                   !                  !
    	-You should maybe adapt the sizes parameters (blksz, radiuses, spotsizes) if your source is not HD
            !                   !                  !                   !                  !
    
    	How it works:
    	Spotless removes dirt spots that are not present in neibourg frames.
    	But sometimes, fast moving objects are removed too (balloons, birds, hands, feet) 
    	Hence is Delta Restore needed. It brings back details that are part of the image.
    	As Spotless tends to soften/degrain the image, parts brought back from the original image by Delta Restore are more grainy.
    	The solution for a discreete replacement (and nicer result) of these parts is to sharpen the Spotless input.
     
    	For Washed out, Slog rushes:
    	Spotless seems to work as well with washed out images (old footage, Slog rushes), but Delta Restore needs colors and contrast to funtion properly. 
    	In this case, a more contrasted clip can be made to feed Delta Restore and only generate masks. However, the final result will not be graded.
    	*/
    	RETURN_DEBUG_STACKED		= default(RETURN_DEBUG_STACKED, False)		# to return the clip processed comparisons stacked
    	RETURN_DEBUG_INTERLEAVED	= default(RETURN_DEBUG_INTERLEAVED, False)	# to return the clip processed comparisons interleaved
    	txt_sz						= default(txt_sz, 36) 				# Test size if infos displayed
    	do_sharpen					= default(do_sharpen, True)			# Sharpen clip or not (recomanded, see intro)
    	# for Washed-Out-clips ----------------------------------------------------------------------------------------------------------------------------------------------------------
    	Slog						= default(Slog, False)				# If True, Generate a leveled clip for washed-out or Slog rushes. Final result will NOT be changed levelwise
    	Slog_border					= default(Slog_border, 8)			# number of pixels from each border edge to ignore in AutoLevels
    	# Grainitude, cancels sharpen effect ----------------------------------------------------------------------------------------------------------------------------------------------------------
    	Rgr							= default(Rgr, False)				# Default false. True Restores grain after passed through Spotless. Might restore some dust too. 5,10 = good compromise grain/dirt.
    	Rgr_val1					= default(Rgr_val1, 10)				# 5,10 = good compromise grain/dirt. Dunno how that works exactly... (script was 10)
    	Rgr_val2					= default(Rgr_val2, 20)				# 5,10 = good compromise grain/dirt. Dunno how that works exactly... (script was 20)
    	# Sharpen variables ----------------------------------------------------------------------------------------------------------------------------------------------------------
    	Usharp_strength				= default(Usharp_strength, 64)		# example was 80 ... Bigger = sharper & more grain. https://github.com/realfinder/AVS-Stuff/blob/Community/avs%202.5%20and%20up/UnsharpMask_avsi.avsi
    	Usharp_radius				= default(Usharp_radius, 3)			# example was 5
    	Usharp_th					= default(Usharp_th, 8)				# example was 1
    	# Spotless variables, to remove dirt and spots. -------------------------------------------------------------------------------------------------------------------------
    	# See Function script for more advanced settings
    	BlkSz						= default(BlkSz, 8)					# Spot Size, Default 8. Try 12 or 16 for big spots. MAnalyse BlkSize. Bigger blksz quicker and perhaps better for HD clips. [Info: current Pinterf MvTools allows for BlkSize=12, and overlap=6]
    	OLap						= default(OLap, Int(BlkSz/2))		# Spot Size, Default BlkSz/2, no less
    	Chroma						= Default(Chroma, True)				# use Chrome in Spotless ?
    	Pel							= default(Pel, 2)					# Default 2. 1, 2, or 4. Maybe set 1 for HD+. (1=precision to pixel, 2=half pixel, 4=quarter pixel)
    	Tm							= default(TM, False)				# TrueMotion Default True. Some folk swear truemotion=false is better.
    	Bblur						= default(Bblur, 0.6)				# Default 0.6. If used, Suggest about 0.6, where MAnalyse create vectors is performed on denoised (blurred) super clip for better motion analysis. 
    	ThSAD						= default(ThSAD, 10000)				# [SAD, Sum of Absolute (pixelwise) Differences]  Default 10000=NEARLY OFF(ie ignore hardly any bad blocks), 0 < ThSAD < 16320(8*8*255). 8x8 block SAD threshold at radius 1 (ie at current_frame +- 1)
    	ThSAD2						= default(ThSAD2, ThSAD)			# default ThSAD (10,000) standard spotless settings for this specific source
    	RadT						= default(RadT, 1)					# Removes Spots on up to RadT [Temporal Radius] consecutive frames. RadT > 2 will usually be overkill. Setting too high could possibly result in blurring.
    																	# Try RadT=3 for super8 double-framerate-deinterlaced stuff.
    																	# Each pixel in result frame is median pixel value of (2*RadT+1) motion compensated frames (including source, ie current_frame-RadT to current_frame+RadT).
    	edgemask_binarize			= default(edgemask_binarize, 52)	# used in edge mask creation
    	darkmask_binarize			= default(darkmask_binarize, 54)	# used in dark mask creation
    	# Delta Restore variables -------------------------------------------------------------------------------------------------------------------------
    	dark2Brt					= default(dark2Brt, 0.85)			#Default 0.97. Decrease if too many spots coming back 
    	dark2BrtLimit				= default(dark2BrtLimit, 0.86)		#Default 0.86. Same mask. Try to change it too.
    	Global RiskyBlur			= default(use_RiskyBlur, True)		#True = use fastblur and risk some glitches.    False = Use Gblur and go stable, at the price of a  slower script
    	#
    	########################################################################################################################
    	#
    	# Using:  https://forum.doom9.org/showthread.php?p=1947717#post1947717
    	#
    	########################################################################################################################
    	#
    	#Sharpen
    	source_shp = do_sharpen ? source.UnsharpMask_avsi(Usharp_strength,Usharp_radius,Usharp_th) : source
    	#SpotRemoved_shp=SpotRemoved.UnsharpMask_avsi(Usharp_strength,Usharp_radius,Usharp_th)
    	#
    	#Remove spots
    	spotless = SDR_SpotLess107(source_shp, blksz=BlkSz, OLap=OLap, Chroma=Chroma, Pel=pel, Tm=Tm, Bblur=Bblur, ThSAD=thsad, ThSAD2=ThSAD2, RadT=RadT) 	
    	#
    	filtered = spotless
    	#
    	#Level for masking only, not used as innput nor output----------------------------------------------------------------------
    	filtered_lvl = Slog ? filtered.Autolevels(filterradius=10, sceneChgThresh=20, autogamma=true, midpoint=0.5, autolevel=true, border=Slog_border)  : filtered
    	#
    	# luma mask - selects where source brightness > filtered brightness 
    	luma_mask = SDR_LumaDeltaMask(source, filtered_lvl, ">", brightness=1.1, spotSize=3).SDR_ExpandMask(3, blur=4)
    	#
    	# chroma mask - selects where source and filtered chromas have large enough difference (formula: sqrt(u*u + v*v))
    	chroma_mask = SDR_ChromaDeltaMask(source, filtered_lvl, delta=3, spotSize=3)
    	#
    	# suppression mask - selects where source brightness < filtered brightness
    	# suppression mask removes too dark areas from chroma mask 
    	suppression_mask = SDR_LumaDeltaMask(source, filtered_lvl, "<", brightness=0.9, spotSize=2)
    	suppressed_chroma_mask = chroma_mask.SDR_SuppressWith(suppression_mask)
    	#
    	# edge mask - detects sharp edges
    	# don't detect edges near the frame edges
    	edges = SDR_scharr(source).SDR_ZPadding(60, 14, 14, 10)		# magic numbers 60, 14, 14, 10
    	edgeMask = edges.mt_binarize(edgemask_binarize) 			# magic number 52
    	#
    	# chroma override mask - selects larger color deltas and spot sizes than plain chroma mask and is not suppressed
    	chroma_override = SDR_ChromaDeltaMask(source, filtered_lvl, delta=5, spotSize=6).SDR_ExpandMask(3, blur=2)
    	#
    	# dark mask: select both darker and lighter mask and keep dark mask if it is near lighter mask or overlaps chroma override mask
    	dark = SDR_LumaDeltaMask(source, filtered_lvl, "<", brightness=0.97, limitBrightness=0.66, spotSize=5)		# magic numbers
    	light = SDR_LumaDeltaMask(source, filtered_lvl, ">", brightness=1.04, spotSize=5).SDR_ZPadding(60, 14, 14, 10)	# magic numbers
    	dark_near_light = dark.SDR_MustBeNear(light, 28).SDR_ExpandMask(3, blur=4)
    	expanded = dark.SDR_MustBeNear(light, 28, expanded=true) # for debugging
    	#
    	# secondary dark mask - doesn't need to be near lighter area but has stricter limits
    	dark2 = SDR_LumaDeltaMask(source, filtered_lvl, "<", brightness=dark2Brt, limitBrightness=dark2BrtLimit, limitAbsBrightness=0.12, spotSize=5).SDR_ExpandMask(2, blur=2)
    	#
    	# edge test for dark areas
    	darkEdgeMask = edges.mt_binarize(darkmask_binarize) # at least 54 needed (for frame 222 in the original use case ... it may vary for different clips !)
    	darkEdgeAreaMask = mt_hysteresis(darkEdgeMask, dark_near_light.SDR_AddTo(dark2), chroma="-128")	# for debug
    	dark_final = SDR_DarkDeltaMask(dark_near_light, secondary=dark2, edgeMask=darkEdgeMask)
    	#
    	# remove mask areas where sharp edges were found (those are most likely dirt)
    	#combined_mask = luma_mask.SDR_AddTo(suppressed_chroma_mask).SDR_AddTo(chroma_override)
    	#edgeAreaMask = mt_hysteresis(edgeMask, combined_mask, chroma="-128")	# for debug
    	#
    	#~ Apply masks with unleveled clips to get a FINAL RESULT in delta_restore
    	#delta_restore = SDR_DeltaRestore(filtered, source_shp, luma=luma_mask, chroma=suppressed_chroma_mask, chromaOverride=chroma_override, edges=edgeMask, dark=dark_final)
    	delta_restore = SDR_DeltaRestore(filtered, source, luma=luma_mask, chroma=suppressed_chroma_mask, chromaOverride=chroma_override, edges=edgeMask, dark=dark_final)
    	# return delta_restore
    	#
    	# Perhaps Restore grain - cancels sharpen ?
    	restored = Rgr ? mRD_RestoreGrain(delta_restore, source, Rgr_val1, Rgr_val2) : delta_restore #5,10 = good compromise grain/dirt
    	#~ return(interleave(restored, source))
    	#
    	## -------------------------------------------------------------------------------------------------------------------------------------------------------------
    	## -------------------------------------------------------------------------------------------------------------------------------------------------------------
    	#
    	# If any DEBUGGING, then continue on, otherwise return the processed restored clip
    	#
    	not_debug = !(RETURN_DEBUG_STACKED || RETURN_DEBUG_INTERLEAVED)
    	if (not_debug){
    		return restored
    	}
    	#
    	# DEBUG DEBUG DEBUG DEBUG DEBUG DEBUG DEBUG DEBUG DEBUG DEBUG: 
    	# DEBUG DEBUG DEBUG DEBUG DEBUG DEBUG DEBUG DEBUG DEBUG DEBUG: 
    	#
    	diff1 = mt_makediff(spotless, restored, y=3, u=3, v=3)
    	diff2 = diff1.mt_adddiff(diff1, y=0, u=3, v=3)
    	diff2 = diff2.mt_adddiff(diff1, y=0, u=3, v=3)
    	diff = CombinePlanes(diff1, diff2, diff2, planes="YUV", source_planes="YUV", sample_clip=diff1)
    	#
    	if (RETURN_DEBUG_STACKED) {
    		# diff with exaggerated chroma difference
    		stack1 = StackHorizontal(SDR_sub(source, "source",txt_sz), SDR_sub(diff,"diff SpotLess107/Spotless107+Delta_Restore",txt_sz))
    		stack2 = StackHorizontal(SDR_sub(spotless, "SpotLess107", txt_sz), SDR_sub(restored, "Spotless107+Delta_Restore", txt_sz))
    		stacks = StackVertical(stack1, stack2)
    		return stacks
    	}
    	#
    	if (RETURN_DEBUG_INTERLEAVED) {
    		return Interleave(SDR_sub(source,"source",txt_sz), SDR_sub(spotless,"SpotLess107",txt_sz), SDR_sub(restored,"Spotless107+Delta_Restore",txt_sz), SDR_sub(diff,"diff SpotLess107/Spotless107+Delta_Restore",txt_sz))
    	}
    	#
    	Assert(False, "DEBUG: ERROR !! Check script to determine why DEBUG went past returning ...")
    }
    ## -------------------------------------------------------------------------------------------------------------------------------------------------------------
    ## -------------------------------------------------------------------------------------------------------------------------------------------------------------
    ## -------------------------------------------------------------------------------------------------------------------------------------------------------------
    ## -------------------------------------------------------------------------------------------------------------------------------------------------------------
    ## -------------------------------------------------------------------------------------------------------------------------------------------------------------
    ## -------------------------------------------------------------------------------------------------------------------------------------------------------------
    #~ FUNCTIONS
    ##########################################################################################################################
    #~ Delta Restore Functions
    ## -------------------------------------------------------------------------------------------------------------------------------------------------------------
    function SDR_sub(c, label, txt_sz) {
    	return subtitle(c, label, size = txt_sz, align=8)
    }
    ## -------------------------------------------------------------------------------------------------------------------------------------------------------------
    function SDR_DeltaRestore(clip filtered, clip source, clip "luma", clip "chroma", clip "chromaOverride", clip "edges", clip "dark") {
    	Assert(luma.Defined || chroma.Defined || chromaOverride.Defined || dark.Defined, "SDR_Spotless_DeltaRestore:  SDR_DeltaRestore:must define at least one of luma, chroma, chromaOverride, dark")
    
    	mask = default(luma, BlankClip(filtered))
    	if (chroma.Defined) {
    		mask = mask.SDR_AddTo(chroma)
    	}
    	if (chromaOverride.Defined) {
    		mask = mask.SDR_AddTo(chromaOverride)
    	}
    	if (edges.Defined) {
    		mask = mask.SDR_MustNotOverlap(edges)
    	}
    	if (dark.Defined) {
    		mask = mask.SDR_AddTo(dark)
    	}
    	return Overlay(filtered, source, mask=mask)
    }
    ## -------------------------------------------------------------------------------------------------------------------------------------------------------------
    function SDR_DarkDeltaMask(clip mask, clip "secondary", clip "edgeMask") {	
    	if (secondary.Defined) {
    		mask = mask.SDR_AddTo(secondary)
    	}
    	if (edgeMask.Defined) {
    		mask = mask.SDR_MustNotOverlap(edgeMask)
    	}
    	return mask
    }
    ## -------------------------------------------------------------------------------------------------------------------------------------------------------------
    function SDR_AddTo(clip mask, clip other) {
    	return mt_logic(mask, other, "or")
    }
    ## -------------------------------------------------------------------------------------------------------------------------------------------------------------
    function SDR_SuppressWith(clip mask, clip suppressionMask) {
    	return mt_lutxy(mask, suppressionMask, expr="x y -")
    }
    ## -------------------------------------------------------------------------------------------------------------------------------------------------------------
    function SDR_MustNotOverlap(clip mask, clip other) {
    	other = mt_hysteresis(other, mask, chroma="-128")
    	return mt_lutxy(mask, other, expr="x y -")
    }
    ## -------------------------------------------------------------------------------------------------------------------------------------------------------------
    function SDR_MustOverlap(clip mask, clip otherMask) {
    	return mt_logic(mask, mt_hysteresis(otherMask, mask), "and")
    }
    ## -------------------------------------------------------------------------------------------------------------------------------------------------------------
    function SDR_MustBeNear(clip mask, clip otherMask, int maxDistance, bool "expanded") {
    	expanded = default(expanded, false)
    
    	expand_amount = maxDistance / 2
    	mask_expanded = SDR_ExpandMask(mask, expand_amount)
    	other_expanded = SDR_ExpandMask(otherMask, maxDistance - expand_amount)
    	common = mt_logic(mask_expanded, other_expanded, "or")
    	if (expanded) {
    		return common
    	}
    	other_near = mt_hysteresis(otherMask, common)
    	return mt_logic(mask, other_near, "and")	
    }
    ## -------------------------------------------------------------------------------------------------------------------------------------------------------------
    function SDR_ZPadding(clip c, int left, int top, int right, int bottom) {
    	return c.Crop(left, top, -right, -bottom).AddBorders(left, top, right, bottom, color_yuv=$008080)
    }
    ## -------------------------------------------------------------------------------------------------------------------------------------------------------------
    function SDR_scharr(clip c) {
    	scharr_x = c.mt_edge("3 0 -3 10 0 -10 3 0 -3", thY1 = 0, thY2 = 255, y=3, u=1, v=1)
    	scharr_y = c.mt_edge("3 10 3 0 0 0 -3 -10 -3", thY1 = 0, thY2 = 255, y=3, u=1, v=1)
    	scharr = mt_lutxy(scharr_x, scharr_y, yexpr=mt_polish("((x*x)+(y*y))^0.5"), chroma="-127")
    	return scharr
    }
    
    function SDR_RemoveSmallSpots(clip mask, int spotSize) {
    	mask_orig = mask
    
    	# remove too small spots
    	for (i = 1, spotSize) {
    		mask = mask.mt_inpand()
    	}
    	mask = mt_hysteresis(mask, mask_orig, chroma="-127") 
    	return mask
    }
    ## -------------------------------------------------------------------------------------------------------------------------------------------------------------
    function SDR_LumaDeltaMask(clip source, clip filtered, string direction, float "brightness", float "limitBrightness", float "limitAbsBrightness", int "spotSize") {
    	# direction is ">" if you want mask to contain areas where source is brighter than filtered by "brightness", direction "<" selects where source is darker
    	# adjust brightness to change how bright objects are selected, typical values between 1.0 and 1.1, larger value = brighter object
    	# remove too bright or dark areas using limitBrightness
    	# spotSize controls the smallest spot size allowed in the mask, typical values between 0 and 3
    	brightness = default(brightness, 0.9)
    	spotSize   = default(spotSize, 2)
    	limitBrightness = default(limitBrightness, brightness)
    	limitAbsBrightness = default(limitAbsBrightness, 0.0)
    	# diff 
    	diff = Grayscale(mt_makediff(source, filtered))
    	# mask 
    	mask = mt_lut(diff, expr="x range_half "+String(brightness)+" * " + direction + " 255 scalef 0 ?")
    	mask_orig = mask
    	# limitBrightness suppression
    	if (limitBrightness != brightness) {
    		mask_suppression = mt_lut(diff, expr="x range_half "+String(limitBrightness)+" * " + direction + " 255 scalef 0 ?")
    		mask = mt_lutxy(mask, mask_suppression, expr="x y -")
    	}
    	# limitAbsBrightness suppression
    	if (limitAbsBrightness > 0.0) {
    		mask = mt_lutxy(mask, source, expr="y range_max "+String(limitAbsBrightness)+" * < 0 x ?")
    	}
    	# remove too small spots
    	mask = SDR_RemoveSmallSpots(mask, spotSize)
    	# limitBrightness or limitAbsBrightness suppression (part 2)
    	if (limitBrightness != brightness || limitAbsBrightness > 0.0) {
    		# if suppression didn't kill the whole mask then return it without suppression
    		mask = mt_hysteresis(mask, mask_orig, chroma="-127")
    	}
    	return mask
    }
    ## -------------------------------------------------------------------------------------------------------------------------------------------------------------
    function SDR_ChromaDeltaMask(clip source, clip filtered, int "delta", int "spotSize") {
    	# adjust delta to change how different colors are selected
    	# spotSize controls the smallest spot size allowed in the mask, typical values between 0 and 3
    	delta = default(delta, 3)
    	spotSize   = default(spotSize, 2)
    	# diff 
    	diff = mt_makediff(source, filtered, y=3, u=3, v=3)
    	# extract chroma channels
    	u = ExtractU(diff)
    	v = ExtractV(diff)
    	# calculate deltas
    	u_delta = mt_lut(u, expr="x range_half - abs")
    	v_delta = mt_lut(v, expr="x range_half - abs")
    	# combine deltas
    #	uv_delta = mt_lutxy(u_delta, v_delta, expr="x y +")
    	uv_delta = mt_lutxy(u_delta, v_delta, expr="x x * y y * + 0.5 ^")
    	# rescale (if needed)
    	if (uv_delta.width < source.width || uv_delta.height < source.height) {
    		uv_delta = uv_delta.BilinearResize(source.width, source.height)
    	}
    	# create mask
    	mask = uv_delta.mt_binarize(delta)
    	# remove too small spots 
    	mask = SDR_RemoveSmallSpots(mask, spotSize)	
    	# restore original format
    	blank = BlankClip(source)
    	mask = CombinePlanes(mask, blank, blank, planes="YUV", source_planes="YUV", sample_clip=source)
    	return mask
    }
    ## -------------------------------------------------------------------------------------------------------------------------------------------------------------
    function SDR_ExpandMask(clip mask, int amount, float "blur") {
    	blur = default(blur, 0)
    
    	for (i = 1, amount) {
    		mask = mask.mt_expand(chroma="-127")
    	}
    	if (blur > 0) {
            if ( RiskyBlur == True) {
                mask = mask.FastBlur(blur)
            }
            if ( RiskyBlur == False) {
                #mask = mask.GBlur(rad=6, sd=blur, u=true)	# GBlur is x86 only, could not locate an x64 dll :(
    			mask = mask.FastBlur(blur)
            }
    		#mask = mask.FastBlur(blur)
    		#mask = mask.binomialBlur(varY=blur)
    		#~ mask = mask.GBlur(rad=6, sd=blur, u=true)
    	}
    	return mask
    }
    ## -------------------------------------------------------------------------------------------------------------------------------------------------------------
    # RestoreGrain Function
    Function mRD_RestoreGrain(clip rd, clip o, float "str1", float "str2") { #https://forum.doom9.org/showthread.php?p=1943371#post1943371
    	sisavs26   = !(VersionNumber() < 2.60)
    	str1 = string(default(str1, 10.0))
    	str2 = string(default(str2, 20.0))
    	expr = sisavs26 ? " x range_half - abs "+str1+" scalef min "+str2+" scalef x range_half - abs - min 0 max x range_half - x range_half - abs 1 max / * range_half + " : " x 128 - abs "+str1+" min "+str2+" x 128 - abs - min 0 max x 128 - x 128 - abs 1 max / * 128 + "
    	Return sisavs26 ? mt_makediff(o, rd).mt_lut(expr, use_expr=2).mt_adddiff(rd, chroma="copy second") : mt_makediff(o, rd).mt_lut(expr).mt_adddiff(rd, chroma="copy second")
    }
    ## -------------------------------------------------------------------------------------------------------------------------------------------------------------
    # SDR_SpotLess107 Function
    # Version 1.07 per https://forum.doom9.org/showthread.php?p=1939724#post1939724
    Function SDR_SpotLess107(clip c,int "RadT",int "ThSAD",int "ThSAD2",int "pel",bool "chroma", int "BlkSz",Int "OLap",bool "tm",Bool "glob", Float "bBlur", clip "dc" ) {
        myName   = "SDR_SpotLess107: "
        RadT     = default(RadT,1)        # Temporal radius. (MCompensate arg)
        ThSAD    = default(ThSAD,10000)   # SAD threshold at radius 1 (Default Nearly OFF).
        ThSAD2   = default(ThSAD2,ThSAD)  # SAD threshold at radius RadT.
        Pel      = default(pel,2)         # Default 2. 1, 2, or 4. Maybe set 1 for HD+. (1=precision to pixel, 2=precision to half pixel, 4=quarter pixel)
        Chroma   = default(chroma,True)   # MAnalyse chroma arg. If set to true, use chroma in block matching.
        BlkSz    = default(BlkSz,8)       # Default 8. MAnalyse BlkSize. Bigger blksz quicker and perhaps  better, esp for HD clips. Maybe also better where BIG noise.
        OLap     = default(OLap, BlkSz/2) # Default half of BlkSz.
        Tm       = default(tm,True)       # TrueMotion, Some folk swear MAnalyse(truemotion=false) is better.
        Glob     = default(glob,True)     # Default True, Allow set MAnalyse(global) independently of TrueMotion.
        bBlur    = default(bblur,0.6)     # Default 0.6. Suggest about 0.6 for better motion analysis, but a bit slower.
        HasDC    = dc.Defined             # bblur ignored if HasDC, ie user already provided prefiltered clip.
        Assert(1 <= RadT,myName + " 1 <= RadT")
        Assert(0.0 <= bblur <= 1.58, myName + "0.0 <= bblur <= 1.58")
        Assert(pel==1 || pel==2 || pel==4, myName + "pel==1 || pel==2 || pel==4")
        pad = max(BlkSz,8)
        sup = (HasDC ? dc : bBlur>0.0  ? c.blur(bBlur) : c ).MSuper(hpad=pad,vpad=pad,pel=pel, sharp=2)
        # Only 1 Level required where not MAnalyse-ing.
        sup_rend = (HasDC||bBlur>0.0) ? c.MSuper(hpad=pad,vpad=pad,pel=pel, sharp=2,Levels=1) : sup
        MultiVec = sup.MAnalyse(multi=true, delta=RadT,blksize=BlkSz,overlap=OLap,chroma=Chroma,truemotion=Tm,global=Glob)
        c.MCompensate(sup_rend, MultiVec, tr=RadT, thSad=ThSAD, thSad2=ThSAD2)
        MedianBlurTemporal(radiusY=0,radiusU=0,radiusV=0,temporalradius=RadT)  # Temporal median blur only [not spatial]
        SelectEvery(RadT*2+1,RadT)                                             # Return middle frame
    }
    ## -------------------------------------------------------------------------------------------------------------------------------------------------------------
    Image Attached Files
    Last edited by hydra3333; 30th Jul 2021 at 23:16.
    Quote Quote  
  2. That script doesn't restore detail but instead keeps it from being removed in the first place via masking.
    Quote Quote  
  3. Member hydra3333's Avatar
    Join Date
    Oct 2009
    Location
    Australia
    Search Comp PM
    Ah, thank you.
    I does do something with that source, except for the hoped-for hair I suppose it may somehow consider it to be noise. Oh well.
    Quote Quote  
  4. @hydra3333: is the 'TEST.mp4' your source or is that an already processed input? Starting from that file I see nothing to salvage, if you have a sample of a less processed source there might be a change to save some details,..
    users currently on my ignore list: deadrats, Stears555
    Quote Quote  
  5. Member hydra3333's Avatar
    Join Date
    Oct 2009
    Location
    Australia
    Search Comp PM
    OK, 'test.mp4' had been pre-processed to the point just before input to the SDR_Spotless_DeltaRestore function, since I was focused on that.
    Apologies, I though I'd already asked "too much" about processing that source.

    Attached is the original.
    Image Attached Files
    Quote Quote  
  6. Looked at it did try a few models from https://upscale.wiki/wiki/Model_Database through VSGAN, also tried vs-dpir and vs-ffdnet depending on the scene some help a bit.
    Sadly over all none of them seems to be a real solution.
    users currently on my ignore list: deadrats, Stears555
    Quote Quote  
  7. Member hydra3333's Avatar
    Join Date
    Oct 2009
    Location
    Australia
    Search Comp PM
    OK, thank you for your time and effort and the link !

    We'll have to live with what can be done to clean it up a bit per non-DeltaRestore advice from JohnMeyer and others.

    Best Regards to All.
    Quote Quote  
  8. Originally Posted by hydra3333 View Post
    Ah, thank you.
    I does do something with that source, except for the hoped-for hair I suppose it may somehow consider it to be noise. Oh well.
    Or dandruffs
    Quote Quote  
  9. Can i have a video sample hydra3333 ? I'd like to see what i can do for you
    *** DIGITIZING VHS / ANALOG VIDEOS SINCE 2001**** GEAR: JVC HR-S7700MS, TOSHIBA V733EF AND MORE
    Quote Quote  
  10. Member hydra3333's Avatar
    Join Date
    Oct 2009
    Location
    Australia
    Search Comp PM
    Sure ! Please feel free. Any success with that would perhaps be a win for everyone, I suspect

    At the bottom of post #1 https://forum.videohelp.com/threads/402645-Seeking-advice-on-Spotless-DeltaRestore#post2627025 is an attachment 'test.mp4' https://forum.videohelp.com/attachments/60123-1627700952/TEST.mp4 which is the original pre-processed to the point just before input to the SDR_Spotless_DeltaRestore function, since I was focused on that.

    At the bottom of post #5 https://forum.videohelp.com/threads/402645-Seeking-advice-on-Spotless-DeltaRestore#post2627171 is an attachment 'Untouched-original.mpg' https://forum.videohelp.com/attachments/60134-1627818726/Untouched-original.mpg which is an original unprocessed sample.

    Cheers !
    Last edited by hydra3333; 17th Aug 2021 at 01:33.
    Quote Quote  



Similar Threads

Visit our sponsor! Try DVDFab and backup Blu-rays!