from abc import ABCMeta, abstractmethod
import os
from vmaf.tools.misc import make_absolute_path, run_process
from vmaf.tools.stats import ListStats

__copyright__ = "Copyright 2016-2018, Netflix, Inc."
__license__ = "Apache, Version 2.0"

import re
import numpy as np
import ast

from vmaf import ExternalProgramCaller, to_list
from vmaf.config import VmafConfig, VmafExternalConfig
from vmaf.core.executor import Executor
from vmaf.core.result import Result
from vmaf.tools.reader import YuvReader

class FeatureExtractor(Executor):
    """
    FeatureExtractor takes in a list of assets, and run feature extraction on
    them, and return a list of corresponding results. A FeatureExtractor must
    specify a unique type and version combination (by the TYPE and VERSION
    attribute), so that the Result generated by it can be identified.

    A derived class of FeatureExtractor must:
        1) Override TYPE and VERSION
        2) Override _generate_result(self, asset), which call a
        command-line executable and generate feature scores in a log file.
        3) Override _get_feature_scores(self, asset), which read the feature
        scores from the log file, and return the scores in a dictionary format.
    For an example, follow VmafFeatureExtractor.
    """

    __metaclass__ = ABCMeta

    @property
    @abstractmethod
    def ATOM_FEATURES(self):
        raise NotImplementedError

    def _read_result(self, asset):
        result = {}
        result.update(self._get_feature_scores(asset))
        executor_id = self.executor_id
        return Result(asset, executor_id, result)

    @classmethod
    def get_scores_key(cls, atom_feature):
        return "{type}_{atom_feature}_scores".format(
            type=cls.TYPE, atom_feature=atom_feature)

    @classmethod
    def get_score_key(cls, atom_feature):
        return "{type}_{atom_feature}_score".format(
            type=cls.TYPE, atom_feature=atom_feature)

    def _get_feature_scores(self, asset):
        # routine to read the feature scores from the log file, and return
        # the scores in a dictionary format.

        log_file_path = self._get_log_file_path(asset)

        atom_feature_scores_dict = {}
        atom_feature_idx_dict = {}
        for atom_feature in self.ATOM_FEATURES:
            atom_feature_scores_dict[atom_feature] = []
            atom_feature_idx_dict[atom_feature] = 0

        with open(log_file_path, 'rt') as log_file:
            for line in log_file.readlines():
                for atom_feature in self.ATOM_FEATURES:
                    re_template = "{af}: ([0-9]+) ([a-zA-Z0-9.-]+)".format(af=atom_feature)
                    mo = re.match(re_template, line)
                    if mo:

                        cur_idx = int(mo.group(1))
                        assert cur_idx == atom_feature_idx_dict[atom_feature]

                        # parse value, allowing NaN and inf
                        val = float(mo.group(2))
                        if np.isnan(val) or np.isinf(val):
                            val = None

                        atom_feature_scores_dict[atom_feature].append(val)
                        atom_feature_idx_dict[atom_feature] += 1
                        continue

        len_score = len(atom_feature_scores_dict[self.ATOM_FEATURES[0]])
        assert len_score != 0
        for atom_feature in self.ATOM_FEATURES[1:]:
            assert len_score == len(atom_feature_scores_dict[atom_feature]), \
                "Feature data possibly corrupt. Run cleanup script and try again."

        feature_result = {}

        for atom_feature in self.ATOM_FEATURES:
            scores_key = self.get_scores_key(atom_feature)
            feature_result[scores_key] = atom_feature_scores_dict[atom_feature]

        return feature_result


class VmafFeatureExtractor(FeatureExtractor):

    TYPE = "VMAF_feature"

    # VERSION = '0.1' # vmaf_study; Anush's VIF fix
    # VERSION = '0.2' # expose vif_num, vif_den, adm_num, adm_den, anpsnr
    # VERSION = '0.2.1' # expose vif num/den of each scale
    # VERSION = '0.2.2'  # adm abs-->fabs, corrected border handling, uniform reading with option of offset for input YUV, updated VIF corner case
    # VERSION = '0.2.2b'  # expose adm_den/num_scalex
    # VERSION = '0.2.3'  # AVX for VMAF convolution; update adm features by folding noise floor into per coef
    # VERSION = '0.2.4'  # Fix a bug in adm feature passing scale into dwt_quant_step
    # VERSION = '0.2.4b'  # Modify by adding ADM noise floor outside cube root; add derived feature motion2
    VERSION = '0.2.4c'  # Modify by moving motion2 to c code

    ATOM_FEATURES = ['vif', 'adm', 'ansnr', 'motion', 'motion2',
                     'vif_num', 'vif_den', 'adm_num', 'adm_den', 'anpsnr',
                     'vif_num_scale0', 'vif_den_scale0',
                     'vif_num_scale1', 'vif_den_scale1',
                     'vif_num_scale2', 'vif_den_scale2',
                     'vif_num_scale3', 'vif_den_scale3',
                     'adm_num_scale0', 'adm_den_scale0',
                     'adm_num_scale1', 'adm_den_scale1',
                     'adm_num_scale2', 'adm_den_scale2',
                     'adm_num_scale3', 'adm_den_scale3',
                     ]

    DERIVED_ATOM_FEATURES = ['vif_scale0', 'vif_scale1', 'vif_scale2', 'vif_scale3',
                             'vif2', 'adm2', 'adm3',
                             'adm_scale0', 'adm_scale1', 'adm_scale2', 'adm_scale3',
                             ]

    ADM2_CONSTANT = 0
    ADM_SCALE_CONSTANT = 0

    def _generate_result(self, asset):
        # routine to call the command-line executable and generate feature
        # scores in the log file.

        quality_width, quality_height = asset.quality_width_height
        log_file_path = self._get_log_file_path(asset)

        yuv_type=self._get_workfile_yuv_type(asset)
        ref_path=asset.ref_workfile_path
        dis_path=asset.dis_workfile_path
        w=quality_width
        h=quality_height
        logger = self.logger

        ExternalProgramCaller.call_vmaf_feature(yuv_type, ref_path, dis_path, w, h, log_file_path, logger)

    @classmethod
    def _post_process_result(cls, result):
        # override Executor._post_process_result

        result = super(VmafFeatureExtractor, cls)._post_process_result(result)

        # adm2 =
        # (adm_num + ADM2_CONSTANT) / (adm_den + ADM2_CONSTANT)
        adm2_scores_key = cls.get_scores_key('adm2')
        adm_num_scores_key = cls.get_scores_key('adm_num')
        adm_den_scores_key = cls.get_scores_key('adm_den')
        result.result_dict[adm2_scores_key] = list(
            (np.array(result.result_dict[adm_num_scores_key]) + cls.ADM2_CONSTANT) /
            (np.array(result.result_dict[adm_den_scores_key]) + cls.ADM2_CONSTANT)
        )

        # vif_scalei = vif_num_scalei / vif_den_scalei, i = 0, 1, 2, 3
        vif_num_scale0_scores_key = cls.get_scores_key('vif_num_scale0')
        vif_den_scale0_scores_key = cls.get_scores_key('vif_den_scale0')
        vif_num_scale1_scores_key = cls.get_scores_key('vif_num_scale1')
        vif_den_scale1_scores_key = cls.get_scores_key('vif_den_scale1')
        vif_num_scale2_scores_key = cls.get_scores_key('vif_num_scale2')
        vif_den_scale2_scores_key = cls.get_scores_key('vif_den_scale2')
        vif_num_scale3_scores_key = cls.get_scores_key('vif_num_scale3')
        vif_den_scale3_scores_key = cls.get_scores_key('vif_den_scale3')
        vif_scale0_scores_key = cls.get_scores_key('vif_scale0')
        vif_scale1_scores_key = cls.get_scores_key('vif_scale1')
        vif_scale2_scores_key = cls.get_scores_key('vif_scale2')
        vif_scale3_scores_key = cls.get_scores_key('vif_scale3')
        result.result_dict[vif_scale0_scores_key] = list(
            (np.array(result.result_dict[vif_num_scale0_scores_key])
             / np.array(result.result_dict[vif_den_scale0_scores_key]))
        )
        result.result_dict[vif_scale1_scores_key] = list(
            (np.array(result.result_dict[vif_num_scale1_scores_key])
             / np.array(result.result_dict[vif_den_scale1_scores_key]))
        )
        result.result_dict[vif_scale2_scores_key] = list(
            (np.array(result.result_dict[vif_num_scale2_scores_key])
             / np.array(result.result_dict[vif_den_scale2_scores_key]))
        )
        result.result_dict[vif_scale3_scores_key] = list(
            (np.array(result.result_dict[vif_num_scale3_scores_key])
             / np.array(result.result_dict[vif_den_scale3_scores_key]))
        )

        # vif2 =
        # ((vif_num_scale0 / vif_den_scale0) + (vif_num_scale1 / vif_den_scale1) +
        # (vif_num_scale2 / vif_den_scale2) + (vif_num_scale3 / vif_den_scale3)) / 4.0
        vif_scores_key = cls.get_scores_key('vif2')
        result.result_dict[vif_scores_key] = list(
            (
                (np.array(result.result_dict[vif_num_scale0_scores_key])
                 / np.array(result.result_dict[vif_den_scale0_scores_key])) +
                (np.array(result.result_dict[vif_num_scale1_scores_key])
                 / np.array(result.result_dict[vif_den_scale1_scores_key])) +
                (np.array(result.result_dict[vif_num_scale2_scores_key])
                 / np.array(result.result_dict[vif_den_scale2_scores_key])) +
                (np.array(result.result_dict[vif_num_scale3_scores_key])
                 / np.array(result.result_dict[vif_den_scale3_scores_key]))
            ) / 4.0
        )

        # adm_scalei = adm_num_scalei / adm_den_scalei, i = 0, 1, 2, 3
        adm_num_scale0_scores_key = cls.get_scores_key('adm_num_scale0')
        adm_den_scale0_scores_key = cls.get_scores_key('adm_den_scale0')
        adm_num_scale1_scores_key = cls.get_scores_key('adm_num_scale1')
        adm_den_scale1_scores_key = cls.get_scores_key('adm_den_scale1')
        adm_num_scale2_scores_key = cls.get_scores_key('adm_num_scale2')
        adm_den_scale2_scores_key = cls.get_scores_key('adm_den_scale2')
        adm_num_scale3_scores_key = cls.get_scores_key('adm_num_scale3')
        adm_den_scale3_scores_key = cls.get_scores_key('adm_den_scale3')
        adm_scale0_scores_key = cls.get_scores_key('adm_scale0')
        adm_scale1_scores_key = cls.get_scores_key('adm_scale1')
        adm_scale2_scores_key = cls.get_scores_key('adm_scale2')
        adm_scale3_scores_key = cls.get_scores_key('adm_scale3')
        result.result_dict[adm_scale0_scores_key] = list(
            (np.array(result.result_dict[adm_num_scale0_scores_key]) + cls.ADM_SCALE_CONSTANT)
            / (np.array(result.result_dict[adm_den_scale0_scores_key]) + cls.ADM_SCALE_CONSTANT)
        )
        result.result_dict[adm_scale1_scores_key] = list(
            (np.array(result.result_dict[adm_num_scale1_scores_key]) + cls.ADM_SCALE_CONSTANT)
            / (np.array(result.result_dict[adm_den_scale1_scores_key]) + cls.ADM_SCALE_CONSTANT)
        )
        result.result_dict[adm_scale2_scores_key] = list(
            (np.array(result.result_dict[adm_num_scale2_scores_key]) + cls.ADM_SCALE_CONSTANT)
            / (np.array(result.result_dict[adm_den_scale2_scores_key]) + cls.ADM_SCALE_CONSTANT)
        )
        result.result_dict[adm_scale3_scores_key] = list(
            (np.array(result.result_dict[adm_num_scale3_scores_key]) + cls.ADM_SCALE_CONSTANT)
            / (np.array(result.result_dict[adm_den_scale3_scores_key]) + cls.ADM_SCALE_CONSTANT)
        )

        # adm3 = \
        # (((adm_num_scale0 + ADM_SCALE_CONSTANT) / (adm_den_scale0 + ADM_SCALE_CONSTANT))
        #  + ((adm_num_scale1 + ADM_SCALE_CONSTANT) / (adm_den_scale1 + ADM_SCALE_CONSTANT))
        #  + ((adm_num_scale2 + ADM_SCALE_CONSTANT) / (adm_den_scale2 + ADM_SCALE_CONSTANT))
        #  + ((adm_num_scale3 + ADM_SCALE_CONSTANT) / (adm_den_scale3 + ADM_SCALE_CONSTANT))) / 4.0
        adm3_scores_key = cls.get_scores_key('adm3')
        result.result_dict[adm3_scores_key] = list(
            (
                ((np.array(result.result_dict[adm_num_scale0_scores_key]) + cls.ADM_SCALE_CONSTANT)
                 / (np.array(result.result_dict[adm_den_scale0_scores_key]) + cls.ADM_SCALE_CONSTANT)) +
                ((np.array(result.result_dict[adm_num_scale1_scores_key]) + cls.ADM_SCALE_CONSTANT)
                 / (np.array(result.result_dict[adm_den_scale1_scores_key]) + cls.ADM_SCALE_CONSTANT)) +
                ((np.array(result.result_dict[adm_num_scale2_scores_key]) + cls.ADM_SCALE_CONSTANT)
                 / (np.array(result.result_dict[adm_den_scale2_scores_key]) + cls.ADM_SCALE_CONSTANT)) +
                ((np.array(result.result_dict[adm_num_scale3_scores_key]) + cls.ADM_SCALE_CONSTANT)
                 / (np.array(result.result_dict[adm_den_scale3_scores_key]) + cls.ADM_SCALE_CONSTANT))
            ) / 4.0
        )

        # validate
        for feature in cls.DERIVED_ATOM_FEATURES:
            assert cls.get_scores_key(feature) in result.result_dict

        return result

class VifFrameDifferenceFeatureExtractor(FeatureExtractor):

    TYPE = "VifDiff_feature"

    VERSION = '0.1'

    ATOM_FEATURES = ['vifdiff',
                     'vifdiff_num', 'vifdiff_den',
                     'vifdiff_num_scale0', 'vifdiff_den_scale0',
                     'vifdiff_num_scale1', 'vifdiff_den_scale1',
                     'vifdiff_num_scale2', 'vifdiff_den_scale2',
                     'vifdiff_num_scale3', 'vifdiff_den_scale3',
                     ]

    DERIVED_ATOM_FEATURES = ['vifdiff_scale0', 'vifdiff_scale1', 'vifdiff_scale2', 'vifdiff_scale3',
                             ]

    ADM2_CONSTANT = 0
    ADM_SCALE_CONSTANT = 0

    def _generate_result(self, asset):
        # routine to call the command-line executable and generate feature
        # scores in the log file.

        quality_width, quality_height = asset.quality_width_height
        log_file_path = self._get_log_file_path(asset)

        yuv_type=self._get_workfile_yuv_type(asset)
        ref_path=asset.ref_workfile_path
        dis_path=asset.dis_workfile_path
        w=quality_width
        h=quality_height
        logger = self.logger

        ExternalProgramCaller.call_vifdiff_feature(yuv_type, ref_path, dis_path, w, h, log_file_path, logger)

    @classmethod
    def _post_process_result(cls, result):
        # override Executor._post_process_result

        result = super(VifFrameDifferenceFeatureExtractor, cls)._post_process_result(result)

        # vifdiff_scalei = vifdiff_num_scalei / vifdiff_den_scalei, i = 0, 1, 2, 3
        vifdiff_num_scale0_scores_key = cls.get_scores_key('vifdiff_num_scale0')
        vifdiff_den_scale0_scores_key = cls.get_scores_key('vifdiff_den_scale0')
        vifdiff_num_scale1_scores_key = cls.get_scores_key('vifdiff_num_scale1')
        vifdiff_den_scale1_scores_key = cls.get_scores_key('vifdiff_den_scale1')
        vifdiff_num_scale2_scores_key = cls.get_scores_key('vifdiff_num_scale2')
        vifdiff_den_scale2_scores_key = cls.get_scores_key('vifdiff_den_scale2')
        vifdiff_num_scale3_scores_key = cls.get_scores_key('vifdiff_num_scale3')
        vifdiff_den_scale3_scores_key = cls.get_scores_key('vifdiff_den_scale3')
        vifdiff_scale0_scores_key = cls.get_scores_key('vifdiff_scale0')
        vifdiff_scale1_scores_key = cls.get_scores_key('vifdiff_scale1')
        vifdiff_scale2_scores_key = cls.get_scores_key('vifdiff_scale2')
        vifdiff_scale3_scores_key = cls.get_scores_key('vifdiff_scale3')
        result.result_dict[vifdiff_scale0_scores_key] = list(
            (np.array(result.result_dict[vifdiff_num_scale0_scores_key])
             / np.array(result.result_dict[vifdiff_den_scale0_scores_key]))
        )
        result.result_dict[vifdiff_scale1_scores_key] = list(
            (np.array(result.result_dict[vifdiff_num_scale1_scores_key])
             / np.array(result.result_dict[vifdiff_den_scale1_scores_key]))
        )
        result.result_dict[vifdiff_scale2_scores_key] = list(
            (np.array(result.result_dict[vifdiff_num_scale2_scores_key])
             / np.array(result.result_dict[vifdiff_den_scale2_scores_key]))
        )
        result.result_dict[vifdiff_scale3_scores_key] = list(
            (np.array(result.result_dict[vifdiff_num_scale3_scores_key])
             / np.array(result.result_dict[vifdiff_den_scale3_scores_key]))
        )

        # validate
        for feature in cls.DERIVED_ATOM_FEATURES:
            assert cls.get_scores_key(feature) in result.result_dict

        return result

class PsnrFeatureExtractor(FeatureExtractor):

    TYPE = "PSNR_feature"
    VERSION = "1.0"

    ATOM_FEATURES = ['psnr']

    def _generate_result(self, asset):
        # routine to call the command-line executable and generate quality
        # scores in the log file.

        quality_width, quality_height = asset.quality_width_height
        log_file_path = self._get_log_file_path(asset)

        yuv_type=self._get_workfile_yuv_type(asset)
        ref_path=asset.ref_workfile_path
        dis_path=asset.dis_workfile_path
        w=quality_width
        h=quality_height
        logger = self.logger

        ExternalProgramCaller.call_psnr(yuv_type, ref_path, dis_path, w, h, log_file_path, logger)


class MomentFeatureExtractor(FeatureExtractor):

    TYPE = "Moment_feature"

    # VERSION = "1.0" # call executable
    VERSION = "1.1" # python only

    ATOM_FEATURES = ['ref1st', 'ref2nd', 'dis1st', 'dis2nd', ]

    DERIVED_ATOM_FEATURES = ['refvar', 'disvar', ]

    def _generate_result(self, asset):
        # routine to call the command-line executable and generate feature
        # scores in the log file.

        quality_w, quality_h = asset.quality_width_height

        ref_scores_mtx = None
        with YuvReader(filepath=asset.ref_workfile_path, width=quality_w, height=quality_h,
                       yuv_type=self._get_workfile_yuv_type(asset)) as ref_yuv_reader:
            scores_mtx_list = []
            i = 0
            for ref_yuv in ref_yuv_reader:
                ref_y = ref_yuv[0]
                firstm = ref_y.mean()
                secondm = ref_y.var() + firstm**2
                scores_mtx_list.append(np.hstack(([firstm], [secondm])))
                i += 1
            ref_scores_mtx = np.vstack(scores_mtx_list)

        dis_scores_mtx = None
        with YuvReader(filepath=asset.dis_workfile_path, width=quality_w, height=quality_h,
                       yuv_type=self._get_workfile_yuv_type(asset)) as dis_yuv_reader:
            scores_mtx_list = []
            i = 0
            for dis_yuv in dis_yuv_reader:
                dis_y = dis_yuv[0]
                firstm = dis_y.mean()
                secondm = dis_y.var() + firstm**2
                scores_mtx_list.append(np.hstack(([firstm], [secondm])))
                i += 1
            dis_scores_mtx = np.vstack(scores_mtx_list)

        assert ref_scores_mtx is not None and dis_scores_mtx is not None

        log_dict = {'ref_scores_mtx': ref_scores_mtx.tolist(),
                    'dis_scores_mtx': dis_scores_mtx.tolist()}

        log_file_path = self._get_log_file_path(asset)
        with open(log_file_path, 'wt') as log_file:
            log_file.write(str(log_dict))

    def _get_feature_scores(self, asset):
        # routine to read the feature scores from the log file, and return
        # the scores in a dictionary format.

        log_file_path = self._get_log_file_path(asset)

        with open(log_file_path, 'rt') as log_file:
            log_str = log_file.read()
            log_dict = ast.literal_eval(log_str)
        ref_scores_mtx = np.array(log_dict['ref_scores_mtx'])
        dis_scores_mtx = np.array(log_dict['dis_scores_mtx'])

        _, num_ref_features = ref_scores_mtx.shape
        assert num_ref_features == 2 # ref1st, ref2nd
        _, num_dis_features = dis_scores_mtx.shape
        assert num_dis_features == 2 # dis1st, dis2nd

        feature_result = {}
        feature_result[self.get_scores_key('ref1st')] = list(ref_scores_mtx[:, 0])
        feature_result[self.get_scores_key('ref2nd')] = list(ref_scores_mtx[:, 1])
        feature_result[self.get_scores_key('dis1st')] = list(dis_scores_mtx[:, 0])
        feature_result[self.get_scores_key('dis2nd')] = list(dis_scores_mtx[:, 1])

        return feature_result

    @classmethod
    def _post_process_result(cls, result):
        # override Executor._post_process_result

        result = super(MomentFeatureExtractor, cls)._post_process_result(result)

        # calculate refvar and disvar from ref1st, ref2nd, dis1st, dis2nd
        refvar_scores_key = cls.get_scores_key('refvar')
        ref1st_scores_key = cls.get_scores_key('ref1st')
        ref2nd_scores_key = cls.get_scores_key('ref2nd')
        disvar_scores_key = cls.get_scores_key('disvar')
        dis1st_scores_key = cls.get_scores_key('dis1st')
        dis2nd_scores_key = cls.get_scores_key('dis2nd')
        get_var = lambda m: m[1] - m[0] * m[0]
        result.result_dict[refvar_scores_key] = \
            to_list(map(get_var, zip(result.result_dict[ref1st_scores_key],
                             result.result_dict[ref2nd_scores_key])))
        result.result_dict[disvar_scores_key] = \
            to_list(map(get_var, zip(result.result_dict[dis1st_scores_key],
                             result.result_dict[dis2nd_scores_key])))

        # validate
        for feature in cls.DERIVED_ATOM_FEATURES:
            assert cls.get_scores_key(feature) in result.result_dict

        return result

class SsimFeatureExtractor(FeatureExtractor):

    TYPE = "SSIM_feature"
    # VERSION = "1.0"
    VERSION = "1.1" # fix OPT_RANGE_PIXEL_OFFSET = 0

    ATOM_FEATURES = ['ssim', 'ssim_l', 'ssim_c', 'ssim_s']

    def _generate_result(self, asset):
        # routine to call the command-line executable and generate quality
        # scores in the log file.

        quality_width, quality_height = asset.quality_width_height
        log_file_path = self._get_log_file_path(asset)

        yuv_type=self._get_workfile_yuv_type(asset)
        ref_path=asset.ref_workfile_path
        dis_path=asset.dis_workfile_path
        w=quality_width
        h=quality_height
        logger = self.logger

        ExternalProgramCaller.call_ssim(yuv_type, ref_path, dis_path, w, h, log_file_path, logger)


class MsSsimFeatureExtractor(FeatureExtractor):

    TYPE = "MS_SSIM_feature"
    # VERSION = "1.0"
    VERSION = "1.1" # fix OPT_RANGE_PIXEL_OFFSET = 0

    ATOM_FEATURES = ['ms_ssim',
                     'ms_ssim_l_scale0', 'ms_ssim_c_scale0', 'ms_ssim_s_scale0',
                     'ms_ssim_l_scale1', 'ms_ssim_c_scale1', 'ms_ssim_s_scale1',
                     'ms_ssim_l_scale2', 'ms_ssim_c_scale2', 'ms_ssim_s_scale2',
                     'ms_ssim_l_scale3', 'ms_ssim_c_scale3', 'ms_ssim_s_scale3',
                     'ms_ssim_l_scale4', 'ms_ssim_c_scale4', 'ms_ssim_s_scale4',
                     ]

    def _generate_result(self, asset):
        # routine to call the command-line executable and generate quality
        # scores in the log file.

        quality_width, quality_height = asset.quality_width_height
        log_file_path = self._get_log_file_path(asset)

        yuv_type=self._get_workfile_yuv_type(asset)
        ref_path=asset.ref_workfile_path
        dis_path=asset.dis_workfile_path
        w=quality_width
        h=quality_height
        logger = self.logger

        ExternalProgramCaller.call_ms_ssim(yuv_type, ref_path, dis_path, w, h, log_file_path, logger)



[((1573, 1607), 'vmaf.core.result.Result', 'Result', (['asset', 'executor_id', 'result'], {}), '(asset, executor_id, result)\n', (1579, 1607), False, 'from vmaf.core.result import Result\n'), ((6044, 6146), 'vmaf.ExternalProgramCaller.call_vmaf_feature', 'ExternalProgramCaller.call_vmaf_feature', (['yuv_type', 'ref_path', 'dis_path', 'w', 'h', 'log_file_path', 'logger'], {}), '(yuv_type, ref_path, dis_path, w, h,\n    log_file_path, logger)\n', (6083, 6146), False, 'from vmaf import ExternalProgramCaller, to_list\n'), ((14143, 14248), 'vmaf.ExternalProgramCaller.call_vifdiff_feature', 'ExternalProgramCaller.call_vifdiff_feature', (['yuv_type', 'ref_path', 'dis_path', 'w', 'h', 'log_file_path', 'logger'], {}), '(yuv_type, ref_path, dis_path, w,\n    h, log_file_path, logger)\n', (14185, 14248), False, 'from vmaf import ExternalProgramCaller, to_list\n'), ((17137, 17231), 'vmaf.ExternalProgramCaller.call_psnr', 'ExternalProgramCaller.call_psnr', (['yuv_type', 'ref_path', 'dis_path', 'w', 'h', 'log_file_path', 'logger'], {}), '(yuv_type, ref_path, dis_path, w, h,\n    log_file_path, logger)\n', (17168, 17231), False, 'from vmaf import ExternalProgramCaller, to_list\n'), ((19599, 19635), 'numpy.array', 'np.array', (["log_dict['ref_scores_mtx']"], {}), "(log_dict['ref_scores_mtx'])\n", (19607, 19635), True, 'import numpy as np\n'), ((19661, 19697), 'numpy.array', 'np.array', (["log_dict['dis_scores_mtx']"], {}), "(log_dict['dis_scores_mtx'])\n", (19669, 19697), True, 'import numpy as np\n'), ((22214, 22308), 'vmaf.ExternalProgramCaller.call_ssim', 'ExternalProgramCaller.call_ssim', (['yuv_type', 'ref_path', 'dis_path', 'w', 'h', 'log_file_path', 'logger'], {}), '(yuv_type, ref_path, dis_path, w, h,\n    log_file_path, logger)\n', (22245, 22308), False, 'from vmaf import ExternalProgramCaller, to_list\n'), ((23415, 23512), 'vmaf.ExternalProgramCaller.call_ms_ssim', 'ExternalProgramCaller.call_ms_ssim', (['yuv_type', 'ref_path', 'dis_path', 'w', 'h', 'log_file_path', 'logger'], {}), '(yuv_type, ref_path, dis_path, w, h,\n    log_file_path, logger)\n', (23449, 23512), False, 'from vmaf import ExternalProgramCaller, to_list\n'), ((18258, 18284), 'numpy.vstack', 'np.vstack', (['scores_mtx_list'], {}), '(scores_mtx_list)\n', (18267, 18284), True, 'import numpy as np\n'), ((18837, 18863), 'numpy.vstack', 'np.vstack', (['scores_mtx_list'], {}), '(scores_mtx_list)\n', (18846, 18863), True, 'import numpy as np\n'), ((19548, 19573), 'ast.literal_eval', 'ast.literal_eval', (['log_str'], {}), '(log_str)\n', (19564, 19573), False, 'import ast\n'), ((7803, 7858), 'numpy.array', 'np.array', (['result.result_dict[vif_num_scale0_scores_key]'], {}), '(result.result_dict[vif_num_scale0_scores_key])\n', (7811, 7858), True, 'import numpy as np\n'), ((7874, 7929), 'numpy.array', 'np.array', (['result.result_dict[vif_den_scale0_scores_key]'], {}), '(result.result_dict[vif_den_scale0_scores_key])\n', (7882, 7929), True, 'import numpy as np\n'), ((8012, 8067), 'numpy.array', 'np.array', (['result.result_dict[vif_num_scale1_scores_key]'], {}), '(result.result_dict[vif_num_scale1_scores_key])\n', (8020, 8067), True, 'import numpy as np\n'), ((8083, 8138), 'numpy.array', 'np.array', (['result.result_dict[vif_den_scale1_scores_key]'], {}), '(result.result_dict[vif_den_scale1_scores_key])\n', (8091, 8138), True, 'import numpy as np\n'), ((8221, 8276), 'numpy.array', 'np.array', (['result.result_dict[vif_num_scale2_scores_key]'], {}), '(result.result_dict[vif_num_scale2_scores_key])\n', (8229, 8276), True, 'import numpy as np\n'), ((8292, 8347), 'numpy.array', 'np.array', (['result.result_dict[vif_den_scale2_scores_key]'], {}), '(result.result_dict[vif_den_scale2_scores_key])\n', (8300, 8347), True, 'import numpy as np\n'), ((8430, 8485), 'numpy.array', 'np.array', (['result.result_dict[vif_num_scale3_scores_key]'], {}), '(result.result_dict[vif_num_scale3_scores_key])\n', (8438, 8485), True, 'import numpy as np\n'), ((8501, 8556), 'numpy.array', 'np.array', (['result.result_dict[vif_den_scale3_scores_key]'], {}), '(result.result_dict[vif_den_scale3_scores_key])\n', (8509, 8556), True, 'import numpy as np\n'), ((15548, 15607), 'numpy.array', 'np.array', (['result.result_dict[vifdiff_num_scale0_scores_key]'], {}), '(result.result_dict[vifdiff_num_scale0_scores_key])\n', (15556, 15607), True, 'import numpy as np\n'), ((15623, 15682), 'numpy.array', 'np.array', (['result.result_dict[vifdiff_den_scale0_scores_key]'], {}), '(result.result_dict[vifdiff_den_scale0_scores_key])\n', (15631, 15682), True, 'import numpy as np\n'), ((15769, 15828), 'numpy.array', 'np.array', (['result.result_dict[vifdiff_num_scale1_scores_key]'], {}), '(result.result_dict[vifdiff_num_scale1_scores_key])\n', (15777, 15828), True, 'import numpy as np\n'), ((15844, 15903), 'numpy.array', 'np.array', (['result.result_dict[vifdiff_den_scale1_scores_key]'], {}), '(result.result_dict[vifdiff_den_scale1_scores_key])\n', (15852, 15903), True, 'import numpy as np\n'), ((15990, 16049), 'numpy.array', 'np.array', (['result.result_dict[vifdiff_num_scale2_scores_key]'], {}), '(result.result_dict[vifdiff_num_scale2_scores_key])\n', (15998, 16049), True, 'import numpy as np\n'), ((16065, 16124), 'numpy.array', 'np.array', (['result.result_dict[vifdiff_den_scale2_scores_key]'], {}), '(result.result_dict[vifdiff_den_scale2_scores_key])\n', (16073, 16124), True, 'import numpy as np\n'), ((16211, 16270), 'numpy.array', 'np.array', (['result.result_dict[vifdiff_num_scale3_scores_key]'], {}), '(result.result_dict[vifdiff_num_scale3_scores_key])\n', (16219, 16270), True, 'import numpy as np\n'), ((16286, 16345), 'numpy.array', 'np.array', (['result.result_dict[vifdiff_den_scale3_scores_key]'], {}), '(result.result_dict[vifdiff_den_scale3_scores_key])\n', (16294, 16345), True, 'import numpy as np\n'), ((2665, 2692), 're.match', 're.match', (['re_template', 'line'], {}), '(re_template, line)\n', (2673, 2692), False, 'import re\n'), ((6651, 6699), 'numpy.array', 'np.array', (['result.result_dict[adm_num_scores_key]'], {}), '(result.result_dict[adm_num_scores_key])\n', (6659, 6699), True, 'import numpy as np\n'), ((6736, 6784), 'numpy.array', 'np.array', (['result.result_dict[adm_den_scores_key]'], {}), '(result.result_dict[adm_den_scores_key])\n', (6744, 6784), True, 'import numpy as np\n'), ((10492, 10547), 'numpy.array', 'np.array', (['result.result_dict[adm_num_scale0_scores_key]'], {}), '(result.result_dict[adm_num_scale0_scores_key])\n', (10500, 10547), True, 'import numpy as np\n'), ((10589, 10644), 'numpy.array', 'np.array', (['result.result_dict[adm_den_scale0_scores_key]'], {}), '(result.result_dict[adm_den_scale0_scores_key])\n', (10597, 10644), True, 'import numpy as np\n'), ((10752, 10807), 'numpy.array', 'np.array', (['result.result_dict[adm_num_scale1_scores_key]'], {}), '(result.result_dict[adm_num_scale1_scores_key])\n', (10760, 10807), True, 'import numpy as np\n'), ((10849, 10904), 'numpy.array', 'np.array', (['result.result_dict[adm_den_scale1_scores_key]'], {}), '(result.result_dict[adm_den_scale1_scores_key])\n', (10857, 10904), True, 'import numpy as np\n'), ((11012, 11067), 'numpy.array', 'np.array', (['result.result_dict[adm_num_scale2_scores_key]'], {}), '(result.result_dict[adm_num_scale2_scores_key])\n', (11020, 11067), True, 'import numpy as np\n'), ((11109, 11164), 'numpy.array', 'np.array', (['result.result_dict[adm_den_scale2_scores_key]'], {}), '(result.result_dict[adm_den_scale2_scores_key])\n', (11117, 11164), True, 'import numpy as np\n'), ((11272, 11327), 'numpy.array', 'np.array', (['result.result_dict[adm_num_scale3_scores_key]'], {}), '(result.result_dict[adm_num_scale3_scores_key])\n', (11280, 11327), True, 'import numpy as np\n'), ((11369, 11424), 'numpy.array', 'np.array', (['result.result_dict[adm_den_scale3_scores_key]'], {}), '(result.result_dict[adm_den_scale3_scores_key])\n', (11377, 11424), True, 'import numpy as np\n'), ((18172, 18204), 'numpy.hstack', 'np.hstack', (['([firstm], [secondm])'], {}), '(([firstm], [secondm]))\n', (18181, 18204), True, 'import numpy as np\n'), ((18751, 18783), 'numpy.hstack', 'np.hstack', (['([firstm], [secondm])'], {}), '(([firstm], [secondm]))\n', (18760, 18783), True, 'import numpy as np\n'), ((9343, 9398), 'numpy.array', 'np.array', (['result.result_dict[vif_num_scale3_scores_key]'], {}), '(result.result_dict[vif_num_scale3_scores_key])\n', (9351, 9398), True, 'import numpy as np\n'), ((9418, 9473), 'numpy.array', 'np.array', (['result.result_dict[vif_den_scale3_scores_key]'], {}), '(result.result_dict[vif_den_scale3_scores_key])\n', (9426, 9473), True, 'import numpy as np\n'), ((2987, 3000), 'numpy.isnan', 'np.isnan', (['val'], {}), '(val)\n', (2995, 3000), True, 'import numpy as np\n'), ((3004, 3017), 'numpy.isinf', 'np.isinf', (['val'], {}), '(val)\n', (3012, 3017), True, 'import numpy as np\n'), ((9192, 9247), 'numpy.array', 'np.array', (['result.result_dict[vif_num_scale2_scores_key]'], {}), '(result.result_dict[vif_num_scale2_scores_key])\n', (9200, 9247), True, 'import numpy as np\n'), ((9267, 9322), 'numpy.array', 'np.array', (['result.result_dict[vif_den_scale2_scores_key]'], {}), '(result.result_dict[vif_den_scale2_scores_key])\n', (9275, 9322), True, 'import numpy as np\n'), ((12610, 12665), 'numpy.array', 'np.array', (['result.result_dict[adm_num_scale3_scores_key]'], {}), '(result.result_dict[adm_num_scale3_scores_key])\n', (12618, 12665), True, 'import numpy as np\n'), ((12712, 12767), 'numpy.array', 'np.array', (['result.result_dict[adm_den_scale3_scores_key]'], {}), '(result.result_dict[adm_den_scale3_scores_key])\n', (12720, 12767), True, 'import numpy as np\n'), ((8890, 8945), 'numpy.array', 'np.array', (['result.result_dict[vif_num_scale0_scores_key]'], {}), '(result.result_dict[vif_num_scale0_scores_key])\n', (8898, 8945), True, 'import numpy as np\n'), ((8965, 9020), 'numpy.array', 'np.array', (['result.result_dict[vif_den_scale0_scores_key]'], {}), '(result.result_dict[vif_den_scale0_scores_key])\n', (8973, 9020), True, 'import numpy as np\n'), ((9041, 9096), 'numpy.array', 'np.array', (['result.result_dict[vif_num_scale1_scores_key]'], {}), '(result.result_dict[vif_num_scale1_scores_key])\n', (9049, 9096), True, 'import numpy as np\n'), ((9116, 9171), 'numpy.array', 'np.array', (['result.result_dict[vif_den_scale1_scores_key]'], {}), '(result.result_dict[vif_den_scale1_scores_key])\n', (9124, 9171), True, 'import numpy as np\n'), ((12405, 12460), 'numpy.array', 'np.array', (['result.result_dict[adm_num_scale2_scores_key]'], {}), '(result.result_dict[adm_num_scale2_scores_key])\n', (12413, 12460), True, 'import numpy as np\n'), ((12507, 12562), 'numpy.array', 'np.array', (['result.result_dict[adm_den_scale2_scores_key]'], {}), '(result.result_dict[adm_den_scale2_scores_key])\n', (12515, 12562), True, 'import numpy as np\n'), ((11995, 12050), 'numpy.array', 'np.array', (['result.result_dict[adm_num_scale0_scores_key]'], {}), '(result.result_dict[adm_num_scale0_scores_key])\n', (12003, 12050), True, 'import numpy as np\n'), ((12097, 12152), 'numpy.array', 'np.array', (['result.result_dict[adm_den_scale0_scores_key]'], {}), '(result.result_dict[adm_den_scale0_scores_key])\n', (12105, 12152), True, 'import numpy as np\n'), ((12200, 12255), 'numpy.array', 'np.array', (['result.result_dict[adm_num_scale1_scores_key]'], {}), '(result.result_dict[adm_num_scale1_scores_key])\n', (12208, 12255), True, 'import numpy as np\n'), ((12302, 12357), 'numpy.array', 'np.array', (['result.result_dict[adm_den_scale1_scores_key]'], {}), '(result.result_dict[adm_den_scale1_scores_key])\n', (12310, 12357), True, 'import numpy as np\n')]