Пример #1
0
	def testDeep( self ) :
		representativeDeep = GafferImage.ImageReader()
		representativeDeep["fileName"].setValue( self.representativeDeepImagePath )

		deepCrop = GafferImage.Crop()
		deepCrop["in"].setInput( representativeDeep["out"] )

		postFlatten = GafferImage.DeepToFlat()
		postFlatten["in"].setInput( deepCrop["out"] )

		preFlatten = GafferImage.DeepToFlat()
		preFlatten["in"].setInput( representativeDeep["out"] )

		flatCrop = GafferImage.Crop()
		flatCrop["in"].setInput( preFlatten["out"] )

		dataWindow = representativeDeep["out"].dataWindow()

		for affectDisplay in [ True, False ]:
			for area in [
				imath.Box2i( imath.V2i( 0, 0 ), imath.V2i( 150, 100 ) ),
				imath.Box2i( imath.V2i( -10, -13 ), imath.V2i( 157, 103 ) ),
				imath.Box2i( imath.V2i( 10, 13 ), imath.V2i( 143, 77 ) ),
				imath.Box2i( imath.V2i( 37, 65 ), imath.V2i( 101, 67 ) ),
				imath.Box2i( imath.V2i( 0, 0 ), imath.V2i( 149, 99 ) )
			] :
				deepCrop["area"].setValue( area )
				flatCrop["area"].setValue( area )

				self.assertImagesEqual( postFlatten["out"], flatCrop["out"] )
Пример #2
0
    def testDeepWithFlatMask(self):

        # Set up a mask
        maskReader = GafferImage.ImageReader()
        maskReader["fileName"].setValue(self.radialPath)

        maskText = GafferImage.Text()
        maskText["in"].setInput(maskReader["out"])
        maskText["area"].setValue(
            imath.Box2i(imath.V2i(0, 0), imath.V2i(256, 256)))
        maskText["text"].setValue('Test\nTest\nTest\nTest')

        maskOffset = GafferImage.Offset()
        maskOffset["in"].setInput(maskText["out"])

        representativeDeepImage = GafferImage.ImageReader()
        representativeDeepImage["fileName"].setValue(
            self.representativeDeepImagePath)

        deepGradeBlack = GafferImage.Grade()
        deepGradeBlack["in"].setInput(representativeDeepImage["out"])
        deepGradeBlack["multiply"].setValue(imath.Color4f(0, 0, 0, 1))

        deepMix = GafferImage.Mix()
        deepMix["in"]["in0"].setInput(representativeDeepImage["out"])
        deepMix["in"]["in1"].setInput(deepGradeBlack["out"])
        deepMix["mask"].setInput(maskOffset["out"])
        deepMix["maskChannel"].setValue('R')

        postFlatten = GafferImage.DeepToFlat()
        postFlatten["in"].setInput(deepMix["out"])

        preFlatten = GafferImage.DeepToFlat()
        preFlatten["in"].setInput(representativeDeepImage["out"])

        flatGradeBlack = GafferImage.Grade()
        flatGradeBlack["in"].setInput(preFlatten["out"])
        flatGradeBlack["multiply"].setValue(imath.Color4f(0, 0, 0, 1))

        flatMix = GafferImage.Mix()
        flatMix["in"]["in0"].setInput(preFlatten["out"])
        flatMix["in"]["in1"].setInput(flatGradeBlack["out"])
        flatMix["mask"].setInput(maskOffset["out"])
        flatMix["maskChannel"].setValue('R')

        for o in [
                imath.V2i(0, 0),
                imath.V2i(-3, -8),
                imath.V2i(-7, -79),
                imath.V2i(12, 8)
        ]:
            maskOffset["offset"].setValue(o)

            self.assertImagesEqual(postFlatten["out"],
                                   flatMix["out"],
                                   maxDifference=0.000003)
Пример #3
0
	def testBasics( self ):
		representativeImage = GafferImage.ImageReader()
		representativeImage["fileName"].setValue( self.representativeImagePath )

		flatImage = GafferImage.ImageReader()
		flatImage["fileName"].setValue( self.flatImagePath )

		rc = GafferImage.DeepRecolor()
		rc["in"].setInput( representativeImage["out"] )
		rc["colorSource"].setInput( flatImage["out"] )

		representativeSampleCounts = GafferImage.DeepSampleCounts()
		representativeSampleCounts["in"].setInput( representativeImage["out"] )

		rcSampleCounts = GafferImage.DeepSampleCounts()
		rcSampleCounts["in"].setInput( rc["out"] )

		# Make sure we keep all the deep samples
		self.assertImagesEqual( representativeSampleCounts["out"], rcSampleCounts["out"] )

		rcFlat = GafferImage.DeepToFlat()
		rcFlat["in"].setInput( rc["out"] )

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

		unpremult = GafferImage.Unpremultiply()
		unpremult["in"].setInput( flatImage["out"] )

		flatCombine = GafferImage.CopyChannels()
		flatCombine["in"][0].setInput( representativeFlat["out"] )
		flatCombine["in"][1].setInput( unpremult["out"] )
		flatCombine["channels"].setValue( "[RGB]" )

		premult = GafferImage.Premultiply()
		premult["in"].setInput( flatCombine["out"] )

		# Make sure that the default recolor matches the flat value of premulting by the deep alpha
		self.assertImagesEqual( rcFlat["out"], premult["out"], maxDifference = 1e-6 )

		compare = GafferImage.Merge()
		compare["in"][0].setInput( rcFlat["out"] )
		compare["in"][1].setInput( premult["out"] )
		compare["operation"].setValue( GafferImage.Merge.Operation.Difference )

		compareStats = GafferImage.ImageStats()
		compareStats["in"].setInput( compare["out"] )
		compareStats["area"].setValue( imath.Box2i( imath.V2i( 0, 0 ), imath.V2i( 150, 100 ) ) )

		m = compareStats["max"].getValue()
		a = compareStats["average"].getValue()
		for i in range( 4 ):
			self.assertLessEqual( m[i], 1e-6 )
			self.assertLessEqual( a[i], 1e-8 )

		rc["useColorSourceAlpha"].setValue( True )

		m = compareStats["max"].getValue()
		a = compareStats["average"].getValue()
		for i in range( 3 ):
			self.assertGreater( m[i], 0.4 )
			self.assertGreater( a[i], 0.0001 )

		# Make sure that using useColorSourceAlpha basically matches the original color source after
		# flattening.  ( It's not exact because of a few pixels with zero samples in the deep which
		# we can't do anything with )
		compare["in"][1].setInput( flatImage["out"] )

		m = compareStats["max"].getValue()
		a = compareStats["average"].getValue()
		for i in range( 4 ):
			self.assertLessEqual( m[i], 0.5 )
			self.assertLessEqual( a[i], 0.0003 )
Пример #4
0
    def testDeep(self):
        # Simple network to swap channels
        inLayer = GafferOSL.OSLShader()
        inLayer.loadShader("ImageProcessing/InLayer")

        colorToFloat = GafferOSL.OSLShader()
        colorToFloat.loadShader("Conversion/ColorToFloat")
        colorToFloat["parameters"]["c"].setInput(inLayer["out"]["layerColor"])

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

        # Read in a deep image
        imageReader = GafferImage.ImageReader()
        imageReader["fileName"].setValue(self.representativeDeepImagePath)

        # Try running OSLImage on deep image, then flattening
        oslImageDeep = GafferOSL.OSLImage()
        oslImageDeep["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))
        oslImageDeep["in"].setInput(imageReader["out"])
        oslImageDeep["channels"]["channel"]["value"].setInput(
            floatToColor["out"]["c"])

        postFlatten = GafferImage.DeepToFlat()
        postFlatten["in"].setInput(oslImageDeep["out"])

        # Try running OSLImage on already flattened image
        preFlatten = GafferImage.DeepToFlat()
        preFlatten["in"].setInput(imageReader["out"])

        oslImageFlat = GafferOSL.OSLImage()
        oslImageFlat["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))
        oslImageFlat["in"].setInput(preFlatten["out"])
        oslImageFlat["channels"]["channel"]["value"].setInput(
            floatToColor["out"]["c"])

        # Results should match
        self.assertImagesEqual(postFlatten["out"], oslImageFlat["out"])

        # Also test reading from UV
        shaderGlobals = GafferOSL.OSLShader("Globals")
        shaderGlobals.loadShader("Utility/Globals")

        uvToColor = GafferOSL.OSLShader()
        uvToColor.loadShader("Conversion/FloatToColor")
        uvToColor["parameters"]["r"].setInput(shaderGlobals["out"]["globalU"])
        uvToColor["parameters"]["g"].setInput(shaderGlobals["out"]["globalV"])

        inAlpha = GafferOSL.OSLShader()
        inAlpha.loadShader("ImageProcessing/InChannel")
        inAlpha["parameters"]["channelName"].setValue('A')

        multiplyAlpha = GafferOSL.OSLShader()
        multiplyAlpha.loadShader("Maths/MultiplyColor")
        multiplyAlpha["parameters"]["a"].setInput(uvToColor["out"]["c"])
        multiplyAlpha["parameters"]["b"]["r"].setInput(
            inAlpha["out"]["channelValue"])
        multiplyAlpha["parameters"]["b"]["g"].setInput(
            inAlpha["out"]["channelValue"])
        multiplyAlpha["parameters"]["b"]["b"].setInput(
            inAlpha["out"]["channelValue"])

        oslImageDeep["channels"]["channel"]["value"].setInput(
            multiplyAlpha["out"]["out"])

        outImage = GafferImage.ImageAlgo.image(postFlatten["out"])
        size = outImage.dataWindow.size() + imath.V2i(1)
        i = 0
        for y in range(size.y):
            for x in range(size.x):
                self.assertAlmostEqual(outImage["R"][i],
                                       (x + 0.5) / size.x * outImage["A"][i],
                                       places=5)
                self.assertAlmostEqual(outImage["G"][i], (size.y - y - 0.5) /
                                       size.y * outImage["A"][i],
                                       places=5)
                i += 1
Пример #5
0
    def testDeep(self):
        representativeDeep = GafferImage.ImageReader()
        representativeDeep["fileName"].setValue(
            self.representativeDeepImagePath)

        deepShuffle = GafferImage.Shuffle()
        deepShuffle["in"].setInput(representativeDeep["out"])

        postFlatten = GafferImage.DeepToFlat()
        postFlatten["in"].setInput(deepShuffle["out"])

        preFlatten = GafferImage.DeepToFlat()
        preFlatten["in"].setInput(representativeDeep["out"])

        flatShuffle = GafferImage.Shuffle()
        flatShuffle["in"].setInput(preFlatten["out"])
        flatShuffle["channels"].setInput(deepShuffle["channels"])

        deepShuffle["channels"].addChild(deepShuffle.ChannelPlug("R", "B"))
        deepShuffle["channels"].addChild(deepShuffle.ChannelPlug("G", "R"))
        deepShuffle["channels"].addChild(deepShuffle.ChannelPlug("B", "G"))

        deepOrig = GafferImage.ImageAlgo.tiles(representativeDeep["out"])
        flatOrig = GafferImage.ImageAlgo.tiles(preFlatten["out"])

        flatShuffled = GafferImage.ImageAlgo.tiles(flatShuffle["out"])
        deepShuffled = GafferImage.ImageAlgo.tiles(deepShuffle["out"])

        self.assertEqual(flatShuffled["R"], flatOrig["B"])
        self.assertEqual(flatShuffled["G"], flatOrig["R"])
        self.assertEqual(flatShuffled["B"], flatOrig["G"])
        self.assertEqual(flatShuffled["A"], flatOrig["A"])

        self.assertEqual(deepShuffled["R"], deepOrig["B"])
        self.assertEqual(deepShuffled["G"], deepOrig["R"])
        self.assertEqual(deepShuffled["B"], deepOrig["G"])
        self.assertEqual(deepShuffled["A"], deepOrig["A"])

        self.assertImagesEqual(postFlatten["out"], flatShuffle["out"])

        deepShuffle["channels"].clearChildren()
        deepShuffle["channels"].addChild(
            deepShuffle.ChannelPlug("R", "__black"))
        deepShuffle["channels"].addChild(
            deepShuffle.ChannelPlug("G", "__white"))
        deepShuffle["channels"].addChild(
            deepShuffle.ChannelPlug("B", "__black"))

        flatGreen = GafferImage.ImageAlgo.tiles(flatShuffle["out"])
        deepGreen = GafferImage.ImageAlgo.tiles(deepShuffle["out"])

        for k in flatGreen["R"].keys():
            self.assertEqual(flatGreen["R"][k],
                             GafferImage.ImagePlug.blackTile())
            self.assertEqual(flatGreen["G"][k],
                             GafferImage.ImagePlug.whiteTile())
            self.assertEqual(flatGreen["B"][k],
                             GafferImage.ImagePlug.blackTile())

            numSamples = deepGreen["sampleOffsets"][k][-1]

            self.assertEqual(deepGreen["R"][k],
                             IECore.FloatVectorData([0.0] * numSamples))
            self.assertEqual(deepGreen["G"][k],
                             IECore.FloatVectorData([1.0] * numSamples))
            self.assertEqual(deepGreen["B"][k],
                             IECore.FloatVectorData([0.0] * numSamples))

        deepPremult = GafferImage.Premultiply()
        deepPremult["in"].setInput(deepShuffle["out"])
        postFlatten["in"].setInput(deepPremult["out"])

        flatPremult = GafferImage.Premultiply()
        flatPremult["in"].setInput(flatShuffle["out"])

        self.assertImagesEqual(postFlatten["out"],
                               flatPremult["out"],
                               maxDifference=0.000001)
Пример #6
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)
Пример #7
0
    def testDeepMix(self):
        representativeDeepImage = GafferImage.ImageReader()
        representativeDeepImage["fileName"].setValue(
            self.representativeDeepImagePath)

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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