/*
* Copyright (c) 2011-2013, Peter Abeles. All Rights Reserved.
*
* This file is part of BoofCV (http://boofcv.org).
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package boofcv.alg.enhance.impl;
import boofcv.misc.AutoTypeImage;
import boofcv.misc.CodeGeneratorBase;
import java.io.FileNotFoundException;
/**
* @author Peter Abeles
*/
public class GenerateImplEnhanceHistogram extends CodeGeneratorBase {
String className = "ImplEnhanceHistogram";
public GenerateImplEnhanceHistogram() throws FileNotFoundException {
setOutputFile(className);
}
@Override
public void generate() throws FileNotFoundException {
printPreamble();
applyTransform_U(AutoTypeImage.U8);
applyTransform_U(AutoTypeImage.U16);
applyTransform_S(AutoTypeImage.S8);
applyTransform_S(AutoTypeImage.S16);
applyTransform_S(AutoTypeImage.S32);
printInner(AutoTypeImage.U8);
printInner(AutoTypeImage.U16);
out.print("\n" +
"}\n");
}
private void printInner( AutoTypeImage image ) {
equalizeLocalNaive(image);
equalizeLocalInner(image);
equalizeLocalRow(image);
equalizeLocalCol(image);
localHistogram(image);
}
private void printPreamble() {
out.print("import boofcv.struct.image.*;\n" +
"\n" +
"/**\n" +
" * <p>\n" +
" * Functions for enhancing images using the image histogram.\n" +
" * </p>\n" +
" *\n" +
" * <p>\n" +
" * NOTE: Do not modify. Automatically generated by {@link GenerateImplEnhanceHistogram}.\n" +
" * </p>\n" +
" *\n" +
" * @author Peter Abeles\n" +
" */\n" +
"public class "+className+" {\n\n");
}
private void applyTransform_U( AutoTypeImage image ) {
String typecast = image.getTypeCastFromSum();
String bitwise = image.getBitWise();
out.print("\tpublic static void applyTransform( "+image.getSingleBandName()+" input , int transform[] , "+image.getSingleBandName()+" output ) {\n" +
"\t\tfor( int i = 0; i < input.height; i++ ) {\n" +
"\t\t\tint indexInput = input.startIndex + i*input.stride;\n" +
"\t\t\tint indexOutput = output.startIndex + i*output.stride;\n" +
"\n" +
"\t\t\tfor( int j = 0; j < input.width; j++ ) {\n" +
"\t\t\t\toutput.data[indexOutput++] = "+typecast+"transform[input.data[indexInput++] "+bitwise+"];\n" +
"\t\t\t}\n" +
"\t\t}\n" +
"\t}\n\n");
}
private void applyTransform_S( AutoTypeImage image ) {
String typecast = image.getTypeCastFromSum();
out.print("\tpublic static void applyTransform( "+image.getSingleBandName()+" input , int transform[] , int minValue , "+image.getSingleBandName()+" output ) {\n" +
"\t\tfor( int i = 0; i < input.height; i++ ) {\n" +
"\t\t\tint indexInput = input.startIndex + i*input.stride;\n" +
"\t\t\tint indexOutput = output.startIndex + i*output.stride;\n" +
"\n" +
"\t\t\tfor( int j = 0; j < input.width; j++ ) {\n" +
"\t\t\t\toutput.data[indexOutput++] = "+typecast+"transform[input.data[indexInput++]- minValue];\n" +
"\t\t\t}\n" +
"\t\t}\n" +
"\t}\n\n");
}
private void equalizeLocalNaive( AutoTypeImage image ) {
String name = image.getSingleBandName();
String typecast = image.getTypeCastFromSum();
String bitwise = image.getBitWise();
out.print("\t/**\n" +
"\t * Inefficiently computes the local histogram, but can handle every possible case for image size and\n" +
"\t * local region size\n" +
"\t */\n" +
"\tpublic static void equalizeLocalNaive( "+name+" input , int radius , "+name+" output ,\n" +
"\t\t\t\t\t\t\t\t\t\t int histogram[] )\n" +
"\t{\n" +
"\t\tint width = 2*radius+1;\n" +
"\t\tint maxValue = histogram.length-1;\n" +
"\n" +
"\t\tfor( int y = 0; y < input.height; y++ ) {\n" +
"\t\t\t// make sure it's inside the image bounds\n" +
"\t\t\tint y0 = y-radius;\n" +
"\t\t\tint y1 = y+radius+1;\n" +
"\t\t\tif( y0 < 0 ) {\n" +
"\t\t\t\ty0 = 0; y1 = width;\n" +
"\t\t\t\tif( y1 > input.height )\n" +
"\t\t\t\t\ty1 = input.height;\n" +
"\t\t\t} else if( y1 > input.height ) {\n" +
"\t\t\t\ty1 = input.height;\n" +
"\t\t\t\ty0 = y1 - width;\n" +
"\t\t\t\tif( y0 < 0 )\n" +
"\t\t\t\t\ty0 = 0;\n" +
"\t\t\t}\n" +
"\n" +
"\t\t\t// pixel indexes\n" +
"\t\t\tint indexIn = input.startIndex + y*input.stride;\n" +
"\t\t\tint indexOut = output.startIndex + y*output.stride;\n" +
"\n" +
"\t\t\tfor( int x = 0; x < input.width; x++ ) {\n" +
"\t\t\t\t// make sure it's inside the image bounds\n" +
"\t\t\t\tint x0 = x-radius;\n" +
"\t\t\t\tint x1 = x+radius+1;\n" +
"\t\t\t\tif( x0 < 0 ) {\n" +
"\t\t\t\t\tx0 = 0; x1 = width;\n" +
"\t\t\t\t\tif( x1 > input.width )\n" +
"\t\t\t\t\t\tx1 = input.width;\n" +
"\t\t\t\t} else if( x1 > input.width ) {\n" +
"\t\t\t\t\tx1 = input.width;\n" +
"\t\t\t\t\tx0 = x1 - width;\n" +
"\t\t\t\t\tif( x0 < 0 )\n" +
"\t\t\t\t\t\tx0 = 0;\n" +
"\t\t\t\t}\n" +
"\n" +
"\t\t\t\t// compute the local histogram\n" +
"\t\t\t\tlocalHistogram(input,x0,y0,x1,y1,histogram);\n" +
"\n" +
"\t\t\t\t// only need to compute up to the value of the input pixel\n" +
"\t\t\t\tint inputValue = input.data[indexIn++] "+bitwise+";\n" +
"\t\t\t\tint sum = 0;\n" +
"\t\t\t\tfor( int i = 0; i <= inputValue; i++ ) {\n" +
"\t\t\t\t\tsum += histogram[i];\n" +
"\t\t\t\t}\n" +
"\n" +
"\t\t\t\tint area = (y1-y0)*(x1-x0);\n" +
"\t\t\t\toutput.data[indexOut++] = "+typecast+"((sum*maxValue)/area);\n" +
"\t\t\t}\n" +
"\t\t}\n" +
"\t}\n\n");
}
private void equalizeLocalInner( AutoTypeImage image ) {
String name = image.getSingleBandName();
String typecast = image.getTypeCastFromSum();
String bitwise = image.getBitWise();
out.print("\t/**\n" +
"\t * Performs local histogram equalization just on the inner portion of the image\n" +
"\t */\n" +
"\tpublic static void equalizeLocalInner( "+name+" input , int radius , "+name+" output ,\n" +
"\t\t\t\t\t\t\t\t\t\t int histogram[] ) {\n" +
"\n" +
"\t\tint width = 2*radius+1;\n" +
"\t\tint area = width*width;\n" +
"\t\tint maxValue = histogram.length-1;\n" +
"\n" +
"\t\tfor( int y = radius; y < input.height-radius; y++ ) {\n" +
"\t\t\tlocalHistogram(input,0,y-radius,width,y+radius+1,histogram);\n" +
"\n" +
"\t\t\t// compute equalized pixel value using the local histogram\n" +
"\t\t\tint inputValue = input.unsafe_get(radius, y);\n" +
"\t\t\tint sum = 0;\n" +
"\t\t\tfor( int i = 0; i <= inputValue; i++ ) {\n" +
"\t\t\t\tsum += histogram[i];\n" +
"\t\t\t}\n" +
"\n" +
"\t\t\toutput.set(radius,y, (sum*maxValue)/area );\n" +
"\n" +
"\t\t\t// start of old and new columns in histogram region\n" +
"\t\t\tint indexOld = input.startIndex + y*input.stride;\n" +
"\t\t\tint indexNew = indexOld+width;\n" +
"\n" +
"\t\t\t// index of pixel being examined\n" +
"\t\t\tint indexIn = input.startIndex + y*input.stride+radius+1;\n" +
"\t\t\tint indexOut = output.startIndex + y*output.stride+radius+1;\n" +
"\n" +
"\t\t\tfor( int x = radius+1; x < input.width-radius; x++ ) {\n" +
"\n" +
"\t\t\t\t// update local histogram by removing the left column\n" +
"\t\t\t\tfor( int i = -radius; i <= radius; i++ ) {\n" +
"\t\t\t\t\thistogram[input.data[indexOld + i*input.stride] "+bitwise+"]--;\n" +
"\t\t\t\t}\n" +
"\n" +
"\t\t\t\t// update local histogram by adding the right column\n" +
"\t\t\t\tfor( int i = -radius; i <= radius; i++ ) {\n" +
"\t\t\t\t\thistogram[input.data[indexNew + i*input.stride] "+bitwise+"]++;\n" +
"\t\t\t\t}\n" +
"\n" +
"\t\t\t\t// compute equalized pixel value using the local histogram\n" +
"\t\t\t\tinputValue = input.data[indexIn++] "+bitwise+";\n" +
"\t\t\t\tsum = 0;\n" +
"\t\t\t\tfor( int i = 0; i <= inputValue; i++ ) {\n" +
"\t\t\t\t\tsum += histogram[i];\n" +
"\t\t\t\t}\n" +
"\n" +
"\t\t\t\toutput.data[indexOut++] = "+typecast+"((sum*maxValue)/area);\n" +
"\n" +
"\t\t\t\tindexOld++;\n" +
"\t\t\t\tindexNew++;\n" +
"\t\t\t}\n" +
"\t\t}\n" +
"\t}\n\n");
}
private void equalizeLocalRow( AutoTypeImage image ) {
String name = image.getSingleBandName();
String typecast = image.getTypeCastFromSum();
String bitwise = image.getBitWise();
out.println("\t/**\n" +
"\t * Local equalization along a row. Image must be at least the histogram's width (2*r+1) in width and height.\n" +
"\t */\n" +
"\tpublic static void equalizeLocalRow( "+name+" input , int radius , int startY , "+name+" output ,\n" +
"\t\t\t\t\t\t\t\t\t\t int histogram[] , int transform[] ) {\n" +
"\n" +
"\t\tint width = 2*radius+1;\n" +
"\t\tint area = width*width;\n" +
"\t\tint maxValue = histogram.length-1;\n" +
"\n" +
"\t\t// specify the top and bottom of the histogram window and make sure it is inside bounds\n" +
"\t\tint hist0 = startY;\n" +
"\t\tint hist1 = startY+width;\n" +
"\t\tif( hist1 > input.height ) {\n" +
"\t\t\thist1 = input.height;\n" +
"\t\t\thist0 = hist1 - width;\n" +
"\t\t}\n" +
"\n" +
"\t\t// the upper and lower bounds of the region being equalized\n" +
"\t\tint region0 = startY;\n" +
"\t\tint region1 = startY+radius;\n" +
"\n" +
"\t\t// local histogram and transformation\n" +
"\t\tlocalHistogram(input,0,hist0,width,hist1,histogram);\n" +
"\n" +
"\t\tint sum = 0;\n" +
"\t\tfor( int i = 0; i < histogram.length; i++ ) {\n" +
"\t\t\ttransform[i] = sum += histogram[i];\n" +
"\t\t}\n" +
"\n" +
"\t\t// equalize the first square region\n" +
"\t\tfor( int y = region0; y < region1; y++ ) {\n" +
"\t\t\tint indexIn = input.startIndex + y*input.stride;\n" +
"\t\t\tint indexOut = output.startIndex + y*output.stride;\n" +
"\n" +
"\t\t\tfor( int x = 0; x <= radius; x++ ) {\n" +
"\t\t\t\tint inputValue = input.data[indexIn++] & 0xff;\n" +
"\t\t\t\toutput.data[indexOut++] = "+typecast+"((transform[ inputValue ]*maxValue)/area);\n" +
"\t\t\t}\n" +
"\t\t}\n" +
"\n" +
"\t\t// move right while equalizing the columns one at a time\n" +
"\t\tfor( int x = radius+1; x < input.width-radius-1; x++ ) {\n" +
"\n" +
"\t\t\t// remove the left most column\n" +
"\t\t\tint indexIn = input.startIndex + x-radius-1;\n" +
"\t\t\tfor( int y = hist0; y < hist1; y++ ) {\n" +
"\t\t\t\thistogram[input.data[indexIn + y*input.stride] "+bitwise+"]--;\n" +
"\t\t\t}\n" +
"\t\t\t// add the right most column\n" +
"\t\t\tindexIn += width;\n" +
"\t\t\tfor( int y = hist0; y < hist1; y++ ) {\n" +
"\t\t\t\thistogram[input.data[indexIn + y*input.stride] "+bitwise+"]++;\n" +
"\t\t\t}\n" +
"\n" +
"\t\t\t// compute transformation table\n" +
"\t\t\tsum = 0;\n" +
"\t\t\tfor( int i = 0; i < histogram.length; i++ ) {\n" +
"\t\t\t\ttransform[i] = sum += histogram[i];\n" +
"\t\t\t}\n" +
"\n" +
"\t\t\t// compute the output down the column\n" +
"\t\t\tindexIn = input.startIndex + region0*input.stride + x;\n" +
"\t\t\tint indexOut = output.startIndex + region0*output.stride + x;\n" +
"\t\t\tfor( int y = 0; y < radius; y++ ) {\n" +
"\t\t\t\tint inputValue = input.data[indexIn] & 0xff;\n" +
"\t\t\t\toutput.data[indexOut] = "+typecast+"((transform[ inputValue ]*maxValue)/area);\n" +
"\n" +
"\t\t\t\tindexIn += input.stride;\n" +
"\t\t\t\tindexOut += output.stride;\n" +
"\t\t\t}\n" +
"\t\t}\n" +
"\n" +
"\t\t// equalize the final square region\n" +
"\t\tlocalHistogram(input,input.width-width,hist0,input.width,hist1,histogram);\n" +
"\n" +
"\t\tsum = 0;\n" +
"\t\tfor( int i = 0; i < histogram.length; i++ ) {\n" +
"\t\t\ttransform[i] = sum += histogram[i];\n" +
"\t\t}\n" +
"\n" +
"\t\tfor( int y = region0; y < region1; y++ ) {\n" +
"\t\t\tint x = input.width-radius-1;\n" +
"\n" +
"\t\t\tint indexIn = input.startIndex + y*input.stride + x;\n" +
"\t\t\tint indexOut = output.startIndex + y*output.stride + x;\n" +
"\n" +
"\t\t\tfor( ; x < input.width; x++ ) {\n" +
"\t\t\t\tint inputValue = input.data[indexIn++] & 0xff;\n" +
"\t\t\t\toutput.data[indexOut++] = "+typecast+"((transform[ inputValue ]*maxValue)/area);\n" +
"\t\t\t}\n" +
"\t\t}\n" +
"\t}\n\n");
}
private void equalizeLocalCol( AutoTypeImage image ) {
String name = image.getSingleBandName();
String typecast = image.getTypeCastFromSum();
String bitwise = image.getBitWise();
out.print("\t/**\n" +
"\t * Local equalization along a column. Image must be at least the histogram's width (2*r+1) in width and height.\n" +
"\t */\n" +
"\tpublic static void equalizeLocalCol( "+name+" input , int radius , int startX , "+name+" output ,\n" +
"\t\t\t\t\t\t\t\t\t\t int histogram[] , int transform[] ) {\n" +
"\n" +
"\t\tint width = 2*radius+1;\n" +
"\t\tint area = width*width;\n" +
"\t\tint maxValue = histogram.length-1;\n" +
"\n" +
"\t\t// specify the top and bottom of the histogram window and make sure it is inside bounds\n" +
"\t\tint hist0 = startX;\n" +
"\t\tint hist1 = startX+width;\n" +
"\t\tif( hist1 > input.width ) {\n" +
"\t\t\thist1 = input.width;\n" +
"\t\t\thist0 = hist1 - width;\n" +
"\t\t}\n" +
"\n" +
"\t\t// initialize the histogram. ignore top border\n" +
"\t\tlocalHistogram(input,hist0,0,hist1,width,histogram);\n" +
"\n" +
"\t\t// compute transformation table\n" +
"\t\tint sum = 0;\n" +
"\t\tfor( int i = 0; i < histogram.length; i++ ) {\n" +
"\t\t\ttransform[i] = sum += histogram[i];\n" +
"\t\t}\n" +
"\n" +
"\t\t// compute the output across the row\n" +
"\t\tint indexIn = input.startIndex + radius*input.stride + startX;\n" +
"\t\tint indexOut = output.startIndex + radius*output.stride + startX;\n" +
"\t\tfor( int x = 0; x < radius; x++ ) {\n" +
"\t\t\tint inputValue = input.data[indexIn++] & 0xff;\n" +
"\t\t\toutput.data[indexOut++] = "+typecast+"((transform[ inputValue ]*maxValue)/area);\n" +
"\t\t}\n" +
"\n" +
"\t\t// move down while equalizing the rows one at a time\n" +
"\t\tfor( int y = radius+1; y < input.height-radius; y++ ) {\n" +
"\n" +
"\t\t\t// remove the top most row\n" +
"\t\t\tindexIn = input.startIndex + (y-radius-1)*input.stride;\n" +
"\t\t\tfor( int x = hist0; x < hist1; x++ ) {\n" +
"\t\t\t\thistogram[input.data[indexIn + x] "+bitwise+"]--;\n" +
"\t\t\t}\n" +
"\t\t\t// add the bottom most row\n" +
"\t\t\tindexIn += width*input.stride;\n" +
"\t\t\tfor( int x = hist0; x < hist1; x++ ) {\n" +
"\t\t\t\thistogram[input.data[indexIn + x] "+bitwise+"]++;\n" +
"\t\t\t}\n" +
"\n" +
"\t\t\t// compute transformation table\n" +
"\t\t\tsum = 0;\n" +
"\t\t\tfor( int i = 0; i < histogram.length; i++ ) {\n" +
"\t\t\t\ttransform[i] = sum += histogram[i];\n" +
"\t\t\t}\n" +
"\n" +
"\t\t\t// compute the output across the row\n" +
"\t\t\tindexIn = input.startIndex + y*input.stride + startX;\n" +
"\t\t\tindexOut = output.startIndex + y*output.stride + startX;\n" +
"\t\t\tfor( int x = 0; x < radius; x++ ) {\n" +
"\t\t\t\tint inputValue = input.data[indexIn++] & 0xff;\n" +
"\t\t\t\toutput.data[indexOut++] = "+typecast+"((transform[ inputValue ]*maxValue)/area);\n" +
"\t\t\t}\n" +
"\t\t}\n" +
"\t}\n\n");
}
private void localHistogram( AutoTypeImage image ) {
String name = image.getSingleBandName();
String bitwise = image.getBitWise();
out.print("\t/**\n" +
"\t * Computes the local histogram just for the specified inner region\n" +
"\t */\n" +
"\tpublic static void localHistogram( "+name+" input , int x0 , int y0 , int x1, int y1 , int histogram[] ) {\n" +
"\t\tfor( int i = 0; i < histogram.length; i++ )\n" +
"\t\t\thistogram[i] = 0;\n" +
"\n" +
"\t\tfor( int i = y0; i < y1; i++ ) {\n" +
"\t\t\tint index = input.startIndex + i*input.stride + x0;\n" +
"\t\t\tint end = index + x1-x0;\n" +
"\t\t\tfor( ; index < end; index++ ) {\n" +
"\t\t\t\thistogram[input.data[index] "+bitwise+"]++;\n" +
"\t\t\t}\n" +
"\t\t}\n" +
"\t}\n\n");
}
public static void main( String args[] ) throws FileNotFoundException {
GenerateImplEnhanceHistogram app = new GenerateImplEnhanceHistogram();
app.generate();
}
}