argoParams = argoSlidesParameters.get(argoSlide);
// run analysis
- if (nImages > 0)
+ if (nImages > 0) {
+ checkCanceled();
Processing.run(retriever, saveHeatMaps, sender,
isDefaultSigma ? defaultSigma : userSigma,
isDefaultMedianRadius ? defaultMedianRadius : userMedianRadius,
@@ -248,8 +244,9 @@ private void runProcessing(boolean isOmeroRetriever, String omeroFolderName, boo
argoSlide,
Integer.parseInt(argoParams.get(argoSpacingPos)),
Integer.parseInt(argoParams.get(argoFoVPos)),
- Integer.parseInt(argoParams.get(argoNRingsPos)));
- else {
+ Integer.parseInt(argoParams.get(argoNRingsPos)),
+ ArgoLightCommand.this);
+ } else {
IJLogger.warn("Parent container : "+rawTarget + ", microscope " + microscope + " does not contain any images");
showWarningMessage("No Images", " Parent container : "+rawTarget + ", microscope '" + microscope + "', does not contain any images." +
"" +
@@ -267,13 +264,7 @@ private void runProcessing(boolean isOmeroRetriever, String omeroFolderName, boo
} catch (Exception e){
finalPopupMessage = false;
IJLogger.error("Unexpected issue occurred", e);
- } finally {
- if(this.client.isConnected()) {
- this.client.disconnect();
- IJLogger.info("Disconnected from OMERO ");
- }
}
- IJLogger.info("ArgoLight Analysis Tool exited");
if(finalPopupMessage) {
showInfoMessage("Processing Done", "All images have been analyzed and results saved");
@@ -292,6 +283,32 @@ private boolean connectToOmero(Client client, String username, char[] password){
}
}
+ @Override
+ public boolean isCanceled() {
+ return canceled.get();
+ }
+
+ @Override
+ public void cancel(String reason) {
+ this.cancelReason = reason;
+ this.canceled.set(true);
+
+ if (processingFuture != null) {
+ processingFuture.cancel(true);
+ }
+ IJLogger.warn("Processing cancelled: " + reason);
+ }
+
+ @Override
+ public String getCancelReason() {
+ return cancelReason;
+ }
+
+ public void checkCanceled() {
+ if (canceled.get()) {
+ throw new CancellationException(cancelReason);
+ }
+ }
/**
* build the main user interface
@@ -691,6 +708,8 @@ private void createGui(){
// change the default button (when pressing enter with the keyboard)
omeroPane.getRootPane().setDefaultButton(bOk);
cbProject.requestFocus();
+ }else{
+ return;
}
}else{
if (this.client.isConnected()) {
@@ -730,34 +749,89 @@ private void createGui(){
cbProject.setSelectedItem(omeroProjects);
});
- bOk.addActionListener(e->{
- startsProcessing = true;
- mainDialog.dispose();
+ JButton bCancel = new JButton("Cancel");
+ bCancel.setFont(stdFont);
+ bCancel.addActionListener(e->{
+ if(bCancel.getText().equals("Cancel")) {
+ mainDialog.dispose();
+ if (this.client.isConnected()) {
+ this.client.disconnect();
+ IJLogger.info("Disconnected from OMERO ");
+ }
+ IJLogger.info("ArgoLight Analysis Tool exited");
+ }else{
+ cancel("Aborted by user !");
+ }
+ });
- char[] password = tfPassword.getPassword();
+ bOk.addActionListener(e->{
+ // freeze UI
+ cbMicroscope.setEnabled(false);
+ cbArgoSlide.setEnabled(false);
+ bArgoSlideSettings.setEnabled(false);
+ bLivePreview.setEnabled(false);
+ chkSaveHeatMap.setEnabled(false);
+ chkAllImages.setEnabled(false);
+ rbOmeroSender.setEnabled(false);
+ rbLocalSender.setEnabled(false);
+ rbOmeroRetriever.setEnabled(false);
+ rbLocalRetriever.setEnabled(false);
+ cbProject.setEnabled(false);
+ rbOmeroDataset.setEnabled(false);
+ rbOmeroProject.setEnabled(false);
+ bGeneralSettings.setEnabled(false);
+ bProcessingSettings.setEnabled(false);
+ bConnectToOmero.setEnabled(false);
+ bOk.setEnabled(false);
+ bCancel.setText("Abort");
String folderName;
if(rbOmeroProject.isSelected() && rbOmeroRetriever.isSelected())
folderName = (String)cbDataset.getSelectedItem();
else folderName = (String)cbProject.getSelectedItem();
- runProcessing(rbOmeroRetriever.isSelected(),
- folderName,
- rbOmeroProject.isSelected(),
- tfRootFolder.getText(),
- ((String)cbMicroscope.getSelectedItem()),
- ((String)cbArgoSlide.getSelectedItem()),
- rbOmeroSender.isSelected(),
- tfSavingFolder.getText(),
- chkSaveHeatMap.isSelected(),
- chkAllImages.isSelected(),
- chkRemovePreviousRun.isSelected());
- });
- JButton bCancel = new JButton("Cancel");
- bCancel.setFont(stdFont);
- bCancel.addActionListener(e->{
- mainDialog.dispose();
+ // send processing in another thread to get the Logs in the log window
+ processingFuture = threadService.run(() -> {
+ canceled.set(false);
+ try {
+ runProcessing(rbOmeroRetriever.isSelected(),
+ folderName,
+ rbOmeroProject.isSelected(),
+ tfRootFolder.getText(),
+ ((String) cbMicroscope.getSelectedItem()),
+ ((String) cbArgoSlide.getSelectedItem()),
+ rbOmeroSender.isSelected(),
+ tfSavingFolder.getText(),
+ chkSaveHeatMap.isSelected(),
+ chkAllImages.isSelected(),
+ chkRemovePreviousRun.isSelected());
+ } catch (CancellationException e1) {
+ IJLogger.warn("Processing stopped by user.");
+ }
+
+ // release UI
+ SwingUtilities.invokeLater(() -> {
+ cbMicroscope.setEnabled(true);
+ cbArgoSlide.setEnabled(true);
+ bArgoSlideSettings.setEnabled(true);
+ bLivePreview.setEnabled(true);
+ chkSaveHeatMap.setEnabled(true);
+ chkAllImages.setEnabled(true);
+ rbOmeroSender.setEnabled(true);
+ rbLocalSender.setEnabled(true);
+ rbOmeroRetriever.setEnabled(true);
+ rbLocalRetriever.setEnabled(true);
+ cbProject.setEnabled(true);
+ rbOmeroDataset.setEnabled(true);
+ rbOmeroProject.setEnabled(true);
+ bGeneralSettings.setEnabled(true);
+ bProcessingSettings.setEnabled(true);
+ bConnectToOmero.setEnabled(true);
+ bOk.setEnabled(true);
+ bCancel.setText("Cancel");
+ });
+ });
});
// build everything together
@@ -1003,7 +1077,7 @@ private void createGui(){
omeroPane.setBorder(BorderFactory.createEmptyBorder(20,20,20,20));
mainDialog.getContentPane().add(omeroPane);
mainDialog.setModalityType(Dialog.ModalityType.DOCUMENT_MODAL);
- mainDialog.setResizable(false);
+ mainDialog.setResizable(true);
if (JDialog.isDefaultLookAndFeelDecorated()) {
boolean supportsWindowDecorations =
@@ -1024,13 +1098,11 @@ private void createGui(){
mainDialog.setVisible(true);
mainDialog.dispose();
- if(!startsProcessing) {
- if (this.client.isConnected()) {
- this.client.disconnect();
- IJLogger.info("Disconnected from OMERO ");
- }
- IJLogger.info("ArgoLight Analysis Tool exited");
+ if (this.client.isConnected()) {
+ this.client.disconnect();
+ IJLogger.info("Disconnected from OMERO ");
}
+ IJLogger.info("ArgoLight Analysis Tool exited");
}
@@ -1146,7 +1218,7 @@ private void createArgoSettingsPane(String argoSlide){
// replace old values
argoSlidesParameters.clear();
- argoSlidesParameters = newMap;
+ argoSlidesParameters.putAll(newMap);
}
}
@@ -1249,8 +1321,9 @@ else if(!userSelectedFile.getAbsolutePath().endsWith(".csv"))
if(readyToSave) {
String argoSlidesList = String.join(",", argoSettings.keySet());
tfArgoslide.setText(argoSlidesList);
- argoSlidesParameters = tempMap;
- saveArgoSlideParams();
+ argoSlidesParameters.clear();
+ argoSlidesParameters.putAll(tempMap);
+ saveArgoSlideParams(tempMap);
setDefaultArgoParams();
}else{
showErrorMessage("ArgoSlide settings", "The provided CSV is not correctly formatted. " +
@@ -2328,7 +2401,7 @@ private void setDefaultArgoParams(){
// replace old parameters
argoSlidesParameters.clear();
- argoSlidesParameters = cleanArgoSlides;
+ argoSlidesParameters.putAll(cleanArgoSlides);
}
/**
@@ -2526,9 +2599,10 @@ private Map> saveUserDefinedArgoSlideParams(String argoSli
argoslideParamList.add(String.valueOf(argoFov));
argoslideParamList.add(String.valueOf(argoNRings));
tempMap.put(argoSlide, argoslideParamList);
- argoSlidesParameters = tempMap;
- return saveArgoSlideParams();
+ saveArgoSlideParams(tempMap);
+
+ return tempMap;
}
/**
@@ -2536,7 +2610,7 @@ private Map> saveUserDefinedArgoSlideParams(String argoSli
*
* @return
*/
- private Map> saveArgoSlideParams() {
+ private void saveArgoSlideParams(Map> argoSlidesParametersMap) {
File directory = new File(folderName);
if(!directory.exists())
@@ -2546,8 +2620,8 @@ private Map> saveArgoSlideParams() {
File file = new File(directory.getAbsoluteFile() + File.separator + argoSlideFileName);
// write the file
BufferedWriter buffer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file), StandardCharsets.UTF_8));
- for(String argoSlideKey : argoSlidesParameters.keySet()){
- String argoSlideParamCSV = String.join(",", argoSlidesParameters.get(argoSlideKey));
+ for(String argoSlideKey : argoSlidesParametersMap.keySet()){
+ String argoSlideParamCSV = String.join(",", argoSlidesParametersMap.get(argoSlideKey));
buffer.write(argoSlideKey+","+ argoSlideParamCSV + "\n");
}
// close the file
@@ -2556,7 +2630,6 @@ private Map> saveArgoSlideParams() {
} catch (IOException e) {
showWarningMessage("CSV writing","Couldn't write the csv for ArgoSlide parameters.");
}
- return argoSlidesParameters;
}
public static void main(String... args){
diff --git a/src/main/java/ch/epfl/biop/processing/ArgoSlideOldProcessing.java b/src/main/java/ch/epfl/biop/processing/ArgoSlideOldProcessing.java
index a994a35..45c6d8c 100644
--- a/src/main/java/ch/epfl/biop/processing/ArgoSlideOldProcessing.java
+++ b/src/main/java/ch/epfl/biop/processing/ArgoSlideOldProcessing.java
@@ -1,5 +1,6 @@
package ch.epfl.biop.processing;
+import ch.epfl.biop.command.ArgoLightCommand;
import ch.epfl.biop.image.ImageChannel;
import ch.epfl.biop.image.ImageFile;
import ch.epfl.biop.utils.IJLogger;
@@ -31,7 +32,7 @@ public class ArgoSlideOldProcessing {
final private static int argoNPoints = 21; // on each row/column
final private static String thresholdingMethod = "Huang dark";
- public static void run(ImageFile imageFile){
+ public static void run(ImageFile imageFile, ArgoLightCommand argoLightCommand){
ImagePlus imp = imageFile.getImage();
// pixel size of the image
final double pixelSizeImage = imp.getCalibration().pixelWidth;
@@ -52,6 +53,7 @@ public static void run(ImageFile imageFile){
imageFile.addKeyValue("thresholding_method", thresholdingMethod);
RoiManager roiManager = new RoiManager();
+ argoLightCommand.checkCanceled();
for(int c = 0; c < NChannels; c++){
// reset all windows
@@ -65,6 +67,7 @@ public static void run(ImageFile imageFile){
imp.setPosition(c+1,1,1);
channel.setProcessor(imp.getProcessor());
channel.show();
+ argoLightCommand.checkCanceled();
// get the central cross
Roi crossRoi = getCentralCross(channel, roiManager, pixelSizeImage);
@@ -74,6 +77,7 @@ public static void run(ImageFile imageFile){
// add the cross ROI on the image
roiManager.addRoi(crossRoi);
channel.setRoi(crossRoi);
+ argoLightCommand.checkCanceled();
double sigma = 0.14 * argoSpacing / (pixelSizeImage * Math.sqrt(2));
List gridPoints = getGridPoint2(channel, crossRoi, pixelSizeImage, sigma);
@@ -97,6 +101,7 @@ public static void run(ImageFile imageFile){
double rotationAngle = getRotationAngle(gridPoints, crossRoi);
imageChannel.setRotationAngle(rotationAngle*180/Math.PI);
IJLogger.info("Channel "+c,"Rotation angle theta = "+rotationAngle*180/Math.PI + "°");
+ argoLightCommand.checkCanceled();
// get the ideal grid
List idealGridPoints = getIdealGridPoints(crossRoi, (int)Math.sqrt(gridPoints.size() + 1), xStepAvg, yStepAvg, rotationAngle);
@@ -105,6 +110,7 @@ public static void run(ImageFile imageFile){
// sort the computed grid points according to ideal grid order
gridPoints = sortFromReference(Arrays.asList(roiManager.getRoisAsArray()), idealGridPoints);
+ argoLightCommand.checkCanceled();
// display all points (grid and ideal)
roiManager.reset();
@@ -121,11 +127,15 @@ public static void run(ImageFile imageFile){
imageChannel.addIdealRings(idealGridPointsRoi);
roiManager.runCommand(channel,"Show All without labels");
+ argoLightCommand.checkCanceled();
// compute metrics
imageChannel.addFieldDistortion(computeFieldDistortion(gridPoints, idealGridPoints, pixelSizeImage));
+ argoLightCommand.checkCanceled();
imageChannel.addFieldUniformity(computeFieldUniformity(gridPoints,channel,ovalRadius));
+ argoLightCommand.checkCanceled();
imageChannel.addFWHM(computeFWHM(gridPoints,channel, lineLength, roiManager, pixelSizeImage));
+ argoLightCommand.checkCanceled();
imageFile.addChannel(imageChannel);
}
@@ -133,9 +143,11 @@ public static void run(ImageFile imageFile){
roiManager.reset();
roiManager.close();
IJ.run("Close All", "");
-
- if(NChannels > 1)
+ argoLightCommand.checkCanceled();
+ if(NChannels > 1) {
imageFile.computePCC();
+ }
+ argoLightCommand.checkCanceled();
}
diff --git a/src/main/java/ch/epfl/biop/processing/ArgoSlideProcessing.java b/src/main/java/ch/epfl/biop/processing/ArgoSlideProcessing.java
index f10767b..fea11de 100644
--- a/src/main/java/ch/epfl/biop/processing/ArgoSlideProcessing.java
+++ b/src/main/java/ch/epfl/biop/processing/ArgoSlideProcessing.java
@@ -1,5 +1,6 @@
package ch.epfl.biop.processing;
+import ch.epfl.biop.command.ArgoLightCommand;
import ch.epfl.biop.image.ImageChannel;
import ch.epfl.biop.image.ImageFile;
import ch.epfl.biop.utils.IJLogger;
@@ -66,7 +67,8 @@ public class ArgoSlideProcessing {
* @param argoNPoints number of rings in the same line
*/
public static void run(ImageFile imageFile, double userSigma, double userMedianRadius, String userThresholdingMethod,
- double userParticleThreshold, double userRingRadius, String argoSlide, int argoSpacing, int argoFOV, int argoNPoints){
+ double userParticleThreshold, double userRingRadius, String argoSlide, int argoSpacing,
+ int argoFOV, int argoNPoints, ArgoLightCommand argoLightCommand){
final ImagePlus imp = imageFile.getImage();
// pixel size of the image
@@ -107,19 +109,22 @@ public static void run(ImageFile imageFile, double userSigma, double userMedianR
IJLogger.info("Detection parameters","Particle threshold : "+particleThreshold + " pix");
RoiManager roiManager = RoiManager.getRoiManager();
+ argoLightCommand.checkCanceled();
for(int c = 0; c < NChannels; c++){
// reset all windows
IJ.run("Close All", "");
roiManager.reset();
+ argoLightCommand.checkCanceled();
ImageChannel imageChannel = new ImageChannel(c, imp.getWidth(), imp.getHeight(), pixelSizeImage);
// extract the current channel
ImagePlus channel = IJ.createHyperStack(imp.getTitle() + "_ch" + c, imp.getWidth(), imp.getHeight(), 1, 1, 1, imp.getBitDepth());
- imp.setPosition(c+1,1,1);
+ imp.setPosition(c+1,(int)((imp.getNSlices() + 1)/2),(int)((imp.getNFrames() + 1)/2));
channel.setProcessor(imp.getProcessor());
channel.show();
+ argoLightCommand.checkCanceled();
// get the central cross
Roi crossRoi = Processing.getCentralCross(channel, roiManager, pixelSizeImage, userThresholdingMethod, argoFOV);
@@ -131,6 +136,7 @@ public static void run(ImageFile imageFile, double userSigma, double userMedianR
imageChannel.setCenterCross(crossRoi);
IJLogger.info("Channel "+c,"Cross = " +crossRoi);
+ argoLightCommand.checkCanceled();
// add the cross ROI on the image
roiManager.addRoi(crossRoi);
@@ -144,6 +150,7 @@ public static void run(ImageFile imageFile, double userSigma, double userMedianR
"Cannot compute metrics");
throw new RuntimeException();
}
+ argoLightCommand.checkCanceled();
// display all points (grid and ideal)
roiManager.reset();
@@ -178,6 +185,7 @@ public static void run(ImageFile imageFile, double userSigma, double userMedianR
imageChannel.setRotationAngle(rotationAngle);
IJLogger.info("Channel "+c,"Rotation angle theta = "+rotationAngle*180/Math.PI + "°");
+ argoLightCommand.checkCanceled();
// create grid point ROIs
gridPoints.forEach(pR-> {roiManager.addRoi(new OvalRoi((pR.getX()-4*ovalRadius+0.5), pR.getY()-4*ovalRadius+0.5, 8*ovalRadius, 8*ovalRadius));});
@@ -188,6 +196,7 @@ public static void run(ImageFile imageFile, double userSigma, double userMedianR
// sort the computed grid points according to ideal grid order
gridPoints = Processing.sortFromReference(Arrays.asList(roiManager.getRoisAsArray()), idealGridPoints);
+ argoLightCommand.checkCanceled();
// display all points (grid and ideal)
roiManager.reset();
@@ -208,15 +217,20 @@ public static void run(ImageFile imageFile, double userSigma, double userMedianR
}
idealGridPointsRoi.forEach(roiManager::addRoi);
imageChannel.addIdealRings(idealGridPointsRoi);
+ argoLightCommand.checkCanceled();
// compute metrics
+ argoLightCommand.checkCanceled();
imageChannel.addFieldDistortion(Processing.computeFieldDistortion(gridPoints, idealGridPoints, pixelSizeImage));
- imageChannel.addFieldUniformity(Processing.computeFieldUniformity(gridPoints, channel,ovalRadius));
+ argoLightCommand.checkCanceled();
+ imageChannel.addFieldUniformity(Processing.computeFieldUniformity(gridPoints, channel, ovalRadius));
// add tags to the image
imageFile.addTags(Tools.FIELD_DISTORTION_TAG, Tools.FIELD_UNIFORMITY_TAG);
+ argoLightCommand.checkCanceled();
}
if(!imageFile.getImagedFoV().equals(Tools.FULL_FOV)){
roiManager.reset();
+ argoLightCommand.checkCanceled();
List fwhmGridPointsRoiList = new ArrayList<>();
// create grid point ROIs
@@ -228,6 +242,7 @@ public static void run(ImageFile imageFile, double userSigma, double userMedianR
fwhmGridPointsRoiList.add(roi);
}
+ argoLightCommand.checkCanceled();
// save ROIs
imageChannel.addGridRings(fwhmGridPointsRoiList);
// add grid point centers
@@ -236,6 +251,8 @@ public static void run(ImageFile imageFile, double userSigma, double userMedianR
imageChannel.addFWHM(Processing.computeFWHM(smallerGrid, channel, lineLength, pixelSizeImage));
// add tag to image
imageFile.addTags(Tools.FWHM_TAG);
+
+ argoLightCommand.checkCanceled();
}
roiManager.runCommand(channel,"Show All without labels");
imageFile.addChannel(imageChannel);
@@ -243,8 +260,11 @@ public static void run(ImageFile imageFile, double userSigma, double userMedianR
roiManager.reset();
roiManager.close();
IJ.run("Close All", "");
+ argoLightCommand.checkCanceled();
- if(NChannels > 1)
+ if(NChannels > 1) {
imageFile.computePCC();
+ }
+ argoLightCommand.checkCanceled();
}
}
diff --git a/src/main/java/ch/epfl/biop/processing/Processing.java b/src/main/java/ch/epfl/biop/processing/Processing.java
index 2ea332c..9c43fe7 100644
--- a/src/main/java/ch/epfl/biop/processing/Processing.java
+++ b/src/main/java/ch/epfl/biop/processing/Processing.java
@@ -1,5 +1,6 @@
package ch.epfl.biop.processing;
+import ch.epfl.biop.command.ArgoLightCommand;
import ch.epfl.biop.image.ImageChannel;
import ch.epfl.biop.image.ImageFile;
import ch.epfl.biop.retrievers.Retriever;
@@ -15,6 +16,7 @@
import ij.measure.ResultsTable;
import ij.plugin.frame.RoiManager;
import ij.process.ImageStatistics;
+import org.scijava.Cancelable;
import java.awt.Rectangle;
import java.awt.geom.AffineTransform;
@@ -27,6 +29,7 @@
import java.util.List;
import java.util.Map;
import java.util.Optional;
+import java.util.concurrent.CancellationException;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
@@ -51,8 +54,10 @@ public class Processing {
* @param argoFOV FoV of the pattern B of the ArgoSlide in um
* @param argoNPoints number of rings in the same line
*/
- public static void run(Retriever retriever, boolean savingHeatMaps, Sender sender, double userSigma, double userMedianRadius, String userThresholdingMethod,
- double userParticleThreshold, double userRingRadius, String argoSlide, int argoSpacing, int argoFOV, int argoNPoints){
+ public static void run(Retriever retriever, boolean savingHeatMaps, Sender sender, double userSigma,
+ double userMedianRadius, String userThresholdingMethod,
+ double userParticleThreshold, double userRingRadius, String argoSlide,
+ int argoSpacing, int argoFOV, int argoNPoints, ArgoLightCommand argoLightCommand){
Map>> summaryMap = new HashMap<>();
List headers = new ArrayList<>();
List IDs = retriever.getIDs();
@@ -82,18 +87,21 @@ public static void run(Retriever retriever, boolean savingHeatMaps, Sender sende
// choose the right ArgoLight processing
if (!imageFile.getArgoSlideName().contains("ArgoSimOld")) {
ArgoSlideProcessing.run(imageFile, userSigma, userMedianRadius, userThresholdingMethod,
- userParticleThreshold, userRingRadius, argoSlide, argoSpacing, argoFOV, argoNPoints);
+ userParticleThreshold, userRingRadius, argoSlide, argoSpacing, argoFOV, argoNPoints,
+ argoLightCommand);
} else {
- ArgoSlideOldProcessing.run(imageFile);
+ ArgoSlideOldProcessing.run(imageFile, argoLightCommand);
isOldProtocol = true;
}
IJLogger.info("End of processing");
+ argoLightCommand.checkCanceled();
IJLogger.info("Sending results ... ");
// send image results (metrics, rings, tags, key-values)
sender.initialize(imageFile, retriever);
sender.sendTags(imageFile.getTags());
+ argoLightCommand.checkCanceled();
sendResults(sender, imageFile, savingHeatMaps, isOldProtocol, argoSpacing);
// metrics summary to populate parent table
@@ -102,6 +110,8 @@ public static void run(Retriever retriever, boolean savingHeatMaps, Sender sende
if (!allChannelMetrics.values().isEmpty())
summaryMap.put(uniqueID, allChannelMetrics.values().iterator().next());
+ } catch (CancellationException e) {
+ throw e;
} catch (Exception e) {
IJLogger.error("An error occurred during processing ; cannot analyse the image " + imgTitle, e);
}
@@ -109,6 +119,7 @@ public static void run(Retriever retriever, boolean savingHeatMaps, Sender sende
}
// populate parent table with summary results
+ argoLightCommand.checkCanceled();
sender.populateParentTable(retriever, summaryMap, headers, !retriever.isProcessingAllRawImages());
}
@@ -123,8 +134,9 @@ private static void sendResults(Sender sender, ImageFile imageFile, boolean savi
Map keyValues = imageFile.getKeyValues();
// send PCC table
- if (imageFile.getNChannels() > 1)
+ if (imageFile.getNChannels() > 1) {
sender.sendPCCTable(imageFile.getPCC(), imageFile.getNChannels());
+ }
List> distortionValues = new ArrayList<>();
List> uniformityValues = new ArrayList<>();
diff --git a/src/main/java/ch/epfl/biop/senders/LocalSender.java b/src/main/java/ch/epfl/biop/senders/LocalSender.java
index c954739..9bdbf05 100644
--- a/src/main/java/ch/epfl/biop/senders/LocalSender.java
+++ b/src/main/java/ch/epfl/biop/senders/LocalSender.java
@@ -30,6 +30,8 @@
import java.util.Comparator;
import java.util.List;
import java.util.Map;
+import java.util.SortedSet;
+import java.util.TreeSet;
import java.util.concurrent.ExecutionException;
import java.util.stream.Collectors;
import java.util.zip.ZipEntry;
@@ -209,6 +211,28 @@ public void sendGridPoints(List rois, int channelId, String roiTitle) {
@Override
public void sendResultsTable(List> values, List channelIdList, boolean createNewTable, String tableName){
IJLogger.info("Sending "+tableName+" table");
+
+ // Make sure that the different columns have the same number of rows i.e. all channels properly detected
+ // If it's not the case, each column with nRows < nMaxRow will have -1 instead
+ SortedSet sizes = new TreeSet<>();
+ for(List val: values){
+ sizes.add(val.size());
+ }
+
+ if(sizes.size() > 1){
+ IJLogger.warn("Not all rings have been detected on all the channels. Only measurements for channels " +
+ "with all rings detected will be sent.");
+ int maxSize = sizes.last();
+ for(List val: values){
+ if(val.size() != maxSize){
+ val.clear();
+ for(int i = 0; i< maxSize; i++){
+ val.add(-1d);
+ }
+ }
+ }
+ }
+
String text = createNewTable(values, channelIdList);
File file = new File(this.imageFolder + File.separator + tableName + "_" + Tools.PARENT_TABLE_SUFFIX + ".csv");
@@ -314,19 +338,22 @@ public void sendTags(List tags) {
return;
}
+ // filter unique tags
+ List uniqueTags = tags.stream().distinct().collect(Collectors.toList());
+
// add tags on OMERO if images was initially on the OMERO server
- for(String tag : tags) {
+ for(String tag : uniqueTags) {
try {
// get the corresponding tag in the list of available tags if exists
List rawTag = groupTags.stream().filter(t -> t.getName().equals(tag)).collect(Collectors.toList());
// check if the tag is already applied to the current image
- boolean isTagAlreadyExists = imageTags
+ boolean isTagAlreadyExisting = imageTags
.stream()
.anyMatch(t -> t.getName().equals(tag));
// add the tag to the current image if it is not already the case
- if (!isTagAlreadyExists) {
+ if (!isTagAlreadyExisting) {
imageWrapper.link(this.client, rawTag.isEmpty() ? new TagAnnotationWrapper(new TagAnnotationData(tag)) : rawTag.get(0));
IJLogger.info("Adding tag","The tag " + tag + " has been successfully applied on the image " + imageWrapper.getId());
} else
diff --git a/src/main/java/ch/epfl/biop/senders/OMEROSender.java b/src/main/java/ch/epfl/biop/senders/OMEROSender.java
index 1f13f85..0d019f8 100644
--- a/src/main/java/ch/epfl/biop/senders/OMEROSender.java
+++ b/src/main/java/ch/epfl/biop/senders/OMEROSender.java
@@ -42,6 +42,8 @@
import java.util.Comparator;
import java.util.List;
import java.util.Map;
+import java.util.SortedSet;
+import java.util.TreeSet;
import java.util.concurrent.ExecutionException;
import java.util.stream.Collectors;
import java.util.stream.LongStream;
@@ -93,19 +95,22 @@ private void sendTags(List tags, ImageWrapper imageWrapper) {
return;
}
+ // filter unique tags
+ List uniqueTags = tags.stream().distinct().collect(Collectors.toList());
+
// loop on tags to add
- for(String tag : tags) {
+ for(String tag : uniqueTags) {
try {
// get the corresponding tag in the list of available tags if exists
List rawTag = groupTags.stream().filter(t -> t.getName().equals(tag)).collect(Collectors.toList());
// check if the tag is already applied to the current image
- boolean isTagAlreadyExists = imageTags
+ boolean isTagAlreadyExisting = imageTags
.stream()
.anyMatch(t -> t.getName().equals(tag));
// add the tag to the current image if it is not already the case
- if (!isTagAlreadyExists) {
+ if (!isTagAlreadyExisting) {
imageWrapper.link(this.client, rawTag.isEmpty() ? new TagAnnotationWrapper(new TagAnnotationData(tag)) : rawTag.get(0));
IJLogger.info("Adding tag","The tag " + tag + " has been successfully applied on the image " + imageWrapper.getId());
} else
@@ -339,6 +344,27 @@ public void sendResultsTable(List> values, List channelIdL
// get the last OMERO table
TableWrapper table = getOmeroTable(this.client, this.imageWrapper, tableName);
+ // Make sure that the different columns have the same number of rows i.e. all channels properly detected
+ // If it's not the case, each column with nRows < nMaxRow will have -1 instead
+ SortedSet sizes = new TreeSet<>();
+ for(List val: values){
+ sizes.add(val.size());
+ }
+
+ if(sizes.size() > 1){
+ IJLogger.warn("Not all rings have been detected on all the channels. Only measurements for channels " +
+ "with all rings detected will be sent.");
+ int maxSize = sizes.last();
+ for(List val: values){
+ if(val.size() != maxSize){
+ val.clear();
+ for(int i = 0; i< maxSize; i++){
+ val.add(-1d);
+ }
+ }
+ }
+ }
+
// populate existing table or create a new one
if(!createNewTable && table != null)
tableWrapper = addNewColumnsToTable(table, values, channelIdList, this.date);
@@ -436,7 +462,7 @@ private TableWrapper createNewTable(List> values, List cha
List> measurements = new ArrayList<>();
int i = 0;
- if(values.size() > 0) {
+ if(!values.isEmpty()) {
// add the first column with the image data (linkable on OMERO)
columns.add(new TableDataColumn("Image ID", i++, ImageData.class));
List