Nothing
if( 1 )
{
library( spacesRGB )
# ls(2)
}
options( width=128 )
cat( 'getwd=', getwd(), '\n' )
path = "CGATS.RR" # system.file( "CGATS.R", package='spacesRGB' )
file.info( path )
source( path )
options( width=256 )
printf <- function( msg, ... )
{
mess = sprintf( msg[1], ... ) # should this really be msg[1] ?
cat( mess, '\n' ) #, file=stderr() )
}
testACES <- function( path="test_values.txt", tol.RGB=1e-5, tol.XYZ=5e-3, tol.RGBsce=5e-5, subset=NULL, redmod='1.1' )
{
data = readCGATS( path )
if( is.null(data) ) return(NULL)
n = length(data)
out = list() #vector(n,mode='list')
# names(out) = names(data)
invalid = integer(0)
for( i in 1:n )
{
theTable = data[[i]]
m = nrow(theTable)
theName = names(data)[i]
theOETF = NULL
theEOTF = NULL
theOOTF = NULL
if( ! is.null(subset) && ! theName %in% subset ) next # ignore this table
if( theName == '5.1' )
{
theOETF = general.RRT( redmod=redmod ) * general.PODT( P3D60_PRI, Ymax=48 ) * power.OETF( 2.6 )
theEOTF = power.EOTF( 2.6 )
#aces2signal = theOETF
#signal2XYZ = theEOTF * XYZfromRGB.TF( P3D60_PRI, 48 )
#aces2XYZ = aces2signal * signal2XYZ
}
else if( theName == '5.2' )
{
theOETF = general.RRT( redmod=redmod ) * general.PODT( P3D65_PRI, Ymax=48 ) * power.OETF( 2.6 )
theEOTF = power.EOTF( 2.6 )
#aces2signal = theOETF
#signal2XYZ = theEOTF * XYZfromRGB.TF( P3D65_PRI, 48 )
#aces2XYZ = aces2signal * signal2XYZ
}
else if( theName == '5.3' )
{
# set observerWP to D60 so there is no CAT
theOETF = general.RRT( redmod=redmod ) * general.PODT( P3D65_PRI, Ymax=48, observer=P3D60_PRI[4,] ) * power.OETF( 2.6 )
theEOTF = power.EOTF( 2.6 )
#aces2signal = theOETF
#signal2XYZ = theEOTF * XYZfromRGB.TF( P3D65_PRI, 48 )
#aces2XYZ = aces2signal * signal2XYZ
}
else if( theName == '5.4' )
{
theOETF = general.RRT( redmod=redmod ) * general.PODT( P3D65_PRI, Ymax=48, limiting_pri=REC709_PRI ) * power.OETF( 2.6 )
theEOTF = power.EOTF( 2.6 )
#aces2signal = theOETF
#signal2XYZ = theEOTF * XYZfromRGB.TF( P3D65_PRI, 48 )
#aces2XYZ = aces2signal * signal2XYZ
}
else if( theName == '5.5' )
{
# set observerWP to D60 so there is no CAT
theOETF = general.RRT( redmod=redmod ) * general.PODT( P3DCI_PRI, Ymax=48, observer=P3D60_PRI['W',] ) * power.OETF( 2.6 )
theEOTF = power.EOTF( 2.6 )
#aces2signal = theOETF
#signal2XYZ = theEOTF * XYZfromRGB.TF( P3DCI_PRI, 48 )
#aces2XYZ = aces2signal * signal2XYZ
}
else if( theName == '5.6' )
{
# set observerWP to D65 so there IS a CAT
theOETF = general.RRT( redmod=redmod ) * general.PODT( P3DCI_PRI, Ymax=48, observer=P3D65_PRI['W',] ) * power.OETF( 2.6 )
theEOTF = power.EOTF( 2.6 )
#aces2signal = theOETF
#signal2XYZ = theEOTF * XYZfromRGB.TF( P3DCI_PRI, 48 )
#aces2XYZ = aces2signal * signal2XYZ
}
else if( theName == '5.7' )
{
theOETF = general.RRT( redmod=redmod ) * general.PODT( NULL, Ymax=48 ) * DCDM.EOTF^-1
theEOTF = DCDM.EOTF
#aces2signal = theOETF
#signal2XYZ = theEOTF * affine.TF(0,48)
#aces2XYZ = aces2signal * signal2XYZ
}
else if( theName == '5.8' )
{
theOETF = general.RRT( redmod=redmod ) * general.PODT( NULL, Ymax=48, limiting_pri=P3D60_PRI ) * DCDM.EOTF^-1
theEOTF = DCDM.EOTF
#aces2signal = theOETF
#signal2XYZ = theEOTF * affine.TF(0,48)
#aces2XYZ = aces2signal * signal2XYZ
}
else if( theName == '5.9' )
{
theOETF = general.RRT( redmod=redmod ) * general.PODT( NULL, Ymax=48, limiting_pri=P3D65_PRI ) * DCDM.EOTF^-1
theEOTF = DCDM.EOTF
#aces2signal = theOETF
#signal2XYZ = theEOTF * affine.TF(0,48)
#aces2XYZ = aces2signal * signal2XYZ
}
else if( theName == '6.1' )
{
# Rec709 - 100 nit
theOETF = general.RRT( redmod=redmod ) * general.PODT( REC709_PRI, Ymax=100, surround='dim' ) * BT.1886.EOTF()^-1
theEOTF = BT.1886.EOTF()
#aces2signal = theOETF
#signal2XYZ = theEOTF * XYZfromRGB.TF(REC709_PRI,100)
#aces2XYZ = aces2signal * signal2XYZ
}
else if( theName == '6.2' )
{
# Rec709 D60sim - 100 nit
# set observerWP to D60 so there is NO CAT
theOETF = general.RRT( redmod=redmod ) * general.PODT( REC709_PRI, Ymax=100, observer=P3D60_PRI['W',], surround='dim' ) * BT.1886.EOTF()^-1
theEOTF = BT.1886.EOTF()
#aces2signal = theOETF
#signal2XYZ = theEOTF * XYZfromRGB.TF(REC709_PRI,100)
#aces2XYZ = aces2signal * signal2XYZ
}
else if( theName == '6.3' )
{
# Rec2020 - 100 nit
theOETF = general.RRT( redmod=redmod ) * general.PODT( REC2020_PRI, Ymax=100, surround='dim' ) * BT.1886.EOTF()^-1
theEOTF = BT.1886.EOTF()
#aces2signal = theOETF
#signal2XYZ = theEOTF * XYZfromRGB.TF(REC2020_PRI,100)
#aces2XYZ = aces2signal * signal2XYZ
}
else if( theName == '6.4' )
{
# Rec2020 - (P3-D65 Limited) 100 nit
theOETF = general.RRT( redmod=redmod ) * general.PODT( REC2020_PRI, Ymax=100, limit=P3D65_PRI, surround='dim' ) * BT.1886.EOTF()^-1
theEOTF = BT.1886.EOTF()
#aces2signal = theOETF
#signal2XYZ = theEOTF * XYZfromRGB.TF(REC2020_PRI,100)
#aces2XYZ = aces2signal * signal2XYZ
}
else if( theName == '6.5' )
{
# Rec2020 - (Rec709 Limited) 100 nit
theOETF = general.RRT( redmod=redmod ) * general.PODT( REC2020_PRI, Ymax=100, limit=REC709_PRI, surround='dim' ) * BT.1886.EOTF()^-1
theEOTF = BT.1886.EOTF()
#aces2signal = theOETF
#signal2XYZ = theEOTF * XYZfromRGB.TF(REC2020_PRI,100)
#aces2XYZ = aces2signal * signal2XYZ
}
else if( theName == '7.1' )
{
# sRGB - 100 nit
theOETF = general.RRT( redmod=redmod ) * general.PODT( REC709_PRI, Ymax=100, surround='dim' ) * sRGB.EOTF^-1 #; print( str(theOETF) )
theEOTF = sRGB.EOTF
#aces2signal = theOETF
#signal2XYZ = theEOTF * XYZfromRGB.TF(REC709_PRI,100)
#aces2XYZ = aces2signal * signal2XYZ
}
else if( theName == '7.2' )
{
# sRGB D60sim - 100 nit
# set observerWP to D60 so there is NO CAT
theOETF = general.RRT( redmod=redmod ) * general.PODT( REC709_PRI, Ymax=100, observer=P3D60_PRI['W',], surround='dim' ) * sRGB.EOTF^-1
theEOTF = sRGB.EOTF
#aces2signal = theOETF
#signal2XYZ = theEOTF * XYZfromRGB.TF(REC709_PRI,100)
#aces2XYZ = aces2signal * signal2XYZ
}
else if( theName == '8.1' )
{
theOOTF = general.OOTF( disp=P3D65_PRI, Ymid=7.2, Ymax=108, redmod=redmod ) #* affine.TF(0,108)
theEOTF = PQ.EOTF(10000/108)
#aces2signal = theOOTF * theEOTF^-1
#aces2XYZ = theOOTF * XYZfromRGB.TF(P3D65_PRI,108)
#signal2XYZ = theEOTF * XYZfromRGB.TF(P3D65_PRI,108) # * affine.TF(0,108)^-1 * XYZfromRGB.TF(P3D65_PRI,108)
}
else if( theName == '9.1' )
{
theOOTF = general.OOTF( disp=REC2020_PRI, Ymid=15, Ymax=1000, redmod=redmod ) #* affine.TF( 0, 1000 )
theEOTF = PQ.EOTF(10000/1000)
#aces2signal = theOOTF * theEOTF^-1
#aces2XYZ = theOOTF * XYZfromRGB.TF(REC2020_PRI,1000)
#signal2XYZ = theEOTF * XYZfromRGB.TF(REC2020_PRI,1000)
}
else if( theName == '9.2' )
{
theOOTF = general.OOTF( disp=REC2020_PRI, Ymid=15, Ymax=2000, redmod=redmod ) #* affine.TF( 0, 2000 )
theEOTF = PQ.EOTF(10000/2000)
#aces2signal = theOOTF * theEOTF^-1
#aces2XYZ = theOOTF * XYZfromRGB.TF(REC2020_PRI,2000)
#signal2XYZ = theEOTF * XYZfromRGB.TF(REC2020_PRI,2000)
}
else if( theName == '9.3' )
{
theOOTF = general.OOTF( disp=REC2020_PRI, Ymid=15, Ymax=4000, redmod=redmod ) #* affine.TF( 0, 4000 )
theEOTF = PQ.EOTF(10000/4000)
#aces2signal = theOOTF * theEOTF^-1
#aces2XYZ = theOOTF * XYZfromRGB.TF(REC2020_PRI,4000)
#signal2XYZ = theEOTF * XYZfromRGB.TF(REC2020_PRI,4000)
}
else if( theName == '9.4' )
{
theOOTF = general.OOTF( disp=REC2020_PRI, Ymid=15, Ymax=1000, redmod=redmod )
hlg.OETF = HLG.OETF()
theEOTF = hlg.OETF^-1 * HLG.OOTF(Lw=1000/1000)
#aces2signal = theOOTF * theEOTF^-1
#aces2XYZ = theOOTF * XYZfromRGB.TF(REC2020_PRI,1000)
#signal2XYZ = theEOTF * XYZfromRGB.TF(REC2020_PRI,1000)
}
else
{
printf( "WARN. Table '%s' unknown.", theName )
next
}
# make a space called 'testACES'
# display primaries and whitepoint not necessary because they are in the metadata
spacename = 'testACES'
if( ! is.null(theOETF) && ! is.null(theEOTF) )
ok = installRGB( spacename, scene=AP0_PRI, OETF=theOETF, EOTF=theEOTF, overwrite=TRUE )
else if( ! is.null(theOOTF) && ! is.null(theEOTF) )
ok = installRGB( spacename, scene=AP0_PRI, OOTF=theOOTF, EOTF=theEOTF, overwrite=TRUE )
else
{
printf( "ERROR. Bad transfer functions." )
return(NULL)
}
if( ! ok )
{
printf( "ERROR. Cannot install RGB space '%s'.", spacename )
return(NULL)
}
if( is.null(theOOTF) ) theOOTF = getRGB( spacename )$OOTF
if( is.null(theOETF) ) theOETF = getRGB( spacename )$OETF
df = data.frame( row.names=theTable[ ,1] )
aces.ref = as.matrix( theTable[ ,2:4] )
signal.ref = as.matrix( theTable[ ,5:7] )
xyY.ref = as.matrix( theTable[ ,8:10] )
XYZ.ref = as.matrix( spacesXYZ::XYZfromxyY( xyY.ref ) )
# for aces.ref, override
#aces.ref[4,1] = 0.4048 # R of patch 'R'
#aces.ref[7,1] = 0.5530 # R of patch 'C'
# compare computed signal to reference signal, the OETF
# signal = transfer( aces2signal, aces.ref )
signal = SignalRGBfromLinearRGB( aces.ref, space=spacename )$RGB
df$delta.OETF = apply( abs(signal - signal.ref), 1, max )
ok.OETF = df$delta.OETF < tol.RGB # all absolute here
df$status.OETF = ifelse( ok.OETF, 'pass', 'FAILED' )
# compare computed EOTF to reference EOTF
# XYZ = transfer( signal2XYZ, signal.ref, domaincheck=TRUE ) #; print( spacesXYZ::xyYfromXYZ(XYZ) )
XYZ = XYZfromRGB( signal.ref, space=spacename, which='display' )$XYZ
delta.EOTF = abs(XYZ - XYZ.ref) # / XYZ.ref[ ,2] # 'relativize' delta.EOTF, the denominator is replicated
df$delta.EOTF = apply( delta.EOTF, 1, max )
ok.EOTF = df$delta.EOTF < tol.XYZ
df$status.EOTF = ifelse( ok.EOTF, 'pass', 'FAILED' )
# compare computed OOTF to reference OOTF
# XYZ = transfer( aces2XYZ, aces.ref, domaincheck=TRUE )
XYZ = XYZfromRGB( signal, space=spacename, which='display' )$XYZ
delta.OOTF = abs(XYZ - XYZ.ref) # / XYZ.ref[ ,2] # 'relativize' delta.OOTF, the denominator is replicated
df$delta.OOTF = apply( delta.OOTF, 1, max )
ok.OOTF = df$delta.OOTF < tol.XYZ
df$status.OOTF = ifelse( ok.OOTF, 'pass', 'FAILED' )
if( is.invertible(theOETF) )
{
# compare computed aces to reference aces, the OETFinv
# aces = transfer( aces2signal^-1, signal.ref ) #; print( aces )
aces = LinearRGBfromSignalRGB( signal.ref, space=spacename, which='scene' )$RGB
df$delta.OETFinv = apply( abs(aces - aces.ref), 1, max )
ok.OETFinv = df$delta.OETFinv < tol.RGBsce # all absolute here
df$status.OETFinv = ifelse( ok.OETFinv, 'pass', 'FAILED' )
}
else
ok.OETFinv = rep(TRUE,nrow(df))
if( is.invertible(theEOTF) )
{
# compare computed signal to reference signal, the EOTFinv
# signal = transfer( signal2XYZ^-1, XYZ.ref )
signal = RGBfromXYZ( XYZ.ref, space=spacename, which='display' )$RGB
df$delta.EOTFinv = apply( abs(signal - signal.ref), 1, max )
ok.EOTFinv = df$delta.EOTFinv < tol.RGB # all absolute here
df$status.EOTFinv = ifelse( ok.EOTFinv, 'pass', 'FAILED' )
}
else
ok.EOTFinv = rep(TRUE,nrow(df))
if( is.invertible(theOOTF) )
{
# compare computed aces to reference aces, the OOTFinv
# aces = transfer( aces2XYZ^-1, XYZ.ref ) #; print( aces )
# this takes 2 steps
signal = RGBfromXYZ( XYZ.ref, space=spacename, which='display' )$RGB
aces = LinearRGBfromSignalRGB( signal, space=spacename, which='scene' )$RGB
df$delta.OOTFinv = apply( abs(aces - aces.ref), 1, max )
ok.OOTFinv = df$delta.OOTFinv < tol.RGBsce # all absolute here
df$status.OOTFinv = ifelse( ok.OOTFinv, 'pass', 'FAILED' )
}
else
ok.OOTFinv = rep(TRUE,nrow(df))
# combine into final status
status.final = ok.OETF & ok.EOTF & ok.OOTF & ok.OETFinv & ok.EOTFinv & ok.OOTFinv
df$status.final = ifelse( status.final, 'pass', 'FAILED' )
invalid[theName] = sum( ! status.final )
out[[ theName ]] = df
}
# print( as.data.frame(invalid) )
return( out )
}
if( 1 )
{
# bump 2 tolerances from 5 to 6
res = testACES( tol.XYZ=6e-3, tol.RGBsce=6e-5, redmod="1.1+pinv" )
if( is.null(res) ) stop( "testACES() failed ! returned NULL.", call.=FALSE )
# res is a list of data.frame's
listbad = list()
for( theName in names(res) )
{
df = res[[ theName ]]
ok = all( df$status.final == 'pass' )
if( ! ok )
listbad[[ theName ]] = df
}
if( 0 < length(listbad) )
{
print( listbad )
stop( "testACES() failed !", call.=FALSE )
}
printf( "\nPassed all ACES tests !" )
}
Any scripts or data that you put into this service are public.
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.