|
36 | 36 | ########################################################################## |
37 | 37 |
|
38 | 38 | import unittest |
39 | | -import os |
| 39 | +import random |
40 | 40 | import imath |
41 | 41 |
|
42 | 42 | import IECore |
@@ -305,5 +305,121 @@ def testFormatAffectsOutput( self ) : |
305 | 305 | crop["format"].setValue( GafferImage.Format( 100, 200 ) ) |
306 | 306 | self.assertIn( crop["out"]["dataWindow"], { x[0] for x in cs } ) |
307 | 307 |
|
| 308 | + def testAutoArea( self ) : |
| 309 | + |
| 310 | + # Rectangle will have a data window fitted perfectly to |
| 311 | + # the rectangle it draws. |
| 312 | + rectangle = GafferImage.Rectangle() |
| 313 | + |
| 314 | + # Merging over a constant (even with zero alpha) will |
| 315 | + # destroy that data window. |
| 316 | + constant = GafferImage.Constant() |
| 317 | + constant["color"]["a"].setValue( 0 ) |
| 318 | + |
| 319 | + merge = GafferImage.Merge() |
| 320 | + merge["in"][0].setInput( constant["out"] ) |
| 321 | + merge["in"][1].setInput( rectangle["out"] ) |
| 322 | + |
| 323 | + # But we can restore it using a crop with `AreaSource.Auto`. |
| 324 | + crop = GafferImage.Crop() |
| 325 | + crop["in"].setInput( merge["out"] ) |
| 326 | + crop["areaSource"].setValue( crop.AreaSource.Auto ) |
| 327 | + crop["affectDisplayWindow"].setValue( False ) |
| 328 | + rectangle["lineWidth"].setValue( 0.5 ) |
| 329 | + |
| 330 | + random.seed( 100 ) |
| 331 | + for i in range( 0, 10 ) : |
| 332 | + |
| 333 | + area = imath.Box2f() |
| 334 | + for p in range( 0, 2 ) : |
| 335 | + area.extendBy( imath.V2f( random.uniform( 0, 1000 ), random.uniform( 0, 1000 ) ) ) |
| 336 | + |
| 337 | + with self.subTest( area = area ) : |
| 338 | + |
| 339 | + rectangle["area"].setValue( area ) |
| 340 | + self.assertEqual( crop["out"].dataWindow(), rectangle["out"].dataWindow() ) |
| 341 | + |
| 342 | + rectangle["color"].setValue( imath.Color4f( 0 ) ) |
| 343 | + self.assertTrue( crop["out"].dataWindow().isEmpty() ) |
| 344 | + |
| 345 | + def testEmptyAutoArea( self ) : |
| 346 | + |
| 347 | + constant = GafferImage.Constant() |
| 348 | + constant["color"]["a"].setValue( 0 ) |
| 349 | + |
| 350 | + crop = GafferImage.Crop() |
| 351 | + crop["in"].setInput( constant["out"] ) |
| 352 | + crop["areaSource"].setValue( crop.AreaSource.Auto ) |
| 353 | + crop["affectDisplayWindow"].setValue( False ) |
| 354 | + |
| 355 | + self.assertTrue( crop["out"].dataWindow().isEmpty() ) |
| 356 | + |
| 357 | + def testAutoAreaReusesTileResults( self ) : |
| 358 | + |
| 359 | + constant = GafferImage.Constant() |
| 360 | + constant["color"].setValue( imath.Color4f( 1 ) ) |
| 361 | + constant["format"].setValue( |
| 362 | + GafferImage.Format( int( GafferImage.ImagePlug.tileSize() * 2.5 ), int( GafferImage.ImagePlug.tileSize() * 3.5 ) ) |
| 363 | + ) |
| 364 | + |
| 365 | + crop = GafferImage.Crop() |
| 366 | + crop["in"].setInput( constant["out"] ) |
| 367 | + crop["areaSource"].setValue( crop.AreaSource.Auto ) |
| 368 | + |
| 369 | + # Limit to one thread to avoid concurrent computes of the same thing. |
| 370 | + with IECore.tbb_global_control( |
| 371 | + IECore.tbb_global_control.parameter.max_allowed_parallelism, 1 |
| 372 | + ) : |
| 373 | + # Compute the entire image. |
| 374 | + with Gaffer.PerformanceMonitor() as monitor : |
| 375 | + self.assertImagesEqual( crop["out"], crop["in"] ) |
| 376 | + |
| 377 | + # All tiles of the constant are the same, so there is only one compute. |
| 378 | + self.assertEqual( monitor.plugStatistics( constant["out"]["channelData"] ).computeCount, 1 ) |
| 379 | + # The tile auto-areas can be shared for all tiles with the same local |
| 380 | + # crop window. Which gives us 4 unique results even though there are |
| 381 | + # 12 tiles. |
| 382 | + self.assertEqual( monitor.plugStatistics( crop["__tileAutoArea"] ).computeCount, 4 ) |
| 383 | + |
| 384 | + def testDeepAutoArea( self ) : |
| 385 | + |
| 386 | + reader = GafferImage.ImageReader() |
| 387 | + reader["fileName"].setValue( self.imagesPath() / "representativeDeepImage.exr" ) |
| 388 | + |
| 389 | + slice = GafferImage.DeepSlice() |
| 390 | + slice["in"].setInput( reader["out"] ) |
| 391 | + slice["nearClip"]["enabled"].setValue( True ) |
| 392 | + slice["nearClip"]["value"].setValue( 2.86 ) |
| 393 | + slice["farClip"]["enabled"].setValue( True ) |
| 394 | + slice["farClip"]["value"].setValue( 3.6 ) |
| 395 | + |
| 396 | + crop = GafferImage.Crop() |
| 397 | + crop["in"].setInput( slice["out"] ) |
| 398 | + crop["areaSource"].setValue( crop.AreaSource.Auto ) |
| 399 | + crop["affectDisplayWindow"].setValue( False ) |
| 400 | + |
| 401 | + self.assertEqual( |
| 402 | + crop["out"].dataWindow(), |
| 403 | + imath.Box2i( |
| 404 | + imath.V2i( 14, 3 ), |
| 405 | + imath.V2i( 93, 56 ) |
| 406 | + ) |
| 407 | + ) |
| 408 | + |
| 409 | + def testChannelDataOnlyAffectsDataWindowForAutoArea( self ) : |
| 410 | + |
| 411 | + constant = GafferImage.Constant() |
| 412 | + crop = GafferImage.Crop() |
| 413 | + crop["in"].setInput( constant["out"] ) |
| 414 | + |
| 415 | + cs = GafferTest.CapturingSlot( crop.plugDirtiedSignal() ) |
| 416 | + constant["color"]["r"].setValue( 0.1 ) |
| 417 | + self.assertNotIn( crop["out"]["dataWindow"], { x[0] for x in cs } ) |
| 418 | + |
| 419 | + crop["areaSource"].setValue( crop.AreaSource.Auto ) |
| 420 | + del cs[:] |
| 421 | + constant["color"]["r"].setValue( 0.2 ) |
| 422 | + self.assertIn( crop["out"]["dataWindow"], { x[0] for x in cs } ) |
| 423 | + |
308 | 424 | if __name__ == "__main__": |
309 | 425 | unittest.main() |
0 commit comments