Exemplo n.º 1
0
    def testHashPassThrough(self):

        constant1 = GafferImage.Constant()
        constant2 = GafferImage.Constant()

        ##########################################
        # Test to see if the input is always passed
        # through if only the first input is connected.
        ##########################################

        merge = GafferImage.DeepMerge()

        merge["in"][0].setInput(constant1["out"])

        for plug in [
                "format", "dataWindow", "metadata", "channelNames",
                "sampleOffsets", "deep"
        ]:
            self.assertEqual(constant1["out"][plug].hash(),
                             merge["out"][plug].hash())

        ##########################################
        # Test that if we add a second input and disable
        # the node the hash still gets passed through.
        ##########################################

        merge["in"][1].setInput(constant2["out"])
        merge["enabled"].setValue(False)

        for plug in [
                "format", "dataWindow", "metadata", "channelNames",
                "sampleOffsets", "deep"
        ]:
            self.assertEqual(constant1["out"][plug].hash(),
                             merge["out"][plug].hash())
Exemplo n.º 2
0
	def testOccludeAll( self ) :
		representativeImage = GafferImage.ImageReader()
		representativeImage["fileName"].setValue( self.representativeImagePath )

		constantNodes = self.__getConstant( 0.1, 0.2, 0.3, 1, -10, -10, imath.V2i( 150, 100 ) )

		empty = GafferImage.Empty()
		empty["format"].setValue( GafferImage.Format( imath.Box2i( imath.V2i( 0 ), imath.V2i( 150, 100 ) ), 1 ) )

		deepConstant = GafferImage.DeepMerge()
		deepConstant["in"][0].setInput( constantNodes[1]["out"] )
		deepConstant["in"][1].setInput( empty["out"] )

		deepMerge = GafferImage.DeepMerge()
		deepMerge["in"][0].setInput( representativeImage["out"] )
		deepMerge["in"][1].setInput( deepConstant["out"] )

		deepState = GafferImage.DeepState()
		deepState["in"].setInput( deepMerge["out"] )
		deepState["pruneOccluded"].setValue( True )

		self.assertEqual( GafferImage.ImageAlgo.tiles( constantNodes[1]["out"] ), GafferImage.ImageAlgo.tiles( constantNodes[1]["out"] ) )
Exemplo n.º 3
0
    def testImageDeepException(self):

        constant1 = GafferImage.Constant()
        constant1["color"].setValue(imath.Color4f(1))

        constant2 = GafferImage.Constant()
        constant2["color"].setValue(imath.Color4f(1))

        merge = GafferImage.DeepMerge()
        merge["in"][0].setInput(constant1["out"])
        merge["in"][1].setInput(constant2["out"])

        with self.assertRaises(RuntimeError):
            GafferImage.ImageAlgo.image(merge["out"])
Exemplo n.º 4
0
    def testOutputDeep(self):

        # Test default deep state when no inputs connected
        merge1 = GafferImage.DeepMerge()
        self.assertEqual(merge1["out"]["deep"].getValue(),
                         merge1["out"]["deep"].defaultValue())

        # Test that deep state passes through Flat value when one input connected
        constant1 = GafferImage.Constant()
        merge1["in"][0].setInput(constant1["out"])
        self.assertEqual(merge1["out"]["deep"].getValue(),
                         constant1["out"]["deep"].getValue())

        # Test that deep state is Deep when two inputs connected
        constant2 = GafferImage.Constant()
        merge1["in"][1].setInput(constant2["out"])
        self.assertEqual(merge1["out"]["deep"].getValue(),
                         GafferImage.ImagePlug.Deep.Deep)

        # Test that deep state passes through Deep value when one input connected
        merge2 = GafferImage.DeepMerge()
        merge2["in"][0].setInput(merge1["out"])
        self.assertEqual(merge2["out"]["deep"].getValue(),
                         merge1["out"]["deep"].getValue())
Exemplo n.º 5
0
    def testDataWindow(self):

        sourceFormat = GafferImage.Format(
            imath.Box2i(imath.V2i(0), imath.V2i(512)), 1)

        constant1 = GafferImage.Constant()
        constant1["format"].setValue(sourceFormat)

        constant2 = GafferImage.Constant()
        constant2["format"].setValue(sourceFormat)

        crop1 = GafferImage.Crop()
        crop1["in"].setInput(constant1["out"])
        crop1["affectDisplayWindow"].setValue(False)

        crop2 = GafferImage.Crop()
        crop2["in"].setInput(constant2["out"])
        crop2["affectDisplayWindow"].setValue(False)

        merge = GafferImage.DeepMerge()
        merge["in"][0].setInput(crop1["out"])
        merge["in"][1].setInput(crop2["out"])

        for i in range(100):
            crop1Area = imath.Box2i()
            crop1Area.extendBy(
                imath.V2i(int(random.uniform(0, sourceFormat.width())),
                          int(random.uniform(0, sourceFormat.height()))))
            crop1Area.extendBy(
                imath.V2i(int(random.uniform(0, sourceFormat.width())),
                          int(random.uniform(0, sourceFormat.height()))))
            crop1["area"].setValue(crop1Area)

            crop2Area = imath.Box2i()
            crop2Area.extendBy(
                imath.V2i(int(random.uniform(0, sourceFormat.width())),
                          int(random.uniform(0, sourceFormat.height()))))
            crop2Area.extendBy(
                imath.V2i(int(random.uniform(0, sourceFormat.width())),
                          int(random.uniform(0, sourceFormat.height()))))
            crop2["area"].setValue(crop2Area)

            expectedDataWindow = crop1Area
            expectedDataWindow.extendBy(crop2Area.min())
            expectedDataWindow.extendBy(crop2Area.max())

            self.assertEqual(merge["out"]["dataWindow"].getValue(),
                             expectedDataWindow)
Exemplo n.º 6
0
	def __getMessy( self, values = None, randomValueCount = 5, forceOverlap = False ) :

		nodes = {}

		if not values:
			values = []

		for i in range( randomValueCount ) :
			v = {}
			for channel in [ "R", "G", "B" ] :
				v[channel] = round( random.uniform( 0.0, 5.0 ), 2 )

			v["A"] = round( random.uniform( 0.0, 1.0 ), 2 )

			for channel in [ "Z", "ZBack" ] :
				v[channel] = round( random.uniform( 0.0, 10.0 ) )

			if random.random() > 0.5 :
				v["ZBack"] = v["Z"]
			else:
				v["ZBack"] = max(v["Z"], v["ZBack"])

			if forceOverlap:
				# All samples will overlap 100% - exercise the merge code
				v["Z"] = 1
				v["ZBack"] = 2

			values.append( v )

		nodes['merge'] = GafferImage.DeepMerge()
		nodes['constants'] = []
		nodes['values'] = values

		for i, v in enumerate( values ) :
			c,d = self.__getConstant( **v )
			nodes['constants'].append( c )
			nodes['constants'].append( d )
			nodes['merge']['in'][i].setInput( d["out"] )

		self.assertEqual( nodes['merge']["out"]["deep"].getValue(), True )

		return nodes
Exemplo n.º 7
0
    def testExceptionOnDeepData(self):

        constant1 = GafferImage.Constant()
        constant1["format"].setValue(GafferImage.Format(1000, 1000))
        constant1["color"].setValue(imath.Color4f(1))

        constant2 = GafferImage.Constant()
        constant2["format"].setValue(GafferImage.Format(1000, 1000))
        constant2["color"].setValue(imath.Color4f(1))

        merge = GafferImage.DeepMerge()
        merge["in"][0].setInput(constant1["out"])
        merge["in"][1].setInput(constant2["out"])

        with self.assertRaises(RuntimeError):
            sampler = GafferImage.Sampler(
                merge["out"],
                "R",
                imath.Box2i(imath.V2i(0), imath.V2i(200)),
                boundingMode=GafferImage.Sampler.BoundingMode.Black)
Exemplo n.º 8
0
	def testRealisticReference( self ) :
		representativeImage = GafferImage.ImageReader()
		representativeImage["fileName"].setValue( self.representativeImagePath )

		offset = GafferImage.Offset()
		offset["in"].setInput( representativeImage["out"] )
		offset["offset"].setValue( imath.V2i( -58, 11 ) )
		depthGrade = self.__createDepthGrade()
		depthGrade["in"].setInput( offset["out"] )
		depthGrade["depthOffset"].setValue( -0.9 )

		offset2 = GafferImage.Offset()
		offset2["in"].setInput( representativeImage["out"] )
		offset2["offset"].setValue( imath.V2i( -44, -46 ) )
		depthGrade2 = self.__createDepthGrade()
		depthGrade2["in"].setInput( offset2["out"] )
		depthGrade2["depthOffset"].setValue( -1.5 )

		deepMerge = GafferImage.DeepMerge()
		deepMerge["in"][-1].setInput( representativeImage["out"] )
		deepMerge["in"][-1].setInput( depthGrade["out"] )
		deepMerge["in"][-1].setInput( depthGrade2["out"] )

		referenceImage = GafferImage.ImageReader()
		referenceImage["fileName"].setValue( self.mergeReferencePath )

		self.__assertDeepStateProcessing( deepMerge["out"], referenceImage["out"], [ 0.002, 0.002, 0.002, 0.0003 ], [ 0.0001, 0.0001, 0.0001, 0.00003 ], 100, 2 )

		firstResult = GafferImage.DeepState()
		firstResult["in"].setInput( deepMerge["out"] )
		firstResult["deepState"].setValue( GafferImage.DeepState.TargetState.Flat )

		giantDepthOffset = self.__createDepthGrade()
		giantDepthOffset["in"].setInput( deepMerge["out"] )
		giantDepthOffset["depthOffset"].setValue( 100000 )

		# A large depth offset means we have insufficient floating point precision to represent
		# some samples, and some samples will collapse together.  This will throw off some pixels,
		# but most pixels should still be close to correct ( and in particular, the alpha channel is independent
		# of the order of results, so it's fine )
		self.__assertDeepStateProcessing( giantDepthOffset["out"], firstResult["out"], [ 0.5, 0.5, 0.5, 0.000002 ], [ 0.0002, 0.0002, 0.0002, 0.00000003 ], 50, 1 )
Exemplo n.º 9
0
    def testSampleOffsets(self):

        ts = GafferImage.ImagePlug.tileSize()

        constant1 = GafferImage.Constant()
        constant2 = GafferImage.Constant()

        constant1["format"].setValue(
            GafferImage.Format(imath.Box2i(imath.V2i(0), imath.V2i(512)), 1))
        constant2["format"].setValue(
            GafferImage.Format(imath.Box2i(imath.V2i(0), imath.V2i(512)), 1))

        merge = GafferImage.DeepMerge()
        merge["in"][0].setInput(constant1["out"])
        merge["in"][1].setInput(constant2["out"])

        expectedSampleOffsets = IECore.IntVectorData(
            range(2, ts * ts * 2 + 1, 2))
        actualSampleOffsets = merge["out"].sampleOffsets(imath.V2i(0))

        self.assertEqual(actualSampleOffsets, expectedSampleOffsets)
Exemplo n.º 10
0
	def testFlattenedWrite( self ) :

		c1 = GafferImage.Constant()
		c1['format'].setValue( GafferImage.Format( 512, 512 ) )
		c2 = GafferImage.Constant()
		c2['format'].setValue( GafferImage.Format( 512, 512 ) )

		m = GafferImage.DeepMerge()
		m['in'][0].setInput( c1["out"] )
		m['in'][1].setInput( c2["out"] )

		iState = GafferImage.DeepState()
		iState['in'].setInput( m['out'] )
		iState['deepState'].setValue( GafferImage.DeepState.TargetState.Flat )

		testFile = self.temporaryDirectory() + "/test.Flat.exr"
		self.assertFalse( os.path.exists( testFile ) )

		w = GafferImage.ImageWriter()
		w['in'].setInput( iState["out"] )

		w["fileName"].setValue( testFile )
		with Gaffer.Context() :
			w.execute()
Exemplo n.º 11
0
    def testBasics(self):
        representativeImage = GafferImage.ImageReader()
        representativeImage["fileName"].setValue(self.representativeImagePath)

        offset = GafferImage.Offset()
        offset["in"].setInput(representativeImage["out"])

        holdout = GafferImage.DeepHoldout()
        holdout["in"].setInput(representativeImage["out"])
        holdout["holdout"].setInput(offset["out"])

        flat = GafferImage.DeepToFlat()
        flat["in"].setInput(representativeImage["out"])

        # For the case of holding out an image by itself, we can find an analytic solution for the
        # held out alpha.  For a composited alpha value A, the held out alpha will be ( 1 - ( 1 - A )^2 ) / 2
        # Check that this relationship holds

        alphaOnlyHoldout = GafferImage.DeleteChannels()
        alphaOnlyHoldout["in"].setInput(holdout["out"])
        alphaOnlyHoldout["mode"].setValue(GafferImage.DeleteChannels.Mode.Keep)
        alphaOnlyHoldout["channels"].setValue('[A]')

        complementAndSquare = GafferImage.Grade()
        complementAndSquare["in"].setInput(flat["out"])
        complementAndSquare["channels"].setValue('[A]')
        complementAndSquare["multiply"].setValue(imath.Color4f(1, 1, 1, -1))
        complementAndSquare["offset"].setValue(imath.Color4f(0, 0, 0, 1))
        complementAndSquare["gamma"].setValue(imath.Color4f(1, 1, 1, 0.5))

        complementAndHalve = GafferImage.Grade()
        complementAndHalve["in"].setInput(complementAndSquare["out"])
        complementAndHalve["channels"].setValue('[A]')
        complementAndHalve["multiply"].setValue(imath.Color4f(1, 1, 1, -0.5))
        complementAndHalve["offset"].setValue(imath.Color4f(0, 0, 0, 0.5))

        alphaOnlyReference = GafferImage.DeleteChannels()
        alphaOnlyReference["in"].setInput(complementAndHalve["out"])
        alphaOnlyReference["mode"].setValue(
            GafferImage.DeleteChannels.Mode.Keep)
        alphaOnlyReference["channels"].setValue('[A]')

        self.assertImagesEqual(alphaOnlyHoldout["out"],
                               alphaOnlyReference["out"],
                               maxDifference=1e-6)

        # For a more complex holdout, we can create a comparison manually using shuffles and a DeepMerge
        preShuffle = GafferImage.Shuffle()
        preShuffle["in"].setInput(representativeImage["out"])
        preShuffle["channels"].addChild(preShuffle.ChannelPlug(
            "holdoutR", "R"))
        preShuffle["channels"].addChild(preShuffle.ChannelPlug(
            "holdoutG", "G"))
        preShuffle["channels"].addChild(preShuffle.ChannelPlug(
            "holdoutB", "B"))
        preShuffle["channels"].addChild(preShuffle.ChannelPlug(
            "holdoutA", "A"))

        manualHoldoutMerge = GafferImage.DeepMerge()
        manualHoldoutMerge["in"][0].setInput(preShuffle["out"])
        manualHoldoutMerge["in"][1].setInput(offset["out"])

        manualHoldoutFlatten = GafferImage.DeepToFlat()
        manualHoldoutFlatten["in"].setInput(manualHoldoutMerge["out"])

        postShuffle = GafferImage.Shuffle()
        postShuffle["in"].setInput(manualHoldoutFlatten["out"])
        postShuffle["channels"].addChild(
            postShuffle.ChannelPlug("R", "holdoutR"))
        postShuffle["channels"].addChild(
            postShuffle.ChannelPlug("G", "holdoutG"))
        postShuffle["channels"].addChild(
            postShuffle.ChannelPlug("B", "holdoutB"))
        postShuffle["channels"].addChild(
            postShuffle.ChannelPlug("A", "holdoutA"))

        channelCleanup = GafferImage.DeleteChannels()
        channelCleanup["in"].setInput(postShuffle["out"])
        channelCleanup["mode"].setValue(GafferImage.DeleteChannels.Mode.Keep)
        channelCleanup["channels"].setValue('[RGBAZ]')

        cropCleanup = GafferImage.Crop()
        cropCleanup["in"].setInput(channelCleanup["out"])
        cropCleanup["area"].setValue(
            imath.Box2i(imath.V2i(0, 0), imath.V2i(150, 100)))

        self.assertImagesEqual(holdout["out"],
                               cropCleanup["out"],
                               maxDifference=1e-5)

        # The way we handle Z is a bit arbitrary, but everything else we should be able to match with
        # this network with arbitrary inputs
        holdoutNoZ = GafferImage.DeleteChannels()
        holdoutNoZ["in"].setInput(holdout["out"])
        holdoutNoZ["channels"].setValue('Z')

        channelCleanup["channels"].setValue('[RGBA]')

        offset["offset"].setValue(imath.V2i(13, 31))
        self.assertImagesEqual(holdoutNoZ["out"],
                               cropCleanup["out"],
                               maxDifference=1e-5)

        offset["offset"].setValue(imath.V2i(-13, -51))
        self.assertImagesEqual(holdoutNoZ["out"],
                               cropCleanup["out"],
                               maxDifference=1e-5)

        offset["offset"].setValue(imath.V2i(103, -27))
        self.assertImagesEqual(holdoutNoZ["out"],
                               cropCleanup["out"],
                               maxDifference=1e-5)
Exemplo n.º 12
0
    def testDeep(self):

        constantA = GafferImage.Constant()
        constantA["color"].setValue(imath.Color4f(0.1, 0.2, 0.3, 0.4))
        constantB = GafferImage.Constant()
        constantB["color"].setValue(imath.Color4f(0.01, 0.02, 0.03, 0.04))
        constantC = GafferImage.Constant()
        constantC["color"].setValue(imath.Color4f(0.001, 0.002, 0.003, 0.004))
        constantD = GafferImage.Constant()
        constantD["color"].setValue(
            imath.Color4f(0.0001, 0.0002, 0.0003, 0.0004))

        deepMergeAB = GafferImage.DeepMerge()
        deepMergeAB["in"][0].setInput(constantA["out"])
        deepMergeAB["in"][1].setInput(constantB["out"])

        deepMergeCD = GafferImage.DeepMerge()
        deepMergeCD["in"][0].setInput(constantC["out"])
        deepMergeCD["in"][1].setInput(constantD["out"])

        switch = Gaffer.Switch()
        switch.setup(GafferImage.ImagePlug("in", ))
        switch["in"][0].setInput(deepMergeAB["out"])
        switch["in"][1].setInput(deepMergeCD["out"])

        switchExpr = Gaffer.Expression()
        switch.addChild(switchExpr)
        switchExpr.setExpression(
            'parent["index"] = context["collect:layerName"] == "CD"')

        collect = GafferImage.CollectImages()
        collect["in"].setInput(switch["out"])
        collect["rootLayers"].setValue(IECore.StringVectorData(['AB', 'CD']))

        o = imath.V2i(0)
        self.assertEqual(collect["out"].channelData("AB.R", o),
                         deepMergeAB["out"].channelData("R", o))
        self.assertEqual(collect["out"].channelData("AB.G", o),
                         deepMergeAB["out"].channelData("G", o))
        self.assertEqual(collect["out"].channelData("AB.B", o),
                         deepMergeAB["out"].channelData("B", o))
        self.assertEqual(collect["out"].channelData("AB.A", o),
                         deepMergeAB["out"].channelData("A", o))
        self.assertEqual(collect["out"].channelData("CD.R", o),
                         deepMergeCD["out"].channelData("R", o))
        self.assertEqual(collect["out"].channelData("CD.G", o),
                         deepMergeCD["out"].channelData("G", o))
        self.assertEqual(collect["out"].channelData("CD.B", o),
                         deepMergeCD["out"].channelData("B", o))
        self.assertEqual(collect["out"].channelData("CD.A", o),
                         deepMergeCD["out"].channelData("A", o))
        self.assertEqual(collect["out"].sampleOffsets(o),
                         deepMergeAB["out"].sampleOffsets(o))
        self.assertEqual(collect["out"].dataWindow(),
                         deepMergeAB["out"].dataWindow())
        self.assertEqual(collect["out"].deep(), True)
        self.assertEqual(
            collect["out"].channelNames(),
            IECore.StringVectorData([
                'AB.R', 'AB.G', 'AB.B', 'AB.A', 'CD.R', 'CD.G', 'CD.B', 'CD.A'
            ]))

        deepMergeAB["enabled"].setValue(False)
        with self.assertRaisesRegexp(
                Gaffer.ProcessException,
                r'Input to CollectImages must be consistent, but it is sometimes deep.*'
        ) as raised:
            collect["out"].deep()

        deepMergeAB["enabled"].setValue(True)

        deepMergeAB["in"][2].setInput(constantB["out"])

        with self.assertRaisesRegexp(
                Gaffer.ProcessException,
                r'SampleOffsets on input to CollectImages must match. Pixel 0,0 received both 3 and 2 samples'
        ) as raised:
            collect["out"].sampleOffsets(o)

        offset = GafferImage.Offset()
        offset["in"].setInput(constantB["out"])
        offset["offset"].setValue(imath.V2i(-5, -13))

        deepMergeAB["in"][2].setInput(offset["out"])
        with self.assertRaisesRegexp(
                Gaffer.ProcessException,
                r'DataWindows on deep input to CollectImages must match. Received both -5,-13 -> 1920,1080 and 0,0 -> 1920,1080'
        ) as raised:
            collect["out"].dataWindow()
Exemplo n.º 13
0
    def testDeepMix(self):
        representativeDeepImage = GafferImage.ImageReader()
        representativeDeepImage["fileName"].setValue(
            self.representativeDeepImagePath)

        # Easier to compare colors if we clamp - this requires unpremulting
        unpremultiply = GafferImage.Unpremultiply()
        unpremultiply["in"].setInput(representativeDeepImage["out"])

        clamp = GafferImage.Grade()
        clamp["in"].setInput(unpremultiply["out"])
        clamp["whiteClamp"].setValue(True)

        premultiply = GafferImage.Premultiply()
        premultiply["in"].setInput(clamp["out"])

        # Create a deep image containing a mixture of samples from two offset copies, where
        # the "offsetted" channel contains a mask showing which of the samples come from
        # the offsetted copy
        offset = GafferImage.Offset()
        offset["in"].setInput(premultiply["out"])
        offset["offset"].setValue(imath.V2i(33, -25))

        addOffsetMarker = GafferImage.Shuffle()
        addOffsetMarker["channels"].addChild(
            GafferImage.Shuffle.ChannelPlug("offsetted", "__white"))
        addOffsetMarker["in"].setInput(offset["out"])

        deepMerge = GafferImage.DeepMerge()
        deepMerge["in"].addChild(
            GafferImage.ImagePlug(
                "in2",
                flags=Gaffer.Plug.Flags.Default | Gaffer.Plug.Flags.Dynamic,
            ))
        deepMerge["in"]["in0"].setInput(addOffsetMarker["out"])
        deepMerge["in"]["in1"].setInput(premultiply["out"])

        gradeBlack = GafferImage.Grade()
        gradeBlack["in"].setInput(deepMerge["out"])
        gradeBlack["channels"].setValue('[RGBA]')
        gradeBlack["multiply"].setValue(imath.Color4f(0, 0, 0, 0))

        mix = GafferImage.Mix("mix")
        mix["in"]["in0"].setInput(deepMerge["out"])
        mix["in"]["in1"].setInput(gradeBlack["out"])
        mix["mask"].setInput(deepMerge["out"])
        mix["maskChannel"].setValue('offsetted')

        mixedFlat = GafferImage.DeepToFlat()
        mixedFlat["in"].setInput(mix["out"])

        mergeRef = GafferImage.DeepToFlat()
        mergeRef["in"].setInput(deepMerge["out"])

        startRef = GafferImage.DeepToFlat()
        startRef["in"].setInput(premultiply["out"])

        startDiff = GafferImage.Merge()
        startDiff["in"]["in0"].setInput(startRef["out"])
        startDiff["in"]["in1"].setInput(mixedFlat["out"])
        startDiff["operation"].setValue(GafferImage.Merge.Operation.Difference)

        startDiffStats = GafferImage.ImageStats("startDiffStats")
        startDiffStats["in"].setInput(startDiff["out"])
        startDiffStats["area"].setValue(mix["out"].dataWindow())

        mergedDiff = GafferImage.Merge()
        mergedDiff["in"]["in0"].setInput(mergeRef["out"])
        mergedDiff["in"]["in1"].setInput(mixedFlat["out"])
        mergedDiff["operation"].setValue(
            GafferImage.Merge.Operation.Difference)

        mergedDiffStats = GafferImage.ImageStats("mergedDiffStats")
        mergedDiffStats["in"].setInput(mergedDiff["out"])
        mergedDiffStats["area"].setValue(mix["out"].dataWindow())

        # With mix set to 0, the mix outputs the left input with everything
        mix["mix"].setValue(0.0)
        self.assertEqual(mergedDiffStats["average"].getValue(),
                         imath.Color4f(0))
        self.assertEqual(mergedDiffStats["max"].getValue(), imath.Color4f(0))
        self.assertGreater(startDiffStats["average"].getValue()[3], 0.2)
        self.assertGreater(startDiffStats["max"].getValue()[3], 0.999)
        for i in range(3):
            self.assertGreater(startDiffStats["average"].getValue()[i], 0.1)
            self.assertGreater(startDiffStats["max"].getValue()[i], 0.8)

        # With mix set to 1, the mix blends the offsetted samples to 0, and outputs just the non-offset
        # samples
        mix["mix"].setValue(1.0)
        for i in range(4):
            self.assertAlmostEqual(startDiffStats["average"].getValue()[i], 0)
            self.assertAlmostEqual(startDiffStats["max"].getValue()[i],
                                   0,
                                   places=5)
        self.assertGreater(mergedDiffStats["average"].getValue()[3], 0.2)
        self.assertGreater(mergedDiffStats["max"].getValue()[3], 0.999)
        for i in range(3):
            self.assertGreater(mergedDiffStats["average"].getValue()[i], 0.1)
            self.assertGreater(mergedDiffStats["max"].getValue()[i], 0.8)

        # With the mix in between, the result should be a bit closer to both than the farthest
        # result at either extreme
        mix["mix"].setValue(0.75)
        self.assertLess(startDiffStats["average"].getValue()[3], 0.16)
        self.assertLess(startDiffStats["max"].getValue()[3], 0.8)
        self.assertLess(mergedDiffStats["average"].getValue()[3], 0.16)
        self.assertLess(mergedDiffStats["max"].getValue()[3], 0.8)
        for i in range(3):
            self.assertLess(startDiffStats["average"].getValue()[i], 0.08)
            self.assertLess(startDiffStats["max"].getValue()[i], 0.7)
            self.assertLess(mergedDiffStats["average"].getValue()[i], 0.08)
            self.assertLess(mergedDiffStats["max"].getValue()[i], 0.7)
Exemplo n.º 14
0
	def testMissingChannels( self ) :

		# Create some messy data
		representativeImage = GafferImage.ImageReader()
		representativeImage["fileName"].setValue( self.representativeImagePath )

		offset = GafferImage.Offset()
		offset["in"].setInput( representativeImage["out"] )
		offset["offset"].setValue( imath.V2i( 29, 9 ) )

		deepMerge = GafferImage.DeepMerge()
		deepMerge["in"][0].setInput( representativeImage["out"] )
		deepMerge["in"][1].setInput( offset["out"] )

		referenceFlatten = GafferImage.DeepState()
		referenceFlatten["in"].setInput( deepMerge["out"] )
		referenceFlatten["deepState"].setValue( GafferImage.DeepState.TargetState.Flat )

		deleteChannels = GafferImage.DeleteChannels()
		deleteChannels["in"].setInput( deepMerge["out"] )

		self.__assertDeepStateProcessing( deleteChannels["out"], referenceFlatten["out"], [ 0, 0, 0, 0 ], [ 0, 0, 0, 0 ], 100, 0.45 )

		# Having no ZBack should be equivalent to having ZBack = Z
		deleteChannels["channels"].setValue( "ZBack" )

		referenceNoZBack = GafferImage.Shuffle()
		referenceNoZBack["in"].setInput( deepMerge["out"] )
		referenceNoZBack["channels"].addChild( referenceNoZBack.ChannelPlug( "ZBack", "Z" ) )

		referenceFlatten["in"].setInput( referenceNoZBack["out"] )

		self.__assertDeepStateProcessing( deleteChannels["out"], referenceFlatten["out"], [ 0, 0, 0, 0 ], [ 0, 0, 0, 0 ], 100, 0.45 )

		# Removing A results in all samples just getting summed.
		deleteChannels["channels"].setValue( "A" )

		referenceNoAlphaA = GafferImage.DeleteChannels()
		referenceNoAlphaA["in"].setInput( representativeImage["out"] )
		referenceNoAlphaA["channels"].setValue( "A" )

		referenceFlattenA = GafferImage.DeepState()
		referenceFlattenA["in"].setInput( referenceNoAlphaA["out"] )
		referenceFlattenA["deepState"].setValue( GafferImage.DeepState.TargetState.Flat )

		referenceNoAlphaB = GafferImage.DeleteChannels()
		referenceNoAlphaB["in"].setInput( offset["out"] )
		referenceNoAlphaB["channels"].setValue( "A" )

		referenceFlattenB = GafferImage.DeepState()
		referenceFlattenB["in"].setInput( referenceNoAlphaB["out"] )
		referenceFlattenB["deepState"].setValue( GafferImage.DeepState.TargetState.Flat )

		referenceSum = GafferImage.Merge()
		referenceSum['operation'].setValue( GafferImage.Merge.Operation.Add )
		referenceSum['in'][0].setInput( referenceFlattenA["out"] )
		referenceSum['in'][1].setInput( referenceFlattenB["out"] )

		self.__assertDeepStateProcessing( deleteChannels["out"], referenceSum["out"], [ 3e-6, 3e-6, 3e-6, 10 ], [ 2e-8, 2e-8, 2e-8, 10 ], 0, 0 )

		deleteChannels["channels"].setValue( "A ZBack" )

		self.__assertDeepStateProcessing( deleteChannels["out"], referenceSum["out"], [ 3e-6, 3e-6, 3e-6, 10 ], [ 2e-8, 2e-8, 2e-8, 10 ], 0, 0 )

		deleteChannels["channels"].setValue( "A Z ZBack" )

		self.__assertDeepStateProcessing( deleteChannels["out"], referenceSum["out"], [ 3e-6, 3e-6, 3e-6, 10 ], [ 2e-8, 2e-8, 2e-8, 10 ], 0, 0 )

		# Having no Z should be equivalent to having all the samples composited in their current order
		deleteChannels["channels"].setValue( "Z ZBack" )

		try:
			import GafferOSL
		except:
			raise unittest.SkipTest( "Could not load GafferOSL, skipping DeepState missing alpha test" )

		outZIndexCode = GafferOSL.OSLCode( "OSLCode" )
		outZIndexCode["out"].addChild( Gaffer.FloatPlug( "output1", direction = Gaffer.Plug.Direction.Out ) )
		outZIndexCode["code"].setValue( 'output1 = P[2];' )

		replaceDepths = GafferOSL.OSLImage( "OSLImage" )
		replaceDepths["in"].setInput( deepMerge["out"] )
		replaceDepths["channels"].addChild( Gaffer.NameValuePlug( "Z", Gaffer.FloatPlug( "value" ), True ) )
		replaceDepths["channels"].addChild( Gaffer.NameValuePlug( "ZBack", Gaffer.FloatPlug( "value" ), True ) )
		replaceDepths["channels"][0]["value"].setInput( outZIndexCode["out"]["output1"] )
		replaceDepths["channels"][1]["value"].setInput( outZIndexCode["out"]["output1"] )

		referenceFlatten["in"].setInput( replaceDepths["out"] )

		self.__assertDeepStateProcessing( deleteChannels["out"], referenceFlatten["out"], [ 0, 0, 0, 10 ], [ 0, 0, 0, 10 ], 100, 0.45 )

		deleteChannels["channels"].setValue( "[Z]" ) # Removing just Z has the same effect

		self.__assertDeepStateProcessing( deleteChannels["out"], referenceFlatten["out"], [ 0, 0, 0, 10 ], [ 0, 0, 0, 10 ], 100, 0.45 )
Exemplo n.º 15
0
	def testMoreArbitraryOffsets( self ) :
		representativeImage = GafferImage.ImageReader()
		representativeImage["fileName"].setValue( self.representativeImagePath )

		crop = GafferImage.Crop()
		crop["in"].setInput( representativeImage["out"] )
		offset = GafferImage.Offset()
		offset["in"].setInput( crop["out"] )
		depthGrade = self.__createDepthGrade()
		depthGrade["in"].setInput( offset["out"] )

		deepMerge = GafferImage.DeepMerge()
		deepMerge["in"][-1].setInput( representativeImage["out"] )
		deepMerge["in"][-1].setInput( depthGrade["out"] )

		firstResult = GafferImage.DeepState()
		firstResult["in"].setInput( deepMerge["out"] )
		firstResult["deepState"].setValue( GafferImage.DeepState.TargetState.Flat )

		deepMergeBackwards = GafferImage.DeepMerge()
		deepMergeBackwards["in"][-1].setInput( depthGrade["out"] )
		deepMergeBackwards["in"][-1].setInput( representativeImage["out"] )

		giantDepthOffset = self.__createDepthGrade()
		giantDepthOffset["in"].setInput( deepMerge["out"] )
		giantDepthOffset["depthOffset"].setValue( 100000 )

		flatRepresentative = GafferImage.DeepState()
		flatRepresentative["in"].setInput( representativeImage["out"] )
		flatRepresentative["deepState"].setValue( GafferImage.DeepState.TargetState.Flat )

		flatCrop = GafferImage.Crop()
		flatCrop["in"].setInput( flatRepresentative["out"] )
		flatCrop["area"].setInput( crop["area"] )

		flatOffset = GafferImage.Offset()
		flatOffset["in"].setInput( flatCrop["out"] )
		flatOffset["offset"].setInput( offset["offset"] )

		flatOver = GafferImage.Merge()
		flatOver['operation'].setValue( GafferImage.Merge.Operation.Over )
		flatOver['in'][0].setInput( flatRepresentative["out"] )
		flatOver['in'][1].setInput( flatOffset["out"] )

		for curOffset, curDepthOffset, curCrop  in [
			[ imath.V2i( 0, 0 ), 0, None ],
			[ imath.V2i( 1, 1 ), 0.0001, None ],
			[ imath.V2i( 4, 6 ), 0.2, None ],
			[ imath.V2i( 10, 14 ), 0.3, None ],
			[ imath.V2i( 0, 0 ), 0, imath.Box2i( imath.V2i( 11, 17 ), imath.V2i( 101, 93 ) ) ],
			[ imath.V2i( 10, 14 ), 0.3, imath.Box2i( imath.V2i( 19, 23 ), imath.V2i( 91, 73 ) ) ],
		]:
			offset["offset"].setValue( curOffset )
			depthGrade["depthOffset"].setValue( curDepthOffset )
			if curCrop:
				crop["area"].setValue( curCrop )
			else:
				crop["area"].setValue( imath.Box2i( imath.V2i( 0, 0 ), imath.V2i( 150, 100 ) ) )

			expectedMaxPrune = 4 if curDepthOffset == 0 or curCrop else 100
			expectedAveragePrune = 0.1 if curDepthOffset == 0 or curCrop else 0.45

			# Comparing to a flat over isn't very accurate - we need a big tolerance.  But we can make sure it
			# didn't explode, and we can check the alpha accurately.
			self.__assertDeepStateProcessing( deepMerge["out"], flatOver["out"], [ 8, 8, 8, 0.000003 ], [ 0.09, 0.09, 0.09, 0.0000002 ], expectedMaxPrune, expectedAveragePrune )

			# Switching the order we merge in should have no impact
			self.__assertDeepStateProcessing( deepMergeBackwards["out"], firstResult["out"], [ 0.000002, 0.000002, 0.000002, 0 ], [ 0.00000002, 0.00000002, 0.00000002, 0 ], expectedMaxPrune, expectedAveragePrune )

			# As in prev test, this is large enough to cause precision problems, but things should still mostly work
			self.__assertDeepStateProcessing( giantDepthOffset["out"], firstResult["out"], [ 0.7, 0.7, 0.7, 0.000004 ], [ 0.002, 0.002, 0.002, 0.0000002 ], min( expectedMaxPrune, 20 ), expectedAveragePrune )
Exemplo n.º 16
0
	def testPracticalTransparencyPrune( self ) :
		representativeImage = GafferImage.ImageReader()
		representativeImage["fileName"].setValue( self.representativeImagePath )

		empty = GafferImage.Empty()
		empty["format"].setValue( GafferImage.Format( imath.Box2i( imath.V2i( 0 ), imath.V2i( 150, 100 ) ), 1 ) )

		properlyLabelledIn = GafferImage.DeepMerge()
		properlyLabelledIn["in"][0].setInput( representativeImage["out"] )
		properlyLabelledIn["in"][1].setInput( empty["out"] )

		# The representative image from Arnold actually contains overlaps one floating point epsilon in width.
		# Get rid of those, and then we can see the sampleCounts change in a predictable way
		actuallyTidyIn = GafferImage.DeepState()
		actuallyTidyIn["in"].setInput( properlyLabelledIn["out"] )

		prune = GafferImage.DeepState()
		prune["in"].setInput( actuallyTidyIn["out"] )
		prune["pruneTransparent"].setValue( True )

		flatRef = GafferImage.DeepState()
		flatRef["in"].setInput( actuallyTidyIn["out"] )
		flatRef["deepState"].setValue( GafferImage.DeepState.TargetState.Flat )

		flatPrune = GafferImage.DeepState()
		flatPrune["in"].setInput( prune["out"] )
		flatPrune["deepState"].setValue( GafferImage.DeepState.TargetState.Flat )

		diff = GafferImage.Merge()
		diff['operation'].setValue( GafferImage.Merge.Operation.Difference )
		diff['in'][0].setInput( flatPrune["out"] )
		diff['in'][1].setInput( flatRef["out"] )

		diffStats = GafferImage.ImageStats()
		diffStats["in"].setInput( diff["out"] )
		diffStats["area"].setValue( diff["out"].dataWindow() )


		origCounts = GafferImage.DeepSampleCounts()
		origCounts["in"].setInput( actuallyTidyIn["out"] )

		prunedCounts = GafferImage.DeepSampleCounts()
		prunedCounts["in"].setInput( prune["out"] )

		diffCounts = GafferImage.Merge()
		diffCounts["operation"].setValue( GafferImage.Merge.Operation.Subtract )
		diffCounts["in"][0].setInput( origCounts["out"] )
		diffCounts["in"][1].setInput( prunedCounts["out"] )

		diffCountsStats = GafferImage.ImageStats()
		diffCountsStats["in"].setInput( diffCounts["out"] )
		diffCountsStats["area"].setValue( diffCounts["out"].dataWindow() )

		self.assertEqual( diffCountsStats["max"].getValue()[0], 0 )
		# For some reason, our test data from Arnold has a bunch of transparent pixels to start with,
		# so we've got some stuff to throw out
		self.assertLess( diffCountsStats["min"].getValue()[0], -20 )
		self.assertLess( diffCountsStats["min"].getValue()[0], -0.26 )

		# We've got some moderate error introduced by discarding transparent.  Why is it so large?
		# Looks like those transparent pixels are slightly emissive
		for i in range( 4 ):
			self.assertLessEqual( diffStats["max"].getValue()[i], [0.00001,0.00001,0.00001,0][i] )
			self.assertGreaterEqual( diffStats["max"].getValue()[i], [0.000001,0.000001,0.000001,0][i] )

		# By premulting/unpremulting, we zero out samples with no alpha
		premultiply = GafferImage.Premultiply()
		premultiply["in"].setInput( actuallyTidyIn["out"] )
		unpremultiply = GafferImage.Unpremultiply()
		unpremultiply["in"].setInput( premultiply["out"] )
		flatRef["in"].setInput( unpremultiply["out"] )
		prune["in"].setInput( unpremultiply["out"] )

		# That gets us a couple extra digits of matching - this is more like what we would expect based
		# on floating point precision
		for i in range( 4 ):
			self.assertLessEqual( diffStats["max"].getValue()[i], [0.0000005,0.0000005,0.0000005,0][i] )

		# But now lets hack it to really make some transparent pixels
		grade = GafferImage.Grade()
		grade["in"].setInput( actuallyTidyIn["out"] )
		grade["channels"].setValue( '[A]' )
		grade["multiply"]["a"].setValue( 1.5 )
		grade["offset"]["a"].setValue( -0.5 )

		premultiply['in'].setInput( grade["out"] )

		# Now we can kill lots of samples
		self.assertEqual( diffCountsStats["max"].getValue()[0], 0 )
		self.assertLess( diffCountsStats["min"].getValue()[0], -200 )
		self.assertLess( diffCountsStats["min"].getValue()[0], -10 )

		# And the flattened results still match closely
		for i in range( 4 ):
			self.assertLessEqual( diffStats["max"].getValue()[i], [0.0000005,0.0000005,0.0000005,0.0000002][i] )
Exemplo n.º 17
0
    def testChannelData(self):

        ts = GafferImage.ImagePlug.tileSize()

        constant1 = GafferImage.Constant()
        constant1["format"].setValue(
            GafferImage.Format(imath.Box2i(imath.V2i(0), imath.V2i(512)), 1))
        constant1["color"].setValue(imath.Color4f(0.25, 0.5, 1.0, 0.5))

        addDepth1 = GafferImage.FlatToDeep()
        addDepth1["in"].setInput(constant1["out"])
        addDepth1["depth"].setValue(10.0)

        constant2 = GafferImage.Constant()
        constant2["format"].setValue(
            GafferImage.Format(imath.Box2i(imath.V2i(0), imath.V2i(512)), 1))
        constant2["color"].setValue(imath.Color4f(2.0, 3.0, 4.0, 1.0))

        addDepth2 = GafferImage.FlatToDeep()
        addDepth2["in"].setInput(constant2["out"])
        addDepth2["depth"].setValue(20.0)

        merge = GafferImage.DeepMerge()
        merge["in"][0].setInput(addDepth1["out"])
        merge["in"][1].setInput(addDepth2["out"])

        expectedChannelData = {}
        expectedChannelData["R"] = IECore.FloatVectorData([0.25, 2.0] * ts *
                                                          ts)
        expectedChannelData["G"] = IECore.FloatVectorData([0.5, 3.0] * ts * ts)
        expectedChannelData["B"] = IECore.FloatVectorData([1.0, 4.0] * ts * ts)
        expectedChannelData["A"] = IECore.FloatVectorData([0.5, 1.0] * ts * ts)
        expectedChannelData["Z"] = IECore.FloatVectorData([10.0, 20.0] * ts *
                                                          ts)

        for channelName in expectedChannelData:
            actualChannelData = merge["out"].channelData(
                channelName, imath.V2i(0))
            self.assertEqual(actualChannelData,
                             expectedChannelData[channelName])

        addDepth1["zBackMode"].setValue(
            GafferImage.FlatToDeep.ZBackMode.Thickness)
        addDepth1["thickness"].setValue(2.0)

        expectedChannelData["ZBack"] = IECore.FloatVectorData([12.0, 20.0] *
                                                              ts * ts)

        for channelName in expectedChannelData:
            actualChannelData = merge["out"].channelData(
                channelName, imath.V2i(0))
            self.assertEqual(actualChannelData,
                             expectedChannelData[channelName])

        addDepth2["zBackMode"].setValue(
            GafferImage.FlatToDeep.ZBackMode.Thickness)
        addDepth2["thickness"].setValue(0.1)

        expectedChannelData["ZBack"] = IECore.FloatVectorData([12.0, 20.1] *
                                                              ts * ts)

        for channelName in expectedChannelData:
            actualChannelData = merge["out"].channelData(
                channelName, imath.V2i(0))
            self.assertEqual(actualChannelData,
                             expectedChannelData[channelName])
Exemplo n.º 18
0
    def __testMergedDifferentDataWindows(self, ensureOverlap=False):

        ts = GafferImage.ImagePlug.tileSize()
        tileCount = 2

        values1 = {
            "R": 0.25,
            "G": 0.5,
            "B": 1.0,
            "A": 0.5,
            "Z": 10.0,
            "ZBack": 12.0
        }
        values2 = {
            "R": 2.0,
            "G": 3.0,
            "B": 4.0,
            "A": 1.0,
            "Z": 20.0,
            "ZBack": 20.0
        }

        sourceFormat = GafferImage.Format(
            imath.Box2i(imath.V2i(0), imath.V2i(ts * tileCount)), 1)

        constant1 = GafferImage.Constant()
        constant1["format"].setValue(sourceFormat)
        constant1["color"].setValue(
            imath.Color4f(values1["R"], values1["G"], values1["B"],
                          values1["A"]))

        addDepth1 = GafferImage.FlatToDeep()
        addDepth1["in"].setInput(constant1["out"])
        addDepth1["depth"].setValue(values1["Z"])
        addDepth1["zBackMode"].setValue(
            GafferImage.FlatToDeep.ZBackMode.Thickness)
        addDepth1["thickness"].setValue(values1["ZBack"] - values1["Z"])

        constant2 = GafferImage.Constant()
        constant2["format"].setValue(sourceFormat)
        constant2["color"].setValue(
            imath.Color4f(values2["R"], values2["G"], values2["B"],
                          values2["A"]))

        addDepth2 = GafferImage.FlatToDeep()
        addDepth2["in"].setInput(constant2["out"])
        addDepth2["depth"].setValue(values2["Z"])
        addDepth2["zBackMode"].setValue(
            GafferImage.FlatToDeep.ZBackMode.Thickness)
        addDepth2["thickness"].setValue(values2["ZBack"] - values2["Z"])

        crop1 = GafferImage.Crop()
        crop1["in"].setInput(addDepth1["out"])
        crop1["affectDisplayWindow"].setValue(False)

        crop2 = GafferImage.Crop()
        crop2["in"].setInput(addDepth2["out"])
        crop2["affectDisplayWindow"].setValue(False)

        merge = GafferImage.DeepMerge()
        merge["in"][0].setInput(crop1["out"])
        merge["in"][1].setInput(crop2["out"])

        for i in range(10):
            crop1Area = imath.Box2i()
            crop1Area.extendBy(
                imath.V2i(int(random.uniform(0, sourceFormat.width())),
                          int(random.uniform(0, sourceFormat.height()))))
            crop1Area.extendBy(
                imath.V2i(int(random.uniform(0, sourceFormat.width())),
                          int(random.uniform(0, sourceFormat.height()))))

            crop2Area = imath.Box2i()
            crop2Area.extendBy(
                imath.V2i(int(random.uniform(0, sourceFormat.width())),
                          int(random.uniform(0, sourceFormat.height()))))
            crop2Area.extendBy(
                imath.V2i(int(random.uniform(0, sourceFormat.width())),
                          int(random.uniform(0, sourceFormat.height()))))

            # If we want to ensure that the two crop areas overlap, extend the second one to a random point
            # within the first one's area
            if ensureOverlap and not GafferImage.BufferAlgo.intersects(
                    crop1Area, crop2Area):
                crop2Area.extendBy(
                    imath.V2i(
                        int(
                            random.uniform(crop1Area.min().x,
                                           crop1Area.max().x)),
                        int(
                            random.uniform(crop1Area.min().y,
                                           crop1Area.max().y))))

            crop1["area"].setValue(crop1Area)
            crop2["area"].setValue(crop2Area)

            for tileX in range(tileCount):
                for tileY in range(tileCount):
                    tileOrigin = imath.V2i(tileX * ts, tileY * ts)

                    sampleOffsets = merge["out"].sampleOffsets(tileOrigin)

                    self.assertEqual(
                        sampleOffsets,
                        self.__getExpectedSampleOffsets(
                            tileOrigin, crop1Area, crop2Area))

                    for channelName in values1.keys():
                        channelData = merge["out"].channelData(
                            channelName, tileOrigin)

                        self.assertEqual(
                            channelData,
                            self.__getExpectedChannelData(
                                tileOrigin, crop1Area, values1[channelName],
                                crop2Area, values2[channelName]))
Exemplo n.º 19
0
    def testChannelRequest(self):

        ts = GafferImage.ImagePlug.tileSize()

        a = GafferImage.Constant()
        a["color"].setValue(imath.Color4f(0.1, 0.2, 0.3, 0.4))

        addDepthA = GafferImage.FlatToDeep()
        addDepthA["in"].setInput(a["out"])
        addDepthA["depth"].setValue(2.0)
        addDepthA["zBackMode"].setValue(
            GafferImage.FlatToDeep.ZBackMode.Thickness)
        addDepthA["thickness"].setValue(1.0)

        ad = GafferImage.DeleteChannels()
        ad["in"].setInput(addDepthA["out"])
        ad["mode"].setValue(GafferImage.DeleteChannels.Mode.Delete)
        ad["channels"].setValue(IECore.StringVectorData(["G", "Z", "ZBack"]))

        b = GafferImage.Constant()
        b["color"].setValue(imath.Color4f(0.5, 0.6, 0.7, 0.8))

        addDepthB = GafferImage.FlatToDeep()
        addDepthB["in"].setInput(b["out"])
        addDepthB["depth"].setValue(4.0)
        addDepthB["zBackMode"].setValue(
            GafferImage.FlatToDeep.ZBackMode.Thickness)
        addDepthB["thickness"].setValue(1.0)

        bd = GafferImage.DeleteChannels()
        bd["in"].setInput(addDepthB["out"])
        bd["mode"].setValue(GafferImage.DeleteChannels.Mode.Delete)
        bd["channels"].setValue(IECore.StringVectorData(["R", "A"]))

        merge = GafferImage.DeepMerge()
        merge["in"][0].setInput(ad["out"])
        merge["in"][1].setInput(bd["out"])

        ad["enabled"].setValue(False)
        bd["enabled"].setValue(False)

        expectedChannelData = {}
        expectedChannelData["R"] = IECore.FloatVectorData([0.1, 0.5] * ts * ts)
        expectedChannelData["G"] = IECore.FloatVectorData([0.2, 0.6] * ts * ts)
        expectedChannelData["B"] = IECore.FloatVectorData([0.3, 0.7] * ts * ts)
        expectedChannelData["A"] = IECore.FloatVectorData([0.4, 0.8] * ts * ts)
        expectedChannelData["Z"] = IECore.FloatVectorData([2.0, 4.0] * ts * ts)
        expectedChannelData["ZBack"] = IECore.FloatVectorData([3.0, 5.0] * ts *
                                                              ts)

        for channelName in expectedChannelData:
            actualChannelData = merge["out"].channelData(
                channelName, imath.V2i(0))
            self.assertEqual(actualChannelData,
                             expectedChannelData[channelName])

        ad["enabled"].setValue(True)
        bd["enabled"].setValue(True)

        expectedChannelData = {}
        expectedChannelData["R"] = IECore.FloatVectorData([0.1, 0.0] * ts * ts)
        expectedChannelData["G"] = IECore.FloatVectorData([0.0, 0.6] * ts * ts)
        expectedChannelData["B"] = IECore.FloatVectorData([0.3, 0.7] * ts * ts)
        expectedChannelData["A"] = IECore.FloatVectorData([0.4, 0.0] * ts * ts)
        expectedChannelData["Z"] = IECore.FloatVectorData([0.0, 4.0] * ts * ts)
        expectedChannelData["ZBack"] = IECore.FloatVectorData([0.0, 5.0] * ts *
                                                              ts)

        for channelName in expectedChannelData:
            actualChannelData = merge["out"].channelData(
                channelName, imath.V2i(0))
            self.assertEqual(actualChannelData,
                             expectedChannelData[channelName])