Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • ida-public/zellige-core
1 result
Show changes
Commits on Source (73)
Showing
with 863 additions and 316 deletions
......@@ -6,7 +6,8 @@
<parent>
<groupId>org.scijava</groupId>
<artifactId>pom-scijava</artifactId>
<version>31.1.0</version>
<version>39.0.0</version>
<relativePath />
</parent>
<groupId>org.example</groupId>
......@@ -48,7 +49,13 @@
</repository>
</repositories>
<build>
<resources>
<resource>
<directory>src/main/resources</directory>
</resource>
</resources>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
......@@ -124,11 +131,11 @@
<artifactId>imagej-legacy</artifactId>
</dependency>
<!-- https://mvnrepository.com/artifact/net.imglib2/imglib2-script -->
<dependency>
<groupId>net.imglib2</groupId>
<artifactId>imglib2-script</artifactId>
</dependency>
<!-- &lt;!&ndash; https://mvnrepository.com/artifact/net.imglib2/imglib2-script &ndash;&gt;-->
<!-- <dependency>-->
<!-- <groupId>net.imglib2</groupId>-->
<!-- <artifactId>imglib2-script</artifactId>-->
<!-- </dependency>-->
<!-- https://mvnrepository.com/artifact/net.imglib2/imglib2 -->
<dependency>
......
......@@ -29,23 +29,49 @@
package fr.pasteur.ida.zellige;
import ch.qos.logback.classic.Level;
import ch.qos.logback.classic.LoggerContext;
import ch.qos.logback.classic.encoder.PatternLayoutEncoder;
import ch.qos.logback.classic.spi.ILoggingEvent;
import ch.qos.logback.core.FileAppender;
import fr.pasteur.ida.zellige.element.ReferenceSurface;
import fr.pasteur.ida.zellige.steps.construction.Construction;
import fr.pasteur.ida.zellige.steps.construction.rounds.ConstructionParameters;
import fr.pasteur.ida.zellige.steps.projection.DisplayParameters;
import fr.pasteur.ida.zellige.steps.projection.ProjectionParameters;
import fr.pasteur.ida.zellige.steps.projection.ReferenceSurfaceProjection;
import fr.pasteur.ida.zellige.steps.selection.Selection;
import fr.pasteur.ida.zellige.steps.selection.classification.ClassificationParameters;
import fr.pasteur.ida.zellige.steps.selection.postTreatment.PostTreatmentParameters;
import fr.pasteur.ida.zellige.steps.selection.pretreatment.PretreatmentParameters;
import ij.IJ;
import ij.ImageJ;
import io.scif.img.IO;
import io.scif.img.SCIFIOImgPlus;
import fr.pasteur.ida.zellige.steps.selection.util.ArgumentCheck;
import io.scif.img.ImgSaver;
import net.imagej.Dataset;
import net.imagej.ImageJ;
import net.imagej.ImgPlus;
import net.imglib2.RandomAccessibleInterval;
import net.imglib2.display.ColorTable;
import net.imglib2.img.Img;
import net.imglib2.img.display.imagej.ImageJFunctions;
import net.imglib2.type.NativeType;
import net.imglib2.type.numeric.RealType;
import net.imglib2.type.numeric.integer.UnsignedShortType;
import net.imglib2.type.numeric.real.FloatType;
import net.imglib2.view.Views;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.text.RandomStringGenerator;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.awt.*;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import static fr.pasteur.ida.zellige.utils.Util.create4dimImage;
/**
......@@ -54,108 +80,13 @@ import java.awt.*;
public class Main
{
private final static Logger LOGGER = LoggerFactory.getLogger( Main.class );
@SuppressWarnings( "unchecked" )
public static < T extends RealType< T > & NativeType< T > > void main( String[] args ) throws Exception
{
// Launch ImageJ.
ImageJ ij = new ImageJ();
// Input of the image.
final String imagePath =// "C:\\Users\\ctrebeau\\Desktop\\Zellige analysis\\files\\SNR\\snr_000\\multiSurfaces\\phantoms_snr0.mat.tif";
args[ 0 ]; /* The image path goes here !!!! */
LOGGER.debug( imagePath );
/* JY version for opening files. */
final SCIFIOImgPlus< ? > imgPlus = IO.openAll( imagePath ).get( 0 );
final Img< T > stackImage = ( Img< T > ) imgPlus.getImg();
/* User Parameters AKA arguments to run the program*/
int amplitude = Integer.parseInt( args[ 1 ] );
int otsu = Integer.parseInt( args[ 2 ] );
int islandSize = Integer.parseInt( args[ 3 ] );
int connexity = Integer.parseInt( args[ 4 ] );
double sigmaXY = Double.parseDouble( args[ 5 ] );
double sigmaZ = Double.parseDouble( args[ 6 ] );
double startingOsSize1 = Double.parseDouble( args[ 7 ] );
int overlap1 = Integer.parseInt( args[ 8 ] );
double connexityRate1 = Double.parseDouble( args[ 9 ] );
double startingOsSize2 = Double.parseDouble( args[ 10 ] );
int overlap2 = Integer.parseInt( args[ 11 ] );
double connexityRate2 = Double.parseDouble( args[ 12 ] );
double surfaceMinSizeFactor = Double.parseDouble( args[ 13 ] );
int delta = Integer.parseInt( args[ 14 ] );
/* End of parameters. */
// Fixed parameters for now...
String filter = "GaussianBlur";
double filterParameter = 2;
/* Print parameters.*/
LOGGER.debug( "Input image : " + imagePath );
LOGGER.debug( "filter : " + filter );
LOGGER.debug( "filter parameter : " + filterParameter );
LOGGER.debug( "amplitude : " + amplitude );
LOGGER.debug( "threshold : " + otsu );
LOGGER.debug( "connexity : " + connexity );
LOGGER.debug( "island size : " + islandSize );
LOGGER.debug( "sigmaXY : " + sigmaXY );
LOGGER.debug( "sigmaZ : " + sigmaZ );
LOGGER.debug( "starting os size1 : " + startingOsSize1 );
LOGGER.debug( "overlap1 :" + overlap1 );
LOGGER.debug( "connexityRate1 :" + connexityRate1 );
LOGGER.debug( "starting os size2 : " + startingOsSize2 );
LOGGER.debug( "overlap2 :" + overlap2 );
LOGGER.debug( "connexityRate2 :" + connexityRate2 );
LOGGER.debug( "surface Minimum size factor : " + surfaceMinSizeFactor );
LOGGER.debug( "delta : " + delta );
LOGGER.debug( System.lineSeparator() );
/* End of Print parameters.*/
PretreatmentParameters pretreatmentParameters = new PretreatmentParameters( filter, filterParameter );
ClassificationParameters classificationParameters = new ClassificationParameters( amplitude, otsu );
PostTreatmentParameters postTreatmentParameters = new PostTreatmentParameters( sigmaXY, sigmaZ, islandSize, connexity );
ProjectionParameters projectionParameters = new ProjectionParameters( delta, "MIP" );// no other method implemented yet.
ConstructionParameters[] constructionParameters = new ConstructionParameters[]{
new ConstructionParameters( startingOsSize1, overlap1, connexityRate1, surfaceMinSizeFactor ),
new ConstructionParameters( startingOsSize2, overlap2, connexityRate2, surfaceMinSizeFactor ) };
DisplayParameters displayParameters = new DisplayParameters(
true,
true,
true,
true,
true, true );
IJ.log( "Type: " + imgPlus.firstElement().getClass().toGenericString() );
if ( stackImage.numDimensions() == 3 )// Is it a stack ?
{
ReferenceSurfaceExtraction< T > rse = new ReferenceSurfaceExtraction<>
( stackImage, stackImage.factory() );
rse.select( pretreatmentParameters, classificationParameters, postTreatmentParameters );
rse.construct( constructionParameters );
rse.project( projectionParameters, displayParameters );
if ( ! GraphicsEnvironment.isHeadless() )
{
try
{
rse.project( projectionParameters, displayParameters );
}
catch ( Exception e )
{
LOGGER.debug( e.getMessage() );
}
}
}
else
{
LOGGER.debug( " This image has to be a z-stack ! " );
}
public static < T extends RealType< T > & NativeType< T > > void main( String [] args ) throws Exception
{
String CSV_FILE ="doc/test.csv";
ReferenceSurfaceExtraction.run( CSV_FILE );
}
}
......@@ -50,18 +50,19 @@ public class Zellige extends ContextCommand
.getPath( "" )
.toAbsolutePath()
.toString();
// String imageFilePath = "C:\\Users\\ctrebeau\\Desktop\\channel_test.tif";
String imageFilePath = "doc/Mouche.tif";
// Launch ImageJ.
ImageJ ij = new ImageJ();
ij.launch( args );
// Load the image.
Object obj = ij.io().open( new File( currentFolder, imageFilePath ).getAbsolutePath() );
Object obj = ij.io().open( new File( imageFilePath ).getAbsolutePath() );
// Display it.
ij.ui().show( obj );
ij.command().run( Zellige.class, true );
}
......
......@@ -30,67 +30,64 @@ package fr.pasteur.ida.zellige.element;
import net.imglib2.img.Img;
import net.imglib2.type.NativeType;
import net.imglib2.type.logic.BitType;
import net.imglib2.type.numeric.RealType;
import net.imglib2.type.numeric.integer.UnsignedShortType;
public class Projection< T extends RealType< T > & NativeType< T > >
{
private final int offset;
private final int deltaZ;
private String method;
private final ReferenceSurface<T> referenceSurface;
private Img< T > projection;
private Img< UnsignedShortType > extractedHeightMap;
private Img< T > segmentedSurface;
private Img< T > reduced3DSpace;
private Img< BitType > segmentedSurfaceMask;
private int index;
private Img<T> subVolume;
public Img< T > getSegmentedSurface()
public Projection( int offset, int deltaZ, String method, ReferenceSurface< T > referenceSurface )
{
return segmentedSurface;
this.offset = offset;
this.deltaZ = deltaZ;
this.method = method;
this.referenceSurface = referenceSurface;
}
public void setSegmentedSurface( Img< T > segmentedSurface )
public Img< T > get()
{
this.segmentedSurface = segmentedSurface;
return projection;
}
public Img< UnsignedShortType > getExtractedHeightMap()
public void setProjection( Img< T > projection )
{
return extractedHeightMap;
this.projection = projection;
}
public void setExtractedHeightMap( Img< UnsignedShortType > extractedHeightMap )
public Img< T > getSubVolume()
{
this.extractedHeightMap = extractedHeightMap;
return subVolume;
}
public Img< T > get()
public int getOffset()
{
return projection;
return offset;
}
public void setProjection( Img< T > projection )
public int getDeltaZ()
{
this.projection = projection;
return deltaZ;
}
public Img< T > getReduced3DSpace()
public String getMethod()
{
return reduced3DSpace;
return method;
}
public void setReduced3DSpace( Img< T > reduced3DSpace )
public void setSubVolume( Img< T > subVolume )
{
this.reduced3DSpace = reduced3DSpace;
this.subVolume = subVolume;
}
public Img< BitType > getSegmentedSurfaceMask()
public void setMethod( String method )
{
return segmentedSurfaceMask;
this.method = method;
}
public void setSegmentedSurfaceMask( Img< BitType > segmentedSurfaceMask )
{
this.segmentedSurfaceMask = segmentedSurfaceMask;
}
}
......@@ -28,6 +28,7 @@
*/
package fr.pasteur.ida.zellige.element;
import net.imglib2.RandomAccess;
import net.imglib2.RandomAccessibleInterval;
import net.imglib2.img.Img;
import net.imglib2.img.ImgFactory;
......@@ -35,14 +36,18 @@ import net.imglib2.type.NativeType;
import net.imglib2.type.numeric.RealType;
import net.imglib2.type.numeric.integer.UnsignedShortType;
import static fr.pasteur.ida.zellige.steps.Utils.setPositionAndGet;
public class ReferenceSurface< T extends RealType< T > & NativeType< T > >
{
private final RandomAccessibleInterval< T > input;
private final ImgFactory< T > factory;
private final Img< UnsignedShortType > zMap;
private final int index;
private Projection< T > projection;
private final String name;
private final Img <T> rawProjection;
public ReferenceSurface( RandomAccessibleInterval< T > input,
ImgFactory< T > factory, Img< UnsignedShortType > zMap, int index )
......@@ -50,13 +55,35 @@ public class ReferenceSurface< T extends RealType< T > & NativeType< T > >
this.input = input;
this.factory = factory;
this.zMap = zMap;
this.projection = new Projection<>();
this.rawProjection = factory.create(zMap);
this.index = index;
this.name = "Reference Surface n°" + (index + 1);
setRawProjection();
}
public Projection< T > getProjection()
/**
* Creates the raw height map projection
*/
private void setRawProjection()
{
return projection;
RandomAccess<T> projectionAccess = rawProjection.randomAccess();
RandomAccess< UnsignedShortType > zMapAccess = zMap.randomAccess();
RandomAccess <T > inputAccess = input.randomAccess();
for ( int x = 0; x < zMap.dimension (0 ); x++ )
{
for ( int y = 0; y <zMap.dimension (1 ); y++ )
{
// Z value on Height Map
int z = setPositionAndGet( zMapAccess, x, y ).getInteger();
if( z > 0 )
{
// pixel value on input
T value = setPositionAndGet( inputAccess, x, y, z - 1 );
// Set value on projection
setPositionAndGet( projectionAccess, x, y ).set( value );
}
}
}
}
public RandomAccessibleInterval< T > getInput()
......@@ -74,14 +101,14 @@ public class ReferenceSurface< T extends RealType< T > & NativeType< T > >
return zMap;
}
public int getIndex()
public String getName()
{
return index;
return name;
}
public void init()
public int getIndex()
{
this.projection = new Projection<>();
return index;
}
}
......
......@@ -149,43 +149,6 @@ public class Surface
return inCommon / ( double ) count;
}
public boolean isTheSameSurfaceAs( Surface other )
{
for ( int i = 0; i <= this.getHeight() - 1; i++ )
{
SurfaceLine refLine = this.get( i );
if ( refLine != null )
{
SurfaceLine toTest = other.get( i );
if ( toTest != null )
{
for ( int j = 0; j < refLine.getLength(); j++ )
{
Pixels refPixels = refLine.get( j );
if ( refPixels != null )
{
Pixels pixelsToTest = toTest.get( j );
if ( pixelsToTest != null )
{
// return false;
// }
if ( ! refPixels.equals( pixelsToTest ) )
{
return false;
}
}
}
}
}
}
}
return true;
}
/**
* Checks if this object shares a majority of {@link Pixels} with another {@link Surface} object.
*
......
......@@ -36,9 +36,7 @@ import java.util.ArrayList;
public abstract class AbstractOSE extends ArrayList< Coordinate >
{
/* Not necessary for the program.*/
private final OSEStartingStatus startingStatus;
/*-------------*/
/**
* The visited status for the 1D and 2D reconstructions.
......@@ -62,10 +60,8 @@ public abstract class AbstractOSE extends ArrayList< Coordinate >
*/
public void set()
{
Integer j = startingStatus.get( this.size() );
startingStatus.put( this.size(), ( j == null ) ? 1 : j + 1 );
startingStatus.compute( this.size(), ( k, j ) -> ( j == null ) ? 1 : j + 1 );
startingStatus.setOSCount();
}
/**
......
......@@ -37,7 +37,6 @@ import java.util.Collection;
public class OSEList extends ArrayList< AbstractOSE >
{
public OSEList()
{
}
......@@ -66,6 +65,10 @@ public class OSEList extends ArrayList< AbstractOSE >
return add;
}
/**
*
* @return the size of the OSE list
*/
public int getSize()
{
int size = 0;
......@@ -76,6 +79,9 @@ public class OSEList extends ArrayList< AbstractOSE >
return size;
}
/**
* Resets to false the visited status
*/
public void reset()
{
for ( AbstractOSE os : this )
......@@ -84,6 +90,10 @@ public class OSEList extends ArrayList< AbstractOSE >
}
}
/**
*
* @return true if the OSE list contains a starting OSE
*/
public boolean containsAStart()
{
for ( AbstractOSE os : this )
......
......@@ -74,14 +74,15 @@ public abstract class SurfaceLine
this.dimension = new Pixels[ length ] ;
set( os );
}
public SurfaceLine( AbstractOSE os, int size )
{
this.dimension = new Pixels[ size] ;
set( os );
}
/**
*
* @param os
* @param overlap
* @param connexity
* @param surfaceLine
* @return
*/
public SurfaceLine match2( AbstractOSE os, int overlap, double connexity, SurfaceLine surfaceLine )
{
int match = 0;
......
......@@ -44,6 +44,15 @@ public class SurfaceLineX extends SurfaceLine
this.setLine( os.get( 0 ).getY() );
}
/**
* Tests if the OS matches the SurfaceLine instance and creates a new SurfaceLine object if so.
*
* @param os - the OS to test against the SurfaceLine instance.
* @param direction - an integer witch indicates the line of the resulting SurfaceLine.
* @param overlap - the minimum number of matching coordinates.
* @param connexity - the minimum percentage of match between the OS and the current instance.
* @return - a new SurfaceLine if there is a match, null otherwise.
*/
public SurfaceLine match( AbstractOSE os, int direction, int overlap, double connexity )
{
SurfaceLineX surfaceLineX = new SurfaceLineX( this.getLength(), this.getLine() + direction );
......@@ -61,12 +70,4 @@ public class SurfaceLineX extends SurfaceLine
super(length, line );
}
public SurfaceLineX( AbstractOSE os, int size )
{
super( os , size);
this.setLine( os.get( 0 ).getY() );
}
}
......@@ -66,8 +66,6 @@ public class SurfaceLineY extends SurfaceLine
* @param connexity - the minimum percentage of match between the OS and the current instance.
* @return - a new SurfaceLine if there is a match, null otherwise.
*/
public SurfaceLine match( AbstractOSE os, int direction, int overlap, double connexity )
{
SurfaceLineY surfaceLineY = new SurfaceLineY( this.getLength(), this.getLine() + direction );
......
package fr.pasteur.ida.zellige.gui;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.fxml.Initializable;
import javafx.scene.control.*;
import javafx.scene.layout.Pane;
import java.io.IOException;
import java.net.URL;
import java.util.ResourceBundle;
public class ChannelPanel extends Pane implements Initializable
{
@FXML
private Spinner<Integer> deltaZ;
@FXML
private ChoiceBox<String> method;
@FXML
private Spinner<Integer> offset;
@FXML
private Button view;
public ChannelPanel( )
{
FXMLLoader fxmlLoader = new FXMLLoader( ChannelPanel.class.getClassLoader().
getResource( "fr.pasteur.ida.zellige.gui.view/ChannelProjection.fxml" ) );
fxmlLoader.setRoot(this);
fxmlLoader.setController( this );
try
{
fxmlLoader.load();
}
catch ( IOException e )
{
e.printStackTrace();
}
}
@Override
public void initialize( URL url, ResourceBundle resourceBundle )
{
SpinnerValueFactory< Integer > valueFactory =
new SpinnerValueFactory.IntegerSpinnerValueFactory( 0, 30, 1, 1 );
deltaZ.setValueFactory( valueFactory );
ObservableList< String > list = FXCollections.observableArrayList( "MIP", "Mean" );
method.setItems( list );
method.getSelectionModel().selectFirst();
SpinnerValueFactory< Integer > valueFactory2 =
new SpinnerValueFactory.IntegerSpinnerValueFactory( 0, 30, 0, 1 );
offset.setValueFactory( valueFactory2 );
}
public Spinner< Integer > getDeltaZ()
{
return deltaZ;
}
public ChoiceBox< String > getMethod()
{
return method;
}
public Spinner< Integer > getOffset()
{
return offset;
}
public Button getView()
{
return view;
}
}
package fr.pasteur.ida.zellige.gui;
import javafx.beans.property.*;
import net.imglib2.img.Img;
import net.imglib2.type.NativeType;
import net.imglib2.type.numeric.RealType;
public class ChannelToolProperty < T extends RealType< T > & NativeType< T > >
{
private final IntegerProperty deltaZ = new SimpleIntegerProperty();
private final IntegerProperty offset = new SimpleIntegerProperty();
private final StringProperty method = new SimpleStringProperty("");
private final SimpleObjectProperty< Img< T > > subVolume = new SimpleObjectProperty<>();
private final SimpleObjectProperty< Img< T > > projection = new SimpleObjectProperty<>();
// private final SimpleObjectProperty< RandomAccessibleInterval<T> > reducedStack = new SimpleObjectProperty<>();
// private final BooleanProperty parameterChanged = new SimpleBooleanProperty( true );
// private final SimpleObjectProperty< RandomAccessibleInterval<T>> projection = new SimpleObjectProperty<>();
public StringProperty getMethod()
{
return method;
}
public IntegerProperty getOffset()
{
return offset;
}
public IntegerProperty getDeltaZ()
{
return deltaZ;
}
// public void setProperties(int delta, int offset, String method)
// {
//
// getDeltaZ().set( delta);
// getOffset().set( offset );
// getMethod().set( method );
// }
public ChannelToolProperty()
{
deltaZ.addListener(( observableValue, number, newValue ) ->
{
if (number.intValue() != newValue.intValue())
{
subVolume.set( null );
projection.set( null );
}
});
offset.addListener(( observableValue, number, newValue ) ->
{
if (number.intValue() != newValue.intValue())
{
subVolume.set( null );
projection.set( null );
}
});
method.addListener(( observableValue, number, newValue ) ->
{
if (! number.equals( newValue))
{
projection.set( null );
}
});
}
public SimpleObjectProperty< Img< T > > getSubVolume()
{
return subVolume;
}
public SimpleObjectProperty< Img< T > > getProjection()
{
return projection;
}
}
package fr.pasteur.ida.zellige.gui;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import java.io.IOException;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.image.ImageView;
import javafx.scene.layout.FlowPane;
import javafx.scene.layout.VBox;
public class ConstructionDisplay extends VBox
{
@FXML
private Label surfaceNb;
@FXML
private FlowPane display;
@FXML
private Label log;
@FXML
private Button minus;
@FXML
private Button plus;
private int surfaceNumber = 1;
private int nbOfSurfaces;
public ConstructionDisplay( )
{
FXMLLoader fxmlLoader = new FXMLLoader( ConstructionDisplay.class.getClassLoader().getResource(
"fr.pasteur.ida.zellige.gui.view/ConstructionDisplay.fxml" ) );
fxmlLoader.setRoot( this );
fxmlLoader.setController( this );
try
{
fxmlLoader.load();
}
catch ( IOException e )
{
e.printStackTrace();
}
}
public void next()
{
if (surfaceNumber == nbOfSurfaces)
{
surfaceNumber = 1;
}
else
{
surfaceNumber++;
}
}
public void previous()
{
if (surfaceNumber == 1)
{
surfaceNumber = nbOfSurfaces;
}
else
{
surfaceNumber--;
}
}
public void set( ImageView image, int index )
{
display.getChildren().add( image );
surfaceNb.setText( "Height map n°" + index );
if ( nbOfSurfaces == 1 )
{
log.setText( "Extraction of " + nbOfSurfaces + " height map." );
}
else
{
log.setText( "Extraction of " + nbOfSurfaces + " height maps." );
}
}
public void setNbOfSurfaces( int nbOfSurfaces )
{
this.nbOfSurfaces = nbOfSurfaces;
}
public Label getLog()
{
return log;
}
public Button getMinus()
{
return minus;
}
public Button getPlus()
{
return plus;
}
public int getSurfaceNumber()
{
return surfaceNumber;
}
public int getNbOfSurfaces()
{
return nbOfSurfaces;
}
public void setSurfaceNumber( int surfaceNumber )
{
this.surfaceNumber = surfaceNumber;
}
public FlowPane getDisplay()
{
return display;
}
}
......@@ -6,13 +6,13 @@
* %%
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
......@@ -28,60 +28,50 @@
*/
package fr.pasteur.ida.zellige.gui;
import javafx.scene.image.ImageView;
import javafx.scene.image.PixelFormat;
import javafx.scene.image.PixelWriter;
import javafx.scene.image.WritableImage;
import javafx.scene.image.*;
import net.imglib2.Cursor;
import net.imglib2.IterableInterval;
import net.imglib2.type.logic.BitType;
import net.imglib2.algorithm.stats.Normalize;
import net.imglib2.img.Img;
import net.imglib2.type.NativeType;
import net.imglib2.type.numeric.RealType;
import net.imglib2.util.ImgUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class ImageFXDisplay
{
private final static Logger LOGGER = LoggerFactory.getLogger( ImageFXDisplay.class );
private final IterableInterval< BitType > input;
private final ImageView[] imageViews;
private final int width;
private final int height;
private final int depth;
public ImageFXDisplay( IterableInterval< BitType > input )
{
this.input = input;
width = ( int ) input.dimension( 0 );
height = ( int ) input.dimension( 1 );
depth = ( int ) input.dimension( 2 );
this.imageViews = new ImageView[ depth ];
}
public void set()
public static < T extends RealType< T > & NativeType< T > > void setSelectedPixels( Img< T > input, ImageView[] imageViews )
{
int[] data2 = convert2( input );
int width = ( int ) input.dimension( 0 );
int height = ( int ) input.dimension( 1 );
int depth = ( int ) input.dimension( 2 );
int[] data = convertToBinary( input, width, height, depth );
for ( int z = 0; z < depth; z++ )
{
WritableImage writableImage = new WritableImage( width, height );
PixelWriter pixelWriter = writableImage.getPixelWriter();
pixelWriter.setPixels( 0, 0, width, height, PixelFormat.getIntArgbInstance(), data2, height * width * z, width );
this.imageViews[ z ] = new ImageView( writableImage );
setImageViews( this.imageViews[ z ] );
pixelWriter.setPixels( 0, 0, width, height, PixelFormat.getIntArgbInstance(), data, height * width * z, width );
ImageView imageView = new ImageView( writableImage );
setImageViews( imageView, width, height , 270);
imageViews[ z ] = imageView;
}
LOGGER.debug( "Selected pixels ImageViews set." );
}
public int[] convert2( IterableInterval< BitType > input )
public static < T extends RealType< T > & NativeType< T > > int[] convertToBinary( IterableInterval< T > input, int width, int height, int depth )
{
int[] data = new int[ height * width * depth ];
Cursor< BitType > cursor = input.cursor();
Cursor< T > cursor = input.cursor();
int index = 0;
System.out.println( 0xFFFFFFFF );
while ( cursor.hasNext() )
{
cursor.fwd();
if ( cursor.get().get() )
if ( cursor.next().getRealFloat() > 0 )
{
data[ index++ ] = ( 0xFFFFFFFF );
}
......@@ -89,37 +79,101 @@ public class ImageFXDisplay
{
data[ index++ ] = 0xFF000000;
}
}
LOGGER.debug( "Selected pixels data converted for selected pixels display.");
return data;
}
public ImageView[] getImageViews()
public static < T extends RealType< T > & NativeType< T > > void setHM( Img< T > input, ImageView[] imageViews, int index )
{
return this.imageViews;
int width = ( int ) input.dimension( 0 );
int height = ( int ) input.dimension( 1 );
int[] data = convertToGrays( normalize( input ), width, height );
WritableImage writableImage = new WritableImage( width, height );
PixelWriter pixelWriter = writableImage.getPixelWriter();
pixelWriter.setPixels( 0, 0, width, height, PixelFormat.getIntArgbInstance(), data, 0, width );
ImageView imageView = new ImageView( writableImage );
setImageViews( imageView, width, height, 300 );
imageViews[ index ] = imageView;
LOGGER.debug( "Height Map ImageView set." );
}
public void setImageViews( ImageView imageView )
public static < T extends RealType< T > & NativeType< T > > int[] convertToGrays( IterableInterval< T > input, int width, int height )
{
imageView.setPreserveRatio( true );
setFit( imageView );
int[] data = new int[ height * width ];
Cursor< T > cursor = input.cursor();
int index = 0;
while ( cursor.hasNext() )
{
int value = ( int ) cursor.next().getRealFloat();
data[ index++ ] = ( 255 ) << 24 | ( 0xFF & value ) << 16 | ( 0xFF & value ) << 8 | ( 0xFF & value );
}
LOGGER.debug( "Height map data converted for construction display.");
return data;
}
public static void setImageViews( ImageView imageView, int width, int height, int size )
{
imageView.setPreserveRatio( true );
setFit( imageView, width, height , size);
imageView.setSmooth( true );
imageView.setCache( true );
}
public void setFit( ImageView imageView )
public static void setFit( ImageView imageView, int width, int height, int size )
{
if ( width >= height )
{
imageView.setFitWidth( 254 );
imageView.setFitWidth( size );
}
else
{
imageView.setFitHeight( 254 );
imageView.setFitHeight( size );
}
}
public static < T extends RealType< T > & NativeType< T > > Img< T > normalize( Img< T > input )
{
Img< T > normalizedImage = input.factory().create( input.dimensionsAsLongArray() );
ImgUtil.copy( input, normalizedImage );
T min = normalizedImage.firstElement().createVariable();
min.setReal( 0 );
T max = normalizedImage.firstElement().copy().createVariable();
max.setReal( 255 );
Normalize.normalize( normalizedImage, min, max );
return normalizedImage;
}
/**
* Creates a copy of an array of ImageView objects.
*
* Each ImageView in the new array is a separate instance
* with the same image and properties as the original.
*
* @param original The original array of ImageView objects to copy.
* @return A new array of ImageView objects with the same content.
*/
public static ImageView[] copyImageViewArray(ImageView[] original) {
if (original == null) {
return null;
}
ImageView[] copy = new ImageView[original.length];
for (int i = 0; i < original.length; i++) {
if (original[i] != null) {
ImageView originalView = original[i];
ImageView newView = new ImageView(originalView.getImage());
// Optional: Copy some properties
newView.setFitWidth(originalView.getFitWidth());
newView.setFitHeight(originalView.getFitHeight());
newView.setPreserveRatio(originalView.isPreserveRatio());
newView.setSmooth(originalView.isSmooth());
copy[i] = newView;
}
}
return copy;
}
}
......@@ -51,7 +51,7 @@ public class LogAppender extends AppenderBase< ILoggingEvent >
protected void append( ILoggingEvent iLoggingEvent )
{
String level = iLoggingEvent.getLevel().toString();
if ( level.equals( Level.INFO.toString() ) )
if ( level.equals( Level.INFO.toString()) && iLoggingEvent.getMarker().contains( "GUI" ))
{
logMessage.setValue( iLoggingEvent.getFormattedMessage() );
}
......
......@@ -45,6 +45,8 @@ import org.scijava.log.LogService;
import org.scijava.plugin.Parameter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.Marker;
import org.slf4j.MarkerFactory;
import javax.swing.*;
import java.awt.*;
......@@ -57,7 +59,7 @@ import java.util.ResourceBundle;
public class MainAppFrame extends JFrame
{
private final static Logger LOGGER = LoggerFactory.getLogger( MainAppFrame.class );
public static final Marker GUI_MARKER = MarkerFactory.getMarker("GUI");
private ImageJ ij;
private final ImageDisplayService image;
@Parameter
......@@ -86,15 +88,21 @@ public class MainAppFrame extends JFrame
*/
public void setLogStatus()
{
LoggerContext lc = ( LoggerContext ) LoggerFactory.getILoggerFactory();
PatternLayoutEncoder ple = new PatternLayoutEncoder();
ple.setPattern( "%msg%n" );
ple.setContext( lc );
ple.start();
LogAppender appender = new LogAppender();
// Get the logger context
LoggerContext context = ( LoggerContext ) LoggerFactory.getILoggerFactory();
// Configure the log pattern
PatternLayoutEncoder layout = new PatternLayoutEncoder();
layout.setPattern( "%msg%n" );
layout.setContext( context );
layout.start();
appender.setContext( lc );
// Create and start the custom LogAppender
LogAppender appender = new LogAppender();
appender.setContext( context );
appender.start();
// Get the root logger and add the appender
ch.qos.logback.classic.Logger logbackLogger =
( ch.qos.logback.classic.Logger ) LoggerFactory.getLogger( Logger.ROOT_LOGGER_NAME );
logbackLogger.addAppender( appender );
......@@ -102,7 +110,6 @@ public class MainAppFrame extends JFrame
public MainAppFrame( Context context )
{
// this.ij = context.;
this.image = context.getService( ImageDisplayService.class );
this.logService = context.getService( LogService.class );
this.setIconImages( ICONS );
......@@ -160,21 +167,19 @@ public class MainAppFrame extends JFrame
{
ResourceBundle bundle = ResourceBundle.getBundle( "gui" );// access to properties f
FXMLLoader loader = new FXMLLoader( MainAppFrame.class.getClassLoader().getResource( "fr.pasteur.ida.zellige.gui.view/Main.fxml" ), bundle );
VBox rootLayout = loader.load();
// Get the controller and add an ImageJ context to it.
MainController< T > controller = loader.getController();
controller.setMainApp( this );
// Show the scene containing the root layout.
scene = new Scene( rootLayout );
this.fxPanel.setScene( scene );
// Resize the JFrame to the JavaFX scene
this.setSize( ( int ) scene.getWidth() + 20, ( int ) scene.getHeight() + 50 );
controller.initExtraction();
// controller.initExtraction();
}
catch ( IOException e )
{
......@@ -183,4 +188,6 @@ public class MainAppFrame extends JFrame
}
}
......@@ -29,7 +29,9 @@
package fr.pasteur.ida.zellige.gui;
import javafx.beans.NamedArg;
import javafx.beans.binding.NumberExpressionBase;
import javafx.beans.property.DoubleProperty;
import javafx.beans.property.Property;
import javafx.beans.property.StringProperty;
import javafx.css.PseudoClass;
import javafx.fxml.FXML;
......@@ -134,6 +136,8 @@ public abstract class ParameterSlider extends GridPane
}
public void enable()
{
this.getSlider().setDisable( false );
......@@ -186,6 +190,16 @@ public abstract class ParameterSlider extends GridPane
{
this.sliderProperty().set( value );
}
public Number getValue ()
{
return this.sliderProperty().getValue();
}
public String getName()
{
return name;
}
}
......
......@@ -75,4 +75,6 @@ public class ParameterSliderInteger extends ParameterSlider
}
}