示例#1
0
    def testPassThrough(self):

        c = GafferImage.Constant()
        f = GafferImage.Reformat()
        f["in"].setInput(c["out"])
        f["format"].setValue(
            GafferImage.Format(IECore.Box2i(IECore.V2i(0), IECore.V2i(10)), 1))
        d = GafferImage.ImageMetadata()
        d["metadata"].addMember(
            "comment", IECore.StringData("reformated and metadata updated"))
        d["in"].setInput(f["out"])

        m = GafferImage.Merge()
        m["in"][0].setInput(c["out"])
        m["in"][1].setInput(d["out"])

        self.assertEqual(m["out"]["format"].hash(), c["out"]["format"].hash())
        self.assertEqual(m["out"]["metadata"].hash(),
                         c["out"]["metadata"].hash())

        self.assertEqual(m["out"]["format"].getValue(),
                         c["out"]["format"].getValue())
        self.assertEqual(m["out"]["metadata"].getValue(),
                         c["out"]["metadata"].getValue())

        m["in"][0].setInput(d["out"])
        m["in"][1].setInput(c["out"])

        self.assertEqual(m["out"]["format"].hash(), d["out"]["format"].hash())
        self.assertEqual(m["out"]["metadata"].hash(),
                         d["out"]["metadata"].hash())

        self.assertEqual(m["out"]["format"].getValue(),
                         d["out"]["format"].getValue())
        self.assertEqual(m["out"]["metadata"].getValue(),
                         d["out"]["metadata"].getValue())
示例#2
0
	def testHash( self ) :

		c = Gaffer.Context()
		c.setFrame( 1 )
		c2 = Gaffer.Context()
		c2.setFrame( 2 )

		writer = GafferImage.ImageWriter()

		# empty file produces no effect
		self.assertEqual( writer["fileName"].getValue(), "" )
		self.assertEqual( writer.hash( c ), IECore.MurmurHash() )

		# no input image produces no effect
		writer["fileName"].setValue( self.temporaryDirectory() + "/test.exr" )
		self.assertEqual( writer.hash( c ), IECore.MurmurHash() )

		# now theres a file and an image, we get some output
		constant = GafferImage.Constant()
		writer["in"].setInput( constant["out"] )
		self.assertNotEqual( writer.hash( c ), IECore.MurmurHash() )

		# output doesn't vary by time yet
		self.assertEqual( writer.hash( c ), writer.hash( c2 ) )

		# now it does vary
		writer["fileName"].setValue( self.temporaryDirectory() + "/test.#.exr" )
		self.assertNotEqual( writer.hash( c ), writer.hash( c2 ) )

		# other plugs matter too
		current = writer.hash( c )
		writer["openexr"]["mode"].setValue( GafferImage.ImageWriter.Mode.Tile )
		self.assertNotEqual( writer.hash( c ), current )
		current = writer.hash( c )
		writer["channels"].setValue( IECore.StringVectorData( [ "R" ] ) )
		self.assertNotEqual( writer.hash( c ), current )
示例#3
0
    def testChannelDataPassThrough(self):

        # Resize to the same size as the input image.
        c = GafferImage.Constant()
        c["format"].setValue(
            GafferImage.Format(imath.Box2i(imath.V2i(0), imath.V2i(512)), 1))
        c["color"].setValue(imath.Color4f(0.25, 0.5, 0.75, 1))

        r = GafferImage.Resize()
        r["in"].setInput(c["out"])
        r["format"].setValue(
            GafferImage.Format(imath.Box2i(imath.V2i(0), imath.V2i(512)), 1))

        # Assert that the pixel data is passed clean through.
        for channel in ["R", "G", "B", "A"]:
            self.assertEqual(
                c["out"].channelDataHash(channel, imath.V2i(0)),
                r["out"].channelDataHash(channel, imath.V2i(0)),
            )
            self.assertTrue(c["out"].channelData(
                channel, imath.V2i(0),
                _copy=False).isSame(r["out"].channelData(channel,
                                                         imath.V2i(0),
                                                         _copy=False)))
	def testDisabling( self ) :

		script = Gaffer.ScriptNode()

		script["constant"] = GafferImage.Constant()

		script["expression"] = Gaffer.Expression()
		script["expression"].setExpression( 'parent["constant"]["color"]["r"] = context["frame"]' )

		script["timeWarp"] = Gaffer.TimeWarp()
		script["timeWarp"].setup( GafferImage.ImagePlug() )

		script["timeWarp"]["offset"].setValue( 1 )
		script["timeWarp"]["in"].setInput( script["constant"]["out"] )

		with script.context() :

			c = GafferImage.ImageAlgo.image( script["constant"]["out"] )
			cHash = GafferImage.ImageAlgo.imageHash( script["constant"]["out"] )
			t = GafferImage.ImageAlgo.image( script["timeWarp"]["out"] )
			tHash = GafferImage.ImageAlgo.imageHash( script["timeWarp"]["out"] )

		self.assertNotEqual( c, t )
		self.assertNotEqual( cHash, tHash )

		script["timeWarp"]["enabled"].setValue( False )

		with script.context() :

			c = GafferImage.ImageAlgo.image( script["constant"]["out"] )
			cHash = GafferImage.ImageAlgo.imageHash( script["constant"]["out"] )
			t = GafferImage.ImageAlgo.image( script["timeWarp"]["out"] )
			tHash = GafferImage.ImageAlgo.imageHash( script["timeWarp"]["out"] )

		self.assertEqual( c, t )
		self.assertEqual( cHash, tHash )
示例#5
0
	def testWriteIntermediateFile( self ) :

		# This tests a fairly common usage pattern whereby
		# an ImageReader loads an image generated higher
		# up the task tree, some processing is done, and
		# then an ImageWriter is used to write out the modified
		# image. A good example of this is a render node being
		# used to generate an image which is then pushed through
		# a slapcomp process. Because the rendered image to be
		# read/written doesn't exist at the point of dispatch
		# we have to make sure this doesn't cause problems.

		s = Gaffer.ScriptNode()

		s["c"] = GafferImage.Constant()

		s["w1"] = GafferImage.ImageWriter()
		s["w1"]["in"].setInput( s["c"]["out"] )
		s["w1"]["fileName"].setValue( self.temporaryDirectory() + "/test1.exr" )

		s["r"] = GafferImage.ImageReader()
		s["r"]["fileName"].setValue( self.temporaryDirectory() + "/test1.exr" )

		s["w2"] = GafferImage.ImageWriter()
		s["w2"]["in"].setInput( s["r"]["out"] )
		s["w2"]["fileName"].setValue( self.temporaryDirectory() + "/test2.exr" )
		s["w2"]["preTasks"][0].setInput( s["w1"]["task"] )

		d = GafferDispatch.LocalDispatcher()
		d["jobsDirectory"].setValue( self.temporaryDirectory() + "/jobs" )

		with s.context() :
			d.dispatch( [ s["w2"] ] )

		self.assertTrue( os.path.isfile( s["w1"]["fileName"].getValue() ) )
		self.assertTrue( os.path.isfile( s["w2"]["fileName"].getValue() ) )
示例#6
0
    def testDisabling(self):

        c1 = GafferImage.Catalogue()
        c1["images"].addChild(
            GafferImage.Catalogue.Image.load(
                "${GAFFER_ROOT}/python/GafferImageTest/images/checker.exr"))

        c2 = GafferImage.Catalogue()
        c2["images"].addChild(
            GafferImage.Catalogue.Image.load(
                "${GAFFER_ROOT}/python/GafferImageTest/images/checker.exr"))

        self.assertImagesEqual(c1["out"], c2["out"])

        c2["enabled"].setValue(False)
        self.assertNotEqual(c2["out"]["format"].getValue(),
                            c1["out"]["format"].getValue())
        self.assertNotEqual(c2["out"]["dataWindow"].getValue(),
                            c1["out"]["dataWindow"].getValue())
        self.assertEqual(c2["out"]["dataWindow"].getValue(), IECore.Box2i())

        disabledConstant = GafferImage.Constant()
        disabledConstant["enabled"].setValue(False)
        self.assertImagesEqual(c2["out"], disabledConstant["out"])
示例#7
0
	def testOffsetDisplayWindowWrite( self ) :

		c = GafferImage.Constant()
		format = GafferImage.Format( IECore.Box2i( IECore.V2i( -20, -15 ), IECore.V2i( 29, 14 ) ), 1. )
		c["format"].setValue( format )

		testFile = self.__testFile( "offsetDisplayWindow", "RGBA", "exr" )
		w = GafferImage.ImageWriter()
		w["in"].setInput( c["out"] )
		w["fileName"].setValue( testFile )

		w["task"].execute()

		self.failUnless( os.path.exists( testFile ) )
		i = IECore.Reader.create( testFile ).read()

		# Cortex uses the EXR convention, which differs
		# from Gaffer's, so we use the conversion methods to
		# check that the image windows are as expected.

		self.assertEqual(
			format.toEXRSpace( format.getDisplayWindow() ),
			i.displayWindow
		)
示例#8
0
    def testDefaultFormatFromScript(self):

        s = Gaffer.ScriptNode()
        self.assertFalse("defaultFormat" in s)

        s["c"] = GafferImage.Constant()
        self.assertFalse("defaultFormat" in s)

        defaultFormatPlug = GafferImage.FormatPlug.acquireDefaultFormatPlug(s)
        self.assertTrue(defaultFormatPlug.isSame(s["defaultFormat"]))

        with s.context():

            self.assertFalse(
                GafferImage.BufferAlgo.empty(
                    s["c"]["out"]["format"].getValue().getDisplayWindow()))

            f = GafferImage.Format(100, 200, 2)
            defaultFormatPlug.setValue(f)
            self.assertEqual(s["c"]["out"]["format"].getValue(), f)

            f = GafferImage.Format(200, 400, 1)
            defaultFormatPlug.setValue(f)
            self.assertEqual(s["c"]["out"]["format"].getValue(), f)
示例#9
0
    def testDefaultFormatFromContext(self):

        constant = GafferImage.Constant()

        with Gaffer.Context() as context:

            # Even if we haven't specified a default context, we should still
            # be given something.
            self.assertFalse(
                GafferImage.BufferAlgo.empty(
                    constant["out"]["format"].getValue().getDisplayWindow()))

            # And if we specify something specific, we should get it.
            f = GafferImage.Format(100, 200, 2)
            GafferImage.FormatPlug.setDefaultFormat(context, f)
            self.assertEqual(GafferImage.FormatPlug.getDefaultFormat(context),
                             f)
            self.assertEqual(constant["out"]["format"].getValue(), f)

            f = GafferImage.Format(200, 400, 1)
            GafferImage.FormatPlug.setDefaultFormat(context, f)
            self.assertEqual(GafferImage.FormatPlug.getDefaultFormat(context),
                             f)
            self.assertEqual(constant["out"]["format"].getValue(), f)
示例#10
0
    def testHashIncludesBlackPixels(self):

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

        crop = GafferImage.Crop()
        crop["in"].setInput(constant["out"])
        crop["areaSource"].setValue(crop.AreaSource.Area)
        crop["area"].setValue(imath.Box2i(imath.V2i(0), imath.V2i(200)))
        crop["affectDisplayWindow"].setValue(False)
        crop["affectDataWindow"].setValue(False)

        # Samples the whole data window
        sampler1 = GafferImage.Sampler(
            crop["out"],
            "R",
            imath.Box2i(imath.V2i(0), imath.V2i(200)),
            boundingMode=GafferImage.Sampler.BoundingMode.Black)
        # Samples the whole data window and then some.
        sampler2 = GafferImage.Sampler(
            crop["out"],
            "R",
            imath.Box2i(imath.V2i(0), imath.V2i(210)),
            boundingMode=GafferImage.Sampler.BoundingMode.Black)
        # Samples the whole data window and then some and then some more.
        sampler3 = GafferImage.Sampler(
            crop["out"],
            "R",
            imath.Box2i(imath.V2i(0), imath.V2i(220)),
            boundingMode=GafferImage.Sampler.BoundingMode.Black)

        # The hashes must take account of the additional pixels being sampled.
        self.assertNotEqual(sampler1.hash(), sampler2.hash())
        self.assertNotEqual(sampler2.hash(), sampler3.hash())
        self.assertNotEqual(sampler3.hash(), sampler1.hash())
示例#11
0
    def testChannelPassThrough(self):

        # we should get a perfect pass-through without cache duplication when
        # all the colour plugs are at their defaults and clamping is disabled

        s = Gaffer.ScriptNode()
        s["c"] = GafferImage.Constant()
        s["g"] = GafferImage.Grade()
        s["g"]["blackClamp"].setValue(False)
        s["g"]["in"].setInput(s["c"]["out"])

        for channelName in ("R", "G", "B", "A"):
            self.assertEqual(
                s["g"]["out"].channelDataHash(channelName, imath.V2i(0)),
                s["c"]["out"].channelDataHash(channelName, imath.V2i(0)),
            )

            c = Gaffer.Context(s.context())
            c["image:channelName"] = channelName
            c["image:tileOrigin"] = imath.V2i(0)
            with c:
                self.assertTrue(
                    s["g"]["out"]["channelData"].getValue(_copy=False).isSame(
                        s["c"]["out"]["channelData"].getValue(_copy=False)))
示例#12
0
    def testEnergyPreservation(self):

        constant = GafferImage.Constant()
        constant["color"].setValue(IECore.Color4f(1))

        crop = GafferImage.Crop()
        crop["in"].setInput(constant["out"])
        crop["area"].setValue(IECore.Box2i(IECore.V2i(10), IECore.V2i(11)))
        crop["affectDisplayWindow"].setValue(False)

        blur = GafferImage.Blur()
        blur["in"].setInput(crop["out"])
        blur["expandDataWindow"].setValue(True)

        stats = GafferImage.ImageStats()
        stats["in"].setInput(blur["out"])
        stats["area"].setValue(IECore.Box2i(IECore.V2i(5), IECore.V2i(15)))

        for i in range(0, 10):

            blur["radius"].setValue(IECore.V2f(i * 0.5))
            self.assertAlmostEqual(stats["average"]["r"].getValue(),
                                   1 / 100.,
                                   delta=0.0001)
示例#13
0
    def testSourceScene(self):

        b = Gaffer.Box()
        b2 = Gaffer.Box()
        p = GafferScene.Plane()
        b["Box2"] = b2
        b2["Plane"] = p

        expectedPath = "Box.Box2.Plane.out"
        self.assertEqual(p["out"].fullName(), expectedPath)

        # Make a test image, we don't have a renderer to use to invoke the real output
        # mechanism so we'll mock the result here.

        c = GafferImage.Constant()
        m = GafferImage.ImageMetadata()
        o = GafferImage.ImageWriter()
        m["in"].setInput(c["out"])
        o["in"].setInput(m["out"])

        pathWithoutMeta = os.path.join(self.temporaryDirectory(),
                                       "sceneAlgoSourceSceneWithoutMeta.exr")
        o["fileName"].setValue(pathWithoutMeta)
        o.execute()

        pathWithMeta = os.path.join(self.temporaryDirectory(),
                                    "sceneAlgoSourceSceneWithMeta.exr")
        m["metadata"].addChild(
            Gaffer.NameValuePlug("gaffer:sourceScene",
                                 IECore.StringData(expectedPath), True,
                                 "sourceScene"))
        o["fileName"].setValue(pathWithMeta)
        o.execute()

        inm = GafferImage.ImageReader()
        im = GafferImage.ImageReader()
        inm["fileName"].setValue(pathWithoutMeta)
        im["fileName"].setValue(pathWithMeta)
        self.assertTrue(
            "gaffer:sourceScene" not in inm["out"].metadata().keys())
        self.assertTrue("gaffer:sourceScene" in im["out"].metadata().keys())

        # Test path retrieval
        self.assertEqual(GafferScene.SceneAlgo.sourceSceneName(inm["out"]), "")
        self.assertEqual(GafferScene.SceneAlgo.sourceSceneName(im["out"]),
                         expectedPath)

        # Check plug retrieval without a script node
        self.assertIsNone(GafferScene.SceneAlgo.sourceScene(inm["out"]))
        self.assertIsNone(GafferScene.SceneAlgo.sourceScene(im["out"]))

        # Add to a script

        s = Gaffer.ScriptNode()
        s["Box"] = b
        s["ImageNoMeta"] = inm
        s["ImageMeta"] = im

        self.assertIsNone(GafferScene.SceneAlgo.sourceScene(inm["out"]))
        self.assertTrue(p["out"].isSame(
            GafferScene.SceneAlgo.sourceScene(im["out"])))

        # Remove target plug

        del s["Box"]["Box2"]

        self.assertIsNone(GafferScene.SceneAlgo.sourceScene(inm["out"]))
        self.assertIsNone(GafferScene.SceneAlgo.sourceScene(im["out"]))
示例#14
0
	def test( self ) :

		getRed = GafferOSL.OSLShader()
		getRed.loadShader( "ImageProcessing/InChannel" )
		getRed["parameters"]["channelName"].setValue( "R" )

		getGreen = GafferOSL.OSLShader()
		getGreen.loadShader( "ImageProcessing/InChannel" )
		getGreen["parameters"]["channelName"].setValue( "G" )

		getBlue = GafferOSL.OSLShader()
		getBlue.loadShader( "ImageProcessing/InChannel" )
		getBlue["parameters"]["channelName"].setValue( "B" )

		floatToColor = GafferOSL.OSLShader()
		floatToColor.loadShader( "Conversion/FloatToColor" )
		floatToColor["parameters"]["r"].setInput( getBlue["out"]["channelValue"] )
		floatToColor["parameters"]["g"].setInput( getGreen["out"]["channelValue"] )
		floatToColor["parameters"]["b"].setInput( getRed["out"]["channelValue"] )

		outRGB = GafferOSL.OSLShader()
		outRGB.loadShader( "ImageProcessing/OutLayer" )
		outRGB["parameters"]["layerColor"].setInput( floatToColor["out"]["c"] )

		imageShader = GafferOSL.OSLShader()
		imageShader.loadShader( "ImageProcessing/OutImage" )
		imageShader["parameters"]["in0"].setInput( outRGB["out"]["layer"] )

		reader = GafferImage.ImageReader()
		reader["fileName"].setValue( os.path.expandvars( "$GAFFER_ROOT/python/GafferImageTest/images/rgb.100x100.exr" ) )

		image = GafferOSL.OSLImage()
		image["in"].setInput( reader["out"] )

		# we haven't connected the shader yet, so the node should act as a pass through

		self.assertEqual( image["out"].image(), reader["out"].image() )

		# that should all change when we hook up a shader

		image["channels"].addChild( Gaffer.NameValuePlug( "", GafferOSL.ClosurePlug(), "testClosure" ) )
		cs = GafferTest.CapturingSlot( image.plugDirtiedSignal() )

		def checkDirtiness( expected):
			self.assertEqual( [ i[0].fullName() for i in cs ], [ "OSLImage." + i for i in expected ] )
			del cs[:]

		image["channels"]["testClosure"]["value"].setInput( imageShader["out"]["out"] )

		checkDirtiness( [
				"channels.testClosure.value", "channels.testClosure", "channels", "__shader", "__shading",
				"out.channelNames", "out.channelData", "out"
		] )

		inputImage = reader["out"].image()
		outputImage = image["out"].image()

		self.assertNotEqual( inputImage, outputImage )
		self.assertEqual( outputImage["R"], inputImage["B"] )
		self.assertEqual( outputImage["G"], inputImage["G"] )
		self.assertEqual( outputImage["B"], inputImage["R"] )

		# changes in the shader network should signal more dirtiness

		getGreen["parameters"]["channelName"].setValue( "R" )
		checkDirtiness( [
				"channels.testClosure.value", "channels.testClosure", "channels", "__shader", "__shading",
				"out.channelNames", "out.channelData", "out"
		] )

		floatToColor["parameters"]["r"].setInput( getRed["out"]["channelValue"] )
		checkDirtiness( [
				"channels.testClosure.value", "channels.testClosure", "channels", "__shader", "__shading",
				"out.channelNames", "out.channelData", "out"
		] )

		inputImage = reader["out"].image()
		outputImage = image["out"].image()

		self.assertEqual( outputImage["R"], inputImage["R"] )
		self.assertEqual( outputImage["G"], inputImage["R"] )
		self.assertEqual( outputImage["B"], inputImage["R"] )

		image["in"].setInput( None )
		checkDirtiness( [
				'in.format', 'in.dataWindow', 'in.metadata', 'in.channelNames', 'in.channelData', 'in',
				'__shading',
				'out.channelNames', 'out.channelData', 'out.format', 'out.dataWindow', 'out.metadata', 'out'
		] )

		image["defaultFormat"]["displayWindow"]["max"]["x"].setValue( 200 )
		checkDirtiness( [
				'defaultFormat.displayWindow.max.x', 'defaultFormat.displayWindow.max', 'defaultFormat.displayWindow', 'defaultFormat',
				'__defaultIn.format', '__defaultIn.dataWindow', '__defaultIn', '__shading',
				'out.channelNames', 'out.channelData', 'out.format', 'out.dataWindow', 'out'
		] )

		constant = GafferImage.Constant()
		image["in"].setInput( constant["out"] )

		checkDirtiness( [
				'in.format', 'in.dataWindow', 'in.metadata', 'in.channelNames', 'in.channelData', 'in',
				'__shading',
				'out.channelNames', 'out.channelData', 'out.format', 'out.dataWindow', 'out.metadata', 'out'
		] )
示例#15
0
    def test(self):
        for useClosure in [False, True]:

            getRed = GafferOSL.OSLShader()
            getRed.loadShader("ImageProcessing/InChannel")
            getRed["parameters"]["channelName"].setValue("R")

            getGreen = GafferOSL.OSLShader()
            getGreen.loadShader("ImageProcessing/InChannel")
            getGreen["parameters"]["channelName"].setValue("G")

            getBlue = GafferOSL.OSLShader()
            getBlue.loadShader("ImageProcessing/InChannel")
            getBlue["parameters"]["channelName"].setValue("B")

            floatToColor = GafferOSL.OSLShader()
            floatToColor.loadShader("Conversion/FloatToColor")
            floatToColor["parameters"]["r"].setInput(
                getBlue["out"]["channelValue"])
            floatToColor["parameters"]["g"].setInput(
                getGreen["out"]["channelValue"])
            floatToColor["parameters"]["b"].setInput(
                getRed["out"]["channelValue"])

            reader = GafferImage.ImageReader()
            reader["fileName"].setValue(
                os.path.expandvars(
                    "$GAFFER_ROOT/python/GafferImageTest/images/rgb.100x100.exr"
                ))

            shuffle = GafferImage.Shuffle()
            shuffle["in"].setInput(reader["out"])
            shuffle["channels"].addChild(
                GafferImage.Shuffle.ChannelPlug("channel"))
            shuffle["channels"]["channel"]["out"].setValue('unchangedR')
            shuffle["channels"]["channel"]["in"].setValue('R')

            image = GafferOSL.OSLImage()
            image["in"].setInput(shuffle["out"])

            # we haven't connected the shader yet, so the node should act as a pass through

            self.assertEqual(GafferImage.ImageAlgo.image(image["out"]),
                             GafferImage.ImageAlgo.image(shuffle["out"]))

            # that should all change when we hook up a shader

            if useClosure:

                outRGB = GafferOSL.OSLShader()
                outRGB.loadShader("ImageProcessing/OutLayer")
                outRGB["parameters"]["layerColor"].setInput(
                    floatToColor["out"]["c"])

                imageShader = GafferOSL.OSLShader()
                imageShader.loadShader("ImageProcessing/OutImage")
                imageShader["parameters"]["in0"].setInput(
                    outRGB["out"]["layer"])

                image["channels"].addChild(
                    Gaffer.NameValuePlug("", GafferOSL.ClosurePlug(),
                                         "testClosure"))

            else:

                image["channels"].addChild(
                    Gaffer.NameValuePlug("", imath.Color3f(), "testColor"))

            cs = GafferTest.CapturingSlot(image.plugDirtiedSignal())

            def checkDirtiness(expected):
                self.assertEqual([i[0].fullName() for i in cs],
                                 ["OSLImage." + i for i in expected])
                del cs[:]

            if useClosure:
                image["channels"]["testClosure"]["value"].setInput(
                    imageShader["out"]["out"])
                channelsDirtied = [
                    "channels.testClosure.value", "channels.testClosure"
                ]
            else:
                image["channels"]["testColor"]["value"].setInput(
                    floatToColor["out"]["c"])
                channelsDirtied = [
                    "channels.testColor.value.r", "channels.testColor.value.g",
                    "channels.testColor.value.b", "channels.testColor.value",
                    "channels.testColor"
                ]

            checkDirtiness(channelsDirtied + [
                "channels", "__shader", "__shading", "__affectedChannels",
                "out.channelNames", "out.channelData", "out"
            ])

            inputImage = GafferImage.ImageAlgo.image(shuffle["out"])

            with Gaffer.ContextMonitor(image["__shading"]) as monitor:
                self.assertEqual(
                    image["out"].channelNames(),
                    IECore.StringVectorData(["A", "B", "G", "R",
                                             "unchangedR"]))
                # Evaluating channel names only requires evaluating the shading plug if we have a closure
                self.assertEqual(
                    monitor.combinedStatistics().numUniqueContexts(),
                    1 if useClosure else 0)

                # Channels we don't touch should be passed through unaltered
                for channel, changed in [('B', True), ('G', True), ('R', True),
                                         ('A', False), ('unchangedR', False)]:
                    self.assertEqual(
                        image["out"].channelDataHash(channel, imath.V2i(
                            0, 0)) == shuffle["out"].channelDataHash(
                                channel, imath.V2i(0, 0)), not changed)
                    image["out"].channelData(channel, imath.V2i(0, 0))

            # Should only need one shading evaluate for all channels
            self.assertEqual(monitor.combinedStatistics().numUniqueContexts(),
                             1)

            outputImage = GafferImage.ImageAlgo.image(image["out"])

            self.assertNotEqual(inputImage, outputImage)
            self.assertEqual(outputImage["R"], inputImage["B"])
            self.assertEqual(outputImage["G"], inputImage["G"])
            self.assertEqual(outputImage["B"], inputImage["R"])

            # changes in the shader network should signal more dirtiness

            getGreen["parameters"]["channelName"].setValue("R")
            checkDirtiness(channelsDirtied + [
                "channels", "__shader", "__shading", "__affectedChannels",
                "out.channelNames", "out.channelData", "out"
            ])

            floatToColor["parameters"]["r"].setInput(
                getRed["out"]["channelValue"])
            checkDirtiness(channelsDirtied + [
                "channels", "__shader", "__shading", "__affectedChannels",
                "out.channelNames", "out.channelData", "out"
            ])

            inputImage = GafferImage.ImageAlgo.image(shuffle["out"])
            outputImage = GafferImage.ImageAlgo.image(image["out"])

            self.assertEqual(outputImage["R"], inputImage["R"])
            self.assertEqual(outputImage["G"], inputImage["R"])
            self.assertEqual(outputImage["B"], inputImage["R"])
            self.assertEqual(outputImage["A"], inputImage["A"])
            self.assertEqual(outputImage["unchangedR"],
                             inputImage["unchangedR"])

            image["in"].setInput(None)
            checkDirtiness([
                'in.format', 'in.dataWindow', 'in.metadata', 'in.deep',
                'in.sampleOffsets', 'in.channelNames', 'in.channelData', 'in',
                '__shading', '__affectedChannels', 'out.channelNames',
                'out.channelData', 'out.format', 'out.dataWindow',
                'out.metadata', 'out.deep', 'out.sampleOffsets', 'out'
            ])

            image["defaultFormat"]["displayWindow"]["max"]["x"].setValue(200)
            checkDirtiness([
                'defaultFormat.displayWindow.max.x',
                'defaultFormat.displayWindow.max',
                'defaultFormat.displayWindow', 'defaultFormat',
                '__defaultIn.format', '__defaultIn.dataWindow', '__defaultIn',
                '__shading', '__affectedChannels', 'out.channelNames',
                'out.channelData', 'out.format', 'out.dataWindow', 'out'
            ])

            constant = GafferImage.Constant()
            image["in"].setInput(constant["out"])

            checkDirtiness([
                'in.format', 'in.dataWindow', 'in.metadata', 'in.deep',
                'in.sampleOffsets', 'in.channelNames', 'in.channelData', 'in',
                '__shading', '__affectedChannels', 'out.channelNames',
                'out.channelData', 'out.format', 'out.dataWindow',
                'out.metadata', 'out.deep', 'out.sampleOffsets', 'out'
            ])

            image["in"].setInput(shuffle["out"])
            if useClosure:
                outRGB["parameters"]["layerName"].setValue("newLayer")
            else:
                image["channels"][0]["name"].setValue("newLayer")

            self.assertEqual(
                image["out"].channelNames(),
                IECore.StringVectorData([
                    "A", "B", "G", "R", "newLayer.B", "newLayer.G",
                    "newLayer.R", "unchangedR"
                ]))

            for channel in ['B', 'G', 'R', 'A', 'unchangedR']:
                self.assertEqual(
                    image["out"].channelDataHash(channel, imath.V2i(0, 0)),
                    shuffle["out"].channelDataHash(channel, imath.V2i(0, 0)))
                self.assertEqual(
                    image["out"].channelData(channel, imath.V2i(0, 0)),
                    shuffle["out"].channelData(channel, imath.V2i(0, 0)))

            crop = GafferImage.Crop()
            crop["area"].setValue(imath.Box2i(imath.V2i(0, 0), imath.V2i(0,
                                                                         0)))
            crop["in"].setInput(shuffle["out"])

            image["in"].setInput(crop["out"])

            if useClosure:
                # When using closures, we can't find out about the new channels being added if the datawindow is
                # empty
                self.assertEqual(
                    image["out"].channelNames(),
                    IECore.StringVectorData(["A", "B", "G", "R",
                                             "unchangedR"]))
            else:
                self.assertEqual(
                    image["out"].channelNames(),
                    IECore.StringVectorData([
                        "A", "B", "G", "R", "newLayer.B", "newLayer.G",
                        "newLayer.R", "unchangedR"
                    ]))
示例#16
0
    def testWarpImage(self):
        def __warpImage(size, distortion, idistortStyle):
            w = IECore.Box2i(IECore.V2i(0), size - IECore.V2i(1))
            image = IECore.ImagePrimitive(w, w)

            R = IECore.FloatVectorData(size.x * size.y)
            G = IECore.FloatVectorData(size.x * size.y)

            for iy in range(size.y):
                for ix in range(size.x):
                    x = (ix + 0.5) / size.x
                    y = 1 - (iy + 0.5) / size.y
                    if idistortStyle:
                        R[iy * size.x +
                          ix] = distortion * math.sin(y * 8) * size.x
                        G[iy * size.x +
                          ix] = distortion * math.sin(x * 8) * size.y
                    else:
                        R[iy * size.x + ix] = x + distortion * math.sin(y * 8)
                        G[iy * size.x + ix] = y + distortion * math.sin(x * 8)

            image["R"] = IECore.PrimitiveVariable(
                IECore.PrimitiveVariable.Interpolation.Vertex, R)
            image["G"] = IECore.PrimitiveVariable(
                IECore.PrimitiveVariable.Interpolation.Vertex, G)

            return image

        def __dotGrid(size):
            w = IECore.Box2i(IECore.V2i(0), size - IECore.V2i(1))
            image = IECore.ImagePrimitive(w, w)

            R = IECore.FloatVectorData(size.x * size.y)
            G = IECore.FloatVectorData(size.x * size.y)
            B = IECore.FloatVectorData(size.x * size.y)

            for iy in range(0, size.y):
                for ix in range(0, size.x):
                    q = max(ix % 16, iy % 16)

                    R[iy * size.x + ix] = q < 1
                    G[iy * size.x + ix] = q < 4
                    B[iy * size.x + ix] = q < 8

            image["R"] = IECore.PrimitiveVariable(
                IECore.PrimitiveVariable.Interpolation.Vertex, R)
            image["G"] = IECore.PrimitiveVariable(
                IECore.PrimitiveVariable.Interpolation.Vertex, G)
            image["B"] = IECore.PrimitiveVariable(
                IECore.PrimitiveVariable.Interpolation.Vertex, B)

            return image

        objectToImageSource = GafferImage.ObjectToImage()
        objectToImageSource["object"].setValue(__dotGrid(IECore.V2i(300)))

        # TODO - reorder channels of our source image because ObjectToImage outputs in opposite order to
        # the rest of Gaffer.  This probably should be fixed in ObjectToImage,
        # or we shouldn't depend on channel order to check if images are equal?
        sourceReorderConstant = GafferImage.Constant()
        sourceReorderConstant["format"].setValue(
            GafferImage.Format(300, 300, 1.000))
        sourceReorderDelete = GafferImage.DeleteChannels()
        sourceReorderDelete["channels"].setValue(IECore.StringVectorData(["A"
                                                                          ]))
        sourceReorderDelete["in"].setInput(sourceReorderConstant["out"])
        sourceReorder = GafferImage.CopyChannels()
        sourceReorder["channels"].setValue("R G B")
        sourceReorder["in"]["in0"].setInput(sourceReorderDelete["out"])
        sourceReorder["in"]["in1"].setInput(objectToImageSource["out"])

        objectToImageVector = GafferImage.ObjectToImage()

        vectorWarp = GafferImage.VectorWarp()
        vectorWarp["in"].setInput(sourceReorder["out"])
        vectorWarp["vector"].setInput(objectToImageVector["out"])

        # Test that a warp with no distortion and a box filter reproduces the input
        objectToImageVector["object"].setValue(
            __warpImage(IECore.V2i(300), 0, False))
        vectorWarp["filter"].setValue("box")
        self.assertImagesEqual(vectorWarp["out"],
                               sourceReorder["out"],
                               maxDifference=0.00001)

        # Test that a warp with distortion produces an expected output
        objectToImageVector["object"].setValue(
            __warpImage(IECore.V2i(300), 0.2, False))
        vectorWarp["filter"].setValue("blackman-harris")

        # Enable to write out images for visual comparison
        if False:
            testWriter = GafferImage.ImageWriter()
            testWriter["in"].setInput(vectorWarp["out"])
            testWriter["fileName"].setValue("/tmp/dotGrid.warped.exr")
            testWriter["task"].execute()

        expectedReader = GafferImage.ImageReader()
        expectedReader["fileName"].setValue(
            os.path.dirname(__file__) + "/images/dotGrid.warped.exr")

        # Test that we can get the same result using pixel offsets instead of normalized coordinates
        objectToImageVector["object"].setValue(
            __warpImage(IECore.V2i(300), 0.2, True))
        vectorWarp["vectorMode"].setValue(
            GafferImage.VectorWarp.VectorMode.Relative)
        vectorWarp["vectorUnits"].setValue(
            GafferImage.VectorWarp.VectorUnits.Pixels)

        self.assertImagesEqual(vectorWarp["out"],
                               expectedReader["out"],
                               maxDifference=0.0005,
                               ignoreMetadata=True)
示例#17
0
    def __init__(self, name='BleedFill'):

        GafferImage.ImageProcessor.__init__(self, name)

        self.addChild(Gaffer.BoolPlug("expandDataWindow"))

        self.addChild(Gaffer.IntPlug("__blurIterations"))
        self['__blurIterations'].setFlags(Gaffer.Plug.Flags.Serialisable,
                                          False)

        self["__blurIterationsExpression"] = Gaffer.Expression()
        self["__blurIterationsExpression"].setExpression(
            inspect.cleandoc("""
			import math
			f = parent["in"]["format"]
			parent["__blurIterations"] = int( math.log( min( f.width(), f.height() ), 2 ) )
			"""), "python")

        self["__displayWindowConstant"] = GafferImage.Constant()
        self["__displayWindowConstant"]["color"].setValue(
            imath.Color4f(0, 0, 0, 0))

        self["__displayWindowExpression"] = Gaffer.Expression()
        self["__displayWindowExpression"].setExpression(
            'parent["__displayWindowConstant"]["format"] = parent["in"]["format"]',
            "python")

        self["__expandMerge"] = GafferImage.Merge()
        self["__expandMerge"]["in"][0].setInput(self["in"])
        self["__expandMerge"]["in"][1].setInput(
            self["__displayWindowConstant"]["out"])
        self["__expandMerge"]["operation"].setValue(
            GafferImage.Merge.Operation.Over)

        self["__expandSwitch"] = Gaffer.Switch()
        self["__expandSwitch"].setup(self["in"])
        self["__expandSwitch"]["in"][0].setInput(self["in"])
        self["__expandSwitch"]["in"][1].setInput(self["__expandMerge"]["out"])
        self["__expandSwitch"]["index"].setInput(self["expandDataWindow"])

        # First blur via repeated downsampling
        self["__blurLoop"] = GafferImage.ImageLoop()
        self["__blurLoop"]["iterations"].setInput(self["__blurIterations"])
        self["__blurLoop"]["in"].setInput(self["__expandSwitch"]["out"])

        self["__downsample"] = GafferImage.Resize()
        self["__downsample"]["in"].setInput(self["__blurLoop"]["previous"])
        self["__downsample"]["filter"].setValue("sharp-gaussian")

        self["__downsampleExpression"] = Gaffer.Expression()
        self["__downsampleExpression"].setExpression(
            inspect.cleandoc("""
			import GafferImage
			import IECore

			f = parent["in"]["format"]

			divisor = 2 <<  context.get("loop:index", 0)

			parent["__downsample"]["format"] =  GafferImage.Format( imath.Box2i( f.getDisplayWindow().min() / divisor, f.getDisplayWindow().max() / divisor ), 1.0 )
			"""), "python")

        # Multiply each successive octave by a falloff factor so that we prioritize higher frequencies when they exist
        self["__grade"] = GafferImage.Grade("Grade")
        self["__grade"]['channels'].setValue("*")
        self["__grade"]['multiply'].setValue(imath.Color4f(0.1))
        self["__grade"]["in"].setInput(self["__downsample"]["out"])

        self["__blurLoop"]["next"].setInput(self["__grade"]["out"])

        self["__reverseLoopContext"] = GafferImage.ImageContextVariables()
        self["__reverseLoopContext"]["in"].setInput(
            self["__blurLoop"]["previous"])
        self["__reverseLoopContext"]["variables"].addMember(
            "loop:index", IECore.IntData(0), "loopIndex")

        self["__reverseLoopExpression"] = Gaffer.Expression()
        self["__reverseLoopExpression"].setExpression(
            inspect.cleandoc("""
			parent["__reverseLoopContext"]["variables"]["loopIndex"]["value"] = parent["__blurIterations"] - context.get( "loop:index", 0 )
			"""), "python")

        # Loop through image resolution levels combining the most downsampled image with less downsampled versions,
        # one level at a time
        self["__combineLoop"] = GafferImage.ImageLoop()

        self["__combineLoopExpression"] = Gaffer.Expression()
        self["__combineLoopExpression"].setExpression(
            'parent["__combineLoop"]["iterations"] = parent["__blurIterations"] + 1',
            "python")

        self["__upsample"] = GafferImage.Resize()
        self["__upsample"]["in"].setInput(self["__combineLoop"]["previous"])
        self["__upsample"]["filter"].setValue("smoothGaussian")

        self["__upsampleExpression"] = Gaffer.Expression()
        self["__upsampleExpression"].setExpression(
            inspect.cleandoc("""
			import GafferImage
			import IECore

			f = parent["in"]["format"]

			divisor = 1 <<  (  parent["__blurIterations"] - context.get("loop:index", 0) )

			parent["__upsample"]["format"] =  GafferImage.Format( imath.Box2i( f.getDisplayWindow().min() / divisor, f.getDisplayWindow().max() / divisor ), 1.0 )
			"""), "python")

        self["__merge"] = GafferImage.Merge()
        self["__merge"]["operation"].setValue(GafferImage.Merge.Operation.Over)
        self["__merge"]["in"][0].setInput(self["__upsample"]["out"])
        self["__merge"]["in"][1].setInput(self["__reverseLoopContext"]["out"])

        self["__combineLoop"]["next"].setInput(self["__merge"]["out"])

        # When downsampling to target display window sizes with a non-square image,
        # the data window size gets rounded up to the nearest integer, potentially introducing
        # a small error in data window size that gets amplified during repeated upsampling.
        # To fix this, crop to the data window after scaling.
        self["__restoreDataSize"] = GafferImage.Crop()
        self["__restoreDataSize"]["in"].setInput(self["__combineLoop"]["out"])
        self["__restoreDataSize"]["affectDisplayWindow"].setValue(False)

        self["__restoreDataExpression"] = Gaffer.Expression()
        self["__restoreDataExpression"].setExpression(
            'parent["__restoreDataSize"]["area"] = parent["__expandSwitch"]["out"]["dataWindow"]',
            "python")

        self["__unpremult"] = GafferImage.Unpremultiply()
        self["__unpremult"]['channels'].setValue("*")
        self["__unpremult"]["in"].setInput(self["__restoreDataSize"]["out"])

        self["__resetAlpha"] = GafferImage.Shuffle()
        self["__resetAlpha"]["channels"].addChild(
            GafferImage.Shuffle.ChannelPlug("A", "__white"))
        self["__resetAlpha"]["in"].setInput(self["__unpremult"]["out"])

        self["__disableSwitch"] = Gaffer.Switch()
        self["__disableSwitch"].setup(self["in"])
        self["__disableSwitch"]["in"][0].setInput(self["in"])
        self["__disableSwitch"]["in"][1].setInput(self["__resetAlpha"]["out"])
        self["__disableSwitch"]["index"].setInput(self["enabled"])

        self['out'].setFlags(Gaffer.Plug.Flags.Serialisable, False)
        self["out"].setInput(self["__disableSwitch"]["out"])
示例#18
0
	def testParallelGatherTileOrder( self ) :

		c = GafferImage.Constant()

		tileOrigins = []
		channelTileOrigins = []

		def tileFunctor( *args ) :

			pass

		def gatherFunctor( image, tileOrigin, tile ) :

			tileOrigins.append( tileOrigin )

		def channelGatherFunctor( image, channelName, tileOrigin, tile ) :

			channelTileOrigins.append( tileOrigin )

		for window in [
			# Window not aligned to tile boundaries
			imath.Box2i( imath.V2i( 2 ), GafferImage.ImagePlug.tileSize() * imath.V2i( 20, 8 ) - imath.V2i( 2 ) ),
			# Window aligned to tile boundaries
			imath.Box2i( imath.V2i( 0 ), GafferImage.ImagePlug.tileSize() * imath.V2i( 6, 7 ) ),
			# Negative origin
			imath.Box2i( imath.V2i( -GafferImage.ImagePlug.tileSize() ), GafferImage.ImagePlug.tileSize() * imath.V2i( 4, 6 ) )
		] :

			size = GafferImage.ImagePlug.tileIndex( window.max() - imath.V2i( 1 ) ) - GafferImage.ImagePlug.tileIndex( window.min() ) + imath.V2i( 1 )
			numTiles = size.x * size.y

			for order in GafferImage.ImageAlgo.TileOrder.values.values() :

				del tileOrigins[:]
				del channelTileOrigins[:]

				GafferImage.ImageAlgo.parallelGatherTiles(
					c["out"],
					tileFunctor,
					gatherFunctor,
					window = window,
					tileOrder = order
				)

				GafferImage.ImageAlgo.parallelGatherTiles(
					c["out"],
					[ "R" ],
					tileFunctor,
					channelGatherFunctor,
					window = window,
					tileOrder = order
				)

				self.assertEqual( len( tileOrigins ), numTiles )
				self.assertEqual( len( channelTileOrigins ), numTiles )

				for i in range( 1, len( tileOrigins ) ) :

					if order == GafferImage.ImageAlgo.TileOrder.TopToBottom :
						self.assertGreaterEqual( tileOrigins[i-1].y, tileOrigins[i].y )
					elif order == GafferImage.ImageAlgo.TileOrder.BottomToTop :
						self.assertLessEqual( tileOrigins[i-1].y, tileOrigins[i].y )

					if order != GafferImage.ImageAlgo.TileOrder.Unordered :
						self.assertEqual( channelTileOrigins[i], tileOrigins[i] )
示例#19
0
    def testOverall(self):

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

        shuffle = GafferImage.Shuffle()
        shuffle["in"].setInput(constant["out"])
        shuffle["channels"].addChild(shuffle.ChannelPlug("Z", "R"))
        shuffle["channels"].addChild(shuffle.ChannelPlug("ZBack", "G"))
        shuffle["enabled"].setValue(False)

        addDepth = GafferImage.FlatToDeep()
        addDepth["in"].setInput(shuffle["out"])
        addDepth["enabled"].setValue(False)

        self.assertEqual(addDepth["out"]["channelNames"].getValue(),
                         IECore.StringVectorData(["R", "G", "B", "A"]))

        addDepth["enabled"].setValue(True)
        self.assertEqual(addDepth["out"]["channelNames"].getValue(),
                         IECore.StringVectorData(["R", "G", "B", "A", "Z"]))
        addDepth["zBackMode"].setValue(
            GafferImage.FlatToDeep.ZBackMode.Thickness)
        self.assertEqual(
            addDepth["out"]["channelNames"].getValue(),
            IECore.StringVectorData(["R", "G", "B", "A", "Z", "ZBack"]))

        with Gaffer.Context() as c:
            c["image:tileOrigin"] = imath.V2i(0)

            c["image:channelName"] = "R"
            rHash = constant["out"]["channelData"].hash()

            c["image:channelName"] = "G"
            gHash = constant["out"]["channelData"].hash()

            # TEST Z CHANNEL
            c["image:channelName"] = "Z"

            tilePixels = GafferImage.ImagePlug.tileSize()**2

            initialZHash = addDepth["out"]["channelData"].hash()
            self.assertEqual(addDepth["out"]["channelData"].getValue(),
                             IECore.FloatVectorData([0] * tilePixels))

            addDepth["depth"].setValue(42.0)

            newZHash = addDepth["out"]["channelData"].hash()
            self.assertEqual(addDepth["out"]["channelData"].getValue(),
                             IECore.FloatVectorData([42.0] * tilePixels))
            self.assertNotEqual(initialZHash, newZHash)

            addDepth["zMode"].setValue(GafferImage.FlatToDeep.ZMode.Channel)
            addDepth["zChannel"].setValue("R")
            self.assertEqual(addDepth["out"]["channelData"].hash(), rHash)
            self.assertEqual(addDepth["out"]["channelData"].getValue(),
                             IECore.FloatVectorData([0.1] * tilePixels))

            addDepth["zChannel"].setValue("G")
            self.assertEqual(addDepth["out"]["channelData"].hash(), gHash)
            self.assertEqual(addDepth["out"]["channelData"].getValue(),
                             IECore.FloatVectorData([0.2] * tilePixels))

            addDepth["zChannel"].setValue("Q")
            six.assertRaisesRegex(
                self, RuntimeError,
                'FlatToDeep : Cannot find requested Z channel - no channel "Q" found.',
                addDepth["out"]["channelData"].hash)
            six.assertRaisesRegex(
                self, RuntimeError,
                'FlatToDeep : Cannot find requested Z channel - no channel "Q" found.',
                addDepth["out"]["channelData"].getValue)

            addDepth["zChannel"].setValue("Z")
            shuffle["enabled"].setValue(True)
            self.assertEqual(shuffle["out"]["channelData"].hash(),
                             addDepth["out"]["channelData"].hash())
            self.assertEqual(addDepth["out"]["channelData"].getValue(),
                             IECore.FloatVectorData([0.1] * tilePixels))

            addDepth["zMode"].setValue(GafferImage.FlatToDeep.ZMode.Constant)
            addDepth["depth"].setValue(0.0)
            shuffle["enabled"].setValue(False)

            # TEST ZBack CHANNEL
            c["image:channelName"] = "ZBack"

            initialZBackHash = addDepth["out"]["channelData"].hash()
            self.assertEqual(addDepth["out"]["channelData"].getValue(),
                             IECore.FloatVectorData([0] * tilePixels))

            addDepth["depth"].setValue(42.0)

            newZBackHash = addDepth["out"]["channelData"].hash()
            self.assertEqual(addDepth["out"]["channelData"].getValue(),
                             IECore.FloatVectorData([42.0] * tilePixels))
            self.assertNotEqual(initialZBackHash, newZBackHash)

            addDepth["thickness"].setValue(0.09)

            newerZBackHash = addDepth["out"]["channelData"].hash()
            self.assertEqual(addDepth["out"]["channelData"].getValue(),
                             IECore.FloatVectorData([42.09] * tilePixels))
            self.assertNotEqual(newZBackHash, newerZBackHash)

            addDepth["zBackMode"].setValue(
                GafferImage.FlatToDeep.ZBackMode.Channel)
            addDepth["zBackChannel"].setValue("R")
            self.assertEqual(addDepth["out"]["channelData"].hash(), rHash)
            self.assertEqual(addDepth["out"]["channelData"].getValue(),
                             IECore.FloatVectorData([0.1] * tilePixels))

            addDepth["zBackChannel"].setValue("G")
            self.assertEqual(addDepth["out"]["channelData"].hash(), gHash)
            self.assertEqual(addDepth["out"]["channelData"].getValue(),
                             IECore.FloatVectorData([0.2] * tilePixels))

            addDepth["zBackChannel"].setValue("Q")
            six.assertRaisesRegex(
                self, RuntimeError,
                'FlatToDeep : Cannot find requested ZBack channel - no channel "Q" found.',
                addDepth["out"]["channelData"].hash)
            six.assertRaisesRegex(
                self, RuntimeError,
                'FlatToDeep : Cannot find requested ZBack channel - no channel "Q" found.',
                addDepth["out"]["channelData"].getValue)

            addDepth["zBackChannel"].setValue("ZBack")
            shuffle["enabled"].setValue(True)
            self.assertEqual(shuffle["out"]["channelData"].hash(),
                             addDepth["out"]["channelData"].hash())
            self.assertEqual(addDepth["out"]["channelData"].getValue(),
                             IECore.FloatVectorData([0.2] * tilePixels))

            addDepth["zBackMode"].setValue(
                GafferImage.FlatToDeep.ZBackMode.Thickness)

            self.assertEqual(newerZBackHash,
                             addDepth["out"]["channelData"].hash())
            self.assertEqual(addDepth["out"]["channelData"].getValue(),
                             IECore.FloatVectorData([42.09] * tilePixels))

            addDepth["zMode"].setValue(GafferImage.FlatToDeep.ZMode.Channel)
            addDepth["zChannel"].setValue("Z")
            self.assertNotEqual(newerZBackHash,
                                addDepth["out"]["channelData"].hash())
            self.assertEqual(addDepth["out"]["channelData"].getValue(),
                             IECore.FloatVectorData([0.19] * tilePixels))
示例#20
0
    def testLayerMapping(self):

        constant1 = GafferImage.Constant()
        constant1['color'].setValue(IECore.Color4f(0.1, 0.2, 0.3, 0.4))
        constant1["format"].setValue(GafferImage.Format(10, 10, 1.000))

        metadata1 = GafferImage.ImageMetadata()
        metadata1["in"].setInput(constant1["out"])
        metadata1["metadata"].addMember("test", 1)

        constant2 = GafferImage.Constant()
        constant2['color'].setValue(IECore.Color4f(0.2, 0.4, 0.6, 0.8))
        constant2["format"].setValue(GafferImage.Format(20, 20, 1.000))

        metadata2 = GafferImage.ImageMetadata()
        metadata2["in"].setInput(constant2["out"])
        metadata2["metadata"].addMember("test", 2)

        switch = GafferImage.ImageSwitch()
        switch["in"][0].setInput(metadata1["out"])
        switch["in"][1].setInput(metadata2["out"])

        e = Gaffer.Expression()
        switch.addChild(e)
        e.setExpression(
            'parent["index"] = context["collect:layerName"] != "A"', "python")

        collect = GafferImage.CollectImages()
        collect["in"].setInput(switch["out"])

        # Metadata and format are driven by the first layer

        collect["rootLayers"].setValue(IECore.StringVectorData(['A', 'B']))
        self.assertEqual(collect["out"]["format"].getValue(),
                         GafferImage.Format(10, 10, 1))
        self.assertEqual(collect["out"]["metadata"].getValue(),
                         IECore.CompoundData({"test": 1}))

        collect["rootLayers"].setValue(IECore.StringVectorData(['B', 'A']))
        self.assertEqual(collect["out"]["format"].getValue(),
                         GafferImage.Format(20, 20, 1))
        self.assertEqual(collect["out"]["metadata"].getValue(),
                         IECore.CompoundData({"test": 2}))

        collect["rootLayers"].setValue(IECore.StringVectorData([]))
        self.assertEqual(
            collect["out"]["format"].getValue(),
            constant1["format"].getDefaultFormat(Gaffer.Context.current()))
        self.assertEqual(collect["out"]["metadata"].getValue(),
                         IECore.CompoundData())

        sampler = GafferImage.ImageSampler("ImageSampler")
        sampler["pixel"].setValue(IECore.V2f(1, 1))
        sampler["channels"].setValue(
            IECore.StringVectorData(["A.R", "A.G", "A.B", "A.A"]))
        sampler["image"].setInput(collect["out"])

        collect["rootLayers"].setValue(IECore.StringVectorData(['A']))

        self.assertEqual(list(collect["out"]["channelNames"].getValue()),
                         ["A.R", "A.G", "A.B", "A.A"])
        self.assertEqual(sampler["color"].getValue(),
                         IECore.Color4f(0.1, 0.2, 0.3, 0.4))

        # Test simple duplicate
        collect["rootLayers"].setValue(IECore.StringVectorData(['A', 'A']))

        self.assertEqual(list(collect["out"]["channelNames"].getValue()),
                         ["A.R", "A.G", "A.B", "A.A"])
        self.assertEqual(sampler["color"].getValue(),
                         IECore.Color4f(0.1, 0.2, 0.3, 0.4))

        collect["rootLayers"].setValue(IECore.StringVectorData(['A', 'B']))
        self.assertEqual(
            list(collect["out"]["channelNames"].getValue()),
            ["A.R", "A.G", "A.B", "A.A", "B.R", "B.G", "B.B", "B.A"])
        self.assertEqual(sampler["color"].getValue(),
                         IECore.Color4f(0.1, 0.2, 0.3, 0.4))
        sampler["channels"].setValue(
            IECore.StringVectorData(["B.R", "B.G", "B.B", "B.A"]))
        self.assertEqual(sampler["color"].getValue(),
                         IECore.Color4f(0.2, 0.4, 0.6, 0.8))

        # Test overlapping names take the first layer
        constant1["layer"].setValue("B")
        collect["rootLayers"].setValue(IECore.StringVectorData(['A', 'A.B']))
        sampler["channels"].setValue(
            IECore.StringVectorData(["A.B.R", "A.B.G", "A.B.B", "A.B.A"]))
        self.assertEqual(list(collect["out"]["channelNames"].getValue()),
                         ["A.B.R", "A.B.G", "A.B.B", "A.B.A"])
        self.assertEqual(sampler["color"].getValue(),
                         IECore.Color4f(0.1, 0.2, 0.3, 0.4))
        collect["rootLayers"].setValue(IECore.StringVectorData(['A.B', 'A']))
        self.assertEqual(list(collect["out"]["channelNames"].getValue()),
                         ["A.B.R", "A.B.G", "A.B.B", "A.B.A"])
        self.assertEqual(sampler["color"].getValue(),
                         IECore.Color4f(0.2, 0.4, 0.6, 0.8))
示例#21
0
    def testRenamePromotedImages(self):

        # Create boxed Catalogue with promoted `images` plug.

        box = Gaffer.Box()

        box["catalogue"] = GafferImage.Catalogue()
        box["catalogue"]["directory"].setValue(
            os.path.join(self.temporaryDirectory(), "catalogue"))

        images = Gaffer.PlugAlgo.promote(box["catalogue"]["images"])

        # Send 2 images and name them using the promoted plugs.

        red = GafferImage.Constant()
        red["format"].setValue(GafferImage.Format(64, 64))
        red["color"]["r"].setValue(1)
        self.sendImage(red["out"], box["catalogue"])
        images[-1].setName("Red")

        green = GafferImage.Constant()
        green["format"].setValue(GafferImage.Format(64, 64))
        green["color"]["g"].setValue(1)
        self.sendImage(green["out"], box["catalogue"])
        images[-1].setName("Green")

        # Assert that images are accessible under those names.

        with Gaffer.Context() as c:
            c["catalogue:imageName"] = "Red"
            self.assertImagesEqual(box["catalogue"]["out"],
                                   red["out"],
                                   ignoreMetadata=True)
            c["catalogue:imageName"] = "Green"
            self.assertImagesEqual(box["catalogue"]["out"],
                                   green["out"],
                                   ignoreMetadata=True)

        # And that invalid names generate errors.

        with six.assertRaisesRegex(self, RuntimeError,
                                   'Unknown image name "Blue"'):
            with Gaffer.Context() as c:
                c["catalogue:imageName"] = "Blue"
                box["catalogue"]["out"].metadata()

        # Assert that we can rename the images and get them under the new name.

        images[0].setName("Crimson")
        images[1].setName("Emerald")

        with Gaffer.Context() as c:
            c["catalogue:imageName"] = "Crimson"
            self.assertImagesEqual(box["catalogue"]["out"],
                                   red["out"],
                                   ignoreMetadata=True)
            c["catalogue:imageName"] = "Emerald"
            self.assertImagesEqual(box["catalogue"]["out"],
                                   green["out"],
                                   ignoreMetadata=True)

        # And that the old names are now invalid.

        with six.assertRaisesRegex(self, RuntimeError,
                                   'Unknown image name "Red"'):
            with Gaffer.Context() as c:
                c["catalogue:imageName"] = "Red"
                box["catalogue"]["out"].metadata()
示例#22
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()
示例#23
0
	def testFilterDerivatives( self ):
		# Size of one grid cell
		subSize = 35

		# Each grid cell gets a dot in the middle
		redDot = GafferImage.Constant()
		redDot["format"].setValue( GafferImage.Format( 1, 1, 1.000 ) )
		redDot["color"].setValue( IECore.Color4f( 10, 0, 0, 1 ) )
		redDotCentered = GafferImage.Crop( "Crop" )
		redDotCentered["in"].setInput( redDot["out"] )
		redDotCentered["area"].setValue( IECore.Box2i( IECore.V2i( -(subSize-1)/2 ), IECore.V2i( (subSize-1)/2 + 1 ) ) )

		borderForFilterWidth = 40
		sampleRegion = redDotCentered["out"]["dataWindow"].getValue()
		sampleRegion.min -= IECore.V2i( borderForFilterWidth )
		sampleRegion.max += IECore.V2i( borderForFilterWidth )

		s = GafferImage.Sampler( redDotCentered["out"], "R", sampleRegion, GafferImage.Sampler.BoundingMode.Black )
	
		filters = GafferImage.FilterAlgo.filterNames()
		dirs = [
			(IECore.V2f(1,0), IECore.V2f(0,1)),
			(IECore.V2f(5,0), IECore.V2f(0,1)),
			(IECore.V2f(1,0), IECore.V2f(0,5)),
			(IECore.V2f(5,0), IECore.V2f(0,5)) ]

		for angle in range( 0, 91, 15 ):
			sa = math.sin( angle / 180.0 * math.pi )
			ca = math.cos( angle / 180.0 * math.pi )
			dirs.append( ( IECore.V2f(ca * 5, sa * 5 ), IECore.V2f(-sa * 3, ca * 3 ) ) )

		size = subSize * IECore.V2i( len( dirs ), len( filters ) )
		w = IECore.Box2i( IECore.V2i( 0 ), size - IECore.V2i( 1 ) )
		parallelogramImage = IECore.ImagePrimitive( w, w )
		boxImage = IECore.ImagePrimitive( w, w )

		parallelogramR = IECore.FloatVectorData( size[0] * size[1] )
		boxR = IECore.FloatVectorData( size[0] * size[1] )
		
		for x_sub, d in enumerate( dirs ):
			for y_sub, f in enumerate( filters ):
				for y in range( subSize ):
					for x in range( subSize ):
						p = IECore.V2f( x + 0.5, y + 0.5 )
						inputDerivatives = GafferImage.FilterAlgo.derivativesToAxisAligned( p, d[0], d[1] )
					
							
						boxR[ ( y_sub * subSize + y ) * size[0] + x_sub * subSize + x ] = GafferImage.FilterAlgo.sampleBox(
							s, p, inputDerivatives[0], inputDerivatives[1], f )
						parallelogramR[ ( y_sub * subSize + y ) * size[0] + x_sub * subSize + x ] = GafferImage.FilterAlgo.sampleParallelogram(
							s, p, d[0], d[1], f )

		parallelogramImage["R"] = IECore.PrimitiveVariable( IECore.PrimitiveVariable.Interpolation.Vertex, parallelogramR )
		boxImage["R"] = IECore.PrimitiveVariable( IECore.PrimitiveVariable.Interpolation.Vertex, boxR )

		# Enable to write out images for visual comparison
		if False:
			IECore.Writer.create( parallelogramImage, "/tmp/filterDerivativesTestResult.parallelogram.exr" ).write()	
			IECore.Writer.create( boxImage, "/tmp/filterDerivativesTestResult.box.exr" ).write()	

		imageNode = GafferImage.ObjectToImage()
		imageNode["object"].setValue( parallelogramImage )

		expectedImage = GafferImage.ImageReader()
		expectedImage["fileName"].setValue( self.derivativesReferenceParallelFileName )

		self.assertImagesEqual( imageNode["out"], expectedImage["out"], ignoreMetadata = True, maxDifference = 0.000005 )

		imageNode["object"].setValue( boxImage )
		expectedImage["fileName"].setValue( self.derivativesReferenceBoxFileName )

		self.assertImagesEqual( imageNode["out"], expectedImage["out"], ignoreMetadata = True, maxDifference = 0.000005 )
示例#24
0
    def testFilterDerivatives(self):
        # Size of one grid cell
        subSize = 35

        # Each grid cell gets a dot in the middle
        redDot = GafferImage.Constant()
        redDot["format"].setValue(GafferImage.Format(1, 1, 1.000))
        redDot["color"].setValue(imath.Color4f(10, 0, 0, 1))
        redDotCentered = GafferImage.Crop("Crop")
        redDotCentered["in"].setInput(redDot["out"])
        redDotCentered["area"].setValue(
            imath.Box2i(imath.V2i(-(subSize - 1) / 2),
                        imath.V2i((subSize - 1) / 2 + 1)))

        borderForFilterWidth = 40
        sampleRegion = redDotCentered["out"]["dataWindow"].getValue()
        sampleRegion.setMin(sampleRegion.min() -
                            imath.V2i(borderForFilterWidth))
        sampleRegion.setMax(sampleRegion.max() +
                            imath.V2i(borderForFilterWidth))

        s = GafferImage.Sampler(redDotCentered["out"], "R", sampleRegion,
                                GafferImage.Sampler.BoundingMode.Black)

        filters = [
            'box',
            'triangle',
            'gaussian',
            'sharp-gaussian',
            'catmull-rom',
            'blackman-harris',
            'sinc',
            'lanczos3',
            'radial-lanczos3',
            'mitchell',
            'bspline',
            'disk',
            'cubic',
            'keys',
            'simon',
            'rifman',
            'smoothGaussian',
        ]
        if filters != GafferImage.FilterAlgo.filterNames():
            print(
                "INFO : GafferImageTest.FilterAlgoTest.testFilterDerivatives : "
                +
                "Some image filters have not been tested ({}). Consider updating the reference images to account for the newly available filters."
                .format(
                    list(
                        set(filters).symmetric_difference(
                            set(GafferImage.FilterAlgo.filterNames())))))

        dirs = [(imath.V2f(1, 0), imath.V2f(0, 1)),
                (imath.V2f(5, 0), imath.V2f(0, 1)),
                (imath.V2f(1, 0), imath.V2f(0, 5)),
                (imath.V2f(5, 0), imath.V2f(0, 5))]

        for angle in range(0, 91, 15):
            sa = math.sin(angle / 180.0 * math.pi)
            ca = math.cos(angle / 180.0 * math.pi)
            dirs.append((imath.V2f(ca * 5, sa * 5), imath.V2f(-sa * 3,
                                                              ca * 3)))

        size = subSize * imath.V2i(len(dirs), len(filters))
        w = imath.Box2i(imath.V2i(0), size - imath.V2i(1))
        parallelogramImage = IECoreImage.ImagePrimitive(w, w)
        boxImage = IECoreImage.ImagePrimitive(w, w)

        parallelogramR = IECore.FloatVectorData(size[0] * size[1])
        boxR = IECore.FloatVectorData(size[0] * size[1])

        for x_sub, d in enumerate(dirs):
            for y_sub, f in enumerate(filters):
                for y in range(subSize):
                    for x in range(subSize):
                        p = imath.V2f(x + 0.5, y + 0.5)
                        inputDerivatives = GafferImage.FilterAlgo.derivativesToAxisAligned(
                            p, d[0], d[1])

                        boxR[(y_sub * subSize + y) * size[0] +
                             x_sub * subSize +
                             x] = GafferImage.FilterAlgo.sampleBox(
                                 s, p, inputDerivatives[0],
                                 inputDerivatives[1], f)
                        parallelogramR[
                            (y_sub * subSize + y) * size[0] + x_sub * subSize +
                            x] = GafferImage.FilterAlgo.sampleParallelogram(
                                s, p, d[0], d[1], f)

        parallelogramImage["R"] = parallelogramR
        boxImage["R"] = boxR

        # Enable to write out images for visual comparison
        if False:
            IECore.Writer.create(
                parallelogramImage,
                "/tmp/filterDerivativesTestResult.parallelogram.exr").write()
            IECore.Writer.create(
                boxImage, "/tmp/filterDerivativesTestResult.box.exr").write()

        parallelogramReference = IECore.Reader.create(
            self.derivativesReferenceParallelFileName).read()
        boxReference = IECore.Reader.create(
            self.derivativesReferenceBoxFileName).read()

        for i in range(len(parallelogramImage["R"])):
            self.assertAlmostEqual(parallelogramReference["R"][i],
                                   parallelogramImage["R"][i],
                                   places=5)
            self.assertAlmostEqual(boxReference["R"][i],
                                   boxImage["R"][i],
                                   places=5)
示例#25
0
    def testPixelAspectRatio(self):

        c = GafferImage.Constant()
        c["format"].setValue(GafferImage.Format(1000, 1000))

        r = GafferImage.Resize()
        r["in"].setInput(c["out"])
        r["format"].setValue(GafferImage.Format(1500, 1000))

        for fitMode in r.FitMode.values:

            r["fitMode"].setValue(fitMode)

            for inputPixelAspect in (0.5, 1, 2):

                c["format"]["pixelAspect"].setValue(inputPixelAspect)

                for outputPixelAspect in (0.5, 1, 2):

                    r["format"]["pixelAspect"].setValue(outputPixelAspect)

                    if fitMode == r.FitMode.Horizontal:
                        self.assertEqual(
                            r["out"]["dataWindow"].getValue().min().x, r["out"]
                            ["format"].getValue().getDisplayWindow().min().x)
                        self.assertEqual(
                            r["out"]["dataWindow"].getValue().max().x, r["out"]
                            ["format"].getValue().getDisplayWindow().max().x)
                    elif fitMode == r.FitMode.Vertical:
                        self.assertEqual(
                            r["out"]["dataWindow"].getValue().min().y, r["out"]
                            ["format"].getValue().getDisplayWindow().min().y)
                        self.assertEqual(
                            r["out"]["dataWindow"].getValue().max().y, r["out"]
                            ["format"].getValue().getDisplayWindow().max().y)

                    if fitMode != r.FitMode.Distort:

                        # All fit modes other than Distort should ensure that the aspect
                        # ratio of the output data window is the same as the aspect ratio
                        # of the input data window.

                        inputDataWindow = r["in"]["dataWindow"].getValue()
                        inputFormat = r["in"]["format"].getValue()
                        inputAspect = (inputDataWindow.size().x
                                       ) * inputFormat.getPixelAspect() / (
                                           inputDataWindow.size().y)

                        outputDataWindow = r["out"]["dataWindow"].getValue()
                        outputFormat = r["out"]["format"].getValue()
                        outputAspect = (outputDataWindow.size().x
                                        ) * outputFormat.getPixelAspect() / (
                                            outputDataWindow.size().y)

                        # `delta` accounts for the fact that we're comparing integer data windows
                        # which have been expanded to enclose "fractional" pixels.
                        self.assertAlmostEqual(outputAspect,
                                               inputAspect,
                                               delta=0.01)

                    else:

                        # Distort mode - data window fills output format.

                        self.assertEqual(
                            r["out"]["dataWindow"].getValue(),
                            r["out"]["format"].getValue().getDisplayWindow())
示例#26
0
    def testGlobals(self):

        constant = GafferImage.Constant()
        constant["format"].setValue(
            GafferImage.Format(IECore.Box2i(IECore.V2i(-10), IECore.V2i(10))))

        globals = GafferOSL.OSLShader()
        globals.loadShader("Utility/Globals")

        outP = GafferOSL.OSLShader()
        outP.loadShader("ImageProcessing/OutLayer")
        outP["parameters"]["layerColor"].setInput(globals["out"]["globalP"])

        outU = GafferOSL.OSLShader()
        outU.loadShader("ImageProcessing/OutChannel")
        outU["parameters"]["channelName"].setValue("u")
        outU["parameters"]["channelValue"].setInput(globals["out"]["globalU"])

        outV = GafferOSL.OSLShader()
        outV.loadShader("ImageProcessing/OutChannel")
        outV["parameters"]["channelName"].setValue("v")
        outV["parameters"]["channelValue"].setInput(globals["out"]["globalV"])

        imageShader = GafferOSL.OSLShader()
        imageShader.loadShader("ImageProcessing/OutImage")
        imageShader["parameters"]["in0"].setInput(outP["out"]["layer"])
        imageShader["parameters"]["in1"].setInput(outU["out"]["channel"])
        imageShader["parameters"]["in2"].setInput(outV["out"]["channel"])

        image = GafferOSL.OSLImage()
        image["in"].setInput(constant["out"])
        image["shader"].setInput(imageShader["out"])

        displayWindow = image["out"]["format"].getValue().getDisplayWindow()

        samplerR = GafferImage.Sampler(image["out"], "R", displayWindow)
        samplerG = GafferImage.Sampler(image["out"], "G", displayWindow)
        samplerB = GafferImage.Sampler(image["out"], "B", displayWindow)
        samplerU = GafferImage.Sampler(image["out"], "u", displayWindow)
        samplerV = GafferImage.Sampler(image["out"], "v", displayWindow)

        size = IECore.V2f(displayWindow.size())
        uvStep = IECore.V2f(1.0) / size
        uvMin = 0.5 * uvStep

        for y in range(displayWindow.min.y, displayWindow.max.y):
            for x in range(displayWindow.min.x, displayWindow.max.x):

                self.assertEqual(samplerR.sample(x, y), x + 0.5,
                                 "Pixel {},{}".format(x, y))
                self.assertEqual(samplerG.sample(x, y), y + 0.5,
                                 "Pixel {},{}".format(x, y))
                self.assertEqual(samplerB.sample(x, y), 0,
                                 "Pixel {},{}".format(x, y))

                uv = uvMin + uvStep * IECore.V2f(
                    IECore.V2i(x, y) - displayWindow.min)
                self.assertAlmostEqual(samplerU.sample(x, y),
                                       uv.x,
                                       delta=0.0000001,
                                       msg="Pixel {},{}".format(x, y))
                self.assertAlmostEqual(samplerV.sample(x, y),
                                       uv.y,
                                       delta=0.0000001,
                                       msg="Pixel {},{}".format(x, y))
示例#27
0
    def testBadCachePolicyHang(self):

        # Using the legacy cache policy for OSLImage.shadingPlug creates a hang due to tbb task stealing,
        # though it's a bit hard to actually demonstrate

        constant = GafferImage.Constant()
        constant["format"].setValue(GafferImage.Format(128, 128, 1.000))

        # Need a slow to compute OSL code in order to trigger hang
        mandelbrotCode = self.mandelbrotNode()

        # In order to trigger the hang, we need to mix threads which are stuck waiting for an expression which
        # uses the Standard policy with threads that are actually finishing, so that tbb tries to start up new
        # threads while we're waiting for the expression result.  To do this, we use the "var" context variable
        # to create two versions of this OSLCode
        mandelbrotCode["varExpression"] = Gaffer.Expression()
        mandelbrotCode["varExpression"].setExpression(
            'parent.parameters.iterations = 100000 + context( "var", 0 );',
            "OSL")

        oslImage = GafferOSL.OSLImage()
        oslImage["channels"].addChild(
            Gaffer.NameValuePlug(
                "",
                Gaffer.Color3fPlug(
                    "value",
                    defaultValue=imath.Color3f(1, 1, 1),
                    flags=Gaffer.Plug.Flags.Default
                    | Gaffer.Plug.Flags.Dynamic,
                ), True, "channel",
                Gaffer.Plug.Flags.Default | Gaffer.Plug.Flags.Dynamic))
        oslImage["in"].setInput(constant["out"])
        oslImage["channels"]["channel"]["value"][0].setInput(
            mandelbrotCode["out"]["outFloat"])
        oslImage["channels"]["channel"]["value"][1].setInput(
            mandelbrotCode["out"]["outFloat"])
        oslImage["channels"]["channel"]["value"][2].setInput(
            mandelbrotCode["out"]["outFloat"])

        # This imageStats is use to create non-blocking slow calculations
        imageStats = GafferImage.ImageStats()
        imageStats["in"].setInput(oslImage["out"])
        imageStats["area"].setValue(
            imath.Box2i(imath.V2i(0, 0), imath.V2i(64, 64)))

        # This box does the non-blocking slow calculation, followed by a blocking slow calculation.
        # This ensures that tasks which do just the non-block calculation will start finishing while
        # the blocking slow calculation is still running, allowing tbb to try running more threads
        # on the blocking calcluation, realizing they can't run, and stealing tasks onto those threads
        # which can hit the Standard policy lock on the expression upstream and deadlock, unless the
        # OSLImage isolates its threads correctly
        expressionBox = Gaffer.Box()
        expressionBox.addChild(
            Gaffer.FloatVectorDataPlug("inChannelData",
                                       defaultValue=IECore.FloatVectorData(
                                           [])))
        expressionBox.addChild(Gaffer.FloatPlug("inStat"))
        expressionBox.addChild(
            Gaffer.FloatPlug("out", direction=Gaffer.Plug.Direction.Out))
        expressionBox["inChannelData"].setInput(oslImage["out"]["channelData"])
        expressionBox["inStat"].setInput(imageStats["average"]["r"])

        expressionBox["contextVariables"] = Gaffer.ContextVariables()
        expressionBox["contextVariables"].setup(
            Gaffer.FloatVectorDataPlug("in",
                                       defaultValue=IECore.FloatVectorData(
                                           [])))
        expressionBox["contextVariables"]["variables"].addChild(
            Gaffer.NameValuePlug("image:tileOrigin", Gaffer.V2iPlug("value"),
                                 True, "member1"))
        expressionBox["contextVariables"]["variables"].addChild(
            Gaffer.NameValuePlug("image:channelName",
                                 Gaffer.StringPlug("value", defaultValue='R'),
                                 True, "member2"))
        expressionBox["contextVariables"]["variables"].addChild(
            Gaffer.NameValuePlug("var", Gaffer.IntPlug("value",
                                                       defaultValue=1), True,
                                 "member3"))
        expressionBox["contextVariables"]["in"].setInput(
            expressionBox["inChannelData"])

        expressionBox["expression"] = Gaffer.Expression()
        expressionBox["expression"].setExpression(
            inspect.cleandoc("""
			d = parent["contextVariables"]["out"]
			parent["out"] = d[0] + parent["inStat"]
			"""))

        # Create a switch to mix which tasks perform the non-blocking or blocking calculation - we need a mixture
        # to trigger the hang
        switch = Gaffer.Switch()
        switch.setup(Gaffer.IntPlug(
            "in",
            defaultValue=0,
        ))
        switch["in"][0].setInput(expressionBox["out"])
        switch["in"][1].setInput(imageStats["average"]["r"])

        switch["switchExpression"] = Gaffer.Expression()
        switch["switchExpression"].setExpression(
            'parent.index = ( stoi( context( "testContext", "0" ) ) % 10 ) > 5;',
            "OSL")

        # In order to evaluate this expression a bunch of times at once with different values of "testContext",
        # we set up a simple scene that can be evaluated with GafferSceneTest.traversScene.
        # In theory, we could use a simple function that used a parallel_for to evaluate switch["out"], but for
        # some reason we don't entirely understand, this does not trigger the hang
        import GafferSceneTest
        import GafferScene

        sphere = GafferScene.Sphere()

        pathFilter = GafferScene.PathFilter()
        pathFilter["paths"].setValue(IECore.StringVectorData(['/sphere']))

        customAttributes = GafferScene.CustomAttributes()
        customAttributes["attributes"].addChild(
            Gaffer.NameValuePlug("foo", Gaffer.FloatPlug("value"), True,
                                 "member1"))
        customAttributes["attributes"]["member1"]["value"].setInput(
            switch["out"])
        customAttributes["in"].setInput(sphere["out"])
        customAttributes["filter"].setInput(pathFilter["out"])

        collectScenes = GafferScene.CollectScenes()
        collectScenes["in"].setInput(customAttributes["out"])
        collectScenes["rootNames"].setValue(
            IECore.StringVectorData([str(i) for i in range(1000)]))
        collectScenes["rootNameVariable"].setValue('testContext')

        # When OSLImage.shadingPlug is not correctly isolated, and grain size on ShadingEngine is smaller than the
        # image tile size, this fails about 50% of the time.  Running it 5 times makes the failure pretty consistent.
        for i in range(5):
            Gaffer.ValuePlug.clearCache()
            Gaffer.ValuePlug.clearHashCache()
            GafferSceneTest.traverseScene(collectScenes["out"])
示例#28
0
    def testBlurRange(self):

        constant = GafferImage.Constant()
        constant["format"].setValue(GafferImage.Format(5, 5, 1.000))
        constant["color"].setValue(IECore.Color4f(1, 1, 1, 1))

        cropDot = GafferImage.Crop()
        cropDot["area"].setValue(
            IECore.Box2i(IECore.V2i(2, 2), IECore.V2i(3, 3)))
        cropDot["affectDisplayWindow"].setValue(False)
        cropDot["in"].setInput(constant["out"])

        blur = GafferImage.Blur()
        blur["expandDataWindow"].setValue(True)
        blur["in"].setInput(cropDot["out"])
        blur["radius"]["y"].setInput(blur["radius"]["x"])

        expression = Gaffer.Expression()
        blur.addChild(expression)
        expression.setExpression(
            'parent["radius"]["x"] = context[ "loop:index" ] * 0.2', "python")

        loopInit = GafferImage.Constant()
        loopInit["format"].setValue(GafferImage.Format(5, 5, 1.000))

        imageLoop = GafferImage.ImageLoop()
        imageLoop["in"].setInput(loopInit["out"])

        merge = GafferImage.Merge()
        merge["in"].addChild(
            GafferImage.ImagePlug(
                "in2",
                flags=Gaffer.Plug.Flags.Default | Gaffer.Plug.Flags.Dynamic,
            ))
        merge["in"]["in0"].setInput(blur["out"])
        merge["in"]["in1"].setInput(imageLoop["previous"])

        offset = GafferImage.Offset()
        offset["offset"].setValue(IECore.V2i(-5, 0))
        offset["in"].setInput(merge["out"])

        imageLoop["next"].setInput(offset["out"])

        deleteChannels = GafferImage.DeleteChannels()
        deleteChannels["mode"].setValue(GafferImage.DeleteChannels.Mode.Keep)
        deleteChannels["channels"].setValue(IECore.StringVectorData(['R']))
        deleteChannels["in"].setInput(imageLoop["out"])

        finalCrop = GafferImage.Crop()
        finalCrop["areaSource"].setValue(1)
        finalCrop["in"].setInput(deleteChannels["out"])

        # Enable to write out images for visual comparison
        if False:
            testWriter = GafferImage.ImageWriter()
            testWriter["in"].setInput(finalCrop["out"])
            testWriter["fileName"].setValue("/tmp/blurRange.exr")
            testWriter["openexr"]["dataType"].setValue('float')
            testWriter["task"].execute()

        expectedReader = GafferImage.ImageReader()
        expectedReader["fileName"].setValue(
            os.path.dirname(__file__) + "/images/blurRange.exr")

        self.assertImagesEqual(finalCrop["out"],
                               expectedReader["out"],
                               maxDifference=0.00001,
                               ignoreMetadata=True)
示例#29
0
    def testDeleteKeepsOrder(self):

        # Send 4 images to a Catalogue : red, green, blue, yellow

        script = Gaffer.ScriptNode()
        script["catalogue"] = GafferImage.Catalogue()
        script["catalogue"]["directory"].setValue(
            os.path.join(self.temporaryDirectory(), "catalogue"))

        script["red"] = GafferImage.Constant()
        script["red"]["format"].setValue(GafferImage.Format(64, 64))
        script["red"]["color"]["r"].setValue(1)
        self.sendImage(script["red"]["out"], script["catalogue"])
        script["catalogue"]["images"][-1].setName("Red")

        script["green"] = GafferImage.Constant()
        script["green"]["format"].setValue(GafferImage.Format(64, 64))
        script["green"]["color"]["g"].setValue(1)
        self.sendImage(script["green"]["out"], script["catalogue"])
        script["catalogue"]["images"][-1].setName("Green")

        script["blue"] = GafferImage.Constant()
        script["blue"]["format"].setValue(GafferImage.Format(64, 64))
        script["blue"]["color"]["b"].setValue(1)
        self.sendImage(script["blue"]["out"], script["catalogue"])
        script["catalogue"]["images"][-1].setName("Blue")

        script["yellow"] = GafferImage.Constant()
        script["yellow"]["format"].setValue(GafferImage.Format(64, 64))
        script["yellow"]["color"].setValue(imath.Color4f(1, 1, 0, 1))
        self.sendImage(script["yellow"]["out"], script["catalogue"])
        script["catalogue"]["images"][-1].setName("Yellow")

        script["fileName"].setValue("/tmp/ttt.gfr")
        script.save()

        # Check it worked

        def assertPreconditions():

            self.assertEqual(len(script["catalogue"]["images"]), 4)
            self.assertEqual(script["catalogue"]["images"][0].getName(), "Red")
            self.assertEqual(script["catalogue"]["images"][1].getName(),
                             "Green")
            self.assertEqual(script["catalogue"]["images"][2].getName(),
                             "Blue")
            self.assertEqual(script["catalogue"]["images"][3].getName(),
                             "Yellow")

            script["catalogue"]["imageIndex"].setValue(0)
            self.assertImagesEqual(script["catalogue"]["out"],
                                   script["red"]["out"],
                                   ignoreMetadata=True)
            script["catalogue"]["imageIndex"].setValue(1)
            self.assertImagesEqual(script["catalogue"]["out"],
                                   script["green"]["out"],
                                   ignoreMetadata=True)
            script["catalogue"]["imageIndex"].setValue(2)
            self.assertImagesEqual(script["catalogue"]["out"],
                                   script["blue"]["out"],
                                   ignoreMetadata=True)
            script["catalogue"]["imageIndex"].setValue(3)
            self.assertImagesEqual(script["catalogue"]["out"],
                                   script["yellow"]["out"],
                                   ignoreMetadata=True)

            with Gaffer.Context(script.context()) as c:
                c["catalogue:imageName"] = "Red"
                self.assertImagesEqual(script["catalogue"]["out"],
                                       script["red"]["out"],
                                       ignoreMetadata=True)
                c["catalogue:imageName"] = "Green"
                self.assertImagesEqual(script["catalogue"]["out"],
                                       script["green"]["out"],
                                       ignoreMetadata=True)
                c["catalogue:imageName"] = "Blue"
                self.assertImagesEqual(script["catalogue"]["out"],
                                       script["blue"]["out"],
                                       ignoreMetadata=True)
                c["catalogue:imageName"] = "Yellow"
                self.assertImagesEqual(script["catalogue"]["out"],
                                       script["yellow"]["out"],
                                       ignoreMetadata=True)

        assertPreconditions()

        # Delete green, then blue, then yellow

        script["catalogue"]["imageIndex"].setValue(0)

        with Gaffer.UndoScope(script):
            del script["catalogue"]["images"][1]
            del script["catalogue"]["images"][1]
            del script["catalogue"]["images"][1]

        # Check it worked

        def assertPostConditions():

            self.assertEqual(len(script["catalogue"]["images"]), 1)
            self.assertEqual(script["catalogue"]["images"][0].getName(), "Red")

            script["catalogue"]["imageIndex"].setValue(0)
            self.assertImagesEqual(script["catalogue"]["out"],
                                   script["red"]["out"],
                                   ignoreMetadata=True)

            with Gaffer.Context(script.context()) as c:
                c["catalogue:imageName"] = "Red"
                self.assertImagesEqual(script["catalogue"]["out"],
                                       script["red"]["out"],
                                       ignoreMetadata=True)

        assertPostConditions()

        # Check that undo and redo work

        script.undo()
        assertPreconditions()

        script.redo()
        assertPostConditions()

        script.undo()
        assertPreconditions()
示例#30
0
	def testFilterDerivatives( self ):
		# Size of one grid cell
		subSize = 35

		# Each grid cell gets a dot in the middle
		redDot = GafferImage.Constant()
		redDot["format"].setValue( GafferImage.Format( 1, 1, 1.000 ) )
		redDot["color"].setValue( imath.Color4f( 10, 0, 0, 1 ) )
		redDotCentered = GafferImage.Crop( "Crop" )
		redDotCentered["in"].setInput( redDot["out"] )
		redDotCentered["area"].setValue( imath.Box2i( imath.V2i( -(subSize-1)/2 ), imath.V2i( (subSize-1)/2 + 1 ) ) )

		borderForFilterWidth = 40
		sampleRegion = redDotCentered["out"]["dataWindow"].getValue()
		sampleRegion.setMin( sampleRegion.min() - imath.V2i( borderForFilterWidth ) )
		sampleRegion.setMax( sampleRegion.max() + imath.V2i( borderForFilterWidth ) )

		s = GafferImage.Sampler( redDotCentered["out"], "R", sampleRegion, GafferImage.Sampler.BoundingMode.Black )

		filters = GafferImage.FilterAlgo.filterNames()
		dirs = [
			(imath.V2f(1,0), imath.V2f(0,1)),
			(imath.V2f(5,0), imath.V2f(0,1)),
			(imath.V2f(1,0), imath.V2f(0,5)),
			(imath.V2f(5,0), imath.V2f(0,5)) ]

		for angle in range( 0, 91, 15 ):
			sa = math.sin( angle / 180.0 * math.pi )
			ca = math.cos( angle / 180.0 * math.pi )
			dirs.append( ( imath.V2f(ca * 5, sa * 5 ), imath.V2f(-sa * 3, ca * 3 ) ) )

		size = subSize * imath.V2i( len( dirs ), len( filters ) )
		w = imath.Box2i( imath.V2i( 0 ), size - imath.V2i( 1 ) )
		parallelogramImage = IECoreImage.ImagePrimitive( w, w )
		boxImage = IECoreImage.ImagePrimitive( w, w )

		parallelogramR = IECore.FloatVectorData( size[0] * size[1] )
		boxR = IECore.FloatVectorData( size[0] * size[1] )

		for x_sub, d in enumerate( dirs ):
			for y_sub, f in enumerate( filters ):
				for y in range( subSize ):
					for x in range( subSize ):
						p = imath.V2f( x + 0.5, y + 0.5 )
						inputDerivatives = GafferImage.FilterAlgo.derivativesToAxisAligned( p, d[0], d[1] )


						boxR[ ( y_sub * subSize + y ) * size[0] + x_sub * subSize + x ] = GafferImage.FilterAlgo.sampleBox(
							s, p, inputDerivatives[0], inputDerivatives[1], f )
						parallelogramR[ ( y_sub * subSize + y ) * size[0] + x_sub * subSize + x ] = GafferImage.FilterAlgo.sampleParallelogram(
							s, p, d[0], d[1], f )

		parallelogramImage["R"] = parallelogramR
		boxImage["R"] = boxR

		# Enable to write out images for visual comparison
		if False:
			IECore.Writer.create( parallelogramImage, "/tmp/filterDerivativesTestResult.parallelogram.exr" ).write()
			IECore.Writer.create( boxImage, "/tmp/filterDerivativesTestResult.box.exr" ).write()

		parallelogramReference = IECore.Reader.create( self.derivativesReferenceParallelFileName ).read()
		boxReference = IECore.Reader.create( self.derivativesReferenceBoxFileName ).read()

		for i in range( len( parallelogramImage["R"] ) ):
			self.assertAlmostEqual( parallelogramReference["R"][i], parallelogramImage["R"][i], places = 5 )
			self.assertAlmostEqual( boxReference["R"][i], boxImage["R"][i], places = 5 )