def generate_vector_field(poly_model, pmodel, \ axr = np.arange(-_VF_MAXR,_VF_MAXR+_VF_DELTAR,_VF_DELTAR), \ bxr = np.arange(-_VF_MAXR,_VF_MAXR+_VF_DELTAR,_VF_DELTAR), \ make_grid = True, limit_grid_radius = 0,color = 'k'): """ Generates a field of vectors using the base color shift model. | Has the option to plot vector field. Args: :poly_model: | function handle to model :pmodel: | ndarray with model parameters. :axr: | np.arange(-_VF_MAXR,_VF_MAXR+_VF_DELTAR,_VF_DELTAR), optional | Ndarray specifying the a-coordinates at which to apply the model. :bxr: | np.arange(-_VF_MAXR,_VF_MAXR+_VF_DELTAR,_VF_DELTAR), optional | Ndarray specifying the b-coordinates at which to apply the model. :make_grid: | True, optional | True: generate a 2d-grid from :axr:, :bxr:. :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: :color: | 'k', optional | For plotting the vector field. | If :color: == 0, no plot will be generated. Returns: :returns: | If :color: == 0: ndarray of axt,bxt,axr,bxr | Else: handle to axes used for plotting. """ # Generate grid from axr, bxr: if make_grid == True: axr, bxr = generate_grid(ax=axr, bx=bxr, out='ax,bx', limit_grid_radius=limit_grid_radius) # Apply model at ref. coordinates: axt, bxt, Cxt, hxt, axr, bxr, Cxr, hxr = apply_poly_model_at_x( poly_model, pmodel, axr, bxr) # Plot vectorfield: if color is not 0: #plt.plot(axr, bxr,'ro',markersize=2) plt.quiver(axr, bxr, axt - axr, bxt - bxr, headlength=1, color=color) plt.xlabel("a'") plt.ylabel("b'") return plt.gca() #plt.show(plot1) else: return axt, bxt, axr, bxr
def plotceruleanline(cieobs=_CIEOBS, cspace=_CSPACE, axh=None, formatstr='ko-', cspace_pars={}): """ Plot cerulean (yellow (577 nm) - blue (472 nm)) line | Kuehni, CRA, 2014: | Table II: spectral lights. Args: :axh: | None or axes handle, optional | Determines axes to plot data in. | None: make new figure. :cieobs: | luxpy._CIEOBS or str, optional | Determines CMF set to calculate spectrum locus or other. :cspace: | luxpy._CSPACE or str, optional | Determines color space / chromaticity diagram to plot data in. | Note that data is expected to be in specified :cspace: :formatstr: | 'k-' or str, optional | Format str for plotting (see ?matplotlib.pyplot.plot) :cspace_pars: | {} or dict, optional | Dict with parameters required by color space specified in :cspace: | (for use with luxpy.colortf()) :kwargs: | additional keyword arguments for use with matplotlib.pyplot. Returns: :returns: | handle to cerulean line References: 1. `Kuehni, R. G. (2014). Unique hues and their stimuli—state of the art. Color Research & Application, 39(3), 279–287. <https://doi.org/10.1002/col.21793>`_ (see Table II, IV) """ if isinstance(cieobs, str): cmf = _CMF[cieobs]['bar'] else: cmf = cieobs p_y = cmf[0] == 577.0 #Kuehni, CRA 2013 (mean, table IV) p_b = cmf[0] == 472.0 #Kuehni, CRA 2013 (mean, table IV) xyz_y = cmf[1:, p_y].T xyz_b = cmf[1:, p_b].T lab = colortf(np.vstack((xyz_b, xyz_y)), tf=cspace, tfa0=cspace_pars) if axh is None: axh = plt.gca() hcerline = axh.plot(lab[:, 1], lab[:, 2], formatstr, label='Cerulean line') return hcerline
def plot(self, ylabel='Spectrum', wavelength_bar=True, *args, **kwargs): """ Make a plot of the spectral data in SPD instance. Returns: :returns: | handle to current axes. """ plt.plot(self.wl, self.value.T, *args, **kwargs) if wavelength_bar == True: Smax = np.nanmax(self.value) axh = plot_spectrum_colors(spd=None, spdmax=Smax, axh=plt.gca(), wavelength_height=-0.05) plt.xlabel('Wavelength (nm)') plt.ylabel(ylabel) return plt.gca()
def plot(self, plt_type='3d', ax=None, title=None, **kwargs): """ Plot color coordinates. Args: :plt_type: | '3d' or 3 or '2d or 2, optional | -'3d' or 3: plot all 3 dimensions (lightness and chromaticity) | -'2d' or 2: plot only chromaticity dimensions. :ax: | None or axes handles, optional | None: create new figure axes, else use :ax: for plotting. :title: | None or str, optional | Give plot a title. :**kwargs: | additional arguments for use with | matplotlib.pyplot.scatter Returns: :gca: | handle to current axes. """ L, a, b = self.split_() if ax is None: fig = plt.figure() if (plt_type == '2d') | (plt_type == 2): if ax is None: ax = fig.add_subplot(111) ax.scatter(a, b, **kwargs) else: if ax is None: ax = fig.add_subplot(111, projection='3d') ax.scatter(a, b, L, **kwargs) ax.set_zlabel(_CSPACE_AXES[self.dtype][0]) ax.set_xlabel(_CSPACE_AXES[self.dtype][1]) ax.set_ylabel(_CSPACE_AXES[self.dtype][2]) if title is not None: ax.set_title(title) return plt.gca()
def plot(self, ax=None, title=None, **kwargs): """ Plot tristimulus or cone fundamental values. Args: :ax: | None or axes handles, optional | None: create new figure axes, else use :ax: for plotting. :title: | None or str, optional | Give plot a title. :**kwargs: | additional arguments for use with | matplotlib.pyplot.scatter Returns: :gca: | handle to current axes. """ X, Y, Z = self.split_() if ax is None: fig = plt.figure() ax = fig.add_subplot(111, projection='3d') if self.dtype == 'xyz': ax.scatter(X, Z, Y, **kwargs) ax.set_xlabel(_CSPACE_AXES[self.dtype][0]) ax.set_ylabel(_CSPACE_AXES[self.dtype][2]) ax.set_zlabel(_CSPACE_AXES[self.dtype][1]) elif self.dtype == 'lms': ax.scatter(X, Y, Z, **kwargs) ax.set_xlabel(_CSPACE_AXES[self.dtype][0]) ax.set_ylabel(_CSPACE_AXES[self.dtype][1]) ax.set_zlabel(_CSPACE_AXES[self.dtype][2]) if title is not None: ax.set_title(title) return plt.gca()
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 plotUH(xyz0=None, uhues=[0, 1, 2, 3], cieobs=_CIEOBS, cspace=_CSPACE, axh=None, formatstr=['yo-.', 'bo-.', 'ro-.', 'go-.'], excludefromlegend='', cspace_pars={}): """ Plot unique hue lines from color space center point xyz0. | Kuehni, CRA, 2014: | uY,uB,uG: Table II: spectral lights; | uR: Table IV: Xiao data. Args: :xyz0: | None, optional | Center of color space (unique hue lines are expected to cross here) | None defaults to equi-energy-white. :uhues: | [0,1,2,3], optional | Unique hue lines to plot [0:'yellow',1:'blue',2:'red',3:'green'] :axh: | None or axes handle, optional | Determines axes to plot data in. | None: make new figure. :cieobs: | luxpy._CIEOBS or str, optional | Determines CMF set to calculate spectrum locus or other. :cspace: | luxpy._CSPACE or str, optional | Determines color space / chromaticity diagram to plot data in. | Note that data is expected to be in specified :cspace: :formatstr: | ['yo-.','bo-.','ro-.','go-.'] or list[str], optional | Format str for plotting the different unique lines | (see also ?matplotlib.pyplot.plot) :excludefromlegend: | '' or str, optional | To exclude certain hues from axes legend. :cspace_pars: | {} or dict, optional | Dict with parameters required by color space specified in :cspace: | (for use with luxpy.colortf()) Returns: :returns: | list[handles] to unique hue lines References: 1. `Kuehni, R. G. (2014). Unique hues and their stimuli—state of the art. Color Research & Application, 39(3), 279–287. <https://doi.org/10.1002/col.21793>`_ (see Table II, IV) """ hues = ['yellow', 'blue', 'red', 'green'] if isinstance(cieobs, str): cmf = _CMF[cieobs]['bar'] else: cmf = cieobs p_y = cmf[ 0] == 577.0 #unique yellow,#Kuehni, CRA 2013 (mean, table IV: spectral data) p_b = cmf[ 0] == 472.0 #unique blue,Kuehni, CRA 2013 (mean, table IV: spectral data) p_g = cmf[ 0] == 514.0 #unique green, Kuehni, CRA 2013 (mean, table II: spectral data) p_r = cmf[ 0] == 650.0 #unique red, Kuehni, CRA 2013 (Xiao data, table IV: display data) xyz_y = 100.0 * cmf[1:, p_y].T xyz_b = 100.0 * cmf[1:, p_b].T xyz_g = 100.0 * cmf[1:, p_g].T xyz_r = 100.0 * cmf[1:, p_r].T xyz_uh = np.vstack((xyz_y, xyz_b, xyz_r, xyz_g)) huniquehues = [] if xyz0 is None: xyz0 = np.array([100.0, 100.0, 100.0]) if axh is None: axh = plt.gca() for huenr in uhues: lab = colortf(np.vstack((xyz0, xyz_uh[huenr])), tf=cspace, tfa0=cspace_pars) huh = axh.plot(lab[:, 1], lab[:, 2], formatstr[huenr], label=excludefromlegend + 'Unique ' + hues[huenr]) huniquehues = [huniquehues, huh] return huniquehues