/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package jjil.algorithm;
import jjil.core.Error;
import jjil.core.Gray8Image;
import jjil.core.Image;
import jjil.core.PipelineStage;
import jjil.core.RgbImage;
import jjil.core.RgbVal;
/**
* Thresholds an RgbImage against a number of input colors.
* @author webb
*/
public class RgbMultiVecThresh extends PipelineStage {
/**
* Simplify lookup of color values in array.
*/
private final int R = 0;
private final int G = 1;
private final int B = 2;
private int[][] nRgbVals;
/**
* Input color values, unpacked.
*/
private int[][] nRgbVecs;
/**
* Input threshold value.
*/
private int nThreshold;
/**
* Thresholds an RgbImage against a number of input colors.
* Each color is described using a target value (rgbVal) and
* a vector (rgbVec). The idea is that a pixel matches a target
* value if its difference from the target value, projected
* on the vector, is less than the threshold. One threshold
* is used for all colors and the minimum absolute value of
* all color distances is compared with the threshold. Since
* the vectors can be unnormalized the relative importance of
* each target color value can be adjusted. </br>
* One way to use this is to set the target color to the mean
* Rgb value of a region and the target vector to the standard
* deviation. The threshold would then be the standard deviation
* squared. Pixels further away than one standard deviation would
* be rejected.
* @param rgbVals packed arry of target Rgb values
* @param rgbVecs packed array of target Rgb vectors
* @param nThreshold threshold value
* @throws Error if the input Rgb vectors are not the same
* length.
*/
public RgbMultiVecThresh(int [] rgbVals, int[] rgbVecs, int nThreshold)
throws Error
{
if (rgbVals.length != rgbVecs.length) {
throw new Error(
Error.PACKAGE.ALGORITHM,
ErrorCodes.PARAMETER_SIZES_DIFFER,
rgbVals.toString(),
rgbVals.toString(),
null);
}
this.nRgbVecs = new int[rgbVecs.length][3];
this.nRgbVals = new int[rgbVecs.length][3];
for (int i=0; i<rgbVecs.length; i++) {
this.nRgbVals[i][R] = RgbVal.getR(rgbVals[i]);
this.nRgbVals[i][G] = RgbVal.getG(rgbVals[i]);
this.nRgbVals[i][B] = RgbVal.getB(rgbVals[i]);
this.nRgbVecs[i][R] = RgbVal.getR(rgbVecs[i]);
this.nRgbVecs[i][G] = RgbVal.getG(rgbVecs[i]);
this.nRgbVecs[i][B] = RgbVal.getB(rgbVecs[i]);
}
this.nThreshold = nThreshold;
}
/**
* Compares input RgbImage with the color values set in the
* constructor and outputs Byte.MAX_VALUE for any pixels within
* the threshold value of any of the input colors. Other
* pixels get Byte.MIN_VALUE.
* @param imageInput input RgbImage
* @throws jjil.core.Error if input is not an RgbImage.
*/
public void push(Image imageInput) throws Error {
if (!(imageInput instanceof RgbImage)) {
throw new Error(
Error.PACKAGE.ALGORITHM,
ErrorCodes.IMAGE_NOT_RGBIMAGE,
imageInput.toString(),
null,
null);
}
RgbImage rgbInput = (RgbImage) imageInput;
int [] rgbData = rgbInput.getData();
Gray8Image grayOutput = new Gray8Image(
rgbInput.getWidth(),
rgbInput.getHeight());
byte [] grayData = grayOutput.getData();
for (int i=0; i<rgbInput.getHeight()*rgbInput.getWidth(); i++) {
int nR = RgbVal.getR(rgbData[i]);
int nG = RgbVal.getG(rgbData[i]);
int nB = RgbVal.getB(rgbData[i]);
int nMinVal = Integer.MAX_VALUE;
for (int j=0; j<this.nRgbVecs.length; j++) {
int nVal = (nR - this.nRgbVals[j][R]) * this.nRgbVecs[j][R] +
(nG - this.nRgbVals[j][G]) * this.nRgbVecs[j][G] +
(nB - this.nRgbVals[j][B]) * this.nRgbVecs[j][B];
nMinVal = Math.min(nMinVal, Math.abs(nVal));
}
if (nMinVal < this.nThreshold) {
grayData[i] = Byte.MAX_VALUE;
} else {
grayData[i] = Byte.MIN_VALUE;
}
}
super.setOutput(grayOutput);
}
/**
* Implements toString
* @return a string including all the input color values
* and the input threshold value.
*/
public String toString() {
String szParams = "{";
for (int i=0; i<this.nRgbVecs.length; i++) {
szParams += "[R=" + Integer.toString(this.nRgbVecs[i][R]) + "," +
"G=" + Integer.toString(this.nRgbVecs[i][G]) + "," +
"B=" + Integer.toString(this.nRgbVecs[i][B]) + "],";
}
szParams += "Threshold=" + Integer.toString(this.nThreshold) + ")";
return super.toString() + szParams;
}
}