Skip to content

Commit 1cdfdd6

Browse files
committed
ImgMath: assertions in the saturation performance benchmark,
which now runs on the sample leaf.jpg image.
1 parent 2c0ca5b commit 1cdfdd6

File tree

1 file changed

+150
-69
lines changed

1 file changed

+150
-69
lines changed

src/test/java/net/imglib2/algorithm/math/ImgMathTest.java

Lines changed: 150 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,16 @@
1919

2020
import static org.junit.Assert.assertTrue;
2121

22+
import java.awt.image.BufferedImage;
23+
import java.awt.image.PixelGrabber;
24+
import java.io.ByteArrayInputStream;
25+
import java.net.URL;
26+
import java.nio.ByteBuffer;
27+
import java.nio.channels.Channels;
28+
import java.nio.channels.ReadableByteChannel;
29+
30+
import javax.imageio.ImageIO;
31+
2232
import org.junit.Test;
2333

2434
import net.imglib2.Cursor;
@@ -31,6 +41,7 @@
3141
import net.imglib2.img.cell.CellImg;
3242
import net.imglib2.img.cell.CellImgFactory;
3343
import net.imglib2.type.numeric.ARGBType;
44+
import net.imglib2.type.numeric.RealType;
3445
import net.imglib2.type.numeric.integer.LongType;
3546
import net.imglib2.type.numeric.integer.UnsignedByteType;
3647
import net.imglib2.type.numeric.integer.UnsignedShortType;
@@ -310,31 +321,75 @@ protected boolean testIfThenElse() {
310321
var( "max" ) ) ) ) )
311322
.into( saturation );
312323

313-
float sum = 0;
314-
315-
for ( final FloatType t : saturation )
316-
sum += t.get();
324+
final long sum = sumAsInts( saturation, 255.0 );
317325

318326
// Ignore floating-point error
319-
System.out.println( "IfThenElse: saturation sum is " + (int)sum + ", expected: " + (int)(saturation_sum / 255.0f) );
327+
System.out.println( "IfThenElse: saturation sum is " + sum + ", expected: " + saturation_sum );
320328

321-
return (int)sum == (int)(saturation_sum / 255.0f);
329+
return sum == saturation_sum;
322330
}
323331

324-
protected boolean testSaturationPerformance( final int n_iterations, final boolean print ) {
325-
final int[] leaf_crop_pix = new int[]{-7430893, -6115530, -4275105, -3354241, -2960497, -3026034, -4012171, -4735905, -4538526, -3814794, -8219392, -7101930, -5589438, -3946389, -3223163, -3419766, -4538005, -5524656, -5589681, -4735134, -8153344, -7890174, -6773213, -5392819, -4406935, -4274320, -5260715, -6247114, -6444498, -6181573, -7890176, -8087552, -7562481, -6576333, -5590446, -5918133, -6509772, -7429350, -7495918, -7364580, -7955694, -8415744, -8349952, -8086528, -7626752, -7560684, -7955442, -8284407, -8218869, -7955692, -7692270, -8022011, -8219390, -8350201, -8022262, -8021490, -8350200, -8547579, -8481786, -8087283, -7561208, -7956218, -8351225, -8680439, -8812276, -8811001, -8876796, -8942336, -8744959, -8415994, -8087552, -8087552, -8679166, -9075199, -9536000, -9337600, -9271808, -9139968, -8876544, -8547584, -8679168, -8415744, -8415744, -9008384, -9666560, -9666816, -9534976, -9205760, -8942336, -8679168, -8548352, -8087552, -8086528, -8547328, -9074176, -9732608, -9534976, -9271552, -8942592, -8744960};
326-
final long saturation_sum = 21367;
332+
/**
333+
* Emulate what ImageJ ij.process.ColorProcessor does: multiply by 255.0d and cast to int.
334+
*
335+
* @param rai
336+
* @param factor
337+
* @return
338+
*/
339+
static private final < O extends RealType< O > > long sumAsInts( final RandomAccessibleInterval< O > rai, final double factor )
340+
{
341+
long sum = 0;
327342

328-
final long[] dims = new long[]{ 10, 10 };
343+
for ( final O t : Views.iterable( rai ) )
344+
sum += (int)(t.getRealFloat() * factor);
345+
346+
return sum;
347+
}
348+
349+
protected boolean testSaturationPerformance( final int n_iterations, final boolean print )
350+
{
351+
// Small cut out
352+
//final int[] leaf_pix = new int[]{-7430893, -6115530, -4275105, -3354241, -2960497, -3026034, -4012171, -4735905, -4538526, -3814794, -8219392, -7101930, -5589438, -3946389, -3223163, -3419766, -4538005, -5524656, -5589681, -4735134, -8153344, -7890174, -6773213, -5392819, -4406935, -4274320, -5260715, -6247114, -6444498, -6181573, -7890176, -8087552, -7562481, -6576333, -5590446, -5918133, -6509772, -7429350, -7495918, -7364580, -7955694, -8415744, -8349952, -8086528, -7626752, -7560684, -7955442, -8284407, -8218869, -7955692, -7692270, -8022011, -8219390, -8350201, -8022262, -8021490, -8350200, -8547579, -8481786, -8087283, -7561208, -7956218, -8351225, -8680439, -8812276, -8811001, -8876796, -8942336, -8744959, -8415994, -8087552, -8087552, -8679166, -9075199, -9536000, -9337600, -9271808, -9139968, -8876544, -8547584, -8679168, -8415744, -8415744, -9008384, -9666560, -9666816, -9534976, -9205760, -8942336, -8679168, -8548352, -8087552, -8086528, -8547328, -9074176, -9732608, -9534976, -9271552, -8942592, -8744960};
353+
//final int width = 10,
354+
// height = 10;
355+
//final long saturation_sum = 21367;
356+
357+
// Full image 507x446 pixels
358+
final int[] leaf_pix;
359+
final int width = 507,
360+
height = 446;
361+
final long saturation_sum = 23641758; // Sum of saturation values * 255.0, each cast to int.
362+
363+
try {
364+
final URL url = new URL( "https://imagej.nih.gov/ij/images/leaf.jpg" );
365+
//final URL url = new URL( "http://127.0.0.1/images/leaf.jpg" );
366+
final ReadableByteChannel rbc = Channels.newChannel( url.openStream() );
367+
final byte[] bytes = new byte[ 36642 ];
368+
final ByteBuffer bb = ByteBuffer.wrap( bytes );
369+
rbc.read( bb );
370+
371+
final BufferedImage bi = ImageIO.read( new ByteArrayInputStream( bytes ) );
372+
leaf_pix = new int[width * height];
373+
final PixelGrabber pg = new PixelGrabber( bi, 0, 0, width, height, leaf_pix, 0, width );
374+
try {
375+
pg.grabPixels();
376+
} catch (InterruptedException e){};
377+
378+
} catch (Exception e) {
379+
e.printStackTrace();
380+
return false;
381+
}
382+
383+
final long[] dims = new long[]{ width, height };
329384

330385
// Fails, don't know why
331-
//final ArrayImg< ARGBType, IntArray > rgb = new ArrayImg< ARGBType, IntArray >( new IntArray( leaf_crop_pix ), dims, new Fraction() );
386+
//final ArrayImg< ARGBType, IntArray > rgb = new ArrayImg< ARGBType, IntArray >( new IntArray( leaf_pix ), dims, new Fraction() );
332387

333388
final ArrayImg< ARGBType, ? > rgb = new ArrayImgFactory< ARGBType >( new ARGBType() ).create( dims );
334389
int k = 0;
335390
for ( final ARGBType t : rgb )
336391
{
337-
t.set( leaf_crop_pix[ k++ ] );
392+
t.set( leaf_pix[ k++ ] );
338393
}
339394

340395
final IterableInterval< UnsignedByteType >
@@ -347,77 +402,93 @@ protected boolean testSaturationPerformance( final int n_iterations, final boole
347402
long minLM = Long.MAX_VALUE,
348403
maxLM = 0;
349404
double meanLM = 0;
405+
406+
// Compute saturation
407+
final Compute op1 =
408+
compute( let( "red", red,
409+
"green", green,
410+
"blue", blue,
411+
"max", max( var( "red" ), var( "green" ), var( "blue" ) ),
412+
"min", min( var( "red" ), var( "green" ), var( "blue" ) ),
413+
IF ( EQ( 0, var( "max" ) ),
414+
0,
415+
mul( div( sub( var( "max" ), var( "min" ) ),
416+
var( "max" ) ),
417+
255.0f ) ) ) );
350418

351-
for ( int i=0; i < n_iterations; ++i ) {
419+
for ( int i=0; i < n_iterations; ++i )
420+
{
352421
final long t0 = System.nanoTime();
353-
354-
// Compute saturation
355-
compute( let( "red", red,
356-
"green", green,
357-
"blue", blue,
358-
"max", max( var( "red" ), var( "green" ), var( "blue" ) ),
359-
"min", min( var( "red" ), var( "green" ), var( "blue" ) ),
360-
IF ( EQ( 0, var( "max" ) ),
361-
0,
362-
div( sub( var( "max" ), var( "min" ) ),
363-
var( "max" ) ) ) ) )
364-
.into( saturation );
422+
423+
op1.into( saturation );
365424

366425
final long t1 = System.nanoTime();
367426
minLM = Math.min(minLM, t1 - t0);
368427
maxLM = Math.max(maxLM, t1 - t0);
369428
meanLM += (t1 - t0) / (double)(n_iterations);
370429
}
430+
431+
assertTrue( "op1", sumAsInts( saturation, 1.0 ) == saturation_sum );
371432

372433
if ( print ) System.out.println("ImgMath 1 saturation performance: min: " + (minLM / 1000.0) + " ms, max: " + (maxLM / 1000.0) + " ms, mean: " + (meanLM / 1000.0) + " ms");
373434

374435
// Reset
375436
minLM = Long.MAX_VALUE;
376437
maxLM = 0;
377438
meanLM = 0;
439+
440+
// Compute saturation: very slightly slower than with vars (unsurprisingly), but easier to read
441+
final Compute op2 =
442+
compute( let( "max", max( red, green, blue ),
443+
"min", min( red, green, blue ),
444+
IF ( EQ( 0, var( "max" ) ),
445+
0,
446+
div( sub( var( "max" ), var( "min" ) ),
447+
var( "max" ) ) ) ) );
378448

379449
for ( int i=0; i < n_iterations; ++i ) {
380450
final long t0 = System.nanoTime();
381451

382-
// Compute saturation: very slightly slower than with vars (unsurprisingly), but easier to read
383-
compute( let( "max", max( red, green, blue ),
384-
"min", min( red, green, blue ),
385-
IF ( EQ( 0, var( "max" ) ),
386-
0,
387-
div( sub( var( "max" ), var( "min" ) ),
388-
var( "max" ) ) ) ) )
389-
.into( saturation );
452+
op2.into( saturation );
390453

391454
final long t1 = System.nanoTime();
392455
minLM = Math.min(minLM, t1 - t0);
393456
maxLM = Math.max(maxLM, t1 - t0);
394457
meanLM += (t1 - t0) / (double)(n_iterations);
395458
}
459+
460+
if ( print ) System.out.println( "Sum: " + sumAsInts( saturation, 255.0 ) + ", saturation_sum: " + saturation_sum );
461+
462+
assertTrue( "op2", sumAsInts( saturation, 255.0 ) == saturation_sum );
396463

397464
if ( print ) System.out.println("ImgMath 2 saturation performance: min: " + (minLM / 1000.0) + " ms, max: " + (maxLM / 1000.0) + " ms, mean: " + (meanLM / 1000.0) + " ms");
398465

399466
// Reset
400467
minLM = Long.MAX_VALUE;
401468
maxLM = 0;
402469
meanLM = 0;
403-
470+
471+
// Compute saturation: easier to read without vars
472+
final Compute op3 =
473+
compute( let( "max", max( red, green, blue ),
474+
"min", min( red, green, blue ),
475+
IF ( EQ( 0, var( "max" ) ),
476+
THEN( 0 ),
477+
ELSE ( div( sub( var( "max" ), var( "min" ) ),
478+
var( "max" ) ) ) ) ) );
479+
404480
for ( int i=0; i < n_iterations; ++i ) {
405481
final long t0 = System.nanoTime();
406-
407-
// Compute saturation: easier to read without vars
408-
compute( let( "max", max( red, green, blue ),
409-
"min", min( red, green, blue ),
410-
IF ( EQ( 0, var( "max" ) ),
411-
THEN( 0 ),
412-
ELSE ( div( sub( var( "max" ), var( "min" ) ),
413-
var( "max" ) ) ) ) ) )
414-
.into( saturation );
482+
483+
op3.into( saturation );
415484

416485
final long t1 = System.nanoTime();
417486
minLM = Math.min(minLM, t1 - t0);
418487
maxLM = Math.max(maxLM, t1 - t0);
419488
meanLM += (t1 - t0) / (double)(n_iterations);
420489
}
490+
491+
assertTrue( "op3", sumAsInts( saturation, 255.0 ) == saturation_sum );
421492

422493
if ( print ) System.out.println("ImgMath 3 saturation performance: min: " + (minLM / 1000.0) + " ms, max: " + (maxLM / 1000.0) + " ms, mean: " + (meanLM / 1000.0) + " ms");
423494

@@ -446,52 +517,60 @@ protected boolean testSaturationPerformance( final int n_iterations, final boole
446517
cb.next().setReal( b.next().getRealDouble() );
447518
}
448519

520+
// Compute saturation:
521+
final Compute op4 =
522+
compute( let( "max", max( redF, greenF, blueF ),
523+
"min", min( redF, greenF, blueF ),
524+
IF ( EQ( 0, var( "max" ) ),
525+
THEN( 0 ),
526+
ELSE ( div( sub( var( "max" ), var( "min" ) ),
527+
var( "max" ) ) ) ) ) );
528+
449529
for ( int i=0; i < n_iterations; ++i ) {
450530
final long t0 = System.nanoTime();
451531

452-
// Compute saturation:
453-
compute( let( "max", max( redF, greenF, blueF ),
454-
"min", min( redF, greenF, blueF ),
455-
IF ( EQ( 0, var( "max" ) ),
456-
THEN( 0 ),
457-
ELSE ( div( sub( var( "max" ), var( "min" ) ),
458-
var( "max" ) ) ) ) ) )
459-
.into( saturation );
532+
op4.into( saturation );
460533

461534
final long t1 = System.nanoTime();
462535
minLM = Math.min(minLM, t1 - t0);
463536
maxLM = Math.max(maxLM, t1 - t0);
464537
meanLM += (t1 - t0) / (double)(n_iterations);
465538
}
466539

540+
assertTrue( "op4", sumAsInts( saturation, 255.0 ) == saturation_sum );
541+
467542
if ( print ) System.out.println("ImgMath 4 saturation without vars performance: min: " + (minLM / 1000.0) + " ms, max: " + (maxLM / 1000.0) + " ms, mean: " + (meanLM / 1000.0) + " ms");
468543

469544
// Reset
470545
minLM = Long.MAX_VALUE;
471546
maxLM = 0;
472547
meanLM = 0;
548+
549+
// Compute saturation:
550+
final Compute op5 =
551+
compute( let( "red", redF,
552+
"green", greenF,
553+
"blue", blueF,
554+
"max", max( var("red"), var("green"), var("blue") ),
555+
"min", min( var("red"), var("green"), var("blue") ),
556+
IF ( EQ( 0, var( "max" ) ),
557+
THEN( 0 ),
558+
ELSE ( div( sub( var( "max" ), var( "min" ) ),
559+
var( "max" ) ) ) ) ) );
473560

474561
for ( int i=0; i < n_iterations; ++i ) {
475562
final long t0 = System.nanoTime();
476563

477-
// Compute saturation:
478-
compute( let( "red", redF,
479-
"green", greenF,
480-
"blue", blueF,
481-
"max", max( var("red"), var("green"), var("blue") ),
482-
"min", min( var("red"), var("green"), var("blue") ),
483-
IF ( EQ( 0, var( "max" ) ),
484-
THEN( 0 ),
485-
ELSE ( div( sub( var( "max" ), var( "min" ) ),
486-
var( "max" ) ) ) ) ) )
487-
.into( saturation );
564+
op5.into( saturation );
488565

489566
final long t1 = System.nanoTime();
490567
minLM = Math.min(minLM, t1 - t0);
491568
maxLM = Math.max(maxLM, t1 - t0);
492569
meanLM += (t1 - t0) / (double)(n_iterations);
493570
}
494571

572+
assertTrue( "op5", sumAsInts( saturation, 255.0 ) == saturation_sum );
573+
495574
if ( print ) System.out.println("ImgMath 5 saturation with vars performance: min: " + (minLM / 1000.0) + " ms, max: " + (maxLM / 1000.0) + " ms, mean: " + (meanLM / 1000.0) + " ms");
496575

497576
}
@@ -512,11 +591,11 @@ protected boolean testSaturationPerformance( final int n_iterations, final boole
512591
final Cursor< FloatType > cs = saturation.cursor();
513592

514593
while (cs.hasNext()) {
515-
final UnsignedByteType r = cr.next(),
516-
g = cg.next(),
517-
b = cb.next();
518-
final float max = Math.max( r.get(), Math.max( g.get(), b.get() ) ),
519-
min = Math.min( r.get(), Math.min( g.get(), b.get() ) );
594+
final int r = cr.next().getInteger(),
595+
g = cg.next().getInteger(),
596+
b = cb.next().getInteger();
597+
final float max = Math.max( r, Math.max( g, b ) ),
598+
min = Math.min( r, Math.min( g, b ) );
520599
cs.next().set( 0.0f == max ? 0.0f : (max - min) / max );
521600
}
522601

@@ -525,6 +604,8 @@ protected boolean testSaturationPerformance( final int n_iterations, final boole
525604
maxLM = Math.max(maxLM, t1 - t0);
526605
meanLM += (t1 - t0) / (double)(n_iterations);
527606
}
607+
608+
assertTrue( "low-level", sumAsInts( saturation, 255.0 ) == saturation_sum );
528609

529610
if ( print ) System.out.println("Low-level saturation performance: min: " + (minLM / 1000.0) + " ms, max: " + (maxLM / 1000.0) + " ms, mean: " + (meanLM / 1000.0) + " ms");
530611

@@ -626,8 +707,8 @@ public void test1IfThenElse() {
626707

627708
//@Test
628709
public void test1IfThenElsePerformance() {
629-
assertTrue ( testSaturationPerformance( 200, false ) ); // warm-up
630-
assertTrue ( testSaturationPerformance( 200, true ) );
710+
//assertTrue ( testSaturationPerformance( 200, false ) ); // warm-up
711+
assertTrue ( testSaturationPerformance( 30, true ) );
631712
}
632713

633714
@Test

0 commit comments

Comments
 (0)