com.github.ojil.algorithm.Gray8HistMatch Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of ojil-core Show documentation
Show all versions of ojil-core Show documentation
Open Java Imaging Library.
/*
* Gray8HistMatch.java
*
* Created on September 9, 2006, 4:07 PM
*
* To change this template, choose Tools | Template Manager
* and open the template in the editor.
*
* Copyright 2007 by Jon A. Webb
* This program 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 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 Lesser General Public License for more details.
*
* You should have received a copy of the Lesser GNU General Public License
* along with this program. If not, see .
*
*/
package com.github.ojil.algorithm;
import com.github.ojil.core.Error;
import com.github.ojil.core.Gray8Image;
import com.github.ojil.core.Image;
import com.github.ojil.core.PipelineStage;
import com.github.ojil.core.RgbVal;
/**
* Pipeline stage modifies a gray image's pixel values to make its histogram
* match a target histogram (to the extent this is possible while uniquely
* mapping each input grayvalue). This PipelineStage modifies its input.
*
* @author webb
*/
public class Gray8HistMatch extends PipelineStage {
/* We use the cumulative pixel count in computation, not
* the input histogram.
*/
private Integer[] histCumTarget;
/** Creates a new instance of Gray8HistMatch
*
* @param histTarget the input histogram.
* @throws com.github.ojil.core.Error if the input histogram does not have
* 256 elements.
*/
public Gray8HistMatch(Integer[] histTarget) throws com.github.ojil.core.Error {
setHistogram(histTarget);
}
private Byte[] createLookup(Integer[] histCumTarget, Integer[] histCumSource) {
Byte[] lookup = new Byte[256];
int j=0;
for (int i=0; i<256; i++) {
while (histCumTarget[j] < histCumSource[i]) {
j++;
}
if (j<256) {
// don't forget byte is a signed 8-bit value
lookup[i] = RgbVal.toSignedByte((byte)j);
} else {
lookup[i] = Byte.MAX_VALUE;
}
}
return lookup;
}
/** getHistogram returns the target histogram that has been
* previously set.
*
* @return the target histogram
*/
public Integer[] getHistogram() {
Integer[] result = new Integer[256];
/* since we store the cumulative histogram, not the original,
* we have to recover it by taking the differences.
*/
result[0] = this.histCumTarget[0];
for (int i=1; i<256; i++) {
result[i] = this.histCumTarget[i] - this.histCumTarget[i-1];
}
return result;
}
/** push transforms an input gray image to have the target histogram,
* as near as possible while assigning each input grayvalue a unique
* output grayvalue.
*
* @param image the input image.
* @throws com.github.ojil.core.Error if the input image is not gray.
*/
public void push(Image image) throws com.github.ojil.core.Error {
if (!(image instanceof Gray8Image)) {
throw new Error(
Error.PACKAGE.ALGORITHM,
ErrorCodes.IMAGE_NOT_GRAY8IMAGE,
image.toString(),
null,
null);
}
/* We could do a test here to make sure that the uppermost
* element of histCumTarget equals the count of pixels in
* the input image. But my own feeling is that it is OK if
* they don't match. The result will be a working lookup
* table, in any case, though the histogram won't quite
* match what was intended.
*/
Gray8Image input = (Gray8Image) image;
// get the input histogram
Integer[] histCum = Gray8Hist.computeHistogram(input);
// for the purposes of computation below we need a cumulative
// pixel count, not a histogram
for (int i=1; i<256; i++) {
histCum[i] = histCum[i] + histCum[i-1];
}
// create a lookkup table to map the input cumulative histogram
// to the target cumulative histogram.
Byte[] lookup = createLookup(this.histCumTarget, histCum);
// apply the lookup table
Gray8Lookup modify = new Gray8Lookup(lookup);
modify.push(input);
super.setOutput(modify.getFront());
}
/** setHistogram sets a new target histogram.
*
* @param histTarget the new target histogram
* @throws com.github.ojil.core.Error if histTarget does not have 256
* elements.
*/
public void setHistogram(Integer[] histTarget) throws com.github.ojil.core.Error {
if (histTarget.length != 256) {
throw new Error(
Error.PACKAGE.ALGORITHM,
ErrorCodes.HISTOGRAM_LENGTH_NOT_256,
histTarget.toString(),
null,
null);
}
this.histCumTarget = new Integer[256];
/* We actually store the cumulative histogram, not the original.
*/
histCumTarget[0] = histTarget[0];
for (int i=1; i<256; i++) {
histCumTarget[i] = histCumTarget[i-1] + histTarget[i];
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy