diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/AbsoluteImageReference.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/AbsoluteImageReference.java index 030dbe2f8b3b748b93190dce70332197bd45960f..794413d82c2125fdfa5ad0d5e03aa0513084a605 100644 --- a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/AbsoluteImageReference.java +++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/AbsoluteImageReference.java @@ -23,6 +23,7 @@ import ch.systemsx.cisd.openbis.dss.etl.dto.ImageLibraryInfo; import ch.systemsx.cisd.openbis.dss.etl.dto.ImageTransfomationFactories; import ch.systemsx.cisd.openbis.dss.generic.server.images.dto.RequestedImageSize; import ch.systemsx.cisd.openbis.dss.generic.shared.utils.ImageUtil; +import ch.systemsx.cisd.openbis.plugin.screening.shared.basic.dto.ImageChannelColor; import ch.systemsx.cisd.openbis.plugin.screening.shared.imaging.dataaccess.ColorComponent; /** @@ -45,15 +46,14 @@ public class AbsoluteImageReference extends AbstractImageReference private BufferedImage image; - // This is an artificial value which helps to keep coloring channels constant. Starts with 0. - // Unique for a given experiment or dataset (if channels are per dataset). - private int channelIndex; + private ImageChannelColor channelColor; /** * @param content is the original content before choosing the color component and the page */ public AbsoluteImageReference(IContent content, String uniqueId, Integer pageOrNull, - ColorComponent colorComponentOrNull, RequestedImageSize imageSize, int channelIndex, + ColorComponent colorComponentOrNull, RequestedImageSize imageSize, + ImageChannelColor channelColor, ImageTransfomationFactories imageTransfomationFactories, ImageLibraryInfo imageLibraryOrNull) { @@ -64,7 +64,7 @@ public class AbsoluteImageReference extends AbstractImageReference this.content = content; this.uniqueId = uniqueId; this.imageSize = imageSize; - this.channelIndex = channelIndex; + this.channelColor = channelColor; this.imageTransfomationFactories = imageTransfomationFactories; this.imageLibraryOrNull = imageLibraryOrNull; } @@ -128,16 +128,16 @@ public class AbsoluteImageReference extends AbstractImageReference return imageTransfomationFactories; } - public int getChannelIndex() + public ImageChannelColor getChannelColor() { - return channelIndex; + return channelColor; } public AbsoluteImageReference createWithoutColorComponent() { ColorComponent colorComponent = null; return new AbsoluteImageReference(content, uniqueId, tryGetPage(), colorComponent, - imageSize, channelIndex, imageTransfomationFactories, imageLibraryOrNull); + imageSize, channelColor, imageTransfomationFactories, imageLibraryOrNull); } } \ No newline at end of file diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/ImagingDatabaseHelper.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/ImagingDatabaseHelper.java index 9dc994cc37ad6880ec22344578b3ffa8dca8005b..ff2d2fbfc056fb4f1e12ebf0b4abeb1d3164b638 100644 --- a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/ImagingDatabaseHelper.java +++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/ImagingDatabaseHelper.java @@ -17,9 +17,12 @@ package ch.systemsx.cisd.openbis.dss.etl; import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Set; +import ch.rinn.restrictions.Private; import ch.systemsx.cisd.common.exceptions.UserFailureException; import ch.systemsx.cisd.openbis.dss.etl.dataaccess.IImagingQueryDAO; import ch.systemsx.cisd.openbis.dss.etl.dto.api.v1.Channel; @@ -237,7 +240,8 @@ public class ImagingDatabaseHelper } /** Logic to find or create channels */ - private static class ImagingChannelsCreator + @Private + static class ImagingChannelsCreator { private final IImagingQueryDAO dao; @@ -290,22 +294,56 @@ public class ImagingDatabaseHelper private Map<String, Long> createChannels(ChannelOwner channelOwner, List<Channel> channels) { - int colorIndex = 0; Map<String, Long> map = new HashMap<String, Long>(); + fillMissingChannelColors(channels); for (Channel channel : channels) { - if (channel.tryGetChannelColor() == null) - { - ChannelColor channelColor = ChannelColor.createFromIndex(colorIndex); - channel.setChannelColor(channelColor); - colorIndex++; - } ImgChannelDTO channelDTO = createChannel(channel, channelOwner); addChannel(map, channelDTO); } return map; } + @Private + static void fillMissingChannelColors(List<Channel> channels) + { + Set<Integer> usedColorsIndieces = createUsedColorsIndiecesSet(channels); + for (Channel channel : channels) + { + if (channel.tryGetChannelColor() == null) + { + int colorIndex = getSmallestUnused(usedColorsIndieces); + ChannelColor color = ChannelColor.createFromIndex(colorIndex); + channel.setChannelColor(color); + usedColorsIndieces.add(colorIndex); + } + } + } + + private static Set<Integer> createUsedColorsIndiecesSet(List<Channel> channels) + { + Set<Integer> usedColorsIndieces = new HashSet<Integer>(); + for (Channel channel : channels) + { + ChannelColor channelColor = channel.tryGetChannelColor(); + if (channelColor != null) + { + usedColorsIndieces.add(channelColor.getColorOrderIndex()); + } + } + return usedColorsIndieces; + } + + private static int getSmallestUnused(Set<Integer> usedColorsIndieces) + { + int colorIndex = 0; + while (usedColorsIndieces.contains(colorIndex)) + { + colorIndex++; + } + return colorIndex; + } + private static void addChannel(Map<String, Long> map, ImgChannelDTO channelDTO) { map.put(channelDTO.getCode(), channelDTO.getId()); diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dataaccess/ImagingDatasetLoader.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dataaccess/ImagingDatasetLoader.java index 2c87c40a4627f4d729b956b9a0b8b50fa2b7fcfe..cbd95afbdcc3e1099df46b56b32fa0174d82cfd2 100644 --- a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dataaccess/ImagingDatasetLoader.java +++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dataaccess/ImagingDatasetLoader.java @@ -34,6 +34,7 @@ import ch.systemsx.cisd.openbis.dss.generic.server.images.dto.ImageChannelStackR import ch.systemsx.cisd.openbis.dss.generic.server.images.dto.ImageChannelStackReference.MicroscopyChannelStackByLocationReference; import ch.systemsx.cisd.openbis.dss.generic.server.images.dto.RequestedImageSize; import ch.systemsx.cisd.openbis.dss.generic.shared.dto.Size; +import ch.systemsx.cisd.openbis.plugin.screening.shared.basic.dto.ImageChannelColor; import ch.systemsx.cisd.openbis.plugin.screening.shared.imaging.HCSDatasetLoader; import ch.systemsx.cisd.openbis.plugin.screening.shared.imaging.dataaccess.ColorComponent; import ch.systemsx.cisd.openbis.plugin.screening.shared.imaging.dataaccess.IImagingReadonlyQueryDAO; @@ -130,10 +131,10 @@ public class ImagingDatasetLoader extends HCSDatasetLoader implements IImagingDa ColorComponent colorComponent = imageDTO.getColorComponent(); ImageTransfomationFactories imageTransfomationFactories = createImageTransfomationFactories(imageDTO, channel); - int channelIndex = getChannelIndex(channel); + ImageChannelColor channelColor = ImageChannelColor.valueOf(channel.getDbChannelColor()); ImageLibraryInfo imageLibrary = tryGetImageLibrary(dataset, useNativeImageLibrary); return new AbsoluteImageReference(content, path, imageDTO.getPage(), colorComponent, - imageSize, channelIndex, imageTransfomationFactories, imageLibrary); + imageSize, channelColor, imageTransfomationFactories, imageLibrary); } private ImageTransfomationFactories createImageTransfomationFactories(ImgImageDTO imageDTO, @@ -157,20 +158,6 @@ public class ImagingDatasetLoader extends HCSDatasetLoader implements IImagingDa return imageTransformerFactory; } - private int getChannelIndex(ImgChannelDTO chosenChannel) - { - int index = 0; - for (ImgChannelDTO channel : channels) - { - if (channel.getId() == chosenChannel.getId()) - { - return index; - } - index++; - } - throw new IllegalStateException("Channel not found: " + chosenChannel); - } - private ImgChannelDTO tryLoadChannel(String chosenChannelCode) { // first we check if there are some channels defined at the dataset level (even for HCS one diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/ChannelColor.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/ChannelColor.java index 0a10cf74204457afb80fbb0b4cc9d82472cf340e..83dbe5c09beed3f0a8b3affbdb022327ba7ac13f 100644 --- a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/ChannelColor.java +++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/ChannelColor.java @@ -9,6 +9,8 @@ public enum ChannelColor { BLUE(0), GREEN(1), RED(2), RED_GREEN(3), RED_BLUE(4), GREEN_BLUE(5); + private static final int MAX_COLOR = calcMaxColorIndex(); + // If no mapping between channels and colors has been provided then channels get consecutive // colors. This field determines the order in which colors are assigned. // It is important for backward compatibility as well. @@ -19,6 +21,16 @@ public enum ChannelColor this.orderIndex = orderIndex; } + private static int calcMaxColorIndex() + { + int max = 0; + for (ChannelColor color : values()) + { + max = Math.max(max, color.getColorOrderIndex()); + } + return max; + } + public int getColorOrderIndex() { return orderIndex; @@ -28,7 +40,7 @@ public enum ChannelColor { for (ChannelColor color : values()) { - if (color.getColorOrderIndex() == colorIndex) + if (color.getColorOrderIndex() == colorIndex % (MAX_COLOR + 1)) { return color; } 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 1ff5f95da8eb40b5b74ca83632315190fbb0775b..3e3cdcb00e166f621eee07b5a94bb4ce8189f13e 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 @@ -84,7 +84,7 @@ abstract public class SimpleImageDataConfig */ public Channel createChannel(String channelCode) { - ChannelColor channelColor = getChannelColor(channelCode); + ChannelColor channelColor = getChannelColor(channelCode.toUpperCase()); return new Channel(channelCode, channelCode, channelColor); } diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/generic/server/images/ImageChannelsUtils.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/generic/server/images/ImageChannelsUtils.java index e3576dc8aad670fd1847b6b8180ac92ab2627c87..885dcb76fd12b0371a4b43c50529b7720ee65678 100644 --- a/screening/source/java/ch/systemsx/cisd/openbis/dss/generic/server/images/ImageChannelsUtils.java +++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/generic/server/images/ImageChannelsUtils.java @@ -51,6 +51,7 @@ import ch.systemsx.cisd.openbis.dss.generic.server.images.dto.ImageGenerationDes import ch.systemsx.cisd.openbis.dss.generic.server.images.dto.RequestedImageSize; import ch.systemsx.cisd.openbis.dss.generic.shared.dto.Size; import ch.systemsx.cisd.openbis.dss.generic.shared.utils.ImageUtil; +import ch.systemsx.cisd.openbis.plugin.screening.shared.basic.dto.ImageChannelColor; import ch.systemsx.cisd.openbis.plugin.screening.shared.basic.dto.ScreeningConstants; import ch.systemsx.cisd.openbis.plugin.screening.shared.imaging.dataaccess.ColorComponent; @@ -712,8 +713,8 @@ public class ImageChannelsUtils colorBuffer[index] = colorComponent.getComponent(singleColor); } else { - int channelIndex = imageReference.getChannelIndex(); - setColorComponentsForChannelIndex(colorBuffer, singleColor, channelIndex); + ImageChannelColor channelColor = imageReference.getChannelColor(); + setColorComponentsForChannelIndex(colorBuffer, singleColor, channelColor); } } @@ -733,9 +734,9 @@ public class ImageChannelsUtils } private static void setColorComponentsForChannelIndex(int[] colorBuffer, Color singleColor, - int channelIndex) + ImageChannelColor channelColor) { - for (int i : getRGBColorIndexes(channelIndex)) + for (int i : getRGBColorIndexes(channelColor)) { colorBuffer[i] = Math.max(colorBuffer[i], extractMaxColorIngredient(singleColor)); } @@ -783,23 +784,27 @@ public class ImageChannelsUtils return newImage; } - // 0=B, 1=G, 2=R, 3=RG, 4=RB, 5=GB - private static int[] getRGBColorIndexes(int channelIndex) + // 0=R, 1=G, 2=B, 3=RG, 4=RB, 5=GB + private static int[] getRGBColorIndexes(ImageChannelColor channelColor) { - switch (channelIndex % 6) + switch (channelColor) { - case 0: - case 1: - case 2: + case RED: + return new int[] + { 0 }; + case GREEN: + return new int[] + { 1 }; + case BLUE: return new int[] - { 2 - (channelIndex % 6) }; - case 3: + { 2 }; + case RED_GREEN: return new int[] { 0, 1 }; - case 4: + case RED_BLUE: return new int[] { 0, 2 }; - case 5: + case GREEN_BLUE: return new int[] { 1, 2 }; default: diff --git a/screening/sourceTest/java/ch/systemsx/cisd/openbis/dss/etl/ImagingChannelsCreatorTest.java b/screening/sourceTest/java/ch/systemsx/cisd/openbis/dss/etl/ImagingChannelsCreatorTest.java new file mode 100644 index 0000000000000000000000000000000000000000..b021abdfac17745e4f56af95c0c154a97304201c --- /dev/null +++ b/screening/sourceTest/java/ch/systemsx/cisd/openbis/dss/etl/ImagingChannelsCreatorTest.java @@ -0,0 +1,68 @@ +/* + * 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; + +import java.util.Arrays; +import java.util.List; + +import org.testng.AssertJUnit; +import org.testng.annotations.Test; + +import ch.rinn.restrictions.Friend; +import ch.systemsx.cisd.openbis.dss.etl.ImagingDatabaseHelper.ImagingChannelsCreator; +import ch.systemsx.cisd.openbis.dss.etl.dto.api.v1.Channel; +import ch.systemsx.cisd.openbis.dss.etl.dto.api.v1.ChannelColor; + +/** + * Test of {@link ImagingChannelsCreator} + * + * @author Tomasz Pylak + */ +@Friend(toClasses = ImagingChannelsCreator.class) +public class ImagingChannelsCreatorTest extends AssertJUnit +{ + @Test + public void testFillMissingChannelColors() + { + List<Channel> channels = + Arrays.asList(mkChannel(), mkChannel(ChannelColor.RED), mkChannel()); + ImagingChannelsCreator.fillMissingChannelColors(channels); + + assertEqual(ChannelColor.BLUE, channels.get(0)); + assertEqual(ChannelColor.RED, channels.get(1)); + assertEqual(ChannelColor.GREEN, channels.get(2)); + + } + + private static void assertEqual(ChannelColor expectedColor, Channel channel) + { + if (expectedColor != channel.tryGetChannelColor()) + { + fail("Expected " + expectedColor + " but got: " + channel.tryGetChannelColor()); + } + } + + private static Channel mkChannel() + { + return mkChannel(null); + } + + private static Channel mkChannel(ChannelColor colorOrNull) + { + return new Channel("code", "label", colorOrNull); + } +} \ No newline at end of file diff --git a/screening/sourceTest/java/ch/systemsx/cisd/openbis/dss/generic/server/images/ImageChannelsUtilsTest.java b/screening/sourceTest/java/ch/systemsx/cisd/openbis/dss/generic/server/images/ImageChannelsUtilsTest.java index eb2a160d7cbf03b2cfae696c68449ef8f914a765..69614af24fa68e4fba014e08b42fad28dc61d397 100644 --- a/screening/sourceTest/java/ch/systemsx/cisd/openbis/dss/generic/server/images/ImageChannelsUtilsTest.java +++ b/screening/sourceTest/java/ch/systemsx/cisd/openbis/dss/generic/server/images/ImageChannelsUtilsTest.java @@ -48,6 +48,7 @@ import ch.systemsx.cisd.openbis.dss.generic.server.images.dto.RequestedImageSize import ch.systemsx.cisd.openbis.dss.generic.shared.dto.Size; import ch.systemsx.cisd.openbis.dss.generic.shared.utils.ImageUtilTest; import ch.systemsx.cisd.openbis.plugin.screening.shared.basic.dto.ImageChannel; +import ch.systemsx.cisd.openbis.plugin.screening.shared.basic.dto.ImageChannelColor; import ch.systemsx.cisd.openbis.plugin.screening.shared.basic.dto.ImageDatasetParameters; /** @@ -218,8 +219,8 @@ public class ImageChannelsUtilsTest extends AssertJUnit private static AbsoluteImageReference createAbsoluteImageReference(String fileName, RequestedImageSize imageSize) { - return new AbsoluteImageReference(image(fileName), "id42", null, null, imageSize, 0, - new ImageTransfomationFactories(), null); + return new AbsoluteImageReference(image(fileName), "id42", null, null, imageSize, + ImageChannelColor.BLUE, new ImageTransfomationFactories(), null); } private ImageChannelsUtils createImageChannelsUtils(Size thumbnailSizeOrNull) diff --git a/screening/sourceTest/java/ch/systemsx/cisd/openbis/dss/screening/server/DssServiceRpcScreeningTest.java b/screening/sourceTest/java/ch/systemsx/cisd/openbis/dss/screening/server/DssServiceRpcScreeningTest.java index cd6cb792052dee44963a18c47beeed4cf55b6fd4..a000c7a6bd13993c2a92d7eadcef6831fe731ab3 100644 --- a/screening/sourceTest/java/ch/systemsx/cisd/openbis/dss/screening/server/DssServiceRpcScreeningTest.java +++ b/screening/sourceTest/java/ch/systemsx/cisd/openbis/dss/screening/server/DssServiceRpcScreeningTest.java @@ -335,13 +335,15 @@ public class DssServiceRpcScreeningTest extends AssertJUnit ImageChannelStackReference.createHCSFromLocations(new Location(3, 1), new Location(1, 1)), thumbnailSize); will(returnValue(new AbsoluteImageReference(image("img1.jpg"), "img1", null, - null, thumbnailSize, 0, new ImageTransfomationFactories(), null))); + null, thumbnailSize, ImageChannelColor.BLUE, + new ImageTransfomationFactories(), null))); one(imageLoader).tryGetImage( channel, ImageChannelStackReference.createHCSFromLocations(new Location(3, 1), new Location(2, 1)), thumbnailSize); will(returnValue(new AbsoluteImageReference(image("img1.gif"), "img1", null, - null, thumbnailSize, 0, new ImageTransfomationFactories(), null))); + null, thumbnailSize, ImageChannelColor.BLUE, + new ImageTransfomationFactories(), null))); } });