|
30 | 30 | import java.util.ArrayList; |
31 | 31 | import java.util.Collection; |
32 | 32 | import java.util.List; |
| 33 | +import java.util.stream.Stream; |
33 | 34 |
|
| 35 | +import ij.IJ; |
34 | 36 | import ij.ImagePlus; |
35 | 37 | import ij.measure.Calibration; |
36 | 38 | import ij.measure.ResultsTable; |
@@ -378,6 +380,7 @@ else if (contains(CENTROID)) |
378 | 380 | results.avgThickness = algo.analyzeRegions(image, labels, calib); |
379 | 381 | } |
380 | 382 |
|
| 383 | + this.fireStatusChanged(this, ""); |
381 | 384 | return results; |
382 | 385 | } |
383 | 386 |
|
@@ -405,170 +408,190 @@ private ResultsTable populateTable(Results results) |
405 | 408 | table.addLabel("" + results.labels[i]); |
406 | 409 | } |
407 | 410 |
|
408 | | - if (features.contains(PIXEL_COUNT)) |
409 | | - { |
410 | | - addColumnToTable(table, "PixelCount", results.pixelCounts); |
411 | | - } |
412 | | - |
413 | | - if (features.contains(AREA)) |
414 | | - { |
415 | | - for (int i = 0; i < nLabels; i++) |
416 | | - { |
417 | | - table.setValue("Area", i, results.intrinsicVolumes[i].area); |
418 | | - } |
419 | | - } |
420 | | - |
421 | | - if (features.contains(PERIMETER)) |
422 | | - { |
423 | | - for (int i = 0; i < nLabels; i++) |
424 | | - { |
425 | | - table.setValue("Perimeter", i, results.intrinsicVolumes[i].perimeter); |
426 | | - } |
427 | | - } |
428 | | - |
429 | | - if (features.contains(CIRCULARITY)) |
430 | | - { |
431 | | - double[] circularities = IntrinsicVolumes2DUtils.computeCircularities(results.intrinsicVolumes); |
432 | | - addColumnToTable(table, "Circularity", circularities); |
433 | | - } |
434 | | - |
435 | | - if (features.contains(EULER_NUMBER)) |
436 | | - { |
437 | | - for (int i = 0; i < nLabels; i++) |
438 | | - { |
439 | | - table.setValue("EulerNumber", i, results.intrinsicVolumes[i].eulerNumber); |
440 | | - } |
441 | | - } |
442 | | - |
443 | | - if (features.contains(BOUNDING_BOX)) |
444 | | - { |
445 | | - for (int i = 0; i < nLabels; i++) |
446 | | - { |
447 | | - Box2D box = results.boundingBoxes[i]; |
448 | | - table.setValue("Box.X.Min", i, box.getXMin()); |
449 | | - table.setValue("Box.X.Max", i, box.getXMax()); |
450 | | - table.setValue("Box.Y.Min", i, box.getYMin()); |
451 | | - table.setValue("Box.Y.Max", i, box.getYMax()); |
452 | | - } |
453 | | - } |
454 | | - |
455 | | - if (features.contains(CENTROID)) |
456 | | - { |
457 | | - for (int i = 0; i < nLabels; i++) |
458 | | - { |
459 | | - Point2D center = results.centroids[i]; |
460 | | - table.setValue("Centroid.X", i, center.getX()); |
461 | | - table.setValue("Centroid.Y", i, center.getY()); |
462 | | - } |
463 | | - } |
464 | | - |
465 | | - if (features.contains(EQUIVALENT_ELLIPSE)) |
466 | | - { |
467 | | - for (int i = 0; i < nLabels; i++) |
468 | | - { |
469 | | - Ellipse elli = results.ellipses[i]; |
470 | | - Point2D center = elli.center(); |
471 | | - table.setValue("Ellipse.Center.X", i, center.getX()); |
472 | | - table.setValue("Ellipse.Center.Y", i, center.getY()); |
473 | | - table.setValue("Ellipse.Radius1", i, elli.radius1()); |
474 | | - table.setValue("Ellipse.Radius2", i, elli.radius2()); |
475 | | - table.setValue("Ellipse.Orientation", i, elli.orientation()); |
476 | | - } |
477 | | - } |
478 | | - |
479 | | - if (features.contains(ELLIPSE_ELONGATION)) |
480 | | - { |
481 | | - double[] elong = new double[nLabels]; |
482 | | - for (int i = 0; i < nLabels; i++) |
483 | | - { |
484 | | - Ellipse elli = results.ellipses[i]; |
485 | | - elong[i] = elli.radius1() / elli.radius2(); |
486 | | - } |
487 | | - addColumnToTable(table, "Ellipse.Elong", elong); |
488 | | - } |
489 | | - |
490 | | - if (features.contains(CONVEXITY)) |
491 | | - { |
492 | | - for (int i = 0; i < nLabels; i++) |
493 | | - { |
494 | | - table.setValue("ConvexArea", i, results.convexities[i].convexArea); |
495 | | - table.setValue("Convexity", i, results.convexities[i].convexity); |
496 | | - } |
497 | | - } |
498 | | - |
499 | | - if (features.contains(MAX_FERET_DIAMETER)) |
500 | | - { |
501 | | - for (int i = 0; i < nLabels; i++) |
502 | | - { |
503 | | - table.setValue("MaxFeretDiam", i, results.maxFeretDiams[i].diameter()); |
504 | | - table.setValue("MaxFeretDiamAngle", i, Math.toDegrees(results.maxFeretDiams[i].angle())); |
505 | | - } |
506 | | - } |
507 | | - |
508 | | - if (features.contains(ORIENTED_BOX)) |
509 | | - { |
510 | | - for (int i = 0; i < nLabels; i++) |
511 | | - { |
512 | | - OrientedBox2D obox = results.orientedBoxes[i]; |
513 | | - Point2D center = obox.center(); |
514 | | - table.setValue("OBox.Center.X", i, center.getX()); |
515 | | - table.setValue("OBox.Center.Y", i, center.getY()); |
516 | | - table.setValue("OBox.Length", i, obox.length()); |
517 | | - table.setValue("OBox.Width", i, obox.width()); |
518 | | - table.setValue("OBox.Orientation", i, obox.orientation()); |
519 | | - } |
520 | | - } |
521 | | - |
522 | | - if (features.contains(GEODESIC_DIAMETER)) |
523 | | - { |
524 | | - for (int i = 0; i < nLabels; i++) |
525 | | - { |
526 | | - GeodesicDiameter.Result result = results.geodDiams[i]; |
527 | | - table.setValue("GeodesicDiameter", i, result.diameter); |
528 | | - } |
529 | | - } |
530 | | - |
531 | | - if (features.contains(TORTUOSITY)) |
532 | | - { |
533 | | - double[] tortuosity = new double[nLabels]; |
534 | | - for (int i = 0; i < nLabels; i++) |
535 | | - { |
536 | | - tortuosity[i] = results.geodDiams[i].diameter / results.maxFeretDiams[i].diameter(); |
537 | | - } |
538 | | - addColumnToTable(table, "Tortuosity", tortuosity); |
539 | | - } |
540 | | - |
541 | | - if (features.contains(MAX_INSCRIBED_DISK)) |
542 | | - { |
543 | | - for (int i = 0; i < nLabels; i++) |
544 | | - { |
545 | | - Point2D center = results.inscrDiscs[i].getCenter(); |
546 | | - table.setValue("InscrDisc.Center.X", i, center.getX()); |
547 | | - table.setValue("InscrDisc.Center.Y", i, center.getY()); |
548 | | - table.setValue("InscrDisc.Radius", i, results.inscrDiscs[i].getRadius()); |
549 | | - } |
550 | | - } |
551 | | - |
552 | | - if (features.contains(AVERAGE_THICKNESS)) |
553 | | - { |
554 | | - for (int i = 0; i < nLabels; i++) |
555 | | - { |
556 | | - AverageThickness.Result res = results.avgThickness[i]; |
557 | | - table.setValue("AverageThickness", i, res.avgThickness); |
558 | | - } |
559 | | - } |
560 | | - |
561 | | - if (features.contains(GEODESIC_ELONGATION)) |
562 | | - { |
563 | | - double[] elong = new double[nLabels]; |
564 | | - for (int i = 0; i < nLabels; i++) |
565 | | - { |
566 | | - elong[i] = results.geodDiams[i].diameter |
567 | | - / (results.inscrDiscs[i].getRadius() * 2); |
568 | | - } |
569 | | - addColumnToTable(table, "GeodesicElongation", elong); |
570 | | - } |
571 | | - |
| 411 | + /** |
| 412 | + * Iterate over features, in the order they are specified. |
| 413 | + */ |
| 414 | + for (Feature feature : features) |
| 415 | + { |
| 416 | + switch (feature) |
| 417 | + { |
| 418 | + case PIXEL_COUNT: |
| 419 | + { |
| 420 | + addColumnToTable(table, "PixelCount", results.pixelCounts); |
| 421 | + break; |
| 422 | + } |
| 423 | + case AREA: |
| 424 | + { |
| 425 | + double[] areas = Stream.of(results.intrinsicVolumes) |
| 426 | + .mapToDouble(res -> res.area) |
| 427 | + .toArray(); |
| 428 | + addColumnToTable(table, "Area", areas); |
| 429 | + break; |
| 430 | + } |
| 431 | + case PERIMETER: |
| 432 | + { |
| 433 | + double[] perimeters = Stream.of(results.intrinsicVolumes) |
| 434 | + .mapToDouble(res -> res.perimeter) |
| 435 | + .toArray(); |
| 436 | + addColumnToTable(table, "Perimeter", perimeters); |
| 437 | + break; |
| 438 | + } |
| 439 | + case CIRCULARITY: |
| 440 | + { |
| 441 | + double[] circularities = IntrinsicVolumes2DUtils.computeCircularities(results.intrinsicVolumes); |
| 442 | + addColumnToTable(table, "Circularity", circularities); |
| 443 | + break; |
| 444 | + } |
| 445 | + case EULER_NUMBER: |
| 446 | + { |
| 447 | + double[] eulerNumbers = Stream.of(results.intrinsicVolumes) |
| 448 | + .mapToDouble(res -> res.eulerNumber) |
| 449 | + .toArray(); |
| 450 | + addColumnToTable(table, "EulerNumber", eulerNumbers); |
| 451 | + break; |
| 452 | + } |
| 453 | + case BOUNDING_BOX: |
| 454 | + { |
| 455 | + for (int i = 0; i < nLabels; i++) |
| 456 | + { |
| 457 | + Box2D box = results.boundingBoxes[i]; |
| 458 | + table.setValue("Box.X.Min", i, box.getXMin()); |
| 459 | + table.setValue("Box.X.Max", i, box.getXMax()); |
| 460 | + table.setValue("Box.Y.Min", i, box.getYMin()); |
| 461 | + table.setValue("Box.Y.Max", i, box.getYMax()); |
| 462 | + } |
| 463 | + break; |
| 464 | + } |
| 465 | + case CENTROID: |
| 466 | + { |
| 467 | + for (int i = 0; i < nLabels; i++) |
| 468 | + { |
| 469 | + Point2D center = results.centroids[i]; |
| 470 | + table.setValue("Centroid.X", i, center.getX()); |
| 471 | + table.setValue("Centroid.Y", i, center.getY()); |
| 472 | + } |
| 473 | + break; |
| 474 | + } |
| 475 | + case EQUIVALENT_ELLIPSE: |
| 476 | + { |
| 477 | + for (int i = 0; i < nLabels; i++) |
| 478 | + { |
| 479 | + Ellipse elli = results.ellipses[i]; |
| 480 | + Point2D center = elli.center(); |
| 481 | + table.setValue("Ellipse.Center.X", i, center.getX()); |
| 482 | + table.setValue("Ellipse.Center.Y", i, center.getY()); |
| 483 | + table.setValue("Ellipse.Radius1", i, elli.radius1()); |
| 484 | + table.setValue("Ellipse.Radius2", i, elli.radius2()); |
| 485 | + table.setValue("Ellipse.Orientation", i, elli.orientation()); |
| 486 | + } |
| 487 | + break; |
| 488 | + } |
| 489 | + case ELLIPSE_ELONGATION: |
| 490 | + { |
| 491 | + double[] elong = new double[nLabels]; |
| 492 | + for (int i = 0; i < nLabels; i++) |
| 493 | + { |
| 494 | + Ellipse elli = results.ellipses[i]; |
| 495 | + elong[i] = elli.radius1() / elli.radius2(); |
| 496 | + } |
| 497 | + addColumnToTable(table, "Ellipse.Elong", elong); |
| 498 | + break; |
| 499 | + } |
| 500 | + case CONVEXITY: |
| 501 | + { |
| 502 | + for (int i = 0; i < nLabels; i++) |
| 503 | + { |
| 504 | + table.setValue("ConvexArea", i, results.convexities[i].convexArea); |
| 505 | + table.setValue("Convexity", i, results.convexities[i].convexity); |
| 506 | + } |
| 507 | + break; |
| 508 | + } |
| 509 | + case MAX_FERET_DIAMETER: |
| 510 | + { |
| 511 | + for (int i = 0; i < nLabels; i++) |
| 512 | + { |
| 513 | + table.setValue("MaxFeretDiam", i, results.maxFeretDiams[i].diameter()); |
| 514 | + table.setValue("MaxFeretDiamAngle", i, Math.toDegrees(results.maxFeretDiams[i].angle())); |
| 515 | + } |
| 516 | + break; |
| 517 | + } |
| 518 | + case ORIENTED_BOX: |
| 519 | + { |
| 520 | + for (int i = 0; i < nLabels; i++) |
| 521 | + { |
| 522 | + OrientedBox2D obox = results.orientedBoxes[i]; |
| 523 | + Point2D center = obox.center(); |
| 524 | + table.setValue("OBox.Center.X", i, center.getX()); |
| 525 | + table.setValue("OBox.Center.Y", i, center.getY()); |
| 526 | + table.setValue("OBox.Length", i, obox.length()); |
| 527 | + table.setValue("OBox.Width", i, obox.width()); |
| 528 | + table.setValue("OBox.Orientation", i, obox.orientation()); |
| 529 | + } |
| 530 | + break; |
| 531 | + } |
| 532 | + case ORIENTED_BOX_ELONGATION: |
| 533 | + { |
| 534 | + double[] elongations = Stream.of(results.orientedBoxes) |
| 535 | + .mapToDouble(obox -> obox.length() / obox.width()) |
| 536 | + .toArray(); |
| 537 | + addColumnToTable(table, "OBox.Elongation", elongations); |
| 538 | + break; |
| 539 | + } |
| 540 | + case GEODESIC_DIAMETER: |
| 541 | + { |
| 542 | + double[] diameter = Stream.of(results.geodDiams) |
| 543 | + .mapToDouble(gdData -> gdData.diameter) |
| 544 | + .toArray(); |
| 545 | + addColumnToTable(table, "GeodesicDiameter", diameter); |
| 546 | + break; |
| 547 | + } |
| 548 | + case TORTUOSITY: |
| 549 | + { |
| 550 | + double[] tortuosity = new double[nLabels]; |
| 551 | + for (int i = 0; i < nLabels; i++) |
| 552 | + { |
| 553 | + tortuosity[i] = results.geodDiams[i].diameter / results.maxFeretDiams[i].diameter(); |
| 554 | + } |
| 555 | + addColumnToTable(table, "Tortuosity", tortuosity); |
| 556 | + break; |
| 557 | + } |
| 558 | + case MAX_INSCRIBED_DISK: |
| 559 | + { |
| 560 | + for (int i = 0; i < nLabels; i++) |
| 561 | + { |
| 562 | + Point2D center = results.inscrDiscs[i].getCenter(); |
| 563 | + table.setValue("InscrDisc.Center.X", i, center.getX()); |
| 564 | + table.setValue("InscrDisc.Center.Y", i, center.getY()); |
| 565 | + table.setValue("InscrDisc.Radius", i, results.inscrDiscs[i].getRadius()); |
| 566 | + } |
| 567 | + break; |
| 568 | + } |
| 569 | + case AVERAGE_THICKNESS: |
| 570 | + { |
| 571 | + for (int i = 0; i < nLabels; i++) |
| 572 | + { |
| 573 | + AverageThickness.Result res = results.avgThickness[i]; |
| 574 | + table.setValue("AverageThickness", i, res.avgThickness); |
| 575 | + } |
| 576 | + break; |
| 577 | + } |
| 578 | + case GEODESIC_ELONGATION: |
| 579 | + { |
| 580 | + double[] elong = new double[nLabels]; |
| 581 | + for (int i = 0; i < nLabels; i++) |
| 582 | + { |
| 583 | + elong[i] = results.geodDiams[i].diameter / (results.inscrDiscs[i].getRadius() * 2); |
| 584 | + } |
| 585 | + addColumnToTable(table, "GeodesicElongation", elong); |
| 586 | + break; |
| 587 | + } |
| 588 | + default: |
| 589 | + { |
| 590 | + IJ.log("Unknown feature: " + feature.toString()); |
| 591 | + } |
| 592 | + } |
| 593 | + } |
| 594 | + |
572 | 595 | this.fireStatusChanged(this, ""); |
573 | 596 | return table; |
574 | 597 | } |
|
0 commit comments