SSI计算方法.txt
# Specification S-2018-001 # Spectral Similarity Index (SSI) # The Academy of Motion Picture Arts and Sciences # Science and Technology Council # Solid State Lighting (SSL) Project # # The Science and Technology Council wishes to acknowledge the following key contributors to the creation # of the SSI metric and the drafting and review of this document and the procedure and calculations described. # Jack Holm Tom Maier Paul Debevec Chloe LeGendre # Joshua Pines Jonathan Erland George Joblove Scott Dyer # Blake Sloan Joe di Gennaro Dan Sherlock Alex Forsythe g.Trap30x301 = NULL # matrix for trapezoidal integration. Created one time in a session, on demand. # x colorSpec object of type 'light', with M test spectra # reference colorSpec object of type 'light' with 1 or M reference spectra. # if NULL, then M reference spectra are computed from the CCT of x # digits for rounding the output # isotherms isotherms for the CCT # locus locus for the CCT # # returns an M-vector with SSI for the corresponding pair of test and reference spectra computeSSI.colorSpec 25000. SSI is NA.", specnames(x)[j], CCT ) next } ref30 = g.Trap30x301 %*% as.matrix(ref) # a vector of length 30 } else { k = min( j, numref ) ref30 = ref30xNUMREF[ ,k] refname[j] = specnames(reference)[k] } # 4.3 Area Normalize sumref30 = sum(ref30) if( is.na(sumref30) || sumref30 <= 0 ) { log.string( WARN, "reference spectrum %d has invalid sum=%g. SSI is NA.", j, sumref30 ) next } ref30 = ref30 / sumref30 out[j] = computeSSI30( test30, ref30 ) } out = round( out, digits=digits ) # to comply with official SSI spec, set digits=0 names(out) = sprintf( "%s_SSI[%s]", specnames(x), refname ) return(out) } # test30 30-vector of test samples (380 to 670 by 10nm). Steps 4.3 and earlier # ref30 30-vector of ref samples (380 to 670 by 10nm). Steps 4.3 and earlier computeSSI30 <- function( test30, ref30 ) { # 4.4 Create Normalized Difference Vector d30 = test30 - ref30 # 4.5 Create Relative Difference Vector dr30 = d30 / (ref30 + 1/length(ref30)) # 4.6 Weighted Relative Difference Vector w = c( c(12,22,32,40,44)/45, rep(1,23), c(11,3)/15 ) # about 3 microseconds dw30 = w * dr30 # 4.7 Smooth the Weighted Relative Difference Vector s = stats::filter( c(0,dw30,0), c(0.22,0.56,0.22), method="convolution", sides=2 )[2:31] # filter() puts NAs on both ends, so subset [2:31] # 4.8 Calculate SSI Value (to full precision and do not round) SSI = 100 - 32*sqrt(sum(s^2)) return(SSI) } # this function is designed to be called only 1 time per session # it takes about 170 usec makeTrap30x301 <- function() { lambda1 = seq(375,675,by=1) # fine lambda10 = seq(380,670,by=10) # coarse out = matrix( 0, length(lambda10), length(lambda1) ) trap = c( 0.5, rep(1,9), 0.5 ) # length is 1+9+1 = 11 for( i in 1:nrow(out) ) { out[ i, (10*(i-1)+1):(10*i+1) ] = trap } return( out ) } #-------- UseMethod() calls --------------# computeSSI <-function( x, reference=NULL, digits=0, isotherms='mccamy', locus='robertson' ) { UseMethod("computeSSI") }