/*
* Copyright 2005, 2009 Cosmin Basca.
* e-mail: cosmin.basca@gmail.com
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1
* of the License, or (at your option) any later version.
*
* Please see COPYING for the complete licence.
*/
package robo.vision;
import java.awt.Rectangle;
import java.awt.image.Raster;
import java.awt.image.RenderedImage;
import java.awt.image.WritableRaster;
import javax.media.jai.DataBufferDouble;
import javax.media.jai.ImageLayout;
import javax.media.jai.UntiledOpImage;
@SuppressWarnings("unchecked")
public class HSISegmentOpImage extends UntiledOpImage
{
private int aBins = 0, bBins = 0;
class ColorBin extends Object
{
double minH;
double maxH;
double minS;
double maxS;
int count;
int r;
int g;
int b;
}
/** Constructs HSISegmentOpImage. Image dimensions are copied from the
* source image. The tile grid layout, SampleModel, and ColorModel may
* optionally be specified by an ImageLayout object
* @param source a RenderedImage
* @param layout an ImageLayout optionally containing the tile grid layout,
* SampleModel, and ColorModel or null.
*/
public HSISegmentOpImage(RenderedImage source, ImageLayout layout, Integer aBins, Integer bBins)
{
super(source, null, layout);
this.aBins = aBins.intValue();
this.bBins = bBins.intValue();
}
/** HSI segments the image.
* @param src the source raster.
* @param dst the resultant connected component image.
* @param destRect the rectangle within the OpImage to be computed */
protected void computeImage(Raster[] srcarr, WritableRaster dst, Rectangle destRect)
{
Raster src = srcarr[0];
RoboRaster source = new RoboRaster(src);
WritableRoboRaster dest = new WritableRoboRaster(dst);
int width = source.getWidth(), height = source.getHeight();
/* Implement op here */
/* perform HSI transform */
DataBufferDouble hsi = new DataBufferDouble(width * height, 3);
@SuppressWarnings("unused")
float hsb[] = new float[3];
double minH = Double.MAX_VALUE, maxH = Double.MIN_VALUE;
double minS = Double.MAX_VALUE, maxS = Double.MIN_VALUE;
for (int v = 0; v < height; v++)
{
for (int u = 0; u < width; u++)
{
int p = v * width + u;
@SuppressWarnings("unused")
double H, S, I;
double r = source.red(u, v);
double g = source.green(u, v);
double b = source.blue(u, v);
double minRGB = (r < g) ? r : g;
minRGB = (minRGB < b) ? minRGB : b;
// Color.RGBtoHSB(r, g, b, hsb);
// hsi.setElemDouble(0, p, H = hsb[0]);
// hsi.setElemDouble(1, p, S = hsb[1]);
// hsi.setElemDouble(2, p, I = hsb[2]);
hsi.setElemDouble(0, p, H = Math.acos(.5 * ((r - g) + (r - b)) / Math.sqrt((r - g) * (r - g) + (r - b) * (g - b))));
hsi.setElemDouble(1, p, S = 1. - 3 / (r + g + b) * minRGB);
hsi.setElemDouble(2, p, I = (r + g + b) / 3.);
if (minH > H)
minH = H;
if (maxH < H)
maxH = H;
if (minS > S)
minS = S;
if (maxS < S)
maxS = S;
}
}
System.out.println(minH + "-"+maxH + " "+minS + "-"+maxS);
double aInc = (maxH - minH) / aBins;
double bInc = (maxS - minS) / bBins;
ColorBin bin[] = new ColorBin[aBins * bBins];
for (int x = 0; x < aBins; x++)
{
for (int y = 0; y < bBins; y++)
{
int p = x * bBins + y;
bin[p] = new ColorBin();
bin[p].minH = minH + x * aInc;
bin[p].maxH = minH + (x + 1) * aInc;
bin[p].minS = minS + y * bInc;
bin[p].maxS = minS + (y + 1) * bInc;
bin[p].count = 0;
bin[p].r = 0;
bin[p].g = 0;
bin[p].b = 0;
}
}
int seg[] = new int[width * height];
for (int v = 0; v < height; v++)
{
for (int u = 0; u < width; u++)
{
int p = v * width + u;
for (int x = 0; x < aBins * bBins; x++)
{
if (hsi.getElemDouble(0, p) >= bin[x].minH && hsi.getElemDouble(0, p) <= bin[x].maxH && hsi.getElemDouble(1, p) >= bin[x].minS && hsi.getElemDouble(1, p) <= bin[x].maxS)
{
seg[p] = x;
bin[x].r += source.red(u, v);
bin[x].g += source.green(u, v);
bin[x].b += source.blue(u, v);
bin[x].count++;
break;
}
}
}
}
for (int x = 0; x < aBins * bBins; x++)
{
if (bin[x].count != 0)
{
bin[x].r /= bin[x].count;
bin[x].g /= bin[x].count;
bin[x].b /= bin[x].count;
}
}
for (int v = 0; v < height; v++)
{
for (int u = 0; u < width; u++)
{
int p = v * width + u;
dest.setRed(u, v, bin[seg[p]].r);
dest.setGreen(u, v, bin[seg[p]].g);
dest.setBlue(u, v, bin[seg[p]].b);
}
}
}
}