/*
* This file is part of Caliph & Emir.
*
* 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
*
* Copyright statement:
* --------------------
* (c) 2002-2005 by Mathias Lux (mathias@juggle.at)
* http://www.juggle.at, http://caliph-emir.sourceforge.net
*/
package at.lux.imageanalysis;
import java.awt.image.BufferedImage;
import java.awt.image.WritableRaster;
import java.util.StringTokenizer;
/**
* ScalableColor
*
* @author Mathias Lux, mathias@juggle.at
*/
public class ScalableColorImpl implements VisualDescriptor {
protected BufferedImage img;
protected int NumberOfCoefficients = 256;
protected int NumberOfBitplanesDiscarded = 0;
protected int _ySize, _xSize;
protected int _h_value, _s_value, _v_value;
protected double _quant_h, _quant_s, _quant_v;
protected int _xNumOfBlocks, _yNumOfBlocks;
protected int[][][] _wholeHist = null;
protected int[] haarTransformedHistogram;
protected static int[][] scalableColorQuantValues =
{
{217, 9, 255}, {-71, 9, 255}, {-27, 8, 127}, {-54, 9, 255}, {-8, 7, 63}, {-14, 7, 63}, {-22, 7, 63}, {-29, 8, 127},
{-6, 6, 31}, {-13, 7, 63}, {-11, 6, 31}, {-22, 7, 63}, {-9, 7, 63}, {-14, 7, 63}, {-19, 7, 63}, {-22, 7, 63},
{0, 4, 7}, {-1, 5, 15}, {0, 3, 3}, {-2, 6, 31}, {1, 5, 15}, {-5, 6, 31}, {0, 5, 15}, {0, 7, 63},
{2, 5, 15}, {-2, 6, 31}, {-2, 5, 15}, {0, 7, 63}, {3, 5, 15}, {-5, 6, 31}, {-1, 6, 31}, {4, 7, 63},
{0, 3, 3}, {0, 3, 3}, {0, 3, 3}, {-1, 5, 15}, {0, 3, 3}, {0, 3, 3}, {-1, 5, 15}, {-2, 5, 15},
{-1, 5, 15}, {-1, 4, 7}, {-1, 5, 15}, {-3, 5, 15}, {-1, 5, 15}, {-2, 5, 15}, {-4, 5, 15}, {-5, 5, 15},
{-1, 5, 15}, {0, 3, 3}, {-2, 5, 15}, {-2, 5, 15}, {-2, 5, 15}, {-3, 5, 15}, {-3, 5, 15}, {0, 5, 15},
{0, 5, 15}, {0, 5, 15}, {0, 5, 15}, {2, 5, 15}, {-1, 5, 15}, {0, 5, 15}, {3, 6, 31}, {3, 5, 15},
{0, 2, 1}, {0, 2, 1}, {0, 3, 3}, {0, 4, 7}, {0, 2, 1}, {0, 2, 1}, {0, 3, 3}, {-1, 4, 7},
{-1, 4, 7}, {-1, 4, 7}, {-2, 5, 15}, {-1, 5, 15}, {-2, 5, 15}, {-2, 5, 15}, {-2, 5, 15}, {-1, 5, 15},
{0, 3, 3}, {0, 2, 1}, {0, 3, 3}, {-1, 4, 7}, {0, 2, 1}, {0, 3, 3}, {-1, 4, 7}, {-1, 5, 15},
{-2, 5, 15}, {-1, 4, 7}, {-2, 5, 15}, {-1, 5, 15}, {-3, 5, 15}, {-3, 5, 15}, {-2, 5, 15}, {0, 5, 15},
{0, 3, 3}, {0, 3, 3}, {0, 3, 3}, {-1, 4, 7}, {0, 3, 3}, {0, 3, 3}, {-2, 5, 15}, {-2, 5, 15},
{-2, 5, 15}, {-2, 4, 7}, {-2, 5, 15}, {-1, 5, 15}, {-3, 5, 15}, {-3, 5, 15}, {-1, 5, 15}, {0, 5, 15},
{1, 4, 7}, {0, 3, 3}, {0, 4, 7}, {-1, 4, 7}, {0, 3, 3}, {0, 4, 7}, {-1, 4, 7}, {0, 4, 7},
{-1, 4, 7}, {-1, 3, 3}, {-1, 4, 7}, {0, 4, 7}, {-1, 5, 15}, {0, 5, 15}, {1, 5, 15}, {-1, 5, 15},
{0, 2, 1}, {0, 2, 1}, {0, 3, 3}, {0, 3, 3}, {0, 2, 1}, {0, 2, 1}, {0, 3, 3}, {0, 3, 3},
{0, 2, 1}, {0, 2, 1}, {0, 3, 3}, {0, 4, 7}, {0, 2, 1}, {0, 2, 1}, {0, 3, 3}, {0, 3, 3},
{0, 3, 3}, {0, 2, 1}, {0, 3, 3}, {1, 4, 7}, {0, 2, 1}, {0, 3, 3}, {-1, 4, 7}, {1, 4, 7},
{0, 3, 3}, {0, 3, 3}, {0, 3, 3}, {0, 4, 7}, {0, 3, 3}, {0, 3, 3}, {-1, 4, 7}, {0, 4, 7},
{0, 3, 3}, {0, 2, 1}, {0, 3, 3}, {0, 3, 3}, {0, 2, 1}, {0, 2, 1}, {0, 3, 3}, {0, 3, 3},
{0, 3, 3}, {0, 2, 1}, {0, 3, 3}, {1, 4, 7}, {0, 2, 1}, {0, 3, 3}, {0, 4, 7}, {1, 4, 7},
{0, 3, 3}, {0, 2, 1}, {0, 3, 3}, {1, 5, 15}, {0, 3, 3}, {0, 3, 3}, {-1, 5, 15}, {2, 5, 15},
{0, 3, 3}, {0, 3, 3}, {0, 3, 3}, {0, 4, 7}, {0, 3, 3}, {0, 3, 3}, {-1, 4, 7}, {1, 5, 15},
{0, 3, 3}, {0, 2, 1}, {0, 3, 3}, {0, 3, 3}, {0, 2, 1}, {0, 3, 3}, {0, 4, 7}, {0, 4, 7},
{0, 3, 3}, {0, 2, 1}, {0, 3, 3}, {1, 4, 7}, {0, 3, 3}, {0, 3, 3}, {-1, 5, 15}, {1, 5, 15},
{0, 3, 3}, {0, 2, 1}, {-1, 3, 3}, {1, 5, 15}, {0, 3, 3}, {-1, 4, 7}, {-1, 5, 15}, {2, 5, 15},
{0, 3, 3}, {0, 3, 3}, {0, 3, 3}, {0, 4, 7}, {0, 3, 3}, {-1, 3, 3}, {0, 4, 7}, {1, 4, 7},
{1, 3, 3}, {0, 2, 1}, {-1, 3, 3}, {0, 3, 3}, {0, 3, 3}, {0, 3, 3}, {0, 3, 3}, {1, 4, 7},
{0, 3, 3}, {0, 2, 1}, {-1, 3, 3}, {0, 4, 7}, {0, 3, 3}, {0, 3, 3}, {0, 4, 7}, {1, 4, 7},
{0, 3, 3}, {0, 2, 1}, {0, 3, 3}, {0, 4, 7}, {0, 3, 3}, {-1, 3, 3}, {0, 4, 7}, {1, 4, 7},
{0, 3, 3}, {0, 3, 3}, {0, 3, 3}, {0, 3, 3}, {0, 3, 3}, {-1, 3, 3}, {0, 3, 3}, {-1, 4, 7}
};
protected static final int[][] tabelle = new int[][]{
{0, 2, 4, 6, 8, 10, 12, 14, 0, 2, 4, 6, 8, 10, 12, 14, 0, 2, 4, 6, 8, 10,
12, 14, 0, 2, 4, 6, 8, 10, 12, 14, 0, 2, 4, 6, 8, 10, 12, 14, 0, 2, 4, 6,
8, 10, 12, 14, 0, 2, 4, 6, 8, 10, 12, 14, 0, 2, 4, 6, 8, 10, 12, 14, 0, 2,
4, 6, 8, 10, 12, 14, 0, 2, 4, 6, 8, 10, 12, 14, 0, 2, 4, 6, 8, 10, 12, 14,
0, 2, 4, 6, 8, 10, 12, 14, 0, 2, 4, 6, 8, 10, 12, 14, 0, 2, 4, 6, 8, 10,
12, 14, 0, 2, 4, 6, 8, 10, 12, 14, 0, 2, 4, 6, 8, 10, 12, 14, 0, 2, 4, 6,
8, 10, 12, 14, 0, 2, 4, 6, 8, 10, 12, 14, 0, 2, 4, 6, 8, 10, 12, 14, 0, 2,
4, 6, 8, 10, 12, 14, 0, 2, 4, 6, 8, 10, 12, 14, 0, 2, 4, 6, 8, 10, 12, 14,
0, 2, 4, 6, 8, 10, 12, 14, 0, 2, 4, 6, 8, 10, 12, 14, 0, 2, 4, 6, 8, 10,
12, 14, 0, 2, 4, 6, 8, 10, 12, 14, 0, 2, 4, 6, 8, 10, 12, 14, 0, 2, 4, 6,
8, 10, 12, 14, 0, 4, 8, 12, 0, 4, 8, 12, 0, 4, 8, 12, 0, 4, 8, 12, 0, 4,
8, 12, 0, 4, 8, 12, 0, 4, 8, 12, 0, 8, 0},
{0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2,
2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5,
5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8,
8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10,
11, 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 13,
13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 0, 0,
0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 4, 4, 4, 4, 4, 4, 4, 4, 6, 6,
6, 6, 6, 6, 6, 6, 8, 8, 8, 8, 8, 8, 8, 8, 10, 10, 10, 10, 10, 10, 10, 10,
12, 12, 12, 12, 12, 12, 12, 12, 14, 14, 14, 14, 14, 14, 14, 14, 0, 0, 0, 0, 0, 0,
0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 8, 8, 8, 8, 8, 8, 8, 8, 10, 10, 10, 10,
10, 10, 10, 10, 0, 0, 0, 0, 2, 2, 2, 2, 8, 8, 8, 8, 10, 10, 10, 10, 0, 0,
0, 0, 8, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0},
{1, 3, 5, 7, 9, 11, 13, 15, 1, 3, 5, 7, 9, 11, 13, 15, 1, 3, 5, 7, 9, 11,
13, 15, 1, 3, 5, 7, 9, 11, 13, 15, 1, 3, 5, 7, 9, 11, 13, 15, 1, 3, 5, 7,
9, 11, 13, 15, 1, 3, 5, 7, 9, 11, 13, 15, 1, 3, 5, 7, 9, 11, 13, 15, 1, 3,
5, 7, 9, 11, 13, 15, 1, 3, 5, 7, 9, 11, 13, 15, 1, 3, 5, 7, 9, 11, 13, 15,
1, 3, 5, 7, 9, 11, 13, 15, 1, 3, 5, 7, 9, 11, 13, 15, 1, 3, 5, 7, 9, 11,
13, 15, 1, 3, 5, 7, 9, 11, 13, 15, 1, 3, 5, 7, 9, 11, 13, 15, 0, 2, 4, 6,
8, 10, 12, 14, 0, 2, 4, 6, 8, 10, 12, 14, 0, 2, 4, 6, 8, 10, 12, 14, 0, 2,
4, 6, 8, 10, 12, 14, 0, 2, 4, 6, 8, 10, 12, 14, 0, 2, 4, 6, 8, 10, 12, 14,
0, 2, 4, 6, 8, 10, 12, 14, 0, 2, 4, 6, 8, 10, 12, 14, 0, 2, 4, 6, 8, 10,
12, 14, 0, 2, 4, 6, 8, 10, 12, 14, 0, 2, 4, 6, 8, 10, 12, 14, 0, 2, 4, 6,
8, 10, 12, 14, 2, 6, 10, 14, 2, 6, 10, 14, 2, 6, 10, 14, 2, 6, 10, 14, 0, 4,
8, 12, 0, 4, 8, 12, 0, 4, 8, 12, 4, 12, 8},
{0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2,
2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5,
5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8,
8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10,
11, 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 13,
13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, 1, 1, 1, 1,
1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 3, 3, 5, 5, 5, 5, 5, 5, 5, 5, 7, 7,
7, 7, 7, 7, 7, 7, 9, 9, 9, 9, 9, 9, 9, 9, 11, 11, 11, 11, 11, 11, 11, 11,
13, 13, 13, 13, 13, 13, 13, 13, 15, 15, 15, 15, 15, 15, 15, 15, 4, 4, 4, 4, 4, 4,
4, 4, 6, 6, 6, 6, 6, 6, 6, 6, 12, 12, 12, 12, 12, 12, 12, 12, 14, 14, 14, 14,
14, 14, 14, 14, 0, 0, 0, 0, 2, 2, 2, 2, 8, 8, 8, 8, 10, 10, 10, 10, 2, 2,
2, 2, 10, 10, 10, 10, 8, 8, 8, 8, 0, 0, 0},
{128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
128, 128, 128, 128, 128, 128, 128, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 32, 32, 32, 32, 32, 32,
32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
32, 32, 32, 32, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 8, 8,
8, 8, 8, 8, 8, 8, 4, 4, 4, 4, 2, 2, 1}
};
protected static final int[] sorttab = new int[]{
0, 4, 8, 12, 32, 36, 40, 44, 128, 132, 136, 140, 160, 164, 168, 172,
2, 6, 10, 14, 34, 38, 42, 46, 130, 134, 138, 142, 162, 166, 170, 174,
64, 66, 68, 70, 72, 74, 76, 78, 96, 98, 100, 102, 104, 106, 108, 110, 192, 194, 196, 198, 200, 202, 204, 206, 224, 226, 228, 230, 232, 234, 236, 238,
16, 18, 20, 22, 24, 26, 28, 30, 48, 50, 52, 54, 56, 58, 60, 62, 80, 82, 84, 86, 88, 90, 92, 94, 112, 114, 116, 118, 120, 122, 124, 126, 144, 146, 148, 150, 152, 154, 156, 158, 176, 178, 180, 182, 184, 186, 188, 190, 208, 210, 212, 214, 216, 218, 220, 222, 240, 242, 244, 246, 248, 250, 252, 254,
1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29, 31, 33, 35, 37, 39, 41, 43, 45, 47, 49, 51, 53, 55, 57, 59, 61, 63, 65, 67, 69, 71, 73, 75, 77, 79, 81, 83, 85, 87, 89, 91, 93, 95, 97, 99, 101, 103, 105, 107, 109, 111, 113, 115, 117, 119, 121, 123, 125, 127, 129, 131, 133, 135, 137, 139, 141, 143, 145, 147, 149, 151, 153, 155, 157, 159, 161, 163, 165, 167, 169, 171, 173, 175, 177, 179, 181, 183, 185, 187, 189, 191, 193, 195, 197, 199, 201, 203, 205, 207, 209, 211, 213, 215, 217, 219, 221, 223, 225, 227, 229, 231, 233, 235, 237, 239, 241, 243, 245, 247, 249, 251, 253, 255
};
private int[] pixels = null;
public ScalableColorImpl() {
}
public ScalableColorImpl(BufferedImage image, int NumberOfCoefficients, int NumberOfBitplanesDiscarded) {
this.img = image;
int numC = NumberOfCoefficients;
if (numC < 31)
numC = 16;
else if (numC < 64)
numC = 32;
else if (numC < 128)
numC = 64;
else if (numC < 256)
numC = 128;
else if (numC >= 256) numC = 256;
int numB = NumberOfBitplanesDiscarded;
if (numB < 1) numB = 0;
if (numB > 8) numB = 8;
this.NumberOfBitplanesDiscarded = numB;
this.NumberOfCoefficients = numC;
_xSize = img.getWidth();
_ySize = img.getHeight();
init();
extract();
}
public ScalableColorImpl(BufferedImage image) {
this.img = image;
this.NumberOfBitplanesDiscarded = 0;
this.NumberOfCoefficients = 64;
_xSize = img.getWidth();
_ySize = img.getHeight();
init();
extract();
}
public void extract(BufferedImage image) {
this.img = image;
this.NumberOfBitplanesDiscarded = 0;
this.NumberOfCoefficients = 64;
_xSize = img.getWidth();
_ySize = img.getHeight();
init();
extract();
}
/**
* Use this constructor 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], ...}<br>
* please note that althought
*
* @param pixels gives the pixels one int after another.
*/
public ScalableColorImpl(int[] pixels) {
this.img = null;
this.NumberOfBitplanesDiscarded = 0;
this.NumberOfCoefficients = 64;
_xSize = 1;
_ySize = pixels.length / 3;
this.pixels = pixels;
init();
extract();
}
public ScalableColorImpl(String descriptor) {
_xSize = 0;
_ySize = 0;
setStringRepresentation(descriptor);
init();
}
protected void init() {
_xNumOfBlocks = 1;
_yNumOfBlocks = 1;
_h_value = 16;
_s_value = 4;
_v_value = 4;
}
protected void extract() {
int imageColSize = _xSize * _ySize * 3;
//contains HSV- values of the Image
int[] hsvImageBuffer;
hsvImageBuffer = createHsvImageBuffer(imageColSize);
if (_xNumOfBlocks > _xSize)
_xNumOfBlocks = _xSize;
if (_yNumOfBlocks > _ySize)
_yNumOfBlocks = _ySize;
//width and height of the blocks
int width = _xSize / _xNumOfBlocks;
int height = _ySize / _yNumOfBlocks;
// nur bei verwendung von bloecken ...
// _desHistograms = new int[_xNumOfBlocks][_yNumOfBlocks][_h_value][_s_value][_v_value];
// for (int i = 0; i < _xNumOfBlocks; i++) {
// for (int j = 0; j < _yNumOfBlocks; j++) {
// for (int k = 0; k < _h_value; k++) {
// for (int l = 0; l < _s_value; l++) {
// for (int m = 0; m < _v_value; m++)
// _desHistograms[i][j][k][l][m] = 0;
// }
// }
// }
// }
_wholeHist = new int[_h_value][_s_value][_v_value];
for (int k = 0; k < _h_value; k++) {
for (int l = 0; l < _s_value; l++) {
for (int m = 0; m < _v_value; m++)
_wholeHist[k][l][m] = 0;
}
}
//Quantisation and histogram-calculation
int x, y;
x = 0;
y = 0;
for (int m = 0; m < _xNumOfBlocks; m++) {
for (int n = 0; n < _yNumOfBlocks; n++) {
int xy;
for (int j = y; j < (y + height); j++) {
xy = (x * 3) + (j * _xSize * 3);
for (int i = xy; i < (xy + (width * 3)); i += 3) {
_Quant(hsvImageBuffer[i], hsvImageBuffer[i + 1], hsvImageBuffer[i + 2], m, n);
}
}
y += height;
}
x += width;
y = 0;
}
int sumPixels = 0;
int[] tmpHist = new int[_h_value * _v_value * _s_value];
int count = 0;
for (int k = 0; k < _v_value; k++) {
for (int l = 0; l < _s_value; l++) {
for (int m = 0; m < _h_value; m++) {
tmpHist[count] = _wholeHist[m][l][k];
sumPixels += tmpHist[count];
count++;
}
}
}
QuantizeHistogram(tmpHist, sumPixels);
haarTransformedHistogram = HaarTransform(tmpHist);
}
private int[] createHsvImageBuffer(int imageColSize) {
int[] hsvImageBuffer = null;
hsvImageBuffer = new int[imageColSize];
if (img != null) {
//convertRgbToHsv
int[] hsv = new int[3];
WritableRaster raster = img.getRaster();
int[] pixel = new int[3];
for (int i = 0; i < imageColSize; i += 3) {
raster.getPixel((i / 3) % _xSize, (i / 3) / _xSize, pixel);
convertRgbToHsv(pixel[0], pixel[1], pixel[2], hsv);
hsvImageBuffer[i] = hsv[0];
hsvImageBuffer[i + 1] = hsv[1];
hsvImageBuffer[i + 2] = hsv[2];
}
} else if (pixels != null) {
int[] hsv = new int[3];
for (int i = 0; i < pixels.length; i += 3) {
convertRgbToHsv(pixels[i], pixels[i + 1], pixels[i + 2], hsv);
hsvImageBuffer[i] = hsv[0];
hsvImageBuffer[i + 1] = hsv[1];
hsvImageBuffer[i + 2] = hsv[2];
}
}
return hsvImageBuffer;
}
public void recalc() {
if (img != null) {
int[] tmpHist = new int[_h_value * _v_value * _s_value];
int count = 0;
int sumPixels = 0;
for (int k = 0; k < _v_value; k++) {
for (int l = 0; l < _s_value; l++) {
for (int m = 0; m < _h_value; m++) {
tmpHist[count] = _wholeHist[m][l][k];
sumPixels += tmpHist[count];
count++;
}
}
}
QuantizeHistogram(tmpHist, sumPixels);
haarTransformedHistogram = HaarTransform(tmpHist);
}
}
protected static void convertRgbToHsv(int R, int G, int B, int[] hsv) {
/*
// clssical approach
int max, min;
float hue = 0f;
max = Math.max(R, G); //calculation of max(R,G,B)
max = Math.max(max, B);
min = Math.min(R, G); //calculation of min(R,G,B)
min = Math.min(min, B);
if (max == 0)
hsv[1] = 0;
else
hsv[1] = (int) (((max - min) / (float) max) * 255f); //Saturation range: (0..255)
if (max == min) {
hue = 0; // (max - min) = 0
} else {
float maxMinusMin = (float) (max - min);
if (R == max)
hue = ((G - B) / maxMinusMin);
else if (G == max)
hue = (2 + (B - R) / maxMinusMin);
else if (B == max)
hue = (4 + (R - G) / maxMinusMin);
hue *= 60f;
if (hue < 0f)
hue += 360f;
}
hsv[0] = (int) (hue); // Hue range: (0..359)
hsv[2] = max; // Value range:(0..255)
*/
// taken from XM ...
int maxrgb, minrgb;
char order;
double floath;
if (G > B) {
if (R > G) {
maxrgb = R;
minrgb = B;
order = 0;
} else {
if (B > R) {
maxrgb = G;
minrgb = R;
order = 1;
} else {
maxrgb = G;
minrgb = B;
order = 2;
}
}
} else {
if (R > B) {
maxrgb = R;
minrgb = G;
order = 3;
} else {
if (G > R) {
maxrgb = B;
minrgb = R;
order = 4;
} else {
maxrgb = B;
minrgb = G;
order = 5;
}
}
}
if (maxrgb == 0) {
hsv[0] = 0;
hsv[1] = 0;
hsv[2] = 0;
return;
}
hsv[2] = maxrgb;
hsv[1] = ((maxrgb - minrgb) * 255) / maxrgb;
if (maxrgb == minrgb) {
hsv[0] = 0;
return;
}
switch (order) {
case 0:
floath = 1.0 - (double) (R - G) / (double) (R - B);
break;
case 1:
floath = 3.0 - (double) (G - B) / (double) (G - R);
break;
case 2:
floath = 1.0 + (double) (G - R) / (double) (G - B);
break;
case 3:
floath = 5.0 + (double) (R - B) / (double) (R - G);
break;
case 4:
floath = 3.0 + (double) (B - G) / (double) (B - R);
break;
case 5:
floath = 5.0 - (double) (B - R) / (double) (B - G);
break;
default:
System.err.println("Error: Internal error in RGB to HSV transformation");
floath = 0.0;
}
hsv[0] = (int) (floath / 6 * 255);
}
protected void _Quant(int H, int S, int V, int m, int n) {
int i, j, k;
i = (int) ((H * _h_value) / 256f); //H in _quant_h levels
j = (int) ((S * _s_value) / 256f); //S in _quant_s levels
k = (int) ((V * _v_value) / 256f); //V in _quant_v levels
// _desHistograms[m][n][i][j][k]++;
_wholeHist[i][j][k]++;
}
public int getSimilarity(ScalableColorImpl secHist) {
int diffsum = 0;
int diff = 0;
// similarity nur wenn #BitPlanes und #Coeff gleich ist:
if (secHist.NumberOfBitplanesDiscarded == NumberOfBitplanesDiscarded &&
secHist.NumberOfCoefficients == NumberOfCoefficients &&
secHist.haarTransformedHistogram != null &&
haarTransformedHistogram != null) {
int[] secHaarHist = secHist.haarTransformedHistogram;
for (int l = 0; l < NumberOfCoefficients; l++) {
diff = Math.abs(secHaarHist[l] - haarTransformedHistogram[l]);
diffsum += diff;
}
} else {
if (haarTransformedHistogram != null && secHist.haarTransformedHistogram != null)
throw new UnsupportedOperationException("NumberOfBitplanesDiscarded and/or NumberOfCoefficients not matching");
else
throw new UnsupportedOperationException("One of the Descriptor histograms is NULL");
}
// Summe der Differenzen als Mass der �hnlichkeit
return diffsum;
}
// von XM ... :)
static void histo_3d_hirarch_5(int[][] tabelle, int tablae, int[] histogram,
int h_size, int s_size, int v_size, int hist_nr) {
int sum, dif, x1, y1, x2, y2;
int[][] matrix = new int[16][16];
for (int i = 0; i < h_size * s_size * v_size; ++i)
matrix[i % (h_size)][i / (h_size)] = histogram[i];
for (int i = 0; i < tablae; ++i) {
y1 = tabelle[0][i];
x1 = tabelle[1][i];
y2 = tabelle[2][i];
x2 = tabelle[3][i];
sum = matrix[y1][x1] + matrix[y2][x2];
dif = matrix[y2][x2] - matrix[y1][x1];
matrix[y1][x1] = sum;
matrix[y2][x2] = dif;
}
for (int i = 0; i < h_size * s_size * v_size; ++i)
histogram[i] = matrix[i % (h_size)][i / (h_size)];
}
// von XM ... :)
private static void histo_3d_hirarch_16_5(int[][] tabelle, int tablae, int[] histogram,
int h_size, int s_size, int v_size, int hist_nr) {
int i, j, sum, dif, x1, y1, x2, y2;
int[][] matrix = new int[16][16];
int iprint = 0;
for (i = 0; i < h_size * s_size * v_size; ++i)
matrix[i % (h_size)][i / (h_size)] = histogram[i];
for (i = 0; i < tablae; ++i) {
if (tabelle[4][i] <= 8) continue;
y1 = tabelle[0][i];
x1 = tabelle[1][i];
y2 = tabelle[2][i];
x2 = tabelle[3][i];
sum = matrix[y1][x1] + matrix[y2][x2];
dif = matrix[y2][x2] - matrix[y1][x1];
if (iprint == 1) {
matrix[y1][x1] = sum;
}
matrix[y2][x2] = dif;
}
for (i = 0; i < h_size * s_size * v_size; ++i)
histogram[i] = matrix[i % (h_size)][i / (h_size)];
}
int[] QuantizeHistogram(int[] aHist, int sumPixels) {
// ** from XM ...
int factor = 0, ibinwert;
// unsigned long NoOfBitsProBin=11;
double binwert;
// factor=0;
// for (i=0; i<NoOfBitsProBin;i++)
// factor=2*factor+1;
factor = 0x7ff; //NoBitsProBin=11
//quantisierung der bins
for (int i = 0; i < NumberOfCoefficients; i++) {
binwert = (double) (factor) * (double) (aHist[i] / (double) sumPixels);
ibinwert = (int) (binwert + 0.49999);
if (ibinwert > factor) ibinwert = factor;//obsolete
aHist[i] = ibinwert;
}
factor = 15;
int iwert = 0;
double wert, potenz = 0.4;
double arg, maxwert;
maxwert = (double) 40 * (double) 2047 / (double) 100;
for (int i = 0; i < NumberOfCoefficients; i++) {
wert = (double) (aHist[i]);
if (wert > maxwert) iwert = factor;
if (wert <= maxwert) {
arg = wert / maxwert;
wert = (float) factor * Math.pow(arg, potenz);
iwert = (int) (wert + 0.5);
}
if (iwert > factor) iwert = factor;
aHist[i] = iwert;
}
return aHist;
}
// kopiert von XM ... :)
private int[] HaarTransform(int[] aHist) {
int index, tablae = 255, iwert, hist_nr;
int[] histogram_in, histogram_out;
int RecHistogram = 0;
int h_size, s_size, v_size, max_color = 256;
h_size = 16;
s_size = 4;
v_size = 4;
hist_nr = 256;
RecHistogram = 0;
histogram_in = new int[max_color];
histogram_out = new int[max_color];
for (int i = 0; i < NumberOfCoefficients; i++) {
histogram_in[i] = (int) aHist[i];
}
if (RecHistogram == 2) {
histo_3d_hirarch_16_5(tabelle, tablae, histogram_in, h_size, s_size, v_size, hist_nr);
hsv_hir_quant_lin_5(histogram_in);
}
if (RecHistogram != 2) {
histo_3d_hirarch_5(tabelle, tablae, histogram_in,
h_size, s_size, v_size, hist_nr);
for (int j = 0; j < 256; ++j) {
index = sorttab[j];
histogram_out[j] = histogram_in[index];
}
hsv_hir_quant_lin_5(histogram_out);
red_bits_pro_bin_5(histogram_out, NumberOfBitplanesDiscarded, 0);
}
int[] returnHist = new int[hist_nr];
System.arraycopy(histogram_out, 0, returnHist, 0, hist_nr);
return returnHist;
}
// XM Kauderwelsch :)
static void red_bits_pro_bin_5(int[] histogram,
int NumberOfBitplanesDiscarded,
int ivert) {
int wert, wert1, bits_pro_bin, bits_pro_bild;
int max_bits_pro_bin, anzkof;
if (NumberOfBitplanesDiscarded == 0) return;
bits_pro_bild = 0;
max_bits_pro_bin = 0;
anzkof = 0;
if (NumberOfBitplanesDiscarded > 0) {
for (int i = 0; i < 256; ++i) {
bits_pro_bin = scalableColorQuantValues[i][1] - NumberOfBitplanesDiscarded;
if (bits_pro_bin < 2) {
wert = histogram[i];
if (wert >= 0) histogram[i] = 1;
if (wert < 0) histogram[i] = 0;
bits_pro_bild = bits_pro_bild + 1;
}
if (bits_pro_bin >= 2) {
wert = histogram[i];
wert1 = wert;
if (wert < 0) wert = -wert;
bits_pro_bild = bits_pro_bild + bits_pro_bin;
if (bits_pro_bin > max_bits_pro_bin) max_bits_pro_bin = bits_pro_bin;
anzkof = anzkof + 1;
for (int j = 0; j < NumberOfBitplanesDiscarded; ++j)
wert = wert >> 1;
// if ((wert == 0) && (wert1 >= 0)) histogram[i] = 0;
// if ((wert == 0) && (wert1 < 0)) histogram[i] = 1;
if (wert1 < 0) wert = -wert;
histogram[i] = wert;
}
}
}
}
// XM Kauderwelsch :)
private static void hsv_hir_quant_lin_5(int[] histogram) {
int i, wert, maxwert;
for (i = 0; i < 256; ++i) {
maxwert = scalableColorQuantValues[i][2];
wert = histogram[i] - scalableColorQuantValues[i][0];
if (wert > maxwert) wert = maxwert;
if (wert < -maxwert) wert = -maxwert;
histogram[i] = wert;
}
}
public int getNumberOfCoefficients() {
return NumberOfCoefficients;
}
public void setNumberOfCoefficients(int numberOfCoefficients) {
if (img != null) {
NumberOfCoefficients = numberOfCoefficients;
}
}
public int getNumberOfBitplanesDiscarded() {
return NumberOfBitplanesDiscarded;
}
public void setNumberOfBitplanesDiscarded(int numberOfBitplanesDiscarded) {
if (img != null) {
NumberOfBitplanesDiscarded = numberOfBitplanesDiscarded;
}
}
public int[] getHaarTransformedHistogram() {
return haarTransformedHistogram;
}
public boolean isRecalcable() {
if (_wholeHist != null) {
return true;
} else {
return false;
}
}
/**
* Compares one descriptor to another.
*
* @param descriptor
* @return the distance from [0,infinite) or -1 if descriptor type does not match
*/
public float getDistance(VisualDescriptor descriptor) {
if (!(descriptor instanceof ScalableColorImpl)) return -1f;
ScalableColorImpl sc = (ScalableColorImpl) descriptor;
return (float) sc.getSimilarity(this);
}
public String getStringRepresentation() {
StringBuilder builder = new StringBuilder(NumberOfCoefficients * 3 + 32);
builder.append("scalablecolor;");
builder.append(NumberOfBitplanesDiscarded);
builder.append(';');
builder.append(NumberOfCoefficients);
builder.append(';');
for (int i = 0; i < NumberOfCoefficients; i++) {
builder.append(haarTransformedHistogram[i]);
if ((i + 1) < NumberOfCoefficients) builder.append(' ');
}
return builder.toString();
}
public void setStringRepresentation(String descriptor) {
String[] parts = descriptor.split(";");
if (!parts[0].equals("scalablecolor")) {
throw new UnsupportedOperationException("This is no valid representation of a ScalableColor descriptor!");
}
NumberOfBitplanesDiscarded = Integer.parseInt(parts[1]);
NumberOfCoefficients = Integer.parseInt(parts[2]);
int[] hist = new int[NumberOfCoefficients];
StringTokenizer st = new StringTokenizer(parts[3], " ");
int count = 0;
while (st.hasMoreElements()) {
hist[count] = Integer.parseInt(st.nextToken());
count++;
}
haarTransformedHistogram = hist;
}
}