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 9ba79c9b523e5b336cc8e254ba800d3fc0d262e4..0ea50170d900c316cca40a3998f927e14d7648c8 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 2a00f8b6d6547dded17ef3dd656c70f5fe2e7d40..3dad3085540195d01732d5434733c23073dbe1fb 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 2e2bd6fbcb670c7819b1b10a2d6e4f827fa783e0..ac7f0e413098bddf3ae58d502b7a77dc2d547c53 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 e3f11abeb47c51893bea5c8f2eeefb9d26e2fa4e..daa1dc24683912dfa8d3083786274cae61ea4e93 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 d626cd91230e4cb5e52f0f2905d1dd34ff67a652..407511571315d5cb1b5bcbfa79d074e59a00cbe0 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 572c124b62f6a6a137aa64b9d2e82f0211137a04..4eec12b479342fd062cf6c653a33a9b45e047166 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());