/*
* Data HUb Service (DHuS) - For Space data distribution.
* Copyright (C) 2013,2014,2015,2016 European Space Agency (ESA)
* Copyright (C) 2013,2014,2015,2016 GAEL Systems
* Copyright (C) 2013,2014,2015,2016 Serco Spa
*
* This file is part of DHuS software sources.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package fr.gael.drb.cortex.topic.sentinel3.jai.operator;
import org.apache.log4j.Logger;
import java.awt.Color;
import java.awt.RenderingHints;
import java.awt.image.BufferedImage;
import java.awt.image.Raster;
import java.awt.image.RenderedImage;
import java.awt.image.renderable.ParameterBlock;
import java.awt.image.renderable.RenderedImageFactory;
import java.io.ObjectInputStream;
import java.util.ArrayList;
import java.util.List;
/**
* JAI Operator dedicated to compute Sentinel-3 histogram equalization.
*/
public class S3HistogramEqualizerRIF implements RenderedImageFactory
{
private static Logger LOGGER=Logger.getLogger(S3HistogramEqualizerRIF.class);
/**
* Compute the output equalized image. In contrary to the QL generation the
* stretching can only performed on full dataset. So no operator can be
* provided to manage this operation by tile...
*
* @param paramBlock contains the RGB source image to produce the quicklook.
* @param hints Optionally contains destination image layout.
* @return the equalized image.
* @throws IllegalArgumentException if source does not contains 3 bands.
*/
@SuppressWarnings ("unchecked")
public RenderedImage create(ParameterBlock paramBlock, RenderingHints hints)
{
// One source supported
RenderedImage image = (RenderedImage)paramBlock.getSource(0);
int num_bands=image.getSampleModel().getNumBands();
Raster raster_data = image.getData();
if (num_bands != 3) // Support only RGB bands :-(
{
throw new IllegalArgumentException (
"S3 Equalization only support 3-banded RGB input image.");
}
int width = image.getWidth();
int height = image.getHeight();
List<int[]> histLUT;
try
{
String equalizationFile = image instanceof QuicklookOlciOpImage ?
"olci-equalization.dat" : null;
// could be loaded statically or inside constructor
ObjectInputStream objectinputstream = new ObjectInputStream(
getClass().getClassLoader().getResourceAsStream(equalizationFile));
histLUT = (ArrayList<int[]>) objectinputstream.readObject();
}
catch (Exception e)
{
LOGGER.warn("Unable to load LUT for equalization. " +
"Using a dynamic LUT " + e.getMessage());
histLUT = histogramEqualizationLUT(raster_data);
}
BufferedImage histogramEQ = new BufferedImage(width, height,
BufferedImage.TYPE_3BYTE_BGR);
int red;
int green;
int blue;
int new_pixel;
for(int j=0; j<height; j++)
{
for(int i=0; i<width; i++)
{
// Get pixels by R, G, B
red = getRed(raster_data, i, j);
green = getGreen(raster_data, i, j);
blue = getBlue(raster_data, i, j);
// Set new pixel values using the histogram lookup table
if(red == 0 && green == 0 && blue == 0) continue;
red = histLUT.get(0)[red];
green = histLUT.get(1)[green];
blue = histLUT.get(2)[blue];
// Return back to original format
new_pixel = new Color(
red*255/Common.colorRange,
green*255/Common.colorRange,
blue*255/Common.colorRange).getRGB();
// Write pixels into image
histogramEQ.setRGB(i, j, new_pixel);
}
}
return histogramEQ;
}
private ArrayList<int[]>imageHistogram(Raster image)
{
int[] rhistogram = new int[Common.colorRange +1];
int[] ghistogram = new int[Common.colorRange +1];
int[] bhistogram = new int[Common.colorRange +1];
for(int i=0; i<rhistogram.length; i++) rhistogram[i] = 0;
for(int i=0; i<ghistogram.length; i++) ghistogram[i] = 0;
for(int i=0; i<bhistogram.length; i++) bhistogram[i] = 0;
boolean flag = false;
for(int j=0; j<image.getHeight(); j++)
{
for(int i=0; i<image.getWidth(); i++)
{
int red = getRed (image, i, j);
int green = getGreen (image, i, j);
int blue = getBlue (image, i, j);
// Increase the values of colors
if(red == 0 && green == 0 && blue == 0)
{
if(!flag)
{
flag = true;
continue;
}
else
{
flag = false;
}
}
rhistogram[red]++; ghistogram[green]++; bhistogram[blue]++;
}
}
ArrayList<int[]> hist = new ArrayList<>();
hist.add(rhistogram);
hist.add(ghistogram);
hist.add(bhistogram);
return hist;
}
private ArrayList<int[]> histogramEqualizationLUT(Raster image)
{
// Get an image histogram - calculated values by R, G, B channels
ArrayList<int[]> imageHist = imageHistogram(image);
// Create the lookup table
ArrayList<int[]> imageLUT = new ArrayList<>();
// Fill the lookup table
int[] rhistogram = new int[Common.colorRange + 1];
int[] ghistogram = new int[Common.colorRange + 1];
int[] bhistogram = new int[Common.colorRange + 1];
for (int i = 0; i < rhistogram.length; i++)
rhistogram[i] = 0;
for (int i = 0; i < ghistogram.length; i++)
ghistogram[i] = 0;
for (int i = 0; i < bhistogram.length; i++)
bhistogram[i] = 0;
long sumr = 0;
long sumg = 0;
long sumb = 0;
// Calculate the scale factor
float scale_factor = (float) (Common.colorRange * 1. /
(image.getHeight() * image.getWidth()));
for (int i = 0; i < rhistogram.length; i++)
{
sumr += imageHist.get(0)[i];
int valr = (int) (sumr * scale_factor);
rhistogram[i] = valr;
sumg += imageHist.get(1)[i];
int valg = (int) (sumg * scale_factor);
ghistogram[i] = valg;
sumb += imageHist.get(2)[i];
int valb = (int) (sumb * scale_factor);
bhistogram[i] = valb;
}
imageLUT.add(rhistogram);
imageLUT.add(ghistogram);
imageLUT.add(bhistogram);
return imageLUT;
}
int getRed (Raster raster, int x,int y)
{
return raster.getSample(x, y, 0);
}
int getGreen (Raster raster, int x,int y)
{
return raster.getSample(x, y, 1);
}
int getBlue (Raster raster, int x,int y)
{
return raster.getSample(x, y, 2);
}
}