Esempio n. 1
0
def ImageBufWeight(weight, inputBuffer, gamma=0.75, clip=0.05, lut=None):
    '''
    Apply a bell / triangular weight function to an Image Buffer
    '''
    (channelType, width, height, channels, orientation, metadata,
     inputSpec) = ImageAttributes(inputBuffer)

    temp = ImageBufMakeConstant(width, height, channels, oiio.HALF)
    grey05 = ImageBufMakeConstant(width, height, channels, oiio.HALF,
                                  tuple([0.5] * channels))

    if lut:
        ImageBufAlgo.add(temp, temp, inputBuffer)
        if 1 in lut:
            ImageBufAlgo.clamp(temp, temp, tuple([0.5] * channels),
                               tuple([1.0] * channels))

        if 2 in lut:
            ImageBufAlgo.clamp(temp, temp, tuple([0.0] * channels),
                               tuple([0.5] * channels))

        #print( "\tLUT application : %s" % result )
        ImageBufAlgo.absdiff(temp, grey05, temp)
    else:
        ImageBufAlgo.absdiff(temp, grey05, inputBuffer)

    ImageBufAlgo.sub(temp, grey05, temp)
    ImageBufAlgo.div(temp, temp, 0.5)

    ImageBufAlgo.sub(temp, temp, clip)
    ImageBufAlgo.mul(temp, temp, 1.0 / (1.0 - clip))

    ImageBufAlgo.clamp(temp, temp, tuple([0.0] * channels),
                       tuple([1.0] * channels))
    ImageBufAlgo.pow(weight, temp, gamma)
Esempio n. 2
0
File: mkhdr.py Progetto: hpd/general
def ImageBufWeight(weight, inputBuffer, gamma=0.75, clip=0.05, lut=None):
    '''
    Apply a bell / triangular weight function to an Image Buffer
    '''
    (channelType, width, height, channels, orientation, metadata, inputSpec) = ImageAttributes(inputBuffer)
    
    temp     = ImageBufMakeConstant(width, height, channels, oiio.HALF )
    grey05   = ImageBufMakeConstant(width, height, channels, oiio.HALF, tuple([0.5]*channels) )
    
    if lut:
        ImageBufAlgo.add(temp, temp, inputBuffer)
        if 1 in lut:
            ImageBufAlgo.clamp(temp, temp, tuple([0.5]*channels), tuple([1.0]*channels))

        if 2 in lut:
            ImageBufAlgo.clamp(temp, temp, tuple([0.0]*channels), tuple([0.5]*channels))

        #print( "\tLUT application : %s" % result )
        ImageBufAlgo.absdiff(temp, grey05, temp)
    else:
        ImageBufAlgo.absdiff(temp, grey05, inputBuffer)
    
    ImageBufAlgo.sub(temp, grey05, temp)
    ImageBufAlgo.div(temp, temp, 0.5)

    ImageBufAlgo.sub(temp, temp, clip)
    ImageBufAlgo.mul(temp, temp, 1.0/(1.0-clip))

    ImageBufAlgo.clamp(temp, temp, tuple([0.0]*channels), tuple([1.0]*channels))
    ImageBufAlgo.pow(weight, temp, gamma)
Esempio n. 3
0
        make_constimage(64, 64, 3, oiio.HALF, (0.1, 0.1, 0.1), 20, 20),
    )
    write(b, "add.exr")

    # sub
    b = ImageBuf()
    ImageBufAlgo.sub(
        b,
        make_constimage(64, 64, 3, oiio.HALF, (0.1, 0.2, 0.3)),
        make_constimage(64, 64, 3, oiio.HALF, (0.1, 0.1, 0.1), 20, 20),
    )
    write(b, "sub.exr")

    # mul
    b = ImageBuf()
    ImageBufAlgo.mul(b, gray128, 1.5)
    write(b, "cmul1.exr")
    b = ImageBuf()
    ImageBufAlgo.mul(b, gray128, (1.5, 1, 0.5))
    write(b, "cmul2.exr")
    # FIXME -- image multiplication; it's not in testsuite/oiiotool either
    # b = ImageBuf()
    # ImageBufAlgo.mul (b, make_constimage(64,64,3,oiio.HALF,(.1,.2,.3)),
    #                        make_constimage(64,64,3,oiio.HALF,(.1,.1,.1),20,20))
    # write (b, "mul.exr")

    # pow
    b = ImageBuf()
    ImageBufAlgo.pow(b, gray128, 2)
    write(b, "cpow1.exr")
    b = ImageBuf()
Esempio n. 4
0
    # Test --absdiff and --abs
    # First, make a test image that's 0.5 on the left, -0.5 on the right
    a = ImageBuf(ImageSpec(128, 128, 3, oiio.HALF))
    ImageBufAlgo.fill(a, (0.5, 0.5, 0.5))
    ImageBufAlgo.fill(a, (-0.25, -0.25, -0.25), oiio.ROI(0, 64, 0, 128))
    b = ImageBuf()
    ImageBufAlgo.abs(b, a)
    write(b, "abs.exr", oiio.HALF)
    b = ImageBuf()
    ImageBufAlgo.absdiff(b, a, (0.2, 0.2, 0.2))
    write(b, "absdiff.exr", oiio.HALF)
    a = ImageBuf()

    # mul
    b = ImageBuf()
    ImageBufAlgo.mul(b, gray128, 1.5)
    write(b, "cmul1.exr")
    b = ImageBuf()
    ImageBufAlgo.mul(b, gray128, (1.5, 1, 0.5))
    write(b, "cmul2.exr")
    # FIXME -- image multiplication; it's not in testsuite/oiiotool either
    # b = ImageBuf()
    # ImageBufAlgo.mul (b, make_constimage(64,64,3,oiio.HALF,(.1,.2,.3)),
    #                        make_constimage(64,64,3,oiio.HALF,(.1,.1,.1),20,20))
    # write (b, "mul.exr")

    # div
    b = ImageBuf()
    ImageBufAlgo.div(b, gray64,
                     make_constimage(64, 64, 3, oiio.HALF, (2.0, 1, 0.5)))
    write(b, "div.exr", oiio.HALF)
Esempio n. 5
0
    # Test --absdiff and --abs
    # First, make a test image that's 0.5 on the left, -0.5 on the right
    a = ImageBuf (ImageSpec(128,128,3,oiio.HALF))
    ImageBufAlgo.fill (a, (0.5,0.5,0.5))
    ImageBufAlgo.fill (a, (-0.25,-0.25,-0.25), oiio.ROI(0,64,0,128))
    b = ImageBuf()
    ImageBufAlgo.abs (b, a)
    write (b, "abs.exr", oiio.HALF)
    b = ImageBuf()
    ImageBufAlgo.absdiff (b, a, (0.2,0.2,0.2))
    write (b, "absdiff.exr", oiio.HALF)
    a = ImageBuf()

    # mul
    b = ImageBuf()
    ImageBufAlgo.mul (b, gray128, 1.5)
    write (b, "cmul1.exr")
    b = ImageBuf()
    ImageBufAlgo.mul (b, gray128, (1.5,1,0.5))
    write (b, "cmul2.exr")
    b = ImageBuf()
    ImageBufAlgo.mul (b, make_constimage(64,64,3,oiio.HALF,(.5,.5,.5)),
                         make_constimage(64,64,3,oiio.HALF,(1.5,1,0.5)))
    write (b, "mul.exr", oiio.HALF)

    # mad
    b = ImageBuf()
    ImageBufAlgo.mad (b, make_constimage(64,64,3,oiio.HALF,(.5,.5,.5)),
                         make_constimage(64,64,3,oiio.HALF,(1.5,1,0.5)),
                         make_constimage(64,64,3,oiio.HALF,(0.1,0.1,0.1)))
    write (b, "mad.exr", oiio.HALF)
Esempio n. 6
0
        make_constimage(64, 64, 3, oiio.HALF, (.1, .1, .1), 20, 20))
    write(b, "sub.exr")

    # Test --absdiff and --abs
    # First, make a test image that's 0.5 on the left, -0.5 on the right
    a = ImageBuf(ImageSpec(128, 128, 3, oiio.HALF))
    ImageBufAlgo.fill(a, (0.5, 0.5, 0.5))
    ImageBufAlgo.fill(a, (-0.25, -0.25, -0.25), oiio.ROI(0, 64, 0, 128))
    b = ImageBufAlgo.abs(a)
    write(b, "abs.exr", oiio.HALF)
    b = ImageBufAlgo.absdiff(a, (0.2, 0.2, 0.2))
    write(b, "absdiff.exr", oiio.HALF)
    a = ImageBuf()

    # mul
    b = ImageBufAlgo.mul(gray128, 1.5)
    write(b, "cmul1.exr")
    b = ImageBufAlgo.mul(gray128, (1.5, 1, 0.5))
    write(b, "cmul2.exr")
    b = ImageBufAlgo.mul(make_constimage(64, 64, 3, oiio.HALF, (.5, .5, .5)),
                         make_constimage(64, 64, 3, oiio.HALF, (1.5, 1, 0.5)))
    write(b, "mul.exr", oiio.HALF)

    # mad
    b = ImageBufAlgo.mad(
        make_constimage(64, 64, 3, oiio.HALF, (.5, .5, .5)),
        make_constimage(64, 64, 3, oiio.HALF, (1.5, 1, 0.5)),
        make_constimage(64, 64, 3, oiio.HALF, (0.1, 0.1, 0.1)))
    write(b, "mad.exr", oiio.HALF)
    b = ImageBufAlgo.mad(make_constimage(64, 64, 3, oiio.HALF, (.5, .5, .5)),
                         (1.5, 1, 0.5), (0.1, 0.1, 0.1))
Esempio n. 7
0
def mkhdr(outputPath,
          inputPaths,
          responseLUTPaths,
          baseExposureIndex,
          writeIntermediate=False,
          outputGamut=1):
    '''
    Create an HDR image from a series of individual exposures
    If the images are non-linear, a series of response LUTs can be used to
    linearize the data
    '''

    global temp_dirs

    # Create buffers for inputs
    inputBuffers = []
    inputAttributes = []

    # Read images
    for inputPath in inputPaths:
        print("Reading input image : %s" % inputPath)
        # Read
        inputBufferRaw = loadImageBuffer(inputPath, outputGamut=outputGamut)

        # Reset the orientation
        ImageBufReorient(inputBufferRaw, inputBufferRaw.orientation)

        # Get attributes
        (channelType, width, height, channels, orientation, metadata,
         inputSpec) = ImageAttributes(inputBufferRaw)

        # Cast to half by adding with a const half buffer.
        inputBufferHalf = ImageBufMakeConstant(width, height, channels,
                                               oiio.HALF)
        ImageBufAlgo.add(inputBufferHalf, inputBufferHalf, inputBufferRaw)

        # Get exposure-specific information
        exposure = getExposureInformation(metadata)

        print("\tChannel Type : %s" % (channelType))
        print("\tWidth        : %s" % (width))
        print("\tHeight       : %s" % (height))
        print("\tChannels     : %s" % (channels))
        print("\tOrientation  : %s" % (orientation))
        print("\tMetadata #   : %s" % (len(metadata)))
        print("\tExposure     : %s" % (exposure))

        # Store pixels and image attributes
        inputBuffers.append(inputBufferHalf)
        inputAttributes.append((channelType, width, height, channels,
                                orientation, metadata, exposure, inputSpec))

    # Get the base exposure information
    # All other images will be scaled to match this exposure
    if baseExposureIndex >= 0:
        baseExposureIndex = max(0, min(len(inputPaths) - 1, baseExposureIndex))
    else:
        multithreaded = True
        if multithreaded:
            threads = cpu_count()
            baseExposureIndex = findBaseExposureIndexMultithreaded(
                inputPaths, width, height, channels, threads)
        else:
            baseExposureIndex = findBaseExposureIndexSerial(
                inputBuffers, width, height, channels)

    baseExposureInfo = inputAttributes[baseExposureIndex][6]
    baseInputspec = inputAttributes[baseExposureIndex][7]

    print("")
    print("Base exposure index : %d" % baseExposureIndex)
    print("Base exposure info  : %s" % baseExposureInfo)

    # Find the lowest and highest exposures
    exposureAdjustments = [
        getExposureAdjustment(x[6], baseExposureInfo) for x in inputAttributes
    ]

    minExposureOffsetIndex = exposureAdjustments.index(
        min(exposureAdjustments))
    maxExposureOffsetIndex = exposureAdjustments.index(
        max(exposureAdjustments))

    print("Max exposure index  : %d" % minExposureOffsetIndex)
    print("Min exposure index  : %d" % maxExposureOffsetIndex)

    print("\nBegin processing\n")

    # Two buffers needed for algorithm
    imageSum = ImageBufMakeConstant(width,
                                    height,
                                    channels,
                                    oiio.HALF,
                                    inputSpec=baseInputspec)
    weightSum = ImageBufMakeConstant(width, height, channels, oiio.HALF)

    # Re-used intermediate buffers
    color = ImageBufMakeConstant(width, height, channels, oiio.HALF)
    weight = ImageBufMakeConstant(width, height, channels, oiio.HALF)
    weightedColor = ImageBufMakeConstant(width, height, channels, oiio.HALF)

    # Process images
    for inputIndex in range(len(inputPaths)):
        inputPathComponents = (os.path.splitext(inputPaths[inputIndex])[0],
                               ".exr")
        intermediate = 0

        ImageBufAlgo.zero(color)
        ImageBufAlgo.zero(weight)
        ImageBufAlgo.zero(weightedColor)

        print("Processing input image : %s" % inputPaths[inputIndex])
        inputBuffer = inputBuffers[inputIndex]

        # Copy the input buffer data
        ImageBufAlgo.add(color, color, inputBuffer)

        if writeIntermediate:
            intermediatePath = "%s_int%d.float_buffer%s" % (
                inputPathComponents[0], intermediate, inputPathComponents[1])
            intermediate += 1
            ImageBufWrite(color, intermediatePath)

        # Linearize using LUTs
        if responseLUTPaths:
            for responseLUTPath in responseLUTPaths:
                print("\tApplying LUT %s" % responseLUTPath)
                ImageBufAlgo.ociofiletransform(
                    color, color, os.path.abspath(responseLUTPath))

                if writeIntermediate:
                    intermediatePath = "%s_int%d.linearized%s" % (
                        inputPathComponents[0], intermediate,
                        inputPathComponents[1])
                    intermediate += 1
                    ImageBufWrite(color, intermediatePath)

        # Get exposure offset
        inputExposureInfo = inputAttributes[inputIndex][6]
        exposureAdjustment = getExposureAdjustment(inputExposureInfo,
                                                   baseExposureInfo)
        exposureScale = pow(2, exposureAdjustment)

        print("\tScaling by %s stops (%s mul)" %
              (exposureAdjustment, exposureScale))

        # Re-expose input
        ImageBufAlgo.mul(color, color, exposureScale)

        if writeIntermediate:
            intermediatePath = "%s_int%d.exposure_adjust%s" % (
                inputPathComponents[0], intermediate, inputPathComponents[1])
            intermediate += 1
            ImageBufWrite(color, intermediatePath)

        print("\tComputing image weight")

        # Weight
        lut = []
        if inputIndex == minExposureOffsetIndex:
            lut.append(1)
        if inputIndex == maxExposureOffsetIndex:
            lut.append(2)
        if lut:
            print("\tUsing LUT %s in weighting calculation" % lut)
        weightIntermediate = intermediate if writeIntermediate else 0
        ImageBufWeight(weight, inputBuffer, lut=lut)

        if writeIntermediate:
            intermediatePath = "%s_int%d.weight%s" % (
                inputPathComponents[0], intermediate, inputPathComponents[1])
            intermediate += 1
            ImageBufWrite(weight, intermediatePath)

        print("\tMultiply by weight")

        # Multiply color by weight
        ImageBufAlgo.mul(weightedColor, weight, color)

        if writeIntermediate:
            intermediatePath = "%s_int%d.color_x_weight%s" % (
                inputPathComponents[0], intermediate, inputPathComponents[1])
            intermediate += 1
            ImageBufWrite(weightedColor, intermediatePath)

        print("\tAdd values into sum")

        # Sum weighted color and weight
        ImageBufAlgo.add(imageSum, imageSum, weightedColor)
        ImageBufAlgo.add(weightSum, weightSum, weight)

        if writeIntermediate:
            intermediatePath = "%s_int%d.color_x_weight_sum%s" % (
                inputPathComponents[0], intermediate, inputPathComponents[1])
            intermediate += 1
            ImageBufWrite(imageSum, intermediatePath)

            intermediatePath = "%s_int%d.weight_sum%s" % (
                inputPathComponents[0], intermediate, inputPathComponents[1])
            intermediate += 1
            ImageBufWrite(weightSum, intermediatePath)

    # Divid out weights
    print("Dividing out weights")
    ImageBufAlgo.div(imageSum, imageSum, weightSum)

    # Write to disk
    print("Writing result : %s" % outputPath)
    ImageBufWrite(imageSum, outputPath)

    # Clean up temp folders
    for temp_dir in temp_dirs:
        #print( "Removing : %s" % temp_dir )
        shutil.rmtree(temp_dir)
Esempio n. 8
0
def mkhdr(outputPath, 
    inputPaths, 
    responseLUTPaths, 
    baseExposureIndex, 
    writeIntermediate = False, 
    outputGamut = 1,
    compression = None,
    compressionQuality = 0,
    rawSaturationPoint = -1.0,
    alignImages = False,
    dcrawVariant = None):
    '''
    Create an HDR image from a series of individual exposures
    If the images are non-linear, a series of response LUTs can be used to
    linearize the data
    '''

    global temp_dirs

    # Set up capture of 
    old_stdout, old_stderr = sys.stdout, sys.stderr
    redirected_stdout = sys.stdout = Logger()
    redirected_stderr = sys.stderr = Logger()

    # Create buffers for inputs
    inputBuffers = []
    inputAttributes = []

    # Read images
    for inputPath in inputPaths:
        print( "Reading input image : %s" % inputPath )
        # Read
        inputBufferRaw = loadImageBuffer( inputPath, outputGamut=outputGamut, 
            rawSaturationPoint=rawSaturationPoint,
            dcrawVariant=dcrawVariant )

        # Reset the orientation
        print( "\tRaw Orientation : %d" % inputBufferRaw.orientation)
        ImageBufReorient(inputBufferRaw, inputBufferRaw.orientation)

        # Get attributes
        (channelType, width, height, channels, orientation, metadata, inputSpec) = ImageAttributes(inputBufferRaw)

        # Cast to half by adding with a const half buffer.
        inputBufferHalf = ImageBufMakeConstant(width, height, channels, oiio.HALF)
        ImageBufAlgo.add(inputBufferHalf, inputBufferHalf, inputBufferRaw)

        # Get exposure-specific information
        exposure = getExposureInformation(metadata)

        print( "\tChannel Type : %s" % (channelType) )
        print( "\tWidth        : %s" % (width) )
        print( "\tHeight       : %s" % (height) )
        print( "\tChannels     : %s" % (channels) )
        print( "\tOrientation  : %s" % (orientation) )
        print( "\tExposure     : %s" % (exposure) )
        print( "\tMetadata #   : %s" % (len(metadata)) )

        # Store pixels and image attributes
        inputBuffers.append( inputBufferHalf )
        inputAttributes.append( (channelType, width, height, channels, orientation, metadata, exposure, inputSpec) )

    # Get the base exposure information
    # All other images will be scaled to match this exposure
    if baseExposureIndex >= 0:
        baseExposureIndex = max(0, min(len(inputPaths)-1, baseExposureIndex))
    else:
        multithreaded = True
        if multithreaded:
            threads = cpu_count()
            baseExposureIndex = findBaseExposureIndexMultithreaded(inputPaths, width, height, channels, threads)
        else:
            baseExposureIndex = findBaseExposureIndexSerial(inputBuffers, width, height, channels)

    baseExposureMetadata = inputAttributes[baseExposureIndex][5]
    baseExposureInfo = inputAttributes[baseExposureIndex][6]
    baseInputspec = inputAttributes[baseExposureIndex][7]

    print( "" )
    print( "Base exposure index : %d" % baseExposureIndex )
    print( "Base exposure info  : %s" % baseExposureInfo )

    # Find the lowest and highest exposures
    exposureAdjustments = [getExposureAdjustment(x[6], baseExposureInfo) for x in inputAttributes]

    minExposureOffsetIndex = exposureAdjustments.index(min(exposureAdjustments))
    maxExposureOffsetIndex = exposureAdjustments.index(max(exposureAdjustments))

    print( "Max exposure index  : %d" % minExposureOffsetIndex )
    print( "Min exposure index  : %d" % maxExposureOffsetIndex )

    print( "\nBegin processing\n" )

    # Two buffers needed for algorithm
    imageSum  = ImageBufMakeConstant(width, height, channels, oiio.HALF, 
        inputSpec=baseInputspec)
    weightSum = ImageBufMakeConstant(width, height, channels, oiio.HALF)

    # Re-used intermediate buffers
    color     = ImageBufMakeConstant(width, height, channels, oiio.HALF)
    weight    = ImageBufMakeConstant(width, height, channels, oiio.HALF)
    weightedColor = ImageBufMakeConstant(width, height, channels, oiio.HALF)

    # Process images
    for inputIndex in range(len(inputPaths)):
        inputPathComponents = (os.path.splitext( inputPaths[inputIndex] )[0], ".exr")
        intermediate = 0

        ImageBufAlgo.zero( color )
        ImageBufAlgo.zero( weight )
        ImageBufAlgo.zero( weightedColor )

        print( "Processing input image : %s" % inputPaths[inputIndex] )
        inputBuffer = inputBuffers[inputIndex]

        # Copy the input buffer data
        ImageBufAlgo.add(color, color, inputBuffer)

        if writeIntermediate:
            intermediatePath = "%s_int%d.float_buffer%s" % (inputPathComponents[0], intermediate, inputPathComponents[1])
            intermediate += 1
            ImageBufWrite(color, intermediatePath)

        # Find the image alignment matrix to align this exposure with the base exposure
        if alignImages:
            try:
                if inputIndex != baseExposureIndex:
                    if cv2:
                        print( "\tAligning image %d to base exposure %d " % (inputIndex, baseExposureIndex) )
                        warpMatrix = find2dAlignmentMatrix(inputBuffer, inputBuffers[baseExposureIndex])

                        # reformat for OIIO's warp
                        w = map(float, list(warpMatrix.reshape(1,-1)[0]))
                        warpTuple = (w[0], w[1], 0.0, w[3], w[4], 0.0, w[2], w[5], 1.0)
                        print( warpTuple )

                        warped = ImageBuf()
                        result = ImageBufAlgo.warp(warped, color, warpTuple)
                        if result:
                            print( "\tImage alignment warp succeeded." )
                            if writeIntermediate:
                                intermediatePath = "%s_int%d.warped%s" % (inputPathComponents[0], intermediate, inputPathComponents[1])
                                intermediate += 1
                                ImageBufWrite(warped, intermediatePath)

                            color = warped
                        else:
                            print( "\tImage alignment warp failed." )
                            if writeIntermediate:
                                intermediate += 1
                    else:
                        print( "\tSkipping image alignment. OpenCV not defined" )
                        if writeIntermediate:
                            intermediate += 1
                else:
                    print( "\tSkipping alignment of base exposure to itself")
                    if writeIntermediate:
                        intermediate += 1

            except:
                print( "Exception in image alignment" )
                print( '-'*60 )
                traceback.print_exc()
                print( '-'*60 )

        # Weight
        print( "\tComputing image weight" )

        lut = []
        if inputIndex == minExposureOffsetIndex:
            lut.append(1)
        if inputIndex == maxExposureOffsetIndex:
            lut.append(2)
        if lut:
            print( "\tUsing LUT %s in weighting calculation" % lut )
        ImageBufWeight(weight, color, lut=lut)

        if writeIntermediate:
            intermediatePath = "%s_int%d.weight%s" % (inputPathComponents[0], intermediate, inputPathComponents[1])
            intermediate += 1
            ImageBufWrite(weight, intermediatePath)

        # Linearize using LUTs
        if responseLUTPaths:
            for responseLUTPath in responseLUTPaths:
                print( "\tApplying LUT %s" % responseLUTPath )
                ImageBufAlgo.ociofiletransform(color, color, os.path.abspath(responseLUTPath) )

                if writeIntermediate:
                    intermediatePath = "%s_int%d.linearized%s" % (inputPathComponents[0], intermediate, inputPathComponents[1])
                    intermediate += 1
                    ImageBufWrite(color, intermediatePath)

        # Get exposure offset
        inputExposureInfo = inputAttributes[inputIndex][6]
        exposureAdjustment = getExposureAdjustment(inputExposureInfo, baseExposureInfo)
        exposureScale = pow(2, exposureAdjustment)

        # Re-expose input
        print( "\tScaling by %s stops (%s mul)" % (exposureAdjustment, exposureScale) )
        ImageBufAlgo.mul(color, color, exposureScale)

        if writeIntermediate:
            intermediatePath = "%s_int%d.exposure_adjust%s" % (inputPathComponents[0], intermediate, inputPathComponents[1])
            intermediate += 1
            ImageBufWrite(color, intermediatePath)

        # Multiply color by weight
        print( "\tMultiply by weight" )

        ImageBufAlgo.mul(weightedColor, weight, color)

        if writeIntermediate:
            intermediatePath = "%s_int%d.color_x_weight%s" % (inputPathComponents[0], intermediate, inputPathComponents[1])
            intermediate += 1
            ImageBufWrite(weightedColor, intermediatePath)

        print( "\tAdd values into sum" )

        # Sum weighted color and weight
        ImageBufAlgo.add(imageSum,  imageSum,  weightedColor)
        ImageBufAlgo.add(weightSum, weightSum, weight)

        if writeIntermediate:
            intermediatePath = "%s_int%d.color_x_weight_sum%s" % (inputPathComponents[0], intermediate, inputPathComponents[1])
            intermediate += 1
            ImageBufWrite(imageSum, intermediatePath)

            intermediatePath = "%s_int%d.weight_sum%s" % (inputPathComponents[0], intermediate, inputPathComponents[1])
            intermediate += 1
            ImageBufWrite(weightSum, intermediatePath)

    # Divid out weights
    print( "Dividing out weights" )
    ImageBufAlgo.div(imageSum, imageSum, weightSum)

    # Write to disk
    print( "Writing result : %s" % outputPath )

    # Restore regular streams
    sys.stdout, sys.stderr = old_stdout, old_stderr

    additionalAttributes = {}
    additionalAttributes['inputPaths'] = " ".join(inputPaths)
    additionalAttributes['stdout'] = "".join(redirected_stdout.log)
    additionalAttributes['stderr'] = "".join(redirected_stderr.log)

    ImageBufWrite(imageSum, outputPath, 
        compression=compression,
        compressionQuality=compressionQuality,
        metadata=baseExposureMetadata,
        additionalAttributes=additionalAttributes)

    # Clean up temp folders
    for temp_dir in temp_dirs:
        #print( "Removing : %s" % temp_dir )
        shutil.rmtree(temp_dir)

    for temp_dir in temp_dirs:
        temp_dirs.remove(temp_dir)
    def compare(self, diff_image_location=None, blur=10, raise_exception=True):
        """Compare the two given images

        Args:
            diff_image_location (str): file path for difference image.
                Written only if there are failures
            blur (float): image blur to apply before comparing
        """

        if not diff_image_location:
            diff_image_location = os.path.dirname(self._image_a_location)

        self.blur_images(blur)
        ImageBufAlgo.compare(
            self.image_a_buffer,
            self.image_b_buffer,
            self.fail_threshold,
            self.warn_threshold,
            self._compare_results,
        )
        diff_buffer = self.create_diff_buffer()

        if self.debug:
            self.image_a_buffer.write(
                '{}/{}_debug{}'.format(
                    diff_image_location,
                    os.path.basename(self._image_a_location),
                    self._file_ext,
                )
            )
            self.image_b_buffer.write(
                '{}/{}_debug{}'.format(
                    diff_image_location,
                    os.path.basename(self._image_b_location),
                    self._file_ext,
                )
            )

        if self._compare_results.nfail > 0:
            ImageBufAlgo.color_map(diff_buffer, diff_buffer, -1, 'inferno')
            remap_buffer = ImageBuf()
            multiplier = 5
            ImageBufAlgo.mul(
                remap_buffer,
                diff_buffer,
                (multiplier, multiplier, multiplier, 1.0),
            )
            ImageBufAlgo.add(remap_buffer, self.image_a_buffer, remap_buffer)
            msg = report_msg.format(
                failures=self._compare_results.nfail,
                warn=self._compare_results.nwarn,
                meanerror=self._compare_results.meanerror,
                rmserror=self._compare_results.rms_error,
                psnr=self._compare_results.PSNR
            )

            remap_buffer.write(
                '{}/{}-{}_diff{}'.format(
                    diff_image_location,
                    os.path.basename(self._image_a_location),
                    os.path.basename(self._image_b_location),
                    self._file_ext,
                )
            )
            self.image_a_buffer.write(
                '{}/{}_debug{}'.format(
                    diff_image_location,
                    '1_a',
                    self._file_ext,
                )
            )
            self.image_b_buffer.write(
                '{}/{}_debug{}'.format(
                    diff_image_location,
                    '1_b',
                    self._file_ext,
                )
            )
            if raise_exception:
                raise ImageDifferenceError(msg)
            else:
                print(msg)