def testDirtyPropagation(self): a = GafferImage.Constant() b = GafferImage.Constant() aShuffle = GafferImage.Shuffle() aShuffle["in"].setInput(a["out"]) bShuffle = GafferImage.Shuffle() bShuffle["in"].setInput(b["out"]) holdout = GafferImage.DeepHoldout() holdout["in"].setInput(aShuffle["out"]) holdout["holdout"].setInput(bShuffle["out"]) cs = GafferTest.CapturingSlot(holdout.plugDirtiedSignal()) a["color"]["r"].setValue(0.5) dirtiedPlugs = {x[0].relativeName(holdout) for x in cs} self.assertIn("__intermediateIn.channelData", dirtiedPlugs) self.assertIn("__flattened.channelData", dirtiedPlugs) self.assertIn("out.channelData", dirtiedPlugs) del cs[:] b["color"]["a"].setValue(0.5) dirtiedPlugs = {x[0].relativeName(holdout) for x in cs} self.assertIn("__flattened.channelData", dirtiedPlugs) self.assertIn("out.channelData", dirtiedPlugs) del cs[:] aShuffle["channels"].addChild(bShuffle.ChannelPlug("Z", "__white")) dirtiedPlugs = {x[0].relativeName(holdout) for x in cs} self.assertIn("__intermediateIn.channelData", dirtiedPlugs) self.assertIn("__flattened.channelData", dirtiedPlugs) self.assertIn("out.channelData", dirtiedPlugs) self.assertIn("__intermediateIn.channelNames", dirtiedPlugs) self.assertIn("__flattened.channelNames", dirtiedPlugs) self.assertIn("out.channelNames", dirtiedPlugs) del cs[:] bShuffle["channels"].addChild(bShuffle.ChannelPlug("Z", "__white")) dirtiedPlugs = {x[0].relativeName(holdout) for x in cs} self.assertIn("__flattened.channelData", dirtiedPlugs) self.assertIn("out.channelData", dirtiedPlugs) self.assertIn("__flattened.channelNames", dirtiedPlugs) del cs[:]
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)