def spd_to_mcri(SPD, D=0.9, E=None, Yb=20.0, out='Rm', wl=None): """ Calculates the MCRI or Memory Color Rendition Index, Rm Args: :SPD: | ndarray with spectral data (can be multiple SPDs, first axis are the wavelengths) :D: | 0.9, optional | Degree of adaptation. :E: | None, optional | Illuminance in lux | (used to calculate La = (Yb/100)*(E/pi) to then calculate D | following the 'cat02' model). | If None: the degree is determined by :D: | If (:E: is not None) & (:Yb: is None): :E: is assumed to contain the adapting field luminance La (cd/m²). :Yb: | 20.0, optional | Luminance factor of background. (used when calculating La from E) | If None, E contains La (cd/m²). :out: | 'Rm' or str, optional | Specifies requested output (e.g. 'Rm,Rmi,cct,duv') :wl: | None, optional | Wavelengths (or [start, end, spacing]) to interpolate the SPDs to. | None: default to no interpolation Returns: :returns: | float or ndarray with MCRI Rm for :out: 'Rm' | Other output is also possible by changing the :out: str value. References: 1. `K.A.G. Smet, W.R. Ryckaert, M.R. Pointer, G. Deconinck, P. Hanselaer,(2012) “A memory colour quality metric for white light sources,” Energy Build., vol. 49, no. C, pp. 216–225. <http://www.sciencedirect.com/science/article/pii/S0378778812000837>`_ """ SPD = np2d(SPD) if wl is not None: SPD = spd(data=SPD, interpolation=_S_INTERP_TYPE, kind='np', wl=wl) # unpack metric default values: avg, catf, cieobs, cri_specific_pars, cspace, ref_type, rg_pars, sampleset, scale = [ _MCRI_DEFAULTS[x] for x in sorted(_MCRI_DEFAULTS.keys()) ] similarity_ai = cri_specific_pars['similarity_ai'] Mxyz2lms = cspace['Mxyz2lms'] scale_fcn = scale['fcn'] scale_factor = scale['cfactor'] sampleset = eval(sampleset) # A. calculate xyz: xyzti, xyztw = spd_to_xyz(SPD, cieobs=cieobs['xyz'], rfl=sampleset, out=2) if 'cct' in out.split(','): cct, duv = xyz_to_cct(xyztw, cieobs=cieobs['cct'], out='cct,duv', mode='lut') # B. perform chromatic adaptation to adopted whitepoint of ipt color space, i.e. D65: if catf is not None: Dtype_cat, F, Yb_cat, catmode_cat, cattype_cat, mcat_cat, xyzw_cat = [ catf[x] for x in sorted(catf.keys()) ] # calculate degree of adaptationn D: if E is not None: if Yb is not None: La = (Yb / 100.0) * (E / np.pi) else: La = E D = cat.get_degree_of_adaptation(Dtype=Dtype_cat, F=F, La=La) else: Dtype_cat = None # direct input of D if (E is None) and (D is None): D = 1.0 # set degree of adaptation to 1 ! if D > 1.0: D = 1.0 if D < 0.6: D = 0.6 # put a limit on the lowest D # apply cat: xyzti = cat.apply(xyzti, cattype=cattype_cat, catmode=catmode_cat, xyzw1=xyztw, xyzw0=None, xyzw2=xyzw_cat, D=D, mcat=[mcat_cat], Dtype=Dtype_cat) xyztw = cat.apply(xyztw, cattype=cattype_cat, catmode=catmode_cat, xyzw1=xyztw, xyzw0=None, xyzw2=xyzw_cat, D=D, mcat=[mcat_cat], Dtype=Dtype_cat) # C. convert xyz to ipt and split: ipt = xyz_to_ipt( xyzti, cieobs=cieobs['xyz'], M=Mxyz2lms ) #input matrix as published in Smet et al. 2012, Energy and Buildings I, P, T = asplit(ipt) # D. calculate specific (hue dependent) similarity indicators, Si: if len(xyzti.shape) == 3: ai = np.expand_dims(similarity_ai, axis=1) else: ai = similarity_ai a1, a2, a3, a4, a5 = asplit(ai) mahalanobis_d2 = (a3 * np.power((P - a1), 2.0) + a4 * np.power( (T - a2), 2.0) + 2.0 * a5 * (P - a1) * (T - a2)) if (len(mahalanobis_d2.shape) == 3) & (mahalanobis_d2.shape[-1] == 1): mahalanobis_d2 = mahalanobis_d2[:, :, 0].T Si = np.exp(-0.5 * mahalanobis_d2) # E. calculate general similarity indicator, Sa: Sa = avg(Si, axis=0, keepdims=True) # F. rescale similarity indicators (Si, Sa) with a 0-1 scale to memory color rendition indices (Rmi, Rm) with a 0 - 100 scale: Rmi = scale_fcn(np.log(Si), scale_factor=scale_factor) Rm = np2d(scale_fcn(np.log(Sa), scale_factor=scale_factor)) # G. calculate Rg (polyarea of test / polyarea of memory colours): if 'Rg' in out.split(','): I = I[ ..., None] #broadcast_shape(I, target_shape = None,expand_2d_to_3d = 0) a1 = a1[:, None] * np.ones( I.shape ) #broadcast_shape(a1, target_shape = None,expand_2d_to_3d = 0) a2 = a2[:, None] * np.ones( I.shape ) #broadcast_shape(a2, target_shape = None,expand_2d_to_3d = 0) a12 = np.concatenate( (a1, a2), axis=2 ) #broadcast_shape(np.hstack((a1,a2)), target_shape = ipt.shape,expand_2d_to_3d = 0) ipt_mc = np.concatenate((I, a12), axis=2) nhbins, normalize_gamut, normalized_chroma_ref, start_hue = [ rg_pars[x] for x in sorted(rg_pars.keys()) ] Rg = jab_to_rg(ipt, ipt_mc, ordered_and_sliced=False, nhbins=nhbins, start_hue=start_hue, normalize_gamut=normalize_gamut) if (out != 'Rm'): return eval(out) else: return Rm
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 plot_tm30_Rfi(spd, cri_type = 'ies-tm30', axh = None, font_size = _TM30_FONT_SIZE, **kwargs): """ Plot Sample Color Fidelity values (Rfi). Args: :spd: | ndarray or dict | If ndarray: single spectral power distribution. | If dict: dictionary with pre-computed parameters (using _tm30_process_spd()). | required keys: | 'Rf','Rg','cct','duv','Sr','cri_type','xyzri','xyzrw', | 'hbinnrs','Rfi','Rfhi','Rcshi','Rhshi', | 'jabt_binned','jabr_binned', | 'nhbins','start_hue','normalize_gamut','normalized_chroma_ref' | see cri.spd_to_cri() for more info on parameters. :cri_type: | _CRI_TYPE_DEFAULT or str or dict, optional | -'str: specifies dict with default cri model parameters | (for supported types, see luxpy.cri._CRI_DEFAULTS['cri_types']) | - dict: user defined model parameters | (see e.g. luxpy.cri._CRI_DEFAULTS['cierf'] | for required structure) | Note that any non-None input arguments (in kwargs) | to the function will override default values in cri_type dict. :axh: | None, optional | If None: create new figure with single axes, else plot on specified axes. :font_size: | _TM30_FONT_SIZE, optional | Font size of text, axis labels and axis values. :kwargs: | Additional optional keyword arguments, | the same as in cri.spd_to_cri() Returns: :axh: | handle to figure axes. :data: | dictionary with required parameters for plotting functions. """ data = _tm30_process_spd(spd, cri_type = 'ies-tm30',**kwargs) Rfi = data['Rfi'] # get rgb values representing each sample: N = data['xyzri'].shape[0] xyzw = spd_to_xyz(_CIE_D65, relative = True, cieobs = data['cri_type']['cieobs']['xyz']) xyzri = cat.apply(data['xyzri'][:,0,:],xyzw1 = data['xyzrw'], xyzw2 = xyzw) rgbri = xyz_to_srgb(xyzri)/255 # Create color map: cmap = [] for i in range(N): cmap.append(rgbri[i,...]) # Plot sample color fidelity, Rfi: if axh is None: fig, axh = plt.subplots(nrows = 1, ncols = 1) for j in range(N): axh.bar(j,Rfi[j,0], color = cmap[j], width = 1,edgecolor = None, alpha = 0.9) #axh.text(j,Rfi[j,0]*1.1, '{:1.0f}'.format(Rfi[j,0]) ,fontsize = 9,horizontalalignment='center',verticalalignment='center',color = np.array([1,1,1])*0.3) xticks = np.arange(0,N,step=2) xtickslabels = ['CES{:1.0f}'.format(ii+1) for ii in range(0,N,2)] axh.set_xticks(xticks) axh.set_xticklabels(xtickslabels, fontsize = font_size, rotation = 90) axh.set_ylabel(r'Color Sample Fidelity $(R_{f,CESi})$', fontsize = font_size) axh.set_ylim([0,100]) axh.set_xlim([-0.5,N-0.5]) return axh, data
def render_image(img = None, spd = None, rfl = None, out = 'img_hyp', \ refspd = None, D = None, cieobs = _CIEOBS, \ cspace = 'ipt', cspace_tf = {},\ 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 uint8 rgb image. | None load a default image. :spd: | ndarray, optional | Light source spectrum for rendering :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: | 'ipt', optional | Color space for color coordinate to rfl mapping. :cspace_tf: | {}, optional | Dict with parameters for xyz_to_cspace and cspace_to_xyz transform. :k_neighbours: | 4 or int, optional | Number of nearest neighbours for reflectance spectrum interpolation. | Neighbours are found using scipy.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 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) # Convert to 2D format: rgb = img.reshape(img.shape[0] * img.shape[1], 3) * 1.0 # *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 Ref spd: if refspd is None: refspd = _CIE_ILLUMINANTS['D65'].copy() # Convert rgb_u to xyz and lab-type values under assumed refspd: xyz_wr = spd_to_xyz(refspd, cieobs=cieobs, relative=True) xyz_ur = colortf(rgb_u, tf='srgb>xyz') # 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,\ k_neighbours = k_neighbours, verbosity = verbosity) # Get default test spd if none supplied: if spd is None: spd = _CIE_ILLUMINANTS['F4'] # 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 # Reconstruct original locations for rendered image rgbs: img_ren = rgbti[rgb_indices] img_ren.shape = img.shape # reshape back to 3D size of original # For output: if show_ref_img == True: rgb_ref = colortf(xyzri, tf='srgb') / 255 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 / 255 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_str) 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 _get_hue_map(hbins = 16, start_hue = 0.0, hbinnrs = None, xyzri = None, xyzrw = None, cri_type = None): """ Generate color map for hue bins. Args: :hbins: | 16 or ndarray with sorted hue bin centers (°), optional :start_hue: | 0.0, optional :hbinnrs: | None, optional | ndarray with hue bin number of each sample. | If hbinnrs, xyzri, xyzrw and cri_type are all not-None: | use these to calculate color map, otherwise just use number of | hue bins :hbins: and :start_hue: :xyzri: | None, optional | relative xyz tristimulus values of samples under ref. illuminant. | see :hbinnrs: for more info when this is used. :xyzrw: | None, optional | relative xyz tristimulus values of ref. illuminant white point. | see :hbinnrs: for more info when this is used. :cri_type: | None, optional | Specifies dict with default cri model parameters | (needed to get correct :cieobs:) | see :hbinnrs: for more info when this is used. Returns: :cmap: | list with rgb values (one for each hue bin) for plotting. """ # Setup hbincenters and hsv_hues: if isinstance(hbins,float) | isinstance(hbins,int): nhbins = hbins dhbins = 360/(nhbins) # hue bin width hbincenters = np.arange(start_hue + dhbins/2, 360, dhbins) hbincenters = np.sort(hbincenters) else: hbincenters = hbins idx = np.argsort(hbincenters) hbincenters = hbincenters[idx] nhbins = hbincenters.shape[0] cmap = [] if (hbinnrs is not None) & (xyzri is not None) & (xyzrw is not None) & (cri_type is not None): xyzw = spd_to_xyz(_CIE_D65, relative = True, cieobs = cri_type['cieobs']['xyz']) xyzri = cat.apply(xyzri[:,0,:],xyzw1 = xyzrw, xyzw2 = xyzw) # Create color from xyz average: for i in range(nhbins): xyzrhi = xyzri[hbinnrs[:,0] == i,:].mean(axis=0,keepdims=True) rgbrhi = xyz_to_srgb(xyzrhi)/255 cmap.append(rgbrhi) else: # Create color from hue angle: # Setup color for plotting hue bins: hbincenters = hbincenters*np.pi/180 hsv_hues = hbincenters - 30*np.pi/180 hsv_hues = hsv_hues/hsv_hues.max() for i in range(nhbins): #c = np.abs(np.array(colorsys.hsv_to_rgb(hsv_hues[i], 0.75, 0.85))) c = np.abs(np.array(colorsys.hls_to_rgb(hsv_hues[i], 0.45, 0.5))) cmap.append(c) return cmap