Skip to content

Commit 47ba8be

Browse files
committed
Additional updates to handle namespaces properly in LUT3D, ASCCDL and Info
Update to handle Inf and NaN values in LUT1D lookups Turned off cachiing of IndexMaps values. Was very, very slow. Updates to handle OpenImageIO versions greater than 1.8, less than 2.0
1 parent 028b909 commit 47ba8be

File tree

6 files changed

+56
-28
lines changed

6 files changed

+56
-28
lines changed

python/aces/clf/ASCCDL.py

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -103,18 +103,18 @@ def write(self, tree):
103103

104104
def readChild(self, element):
105105
elementType = self.getElementType(element.tag)
106-
if elementType == 'SOPNode':
106+
if elementType.lower() == 'sopnode':
107107
for child in element:
108-
childType = child.tag
108+
childType = self.getElementType(child.tag)
109109
if childType == 'Slope':
110110
self._values['slope'] = map(float, child.text.split())
111111
elif childType == 'Offset':
112112
self._values['offset'] = map(float, child.text.split())
113113
elif childType == 'Power':
114114
self._values['power'] = map(float, child.text.split())
115-
elif elementType == 'SatNode':
115+
elif elementType.lower() == 'satnode':
116116
for child in element:
117-
childType = child.tag
117+
childType = self.getElementType(child.tag)
118118
if childType == 'Saturation':
119119
self._values['saturation'] = float(child.text)
120120
return None
@@ -202,7 +202,6 @@ def process(self, values, stride=0, verbose=False):
202202
outValue[i] = clamp( outValue[i] )
203203

204204
luma = 0.2126 * outValue[0] + 0.7152 * outValue[1] + 0.0722 * outValue[2]
205-
print( luma )
206205

207206
for i in range(3):
208207
outSat = luma + (1.0/saturation) * (outValue[i] - luma)

python/aces/clf/Array.py

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -488,14 +488,20 @@ def lookup1DLinear(self, position, channel):
488488
dimensions = self._dimensions
489489

490490
index = position*(dimensions[0]-1)
491-
indexLow = int(math.floor(index))
492-
indexHigh = int(math.ceil(index))
493-
interp = index - indexLow
494491

495-
value1 = self.lookup1D(indexLow, channel)
496-
value2 = self.lookup1D(indexHigh, channel)
492+
# NaNs, Infs
493+
if np.isnan(index) or np.isinf(index):
494+
result = index
495+
# Normal values
496+
else:
497+
indexLow = int(math.floor(index))
498+
indexHigh = int(math.ceil(index))
499+
interp = index - indexLow
500+
501+
value1 = self.lookup1D(indexLow, channel)
502+
value2 = self.lookup1D(indexHigh, channel)
497503

498-
result = (1-interp)*value1 + interp*value2
504+
result = (1-interp)*value1 + interp*value2
499505

500506
return result
501507
# lookup1DLinear

python/aces/clf/IndexMap.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@
6262
class IndexMap:
6363
"A Common LUT Format IndexMap element"
6464

65-
def __init__(self, dimension=[], values=[], elementType='IndexMap', useCachedProcess=True):
65+
def __init__(self, dimension=[], values=[], elementType='IndexMap', useCachedProcess=False):
6666
"%s - Initialize the standard class variables" % elementType
6767
self._dimension = dimension
6868
self._values = values

python/aces/clf/Info.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,10 +84,17 @@ def write(self, tree):
8484
return element
8585
# write
8686

87+
def getElementType(self, tag):
88+
# ..find('}') allows us to strip out namespaces
89+
elementType = tag[tag.find('}')+1:]
90+
elementType = elementType.replace('-', '')
91+
elementType = elementType.replace('_', '')
92+
return elementType
93+
8794
def read(self, element):
8895
# Read child elements
8996
for child in element:
90-
elementType = child.tag
97+
elementType = self.getElementType(child.tag)
9198

9299
if elementType == 'AppRelease':
93100
self._children.append( Comment(child.text, 'AppRelease') )

python/aces/clf/LUT3D.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ def readChild(self, element):
120120
child.setValuesAreIntegers(integers)
121121

122122
self._array = child
123-
elif element.tag == 'IndexMap':
123+
elif elementType == 'IndexMap':
124124
child = IndexMap()
125125
child.read(element)
126126
self._indexMaps.append( child )
@@ -156,12 +156,12 @@ def process(self, values, stride=0, verbose=False):
156156

157157
# Run each channel through the index map, or base normalization
158158
for i in range(min(3, len(value))):
159-
# Run through single Index Map then normalize
159+
# Run through per-channel Index Map then normalize
160160
if len(self._indexMaps) > 1:
161161
outValue[i] = self._indexMaps[i].process(outValue[i])
162162
outValue[i] /= float(dimensions[i]-1)
163163

164-
# Run through per-channel Index Map then normalize
164+
# Run through single Index Map then normalize
165165
elif len(self._indexMaps) > 0:
166166
outValue[i] = self._indexMaps[0].process(outValue[i])
167167
outValue[i] /= float(dimensions[i]-1)

python/aces/filterImageWithCLF.py

Lines changed: 28 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -84,8 +84,13 @@ def halfsToFloat(half1, half2):
8484
# 'floats' read from OpenImageIO.
8585
# Each 4 byte 'float' is the binary equivalent of two packed 2-byte half-floats.
8686
def oiioFloatPixelsToNPHalfArray(width, height, channels, oiioFloats):
87-
# Read float pixels into a numpy half-float pixel array
88-
npPixels = np.frombuffer(np.getbuffer(np.float32(oiioFloats)), dtype=np.float16)
87+
88+
if oiio.VERSION < 10800:
89+
# Read float pixels into a numpy half-float pixel array
90+
npPixels = np.frombuffer(np.getbuffer(np.float32(oiioFloats)), dtype=np.float16)
91+
else:
92+
# Convert uint16 values into a numpy half-float pixel array
93+
npPixels = np.frombuffer(np.getbuffer(np.uint16(oiioFloats)), dtype=np.float16)
8994

9095
return npPixels
9196
# oiioFloatPixelsToNPHalfArray
@@ -95,8 +100,12 @@ def oiioFloatPixelsToNPHalfArray(width, height, channels, oiioFloats):
95100
# is a numpy array of half-float pixels.
96101
# Each 4 byte 'float' is the binary equivalent of two packed 2-byte half-floats.
97102
def npHalfArrayToOIIOFloatPixels(width, height, channels, npPixels):
98-
# Read half-float pixels into a numpy float pixel array
99-
oiioFloatsArray = np.frombuffer(np.getbuffer(np.float16(npPixels)), dtype=np.float32)
103+
if oiio.VERSION < 10800:
104+
# Read half-float pixels into a numpy float pixel array
105+
oiioFloatsArray = np.frombuffer(np.getbuffer(np.float16(npPixels)), dtype=np.float32)
106+
else:
107+
# Read half-float pixels into a numpy float pixel array
108+
oiioFloatsArray = np.frombuffer(np.getbuffer(np.float16(npPixels)), dtype=np.uint16)
100109

101110
return oiioFloatsArray
102111
# npHalfArrayToOIIOFloatPixels
@@ -136,11 +145,14 @@ def readPixelArray(inputPath,
136145
width = inputImageSpec.width
137146
height = inputImageSpec.height
138147
channels = inputImageSpec.nchannels
148+
channelnames = inputImageSpec.channelnames
139149
metadata = inputImageSpec.extra_attribs
140150
metanames = [attr.name for attr in metadata]
141151

142152
bitShift = 0
143153

154+
print( "Loading image - spects : %d x %d - %d channels, %s bit depth, %s" % (width, height, channels, type, channelnames))
155+
144156
# Handle automatic bit-depth conversions
145157
if bitDepthOverride:
146158
if bitDepthOverride == "auto":
@@ -176,15 +188,15 @@ def readPixelArray(inputPath,
176188
for i in range(len(sourceData)):
177189
sourceData[i] = sourceData[i] >> bitShift
178190

179-
# OIIO doesn't return half-float values directly, so this will
180-
# convert from the packed representation to half-floats
191+
# OIIO versions < 1.8 didn't return half-float values directly
192+
# so this will convert from the packed representation to half-floats
181193
if type == oiio.HALF:
182194
print( "Unpacking half-float values" )
183195
sourceData = oiioFloatPixelsToNPHalfArray(width, height, channels, sourceData)
184196
else:
185-
(sourceData, bitDepth, width, height, channels, metadata) = (None, clf.bitDepths["UINT10"], 0, 0, 0, None)
197+
(sourceData, bitDepth, width, height, channels, metadata) = (None, clf.bitDepths["UINT10"], 0, 0, 0, None, None)
186198

187-
return (sourceData, bitDepth, width, height, channels, metadata)
199+
return (sourceData, bitDepth, width, height, channels, metadata, channelnames)
188200
# readPixelArray
189201

190202
#
@@ -197,6 +209,7 @@ def writePixelArray(outputPath,
197209
height,
198210
channels,
199211
metadata,
212+
channelnames,
200213
compression=None,
201214
compressionQuality=0):
202215
print( "Writing image - path : %s" % outputPath)
@@ -251,6 +264,7 @@ def writePixelArray(outputPath,
251264
outputSpec.width = width
252265
outputSpec.height = height
253266
outputSpec.nchannels = channels
267+
outputSpec.channelnames = channelnames
254268

255269
# Mapping between bit depth and 'oiio:BitsPerSample' metadata value
256270
bitDepthValue = {
@@ -389,7 +403,7 @@ def filterRow_stride(row,
389403

390404
# Process values
391405
#print( "Processing %04d, %04d : %s" % (i, j, ovalue))
392-
pvalue = processList.process(pvalue, stride=channels)
406+
pvalue = processList.process(pvalue, stride=channels, verbose=verbose)
393407

394408
# Reset values if output image and CLF output bit depths don't match
395409
if OutRange:
@@ -477,7 +491,7 @@ def filterImageWithCLF(inputPath,
477491
#
478492
t0 = timeit.default_timer()
479493

480-
pixels, inBitDepth, width, height, channels, metadata = readPixelArray(inputPath)
494+
pixels, inBitDepth, width, height, channels, metadata, channelnames = readPixelArray(inputPath)
481495
if pixels == None:
482496
print( "\nImage %s could not be opened. Filtering aborted.\n" % inputPath )
483497
return
@@ -571,7 +585,9 @@ def filterImageWithCLF(inputPath,
571585
else:
572586
print( "Filtering image - single threaded" )
573587

574-
for j in range(height):
588+
#for j in range(height):
589+
j = 5
590+
if True:
575591
# Using filterRow_stride instead of filterRow_pixel
576592
# Processing a full row is ~10% faster than processing individual pixels
577593
filterRow_stride(j,
@@ -590,7 +606,7 @@ def filterImageWithCLF(inputPath,
590606
t0 = timeit.default_timer()
591607

592608
writePixelArray(outputPath, processedPixels, outBitDepth, width, height, channels, metadata,
593-
compression, compressionQuality)
609+
channelnames, compression, compressionQuality)
594610

595611
t1 = timeit.default_timer()
596612
elapsed = t1 - t0

0 commit comments

Comments
 (0)