def DE2000(xyzt, xyzr, dtype='xyz', DEtype='jab', avg=None, avg_axis=0, out='DEi', xyzwt=None, xyzwr=None, KLCH=None): """ Calculate DE2000 color difference. Args: :xyzt: | ndarray with tristimulus values of test data. :xyzr: | ndarray with tristimulus values of reference data. :dtype: | 'xyz' or 'lab', optional | Specifies data type in :xyzt: and :xyzr:. :xyzwt: | None or ndarray, optional | White point tristimulus values of test data | None defaults to the one set in lx.xyz_to_lab() :xyzwr: | None or ndarray, optional | Whitepoint tristimulus values of reference data | None defaults to the one set in lx.xyz_to_lab() :DEtype: | 'jab' or str, optional | Options: | - 'jab' : calculates full color difference over all 3 dimensions. | - 'ab' : calculates chromaticity difference. | - 'j' : calculates lightness or brightness difference | (depending on :outin:). | - 'j,ab': calculates both 'j' and 'ab' options | and returns them as a tuple. :KLCH: | None, optional | Weigths for L, C, H | None: default to [1,1,1] :avg: | None, optional | None: don't calculate average DE, | otherwise use function handle in :avg:. :avg_axis: | axis to calculate average over, optional :out: | 'DEi' or str, optional | Requested output. Note: For the other input arguments, see specific color space used. Returns: :returns: | ndarray with DEi [, DEa] or other as specified by :out: References: 1. `Sharma, G., Wu, W., & Dalal, E. N. (2005). The CIEDE2000 color‐difference formula: Implementation notes, supplementary test data, and mathematical observations. Color Research & Application, 30(1), 21–30. <https://doi.org/10.1002/col.20070>`_ """ if KLCH is None: KLCH = [1, 1, 1] if dtype == 'xyz': labt = xyz_to_lab(xyzt, xyzw=xyzwt) labr = xyz_to_lab(xyzr, xyzw=xyzwr) else: labt = xyzt labr = xyzr Lt = labt[..., 0:1] at = labt[..., 1:2] bt = labt[..., 2:3] Ct = np.sqrt(at**2 + bt**2) #ht = cam.hue_angle(at,bt,htype = 'rad') Lr = labr[..., 0:1] ar = labr[..., 1:2] br = labr[..., 2:3] Cr = np.sqrt(ar**2 + br**2) #hr = cam.hue_angle(at,bt,htype = 'rad') # Step 1: Cavg = (Ct + Cr) / 2 G = 0.5 * (1 - np.sqrt((Cavg**7.0) / ((Cavg**7.0) + (25.0**7)))) apt = (1 + G) * at apr = (1 + G) * ar Cpt = np.sqrt(apt**2 + bt**2) Cpr = np.sqrt(apr**2 + br**2) Cpprod = Cpt * Cpr hpt = cam.hue_angle(apt, bt, htype='deg') hpr = cam.hue_angle(apr, br, htype='deg') hpt[(apt == 0) * (bt == 0)] = 0 hpr[(apr == 0) * (br == 0)] = 0 # Step 2: dL = np.abs(Lr - Lt) dCp = np.abs(Cpr - Cpt) dhp_ = hpr - hpt dhp = dhp_.copy() dhp[np.where(np.abs(dhp_) > 180)] = dhp[np.where(np.abs(dhp_) > 180)] - 360 dhp[np.where( np.abs(dhp_) < -180)] = dhp[np.where(np.abs(dhp_) < -180)] + 360 dhp[np.where(Cpprod == 0)] = 0 #dH = 2*np.sqrt(Cpprod)*np.sin(dhp/2*np.pi/180) dH = deltaH(dhp, Cpprod, htype='deg') # Step 3: Lp = (Lr + Lt) / 2 Cp = (Cpr + Cpt) / 2 hps = hpt + hpr hp = (hpt + hpr) / 2 hp[np.where((np.abs(dhp_) > 180) & (hps < 360))] = hp[np.where((np.abs(dhp_) > 180) & (hps < 360))] + 180 hp[np.where((np.abs(dhp_) > 180) & (hps >= 360))] = hp[np.where((np.abs(dhp_) > 180) & (hps >= 360))] - 180 hp[np.where(Cpprod == 0)] = 0 T = 1 - 0.17*np.cos((hp - 30)*np.pi/180) + 0.24*np.cos(2*hp*np.pi/180) +\ 0.32*np.cos((3*hp + 6)*np.pi/180) - 0.20*np.cos((4*hp - 63)*np.pi/180) dtheta = 30 * np.exp(-((hp - 275) / 25)**2) RC = 2 * np.sqrt((Cp**7) / ((Cp**7) + (25**7))) SL = 1 + ((0.015 * (Lp - 50)**2) / np.sqrt(20 + (Lp - 50)**2)) SC = 1 + 0.045 * Cp SH = 1 + 0.015 * Cp * T RT = -np.sin(2 * dtheta * np.pi / 180) * RC kL, kC, kH = KLCH DEi = ((dL / (kL * SL))**2, (dCp / (kC * SC))**2 + (dH / (kH * SH))**2 + RT * (dCp / (kC * SC)) * (dH / (kH * SH))) return _process_DEi(DEi, DEtype=DEtype, avg=avg, avg_axis=avg_axis, out=out)
def DE_cspace(xyzt, xyzr, dtype = 'xyz', tf = _CSPACE, DEtype = 'jab', avg = None, avg_axis = 0, out = 'DEi', xyzwt = None, xyzwr = None, fwtft = {}, fwtfr = {}, KLCH = None,\ camtype = cam._CAM_DEFAULT_TYPE, ucstype = 'ucs'): """ Calculate color difference DE in specific color space. Args: :xyzt: | ndarray with tristimulus values of test data. :xyzr: | ndarray with tristimulus values of reference data. :dtype: | 'xyz' or 'jab', optional | Specifies data type in :xyzt: and :xyzr:. :xyzwt: | None or ndarray, optional | White point tristimulus values of test data | None defaults to the one set in :fwtft: | or else to the default of cspace. :xyzwr: | None or ndarray, optional | Whitepoint tristimulus values of reference data | None defaults to the one set in non-empty :fwtfr: | or else to default of cspace. :tf: | _CSPACE, optional | Color space to use for color difference calculation. :fwtft: | {}, optional | Dict with parameters for forward transform from xyz to cspace for test data. :fwtfr: | {}, optional | Dict with parameters for forward transform | from xyz to cspace for reference data. :KLCH: | None, optional | Weigths for L, C, H | None: default to [1,1,1] | KLCH is not used when tf == 'camucs'. :DEtype: | 'jab' or str, optional | Options: | - 'jab' : calculates full color difference over all 3 dimensions. | - 'ab' : calculates chromaticity difference. | - 'j' : calculates lightness or brightness difference | (depending on :outin:). | - 'j,ab': calculates both 'j' and 'ab' options | and returns them as a tuple. :avg: | None, optional | None: don't calculate average DE, | otherwise use function handle in :avg:. :avg_axis: | axis to calculate average over, optional :out: | 'DEi' or str, optional | Requested output. :camtype: | luxpy.cam._CAM_DEFAULT_TYPE, optional | Str specifier for CAM type to use, options: 'ciecam02' or 'ciecam16'. | Only when DEtype == 'camucs'. :ucstype: | 'ucs' or 'lcd' or 'scd', optional | Str specifier for which type of color attribute compression | parameters to use: | -'ucs': uniform color space, | -'lcd', large color differences, | -'scd': small color differences | Only when DEtype == 'camucs'. Note: For the other input arguments, see specific color space used. Returns: :returns: | ndarray with DEi [, DEa] or other as specified by :out: """ # Get xyzw from dict if xyzw is None & dict is Not None if xyzwr is not None: fwtfr['xyzw'] = xyzwr else: if bool(fwtfr): xyzwr = fwtfr['xyzw'] if xyzwt is not None: fwtft['xyzw'] = xyzwt else: if bool(fwtft): xyzwt = fwtft['xyzw'] if tf == 'camucs': if dtype == 'xyz': if fwtfr['xyzw'] is None: fwtfr['xyzw'] = cam._CAM_DEFAULT_WHITE_POINT if fwtft['xyzw'] is None: fwtft['xyzw'] = cam._CAM_DEFAULT_WHITE_POINT jabt = cam.camXucs(xyzt, camtype=camtype, ucstype=ucstype, **fwtft) jabr = cam.camXucs(xyzr, camtype=camtype, ucstype=ucstype, **fwtfr) else: jabt = xyzt jabr = xyzr KL, c1, c2 = [ cam._CAM_UCS_PARAMETERS[camtype][ucstype][x] for x in sorted(cam._CAM_UCS_PARAMETERS[camtype][ucstype].keys()) ] # Calculate color difference and take account of KL: DEi = ((((jabt[...,0:1]-jabr[...,0:1])/KL)**2).sum(axis = jabt[...,0:1].ndim - 1, keepdims = True),\ ((jabt[...,1:3]-jabr[...,1:3])**2).sum(axis = jabt[...,1:3].ndim - 1, keepdims = True)) elif (tf == 'DE2000') | (tf == 'DE00'): return DE2000(xyzt, xyzr, dtype = 'xyz', DEtype = DEtype, avg = avg,\ avg_axis = avg_axis, out = out, xyzwt = xyzwt, xyzwr = xyzwr, KLCH = KLCH) else: if dtype == 'xyz': # Use colortf: jabt = colortf(xyzt, tf=tf, fwtf=fwtft) jabr = colortf(xyzr, tf=tf, fwtf=fwtfr) else: jabt = xyzt jabr = xyzr if (KLCH == None) | (KLCH == [1, 1, 1]): # Calculate color difference and take account of KL: DEi = (((jabt[...,0:1]-jabr[...,0:1])**2).sum(axis = jabt[...,0:1].ndim - 1, keepdims = True),\ ((jabt[...,1:3]-jabr[...,1:3])**2).sum(axis = jabt[...,1:3].ndim - 1, keepdims = True)) else: #using LCH specification for use with KLCH weights: Jt = jabt[..., 0:1] at = jabt[..., 1:2] bt = jabt[..., 2:3] Ct = np.sqrt(at**2 + bt**2) ht = cam.hue_angle(at, bt, htype='rad') Jr = jabr[..., 0:1] ar = jabr[..., 1:2] br = jabr[..., 2:3] Cr = np.sqrt(ar**2 + br**2) hr = cam.hue_angle(at, bt, htype='rad') dJ = Jt - Jr dC = Ct - Cr dH = ht - hr DEab2 = ((at - ar)**2 + (bt - br)**2) dH = np.sqrt(DEab2 - dC**2) DEi = ((dJ / KLCH[0])**2, (dC / KLCH[1])**2 + (dH / KLCH[2])**2) return _process_DEi(DEi, DEtype=DEtype, avg=avg, avg_axis=avg_axis, out=out)
jabt, jabr = out2 # jabt2,jabr2=out2 # ii=0 # ht = positive_arctan(jabt[:,ii,1],jabt[:,ii,2], htype='rad') # ht2 = positive_arctan(jabt2[...,1], jabt2[...,2], htype = 'rad') # ht = np.arctan2(jabt[:,ii,2],jabt[:,ii,1]) # ht2 = np.arctan2(jabt2[...,2], jabt2[...,1]) #----------------------------------------------------------- dh = 360 / nhbins hue_bin_edges = np.arange(start_hue, 360 + 1, dh) * np.pi / 180 # get hues of jabt, jabr: ht = cam.hue_angle(jabt[..., 1], jabt[..., 2], htype='rad') hr = cam.hue_angle(jabr[..., 1], jabr[..., 2], htype='rad') # Get chroma of jabt, jabr: Ct = ((jabt[..., 1]**2 + jabt[..., 2]**2))**0.5 Cr = ((jabr[..., 1]**2 + jabr[..., 2]**2))**0.5 # Calculate DEi between jabt, jabr: DEi = ((jabt - jabr)**2).sum(axis=-1, keepdims=True)**0.5 # calculate hue-bin averages for jabt, jabr: jabt_hj = np.ones((nhbins, ht.shape[1], 3)) * np.nan jabr_hj = np.ones((nhbins, hr.shape[1], 3)) * np.nan DE_hj = np.ones((nhbins, hr.shape[1])) * np.nan ht_idx = np.ones_like((ht)) * np.nan hr_idx = np.ones_like((hr)) * np.nan