def mean(self): """ Take mean of all spectra in SPD instance. """ self.value = np.nanmean(self.value, axis=0, keepdims=True) self.shape = self.value.shape self.N = self.shape[0] return self
def PX_colorshift_model(Jabt, Jabr, jab_ranges=None, jab_deltas=None, limit_grid_radius=0): """ Pixelates the color space and calculates the color shifts in each pixel. Args: :Jabt: | ndarray with color coordinates under the (single) test SPD. :Jabr: | ndarray with color coordinates under the (single) reference SPD. :jab_ranges: | None or ndarray, optional | Specifies the pixelization of color space. | (ndarray.shape = (3,3), with first axis: J,a,b, and second | axis: min, max, delta) :jab_deltas: | float or ndarray, optional | Specifies the sampling range. | A float uses jab_deltas as the maximum Euclidean distance to select | samples around each pixel center. A ndarray of 3 deltas, uses | a city block sampling around each pixel center. :limit_grid_radius: | 0, optional | A value of zeros keeps grid as specified by axr,bxr. | A value > 0 only keeps (a,b) coordinates within :limit_grid_radius: Returns: :returns: | dict with the following keys: | - 'Jab': dict with with ndarrays for: | Jabt, Jabr, DEi, DEi_ab (only ab-coordinates), DEa (mean) | and DEa_ab | - 'vshifts': dict with: | * 'vectorshift': ndarray with vector shifts between average | Jabt and Jabr for each pixel | * 'vectorshift_ab': ndarray with vector shifts averaged | over J for each pixel | * 'vectorshift_ab_J0': ndarray with vector shifts averaged | over J for each pixel of J=0 plane. | * 'vectorshift_len': length of 'vectorshift' | * 'vectorshift_ab_len': length of 'vectorshift_ab' | * 'vectorshift_ab_J0_len': length of 'vectorshift_ab_J0' | * 'vectorshift_len_DEnormed': length of 'vectorshift' | normalized to 'DEa' | * 'vectorshift_ab_len_DEnormed': length of 'vectorshift_ab' | normalized to 'DEa_ab' | * 'vectorshift_ab_J0_len_DEnormed': length of 'vectorshift_ab_J0' | normalized to 'DEa_ab' | - 'pixeldata': dict with pixel info: | * 'grid' ndarray with coordinates of all pixel centers. | * 'idx': list[int] with pixel index for each non-empty pixel | * 'Jab': ndarray with center coordinates of non-empty pixels | * 'samplenrs': list[list[int]] with sample numbers belong to | each non-empty pixel | * 'IDs: summarizing list, | with column order: 'idxp, jabp, samplenrs' | - 'fielddata' : dict with dicts containing data on the calculated | vector-field and circle-fields | * 'vectorfield': dict with ndarrays for the ab-coordinates | under the ref. (axr, bxr) and test (axt, bxt) illuminants, | centered at the pixel centers corresponding to the ab-coordinates of the reference illuminant. """ # get pixelIDs of all samples under ref. conditions: gridp, idxp, jabp, pixelsamplenrs, pixelIDs = get_pixel_coordinates( Jabr, jab_ranges=jab_ranges, jab_deltas=jab_deltas, limit_grid_radius=limit_grid_radius) # get average Jab coordinates for each pixel: Npixels = len(idxp) # number of non-empty pixels Jabr_avg = np.zeros((gridp.shape[0], 3)) Jabr_avg.fill(np.nan) Jabt_avg = Jabr_avg.copy() for i in range(Npixels): Jabr_avg[idxp[i], :] = Jabr[pixelsamplenrs[i], :].mean(axis=0) Jabt_avg[idxp[i], :] = Jabt[pixelsamplenrs[i], :].mean(axis=0) #jabtemp = Jabr[pixelsamplenrs[i],:] #jabtempm = Jabr_avg[idxp[i],:] # calculate Jab vector shift: vectorshift = Jabt_avg - Jabr_avg # calculate ab vector shift: uabs = gridp[gridp[:, 0] == 0, 1:3] #np.unique(gridp[:,1:3],axis=0) vectorshift_ab_J0 = np.zeros((uabs.shape[0], 2)) vectorshift_ab_J0.fill(np.nan) vectorshift_ab = np.zeros((vectorshift.shape[0], 2)) vectorshift_ab.fill(np.nan) for i in range(uabs.shape[0]): cond = (gridp[:, 1:3] == uabs[i, :]).all(axis=1) if cond.any() & np.logical_not( np.isnan(vectorshift[cond, 1:3]).all() ): #last condition is to avoid warning of taking nanmean of empty slice when all are NaNs vectorshift_ab_J0[i, :] = np.nanmean(vectorshift[cond, 1:3], axis=0) vectorshift_ab[cond, :] = np.nanmean(vectorshift[cond, 1:3], axis=0) # Calculate length of shift vectors: vectorshift_len = np.sqrt((vectorshift**2).sum(axis=vectorshift.ndim - 1)) vectorshift_ab_len = np.sqrt( (vectorshift_ab**2).sum(axis=vectorshift_ab.ndim - 1)) vectorshift_ab_J0_len = np.sqrt( (vectorshift_ab_J0**2).sum(axis=vectorshift_ab_J0.ndim - 1)) # Calculate average DE for normalization of vectorshifts DEi_Jab_avg = np.sqrt(((Jabt - Jabr)**2).sum(axis=Jabr.ndim - 1)) DE_Jab_avg = DEi_Jab_avg.mean(axis=0) DEi_ab_avg = np.sqrt( ((Jabt[..., 1:3] - Jabr[..., 1:3])**2).sum(axis=Jabr[..., 1:3].ndim - 1)) DE_ab_avg = DEi_ab_avg.mean(axis=0) # calculate vectorfield: axr = uabs[:, 0, None] bxr = uabs[:, 1, None] axt = axr + vectorshift_ab_J0[:, 0, None] bxt = bxr + vectorshift_ab_J0[:, 1, None] data = { 'Jab': { 'Jabr': Jabr_avg, 'Jabt': Jabt_avg, 'DEi': DEi_Jab_avg, 'DEi_ab': DEi_ab_avg, 'DEa': DE_Jab_avg, 'DEa_ab': DE_ab_avg }, 'vshifts': { 'vectorshift': vectorshift, 'vectorshift_ab': vectorshift_ab, 'vectorshift_ab_J0': vectorshift_ab_J0, 'vectorshift_len': vectorshift_len, 'vectorshift_ab_len': vectorshift_ab_len, 'vectorshift_ab_J0_len': vectorshift_ab_J0_len, 'vectorshift_len_DEnormed': vectorshift_len / DE_Jab_avg, 'vectorshift_ab_len_DEnormed': vectorshift_ab_len / DE_ab_avg, 'vectorshift_ab_J0_len_DEnormed': vectorshift_ab_J0_len / DE_ab_avg }, 'pixeldata': { 'grid': gridp, 'idx': idxp, 'Jab': jabp, 'samplenrs': pixelsamplenrs, 'IDs': pixelIDs }, 'fielddata': { 'vectorfield': { 'axr': axr, 'bxr': bxr, 'axt': axt, 'bxt': bxt } } } return data
def subsample_RFL_set(rfl, rflpath = '', samplefcn = 'rand', S = _CIE_ILLUMINANTS['E'], \ jab_ranges = None, jab_deltas = None, cieobs = _VF_CIEOBS, cspace = _VF_CSPACE, \ ax = np.arange(-_VF_MAXR,_VF_MAXR+_VF_DELTAR,_VF_DELTAR), \ bx = np.arange(-_VF_MAXR,_VF_MAXR+_VF_DELTAR,_VF_DELTAR), \ jx = None, limit_grid_radius = 0): """ Sub-samples a spectral reflectance set by pixelization of color space. Args: :rfl: | ndarray or str | Array with of str referring to a set of spectral reflectance | functions to be subsampled. | If str to file: file must contain data as columns, with first | column the wavelengths. :rflpath: | '' or str, optional | Path to folder with rfl-set specified in a str :rfl: filename. :samplefcn: | 'rand' or 'mean', optional | -'rand': selects a random sample from the samples within each pixel | -'mean': returns the mean spectral reflectance in each pixel. :S: | _CIE_ILLUMINANTS['E'], optional | Illuminant used to calculate the color coordinates of the spectral | reflectance samples. :jab_ranges: | None or ndarray, optional | Specifies the pixelization of color space. | (ndarray.shape = (3,3), with first axis: J,a,b, and second | axis: min, max, delta) :jab_deltas: | float or ndarray, optional | Specifies the sampling range. | A float uses jab_deltas as the maximum Euclidean distance to select | samples around each pixel center. A ndarray of 3 deltas, uses | a city block sampling around each pixel center. :cspace: | _VF_CSPACE or dict, optional | Specifies color space. See _VF_CSPACE_EXAMPLE for example structure. :cieobs: | _VF_CIEOBS or str, optional | Specifies CMF set used to calculate color coordinates. :ax: | default ndarray or user defined ndarray, optional | default = np.arange(-_VF_MAXR,_VF_MAXR+_VF_DELTAR,_VF_DELTAR) :bx: | default ndarray or user defined ndarray, optional | default = np.arange(-_VF_MAXR,_VF_MAXR+_VF_DELTAR,_VF_DELTAR) :jx: | None, optional | Note that not-None :jab_ranges: override :ax:, :bx: and :jx input. :limit_grid_radius: | 0, optional | A value of zeros keeps grid as specified by axr,bxr. | A value > 0 only keeps (a,b) coordinates within :limit_grid_radius: Returns: :returns: | rflsampled, jabp | ndarrays with resp. the subsampled set of spectral reflectance | functions and the pixel coordinate centers. """ # Testing effects of sample set, pixel size and gamut size: if type(rfl) == str: rfl = pd.read_csv(os.path.join(rflpath, rfl), header=None).get_values().T # Calculate Jab coordinates of samples: xyz, xyzw = spd_to_xyz(S, cieobs=cieobs, rfl=rfl.copy(), out=2) cspace_pars = cspace.copy() cspace_pars.pop('type') cspace_pars['xyzw'] = xyzw jab = colortf(xyz, tf=cspace['type'], fwtf=cspace_pars) # Generate grid and get samples in each grid: gridp, idxp, jabp, pixelsamplenrs, pixelIDs = get_pixel_coordinates( jab, jab_ranges=jab_ranges, jab_deltas=jab_deltas, limit_grid_radius=limit_grid_radius) # Get rfls from set using sampling function (mean or rand): W = rfl[:1] R = rfl[1:] rflsampled = np.zeros((len(idxp), R.shape[1])) rflsampled.fill(np.nan) for i in range(len(idxp)): if samplefcn == 'mean': rfl_i = np.nanmean(rfl[pixelsamplenrs[i], :], axis=0) else: samplenr_i = np.random.randint(len(pixelsamplenrs[i])) rfl_i = rfl[pixelsamplenrs[i][samplenr_i], :] rflsampled[i, :] = rfl_i rflsampled = np.vstack((W, rflsampled)) return rflsampled, jabp
def calculate_VF_PX_models(S, cri_type = _VF_CRI_DEFAULT, sampleset = None, pool = False, \ pcolorshift = {'href': np.arange(np.pi/10,2*np.pi,2*np.pi/10),\ 'Cref' : _VF_MAXR, 'sig' : _VF_SIG, 'labels' : '#'},\ vfcolor = 'k', verbosity = 0): """ Calculate Vector Field and Pixel color shift models. Args: :cri_type: | _VF_CRI_DEFAULT or str or dict, optional | Specifies type of color fidelity model to use. | Controls choice of ref. ill., sample set, averaging, scaling, etc. | See luxpy.cri.spd_to_cri for more info. :sampleset: | None or str or ndarray, optional | Sampleset to be used when calculating vector field model. :pool: | False, optional | If :S: contains multiple spectra, True pools all jab data before | modeling the vector field, while False models a different field | for each spectrum. :pcolorshift: | default dict (see below) or user defined dict, optional | Dict containing the specification input | for apply_poly_model_at_hue_x(). | Default dict = {'href': np.arange(np.pi/10,2*np.pi,2*np.pi/10), | 'Cref' : _VF_MAXR, | 'sig' : _VF_SIG, | 'labels' : '#'} | The polynomial models of degree 5 and 6 can be fully specified or | summarized by the model parameters themselved OR by calculating the | dCoverC and dH at resp. 5 and 6 hues. :vfcolor: | 'k', optional | For plotting the vector fields. :verbosity: | 0, optional | Report warnings or not. Returns: :returns: | :dataVF:, :dataPX: | Dicts, for more info, see output description of resp.: | luxpy.cri.VF_colorshift_model() and luxpy.cri.PX_colorshift_model() """ # calculate VectorField cri_color_shift model: dataVF = VF_colorshift_model(S, cri_type=cri_type, sampleset=sampleset, vfcolor=vfcolor, pcolorshift=pcolorshift, pool=pool, verbosity=verbosity) # Set jab_ranges and _deltas for PX-model pixel calculations: PX_jab_deltas = np.array([_VF_DELTAR, _VF_DELTAR, _VF_DELTAR ]) #set same as for vectorfield generation PX_jab_ranges = np.vstack( ([0, 100, _VF_DELTAR], [-_VF_MAXR, _VF_MAXR + _VF_DELTAR, _VF_DELTAR], [-_VF_MAXR, _VF_MAXR + _VF_DELTAR, _VF_DELTAR])) #IES4880 gamut # Calculate shift vectors using vectorfield and pixel methods: delta_SvsVF_vshift_ab_mean = np.zeros((len(dataVF), 1)) delta_SvsVF_vshift_ab_mean.fill(np.nan) delta_SvsVF_vshift_ab_mean_normalized = delta_SvsVF_vshift_ab_mean.copy() delta_PXvsVF_vshift_ab_mean = np.zeros((len(dataVF), 1)) delta_PXvsVF_vshift_ab_mean.fill(np.nan) delta_PXvsVF_vshift_ab_mean_normalized = delta_PXvsVF_vshift_ab_mean.copy() dataPX = [[] for k in range(len(dataVF))] for Snr in range(len(dataVF)): # Calculate shifts using pixel method, PX: dataPX[Snr] = PX_colorshift_model(dataVF[Snr]['Jab']['Jabt'][:, 0, :], dataVF[Snr]['Jab']['Jabr'][:, 0, :], jab_ranges=PX_jab_ranges, jab_deltas=PX_jab_deltas, limit_grid_radius=_VF_MAXR) # Calculate shift difference between Samples (S) and VectorField model predictions (VF): delta_SvsVF_vshift_ab = dataVF[Snr]['vshifts']['vshift_ab_s'] - dataVF[ Snr]['vshifts']['vshift_ab_s_vf'] delta_SvsVF_vshift_ab_mean[Snr] = np.nanmean(np.sqrt( (delta_SvsVF_vshift_ab[..., 1:3]**2).sum( axis=delta_SvsVF_vshift_ab[..., 1:3].ndim - 1)), axis=0) delta_SvsVF_vshift_ab_mean_normalized[ Snr] = delta_SvsVF_vshift_ab_mean[Snr] / dataVF[Snr]['Jab'][ 'DEi'].mean(axis=0) # Calculate shift difference between PiXel method (PX) and VectorField (VF): delta_PXvsVF_vshift_ab = dataPX[Snr]['vshifts'][ 'vectorshift_ab_J0'] - dataVF[Snr]['vshifts']['vshift_ab_vf'] delta_PXvsVF_vshift_ab_mean[Snr] = np.nanmean(np.sqrt( (delta_PXvsVF_vshift_ab[..., 1:3]**2).sum( axis=delta_PXvsVF_vshift_ab[..., 1:3].ndim - 1)), axis=0) delta_PXvsVF_vshift_ab_mean_normalized[ Snr] = delta_PXvsVF_vshift_ab_mean[Snr] / dataVF[Snr]['Jab'][ 'DEi'].mean(axis=0) dataVF[Snr]['vshifts'][ 'delta_PXvsVF_vshift_ab_mean'] = delta_PXvsVF_vshift_ab_mean[Snr] dataVF[Snr]['vshifts'][ 'delta_SvsVF_vshift_ab_mean'] = delta_SvsVF_vshift_ab_mean[Snr] dataVF[Snr]['vshifts'][ 'delta_SvsVF_vshift_ab_mean_normalized'] = delta_SvsVF_vshift_ab_mean_normalized[ Snr] dataVF[Snr]['vshifts'][ 'delta_PXvsVF_vshift_ab_mean_normalized'] = delta_PXvsVF_vshift_ab_mean_normalized[ Snr] dataPX[Snr]['vshifts']['delta_PXvsVF_vshift_ab_mean'] = dataVF[Snr][ 'vshifts']['delta_PXvsVF_vshift_ab_mean'] dataPX[Snr]['vshifts'][ 'delta_PXvsVF_vshift_ab_mean_normalized'] = dataVF[Snr]['vshifts'][ 'delta_PXvsVF_vshift_ab_mean_normalized'] return dataVF, dataPX
def spd_to_COI_ASNZS1680(S=None, tf=_COI_CSPACE, cieobs=_COI_CIEOBS, out='COI,cct', extrapolate_rfl=False): """ Calculate the Cyanosis Observation Index (COI) [ASNZS 1680.2.5-1995]. Args: :S: | ndarray with light source spectrum (first column are wavelengths). :tf: | _COI_CSPACE, optional | Color space in which to calculate the COI. | Default is CIELAB. :cieobs: | _COI_CIEOBS, optional | CMF set to use. | Default is '1931_2'. :out: | 'COI,cct' or str, optional | Determines output. :extrapolate_rfl: | False, optional | If False: | limit the wavelength range of the source to that of the standard | reflectance spectra for the 50% and 100% oxygenated blood. Returns: :COI: | ndarray with cyanosis indices for input sources. :cct: | ndarray with correlated color temperatures. Note: Clause 7.2 of the ASNZS 1680.2.5-1995. standard mentions the properties demanded of the light source used in region where visual conditions suitable to the detection of cyanosis should be provided: 1. The correlated color temperature (CCT) of the source should be from 3300 to 5300 K. 2. The cyanosis observation index should not exceed 3.3 """ if S is None: #use default S = _CIE_ILLUMINANTS['F4'] if extrapolate_rfl == False: # _COI_RFL do not cover the full 360-830nm range. wl_min = _COI_RFL_BLOOD[0].min() wl_max = _COI_RFL_BLOOD[0].max() S = S[:, np.where((S[0] >= wl_min) & (S[0] <= wl_max))[0]] # Calculate reference spd: Sr = blackbody(4000, wl3=S[0]) # same wavelength range # Calculate xyz of blood under test source and ref. source: xyzt, xyzwt = spd_to_xyz(S, rfl=_COI_RFL_BLOOD, relative=True, cieobs=cieobs, out=2) xyzr, xyzwr = spd_to_xyz(Sr, rfl=_COI_RFL_BLOOD, relative=True, cieobs=cieobs, out=2) # Calculate color difference between blood under test and ref. DEi = deltaE.DE_cspace(xyzt, xyzr, xyzwt=xyzwt, xyzwr=xyzwr, tf=tf) # Calculate Cyanosis Observation Index: COI = np.nanmean(DEi, axis=0)[:, None] # Calculate cct, if requested: if 'cct' in out.split(','): cct, duv = xyz_to_cct(xyzwt, cieobs=cieobs, out=2) # manage output: if out == 'COI': return COI elif out == 'COI,cct': return COI, cct else: return eval(out)
def spd_to_ies_tm30_metrics(St, cri_type = None, \ hbins = 16, start_hue = 0.0,\ scalef = 100, \ vf_model_type = _VF_MODEL_TYPE, \ vf_pcolorshift = _VF_PCOLORSHIFT,\ scale_vf_chroma_to_sample_chroma = False): """ Calculates IES TM30 metrics from spectral data. Args: :St: | numpy.ndarray with spectral data :cri_type: | None, optional | If None: defaults to cri_type = 'iesrf'. | Not none values of :hbins:, :start_hue: and :scalef: overwrite | input in cri_type['rg_pars'] :hbins: | None or numpy.ndarray with sorted hue bin centers (°), optional :start_hue: | None, optional :scalef: | None, optional | Scale factor for reference circle. :vf_pcolorshift: | _VF_PCOLORSHIFT or user defined dict, optional | The polynomial models of degree 5 and 6 can be fully specified or | summarized by the model parameters themselved OR by calculating the | dCoverC and dH at resp. 5 and 6 hues. :VF_pcolorshift: specifies | these hues and chroma level. :scale_vf_chroma_to_sample_chroma: | False, optional | Scale chroma of reference and test vf fields such that average of | binned reference chroma equals that of the binned sample chroma | before calculating hue bin metrics. Returns: :data: | Dictionary with color rendering data: | | - 'St, Sr' : ndarray of test SPDs and corresponding ref. illuminants. | - 'xyz_cct': xyz of white point calculate with cieobs defined for cct calculations in cri_type['cieobs'] | - 'cct, duv': CCT and Duv obtained with cieobs in cri_type['cieobs']['cct'] | - 'xyzti, xyzri': ndarray tristimulus values of test and ref. samples (obtained with with cieobs in cri_type['cieobs']['xyz']) | - 'xyztw, xyzrw': ndarray tristimulus values of test and ref. white points (obtained with with cieobs in cri_type['cieobs']['xyz']) | - 'DEi, DEa': ndarray with individual sample color differences DEi and average DEa between test and ref. | - 'Rf' : ndarray with general color fidelity index values | - 'Rg' : ndarray with color gamut area index values | - 'Rfi' : ndarray with specific (sample) color fidelity indices | - 'Rfhj' : ndarray with local (hue binned) fidelity indices | - 'DEhj' : ndarray with local (hue binned) color differences | - 'Rcshj': ndarray with local chroma shifts indices | - 'Rhshj': ndarray with local hue shifts indices | - 'hue_bin_data': dict with output from _get_hue_bin_data() [see its help for more info] | - 'cri_type': same as input (for reference purposes) | - 'vf' : dictionary with vector field measures and data. | Keys: | - 'Rt' : ndarray with general metameric uncertainty index Rt | - 'Rti' : ndarray with specific metameric uncertainty indices Rti | - 'Rfhj' : ndarray with local (hue binned) fidelity indices | obtained from VF model predictions at color space | pixel coordinates | - 'DEhj' : ndarray with local (hue binned) color differences | (same as above) | - 'Rcshj': ndarray with local chroma shifts indices for vectorfield coordinates | (same as above) | - 'Rhshj': ndarray with local hue shifts indicesfor vectorfield coordinates | (same as above) | - 'Rfi': ndarray with sample fidelity indices for vectorfield coordinates | (same as above) | - 'DEi': ndarray with sample color differences for vectorfield coordinates | (same as above) | - 'hue_bin_data': dict with output from _get_hue_bin_data() for vectorfield coordinates | - 'dataVF': dictionary with output of cri.VFPX.VF_colorshift_model() """ if cri_type is None: cri_type = 'iesrf' if isinstance(cri_type,str): # get dict cri_type = copy.deepcopy(_CRI_DEFAULTS[cri_type]) if hbins is not None: cri_type['rg_pars']['nhbins'] = hbins if start_hue is not None: cri_type['rg_pars']['start_hue'] = start_hue if scalef is not None: cri_type['rg_pars']['normalized_chroma_ref'] = scalef #Calculate color rendering measures for SPDs in St: data,_ = spd_to_cri(St, cri_type = cri_type, out = 'data,hue_bin_data', fit_gamut_ellipse = True) hdata = data['hue_bin_data'] Rfhj, Rcshj, Rhshj = data['Rfhj'], data['Rcshj'], data['Rhshj'] cct = data['cct'] #Calculate Metameric uncertainty and base color shifts: dataVF = VF_colorshift_model(St, cri_type = cri_type, model_type = vf_model_type, cspace = cri_type['cspace'], sampleset = eval(cri_type['sampleset']), pool = False, pcolorshift = vf_pcolorshift, vfcolor = 0) Rf_ = np.array([dataVF[i]['metrics']['Rf'] for i in range(len(dataVF))]).T Rt = np.array([dataVF[i]['metrics']['Rt'] for i in range(len(dataVF))]).T Rti = np.array([dataVF[i]['metrics']['Rti'] for i in range(len(dataVF))][0]) _data_vf = {'Rt' : Rt, 'Rti' : Rti, 'Rf_' : Rf_} # add to dict for output # Get normalized and sliced hue-bin _hj data for plotting: rg_pars = cri_type['rg_pars'] nhbins, normalize_gamut, normalized_chroma_ref, start_hue = [rg_pars[x] for x in sorted(rg_pars.keys())] # Get chroma of samples: if scale_vf_chroma_to_sample_chroma == True: jabt_hj_closed, jabr_hj_closed = hdata['jabt_hj_closed'], hdata['jabr_hj_closed'] Cr_hj_s = (np.sqrt(jabr_hj_closed[:-1,...,1]**2 + jabr_hj_closed[:-1,...,2]**2)).mean(axis=0) # for rescaling vector field average reference chroma #jabtn_hj_closed, jabrn_hj_closed = hdata['jabtn_hj_closed'], hdata['jabrn_hj_closed'] # get vector field data for each source (must be on 2nd dim) jabt_vf = np.transpose(np.array([np.hstack((np.ones(dataVF[i]['fielddata']['vectorfield']['axt'].shape),dataVF[i]['fielddata']['vectorfield']['axt'],dataVF[i]['fielddata']['vectorfield']['bxt'])) for i in range(cct.shape[0])]),(1,0,2)) jabr_vf = np.transpose(np.array([np.hstack((np.ones(dataVF[i]['fielddata']['vectorfield']['axr'].shape),dataVF[i]['fielddata']['vectorfield']['axr'],dataVF[i]['fielddata']['vectorfield']['bxr'])) for i in range(cct.shape[0])]),(1,0,2)) # Get hue bin data for vector field data: hue_bin_data_vf = _get_hue_bin_data(jabt_vf, jabr_vf, start_hue = start_hue, nhbins = nhbins, normalized_chroma_ref = normalized_chroma_ref ) # Rescale chroma of vector field such that it is on average equal to that of the binned samples: if scale_vf_chroma_to_sample_chroma == True: Cr_vf_hj, Cr_vf, Ct_vf = hue_bin_data_vf['Cr_hj'], hue_bin_data_vf['Cr'], hue_bin_data_vf['Ct'] hr_vf, ht_vf = hue_bin_data_vf['hr'], hue_bin_data_vf['ht'] fC = np.nanmean(Cr_hj_s)/np.nanmean(Cr_vf_hj) jabr_vf[...,1], jabr_vf[...,2] = fC * Cr_vf*np.cos(hr_vf), fC * Cr_vf*np.sin(hr_vf) jabt_vf[...,1], jabt_vf[...,2] = fC * Ct_vf*np.cos(ht_vf), fC * Ct_vf*np.sin(ht_vf) # Get new hue bin data for rescaled vector field data: hue_bin_data_vf = _get_hue_bin_data(jabt_vf, jabr_vf, start_hue = start_hue, nhbins = nhbins, normalized_chroma_ref = normalized_chroma_ref ) # Get scale factor and scaling function for Rfx: scale_factor = cri_type['scale']['cfactor'] scale_fcn = cri_type['scale']['fcn'] # Calculate Local color fidelity, chroma and hue shifts for vector field data: (Rcshj_vf, Rhshj_vf, Rfhj_vf, DEhj_vf) = _hue_bin_data_to_rxhj(hue_bin_data_vf, cri_type = cri_type, scale_factor = scale_factor, scale_fcn = scale_fcn) # Get sample color fidelity for vector field data: (Rfi_vf, DEi_vf) = _hue_bin_data_to_rfi(hue_bin_data_vf, cri_type = cri_type, scale_factor = scale_factor, scale_fcn = scale_fcn) # Store in dict: _data_vf.update({'Rfi' : Rfi_vf, 'DEi' : DEi_vf, 'Rcshj' : Rcshj_vf, 'Rhshj' : Rhshj_vf, 'Rfhj' : Rfhj_vf, 'DEhj': DEhj_vf, 'dataVF' : dataVF, 'hue_bin_data' : hue_bin_data_vf}) # Add to main dictionary: data['vf'] = _data_vf return data