diff --git a/screening/resource/test-data/ConvertToolImageTransformerTest/pond-transformed.png b/screening/resource/test-data/ConvertToolImageTransformerTest/pond-transformed.png new file mode 100644 index 0000000000000000000000000000000000000000..6b41b07cde5e588e2bf182ee759e4d2b1967b131 Binary files /dev/null and b/screening/resource/test-data/ConvertToolImageTransformerTest/pond-transformed.png differ diff --git a/screening/resource/test-data/ConvertToolImageTransformerTest/pond.png b/screening/resource/test-data/ConvertToolImageTransformerTest/pond.png new file mode 100644 index 0000000000000000000000000000000000000000..21f8705bee636013b88b21ab151a1b148805039c Binary files /dev/null and b/screening/resource/test-data/ConvertToolImageTransformerTest/pond.png differ diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/AbstractImageDatasetUploader.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/AbstractImageDatasetUploader.java index 32d0e9b160ec38fffcf42953cefe8d3a89132fea..6bc57261a8affb2a6bc1c24a722846736619cf91 100644 --- a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/AbstractImageDatasetUploader.java +++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/AbstractImageDatasetUploader.java @@ -27,6 +27,7 @@ import java.util.Map.Entry; import java.util.Set; import ch.rinn.restrictions.Private; +import ch.systemsx.cisd.base.image.IImageTransformerFactory; import ch.systemsx.cisd.openbis.dss.etl.ImagingDatabaseHelper.ImagingChannelsMap; import ch.systemsx.cisd.openbis.dss.etl.dataaccess.IImagingQueryDAO; import ch.systemsx.cisd.openbis.plugin.screening.shared.imaging.dataaccess.ImgAcquiredImageDTO; @@ -55,12 +56,16 @@ abstract class AbstractImageDatasetUploader private final RelativeImageReference thumbnailPathOrNull; + private final IImageTransformerFactory imageTransformerFactoryOrNull; + public AcquiredImageInStack(String channelCode, RelativeImageReference imageFilePath, - RelativeImageReference thumbnailPathOrNull) + RelativeImageReference thumbnailPathOrNull, + IImageTransformerFactory imageTransformerFactoryOrNull) { this.channelCode = channelCode.toUpperCase(); this.imageFilePath = imageFilePath; this.thumbnailPathOrNull = thumbnailPathOrNull; + this.imageTransformerFactoryOrNull = imageTransformerFactoryOrNull; } public String getChannelCode() @@ -77,6 +82,11 @@ abstract class AbstractImageDatasetUploader { return thumbnailPathOrNull; } + + public IImageTransformerFactory getImageTransformerFactoryOrNull() + { + return imageTransformerFactoryOrNull; + } } protected static interface ISpotProvider @@ -137,7 +147,7 @@ abstract class AbstractImageDatasetUploader private static AcquiredImageInStack makeAcquiredImageInStack(AcquiredSingleImage image) { return new AcquiredImageInStack(image.getChannelCode(), image.getImageReference(), - image.getThumbnailFilePathOrNull()); + image.getThumbnailFilePathOrNull(), image.getImageTransformerFactoryOrNull()); } private ImgChannelStackDTO makeStackDtoWithouId(AcquiredSingleImage image, @@ -178,19 +188,22 @@ abstract class AbstractImageDatasetUploader List<ImgAcquiredImageDTO> acquiredImageDTOs = imagesToCreate.getAcquiredImages(); for (AcquiredImageInStack image : images) { - long channelTechId = channelsMap.getChannelId(image.getChannelCode()); - ImgImageDTO imageDTO = mkImageWithIdDTO(image.getImageFilePath()); - ImgImageDTO thumbnailDTO = tryMkImageWithIdDTO(image.getThumbnailPathOrNull()); - Long thumbnailId = thumbnailDTO == null ? null : thumbnailDTO.getId(); - ImgAcquiredImageDTO acquiredImage = - mkAcquiredImage(stackId, channelTechId, imageDTO.getId(), thumbnailId); - imageDTOs.add(imageDTO); + + ImgImageDTO thumbnailDTO = tryMkImageWithIdDTO(image.getThumbnailPathOrNull()); + Long thumbnailId = null; if (thumbnailDTO != null) { + thumbnailId = thumbnailDTO.getId(); imageDTOs.add(thumbnailDTO); } + + long channelTechId = channelsMap.getChannelId(image.getChannelCode()); + ImgAcquiredImageDTO acquiredImage = + mkAcquiredImage(stackId, channelTechId, imageDTO.getId(), thumbnailId, + image.getImageTransformerFactoryOrNull()); + acquiredImageDTOs.add(acquiredImage); } } @@ -220,13 +233,14 @@ abstract class AbstractImageDatasetUploader } private ImgAcquiredImageDTO mkAcquiredImage(long stackId, long channelTechId, long imageId, - Long thumbnailId) + Long thumbnailId, IImageTransformerFactory transformerFactoryOrNull) { ImgAcquiredImageDTO acquiredImage = new ImgAcquiredImageDTO(); acquiredImage.setImageId(imageId); acquiredImage.setThumbnailId(thumbnailId); acquiredImage.setChannelStackId(stackId); acquiredImage.setChannelId(channelTechId); + acquiredImage.setImageTransformerFactory(transformerFactoryOrNull); return acquiredImage; } @@ -241,6 +255,7 @@ abstract class AbstractImageDatasetUploader private ImgImageDTO mkImageWithIdDTO(RelativeImageReference imageReferenceOrNull) { + ImgImageDTO dto = new ImgImageDTO(dao.createImageId(), imageReferenceOrNull.getRelativeImagePath(), imageReferenceOrNull.tryGetPage(), diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/AbstractImageStorageProcessor.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/AbstractImageStorageProcessor.java index 299adf9efaecaa9f9aad5a68202bd34cce3d0990..087fe3425e75053c1f0d916fe0ea61366da423da 100644 --- a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/AbstractImageStorageProcessor.java +++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/AbstractImageStorageProcessor.java @@ -32,6 +32,7 @@ import org.apache.commons.io.FilenameUtils; import org.apache.commons.lang.time.DurationFormatUtils; import org.apache.log4j.Logger; +import ch.systemsx.cisd.base.image.IImageTransformerFactory; import ch.systemsx.cisd.bds.hcs.Geometry; import ch.systemsx.cisd.common.collections.CollectionUtils; import ch.systemsx.cisd.common.exceptions.ConfigurationFailureException; @@ -640,6 +641,8 @@ abstract class AbstractImageStorageProcessor extends AbstractStorageProcessor im imageStorageConfiguraton = globalImageStorageConfiguraton; } + setPerImageTransformationIfNeeded(images, imageStorageConfiguraton); + ImageFileExtractionResult extractionResult = new ImageFileExtractionResult(images, invalidFiles, imageDataSetInfo.getChannels(), tileGeometry, imageStorageConfiguraton.getStoreChannelsOnExperimentLevel()); @@ -682,6 +685,20 @@ abstract class AbstractImageStorageProcessor extends AbstractStorageProcessor im return ColorComponent.valueOf(channelColorComponent.name()); } + private void setPerImageTransformationIfNeeded(List<AcquiredSingleImage> images, + ImageStorageConfiguraton imageStorageConfiguraton) + { + if (imageStorageConfiguraton != null + && imageStorageConfiguraton.getImageTransformerFactory() != null) + { + IImageTransformerFactory imgTransformerFactory = + imageStorageConfiguraton.getImageTransformerFactory(); + for (AcquiredSingleImage image : images) { + image.setImageTransformerFactoryOrNull(imgTransformerFactory); + } + } + } + protected IImageFileExtractor tryGetImageFileExtractor(File incomingDataSetDirectory) { return imageFileExtractorOrNull; diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/AcquiredSingleImage.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/AcquiredSingleImage.java index 745daa8167c6a7257d2d8db5fa7f9385309031a4..409583834d2cb8642e8b88dd1f9561154144c7af 100644 --- a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/AcquiredSingleImage.java +++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/AcquiredSingleImage.java @@ -16,6 +16,7 @@ package ch.systemsx.cisd.openbis.dss.etl; +import ch.systemsx.cisd.base.image.IImageTransformerFactory; import ch.systemsx.cisd.bds.hcs.Location; import ch.systemsx.cisd.common.utilities.AbstractHashable; @@ -45,6 +46,8 @@ public class AcquiredSingleImage extends AbstractHashable private RelativeImageReference thumbnailFilePathOrNull; + private IImageTransformerFactory imageTransformerFactoryOrNull; + public AcquiredSingleImage(Location wellLocationOrNull, Location tileLocation, String channelCode, Float timePointOrNull, Float depthOrNull, Integer seriesNumberOrNull, RelativeImageReference imageFilePath) @@ -128,4 +131,15 @@ public class AcquiredSingleImage extends AbstractHashable { this.seriesNumberOrNull = seriesNumber; } + + public IImageTransformerFactory getImageTransformerFactoryOrNull() + { + return imageTransformerFactoryOrNull; + } + + public void setImageTransformerFactoryOrNull( + IImageTransformerFactory imageTransformerFactoryOrNull) + { + this.imageTransformerFactoryOrNull = imageTransformerFactoryOrNull; + } } diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/biozentrum/ConvertToolImageTransformer.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/biozentrum/ConvertToolImageTransformer.java new file mode 100644 index 0000000000000000000000000000000000000000..8454cdc84353476110201c4e89bfa04d802b4fa8 --- /dev/null +++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/biozentrum/ConvertToolImageTransformer.java @@ -0,0 +1,149 @@ +/* + * Copyright 2011 ETH Zuerich, CISD + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package ch.systemsx.cisd.openbis.dss.etl.biozentrum; + +import java.awt.image.BufferedImage; +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import javax.imageio.ImageIO; + +import org.apache.log4j.Logger; + +import ch.systemsx.cisd.base.exceptions.CheckedExceptionTunnel; +import ch.systemsx.cisd.base.image.IImageTransformer; +import ch.systemsx.cisd.base.utilities.OSUtilities; +import ch.systemsx.cisd.common.concurrent.ConcurrencyUtilities; +import ch.systemsx.cisd.common.exceptions.ConfigurationFailureException; +import ch.systemsx.cisd.common.logging.LogCategory; +import ch.systemsx.cisd.common.logging.LogFactory; +import ch.systemsx.cisd.common.process.ProcessExecutionHelper; +import ch.systemsx.cisd.common.process.ProcessIOStrategy; +import ch.systemsx.cisd.common.process.ProcessResult; +import ch.systemsx.cisd.imagereaders.IImageReader; +import ch.systemsx.cisd.imagereaders.ImageReaderConstants; +import ch.systemsx.cisd.imagereaders.ImageReaderFactory; + +/** + * An {@link IImageTransformer} using the convert command line tool for transformations. + * + * @author Kaloyan Enimanev + */ +public class ConvertToolImageTransformer implements IImageTransformer +{ + + private static final String PNG = "png"; + + private static final File convertUtilityOrNull = OSUtilities.findExecutable("convert"); + + private static final Logger machineLog = LogFactory.getLogger(LogCategory.MACHINE, + ConvertToolImageTransformer.class); + + private static final Logger operationLog = LogFactory.getLogger(LogCategory.OPERATION, + ConvertToolImageTransformer.class); + + private final List<String> convertCliArguments; + + ConvertToolImageTransformer(String arguments) + { + this.convertCliArguments = parseCommandArguments(arguments); + } + + public BufferedImage transform(BufferedImage image) + { + File tmpFile = null; + try + { + // TODO KE: we should use the standard input to instead of a temporary file + tmpFile = createTempImageFile(image); + byte[] output = transform(tmpFile); + return toBufferedImage(output); + } catch (IOException ioex) + { + throw CheckedExceptionTunnel.wrapIfNecessary(ioex); + } finally + { + if (tmpFile != null) + { + tmpFile.delete(); + } + } + } + + private BufferedImage toBufferedImage(byte[] output) throws ConfigurationFailureException + { + IImageReader imageReader = + ImageReaderFactory.tryGetReader(ImageReaderConstants.IMAGEIO_LIBRARY, PNG); + if (imageReader == null) + { + throw new ConfigurationFailureException("No ImageIO image readers available"); + } + return imageReader.readImage(output, null); + } + + private byte[] transform(File imageFile) throws IOException + { + String filePath = imageFile.getAbsolutePath(); + + ProcessResult result = + ProcessExecutionHelper.run(getCommandLine(filePath), operationLog, machineLog, + ConcurrencyUtilities.NO_TIMEOUT, + ProcessIOStrategy.BINARY_DISCARD_STDERR_IO_STRATEGY, false); + + if (result.isOK() == false) + { + System.err.println(result.getErrorOutput()); + System.err.println(result.getOutput()); + System.err.println(result.getCommandLine()); + throw new IOException(String.format( + "Error calling 'convert' for image '%s'. Exit value: %d, I/O status: %s", + filePath, result.getExitValue(), result.getProcessIOResult().getStatus())); + } else + { + return result.getBinaryOutput(); + } + + } + + private List<String> parseCommandArguments(String argsString) + { + String[] arguments = argsString.trim().split("\\s"); + return Arrays.asList(arguments); + } + + private List<String> getCommandLine(String filePath) + { + ArrayList<String> result = new ArrayList<String>(); + result.add(convertUtilityOrNull.getPath()); + result.addAll(convertCliArguments); + result.add(filePath); + result.add("png:-"); + return result; + } + + private File createTempImageFile(BufferedImage image) throws IOException + { + File tmpFile = File.createTempFile(getClass().getSimpleName(), PNG); + tmpFile.deleteOnExit(); + ImageIO.write(image, PNG, tmpFile); + return tmpFile; + } + +} diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/biozentrum/ConvertToolImageTransformerFactory.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/biozentrum/ConvertToolImageTransformerFactory.java new file mode 100644 index 0000000000000000000000000000000000000000..8c2591ee481bbfd32f26c726ed8d4699f0862a95 --- /dev/null +++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/biozentrum/ConvertToolImageTransformerFactory.java @@ -0,0 +1,43 @@ +/* + * Copyright 2011 ETH Zuerich, CISD + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package ch.systemsx.cisd.openbis.dss.etl.biozentrum; + +import ch.systemsx.cisd.base.image.IImageTransformer; +import ch.systemsx.cisd.base.image.IImageTransformerFactory; + +/** + * A {@link IImageTransformerFactory} that constructs {@link ConvertToolImageTransformer} instances. + * + * @author Kaloyan Enimanev + */ +public class ConvertToolImageTransformerFactory implements IImageTransformerFactory +{ + private static final long serialVersionUID = 1L; + + private final String convertCliArguments; + + public ConvertToolImageTransformerFactory(String convertCliArguments) + { + this.convertCliArguments = convertCliArguments; + } + + public IImageTransformer createTransformer() + { + return new ConvertToolImageTransformer(convertCliArguments); + } + +} diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dataaccess/IImagingQueryDAO.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dataaccess/IImagingQueryDAO.java index 417eef63693ab7f65a2bf74e5e81a8d8357eed5e..abe4e2a8a478b23454086d224e924c706c569821 100644 --- a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dataaccess/IImagingQueryDAO.java +++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dataaccess/IImagingQueryDAO.java @@ -60,8 +60,8 @@ public interface IImagingQueryDAO extends TransactionQuery, IImagingReadonlyQuer + "(?{1.id}, ?{1.filePath}, ?{1.page}, ?{1.colorComponentAsString})", batchUpdate = true) public void addImages(List<ImgImageDTO> images); - @Update(sql = "insert into ACQUIRED_IMAGES (IMG_ID, THUMBNAIL_ID, CHANNEL_STACK_ID, CHANNEL_ID) values " - + "(?{1.imageId}, ?{1.thumbnailId}, ?{1.channelStackId}, ?{1.channelId})", batchUpdate = true) + @Update(sql = "insert into ACQUIRED_IMAGES (IMG_ID, THUMBNAIL_ID, CHANNEL_STACK_ID, CHANNEL_ID, IMAGE_TRANSFORMER_FACTORY) values " + + "(?{1.imageId}, ?{1.thumbnailId}, ?{1.channelStackId}, ?{1.channelId}, ?{1.serializedImageTransformerFactory})", batchUpdate = true) public void addAcquiredImages(List<ImgAcquiredImageDTO> acquiredImages); // inserts diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/ImageStorageConfiguraton.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/ImageStorageConfiguraton.java index 5674ac8a2762653e5166efb2ff6971140a7412be..b0d1c4a644e8bc13c362a5baec2062d098e7ae88 100644 --- a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/ImageStorageConfiguraton.java +++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/ImageStorageConfiguraton.java @@ -16,6 +16,7 @@ package ch.systemsx.cisd.openbis.dss.etl.dto.api.v1; +import ch.systemsx.cisd.base.image.IImageTransformerFactory; import ch.systemsx.cisd.common.utilities.AbstractHashable; /** @@ -38,6 +39,11 @@ public class ImageStorageConfiguraton extends AbstractHashable /** No preferences by default, each storage processor decides by its own if it is not set. */ private Boolean storeChannelsOnExperimentLevelOrNull = null; + /** + * an image transformation to be applied before the image is stored. + */ + private IImageTransformerFactory imageTransformerFactoryOrNull; + /** Returns the default configuration. */ public static ImageStorageConfiguraton createDefault() { @@ -89,4 +95,17 @@ public class ImageStorageConfiguraton extends AbstractHashable return storeChannelsOnExperimentLevelOrNull; } + public IImageTransformerFactory getImageTransformerFactory() + { + return imageTransformerFactoryOrNull; + } + + /** + * Allows for applying an image transformation before persisting an image in the store. + */ + public void setImageTransformerFactory(IImageTransformerFactory transformerFactory) + { + this.imageTransformerFactoryOrNull = transformerFactory; + } + } diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/SimpleImageDataConfig.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/SimpleImageDataConfig.java index 221dd019dedaa820316fb591a462b582f388983a..d866e4ad55e3ba70906ebdbc4ec07975b7447c5e 100644 --- a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/SimpleImageDataConfig.java +++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/SimpleImageDataConfig.java @@ -18,6 +18,9 @@ package ch.systemsx.cisd.openbis.dss.etl.dto.api.v1; import java.util.List; +import ch.systemsx.cisd.base.image.IImageTransformerFactory; +import ch.systemsx.cisd.common.shared.basic.utils.StringUtils; +import ch.systemsx.cisd.openbis.dss.etl.biozentrum.ConvertToolImageTransformerFactory; import ch.systemsx.cisd.openbis.plugin.screening.shared.api.v1.dto.Geometry; import ch.systemsx.cisd.openbis.plugin.screening.shared.basic.dto.ScreeningConstants; @@ -110,6 +113,8 @@ abstract public class SimpleImageDataConfig private OriginalDataStorageFormat originalDataStorageFormat = OriginalDataStorageFormat.UNCHANGED; + private String convertTransformationCliArgumentsOrNull; + // --- getters & setters ---------------------------------------------- public ImageStorageConfiguraton getImageStorageConfiguration() @@ -130,6 +135,13 @@ abstract public class SimpleImageDataConfig thumbnailsStorageFormat.setHighQuality(generateThumbnailsInHighQuality); imageStorageConfiguraton.setThumbnailsStorageFormat(thumbnailsStorageFormat); } + if (false == StringUtils.isBlank(convertTransformationCliArgumentsOrNull)) + { + IImageTransformerFactory convertTransformerFactory = + new ConvertToolImageTransformerFactory(convertTransformationCliArgumentsOrNull); + imageStorageConfiguraton.setImageTransformerFactory(convertTransformerFactory); + + } return imageStorageConfiguraton; } @@ -321,4 +333,18 @@ abstract public class SimpleImageDataConfig return isMeasured; } + public String getConvertTransformationCliArguments() + { + return convertTransformationCliArgumentsOrNull; + } + + /** + * Sets parameters for the 'convert' command line tool, which will be used to apply an image + * transformation before persisting the images in the data store. + */ + public void setConvertTransformationCliArguments(String convertTransformationCliArguments) + { + this.convertTransformationCliArgumentsOrNull = convertTransformationCliArguments; + } + } diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/jython/SimpleImageDataSetRegistrator.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/jython/SimpleImageDataSetRegistrator.java index ca07053cf9304b6f8f1e252a1082e08fd1f00c97..f26648c429a4e0059b8435d5fecfaff4a7b3eb54 100644 --- a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/jython/SimpleImageDataSetRegistrator.java +++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/jython/SimpleImageDataSetRegistrator.java @@ -69,18 +69,18 @@ public class SimpleImageDataSetRegistrator } public static DataSetRegistrationDetails<ImageDataSetInformation> createImageDatasetDetails( - SimpleImageDataConfig imageDataSet, File incoming, + SimpleImageDataConfig simpleImageConfig, File incoming, IDataSetRegistrationDetailsFactory<ImageDataSetInformation> factory) { - return new SimpleImageDataSetRegistrator(imageDataSet).createImageDatasetDetails(incoming, + return new SimpleImageDataSetRegistrator(simpleImageConfig).createImageDatasetDetails(incoming, factory); } - private final SimpleImageDataConfig imageDataSet; + private final SimpleImageDataConfig simpleImageConfig; - private SimpleImageDataSetRegistrator(SimpleImageDataConfig imageDataSet) + private SimpleImageDataSetRegistrator(SimpleImageDataConfig simpleImageConfig) { - this.imageDataSet = imageDataSet; + this.simpleImageConfig = simpleImageConfig; } private DataSetRegistrationDetails<ImageDataSetInformation> createImageDatasetDetails( @@ -101,7 +101,7 @@ public class SimpleImageDataSetRegistrator private List<File> listImageFiles(final File incomingDirectory) { return FileOperations.getInstance().listFiles(incomingDirectory, - imageDataSet.getRecognizedImageExtensions(), true); + simpleImageConfig.getRecognizedImageExtensions(), true); } /** @@ -115,7 +115,7 @@ public class SimpleImageDataSetRegistrator { String imageRelativePath = FileUtilities.getRelativeFile(incomingDirectory, new File(imageFile.getPath())); - ImageMetadata imageTokens = imageDataSet.extractImageMetadata(imageRelativePath); + ImageMetadata imageTokens = simpleImageConfig.extractImageMetadata(imageRelativePath); imageTokens.ensureValid(); imageTokensList.add(new ImageTokensWithPath(imageTokens, imageRelativePath)); } @@ -124,7 +124,7 @@ public class SimpleImageDataSetRegistrator throw UserFailureException.fromTemplate( "Incoming directory '%s' contains no images with extensions %s!", incomingDirectory.getPath(), - CollectionUtils.abbreviate(imageDataSet.getRecognizedImageExtensions(), -1)); + CollectionUtils.abbreviate(simpleImageConfig.getRecognizedImageExtensions(), -1)); } return imageTokensList; } @@ -135,7 +135,7 @@ public class SimpleImageDataSetRegistrator protected ImageFileInfo createImageInfo(ImageTokensWithPath imageTokens, Geometry tileGeometry) { Location tileCoords = - imageDataSet.getTileCoordinates(imageTokens.getTileNumber(), tileGeometry); + simpleImageConfig.getTileCoordinates(imageTokens.getTileNumber(), tileGeometry); ImageFileInfo img = new ImageFileInfo(imageTokens.getChannelCode(), tileCoords.getRow(), tileCoords.getColumn(), imageTokens.getImagePath()); @@ -172,7 +172,7 @@ public class SimpleImageDataSetRegistrator List<Channel> channels = new ArrayList<Channel>(); for (String channelCode : channelCodes) { - channels.add(imageDataSet.createChannel(channelCode)); + channels.add(simpleImageConfig.createChannel(channelCode)); } return channels; } @@ -195,18 +195,18 @@ public class SimpleImageDataSetRegistrator */ protected void setImageDataset(File incoming, ImageDataSetInformation dataset) { - dataset.setDatasetTypeCode(imageDataSet.getDataSetType()); - dataset.setFileFormatCode(imageDataSet.getFileFormatType()); - dataset.setMeasured(imageDataSet.isMeasuredData()); + dataset.setDatasetTypeCode(simpleImageConfig.getDataSetType()); + dataset.setFileFormatCode(simpleImageConfig.getFileFormatType()); + dataset.setMeasured(simpleImageConfig.isMeasuredData()); - String sampleCode = imageDataSet.getPlateCode(); - String spaceCode = imageDataSet.getPlateSpace(); + String sampleCode = simpleImageConfig.getPlateCode(); + String spaceCode = simpleImageConfig.getPlateSpace(); dataset.setSample(spaceCode, sampleCode); dataset.setMeasured(true); List<ImageTokensWithPath> imageTokensList = parseImageTokens(incoming); int maxTileNumber = getMaxTileNumber(imageTokensList); - Geometry tileGeometry = imageDataSet.getTileGeometry(imageTokensList, maxTileNumber); + Geometry tileGeometry = simpleImageConfig.getTileGeometry(imageTokensList, maxTileNumber); List<ImageFileInfo> images = createImageInfos(imageTokensList, tileGeometry); List<Channel> channels = getAvailableChannels(images); @@ -214,16 +214,16 @@ public class SimpleImageDataSetRegistrator dataset.setChannels(channels); dataset.setTileGeometry(tileGeometry.getNumberOfRows(), tileGeometry.getNumberOfColumns()); - dataset.setImageStorageConfiguraton(imageDataSet.getImageStorageConfiguration()); + dataset.setImageStorageConfiguraton(simpleImageConfig.getImageStorageConfiguration()); } private <T extends DataSetInformation> void setRegistrationDetails( DataSetRegistrationDetails<T> registrationDetails, T dataset) { registrationDetails.setDataSetInformation(dataset); - registrationDetails.setFileFormatType(new FileFormatType(imageDataSet.getFileFormatType())); - registrationDetails.setDataSetType(new DataSetType(imageDataSet.getDataSetType())); - registrationDetails.setMeasuredData(imageDataSet.isMeasuredData()); + registrationDetails.setFileFormatType(new FileFormatType(simpleImageConfig.getFileFormatType())); + registrationDetails.setDataSetType(new DataSetType(simpleImageConfig.getDataSetType())); + registrationDetails.setMeasuredData(simpleImageConfig.isMeasuredData()); } diff --git a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/imaging/dataaccess/AbstractImageTransformerFactoryHolder.java b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/imaging/dataaccess/AbstractImageTransformerFactoryHolder.java index 90944b759cfc4c2f1264b2f17894502a71036896..2d23bc7066217a202068a6cc8bdbc2c564e115ae 100644 --- a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/imaging/dataaccess/AbstractImageTransformerFactoryHolder.java +++ b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/imaging/dataaccess/AbstractImageTransformerFactoryHolder.java @@ -1,5 +1,6 @@ /* * Copyright 2010 ETH Zuerich, CISD + * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -25,7 +26,7 @@ import ch.systemsx.cisd.base.image.IImageTransformerFactory; /** * @author Franz-Josef Elmer */ -abstract class AbstractImageTransformerFactoryHolder extends AbstractImgIdentifiable +public abstract class AbstractImageTransformerFactoryHolder extends AbstractImgIdentifiable { @ResultColumn("IMAGE_TRANSFORMER_FACTORY") private byte[] serializedImageTransformerFactory; @@ -40,7 +41,18 @@ abstract class AbstractImageTransformerFactoryHolder extends AbstractImgIdentifi this.serializedImageTransformerFactory = serializedImageTransformerFactory; } - public IImageTransformerFactory tryGetImageTransformerFactory() + public final void setImageTransformerFactory(IImageTransformerFactory factory) + { + if (factory != null) + { + this.serializedImageTransformerFactory = SerializationUtils.serialize(factory); + } else + { + this.serializedImageTransformerFactory = null; + } + } + + public final IImageTransformerFactory tryGetImageTransformerFactory() { if (serializedImageTransformerFactory == null) { diff --git a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/imaging/dataaccess/ImgAcquiredImageDTO.java b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/imaging/dataaccess/ImgAcquiredImageDTO.java index 767a3d10a70b0c31ccfc7ab5b52fbc8ffc1905e0..448fd7ead8d8663db4d1da350ccdc127ccce756d 100644 --- a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/imaging/dataaccess/ImgAcquiredImageDTO.java +++ b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/imaging/dataaccess/ImgAcquiredImageDTO.java @@ -21,7 +21,7 @@ import net.lemnik.eodsql.ResultColumn; /** * @author Tomasz Pylak */ -public class ImgAcquiredImageDTO extends AbstractImgIdentifiable +public class ImgAcquiredImageDTO extends AbstractImageTransformerFactoryHolder { @ResultColumn("IMG_ID") private long imageId; diff --git a/screening/sourceTest/java/ch/systemsx/cisd/openbis/dss/etl/biozentrum/ConvertToolImageTransformerTest.java b/screening/sourceTest/java/ch/systemsx/cisd/openbis/dss/etl/biozentrum/ConvertToolImageTransformerTest.java new file mode 100644 index 0000000000000000000000000000000000000000..6104232c32139da7df2d3c53a3d1811095824422 --- /dev/null +++ b/screening/sourceTest/java/ch/systemsx/cisd/openbis/dss/etl/biozentrum/ConvertToolImageTransformerTest.java @@ -0,0 +1,81 @@ +/* + * Copyright 2011 ETH Zuerich, CISD + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package ch.systemsx.cisd.openbis.dss.etl.biozentrum; + +import java.awt.image.BufferedImage; +import java.awt.image.DataBuffer; +import java.io.File; + +import org.testng.AssertJUnit; +import org.testng.annotations.Test; + +import ch.systemsx.cisd.base.image.IImageTransformer; +import ch.systemsx.cisd.openbis.dss.generic.shared.utils.ImageUtil; + +/** + * @author Kaloyan Enimanev + */ +public class ConvertToolImageTransformerTest extends AssertJUnit +{ + private final String IMAGE_FOLDER = "./resource/test-data/" + getClass().getSimpleName(); + + private final String CONVERT_PARAMS = + " -contrast-stretch 0 -edge 1 -threshold 1 -transparent black "; + + @Test + public void testTransformation() + { + BufferedImage templateImage = readImage("pond.png"); + BufferedImage expected = readImage("pond-transformed.png"); + + BufferedImage transformationResult = createTransformer().transform(templateImage); + + assertNotNull(transformationResult); + assertEqualImages(expected, transformationResult); + + } + + private IImageTransformer createTransformer() + { + ConvertToolImageTransformerFactory factory = + new ConvertToolImageTransformerFactory(CONVERT_PARAMS); + return factory.createTransformer(); + } + + private void assertEqualImages(BufferedImage expected, BufferedImage actual) + { + DataBuffer expectedDB = expected.getData().getDataBuffer(); + DataBuffer actualDB = actual.getData().getDataBuffer(); + + String notEqualError = "Converted image not equal to expected result"; + assertEquals(notEqualError, expectedDB.getSize(), actualDB.getSize()); + + for (int i = 0; i < expectedDB.getSize(); i++) + { + assertEquals(notEqualError, expectedDB.getElem(i), actualDB.getElem(i)); + + } + + } + + private BufferedImage readImage(String image) + { + File imageFile = new File(IMAGE_FOLDER, image); + return ImageUtil.loadImage(imageFile); + } + +}