Author: nvtuan86 Language: text
Description: hoat hinh resize Timestamp: 2017-10-09 01:49:12 +0000
View raw paste Reply
  1. """
  2. This project was moved to https://github.com/kageru/Irrational-Encoding-Wizardry.
  3. Don't expect this gist to be updated regularly.
  4. """
  5.  
  6.  
  7. import vapoursynth as vs
  8. import mvsfunc as mvf
  9. import fvsfunc as fvf
  10. from functools import partial
  11.  
  12. core = vs.core  # R37 or newer
  13.  
  14. # TODO fixedge port
  15.  
  16. def inverse_scale(source: vs.VideoNode, width=None, height=720, kernel='bilinear', kerneluv='blackman', taps=4, a1=1/3, a2=1/3, invks=True, mask_detail=False,
  17.                   masking_areas=None, mask_highpass=0.3, denoise=False, bm3d_sigma=1, knl_strength=0.4, use_gpu=True) -> vs.VideoNode:
  18.     """
  19.     source = input clip
  20.     width, height, kernel, taps, a1, a2 are parameters for resizing
  21.     mask_detail, masking_areas, mask_highpass are parameters for masking; mask_detail = False to disable
  22.     masking_areas takes frame tuples to define areas which will be masked (e.g. opening and ending)
  23.     masking_areas = [[1000, 2500], [30000, 32000]]. Start and end frame are inclusive.
  24.     mask_highpass is used to remove small artifacts from the mask. Value must be normalized.
  25.     denoise, bm3d_sigma, knl_strength, and use_gpu are parameters for denoising; denoise = False to disable
  26.     use_gpu = True -> chroma will be denoised with KNLMeansCL (faster)
  27.     """
  28.     if source.format.bits_per_sample != 32:
  29.         source = core.fmtc.bitdepth(source, bits=32)
  30.     if width is None:
  31.         width = getw(height, ar=source.width/source.height)
  32.     planes = clip_to_plane_array(source)
  33.     if denoise and use_gpu:
  34.         planes[1], planes[2] = [core.knlm.KNLMeansCL(plane, a=2, h=knl_strength, d=3, device_type='gpu', device_id=0)
  35.                                 for plane in planes[1:]]
  36.         planes = inverse_scale_clip_array(planes, width, height, kernel, kerneluv, taps, a1, a2, invks)
  37.         planes[0] = mvf.BM3D(planes[0], sigma=bm3d_sigma, radius1=1)
  38.     else:
  39.         planes = inverse_scale_clip_array(planes, width, height, kernel, kerneluv, taps, a1, a2, invks)
  40.     scaled = plane_array_to_clip(planes)
  41.     if denoise and not use_gpu:
  42.         scaled = mvf.BM3D(scaled, radius1=1, sigma=bm3d_sigma)
  43.     if mask_detail:
  44.         mask = generate_mask(source, width, height, kernel, taps, a1, a2, mask_highpass)
  45.         if masking_areas is None:
  46.             scaled = apply_mask(source, scaled, mask)
  47.         else:
  48.             scaled = apply_mask_to_area(source, scaled, mask, masking_areas)
  49.     return scaled
  50.  
  51.  
  52. # the following 6 functions are mostly called from inside inverse_scale
  53. def inverse_scale_clip_array(planes, w, h, kernel, kerneluv, taps, a1, a2, invks=True):
  54.     if hasattr(core, 'descale') and invks:
  55.         planes[0] = get_descale_filter(kernel, b=a1, c=a2, taps=taps)(planes[0], w, h)
  56.     elif kernel == 'bilinear' and hasattr(core, 'unresize') and invks:
  57.         planes[0] = core.unresize.Unresize(planes[0], w, h)
  58.     else:
  59.         planes[0] = core.fmtc.resample(planes[0], w, h, kernel=kernel, invks=invks, invkstaps=taps, a1=a1, a2=a2)
  60.     planes[1], planes[2] = [core.fmtc.resample(plane, w, h, kernel=kerneluv, sx=0.25) for plane in planes[1:]]
  61.     return planes
  62.  
  63.  
  64. def clip_to_plane_array(clip):
  65.     return [core.std.ShufflePlanes(clip, x, colorfamily=vs.GRAY) for x in range(clip.format.num_planes)]
  66.  
  67.  
  68. def plane_array_to_clip(planes, family=vs.YUV):
  69.     return core.std.ShufflePlanes(clips=planes, planes=[0]*len(planes), colorfamily=family)
  70.  
  71.  
  72. def generate_mask(source, w=None, h=720, kernel='bilinear', taps=4, a1=0.15, a2=0.5, highpass=0.3, unresize=False):
  73.     if w is None: w = getw(h)
  74.     mask = mask_detail(source, w, h, kernel=kernel, taps=taps, invkstaps=taps, a1=a1, a2=a2, cutoff=highpass,
  75.                        unresize=unresize)
  76.     return mask
  77.  
  78.  
  79. def apply_mask(source, scaled, mask):
  80.     noalias = core.fmtc.resample(source, scaled.width, scaled.height, css=get_subsampling(scaled),
  81.                                  kernel='blackmanminlobe', taps=5)
  82.     masked = core.std.MaskedMerge(scaled, noalias, mask)
  83.     return masked
  84.  
  85.  
  86. def apply_mask_to_area(source, scaled, mask, area):
  87.     if len(area) == 2 and isinstance(area[0], int):
  88.         area = [[area[0], area[1]]]
  89.     noalias = core.fmtc.resample(source, scaled.width, scaled.height, css=get_subsampling(scaled),
  90.                                  kernel='blackmanminlobe', taps=5)
  91.     for a in area:  # TODO: use ReplaceFrames
  92.         source_cut = core.std.Trim(noalias, a[0], a[1])
  93.         scaled_cut = core.std.Trim(scaled, a[0], a[1])
  94.         mask_cut = core.std.Trim(mask, a[0], a[1])
  95.         masked = apply_mask(source_cut, scaled_cut, mask_cut)
  96.         scaled = insert_clip(scaled, masked, a[0])
  97.     return scaled
  98.  
  99.  
  100. # less typing == more time to encode
  101. split = clip_to_plane_array
  102. join = plane_array_to_clip
  103.  
  104.  
  105. def getY(c: vs.VideoNode) -> vs.VideoNode:
  106.     return core.std.ShufflePlanes(c, 0, vs.GRAY)
  107.  
  108.  
  109. # TODO: currently, this should fail for non mod4 subsampled input.
  110. # Not really relevant, though, as 480p, 576p, 720p, and 1080p are all mod32
  111. def generate_keyframes(clip: vs.VideoNode, out_path=None) -> None:

This paste is large and only partially shown.
View full paste

View raw paste Reply