Пример #1
0
    def testChannelRequest(self):

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

        ad = GafferImage.DeleteChannels()
        ad["in"].setInput(a["out"])
        ad["mode"].setValue(GafferImage.DeleteChannels.Mode.Delete)
        ad["channels"].setValue("R")

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

        bd = GafferImage.DeleteChannels()
        bd["in"].setInput(b["out"])
        bd["mode"].setValue(GafferImage.DeleteChannels.Mode.Delete)
        bd["channels"].setValue("G")

        merge = GafferImage.Merge()
        merge["in"][0].setInput(ad["out"])
        merge["in"][1].setInput(bd["out"])
        merge["operation"].setValue(GafferImage.Merge.Operation.Add)

        sampler = GafferImage.ImageSampler()
        sampler["image"].setInput(merge["out"])
        sampler["pixel"].setValue(imath.V2f(10))

        self.assertAlmostEqual(sampler["color"]["r"].getValue(), 0.0 + 1.0)
        self.assertAlmostEqual(sampler["color"]["g"].getValue(), 0.2 + 0.0)
        self.assertAlmostEqual(sampler["color"]["b"].getValue(), 0.3 + 0.1)
        self.assertAlmostEqual(sampler["color"]["a"].getValue(), 0.4 + 0.2)
Пример #2
0
	def testChannelRequest( self ) :

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

		ad = GafferImage.DeleteChannels()
		ad["in"].setInput( a["out"] )
		ad["mode"].setValue( GafferImage.DeleteChannels.Mode.Delete )
		ad["channels"].setValue( IECore.StringVectorData( [ "R" ] ) )

		b = GafferImage.Constant()
		b["color"].setValue( IECore.Color4f( 1.0, 0.3, 0.1, 0.2 ) )

		bd = GafferImage.DeleteChannels()
		bd["in"].setInput( b["out"] )
		bd["mode"].setValue( GafferImage.DeleteChannels.Mode.Delete )
		bd["channels"].setValue( IECore.StringVectorData( [ "G" ] ) )

		m = GafferImage.Constant()
		m["color"].setValue( IECore.Color4f( 0.5 ) )

		mix = GafferImage.Mix()
		mix["in"][0].setInput( ad["out"] )
		mix["in"][1].setInput( bd["out"] )
		mix["mask"].setInput( m["out"] )

		sampler = GafferImage.ImageSampler()
		sampler["image"].setInput( mix["out"] )
		sampler["pixel"].setValue( IECore.V2f( 10 ) )

		self.assertAlmostEqual( sampler["color"]["r"].getValue(), ( 0.0 + 1.0 ) * 0.5 )
		self.assertAlmostEqual( sampler["color"]["g"].getValue(), ( 0.2 + 0.0 ) * 0.5 )
		self.assertAlmostEqual( sampler["color"]["b"].getValue(), ( 0.3 + 0.1 ) * 0.5 )
		self.assertAlmostEqual( sampler["color"]["a"].getValue(), ( 0.4 + 0.2 ) * 0.5 )
Пример #3
0
    def testDriverChannel(self):

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

        r = GafferImage.Grade()
        r["in"].setInput(rRaw["out"])
        # Trim off the noise in the blacks so that areas with no visible color are actually flat
        r["blackPoint"].setValue(imath.Color4f(0.03))

        masterMedian = GafferImage.Median()
        masterMedian["in"].setInput(r["out"])
        masterMedian["radius"].setValue(imath.V2i(2))

        masterMedian["masterChannel"].setValue("G")

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

        # Note that in this expected image, the green channel is nicely medianed, and red and blue are completely
        # unchanged in areas where there is no green.  In areas where red and blue overlap with a noisy green,
        # they get a bit scrambled.  This is why in practice, you would use something like luminance, rather
        # than just the green channel
        self.assertImagesEqual(masterMedian["out"],
                               expected["out"],
                               ignoreMetadata=True,
                               maxDifference=0.0005)

        defaultMedian = GafferImage.Median()
        defaultMedian["in"].setInput(r["out"])
        defaultMedian["radius"].setValue(imath.V2i(2))

        masterMedianSingleChannel = GafferImage.DeleteChannels()
        masterMedianSingleChannel["in"].setInput(masterMedian["out"])
        masterMedianSingleChannel["mode"].setValue(
            GafferImage.DeleteChannels.Mode.Keep)

        defaultMedianSingleChannel = GafferImage.DeleteChannels()
        defaultMedianSingleChannel["in"].setInput(defaultMedian["out"])
        defaultMedianSingleChannel["mode"].setValue(
            GafferImage.DeleteChannels.Mode.Keep)

        for c in ["R", "G", "B"]:
            masterMedian["masterChannel"].setValue(c)
            masterMedianSingleChannel["channels"].setValue(c)
            defaultMedianSingleChannel["channels"].setValue(c)

            # When we look at just the channel being used as the master, it matches a default median not using
            # a master
            self.assertImagesEqual(masterMedianSingleChannel["out"],
                                   defaultMedianSingleChannel["out"])
Пример #4
0
    def testDirtyPropagation(self):

        r = GafferImage.ImageReader()
        r["fileName"].setValue(self.checkerFile)

        c = GafferImage.DeleteChannels()
        c["in"].setInput(r["out"])

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

        self.assertEqual(c["mode"].getValue(),
                         GafferImage.DeleteChannels.Mode.Delete)
        c["mode"].setValue(GafferImage.DeleteChannels.Mode.Keep)

        dirtiedPlugs = set([x[0].relativeName(x[0].node()) for x in cs])

        self.assertEqual(len(dirtiedPlugs), 3)
        self.assertTrue("mode" in dirtiedPlugs)
        self.assertTrue("out" in dirtiedPlugs)
        self.assertTrue("out.channelNames" in dirtiedPlugs)

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

        c["channels"].setValue("R")

        dirtiedPlugs = set([x[0].relativeName(x[0].node()) for x in cs])
        self.assertEqual(len(dirtiedPlugs), 3)
        self.assertTrue("channels" in dirtiedPlugs)
        self.assertTrue("out" in dirtiedPlugs)
        self.assertTrue("out.channelNames" in dirtiedPlugs)
Пример #5
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 )
Пример #6
0
    def testCollaboratePerf(self):
        # Test an expensive OSLImage, with many output tiles depending on the same input tiles,
        # which should give TaskCollaborate a chance to show some benefit

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

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

        mandelbrotCode = self.mandelbrotNode()
        mandelbrotCode["parameters"]["iterations"].setValue(500000)

        oslImage = GafferOSL.OSLImage()
        oslImage["in"].setInput(deleteChannels["out"])
        oslImage["channels"].addChild(
            Gaffer.NameValuePlug("R", Gaffer.FloatPlug("value"), True,
                                 "channel"))
        oslImage["channels"]["channel"]["value"].setInput(
            mandelbrotCode["out"]["outFloat"])

        resize = GafferImage.Resize()
        resize["in"].setInput(oslImage["out"])
        resize["format"].setValue(
            GafferImage.Format(imath.Box2i(imath.V2i(0), imath.V2i(2048)), 1))
        # We use a resize because it pulls the input tiles repeatedly, we don't want to spend time on resizing
        # pixels, so use a fast filter
        resize["filter"].setValue('box')

        with GafferTest.TestRunner.PerformanceScope():
            GafferImage.ImageAlgo.image(resize["out"])
Пример #7
0
        def __test(fileName, size, filter):

            inputFileName = os.path.dirname(__file__) + "/images/" + fileName

            reader = GafferImage.ImageReader()
            reader["fileName"].setValue(inputFileName)

            inSize = reader["out"]["format"].getValue().getDisplayWindow(
            ).size()
            inSize = imath.V2f(inSize.x, inSize.y)

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

            scale = imath.V2f(size.x, size.y) / inSize

            resample = GafferImage.Resample()
            resample["in"].setInput(deleteChannels["out"])
            resample["matrix"].setValue(imath.M33f().scale(scale))
            resample["filter"].setValue(filter)
            resample["boundingMode"].setValue(
                GafferImage.Sampler.BoundingMode.Clamp)

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

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

            s = GafferImage.Sampler(reader["out"], "R", sampleRegion,
                                    GafferImage.Sampler.BoundingMode.Clamp)
            resampledS = GafferImage.Sampler(
                resample["out"], "R", resample["out"]["dataWindow"].getValue())

            for y in range(size.y):
                for x in range(size.x):
                    resampled = resampledS.sample(x, y)
                    self.assertAlmostEqual(
                        resampled,
                        GafferImage.FilterAlgo.sampleBox(
                            s,
                            imath.V2f(x + 0.5, y + 0.5) / scale,
                            max(1.0 / scale[0], 1.0), max(1.0 / scale[1], 1.0),
                            filter),
                        places=5)
                    self.assertAlmostEqual(
                        resampled,
                        GafferImage.FilterAlgo.sampleParallelogram(
                            s,
                            imath.V2f(x + 0.5, y + 0.5) / scale,
                            imath.V2f(1.0 / scale[0], 0),
                            imath.V2f(0, 1.0 / scale[1]), filter),
                        places=5)
Пример #8
0
    def testPassThrough(self):

        i = GafferImage.ImageReader()
        i["fileName"].setValue(self.checkerFile)

        d = GafferImage.DeleteChannels()
        d["in"].setInput(i["out"])
        d["mode"].setValue(d.Mode.Keep)
        d["channels"].setValue("R")

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

        self.assertEqual(i["out"]["format"].getValue(),
                         d["out"]["format"].getValue())
        self.assertEqual(i["out"]["dataWindow"].getValue(),
                         d["out"]["dataWindow"].getValue())
        self.assertEqual(i["out"]["metadata"].getValue(),
                         d["out"]["metadata"].getValue())

        context = Gaffer.Context()
        context["image:tileOrigin"] = imath.V2i(0)
        with context:
            for c in ["G", "B", "A"]:
                context["image:channelName"] = c
                self.assertEqual(i["out"]["channelData"].hash(),
                                 d["out"]["channelData"].hash())
                self.assertEqual(i["out"]["channelData"].getValue(),
                                 d["out"]["channelData"].getValue())
Пример #9
0
	def testBlankScanlines( self ) :

		# create a wide image
		constant = GafferImage.Constant()
		constant["color"].setValue( IECore.Color4f( 0.5, 0.5, 0.5, 1 ) )
		constant["format"].setValue( GafferImage.Format( IECore.Box2i( IECore.V2i( 0 ), IECore.V2i( 3000, 1080 ) ), 1. ) )

		# fit it such that we have several tiles of blank lines on top (and bottom)
		resize = GafferImage.Resize()
		resize["in"].setInput( constant["out"] )
		resize["fitMode"].setValue( GafferImage.Resize.FitMode.Horizontal )

		# write to a file format that requires consecutive scanlines
		writer = GafferImage.ImageWriter()
		writer["in"].setInput( resize["out"] )
		writer["fileName"].setValue( "{0}/blankScanlines.jpg".format( self.temporaryDirectory() ) )
		writer["task"].execute()

		# ensure we wrote the file successfully
		reader = GafferImage.ImageReader()
		reader["fileName"].setInput( writer["fileName"] )
		cleanOutput = GafferImage.DeleteChannels()
		cleanOutput["in"].setInput( writer["in"] )
		cleanOutput["channels"].setValue( "A" )
		self.assertImagesEqual( reader["out"], cleanOutput["out"], ignoreMetadata=True, ignoreDataWindow=True, maxDifference=0.05 )
Пример #10
0
	def testMultipartRead( self ) :

		rgbReader = GafferImage.OpenImageIOReader()
		rgbReader["fileName"].setValue( self.offsetDataWindowFileName )

		compareDelete = GafferImage.DeleteChannels()
		compareDelete["in"].setInput( rgbReader["out"] )

		# This test multipart file contains a "rgb" subimage, an "rgba" subimage, and a "depth" subimage, with
		# one channel named "Z" ( copied from the green channel of our reference image.
		# It was created using this command:
		# > oiiotool rgb.100x100.exr --attrib "oiio:subimagename" rgb -ch "R,G,B" rgb.100x100.exr --attrib "oiio:subimagename" rgba rgb.100x100.exr --attrib "oiio:subimagename" depth --ch "G" --chnames "Z" --siappendall -o multipart.exr
		multipartReader = GafferImage.OpenImageIOReader()
		multipartReader["fileName"].setValue( self.multipartFileName )

		multipartShuffle = GafferImage.Shuffle()
		multipartShuffle["in"].setInput( multipartReader["out"] )

		multipartDelete = GafferImage.DeleteChannels()
		multipartDelete["in"].setInput( multipartShuffle["out"] )
		multipartDelete['channels'].setValue( "*.*" )

		self.assertEqual( set( multipartReader["out"]["channelNames"].getValue() ),
			set([ "rgba.R", "rgba.G", "rgba.B", "rgba.A", "rgb.R", "rgb.G", "rgb.B", "depth.Z" ])
		)

		multipartShuffle["channels"].clearChildren()
		multipartShuffle["channels"].addChild( GafferImage.Shuffle.ChannelPlug( "R", "rgba.R" ) )
		multipartShuffle["channels"].addChild( GafferImage.Shuffle.ChannelPlug( "G", "rgba.G" ) )
		multipartShuffle["channels"].addChild( GafferImage.Shuffle.ChannelPlug( "B", "rgba.B" ) )
		multipartShuffle["channels"].addChild( GafferImage.Shuffle.ChannelPlug( "A", "rgba.A" ) )
		self.assertImagesEqual( compareDelete["out"], multipartDelete["out"], ignoreMetadata = True )

		multipartShuffle["channels"].clearChildren()
		multipartShuffle["channels"].addChild( GafferImage.Shuffle.ChannelPlug( "R", "rgb.R" ) )
		multipartShuffle["channels"].addChild( GafferImage.Shuffle.ChannelPlug( "G", "rgb.G" ) )
		multipartShuffle["channels"].addChild( GafferImage.Shuffle.ChannelPlug( "B", "rgb.B" ) )
		compareDelete['channels'].setValue( "A" )
		self.assertImagesEqual( compareDelete["out"], multipartDelete["out"], ignoreMetadata = True )

		multipartShuffle["channels"].clearChildren()
		multipartShuffle["channels"].addChild( GafferImage.Shuffle.ChannelPlug( "G", "depth.Z" ) )
		compareDelete['channels'].setValue( "R B A" )
		self.assertImagesEqual( compareDelete["out"], multipartDelete["out"], ignoreMetadata = True )
Пример #11
0
            def __init__(self, name="DeleteAlpha"):

                GafferImage.ImageProcessor.__init__(self, name)

                self["__deleteChannels"] = GafferImage.DeleteChannels()
                self["__deleteChannels"]["in"].setInput(self["in"])
                self["__deleteChannels"]["enabled"].setInput(self["enabled"])
                self["__deleteChannels"]["channels"].setValue("A")

                self["out"].setInput(self["__deleteChannels"]["out"])
Пример #12
0
    def testModePlug(self):

        n = GafferImage.DeleteChannels()
        self.assertEqual(n["mode"].defaultValue(), n.Mode.Delete)
        self.assertEqual(n["mode"].getValue(), n.Mode.Delete)

        n["mode"].setValue(n.Mode.Keep)
        self.assertEqual(n["mode"].getValue(), n.Mode.Keep)

        self.assertEqual(n["mode"].minValue(), n.Mode.Delete)
        self.assertEqual(n["mode"].maxValue(), n.Mode.Keep)
Пример #13
0
            def __init__(self, name="DeleteAlpha"):

                GafferImage.ImageProcessor.__init__(self, name)

                self["__deleteChannels"] = GafferImage.DeleteChannels()
                self["__deleteChannels"]["in"].setInput(self["in"])
                self["__deleteChannels"]["enabled"].setInput(self["enabled"])
                self["__deleteChannels"]["channels"].setValue(
                    IECore.StringVectorData(["A"]))

                self["out"].setInput(self["__deleteChannels"]["out"])
Пример #14
0
    def testKeepChannels(self):

        r = GafferImage.ImageReader()
        r["fileName"].setValue(self.checkerFile)

        c = GafferImage.DeleteChannels()
        c["in"].setInput(r["out"])
        c["mode"].setValue(
            GafferImage.DeleteChannels.Mode.Keep)  # Keep selected channels
        c["channels"].setValue("G A")

        self.assertEqual(c["out"]["channelNames"].getValue(),
                         IECore.StringVectorData(["G", "A"]))
Пример #15
0
	def testChannelExistsBindings( self ) :

		# Test that both forms of binding to channelExists return the same
		# value

		c = GafferImage.Constant()

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

		for chan in [ "R", "G", "B", "A" ] :
			self.assertEqual( GafferImage.ImageAlgo.channelExists( d["out"], chan ), GafferImage.ImageAlgo.channelExists( d["out"]["channelNames"].getValue(), chan ) )
Пример #16
0
    def testHashChanged(self):

        r = GafferImage.ImageReader()
        r["fileName"].setValue(self.checkerFile)

        c = GafferImage.DeleteChannels()
        c["in"].setInput(r["out"])
        c["mode"].setValue(
            GafferImage.DeleteChannels.Mode.Keep)  # Keep selected channels
        c["channels"].setValue(" ".join(r["out"]["channelNames"].getValue()))
        h = c["out"]["channelNames"].hash()

        c["channels"].setValue("R B")
        h2 = c["out"]["channelNames"].hash()
        self.assertNotEqual(h, h2)
Пример #17
0
    def testImage(self):

        r = GafferImage.ImageReader()
        r["fileName"].setValue(self.checkerFile)

        d = GafferImage.DeleteChannels()
        d["in"].setInput(r["out"])
        d["mode"].setValue(d.Mode.Keep)
        d["channels"].setValue("R")

        ri = GafferImage.ImageAlgo.image(r["out"])
        di = GafferImage.ImageAlgo.image(d["out"])

        self.assertEqual(set(ri.keys()), set(["R", "G", "B", "A"]))
        self.assertEqual(di.keys(), ["R"])
        self.assertEqual(di["R"], ri["R"])
Пример #18
0
    def testImage(self):

        r = GafferImage.ImageReader()
        r["fileName"].setValue(self.checkerFile)

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

        ri = r["out"].image()
        di = d["out"].image()

        self.assertEqual(set(ri.keys()), set(["R", "G", "B", "A"]))
        self.assertEqual(di.keys(), ["R"])
        self.assertEqual(di["R"].data, ri["R"].data)
Пример #19
0
	def testChannelExists( self ) :

		c = GafferImage.Constant()

		d = GafferImage.DeleteChannels()
		d["in"].setInput( c["out"] )
		d["mode"].setValue( GafferImage.DeleteChannels.Mode.Delete )
		d["channels"].setValue( IECore.StringVectorData( [] ) )

		self.assertTrue( GafferImage.ImageAlgo.channelExists( d["out"], "R" ) )
		self.assertTrue( GafferImage.ImageAlgo.channelExists( d["out"], "G" ) )
		self.assertTrue( GafferImage.ImageAlgo.channelExists( d["out"], "B" ) )
		self.assertTrue( GafferImage.ImageAlgo.channelExists( d["out"], "A" ) )

		for chan in [ "R", "G", "B", "A" ] :
			d["channels"].setValue( IECore.StringVectorData( [ chan ] ) )
			self.assertFalse( GafferImage.ImageAlgo.channelExists( d["out"], chan ) )
Пример #20
0
    def testUnsupportedMultipartRead(self):

        rgbReader = GafferImage.OpenImageIOReader()
        rgbReader["fileName"].setValue(self.offsetDataWindowFileName)

        compareShuffle = GafferImage.Shuffle()
        compareShuffle["in"].setInput(rgbReader["out"])
        compareShuffle["channels"].clearChildren()
        compareShuffle["channels"].addChild(
            GafferImage.Shuffle.ChannelPlug("rgba.R", "R"))
        compareShuffle["channels"].addChild(
            GafferImage.Shuffle.ChannelPlug("rgba.G", "G"))
        compareShuffle["channels"].addChild(
            GafferImage.Shuffle.ChannelPlug("rgba.B", "B"))
        compareShuffle["channels"].addChild(
            GafferImage.Shuffle.ChannelPlug("rgba.A", "A"))

        compareDelete = GafferImage.DeleteChannels()
        compareDelete["in"].setInput(compareShuffle["out"])
        compareDelete["channels"].setValue("R G B A")

        # This test multipart file contains a "rgba" subimage, and a second subimage with a
        # differing data window.  The second part can currently not be loaded, because Gaffer images
        # have a single data window for the whole image.
        #
        # In the future, should we union the data windows?  Are subimages with differing data windows common?
        # This would probably happen with stereo images, but we should probably put work into handling stereo
        # images differently - with a context variable to control which eye we get, rather than loading everything
        # as channels.
        #
        # It was created using this command:
        # > oiiotool rgb.100x100.exr --attrib "oiio:subimagename" rgba checkerboard.100x100.exr --attrib "oiio:subimagename" fullDataWindow --siappendall -o unsupportedMultipart.exr
        multipartReader = GafferImage.OpenImageIOReader()
        multipartReader["fileName"].setValue(self.unsupportedMultipartFileName)

        # When we compare to the single part comparison file, the image will come out the same, because
        # the second part is ignored - and we should get a message about it being ignored
        with IECore.CapturingMessageHandler() as mh:
            self.assertImagesEqual(compareDelete["out"],
                                   multipartReader["out"],
                                   ignoreMetadata=True)

        self.assertEqual(len(mh.messages), 1)
        self.assertTrue(
            mh.messages[0].message.startswith("Ignoring subimage 1 of "))
Пример #21
0
    def testSimpleLayers(self):

        expected = GafferImage.ImageReader()
        expected["fileName"].setValue(self.layersPath)

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

        crop = GafferImage.Crop()
        crop["affectDisplayWindow"].setValue(False)
        crop["in"].setInput(constant["out"])

        delete = GafferImage.DeleteChannels()
        delete["channels"].setValue("A")
        delete["in"].setInput(crop["out"])

        collect = GafferImage.CollectImages()
        collect["rootLayers"].setValue(IECore.StringVectorData(['0', '1',
                                                                '2']))
        collect["in"].setInput(delete["out"])

        e = Gaffer.Expression()
        crop.addChild(e)
        e.setExpression(
            inspect.cleandoc("""
		layer = context.get( "collect:layerName", None )

		if layer:
			o = IECore.V2i(2, 2 ) * ( 1 + int( layer ) )
			area = IECore.Box2i( o, IECore.V2i( 1, 1 ) + o )
		else:
			area = IECore.Box2i( IECore.V2i( 3, 1 ), IECore.V2i( 4, 2 ) )

		parent["area"] = area
		"""), "python")

        copyChannels = GafferImage.CopyChannels()
        copyChannels["channels"].setValue("*")
        copyChannels["in"][0].setInput(crop["out"])
        copyChannels["in"][1].setInput(collect["out"])

        self.assertImagesEqual(copyChannels["out"],
                               expected["out"],
                               ignoreMetadata=True)
Пример #22
0
    def testChannelDataHash(self):

        r = GafferImage.ImageReader()
        r["fileName"].setValue(self.checkerFile)

        d = GafferImage.DeleteChannels()
        d["in"].setInput(r["out"])
        d["mode"].setValue(GafferImage.DeleteChannels.Mode.Delete)
        d["channels"].setValue("R")

        # the channels that are passed through should have identical hashes to the input,
        # so they can share cache entries.
        self.assertEqual(r["out"].channelDataHash("G", imath.V2i(0)),
                         d["out"].channelDataHash("G", imath.V2i(0)))
        self.assertEqual(r["out"].channelDataHash("B", imath.V2i(0)),
                         d["out"].channelDataHash("B", imath.V2i(0)))
        self.assertEqual(r["out"].channelDataHash("A", imath.V2i(0)),
                         d["out"].channelDataHash("A", imath.V2i(0)))
Пример #23
0
    def testConcatenation(self):

        # Identical transformation chains, but one
        # with concatenation broken by a Blur node.
        #
        #        checker
        #          |
        #    deleteChannels
        #          /\
        #         /  \
        #       tc1  t1
        #        |    |
        #       tc2  blur
        #             |
        #            t2

        checker = GafferImage.Checkerboard()
        checker["format"].setValue(GafferImage.Format(200, 200))

        deleteChannels = GafferImage.DeleteChannels()
        deleteChannels["in"].setInput(checker["out"])
        deleteChannels["channels"].setValue("A")

        tc1 = GafferImage.ImageTransform()
        tc1["in"].setInput(deleteChannels["out"])
        tc1["filter"].setValue("gaussian")

        tc2 = GafferImage.ImageTransform()
        tc2["in"].setInput(tc1["out"])
        tc2["filter"].setInput(tc1["filter"])

        t1 = GafferImage.ImageTransform()
        t1["in"].setInput(deleteChannels["out"])
        t1["transform"].setInput(tc1["transform"])
        t1["filter"].setInput(tc1["filter"])

        blur = GafferImage.Blur()
        blur["in"].setInput(t1["out"])

        t2 = GafferImage.ImageTransform()
        t2["in"].setInput(blur["out"])
        t2["transform"].setInput(tc2["transform"])
        t2["filter"].setInput(tc1["filter"])

        # The blur doesn't do anything except
        # break concatentation. Check that tc2
        # is practically identical to t2 for
        # a range of transforms.

        for i in range(0, 10):

            random.seed(i)

            translate1 = imath.V2f(random.uniform(-100, 100),
                                   random.uniform(-100, 100))
            rotate1 = random.uniform(-360, 360)
            scale1 = imath.V2f(random.uniform(-2, 2), random.uniform(-2, 2))

            tc1["transform"]["translate"].setValue(translate1)
            tc1["transform"]["rotate"].setValue(rotate1)
            tc1["transform"]["scale"].setValue(scale1)

            translate2 = imath.V2f(random.uniform(-100, 100),
                                   random.uniform(-100, 100))
            rotate2 = random.uniform(-360, 360)
            scale2 = imath.V2f(random.uniform(-2, 2), random.uniform(-2, 2))

            tc2["transform"]["translate"].setValue(translate2)
            tc2["transform"]["rotate"].setValue(rotate2)
            tc2["transform"]["scale"].setValue(scale2)

            # The `maxDifference` here is surprisingly high, but visual checks
            # show that it is legitimate : differences in filtering are that great.
            # The threshold is still significantly lower than the differences between
            # checker tiles, so does guarantee that tiles aren't getting out of alignment.
            self.assertImagesEqual(tc2["out"],
                                   t2["out"],
                                   maxDifference=0.11,
                                   ignoreDataWindow=True)
Пример #24
0
    def testChannelRequest(self):

        ts = GafferImage.ImagePlug.tileSize()

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

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

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

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

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

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

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

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

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

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

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

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

        for channelName in expectedChannelData:
            actualChannelData = merge["out"].channelData(
                channelName, imath.V2i(0))
            self.assertEqual(actualChannelData,
                             expectedChannelData[channelName])
Пример #25
0
	def testMissingChannels( self ) :

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

		self.__assertDeepStateProcessing( deleteChannels["out"], referenceFlatten["out"], [ 0, 0, 0, 10 ], [ 0, 0, 0, 10 ], 100, 0.45 )
Пример #26
0
    def testMultipartRead(self):

        rgbReader = GafferImage.OpenImageIOReader()
        rgbReader["fileName"].setValue(self.offsetDataWindowFileName)

        compareDelete = GafferImage.DeleteChannels()
        compareDelete["in"].setInput(rgbReader["out"])

        # This test multipart file contains a "customRgb" subimage, a "customRgba" subimage,
        # and a "customDepth" subimage, with one channel named "Z" ( copied from the green
        # channel of our reference image. )
        # We don't use the subimage names "rgb", "rgba" or "depth", because we want to look
        # at channels which don't get automatically mapped to the default channel names.
        # ( see testDefaultChannelsMultipartRead for that )
        # The test file was created using this command:
        # > oiiotool rgb.100x100.exr --attrib "oiio:subimagename" customRgb -ch "R,G,B" rgb.100x100.exr --attrib "oiio:subimagename" customRgba rgb.100x100.exr --attrib "oiio:subimagename" customDepth --ch "G" --chnames "Z" --siappendall -o multipart.exr
        multipartReader = GafferImage.OpenImageIOReader()
        multipartReader["fileName"].setValue(self.multipartFileName)

        multipartShuffle = GafferImage.Shuffle()
        multipartShuffle["in"].setInput(multipartReader["out"])

        multipartDelete = GafferImage.DeleteChannels()
        multipartDelete["in"].setInput(multipartShuffle["out"])
        multipartDelete['channels'].setValue("*.*")

        self.assertEqual(
            set(multipartReader["out"]["channelNames"].getValue()),
            set([
                "customRgba.R", "customRgba.G", "customRgba.B", "customRgba.A",
                "customRgb.R", "customRgb.G", "customRgb.B", "customDepth.Z"
            ]))

        multipartShuffle["channels"].clearChildren()
        multipartShuffle["channels"].addChild(
            GafferImage.Shuffle.ChannelPlug("R", "customRgba.R"))
        multipartShuffle["channels"].addChild(
            GafferImage.Shuffle.ChannelPlug("G", "customRgba.G"))
        multipartShuffle["channels"].addChild(
            GafferImage.Shuffle.ChannelPlug("B", "customRgba.B"))
        multipartShuffle["channels"].addChild(
            GafferImage.Shuffle.ChannelPlug("A", "customRgba.A"))
        self.assertImagesEqual(compareDelete["out"],
                               multipartDelete["out"],
                               ignoreMetadata=True)

        multipartShuffle["channels"].clearChildren()
        multipartShuffle["channels"].addChild(
            GafferImage.Shuffle.ChannelPlug("R", "customRgb.R"))
        multipartShuffle["channels"].addChild(
            GafferImage.Shuffle.ChannelPlug("G", "customRgb.G"))
        multipartShuffle["channels"].addChild(
            GafferImage.Shuffle.ChannelPlug("B", "customRgb.B"))
        compareDelete['channels'].setValue("A")
        self.assertImagesEqual(compareDelete["out"],
                               multipartDelete["out"],
                               ignoreMetadata=True)

        multipartShuffle["channels"].clearChildren()
        multipartShuffle["channels"].addChild(
            GafferImage.Shuffle.ChannelPlug("G", "customDepth.Z"))
        compareDelete['channels'].setValue("R B A")
        self.assertImagesEqual(compareDelete["out"],
                               multipartDelete["out"],
                               ignoreMetadata=True)
Пример #27
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)
Пример #28
0
    def testBasics(self):
        representativeImage = GafferImage.ImageReader()
        representativeImage["fileName"].setValue(self.representativeImagePath)

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

        offset["offset"].setValue(imath.V2i(103, -27))
        self.assertImagesEqual(holdoutNoZ["out"],
                               cropCleanup["out"],
                               maxDifference=1e-5)
Пример #29
0
		def __test( fileName, size, filter ) :

			inputFileName = os.path.dirname( __file__ ) + "/images/" + fileName

			reader = GafferImage.ImageReader()
			reader["fileName"].setValue( inputFileName )

			inSize = reader["out"]["format"].getValue().getDisplayWindow().size()
			inSize = IECore.V2f( inSize.x, inSize.y )
			
			deleteChannels = GafferImage.DeleteChannels()
			deleteChannels["mode"].setValue( 1 )
			deleteChannels["channels"].setValue( IECore.StringVectorData( [ 'R' ] ) )
			deleteChannels["in"].setInput( reader["out"] )


			scale = IECore.V2f( size.x, size.y ) / inSize

			resample = GafferImage.Resample()
			resample["in"].setInput( deleteChannels["out"] )
			resample["matrix"].setValue(
				IECore.M33f().scale( scale )
			)
			resample["filter"].setValue( filter )
			resample["boundingMode"].setValue( GafferImage.Sampler.BoundingMode.Clamp )

			crop = GafferImage.Crop()
			crop["in"].setInput( resample["out"] )
			crop["area"].setValue( IECore.Box2i( IECore.V2i( 0 ), size ) )

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

			s = GafferImage.Sampler( reader["out"], "R", sampleRegion, GafferImage.Sampler.BoundingMode.Clamp )

			w = IECore.Box2i( IECore.V2i( 0 ), size - IECore.V2i( 1 ) )
			boxImage = IECore.ImagePrimitive( w, w )
			parallelImage = IECore.ImagePrimitive( w, w )

			boxR = IECore.FloatVectorData( size.x * size.y )
			parallelR = IECore.FloatVectorData( size.x * size.y )
		
			for y in range( size.y ):
				for x in range( size.x ):
						boxR[ ( size.y - 1 - y ) * size.x + x ] = GafferImage.FilterAlgo.sampleBox(
							s,
							IECore.V2f( x + 0.5, y + 0.5 ) / scale,
							max( 1.0 / scale[0], 1.0 ),
							max( 1.0 / scale[1], 1.0 ),
							filter )
						parallelR[ ( size.y - 1 - y ) * size.x + x ] = GafferImage.FilterAlgo.sampleParallelogram(
							s,
							IECore.V2f( x + 0.5, y + 0.5 ) / scale,
							IECore.V2f( 1.0 / scale[0], 0),
							IECore.V2f( 0, 1.0 / scale[1]),
							filter )

			boxImage["R"] = IECore.PrimitiveVariable( IECore.PrimitiveVariable.Interpolation.Vertex, boxR )
			parallelImage["R"] = IECore.PrimitiveVariable( IECore.PrimitiveVariable.Interpolation.Vertex, parallelR )

			# Enable to write out images for visual comparison
			if False:
				tempDirectory = "/tmp"
				expectedFileName = tempDirectory + "/%s_%dx%d_%s_expected.exr" % ( os.path.splitext( fileName )[0], size.x, size.y, filter )
				expectedWriter = GafferImage.ImageWriter()
				expectedWriter["in"].setInput( crop["out"] )
				expectedWriter["fileName"].setValue( expectedFileName )
				expectedWriter["task"].execute()

				outputFileName = tempDirectory + "/%s_%dx%d_%s.box.exr" % ( os.path.splitext( fileName )[0], size.x, size.y, filter )
				IECore.Writer.create( boxImage, outputFileName ).write()	
				outputFileName = tempDirectory + "/%s_%dx%d_%s.parallel.exr" % ( os.path.splitext( fileName )[0], size.x, size.y, filter )
				IECore.Writer.create( parallelImage, outputFileName ).write()	

			imageNode = GafferImage.ObjectToImage()
			imageNode["object"].setValue( boxImage )
			self.assertImagesEqual( crop["out"], imageNode["out"], maxDifference = 0.000011, ignoreMetadata = True )

			imageNode["object"].setValue( parallelImage )
			self.assertImagesEqual( crop["out"], imageNode["out"], maxDifference = 0.000011, ignoreMetadata = True )