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

BIS-338 / SP-522: Apply rescaling transformation also for color images that...

BIS-338 / SP-522: Apply rescaling transformation also for color images that are using only one color component (R, G or B)

SVN: 28412
parent 97f37eab
No related branches found
No related tags found
No related merge requests found
......@@ -18,6 +18,7 @@ package ch.systemsx.cisd.common.image;
import java.awt.image.BufferedImage;
import java.awt.image.WritableRaster;
import java.util.EnumSet;
/**
* Methods for performing an intensity rescaling to 8bits for gray-scale images with a color-depth
......@@ -31,6 +32,31 @@ public class IntensityRescaling
/** The largest number a unsigned short can store. */
private final static int MAX_USHORT = (1 << 16) - 1;
public static enum Channel
{
RED(0, 16), GREEN(1, 8), BLUE(2, 0);
private int band;
private int shift;
private Channel(int band, int shift)
{
this.band = band;
this.shift = shift;
}
public int getShift()
{
return shift;
}
public int getBand()
{
return band;
}
}
/**
* The levels in a distribution of pixel values for a given symmetric quantile value.
*/
......@@ -156,6 +182,39 @@ public class IntensityRescaling
return image.getColorModel().getColorSpace().getNumComponents() > 1;
}
/** @return Used rgb channels in an image. Returns empty set if image type not RGB */
public static EnumSet<Channel> getUsedRgbChannels(BufferedImage image)
{
EnumSet<Channel> channels = EnumSet.noneOf(Channel.class);
if (image.getType() != BufferedImage.TYPE_INT_RGB
&& image.getType() != BufferedImage.TYPE_INT_ARGB)
{
return channels;
}
for (int i = 0; i < image.getHeight(); i++)
{
for (int j = 0; j < image.getWidth(); j++)
{
int rgb = image.getRGB(i, j);
if (((rgb >> 16) & 0xff) > 0)
{
channels.add(Channel.RED);
}
if (((rgb >> 8) & 0xff) > 0)
{
channels.add(Channel.GREEN);
}
if ((rgb & 0xff) > 0)
{
channels.add(Channel.BLUE);
}
}
}
return channels;
}
/**
* Performs an intensity rescaling on a gray-scale image by shifting all intensities so that
* only significant bits are kept. A bit position is considered significant if only a small
......@@ -369,6 +428,37 @@ public class IntensityRescaling
return rescaleIntensityLevelTo8Bits(new GrayscalePixels(image), levels);
}
public static BufferedImage rescaleIntensityLevelTo8Bits(BufferedImage image, Levels levels,
Channel channel)
{
final int width = image.getWidth();
final int height = image.getHeight();
final BufferedImage rescaledImage =
new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
WritableRaster rescaledRaster = rescaledImage.getRaster();
final float dynamicRange = 255f / (levels.maxLevel - levels.minLevel);
for (int y = 0; y < height; ++y)
{
for (int x = 0; x < width; ++x)
{
int originalIntensity = (image.getRGB(x, y) >> channel.getShift()) & 0xff;
// cut all intensities above the white point
int intensity = Math.min(levels.maxLevel, originalIntensity);
// cut all intensities below the black point and move the origin to 0
intensity = Math.max(0, intensity - levels.minLevel);
// normalize to [0, 1] and rescale to 8 bits
intensity = (int) (0.5 + (intensity * dynamicRange));
rescaledRaster
.setSample(x, y, channel.getBand(), intensity);
}
}
return rescaledImage;
}
/**
* See {@link #rescaleIntensityLevelTo8Bits}.
*/
......
......@@ -17,13 +17,13 @@
package ch.systemsx.cisd.openbis.dss.etl.dto.api.transformations;
import java.awt.image.BufferedImage;
import java.util.EnumSet;
import ch.systemsx.cisd.base.annotation.JsonObject;
import ch.systemsx.cisd.base.image.IImageTransformer;
import ch.systemsx.cisd.base.image.IImageTransformerFactory;
import ch.systemsx.cisd.base.annotation.JsonObject;
import ch.systemsx.cisd.common.image.IntensityRescaling;
import ch.systemsx.cisd.common.image.IntensityRescaling.Channel;
import ch.systemsx.cisd.common.image.IntensityRescaling.Levels;
/**
......@@ -71,7 +71,16 @@ public class IntensityRangeImageTransformerFactory implements IImageTransformerF
{
if (IntensityRescaling.isNotGrayscale(image))
{
return image;
EnumSet<Channel> channels = IntensityRescaling.getUsedRgbChannels(image);
if (channels.size() != 1)
{
return image;
} else
{
Levels levels = new Levels(blackPointIntensity, whitePointIntensity);
return IntensityRescaling.rescaleIntensityLevelTo8Bits(image, levels,
channels.iterator().next());
}
}
Levels levels = new Levels(blackPointIntensity, whitePointIntensity);
return IntensityRescaling.rescaleIntensityLevelTo8Bits(image, levels);
......
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