Skip to content
Snippets Groups Projects
Commit f4f91dee authored by anttil's avatar anttil
Browse files

SSDM-774 Allow to assign a representative thumbnail for a dataset

SVN: 32538
parent 5f3fc72a
No related branches found
No related tags found
No related merge requests found
Showing
with 271 additions and 2 deletions
...@@ -23,5 +23,5 @@ package ch.systemsx.cisd.openbis.generic.shared.basic.dto; ...@@ -23,5 +23,5 @@ package ch.systemsx.cisd.openbis.generic.shared.basic.dto;
*/ */
public final class ServiceVersionHolder public final class ServiceVersionHolder
{ {
public static final int VERSION = 35; // for S145 public static final int VERSION = 36; // for S190
} }
package ch.systemsx.cisd.openbis.dss.etl.dto.api;
import java.awt.image.BufferedImage;
import java.util.List;
import ch.systemsx.cisd.openbis.dss.etl.dto.api.impl.ImageDataSetInformation;
import ch.systemsx.cisd.openbis.dss.etl.dto.api.impl.ImageDataSetStructure;
public interface IImageGenerationAlgorithm
{
public List<BufferedImage> generateImages(ImageDataSetInformation information, ImageDataSetStructure structure);
public String getDataSetTypeCode();
public String getImageFileName(int index);
}
...@@ -47,6 +47,8 @@ abstract public class SimpleImageDataConfig ...@@ -47,6 +47,8 @@ abstract public class SimpleImageDataConfig
{ {
// --- one of the following two methods has to be overridden ----------------- // --- one of the following two methods has to be overridden -----------------
private IImageGenerationAlgorithm imageGenerationAlgorithm;
/** /**
* Extracts tile number, channel code and well code for a given relative path to a single image. * Extracts tile number, channel code and well code for a given relative path to a single image.
* This method should overridden to deal with files containing single images. It is ignored if * This method should overridden to deal with files containing single images. It is ignored if
...@@ -997,5 +999,12 @@ abstract public class SimpleImageDataConfig ...@@ -997,5 +999,12 @@ abstract public class SimpleImageDataConfig
{ {
this.colorDepth = colorDepth; this.colorDepth = colorDepth;
} }
public IImageGenerationAlgorithm getImageGenerationAlgorithm() {
return imageGenerationAlgorithm;
}
public void setImageGenerationAlgorithm(IImageGenerationAlgorithm algorithm) {
this.imageGenerationAlgorithm = algorithm;
}
} }
package ch.systemsx.cisd.openbis.dss.etl.dto.api.impl;
import java.awt.image.BufferedImage;
import java.io.Serializable;
import java.util.Collections;
import java.util.List;
import ch.systemsx.cisd.openbis.dss.etl.dto.api.IImageGenerationAlgorithm;
import ch.systemsx.cisd.openbis.generic.shared.IServer;
public class EmptyImageCreationAlgorithm implements IImageGenerationAlgorithm, Serializable
{
private static final long serialVersionUID = IServer.VERSION;
@Override
public String getDataSetTypeCode()
{
throw new UnsupportedOperationException();
}
@Override
public List<BufferedImage> generateImages(ImageDataSetInformation information, ImageDataSetStructure structure)
{
return Collections.emptyList();
}
@Override
public String getImageFileName(int index)
{
throw new UnsupportedOperationException();
}
}
...@@ -24,6 +24,7 @@ import ch.systemsx.cisd.common.shared.basic.string.CommaSeparatedListBuilder; ...@@ -24,6 +24,7 @@ import ch.systemsx.cisd.common.shared.basic.string.CommaSeparatedListBuilder;
import ch.systemsx.cisd.openbis.dss.etl.dto.api.BasicDataSetInformation; import ch.systemsx.cisd.openbis.dss.etl.dto.api.BasicDataSetInformation;
import ch.systemsx.cisd.openbis.dss.etl.dto.api.Channel; import ch.systemsx.cisd.openbis.dss.etl.dto.api.Channel;
import ch.systemsx.cisd.openbis.dss.etl.dto.api.ChannelColorComponent; 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.generic.shared.dto.DataSetInformation; import ch.systemsx.cisd.openbis.dss.generic.shared.dto.DataSetInformation;
import ch.systemsx.cisd.openbis.generic.shared.IServer; import ch.systemsx.cisd.openbis.generic.shared.IServer;
...@@ -60,6 +61,8 @@ public class ImageDataSetInformation extends BasicDataSetInformation ...@@ -60,6 +61,8 @@ public class ImageDataSetInformation extends BasicDataSetInformation
private Integer colorDepth; private Integer colorDepth;
private final List<DataSetInformation> secondaryDataSets = new ArrayList<DataSetInformation>(); private final List<DataSetInformation> secondaryDataSets = new ArrayList<DataSetInformation>();
private IImageGenerationAlgorithm imageGenerationAlgorithm;
public File getIncomingDirectory() public File getIncomingDirectory()
{ {
...@@ -222,4 +225,13 @@ public class ImageDataSetInformation extends BasicDataSetInformation ...@@ -222,4 +225,13 @@ public class ImageDataSetInformation extends BasicDataSetInformation
} }
return buffer.toString(); return buffer.toString();
} }
public void setAlgorithm(IImageGenerationAlgorithm imageGenerationAlgorithm)
{
this.imageGenerationAlgorithm = imageGenerationAlgorithm;
}
public IImageGenerationAlgorithm getAlgorithm() {
return imageGenerationAlgorithm;
}
} }
package ch.systemsx.cisd.openbis.dss.etl.dto.api.impl;
import java.awt.geom.AffineTransform;
import java.awt.image.AffineTransformOp;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.Serializable;
import java.util.Collections;
import java.util.List;
import ch.systemsx.cisd.openbis.common.io.FileBasedContentNode;
import ch.systemsx.cisd.openbis.dss.etl.Utils;
import ch.systemsx.cisd.openbis.dss.etl.dto.ImageLibraryInfo;
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.generic.shared.IServer;
public class MaximumIntensityProjectionGenerationAlgorithm implements IImageGenerationAlgorithm, Serializable
{
private static final long serialVersionUID = IServer.VERSION;
private transient BufferedImage result = null;
private String dataSetTypeCode;
private String filename;
private int width;
private int height;
public MaximumIntensityProjectionGenerationAlgorithm(String dataSetTypeCode) {
this(dataSetTypeCode, 0, 0);
}
public MaximumIntensityProjectionGenerationAlgorithm(String dataSetTypeCode, String filename) {
this(dataSetTypeCode, 0, 0, filename);
}
public MaximumIntensityProjectionGenerationAlgorithm(String dataSetTypeCode, int width, int height) {
this(dataSetTypeCode, width, height, "maximum_intensity_projection");
}
public MaximumIntensityProjectionGenerationAlgorithm(String dataSetTypeCode, int width, int height, String filename) {
this.dataSetTypeCode = dataSetTypeCode;
this.width = width;
this.height = height;
this.filename = filename;
}
@Override
public String getDataSetTypeCode()
{
return dataSetTypeCode;
}
@Override
public List<BufferedImage> generateImages(ImageDataSetInformation information, ImageDataSetStructure structure)
{
ImageLibraryInfo library = structure.getImageStorageConfiguraton().tryGetImageLibrary();
List<ImageFileInfo> images = structure.getImages();
int maxIntensity = 0;
for (ImageFileInfo image: images) {
String imagePath = image.getImageRelativePath();
if (image.tryGetTimepoint() == null || image.tryGetTimepoint() != 0) {
continue;
}
BufferedImage imageData = Utils.loadUnchangedImage(new FileBasedContentNode(new File(
information.getIncomingDirectory(), imagePath)), image.tryGetUniqueStringIdentifier(), library);
maxIntensity = addImage(imageData);
}
if (result == null) {
return Collections.emptyList();
} else {
for (int y=0; y<result.getHeight(); y++) {
for (int x=0; x<result.getWidth(); x++) {
result.setRGB(x, y, adjust(result.getRGB(x, y), maxIntensity));
}
}
if (width > 0 && height > 0) {
BufferedImage scaled = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
AffineTransform at = new AffineTransform();
at.scale((double)width / (double)result.getWidth(), (double)height / (double)result.getHeight());
AffineTransformOp scaleOp = new AffineTransformOp(at, AffineTransformOp.TYPE_BILINEAR);
result = scaleOp.filter(result, scaled);
}
return Collections.singletonList(result);
}
}
private int adjust(int rgb, int maxIntensity)
{
if (maxIntensity > 255) {
maxIntensity = 255;
}
int r = new Double( ((double)getRed(rgb)) / ((double)maxIntensity) * 255).intValue();
int g = new Double( ((double)getGreen(rgb)) / ((double)maxIntensity) * 255).intValue();
int b = new Double( ((double)getBlue(rgb)) / ((double)maxIntensity) * 255).intValue();
return (r << 16) + (g << 8) + b;
}
private int addImage(BufferedImage image)
{
System.out.println("Adding image "+image.toString());
if (result == null) {
result = new BufferedImage(image.getWidth(),image.getHeight(), BufferedImage.TYPE_INT_RGB);
for (int y=0; y<image.getHeight(); y++) {
for (int x=0; x<image.getWidth(); x++) {
image.setRGB(x,y, 0);
}
}
}
int maxIntensity = 0;
for (int y=0; y<image.getHeight(); y++) {
for (int x=0; x<image.getWidth(); x++) {
int rgb1 = result.getRGB(x,y);
int rgb2 = image.getRGB(x,y);
int intensity1 = intensity(rgb1);
int intensity2 = intensity(rgb2);
if (intensity1 > maxIntensity) {
maxIntensity = intensity1;
}
if (intensity2 > maxIntensity) {
maxIntensity = intensity2;
}
result.setRGB(x,y, intensity1 > intensity2 ? rgb1 : rgb2);
}
}
return maxIntensity;
}
private int intensity(int rgb)
{
double r = getRed(rgb);
double g = getGreen(rgb);
double b = getBlue(rgb);
return new Double(Math.sqrt(r*r + g*g + b*b)).intValue();
}
private int getBlue(int rgb)
{
return rgb & 0xff;
}
private int getGreen(int rgb)
{
return (rgb >> 8) & 0xff;
}
private int getRed(int rgb)
{
return (rgb >> 16) & 0xff;
}
@Override
public String getImageFileName(int index)
{
return filename;
}
}
...@@ -19,6 +19,7 @@ package ch.systemsx.cisd.openbis.dss.etl.jython.v2; ...@@ -19,6 +19,7 @@ package ch.systemsx.cisd.openbis.dss.etl.jython.v2;
import static ch.systemsx.cisd.openbis.plugin.screening.shared.basic.dto.ScreeningConstants.MICROSCOPY_CONTAINER_TYPE_SUBSTRING; import static ch.systemsx.cisd.openbis.plugin.screening.shared.basic.dto.ScreeningConstants.MICROSCOPY_CONTAINER_TYPE_SUBSTRING;
import static ch.systemsx.cisd.openbis.plugin.screening.shared.basic.dto.ScreeningConstants.MICROSCOPY_IMAGE_TYPE_SUBSTRING; import static ch.systemsx.cisd.openbis.plugin.screening.shared.basic.dto.ScreeningConstants.MICROSCOPY_IMAGE_TYPE_SUBSTRING;
import java.awt.image.BufferedImage;
import java.io.BufferedWriter; import java.io.BufferedWriter;
import java.io.File; import java.io.File;
import java.io.FileWriter; import java.io.FileWriter;
...@@ -29,6 +30,8 @@ import java.util.LinkedList; ...@@ -29,6 +30,8 @@ import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.Properties; import java.util.Properties;
import javax.imageio.ImageIO;
import ch.systemsx.cisd.base.exceptions.CheckedExceptionTunnel; import ch.systemsx.cisd.base.exceptions.CheckedExceptionTunnel;
import ch.systemsx.cisd.common.exceptions.UserFailureException; import ch.systemsx.cisd.common.exceptions.UserFailureException;
import ch.systemsx.cisd.etlserver.registrator.DataSetRegistrationDetails; import ch.systemsx.cisd.etlserver.registrator.DataSetRegistrationDetails;
...@@ -45,6 +48,7 @@ import ch.systemsx.cisd.openbis.dss.Constants; ...@@ -45,6 +48,7 @@ import ch.systemsx.cisd.openbis.dss.Constants;
import ch.systemsx.cisd.openbis.dss.etl.Hdf5ThumbnailGenerator; import ch.systemsx.cisd.openbis.dss.etl.Hdf5ThumbnailGenerator;
import ch.systemsx.cisd.openbis.dss.etl.Utils; import ch.systemsx.cisd.openbis.dss.etl.Utils;
import ch.systemsx.cisd.openbis.dss.etl.dto.ImageLibraryInfo; import ch.systemsx.cisd.openbis.dss.etl.dto.ImageLibraryInfo;
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.etl.dto.api.ImageFileInfo;
import ch.systemsx.cisd.openbis.dss.etl.dto.api.SimpleImageDataConfig; import ch.systemsx.cisd.openbis.dss.etl.dto.api.SimpleImageDataConfig;
import ch.systemsx.cisd.openbis.dss.etl.dto.api.ThumbnailsStorageFormat; import ch.systemsx.cisd.openbis.dss.etl.dto.api.ThumbnailsStorageFormat;
...@@ -341,6 +345,29 @@ public class ImagingDataSetRegistrationTransaction extends DataSetRegistrationTr ...@@ -341,6 +345,29 @@ public class ImagingDataSetRegistrationTransaction extends DataSetRegistrationTr
} }
containedDataSetCodes.add(mainDataset.getDataSetCode()); containedDataSetCodes.add(mainDataset.getDataSetCode());
IImageGenerationAlgorithm algorithm = imageDataSetInformation.getAlgorithm();
List<BufferedImage> images = algorithm != null ? algorithm.generateImages(imageDataSetInformation, imageDataSetStructure) : new ArrayList<BufferedImage>();
if (images.size() > 0) {
IDataSet representative = createNewDataSet(algorithm.getDataSetTypeCode());
int i=0;
for (BufferedImage imageData: images) {
String imageFile = createNewFile(representative, algorithm.getImageFileName(i));
File f = new File(imageFile);
try
{
ImageIO.write(imageData, "png", f);
} catch (IOException e)
{
e.printStackTrace();
}
i++;
}
containedDataSetCodes.add(representative.getDataSetCode());
thumbnailDatasets.add(representative);
}
for (IDataSet thumbnailDataset : thumbnailDatasets) for (IDataSet thumbnailDataset : thumbnailDatasets)
{ {
...@@ -353,7 +380,7 @@ public class ImagingDataSetRegistrationTransaction extends DataSetRegistrationTr ...@@ -353,7 +380,7 @@ public class ImagingDataSetRegistrationTransaction extends DataSetRegistrationTr
containerDataset.setThumbnailDatasets(thumbnailDatasets); containerDataset.setThumbnailDatasets(thumbnailDatasets);
String containerDataSetCode = containerDataset.getDataSetCode(); String containerDataSetCode = containerDataset.getDataSetCode();
imageDataSetInformation.setContainerDatasetPermId(containerDataSetCode); imageDataSetInformation.setContainerDatasetPermId(containerDataSetCode);
return containerDataset; return containerDataset;
} }
......
...@@ -204,6 +204,7 @@ public class SimpleImageDataSetRegistrator ...@@ -204,6 +204,7 @@ public class SimpleImageDataSetRegistrator
imageDataset.setColorDepth(simpleImageConfig.getColorDepth()); imageDataset.setColorDepth(simpleImageConfig.getColorDepth());
setRegistrationDetails(registrationDetails, imageDataset); setRegistrationDetails(registrationDetails, imageDataset);
registrationDetails.getDataSetInformation().setAlgorithm(simpleImageConfig.getImageGenerationAlgorithm());
return registrationDetails; return registrationDetails;
} }
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment