package eu.europeana.service.ir.image.features;
/*
* This file is part of the Caliph and Emir project: http://www.SemanticMetadata.net.
*
* Caliph & Emir is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* Caliph & Emir 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Caliph & Emir; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
import java.awt.image.BufferedImage;
import java.awt.image.WritableRaster;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import javax.imageio.ImageIO;
/*
* DominantColorLogic.java
*
* Created on 25. June 2004, 07:15 and updated until 04. November 2004
* Author: Wolfgang Seiringer, 002521, w.seiringer@utanet.at for the vizir-project (visual information retrieval project)
* (http://vizir.ims.tuwien.ac.at) project of the IMS (Interactive Media Systems Group) www.ims.tuwien.ac.at, at the TU Wien
* www.tuwien.ac.at
*/
public class DominantColorLogic {
private int imageHeight;
private int imageWidth;
private int imsize;
// --------------------------------------------------------//
// Holding the actual image to process:
private BufferedImage bufferedImage = null;
private int SC_BIT = 5;
// private final char quantImageAlpha = 255;
private static final int FLT_MAX = 1000000;
private float DSTMIN = (float) 255.0;
private float SPLFCT = (float) 0.10;
private int DCNMAX = 8;
private double EPSGLOB = 0.01; // Global stopping criteria, see extract
// method
private double EPSSPLT = 0.02; // Criteria for splitting the colorbins
private double VARTHR = 50.0;
private int m_Coherency; // saves the spatical coherency
// private double dist, distold = FLT_MAX, distnew, eps = 1.0;
private int j;
int m_MaxSize = DCNMAX;
int m_CurrSize = 1;
private float[] m_Weights = new float[m_MaxSize]; // Saves the Percentages
// of the Dominant
// Colors
private float[][] m_Centroids = new float[m_MaxSize][3]; // Saves the values
// of the
// Domiant
// Colors
// private int[] closest = new int[imsize]; //Is used for Clustering, see
// Method Cluster
private int[] closest; // Is used for Clustering, see Method Cluster
private int component0, component1, component2;
private int bin_number0, bin_number1, bin_number2;
// Variables for Saving the Values extracted from the XML-String
public int DominantSize = 0; // Saves the "Size" extracted from the
// XML-String
public int spatcoher = 0; // Saves the "SpatialCoherency" extracted from the
// XML-String
public int[] Percentage = null; // Saves the "Percentage" extracted from the
// XML-String
public int[][] ColorValueIndex = null; // Saves the "ColorValueIndex"
// extracted from the XML-String
// -----------------
// ----- Variables used for the dominant color parameters
private int VariancePresent = 0;
private int SpatialCoherency = 0;
private int ColorSpacePresentInt = 0;
private String ColorSpacePresentStr = "0";
private int ColorQuantizationPresent = 0;
private int[][] icnts_f;
private int[] iwgts_f;
private float[][] m_Variances = new float[m_MaxSize][3];
private int[] interleavedArray;
// ---------------------------------------------------//
public DominantColorLogic() {
}
public DominantColorValues extractDescriptor(File imageFile) throws IOException{
InputStream in = new FileInputStream(imageFile);
BufferedImage image = ImageIO.read(in);
DominantColorValues values = extractDescriptor(image);
values.centroids = m_Centroids;
values.weights = m_Weights;
return values;
}
public DominantColorValues extractDescriptor(BufferedImage image) {
this.imageHeight = image.getHeight();
this.imageWidth = image.getWidth();
this.imsize = this.imageHeight * this.imageWidth;
this.closest = new int[imsize];
this.bufferedImage = image;
this.extractFeature();
DominantColorValues dc = new DominantColorValues();
dc.size = m_CurrSize;
dc.coherency = m_Coherency;
dc.percentages = new int[dc.size];
dc.colorValues = new int[dc.size][3];
for (int i = 0; i < dc.size; i++) {
dc.percentages[i] = iwgts_f[i];
dc.colorValues[i][0] = icnts_f[i][0];
dc.colorValues[i][1] = icnts_f[i][1];
dc.colorValues[i][2] = icnts_f[i][2];
}
return dc;
}
/**
* Use this extraction routine if the pixel data was taken from a non
* rectangular region. Please note that the neighbourhood of pixels cannot
* be taken into account (No reliable spatial coherency can be created). The
* pixels array goes like: {pixel1[0], pixel1[1], pixel1[2], pixel2[0],
* pixel2[1], ...}
*
* @param pixels
* gives the pixels one int after another
* @return the extracted data.
*/
public DominantColorValues extractDescriptor(int[] pixels) {
this.imageHeight = pixels.length / 3;
this.imageWidth = 1;
this.imsize = pixels.length / 3;
this.closest = new int[imsize];
this.bufferedImage = null;
this.interleavedArray = pixels;
this.extractFeature();
DominantColorValues dc = new DominantColorValues();
dc.size = m_CurrSize;
dc.coherency = m_Coherency;
dc.percentages = new int[dc.size];
dc.colorValues = new int[dc.size][3];
for (int i = 0; i < dc.size; i++) {
dc.percentages[i] = iwgts_f[i];
dc.colorValues[i][0] = icnts_f[i][0];
dc.colorValues[i][1] = icnts_f[i][1];
dc.colorValues[i][2] = icnts_f[i][2];
}
return dc;
}
/**
* Makes some initial Operations and calls the Main Extracting-Method
* <p/>
* First some Variables are set for the further work. Then the input
* RBG-Values are converted into the necessary CIE-LUV values, the method
* rgb2luv is used for conversion. After the need CIE-LUV values are
* availabe we can call the method EXTRACT, this method is responsible for
* clustering, splitting calculating centroids,... and also puts the
* calculated Bins with color, perentage in an array for outputting.
*/
public void extractFeature() {
int[] RGB;
float[] LUV;
if (bufferedImage != null) {
RGB = interleave(imsize, this.imageWidth, this.imageHeight);
} else {
RGB = interleavedArray;
}
LUV = new float[3 * imsize];
rgb2luv(RGB, LUV, 3 * imsize); // Calculate the needed LUV-Values for
// the further operations
char quantImageAlpha = 255;
Extract(LUV, imsize, quantImageAlpha);// Calls the Main Extracting
// Method
}// End Method extractFeature
// ------------------------------- RGB to LUV konversation
// -----------------------------------
/**
* This method takes the Input-RGB Values and calculates the corresponding
* CIELUV Values.
* <p/>
* The LUV-Values are used during the DominantColors, after extracting the
* Dominant Colors, the CIELUV Values are converted from CIELUV to RGB
*/
private static void rgb2luv(int[] RGB, float[] LUV, int size) {
int i;
double x, y, X, Y, Z, den, u2, v2, X0, Z0, Y0, u20, v20, r, g, b;
X0 = (0.607 + 0.174 + 0.201);
Y0 = (0.299 + 0.587 + 0.114);
Z0 = (0.066 + 1.117);
u20 = 4d * X0 / (X0 + 15d * Y0 + 3d * Z0);
v20 = 9d * Y0 / (X0 + 15d * Y0 + 3d * Z0);
for (i = 0; i < size; i += 3) {
if (RGB[i] <= 20)
r = (double) (8.715e-4 * RGB[i]);
else
r = (double) Math.pow((RGB[i] + 25.245) / 280.245, 2.22);
if (RGB[i + 1] <= 20)
g = (double) (8.715e-4 * RGB[i + 1]);
else
g = (double) Math.pow((RGB[i + 1] + 25.245) / 280.245, 2.22);
if (RGB[i + 2] <= 20)
b = (double) (8.715e-4 * RGB[i + 2]);
else
b = (double) Math.pow((RGB[i + 2] + 25.245) / 280.245, 2.22);
X = 0.412453 * r + 0.357580 * g + 0.180423 * b;
Y = 0.212671 * r + 0.715160 * g + 0.072169 * b;
Z = 0.019334 * r + 0.119193 * g + 0.950227 * b;
if (X == 0.0 && Y == 0.0 && Z == 0.0) {
x = 1.0 / 3.0;
y = 1.0 / 3.0;
} else {
den = X + Y + Z;
x = X / den;
y = Y / den;
}
den = -2 * x + 12 * y + 3;
u2 = 4 * x / den;
v2 = 9 * y / den;
if (Y > 0.008856)
LUV[i] = (float) (116 * Math.pow(Y, 1.0 / 3.0) - 16);
else
LUV[i] = (float) (903.3 * Y);
LUV[i + 1] = (float) (13 * LUV[i] * (u2 - u20));
LUV[i + 2] = (float) (13 * LUV[i] * (v2 - v20));
}
}// End Method RGBtoLUV
// --------------------- LUV to RGB conversion------------------
/**
* Converts the LUV-Values in the corresponding RGB Values (Range 256)
*/
private static void luv2rgb(int[] RGB, float[] LUV, int size) {
int i, k;
double x, y, X, Y, Z, den, u2, v2, X0, Z0, Y0, u20, v20;
double[] vec = new double[3];
X0 = (0.607 + 0.174 + 0.201);
Y0 = (0.299 + 0.587 + 0.114);
Z0 = (0.066 + 1.117);
u20 = 4 * X0 / (X0 + 15 * Y0 + 3 * Z0);
v20 = 9 * Y0 / (X0 + 15 * Y0 + 3 * Z0);
for (i = 0; i < size; i += 3) {
if (LUV[i] > 0) {
if (LUV[i] < 8.0)
Y = ((double) LUV[i]) / 903.3;
else
Y = Math.pow((((double) LUV[i]) + 16) / 116.0, 3.0);
u2 = ((double) LUV[i + 1]) / 13.0 / ((double) LUV[i]) + u20;
v2 = ((double) LUV[i + 2]) / 13.0 / ((double) LUV[i]) + v20;
den = 6 + 3 * u2 - 8 * v2;
x = 4.5 * u2 / den;
y = 2.0 * v2 / den;
X = x / y * Y;
Z = (1 - x - y) / y * Y;
} else {
X = 0.0;
Y = 0.0;
Z = 0.0;
}
vec[0] = (3.240479 * X - 1.537150 * Y - 0.498536 * Z);
vec[1] = (-0.969256 * X + 1.875992 * Y + 0.041556 * Z);
vec[2] = (0.055648 * X - 0.204043 * Y + 1.057311 * Z);
for (k = 0; k < 3; k++) {
if (vec[k] <= 0.018)
vec[k] = 255 * 4.5 * vec[k];
else
vec[k] = 255 * (1.099 * Math.pow(vec[k], 0.45) - 0.099);
if (vec[k] > 255)
vec[k] = 255;
else if (vec[k] < 0)
vec[k] = 0;
RGB[i + k] = Math.round((float) vec[k]);
}
}
}
/**
* This method controlls the extracting.
* <p/>
* The Method is responsible for the correct number of iterations and calls
* the submethod which calculate the required values. It loops trough the
* mthods cluster, calculate centroids and calculates the distortion. imdata
* -> color value of input image ( LUV color space, linear array) imsize ->
* total image size ( width * height) m_MaxSize -> Maximun DominantColor
* Number (initial value DCNMAX = 8) m_CurrSize -> Current(final)
* DominantColor Number (int) m_Weights -> Percentage of DominantColor
* (float) m_Centroids -> ColorValue of DominantColor (LUV color space,
* float) m_Variances -> ColorVariance of DominantColor (float) iwgts ->
* Percentage of DominantColor (int) icnts -> ColorValue of DominantColor
* (RGB color space, int) m_Coherency -> Spatial Coherency of DominantColor
*/
private void Extract(float[] imdata, int imsize, char quantImageAlpha) {
double dist, distold = FLT_MAX, distnew, eps = 1.0, tmp;
float aglfct = DSTMIN;
float splfct = SPLFCT;
int i, k;
m_MaxSize = DCNMAX;
m_CurrSize = 1;
for (i = 0; i < m_MaxSize; i++) {
m_Weights[i] = (float) 0.0;
m_Centroids[i][0] = (float) 0.0;
m_Centroids[i][1] = (float) 0.0;
m_Centroids[i][2] = (float) 0.0;
m_Variances[i][0] = (float) 0.0;
m_Variances[i][1] = (float) 0.0;
m_Variances[i][2] = (float) 0.0;
}
i = 0;
distnew = Cluster(closest, imdata, imsize, quantImageAlpha);
while (eps > EPSGLOB) {
// find centroids
Centroids(closest, imdata, imsize, quantImageAlpha);
// classify bins
distnew = Cluster(closest, imdata, imsize, quantImageAlpha);
// calculate total distortion
if (distold > 0.0)
eps = (distold - distnew) / distold;
else
eps = 0.0;
distold = distnew;
// decide on splitting
if (i == 0 || ((eps < EPSSPLT) && (m_CurrSize < m_MaxSize))) {
Split(closest, imdata, imsize, splfct, quantImageAlpha);
distnew = Cluster(closest, imdata, imsize, quantImageAlpha);
eps = 1.0;
}
// check for identical codevectors
for (j = 0; j < m_CurrSize; j++) {
for (k = 0; k < j; k++) {
dist = 0.0;
tmp = m_Centroids[j][0] - m_Centroids[k][0];
dist += tmp * tmp;
tmp = m_Centroids[j][1] - m_Centroids[k][1];
dist += tmp * tmp;
tmp = m_Centroids[j][2] - m_Centroids[k][2];
dist += tmp * tmp;
if (dist == 0.0)
System.out
.println("WARNING: two identical codevectors "
+ j + ", " + k);
}
}
i++;
}
// System.out.println("Extract: iterations finished " + i);
// merging using agglomerative clustering
Agglom(aglfct);
// calculate variances and normalise
distnew = Cluster(closest, imdata, imsize, quantImageAlpha);
Centroids(closest, imdata, imsize, quantImageAlpha);
distnew = Cluster(closest, imdata, imsize, quantImageAlpha);
if (this.VariancePresent != 0) {
Vars(closest, imdata, imsize, quantImageAlpha);
}
for (j = 0; j < m_CurrSize; j++)
m_Weights[j] /= imsize;
// quantise and set descriptor members
int[] iwgts = new int[m_CurrSize];
int[][] icnts = new int[3 * m_CurrSize][3 * m_CurrSize];
for (i = 0; i < m_CurrSize; i++)
icnts[i] = new int[3];
int[][] ivars = new int[3 * m_CurrSize][3 * m_CurrSize];
for (i = 0; i < m_CurrSize; i++)
ivars[i] = new int[3];
for (i = 0; i < m_CurrSize; i++) {
iwgts[i] = (int) (31.9999 * m_Weights[i]);
luv2rgb(icnts[i], m_Centroids[i], 3);
}
for (i = 0; i < m_CurrSize; i++) {
for (int j = 0; j < 3; j++)
ivars[i][j] = (m_Variances[i][j] > VARTHR) ? 1 : 0;
}
// calculate spatial coherency
if (this.SpatialCoherency != 0) {
m_Coherency = GetSpatialCoherency(imdata, 3, m_CurrSize,
m_Centroids, quantImageAlpha);
} else
m_Coherency = 0;
String colspcpres = this.ColorSpacePresentStr;
// int colspcpresInt = this.ColorSpacePresentInt;
int colquantpres = this.ColorQuantizationPresent;
int max_h;
// float conversionmatrix;
component0 = 0;
component1 = 1;
component2 = 2; // default RGB
bin_number0 = 32;
bin_number1 = 32;
bin_number2 = 32; // default 5 bit
max_h = 256;
if (colspcpres != "0") {
int[] in = new int[25];
// int[] res = in;
for (i = 0; i < m_CurrSize; i++) {
in[12] = icnts[i][1];
in[12] = icnts[i][2];
in[12] = icnts[i][0];
}
}
if (colquantpres != 0) {
bin_number0 = this.GetBinNumberByComponent(component0);
bin_number1 = this.GetBinNumberByComponent(component1);
bin_number2 = this.GetBinNumberByComponent(component2);
}
for (i = 0; i < m_CurrSize; i++) {
icnts[i][0] = icnts[i][0] * bin_number0 / max_h;
icnts[i][1] = icnts[i][1] * bin_number1 >> 8;
icnts[i][2] = icnts[i][2] * bin_number2 >> 8;
}
// Save values for output
// String ColorSpacePresent = colspcpres;
// int ColorQuantizationPresen = colquantpres;
// *****************************************************************
// This output is used for testing the outputvalues, can be removed
// System.out.println("size: " + m_CurrSize);
//
// System.out.println("SpatialCoherency: " + m_Coherency);
for (int we = 0; we < m_CurrSize; we++) {
// System.out.println("Percentage: " + iwgts[we]);
// System.out.println("Values: " + icnts[we][0] + " " + icnts[we][1]
// + " " + icnts[we][2]);
// System.out.println("------------------------------------------------");
}
// ********************************************************************
icnts_f = icnts;
iwgts_f = iwgts;
} // end method extract
// ---------------------------------------------------------------------------
/**
* Each color is asign a cluster
*/
private double Cluster(int[] closest, float[] imdata, int imsize,
char quantImageAlpha) {
int i, j, jmin;
double d1, d2, d3, dist, distmin, disttot = 0.0;
float[] im1 = imdata;
// float[] im2 = imdata, im3 = imdata;
int imsize_msk;
// char pAlpha;
// now we cluster
imsize_msk = 0;
for (i = 0; i < imsize; i++) {
jmin = 0;
distmin = FLT_MAX;
for (j = 0; j < m_CurrSize; j++) {
d1 = im1[3 * i] - m_Centroids[j][0];
d2 = im1[3 * i + 1] - m_Centroids[j][1];
d3 = im1[3 * i + 2] - m_Centroids[j][2];
dist = d1 * d1 + d2 * d2 + d3 * d3;
if (dist < distmin) {
jmin = j;
distmin = dist;
}
}
closest[i] = jmin;
if (closest[i] != 0)
disttot += distmin;
imsize_msk++;
}
return disttot / imsize_msk;
} // end method cluster
// ----------------------------------Ende
// Cluster-----------------------------------------
/**
* Calculates the centroid of the colorcluster
*/
// ----------------------------------Begin
// Centroid-----------------------------------------
private void Centroids(int[] closest, float[] imdata, int imsize,
char quantImageAlpha) {
int i, j;
double weight;
float[] im1 = imdata;
// float[] im2 = imdata, im3 = imdata;
// char pAlpha;
// set the centroids values to 0
for (j = 0; j < m_CurrSize; j++) {
m_Weights[j] = (float) 0.0;
m_Centroids[j][0] = (float) 0.0;
m_Centroids[j][1] = (float) 0.0;
m_Centroids[j][2] = (float) 0.0;
}
for (i = 0; i < imsize; i++) {
int ii = closest[i];
m_Weights[ii]++;
m_Centroids[ii][0] += im1[3 * i];
m_Centroids[ii][1] += im1[3 * i + 1];
m_Centroids[ii][2] += im1[3 * i + 2];
}
for (j = 0; j < m_CurrSize; j++) {
weight = m_Weights[j];
if (weight != 0.0) {
m_Centroids[j][0] /= weight;
m_Centroids[j][1] /= weight;
m_Centroids[j][2] /= weight;
} else {
System.out.println("WARNING: zero weight for colour " + j);
}
}
} // end method centroids
// ------------------------- END CENTROIDS
// --------------------------------------------------
// ---------------------------------------------------------------------------
/**
* Calculates the Total Distortion, the distorion is further on needed for
* deciding if we should split the colorbins or not.
*/
/*
* private double Dist(int[] closest, float[] imdata, int imsize, char
* quantImageAlpha) { int i, j; double d1, d2, d3, dist = 0.0; float[] im1 =
* imdata; int imsize_msk; // char pAlpha; imsize_msk = 0; for (i = 0; i <
* imsize; i++) { j = closest[i]; d1 = im1[3 * i] - m_Centroids[j][0]; d2 =
* im1[3 * i + 1] - m_Centroids[j][1]; d3 = im1[3 * i + 2] -
* m_Centroids[j][2]; dist += (d1 * d1) + (d2 * d2) + (d3 * d3);
* imsize_msk++; } return dist / imsize_msk; } //end method dist
*/
// ---------------------------------------------------------------------------
private void Vars(int[] closest, float[] imdata, int imsize,
char quantImageAlpha) {
int i, j;
double tmp;
// char pAlpha;
// set the m_Variances Values to 0
for (i = 0; i < m_CurrSize; i++) {
m_Variances[i][0] = (float) 0.0;
m_Variances[i][1] = (float) 0.0;
m_Variances[i][2] = (float) 0.0;
}
for (i = 0; i < imsize; i++) {
j = closest[i];
tmp = imdata[3 * i] - m_Centroids[j][0];
m_Variances[j][0] += tmp * tmp;
tmp = imdata[3 * i + 1] - m_Centroids[j][1];
m_Variances[j][1] += tmp * tmp;
tmp = imdata[3 * i + 2] - m_Centroids[j][2];
m_Variances[j][2] += tmp * tmp;
}
// Normalise values
for (j = 0; j < m_CurrSize; j++) {
m_Variances[j][0] /= m_Weights[j];
m_Variances[j][1] /= m_Weights[j];
m_Variances[j][2] /= m_Weights[j];
}
} // end method vars
// ---------------------------------------------------------------------------
/**
* Splits the ColorBins, this means that one colorbin is split in to two new
* colorbins and the old colorbin is discarded
*/
private void Split(int[] closest, float[] imdata, int imsize,
double factor, char quantImageAlpha) {
int i, j, jmax = 0;
double d1, d2, d3, diff1, diff2, diff3;
double[] d1s = new double[8];
double[] d2s = new double[8];
double[] d3s = new double[8];
double[] dists = new double[8];
double distmax = 0.0;
// char pAlpha;
// set distortion values to 0
for (j = 0; j < m_CurrSize; j++) {
d1s[j] = 0.0;
d2s[j] = 0.0;
d3s[j] = 0.0;
dists[j] = 0.0;
}
for (i = 0; i < imsize; i++) {
j = closest[i];
d1 = imdata[3 * i] - m_Centroids[j][0];
d2 = imdata[3 * i + 1] - m_Centroids[j][1];
d3 = imdata[3 * i + 2] - m_Centroids[j][2];
d1s[j] += d1 * d1;
d2s[j] += d2 * d2;
d3s[j] += d3 * d3;
}
for (j = 0; j < m_CurrSize; j++) {
dists[j] = d1s[j] + d2s[j] + d3s[j];
d1s[j] /= m_Weights[j];
d2s[j] /= m_Weights[j];
d3s[j] /= m_Weights[j];
}
for (j = 0; j < m_CurrSize; j++)
if (dists[j] > distmax) {
jmax = j;
distmax = dists[j];
}
diff1 = factor * Math.sqrt(d1s[jmax]);
diff2 = factor * Math.sqrt(d2s[jmax]);
diff3 = factor * Math.sqrt(d3s[jmax]);
m_Centroids[m_CurrSize][0] = (float) (m_Centroids[jmax][0] + diff1);
m_Centroids[m_CurrSize][1] = (float) (m_Centroids[jmax][1] + diff2);
m_Centroids[m_CurrSize][2] = (float) (m_Centroids[jmax][2] + diff3);
m_Centroids[jmax][0] = (float) (m_Centroids[jmax][0] - diff1);
m_Centroids[jmax][1] = (float) (m_Centroids[jmax][1] - diff2);
m_Centroids[jmax][2] = (float) (m_Centroids[jmax][2] - diff3);
m_CurrSize++;
} // end method Split
// ----------------- END SPLIT -------------------------------------
// ------------------Begin
// Agglom---------------------------------------------------------
/**
* Merging the bins using the "Agglomerative Clusterint Method"
*
* @param distthr
* ... some parameter :-)
*/
private void Agglom(double distthr) {
double d1, d2, d3, distmin = 0.0;
double[][] dists = new double[8][8];
double w1min, w2min;
int ja, jb = 0, jamin, jbmin;
do {
for (ja = 0; ja < m_CurrSize; ja++)
for (jb = 0; jb < ja; jb++) {
d1 = m_Centroids[ja][0] - m_Centroids[jb][0];
d2 = m_Centroids[ja][1] - m_Centroids[jb][1];
d3 = m_Centroids[ja][2] - m_Centroids[jb][2];
// dists[ja][jb] = d1 * d1 + d2 * d2 + d3 * d3;
/* START: added by janine to circumvent divisions by 0 */
// Distanz > 0, nur wenn weight nicht 0 ist!
if (m_Weights[ja] > 0.0 && m_Weights[jb] > 0.0)
dists[ja][jb] = (d1 * d1 + d2 * d2 + d3 * d3);
else
dists[ja][jb] = 0.0;
/* END: added by janine to circumvent divisions by 0 */
}
distmin = FLT_MAX;
jamin = 0;
jbmin = 0;
for (ja = 0; ja < m_CurrSize; ja++)
for (jb = 0; jb < ja; jb++)
if (dists[ja][jb] < distmin) {
distmin = dists[ja][jb];
jamin = ja;
jbmin = jb;
}
if (distmin > distthr)
break;
w1min = m_Weights[jamin];
w2min = m_Weights[jbmin];
// 'if' eingefuegt von Janine (division durch 0)
if (w1min + w2min > 0) {
m_Centroids[jbmin][0] = (float) ((w1min * m_Centroids[jamin][0] + w2min
* m_Centroids[jbmin][0]) / (w1min + w2min));
m_Centroids[jbmin][1] = (float) ((w1min * m_Centroids[jamin][1] + w2min
* m_Centroids[jbmin][1]) / (w1min + w2min));
m_Centroids[jbmin][2] = (float) ((w1min * m_Centroids[jamin][2] + w2min
* m_Centroids[jbmin][2]) / (w1min + w2min));
}
m_Weights[jbmin] += w1min;
m_CurrSize--;
for (jb = jamin; jb < m_CurrSize; jb++) {
m_Weights[jb] = m_Weights[jb + 1];
m_Centroids[jb][0] = m_Centroids[jb + 1][0];
m_Centroids[jb][1] = m_Centroids[jb + 1][1];
m_Centroids[jb][2] = m_Centroids[jb + 1][2];
m_Variances[jb][0] = m_Variances[jb + 1][0];
m_Variances[jb][1] = m_Variances[jb + 1][1];
m_Variances[jb][2] = m_Variances[jb + 1][2];
}
} while (m_CurrSize > 1 && distmin < distthr);
} // end method aglom
// ----------------------------END
// Agglom-----------------------------------------------
// ------------------------- Get Spatial Coherency
// ---------------------------------------------------
/**
* Extracts the spatial coherency
*/
private int GetSpatialCoherency(float[] ColorData, int dim, int N,
float[][] col_float, char quantImageAlpha) {
// char pAlpha;
double CM = 0.0;
int NeighborRange = 1;
float SimColorAllow = (float) Math.sqrt(DSTMIN);
boolean[] IVisit = new boolean[imsize];
for (int x = 0; x < (imsize); x++) {
IVisit[x] = false;
}
int All_Pixels = 0;
{
for (int x = 0; x < (imsize); x++)
if (IVisit[x] == false)
All_Pixels++;
}
{
for (int i = 0; i < N; i++) {
int Corres_Pixels = 0;
double Coherency = GetCoherencyWithColorAllow(ColorData, dim,
IVisit, col_float[i][0], col_float[i][1],
col_float[i][2], SimColorAllow, NeighborRange,
Corres_Pixels++);
CM += (Coherency * (double) Corres_Pixels) / 2.7;
}
}
return QuantizeSC(CM);
}// end method get spatial coherency
// ---------------------------------- ENDe GET spazial
// conherency-----------------------------------------
// --------------------------------- GET Coherency with Color Allow
// ---------------------------------
private double GetCoherencyWithColorAllow(float[] ColorData, int dim,
boolean[] IVisit, float l, float u, float v, float Allow,
int NeighborRange, int OUTPUT_Corres_Pixel_Count) {
int count, i, j;
int Neighbor_Count = 0;
int Pixel_Count = 0;
double Coherency = 0.0;
int width = imageWidth;
int height = imageHeight;
int ISize = imsize * dim;
for (count = 0; count < ISize; count += dim) {
i = (count / dim) % width; // width
//NOTE sergiu updated from width to height ... not sure if correct
j = (count / dim) / height; // height
float l1, u1, v1;
l1 = ColorData[count];
u1 = ColorData[count + 1];
v1 = ColorData[count + 2];
double distance;
distance = Math.sqrt(Math.pow(l - l1, 2) + Math.pow(u - u1, 2)
+ Math.pow(v - v1, 2));
if ((distance < Allow) && (IVisit[count / dim] == false))// no
// overlap
// checking
{
IVisit[count / dim] = true;
Pixel_Count++;
int nSameNeighbor = 0;
for (int y = j - NeighborRange; y <= j + NeighborRange; y++) {
for (int x = i - NeighborRange; x <= i + NeighborRange; x++) {
if (!((i == x) && (j == y))) {
int Index = (y * width + x) * dim;
if ((Index >= 0) && (Index < ISize)) {
float l2 = ColorData[Index];
float u2 = ColorData[Index + 1];
float v2 = ColorData[Index + 2];
distance = Math.sqrt(Math.pow((l - l2), 2)
+ Math.pow((u - u2), 2)
+ Math.pow((v - v2), 2));
if (distance < Allow) {
nSameNeighbor++;
}
}
}
}
}
Neighbor_Count += nSameNeighbor;
}
}
OUTPUT_Corres_Pixel_Count = Pixel_Count;
int neighbor_check_window_size = (NeighborRange << 1) + 1;
neighbor_check_window_size *= neighbor_check_window_size;
if (Pixel_Count == 0)
Coherency = 0.0;
else
Coherency = (double) Neighbor_Count / (double) Pixel_Count
/ (double) (neighbor_check_window_size - 1);
return Coherency;
}// method get Coherency with Color Allow
// -----------------------------END get coherency with color allow
// ----------------------------------------------
/**
* Takes the input RGB-Matrix and converts it into an array, withe
* 3*imagesize
*/
private int[] interleave(int size, int width, int height) {
int[] pixelarray = new int[3 * size];
int j = 0;
WritableRaster raster = bufferedImage.getRaster();
int[] pixel = new int[3];
for (int i = 0; i < width; i++) { // row
for (int ii = 0; ii < height; ii++) {// column
raster.getPixel(i, ii, pixel);
pixelarray[3 * j] = pixel[0];
pixelarray[3 * j + 1] = pixel[1];
pixelarray[3 * j + 2] = pixel[2];
j++;
}
}
return pixelarray;
}
private int QuantizeSC(double sc) {
if (sc < 0.70)
return 1;
else
return (int) ((sc - 0.70) / (1.0 - 0.70)
* (Math.pow(2.0, (double) SC_BIT) - 3.0) + .5) + 2;
}
private int GetBinNumberByComponent(int component) {
int i;
int NumComponents = 3;
int[] m_Component = new int[3];
int[] m_BinNumber = new int[3];
int ColorSpace = this.ColorSpacePresentInt;
String ColorSpaceStr = this.ColorSpacePresentStr;
if (ColorSpaceStr == "Monochrome")
NumComponents = 1; // monochrome (0101)
if (ColorSpace == 5)
NumComponents = 1; // monochrome (0101)
for (i = 0; i < NumComponents; i++)
if (m_Component[i] == component)
return m_BinNumber[i];
return -1;
}
// ---------------------------------------------------------------------------
// now some methods which are used to get and set die parameters for the
// extraction -> ColorQuantizationPresent,
// VariancePresent, SpatialCoherency, ColorSpacePresent
// gets the parameter for Varinace
public int getVariance() {
return (this.VariancePresent);
}
// sets the parameter for variance
public void setVariance(int Variance) {
this.VariancePresent = Variance;
}
// gets the parameter for spatialcoherency
public int getSpatialCoherency() {
return (this.SpatialCoherency);
}
// sets the parameter for spatial coherency
public void setSpatialCoherency(int Coherency) {
this.SpatialCoherency = Coherency;
}
// gets the parameter for ColorQuantizationPresent
public int getColorQuantizationPresent() {
return (this.ColorQuantizationPresent);
}
// sets the parameter for spatial ColorQuantizationPresent
public void setColorQuantizationPresent(int Quantization) {
this.ColorQuantizationPresent = Quantization;
}
// gets the parameter for ColorSpacePresent as Integer
public int getColorSpacePresentInt() {
return (this.ColorSpacePresentInt);
}
// sets the parameter for ColorSpacePresent as Integer
public void setColorSpacePresentInt(String Colorspace) {
this.ColorSpacePresentStr = Colorspace;
}
// gets the parameter for ColorSpacePresent as String
public String getColorSpacePresentStr() {
return (this.ColorSpacePresentStr);
}
// sets the parameter for ColorSpacePresent as String
public void setColorSpacePresentStr(String Colorspace) {
this.ColorSpacePresentStr = Colorspace;
}
}