Advertisement
Guest User

Untitled

a guest
Feb 8th, 2019
374
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 6.66 KB | None | 0 0
  1. #
  2. # Zoptilib - helper script for the Zopti optimizer
  3. #
  4. # -supported similarity metrics are 'ssim', 'gmsd' and 'vmaf' (note: currently cannot have both gmsd and vmaf at the same time)
  5. # -measures the runtime in milliseconds when 'time' is added to metrics list
  6. #
  7. # Requirements: muvsfunc (for SSIM and GMSD), VapourSynth-VMAF (for VMAF)
  8. #
  9. # Usage examples:
  10. #
  11. # from zoptilib import Zopti
  12. # output_file = r'results.txt' # output out1="SSIM: MAX(float)" out2="time: MIN(time) ms" file="results.txt"
  13. # zopti = Zopti(output_file, metrics=['ssim', 'time']) # initialize output file and chosen metrics
  14. # # make sure metrics match what is defined at the line above
  15. # # Zopti starts measuring runtime at this point so call it just before the processing you want to measure
  16. #
  17. # # define parameters to optimize (in the comments)
  18. # super_pel = 4 # optimize super_pel = _n_ | 2,4 | super_pel
  19. # super_sharp = 2 # optimize super_sharp = _n_ | 0..2 | super_sharp
  20. # super_rfilter = 2 # optimize super_rfilter = _n_ | 0..4 | super_rfilter
  21. # super = core.mv.Super(orig, pel=super_pel, sharp=super_sharp, rfilter=super_rfilter)
  22. #
  23. # ... process the video ...
  24. #
  25. # zopti.run(orig, alternate) # measure similarity of original and alternate videos, save results to output file
  26. # # note: the first clip should be the reference / original clip
  27. # # the output video is the second clip when vmaf is not used and the first clip when vmaf is used
  28. #
  29. # OR
  30. #
  31. # zopti = Zopti(output_file) # initialize output file
  32. # zopti.addMetrics(['ssim','time']) # add chosen metrics
  33. # ... process the video and measure similarity ...
  34. #
  35. #
  36. # Changelog:
  37. # 2019-01-23 v1.0 initial version
  38. #
  39.  
  40. import vapoursynth as vs
  41. import time
  42. import muvsfunc as muv
  43. import functools
  44.  
  45. core = vs.core
  46.  
  47. class FrameData:
  48.  
  49. def __init__(self, name):
  50. self.name = name
  51. self.per_frame_data = {}
  52.  
  53. class Zopti:
  54.  
  55. def __init__(self, output_file, metrics = None):
  56.  
  57. self.valid_metrics = ['time', 'ssim', 'gmsd', 'mdsi', 'butteraugli', 'vmaf']
  58. self.supported_with_vmaf = ['time', 'ssim'] # these metrics can be read from the vmaf output
  59. self.output_file = output_file
  60. self.vmaf_model = 0 # default model: vmaf_v0.6.1.pkl
  61.  
  62. # measure total runtime
  63. self.start_time = time.perf_counter()
  64.  
  65. # used metrics
  66. self.metrics = []
  67. if metrics:
  68. self.addMetrics(metrics)
  69.  
  70.  
  71. def addMetric(self, metric):
  72. if metric in self.valid_metrics:
  73. if metric == 'vmaf':
  74. if (len(set(self.metrics) & set(self.supported_with_vmaf)) != len(self.metrics)):
  75. raise NameError('Only these metrics are supported with vmaf: '+str(list(self.supported_with_vmaf)))
  76. elif metric not in self.supported_with_vmaf:
  77. if 'vmaf' in self.metrics:
  78. raise NameError('Only these metrics are supported with vmaf: '+str(list(self.supported_with_vmaf)))
  79. self.metrics.append(metric)
  80. else:
  81. raise NameError('Unknown metric "'+metric+'"')
  82.  
  83. def addMetrics(self, metrics):
  84. for metric in metrics:
  85. self.addMetric(metric)
  86.  
  87. def setVMAFModel(self, model):
  88. self.vmaf_model = model
  89.  
  90. def run(self, clip, alt_clip):
  91.  
  92. if len(self.metrics) == 0:
  93. raise ValueError('No metrics defined')
  94.  
  95. if 'vmaf' not in self.metrics:
  96.  
  97. total_frames = clip.num_frames
  98. metricsSet = set(self.metrics)
  99. data = []
  100. prop_src = []
  101. for metric in self.metrics:
  102. if metric == 'gmsd':
  103. # calculate GMSD between original and alternate version
  104. alt_clip = muv.GMSD(alt_clip, clip, show_map=False)
  105. prop_src = [alt_clip]
  106. data.append(FrameData('gmsd'))
  107. elif metric == 'ssim':
  108. # calculate SSIM between original and alternate version
  109. alt_clip = muv.SSIM(alt_clip, clip, show_map=False)
  110. prop_src = [alt_clip]
  111. data.append(FrameData('ssim'))
  112. elif metric == 'mdsi':
  113. # calculate MDSI between original and alternate version
  114. alt_clip = muv.MDSI(alt_clip, clip, down_scale=2)
  115. prop_src = [alt_clip]
  116. data.append(FrameData('mdsi'))
  117. elif metric == 'butteraugli':
  118. # calculate butteraugli between original and alternate version
  119. alt_clip = core.Butteraugli.butteraugli(alt_clip, clip)
  120. prop_src = [alt_clip]
  121. data.append(FrameData('butteraugli'))
  122. elif metric == 'time':
  123. data.append(FrameData('time'))
  124. else:
  125. raise NameError('Unknown metric '+metric)
  126.  
  127. def save_per_frame_data(n, frame_data, f):
  128. prop_name = ''
  129. if (frame_data.name == 'gmsd'):
  130. prop_name = 'PlaneGMSD'
  131. elif (frame_data.name == 'ssim'):
  132. prop_name = 'PlaneSSIM'
  133. elif (frame_data.name == 'mdsi'):
  134. prop_name = 'FrameMDSI'
  135. elif (frame_data.name == 'butteraugli'):
  136. prop_name = '_Diff'
  137. elif (frame_data.name == 'time'):
  138. pass
  139. else:
  140. raise NameError('Unknown per frame type '+frame_data.name)
  141.  
  142. if prop_name != '':
  143. frame_data.per_frame_data[n] = f.props[prop_name]
  144.  
  145.  
  146. # write per frame GMSD and/or SSIM and total runtime to a file
  147. def calc(n, f, clip, data):
  148.  
  149. for frame_data in data:
  150. save_per_frame_data(n, frame_data, f)
  151.  
  152. # when all frames have been processed write results to a file
  153. if (len(data[0].per_frame_data) == total_frames):
  154. runtime = time.perf_counter() - self.start_time
  155. with open(self.output_file, 'w') as file:
  156. for frame in data[0].per_frame_data.items():
  157. frame_nbr = frame[0]
  158. file.write(str(frame_nbr) + '; ')
  159. for frame_data in data:
  160. if frame_data.name == 'time':
  161. file.write('0.0; ')
  162. else:
  163. info = frame_data.per_frame_data[frame_nbr]
  164. file.write(str(info)+'; ')
  165. file.write('\n')
  166.  
  167. # write sum of per frame values and/or total runtime to last line
  168. file.write('stop ')
  169. for frame_data in data:
  170. if frame_data.name == 'time':
  171. file.write(str(runtime*1000)+' ')
  172. else:
  173. file.write(str(sum(frame_data.per_frame_data.values()))+' ')
  174.  
  175. return clip
  176.  
  177. final = alt_clip.std.FrameEval(functools.partial(calc, clip=alt_clip, data=data), prop_src=prop_src)
  178. final.set_output()
  179. return final
  180. else:
  181.  
  182. # VMAF
  183. # model: 0 = vmaf_v0.6.1.pkl, 1 = vmaf_4k_v0.6.1.pkl
  184. # log_fmt: 0 = xml, 1 = json
  185. # pool: 0 = mean, 1 = harmonic mean, 2 = min
  186. # ci: return confidence interval True/False
  187. calc_ssim = 'ssim' in self.metrics
  188. final = core.vmaf.VMAF(clip, alt_clip, model=self.vmaf_model, log_path=self.output_file, log_fmt=0, ssim=calc_ssim, ms_ssim=False, pool=0, ci=False)
  189. final.set_output()
  190. return final
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement