1+ #!/usr/local/bin/python3
2+
3+ import argparse
4+ import cv2
5+ import dill
6+ import imutils
7+ import numpy as np
8+ import os
9+ from skimage .metrics import structural_similarity
10+ import subprocess
11+ import sys
12+
13+ # Verify script is colocated with ./lib/ and import dependencies
14+ sys .path .append (os .path .join (sys .path [0 ], "lib" ))
15+ try :
16+ from common import get_choice_from_menu
17+ except ImportError :
18+ sys .exit ("FATAL: failed to import dependencies from ./lib/\n " )
19+
20+ # Parse command-line arguments
21+ parser = argparse .ArgumentParser ()
22+ source_group = parser .add_mutually_exclusive_group ()
23+ source_group .add_argument ("--source" , help = "Source filename to compare that exists in both ./source/ and ./hevc/)" )
24+ source_group .add_argument ("--all" , action = "store_true" , help = "Compare all files which exist in both ./source/ and ./hevc/" )
25+ parser .add_argument ("--frame" , nargs = 1 , type = int , help = "Compare SSIM values for specific frames from previously generated comparisons" )
26+ parser .add_argument ("--num_frames" , nargs = "?" , default = 5 , type = int , help = "Number of comparison frames to generate" )
27+ parser .add_argument ("--dill" , action = "store_true" )
28+ args = parser .parse_args ()
29+
30+ # Verify we're working from a directory that contains expected subdirectories
31+ if not set (["source" , "hevc" , "performance" ]).issubset (set (os .listdir ())):
32+ sys .exit ("Invalid working directory, exiting." )
33+
34+ if args .all and args .frame :
35+ sys .exit ("Error: --frame must be used with --source, not --all. Exiting." )
36+ elif args .all :
37+ source_files = [filename for filename in os .listdir ("source" ) if os .path .splitext (filename )[1 ] == ".mp4" ]
38+ elif args .source .endswith (".mp4" ):
39+ source_files = [args .source ]
40+ # if args.frame, fail unless args.source exists
41+ # if args.frame, verify filename exists in "comparison"
42+ else :
43+ sys .exit ("Invalid filename, exiting." )
44+
45+ # if comparison directory already exists, exit
46+
47+ print ("\n Comparison frames:\t {frames}" .format (frames = args .num_frames ))
48+
49+ for source_file in source_files :
50+ source_file_path = os .path .join ("source" , source_file )
51+ source_file_size = int (os .path .getsize (source_file_path )/ 1000000 )
52+ source_file_handle = cv2 .VideoCapture (source_file_path )
53+ hevc_files = [filename for filename in os .listdir ("hevc" ) if filename .startswith (os .path .splitext (source_file )[0 ])]
54+
55+ for hevc_file in hevc_files :
56+ evaluate_frames = True
57+ output_directory = os .path .join (os .path .relpath ("comparison" ), os .path .splitext (os .path .basename (hevc_file ))[0 ])
58+ hevc_file_path = os .path .join ("hevc" , hevc_file )
59+ hevc_file_handle = cv2 .VideoCapture (hevc_file_path )
60+ hevc_file_size = int (os .path .getsize (hevc_file_path )/ 1000000 )
61+ compression_ratio = int (100 - (hevc_file_size / source_file_size * 100 ))
62+ total_frames = source_file_handle .get (cv2 .CAP_PROP_FRAME_COUNT )
63+ # get other attributes from ./performance/<<>>.log
64+ stride = int (total_frames / (args .num_frames + 1 ))
65+
66+ print ("\n Filename:\t \t {filename}" .format (filename = hevc_file ))
67+ if source_file_handle .get (cv2 .CAP_PROP_FRAME_COUNT ) != hevc_file_handle .get (cv2 .CAP_PROP_FRAME_COUNT ):
68+ print ("\t \t \t !!! WARNING: Frame counts do not match, screencaps may be time-shifted" )
69+ evaluate_frames = False
70+ print ("\t Source Size:\t {size} MB" .format (size = source_file_size ))
71+ print ("\t HEVC Size:\t {size} MB" .format (size = hevc_file_size ))
72+ print ("\t Reduction:\t {ratio}%\n " .format (ratio = compression_ratio ))
73+
74+ ssim_total = 0.0
75+ ssim_values = {}
76+ print ("\t SSIM:" )
77+ if not os .path .exists (output_directory ): os .makedirs (output_directory )
78+ #if frame_resolution_differs: # e.g. letterboxing removed -- where does this go?
79+ for frame in range (1 , args .num_frames + 1 ):
80+ source_file_handle .set (cv2 .CAP_PROP_POS_FRAMES ,stride * frame )
81+ hevc_file_handle .set (cv2 .CAP_PROP_POS_FRAMES ,stride * frame )
82+ ret ,source_frame = source_file_handle .read ()
83+ ret ,hevc_frame = hevc_file_handle .read ()
84+ cv2 .imwrite (os .path .join (output_directory , "{number}-source.png" .format (number = frame )), source_frame , [cv2 .IMWRITE_PNG_COMPRESSION , 0 ])
85+ cv2 .imwrite (os .path .join (output_directory , "{number}-x265.png" .format (number = frame )), hevc_frame , [cv2 .IMWRITE_PNG_COMPRESSION , 0 ])
86+ if evaluate_frames :
87+ try :
88+ ssim = structural_similarity (cv2 .cvtColor (source_frame , cv2 .COLOR_BGR2GRAY ), cv2 .cvtColor (hevc_frame , cv2 .COLOR_BGR2GRAY ))
89+ except ValueError as error :
90+ print ("\t ERROR: " + str (error ))
91+ evaluate_frames = False
92+ else :
93+ ssim_values [frame ] = ssim
94+ ssim_total += ssim
95+ print ("\t Frame {frame}:\t {ssim}" .format (frame = frame , ssim = ssim ))
96+
97+ ssim_average = ssim_total / args .num_frames
98+ print ("\t Average:\t {average}\n " .format (average = ssim_average ))
99+ with open (os .path .join ("performance" , hevc_file [:- 4 ] + ".log" ), "r" ) as performance_file :
100+ duration = performance_file .readline ().rstrip ()
101+ fps = "{:0.2f}" .format (float (performance_file .readline ().rstrip ().split (" " )[0 ]))
102+ with open (os .path .join (output_directory , "summary.txt" ), "w" ) as summary_file :
103+ summary_file .write ("SSIM Avg:\t {average}\n Duration:\t {duration}\n FPS:\t \t {fps}\n Compression:\t {compression}%\n \n " .format (average = ssim_average , duration = duration , fps = fps , compression = compression_ratio ))
104+ if evaluate_frames :
105+ for iterator in range (1 , args .num_frames + 1 ):
106+ summary_file .write ("\t {iterator}:\t {ssim}\n " .format (iterator = iterator , ssim = ssim_values [iterator ]))
107+
108+ hevc_file_handle .release ()
109+
110+ source_file_handle .release ()
111+
112+ sys .exit ("Done.\n " )
0 commit comments