From 15aabc4a5e966fd40e5cd38b8f03c1ef748664bf Mon Sep 17 00:00:00 2001
From: felmer <felmer>
Date: Mon, 2 Nov 2015 11:30:34 +0000
Subject: [PATCH] SSDM-2710: Extending
 MaximumIntensityProjectionGenerationAlgorithm by allowing to use thumbnails
 as image sources if available.

SVN: 34957
---
 .../dss/etl/Hdf5ThumbnailGenerator.java       |  2 +-
 .../dto/api/IImageGenerationAlgorithm.java    |  8 +-
 .../api/impl/EmptyImageCreationAlgorithm.java |  4 +-
 ...ntensityProjectionGenerationAlgorithm.java | 92 ++++++++++++++++++-
 ...ImagingDataSetRegistrationTransaction.java |  2 +-
 ...sityProjectionGenerationAlgorithmTest.java |  4 +-
 6 files changed, 99 insertions(+), 13 deletions(-)

diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/Hdf5ThumbnailGenerator.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/Hdf5ThumbnailGenerator.java
index 9ba79c9b523..0ea50170d90 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/Hdf5ThumbnailGenerator.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/Hdf5ThumbnailGenerator.java
@@ -300,7 +300,7 @@ public class Hdf5ThumbnailGenerator implements IHDF5WriterClient
         return Status.OK;
     }
 
-    private String createThumbnailPath(ImageFileInfo plateImage, String channelCode)
+    public static String createThumbnailPath(ImageFileInfo plateImage, String channelCode)
     {
         StringBuilder newImagePath = new StringBuilder();
         if (plateImage.hasWellLocation())
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/IImageGenerationAlgorithm.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/IImageGenerationAlgorithm.java
index 2a00f8b6d65..3dad3085540 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/IImageGenerationAlgorithm.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/IImageGenerationAlgorithm.java
@@ -3,6 +3,7 @@ package ch.systemsx.cisd.openbis.dss.etl.dto.api;
 import java.awt.image.BufferedImage;
 import java.util.List;
 
+import ch.systemsx.cisd.etlserver.registrator.api.v2.IDataSet;
 import ch.systemsx.cisd.openbis.dss.etl.IImageProvider;
 import ch.systemsx.cisd.openbis.dss.etl.dto.api.impl.ImageDataSetInformation;
 
@@ -16,7 +17,8 @@ public interface IImageGenerationAlgorithm
     /**
      * Creates thumbnails for the specified data set info.
      */
-    public List<BufferedImage> generateImages(ImageDataSetInformation information, IImageProvider imageProvider);
+    public List<BufferedImage> generateImages(ImageDataSetInformation information, 
+            List<IDataSet> thumbnailDatasets, IImageProvider imageProvider);
     
     /**
      * Returns the code of the data set to be registered containing these representative thumbnails.
@@ -25,8 +27,8 @@ public interface IImageGenerationAlgorithm
     
     /**
      * Returns the thumbnail file name for the specified index. The index specifies the corresponding
-     * image returned by {@link #generateImages(ImageDataSetInformation, IImageProvider)}.
-     * Note, all file names generated by this method have to different.
+     * image returned by {@link #generateImages(ImageDataSetInformation, List, IImageProvider)}.
+     * Note, all file names generated by this method have to be different.
      */
     public String getImageFileName(int index);
 }
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/impl/EmptyImageCreationAlgorithm.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/impl/EmptyImageCreationAlgorithm.java
index 2e2bd6fbcb6..ac7f0e41309 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/impl/EmptyImageCreationAlgorithm.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/impl/EmptyImageCreationAlgorithm.java
@@ -5,6 +5,7 @@ import java.io.Serializable;
 import java.util.Collections;
 import java.util.List;
 
+import ch.systemsx.cisd.etlserver.registrator.api.v2.IDataSet;
 import ch.systemsx.cisd.openbis.dss.etl.IImageProvider;
 import ch.systemsx.cisd.openbis.dss.etl.dto.api.IImageGenerationAlgorithm;
 import ch.systemsx.cisd.openbis.generic.shared.IServer;
@@ -21,7 +22,8 @@ public class EmptyImageCreationAlgorithm implements IImageGenerationAlgorithm, S
     }
 
     @Override
-    public List<BufferedImage> generateImages(ImageDataSetInformation information, IImageProvider imageProvider)
+    public List<BufferedImage> generateImages(ImageDataSetInformation information, 
+            List<IDataSet> thumbnailDatasets, IImageProvider imageProvider)
     {
         return Collections.emptyList();
     }
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/impl/MaximumIntensityProjectionGenerationAlgorithm.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/impl/MaximumIntensityProjectionGenerationAlgorithm.java
index e3f11abeb47..daa1dc24683 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/impl/MaximumIntensityProjectionGenerationAlgorithm.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/impl/MaximumIntensityProjectionGenerationAlgorithm.java
@@ -11,7 +11,13 @@ import java.util.List;
 import java.util.Map;
 
 import ch.rinn.restrictions.Private;
+import ch.systemsx.cisd.etlserver.registrator.api.v2.IDataSet;
+import ch.systemsx.cisd.etlserver.registrator.api.v2.impl.DataSet;
 import ch.systemsx.cisd.openbis.common.io.FileBasedContentNode;
+import ch.systemsx.cisd.openbis.common.io.hierarchical_content.DefaultFileBasedHierarchicalContentFactory;
+import ch.systemsx.cisd.openbis.common.io.hierarchical_content.api.IHierarchicalContent;
+import ch.systemsx.cisd.openbis.common.io.hierarchical_content.api.IHierarchicalContentNode;
+import ch.systemsx.cisd.openbis.dss.etl.Hdf5ThumbnailGenerator;
 import ch.systemsx.cisd.openbis.dss.etl.IImageProvider;
 import ch.systemsx.cisd.openbis.dss.etl.dto.ImageLibraryInfo;
 import ch.systemsx.cisd.openbis.dss.etl.dto.api.Channel;
@@ -19,6 +25,7 @@ import ch.systemsx.cisd.openbis.dss.etl.dto.api.ChannelColorComponent;
 import ch.systemsx.cisd.openbis.dss.etl.dto.api.IImageGenerationAlgorithm;
 import ch.systemsx.cisd.openbis.dss.etl.dto.api.ImageFileInfo;
 import ch.systemsx.cisd.openbis.dss.generic.server.images.ImageChannelsUtils;
+import ch.systemsx.cisd.openbis.dss.generic.shared.dto.Size;
 import ch.systemsx.cisd.openbis.generic.shared.IServer;
 import ch.systemsx.cisd.openbis.plugin.screening.shared.imaging.dataaccess.ColorComponent;
 
@@ -56,6 +63,8 @@ public class MaximumIntensityProjectionGenerationAlgorithm implements IImageGene
     private int width;
 
     private int height;
+    
+    private boolean useThumbnails;
 
     /**
      * Creates an instance for the specified data set type. The generated image will have the same size as
@@ -94,6 +103,15 @@ public class MaximumIntensityProjectionGenerationAlgorithm implements IImageGene
         this.height = height;
         this.filename = filename;
     }
+    
+    /**
+     * Uses thumbnails (if present) instead of original images.
+     */
+    public MaximumIntensityProjectionGenerationAlgorithm useThumbnails()
+    {
+        useThumbnails = true;
+        return this;
+    }
 
     @Override
     public String getDataSetTypeCode()
@@ -102,13 +120,15 @@ public class MaximumIntensityProjectionGenerationAlgorithm implements IImageGene
     }
     
     @Override
-    public List<BufferedImage> generateImages(ImageDataSetInformation information, IImageProvider imageProvider)
+    public List<BufferedImage> generateImages(ImageDataSetInformation information, 
+            List<IDataSet> thumbnailDatasets, IImageProvider imageProvider)
     {
         ImageDataSetStructure structure = information.getImageDataSetStructure();
         ImageLibraryInfo library = structure.getImageStorageConfiguraton().tryGetImageLibrary();
         List<ImageFileInfo> images = structure.getImages();
         Map<String, ChannelAndColorComponent> channelsByCode = getChannelsByCode(structure);
         File incomingDirectory = information.getIncomingDirectory();
+        File thumbnailDataSet = tryFindMatchingThumbnailDataSet(information, thumbnailDatasets);
         int maxIntensity = 0;
         for (ImageFileInfo imageFileInfo : images)
         {
@@ -116,10 +136,10 @@ public class MaximumIntensityProjectionGenerationAlgorithm implements IImageGene
             {
                 continue;
             }
-            String imagePath = imageFileInfo.getImageRelativePath();
-            ChannelAndColorComponent channelAndColorComponent = channelsByCode.get(imageFileInfo.getChannelCode());
-            String identifier = imageFileInfo.tryGetUniqueStringIdentifier();
-            BufferedImage image = loadImage(imageProvider, incomingDirectory, imagePath, identifier, library);
+            String channelCode = imageFileInfo.getChannelCode();
+            ChannelAndColorComponent channelAndColorComponent = channelsByCode.get(channelCode);
+            BufferedImage image = loadImage(imageProvider, library, images, incomingDirectory, 
+                    thumbnailDataSet, imageFileInfo, channelCode);
             image = ImageChannelsUtils.rescaleIfNot8Bit(image, 0f, channelAndColorComponent.channel.tryGetChannelColor());
             image = ImageChannelsUtils.extractChannel(image, channelAndColorComponent.colorComponent);
             image = ImageChannelsUtils.transformGrayToColor(image, channelAndColorComponent.channel.tryGetChannelColor());
@@ -150,6 +170,68 @@ public class MaximumIntensityProjectionGenerationAlgorithm implements IImageGene
         }
     }
 
+    private BufferedImage loadImage(IImageProvider imageProvider, ImageLibraryInfo library, 
+            List<ImageFileInfo> images, File incomingDirectory,
+            File thumbnailDataSet, ImageFileInfo imageFileInfo, String channelCode)
+    {
+        String imagePath = imageFileInfo.getImageRelativePath();
+        String identifier = imageFileInfo.tryGetUniqueStringIdentifier();
+        BufferedImage image = null;
+        if (thumbnailDataSet != null && useThumbnails)
+        {
+            IHierarchicalContent content = new DefaultFileBasedHierarchicalContentFactory()
+                    .asHierarchicalContent(thumbnailDataSet, null);
+            String thumbnailPath = Hdf5ThumbnailGenerator.createThumbnailPath(imageFileInfo, channelCode);
+            IHierarchicalContentNode rootNode = content.getRootNode();
+            String containerPath = rootNode.getChildNodes().get(0).getRelativePath();
+            IHierarchicalContentNode node = content.tryGetNode(containerPath + "/" + thumbnailPath + ".png");
+            if (node != null)
+            {
+                image = imageProvider.getImage(node, images.get(0).tryGetUniqueStringIdentifier(), null);
+            }
+        }
+        if (image == null)
+        {
+            image = loadImage(imageProvider, incomingDirectory, imagePath, identifier, library);
+        }
+        return image;
+    }
+
+    private File tryFindMatchingThumbnailDataSet(ImageDataSetInformation information, List<IDataSet> thumbnailDatasets)
+    {
+        ThumbnailsInfo thumbnailsInfos = information.getThumbnailsInfos();
+        if (thumbnailsInfos != null)
+        {
+            for (String permId : thumbnailsInfos.getThumbnailPhysicalDatasetsPermIds())
+            {
+                Size dimension = thumbnailsInfos.tryGetDimension(permId);
+                if (dimension != null && (dimension.getWidth() == width || dimension.getHeight() == height))
+                {
+                    IDataSet thumbnailDataSet = tryFindDataSetByPermId(thumbnailDatasets, permId);
+                    if (thumbnailDataSet instanceof DataSet)
+                    {
+                        return ((DataSet<?>) thumbnailDataSet).getDataSetStagingFolder();
+                    }
+                }
+            }
+        }
+        return null;
+    }
+    
+    
+    
+    private IDataSet tryFindDataSetByPermId(List<IDataSet> dataSets, String permId)
+    {
+        for (IDataSet dataSet : dataSets)
+        {
+            if (dataSet.getDataSetCode().equals(permId))
+            {
+                return dataSet;
+            }
+        }
+        return null;
+    }
+
     @Private BufferedImage loadImage(IImageProvider imageProvider, File incomingDirectory, String imagePath, 
             String identifier, ImageLibraryInfo library)
     {
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/jython/v2/ImagingDataSetRegistrationTransaction.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/jython/v2/ImagingDataSetRegistrationTransaction.java
index d626cd91230..40751157131 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/jython/v2/ImagingDataSetRegistrationTransaction.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/jython/v2/ImagingDataSetRegistrationTransaction.java
@@ -384,7 +384,7 @@ public class ImagingDataSetRegistrationTransaction extends DataSetRegistrationTr
         {
             return;
         }
-        List<BufferedImage> images = algorithm.generateImages(imageDataSetInformation, imageCache);
+        List<BufferedImage> images = algorithm.generateImages(imageDataSetInformation, thumbnailDatasets, imageCache);
         if (images.size() > 0)
         {
             IDataSet representative = createNewDataSet(algorithm.getDataSetTypeCode());
diff --git a/screening/sourceTest/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/impl/MaximumIntensityProjectionGenerationAlgorithmTest.java b/screening/sourceTest/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/impl/MaximumIntensityProjectionGenerationAlgorithmTest.java
index 572c124b62f..4eec12b4793 100644
--- a/screening/sourceTest/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/impl/MaximumIntensityProjectionGenerationAlgorithmTest.java
+++ b/screening/sourceTest/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/impl/MaximumIntensityProjectionGenerationAlgorithmTest.java
@@ -186,7 +186,7 @@ public class MaximumIntensityProjectionGenerationAlgorithmTest extends AbstractF
         Channel channel2 = new Channel("CI2", "i2", new ChannelColorRGB(0, 120, 180));
         structure.setChannels(Arrays.asList(channel1, channel2));
         
-        List<BufferedImage> generatedImages = generationAlgorithm.generateImages(information, DUMMY_IMAGE_PROVIDER);
+        List<BufferedImage> generatedImages = generationAlgorithm.generateImages(information, null, DUMMY_IMAGE_PROVIDER);
         
         assertEquals("[incoming/images/i1.png: i1 [lib (reader: reader)], "
                 + "incoming/images/i2.png: i2 [lib (reader: reader)]]", generationAlgorithm.recorder.toString());
@@ -208,7 +208,7 @@ public class MaximumIntensityProjectionGenerationAlgorithmTest extends AbstractF
         Channel channel2 = new Channel("CI3", "i3", new ChannelColorRGB(0, 120, 180));
         structure.setChannels(Arrays.asList(channel1, channel2));
         
-        List<BufferedImage> generatedImages = generationAlgorithm.generateImages(information, DUMMY_IMAGE_PROVIDER);
+        List<BufferedImage> generatedImages = generationAlgorithm.generateImages(information, null, DUMMY_IMAGE_PROVIDER);
         
         assertEquals("[incoming/images/i2.png: i2 [lib (reader: reader)], "
                 + "incoming/images/i3.png: i3 [lib (reader: reader)]]", generationAlgorithm.recorder.toString());
-- 
GitLab