Пример #1
0
def _compute_groups(samples, test_type, grouping, subjects, paired, *args):
    """ calculate test statistic for PERMDISP"""
    groups = []

    samples['grouping'] = grouping
    if test_type == 'centroid':
        centroids = samples.groupby('grouping').aggregate('mean')
    elif test_type == 'median':
        centroids = samples.groupby('grouping').aggregate(_config_med)

    for label, df in samples.groupby('grouping'):
        groups.append(
            cdist(df.values[:, :-1], [centroids.loc[label].values],
                  metric='euclidean'))

    stat, _ = f_oneway(*groups)
    stat = stat[0]

    # effect sizes:
    num_groups = len(np.unique(grouping))
    sample_size = len(grouping)
    if paired == True:
        dfErr = (num_groups - 1) * (len(np.unique(subjects)) - 1)
    else:
        dfErr = sample_size - num_groups
    R2 = 1.0 - 1 / (1 + stat * num_groups / (dfErr - 1))
    R2adj = 1 - ((1 - R2) * (sample_size - 1) / (sample_size - num_groups - 1))
    effect_sizes = {
        'p_eta2': np.nan,
        'omega2': np.nan,
        'R2': R2,
        'R2adj': R2adj
    }  # not yet determined

    return stat, effect_sizes
Пример #2
0
def _create_subjects_index_arr(subjects=None, grouping=None):
    """ Create subjects indexing array"""
    if subjects is None:
        if grouping is None:
            raise Exception('Grouping must be supplied!')
        groups = np.unique(grouping)
        for i, group in enumerate(groups):
            if i == 0:
                subjects = np.arange(((grouping == group) * 1).sum())
            else:
                subjects = np.hstack(
                    (subjects, np.arange(((grouping == group) * 1).sum())))
    return subjects
Пример #3
0
def _permutate_grouping(grouping, subjects, paired=False):
    """ permutate grouping and subjects indexing arrays"""
    if paired == False:
        perm_idx = np.arange(grouping.shape[0], dtype=int)
        perm_idx = np.random.permutation(perm_idx)
        perm_grouping = grouping[perm_idx]
        perm_subjects = subjects[perm_idx]
    else:
        groups = np.unique(grouping)
        o = 10**((grouping.reshape(len(groups),
                                   len(grouping) // len(groups))) + 1)
        if subjects is not None:
            s = subjects.reshape(len(groups), len(grouping) // len(groups))
        for i in range(o.shape[-1]):
            perm_idx = np.arange(o.shape[0], dtype=int)
            perm_idx = np.random.permutation(perm_idx)
            o[:, i] = o[perm_idx, i]
            s[:, i] = s[perm_idx, i]
        o = np.log10(o) - 1
        perm_grouping = o.flatten()
        if subjects is not None:
            perm_subjects = s.flatten()
    return perm_grouping, perm_subjects
Пример #4
0
def render_image(img = None, spd = None, rfl = None, out = 'img_hyp', \
                 refspd = None, D = None, cieobs = _CIEOBS, \
                 cspace = 'xyz', cspace_tf = {}, CSF = None,\
                 interp_type = 'nd', k_neighbours = 4, show = True,
                 verbosity = 0, show_ref_img = True,\
                 stack_test_ref = 12,\
                 write_to_file = None):
    """
    Render image under specified light source spd.
    
    Args:
        :img: 
            | None or str or ndarray with float (max = 1) rgb image.
            | None load a default image.
        :spd: 
            | ndarray, optional
            | Light source spectrum for rendering
            | If None: use CIE illuminant F4
        :rfl: 
            | ndarray, optional
            | Reflectance set for color coordinate to rfl mapping.
        :out: 
            | 'img_hyp' or str, optional
            |  (other option: 'img_ren': rendered image under :spd:)
        :refspd:
            | None, optional
            | Reference spectrum for color coordinate to rfl mapping.
            | None defaults to D65 (srgb has a D65 white point)
        :D: 
            | None, optional
            | Degree of (von Kries) adaptation from spd to refspd. 
        :cieobs:
            | _CIEOBS, optional
            | CMF set for calculation of xyz from spectral data.
        :cspace:
            | 'xyz',  optional
            | Color space for color coordinate to rfl mapping.
            | Tip: Use linear space (e.g. 'xyz', 'Yuv',...) for (interp_type == 'nd'),
            |      and perceptually uniform space (e.g. 'ipt') for (interp_type == 'nearest')
        :cspace_tf:
            | {}, optional
            | Dict with parameters for xyz_to_cspace and cspace_to_xyz transform.
        :CSF:
            | None, optional
            | RGB camera response functions.
            | If None: input :xyz: contains raw rgb values. Override :cspace:
            | argument and perform estimation directly in raw rgb space!!!
        :interp_type:
            | 'nd', optional
            | Options:
            | - 'nd': perform n-dimensional linear interpolation using Delaunay triangulation.
            | - 'nearest': perform nearest neighbour interpolation. 
        :k_neighbours:
            | 4 or int, optional
            | Number of nearest neighbours for reflectance spectrum interpolation.
            | Neighbours are found using scipy.spatial.cKDTree
        :show: 
            | True, optional
            |  Show images.
        :verbosity:
            | 0, optional
            | If > 0: make a plot of the color coordinates of original and 
              rendered image pixels.
        :show_ref_img:
            | True, optional
            | True: shows rendered image under reference spd. False: shows
            |  original image.
        :write_to_file:
            | None, optional
            | None: do nothing, else: write to filename(+path) in :write_to_file:
        :stack_test_ref: 
            | 12, optional
            |   - 12: left (test), right (ref) format for show and imwrite
            |   - 21: top (test), bottom (ref)
            |   - 1: only show/write test
            |   - 2: only show/write ref
            |   - 0: show both, write test

    Returns:
        :returns: 
            | img_hyp, img_ren, 
            | ndarrays with float hyperspectral image and rendered images 
    """

    # Get image:
    #imread = lambda x: plt.imread(x) #matplotlib.pyplot

    if img is not None:
        if isinstance(img, str):
            img = plt.imread(img)  # use matplotlib.pyplot's imread
    else:
        img = plt.imread(_HYPSPCIM_DEFAULT_IMAGE)
    if isinstance(img, np.uint8):
        img = img / 255
    elif isinstance(img, np.uint16):
        img = img / (2**16 - 1)

    # Convert to 2D format:
    rgb = img.reshape(img.shape[0] * img.shape[1], 3)  # *1.0: make float
    rgb[rgb == 0] = _EPS  # avoid division by zero for pure blacks.

    # Get unique rgb values and positions:
    rgb_u, rgb_indices = np.unique(rgb, return_inverse=True, axis=0)

    # get rfl set:
    if rfl is None:  # use IESTM30['4880'] set
        rfl = _CRI_RFL['ies-tm30']['4880']['5nm']
    wlr = rfl[
        0]  # spectral reflectance set determines wavelength range for estimation (xyz_to_rfl())

    # get Ref spd:
    if refspd is None:
        refspd = _CIE_ILLUMINANTS['D65'].copy()
    refspd = cie_interp(
        refspd, wlr,
        kind='linear')  # force spd to same wavelength range as rfl

    # Convert rgb_u to xyz and lab-type values under assumed refspd:
    if CSF is None:
        xyz_wr = spd_to_xyz(refspd, cieobs=cieobs, relative=True)
        xyz_ur = colortf(rgb_u * 255, tf='srgb>xyz')
    else:
        xyz_ur = rgb_u  # for input in xyz_to_rfl (when CSF is not None: this functions assumes input is indeed rgb !!!)

    # Estimate rfl's for xyz_ur:
    rfl_est, xyzri = xyz_to_rfl(xyz_ur, rfl = rfl, out = 'rfl_est,xyz_est', \
                 refspd = refspd, D = D, cieobs = cieobs, \
                 cspace = cspace, cspace_tf = cspace_tf, CSF = CSF,\
                 interp_type = interp_type, k_neighbours = k_neighbours,
                 verbosity = verbosity)

    # Get default test spd if none supplied:
    if spd is None:
        spd = _CIE_ILLUMINANTS['F4']

    if CSF is None:
        # calculate xyz values under test spd:
        xyzti, xyztw = spd_to_xyz(spd, rfl=rfl_est, cieobs=cieobs, out=2)

        # Chromatic adaptation from test spd to refspd:
        if D is not None:
            xyzti = cat.apply(xyzti, xyzw1=xyztw, xyzw2=xyz_wr, D=D)

        # Convert xyzti under test spd to srgb:
        rgbti = colortf(xyzti, tf='srgb') / 255
    else:
        # Calculate rgb coordinates from camera sensitivity functions under spd:
        rgbti = rfl_to_rgb(rfl_est, spd=spd, CSF=CSF, wl=None)

        # Chromatic adaptation from test spd to refspd:
        if D is not None:
            white = np.ones_like(spd)
            white[0] = spd[0]
            rgbwr = rfl_to_rgb(white, spd=refspd, CSF=CSF, wl=None)
            rgbwt = rfl_to_rgb(white, spd=spd, CSF=CSF, wl=None)
            rgbti = cat.apply_vonkries2(rgbti,
                                        rgbwt,
                                        rgbwr,
                                        xyzw0=np.array([[1.0, 1.0, 1.0]]),
                                        in_='rgb',
                                        out_='rgb',
                                        D=1)

    # Reconstruct original locations for rendered image rgbs:
    img_ren = rgbti[rgb_indices]
    img_ren.shape = img.shape  # reshape back to 3D size of original
    img_ren = img_ren

    # For output:
    if show_ref_img == True:
        rgb_ref = colortf(xyzri, tf='srgb') / 255 if (
            CSF is None
        ) else xyzri  # if CSF not None: xyzri contains rgbri !!!
        img_ref = rgb_ref[rgb_indices]
        img_ref.shape = img.shape  # reshape back to 3D size of original
        img_str = 'Rendered (under ref. spd)'
        img = img_ref
    else:
        img_str = 'Original'
        img = img

    if (stack_test_ref > 0) | show == True:
        if stack_test_ref == 21:
            img_original_rendered = np.vstack(
                (img_ren, np.ones((4, img.shape[1], 3)), img))
            img_original_rendered_str = 'Rendered (under test spd)\n ' + img_str
        elif stack_test_ref == 12:
            img_original_rendered = np.hstack(
                (img_ren, np.ones((img.shape[0], 4, 3)), img))
            img_original_rendered_str = 'Rendered (under test spd) | ' + img_str
        elif stack_test_ref == 1:
            img_original_rendered = img_ren
            img_original_rendered_str = 'Rendered (under test spd)'
        elif stack_test_ref == 2:
            img_original_rendered = img
            img_original_rendered_str = img_str
        elif stack_test_ref == 0:
            img_original_rendered = img_ren
            img_original_rendered_str = 'Rendered (under test spd)'

    if write_to_file is not None:
        # Convert from RGB to BGR formatand write:
        #print('Writing rendering results to image file: {}'.format(write_to_file))
        with warnings.catch_warnings():
            warnings.simplefilter("ignore")
            imsave(write_to_file, img_original_rendered)

    if show == True:
        # show images using pyplot.show():
        plt.figure()

        plt.imshow(img_original_rendered)
        plt.title(img_original_rendered_str)
        plt.gca().get_xaxis().set_ticklabels([])
        plt.gca().get_yaxis().set_ticklabels([])

        if stack_test_ref == 0:
            plt.figure()
            plt.imshow(img)
            plt.title(img_str)
            plt.axis('off')

    if 'img_hyp' in out.split(','):
        # Create hyper_spectral image:
        rfl_image_2D = rfl_est[
            rgb_indices +
            1, :]  # create array with all rfls required for each pixel
        img_hyp = rfl_image_2D.reshape(img.shape[0], img.shape[1],
                                       rfl_image_2D.shape[1])

    # Setup output:
    if out == 'img_hyp':
        return img_hyp
    elif out == 'img_ren':
        return img_ren
    else:
        return eval(out)
def genMonteCarloObs(n_obs=1,
                     fieldsize=10,
                     list_Age=[32],
                     out='LMS',
                     wl=None,
                     allow_negative_values=False):
    """
    Monte-Carlo generation of individual observer cone fundamentals.
    
    Args: 
        :n_obs: 
            | 1, optional
            | Number of observer CMFs to generate.
        :list_Age:
            | list of observer ages or str, optional
            | Defaults to 32 (cfr. CIE2006 CMFs)
            | If 'us_census': use US population census of 2010 
              to generate list_Age.
        :fieldsize: 
            | fieldsize in degrees (between 2° and 10°), optional
            | Defaults to 10°.
        :out: 
            | 'LMS' or str, optional
            | Determines output.
        :wl: 
            | None, optional
            | Interpolation/extraplation of :LMS: output to specified wavelengths.
            | None: output original _WL = np.array([390,780,5])
        :allow_negative_values: 
            | False, optional
            | Cone fundamentals or color matching functions 
            |   should not have negative values.
            |     If False: X[X<0] = 0.
    
    Returns:
        :returns: 
            | LMS [,var_age, vAll] 
            |   - LMS: ndarray with population LMS functions.
            |   - var_age: ndarray with population observer ages.
            |   - vAll: dict with population physiological factors (see .keys()) 
            
    References:
         1. `Asano Y, Fairchild MD, and Blondé L (2016). 
         Individual Colorimetric Observer Model. 
         PLoS One 11, 1–19. 
         <http://journals.plos.org/plosone/article?id=10.1371/journal.pone.0145671>`_
         
         2. `Asano Y, Fairchild MD, Blondé L, and Morvan P (2016). 
         Color matching experiment for highlighting interobserver variability. 
         Color Res. Appl. 41, 530–539. 
         <https://onlinelibrary.wiley.com/doi/abs/10.1002/col.21975>`_
         
         3. `CIE, and CIE (2006). 
         Fundamental Chromaticity Diagram with Physiological Axes - Part I 
         (Vienna: CIE). 
         <http://www.cie.co.at/publications/fundamental-chromaticity-diagram-physiological-axes-part-1>`_ 
         
         4. `Asano's Individual Colorimetric Observer Model 
         <https://www.rit.edu/cos/colorscience/re_AsanoObserverFunctions.php>`_
    """

    # Scale down StdDev by scalars optimized using Asano's 75 observers
    # collected in Germany:
    stdDevAllParam = _INDVCMF_STD_DEV_ALL_PARAM.copy()
    scale_factors = [0.98, 0.98, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5]
    scale_factors = dict(zip(list(stdDevAllParam.keys()), scale_factors))
    stdDevAllParam = {
        k: v * scale_factors[k]
        for (k, v) in stdDevAllParam.items()
    }

    # Get Normally-distributed Physiological Factors:
    vAll = getMonteCarloParam(n_obs=n_obs)

    if list_Age is 'us_census':
        list_Age = getUSCensusAgeDist()

    # Generate Random Ages with the same probability density distribution
    # as color matching experiment:
    sz_interval = 1
    list_AgeRound = np.round(np.array(list_Age) / sz_interval) * sz_interval
    h = math.histogram(list_AgeRound,
                       bins=np.unique(list_AgeRound),
                       bin_center=True)[0]
    p = h / h.sum()  # probability density distribution

    var_age = np.random.choice(np.unique(list_AgeRound), \
                               size = n_obs, replace = True,\
                               p = p)

    # Set requested wavelength range:
    if wl is not None:
        wl = getwlr(wl3=wl)
    else:
        wl = _WL

    LMS_All = np.zeros((3 + 1, wl.shape[0], n_obs))
    LMS_All.fill(np.nan)
    for k in range(n_obs):
        t_LMS, t_trans_lens, t_trans_macula, t_sens_photopig = cie2006cmfsEx(age = var_age[k], fieldsize = fieldsize, wl = wl,\
                                                                          var_od_lens = vAll['od_lens'][k], var_od_macula = vAll['od_macula'][k], \
                                                                          var_od_L = vAll['od_L'][k], var_od_M = vAll['od_M'][k], var_od_S = vAll['od_S'][k],\
                                                                          var_shft_L = vAll['shft_L'][k], var_shft_M = vAll['shft_M'][k], var_shft_S = vAll['shft_S'][k],\
                                                                          out = 'LMS,trans_lens,trans_macula,sens_photopig')
        LMS_All[:, :, k] = t_LMS


#        listout = out.split(',')
#        if ('trans_lens' in listout) | ('trans_macula' in listout) | ('trans_photopig' in listout):
#            trans_lens[:,k] = t_trans_lens
#            trans_macula[:,k] = t_trans_macula
#            sens_photopig[:,:,k] = t_sens_photopig

    if n_obs == 1:
        LMS_All = np.squeeze(LMS_All, axis=2)

    if ('xyz' in out.lower().split(',')):
        LMS_All = lmsb_to_xyzb(LMS_All,
                               fieldsize,
                               out='xyz',
                               allow_negative_values=allow_negative_values)
        out = out.replace('xyz', 'LMS').replace('XYZ', 'LMS')
    if ('lms' in out.lower().split(',')):
        out = out.replace('lms', 'LMS')

    if (out == 'LMS'):
        return LMS_All
    elif (out == 'LMS,var_age,vAll'):
        return LMS_All, var_age, vAll
    else:
        return eval(out)
Пример #6
0
def initialize_VF_hue_angles(hx = None, Cxr = _VF_MAXR, \
                             cri_type = _VF_CRI_DEFAULT, \
                             modeltype = _VF_MODEL_TYPE,\
                             determine_hue_angles = _DETERMINE_HUE_ANGLES):
    """
    Initialize the hue angles that will be used to 'summarize' 
    the VF model fitting parameters.
    
    Args:       
        :hx: 
            | None or ndarray, optional
            | None defaults to Munsell H5 hues.
        :Cxr: 
            | _VF_MAXR, optional
        :cri_type: 
            | _VF_CRI_DEFAULT or str or dict, optional,
            | Cri_type parameters for cri and VF model.
        :modeltype:
            | _VF_MODEL_TYPE or 'M5' or 'M6', optional
            | Determines the type of polynomial model.
        :determine_hue_angles:
            | _DETERMINE_HUE_ANGLES or True or False, optional
            | True: determines the 10 primary / secondary Munsell hues ('5..').
            | Note that for 'M6', an additional 
            
    Returns:
        :pcolorshift: 
            | {'href': href,
            |           'Cref' : _VF_MAXR, 
            |           'sig' : _VF_SIG, 
            |           'labels' : list[str]}
    """

    ###########################################
    # Get Munsell H5 hues:
    ###########################################

    rflM = _MUNSELL['R']
    hn = _MUNSELL['H']  # all Munsell hues
    rH5 = np.where([
        _MUNSELL['H'][:, 0][x][0] == '5'
        for x in range(_MUNSELL['H'][:, 0].shape[0])
    ])[0]  #all Munsell H5 hues
    hns5 = np.unique(_MUNSELL['H'][rH5])
    #------------------------------------------------------------------------------
    # Determine Munsell hue angles in cam02ucs:
    pool = False
    IllC = _CIE_ILLUMINANTS[
        'C']  # for determining Munsell hue angles in cam02ucs
    outM = VF_colorshift_model(IllC,
                               cri_type=cri_type,
                               sampleset=rflM,
                               vfcolor='g',
                               pool=pool)
    #------------------------------------------------------------------------------
    if (determine_hue_angles == True) | (hx is None):
        # find samples at major Munsell hue angles:
        all_h5_Munsell_cam02ucs = np.ones(hns5.shape)
        Jabt_IllC = outM[0]['Jab']['Jabt']
        for i, v in enumerate(hns5):
            hm = np.where(hn == v)[0]
            all_h5_Munsell_cam02ucs[i] = math.positive_arctan(
                [Jabt_IllC[hm, 0, 1].mean()], [Jabt_IllC[hm, 0, 2].mean()],
                htype='rad')[0]
        hx = all_h5_Munsell_cam02ucs

    #------------------------------------------------------------------------------
    # Setp color shift parameters:
    pcolorshift = {'href': hx, 'Cref': Cxr, 'sig': _VF_SIG, 'labels': hns5}
    return pcolorshift
Пример #7
0
def _compute_f_stat(sample_size, num_groups, tri_idxs, distances, group_sizes,
                    s_T, grouping, subjects, paired):
    """Compute PERMANOVA Pseudo-F."""
    s_WG, s_WS, s_WG_V = _compute_s_W_S(sample_size, num_groups, tri_idxs,
                                        distances, group_sizes, grouping,
                                        subjects, paired)

    # for pseudo-F1:
    s_BG = s_T - s_WG  # = s_Effect
    dfBG = (num_groups - 1)

    if (paired == True):
        s_BS = s_T - s_WS
        s_Error = s_WS - s_BG
        dfErr = (num_groups - 1) * (len(np.unique(subjects)) - 1)
        if np.isclose(s_Error, 0, atol=1e-9):
            s_Error = np.abs(s_Error)
        if (s_Error < 0):
            print('WARNING: s_Error = {:1.4f} < 0!'.format(s_Error))
            print(
                '         s_BG = {:1.4f}, s_WG = {:1.4f}, s_BS = {:1.4f}, s_WS = {:1.4f}.'
                .format(s_BG, s_WG, s_BS, s_WS))
            print(
                '         Setting s_Error to s_WGB (s_S -> 0) (cfr. paired = False)!'
            )
            s_Error = s_WG
            s_BS = np.nan
            dfErr = (sample_size - num_groups)

    else:
        s_Error = s_WG  # for pseudo-F1
        s_Error2 = s_WG_V  # for pseudo-F2
        s_BS = np.nan
        dfErr = (sample_size - num_groups)

    # test statistic, pseudo-F1:
    stat_ = (s_BG / dfBG) / (s_Error / dfErr)

    if paired == True:
        # test statistic, pseudo-F2 (equals pseudo-F1 for equal sample sizes!):
        stat = stat_
    else:
        # test statistic, pseudo-F2:
        stat = (s_BG) / (s_Error2)

    # effect sizes:
    p_eta2 = s_BG / (s_BG + s_Error)
    omega2 = (s_BG - dfBG * (s_Error / dfErr)) / (s_T - (s_Error / dfErr))
    R2 = 1.0 - 1 / (1 + stat * (dfBG / dfErr))
    #print('t:',sample_size, num_groups, (sample_size - num_groups - 1))
    R2adj = 1.0 - ((1 - R2) * (sample_size - 1) /
                   (sample_size - num_groups - 1))
    effect_sizes = {
        'p_eta2': p_eta2,
        'omega2': omega2,
        'R2': R2,
        'R2adj': R2adj
    }

    #    print('s_BG = {:1.2f}, s_WG = {:1.2f}, s_BS = {:1.2f}, s_WS = {:1.2f}, s_Err = {:1.2f} -- > s_T = {:1.2f}(Sum={:1.2f}:{:1.2f}).'.format(s_BG, s_WG, s_BS, s_WS, s_Error, s_T, s_BG + s_WG, s_BS + s_WS))

    if s_Error < 0:
        print('WARNING: s_Error = {:1.4f} <= 0!'.format(s_Error))
        print(
            '         s_BG = {:1.4f}, s_WG = {:1.4f}, s_BS = {:1.4f}, s_WS = {:1.4f}.'
            .format(s_BG, s_WG, s_BS, s_WS))
        print('         Setting F to NaN.')
        stat = np.nan
    return stat, effect_sizes