diff --git a/Changes.md b/Changes.md index dc7d25211bd..808ebbe1d56 100644 --- a/Changes.md +++ b/Changes.md @@ -45,6 +45,7 @@ Fixes - Stopped failed jobs jumping to the end of the Local Jobs UI. - Fixed message log update. - Fixed `Job.statistics()` errors on Windows, ensuring that a `pid` is always returned when available. +- ImageStats : Fixed output of infinite values, which were previously being clamped. API --- diff --git a/python/GafferImageTest/ImageStatsTest.py b/python/GafferImageTest/ImageStatsTest.py index 5fc1dac5e18..e9a154080fc 100644 --- a/python/GafferImageTest/ImageStatsTest.py +++ b/python/GafferImageTest/ImageStatsTest.py @@ -36,6 +36,7 @@ import os import unittest +import math import imath import IECore @@ -300,6 +301,31 @@ def testTaskCollaboration( self ) : self.assertEqual( pm.plugStatistics( stats["__allStats" ] ).computeCount, 1 ) + def testInf( self ) : + + # Make an image with all `inf` values. We can't do this directly + # with a Constant because the inputs are clamped at float max, + # so we divide an image by zero to get what we want. + + constant0 = GafferImage.Constant() + constant1 = GafferImage.Constant() + constant1["color"].setValue( imath.Color4f( 1 ) ) + + merge = GafferImage.Merge() + merge["in"][0].setInput( constant0["out"] ) + merge["in"][1].setInput( constant1["out"] ) + merge["operation"].setValue( merge.Operation.Divide ) + + # Since all values are `inf`, all outputs should be too. + + stats = GafferImage.ImageStats() + stats["in"].setInput( merge["out"] ) + stats["area"].setValue( stats["in"].format().getDisplayWindow() ) + + self.assertTrue( math.isinf( stats["max"][0].getValue() ) ) + self.assertTrue( math.isinf( stats["min"][0].getValue() ) ) + self.assertTrue( math.isinf( stats["average"][0].getValue() ) ) + def __assertColour( self, colour1, colour2 ) : for i in range( 0, 4 ): self.assertEqual( "%.4f" % colour2[i], "%.4f" % colour1[i] ) diff --git a/src/GafferImage/ImageStats.cpp b/src/GafferImage/ImageStats.cpp index d8a0b56a8bd..2579a13996e 100644 --- a/src/GafferImage/ImageStats.cpp +++ b/src/GafferImage/ImageStats.cpp @@ -113,9 +113,18 @@ ImageStats::ImageStats( const std::string &name ) addChild( new StringVectorDataPlug( "channels", Plug::In, defaultChannelsData ) ); addChild( new Box2iPlug( "area", Gaffer::Plug::In ) ); - addChild( new Color4fPlug( "average", Gaffer::Plug::Out, Imath::Color4f( 0, 0, 0, 1 ) ) ); - addChild( new Color4fPlug( "min", Gaffer::Plug::Out, Imath::Color4f( 0, 0, 0, 1 ) ) ); - addChild( new Color4fPlug( "max", Gaffer::Plug::Out, Imath::Color4f( 0, 0, 0, 1 ) ) ); + addChild( new Color4fPlug( + "average", Gaffer::Plug::Out, Imath::Color4f( 0, 0, 0, 1 ), + Imath::Color4f( -std::numeric_limits::infinity() ), Imath::Color4f( std::numeric_limits::infinity() ) + ) ); + addChild( + new Color4fPlug( "min", Gaffer::Plug::Out, Imath::Color4f( 0, 0, 0, 1 ), + Imath::Color4f( -std::numeric_limits::infinity() ), Imath::Color4f( std::numeric_limits::infinity() ) + ) ); + addChild( + new Color4fPlug( "max", Gaffer::Plug::Out, Imath::Color4f( 0, 0, 0, 1 ), + Imath::Color4f( -std::numeric_limits::infinity() ), Imath::Color4f( std::numeric_limits::infinity() ) + ) ); addChild( new ObjectPlug( "__tileStats", Gaffer::Plug::Out, new IECore::V3dData() ) ); addChild( new ObjectPlug( "__allStats", Gaffer::Plug::Out, new IECore::V3dData() ) ); @@ -419,8 +428,8 @@ void ImageStats::compute( ValuePlug *output, const Context *context ) const IECore::ConstFloatVectorDataPtr channelData = flattenedInPlug()->channelDataPlug()->getValue(); - float min = std::numeric_limits::max(); - float max = std::numeric_limits::lowest(); + float min = std::numeric_limits::infinity(); + float max = -std::numeric_limits::infinity(); double sum = 0.; const std::vector &channel = channelData->readable(); @@ -444,8 +453,8 @@ void ImageStats::compute( ValuePlug *output, const Context *context ) const static_cast( output )->setValue( new IECore::V3dData( Imath::V3d( 0 ) ) ); return; } - float min = std::numeric_limits::max(); - float max = std::numeric_limits::lowest(); + float min = std::numeric_limits::infinity(); + float max = -std::numeric_limits::infinity(); double sum = 0.; // We traverse in TopToBottom order because floating point precision means that changing