1 /* 2 * $RCSfile: MatchCDFCRIF.java,v $ 3 * 4 * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved. 5 * 6 * Use is subject to license terms. 7 * 8 * $Revision: 1.1 $ 9 * $Date: 2005/02/11 04:56:31 $ 10 * $State: Exp $ 11 */ 12 package com.lightcrafts.media.jai.opimage; 13 import java.awt.RenderingHints; 14 import java.awt.image.RenderedImage; 15 import java.awt.image.renderable.ParameterBlock; 16 import com.lightcrafts.mediax.jai.CRIFImpl; 17 import com.lightcrafts.mediax.jai.Histogram; 18 import com.lightcrafts.mediax.jai.ImageLayout; 19 20 /** 21 * A <code>CRIF</code> supporting the "MatchCDF" operation in the rendered 22 * and renderable image layers. 23 * 24 * @see com.lightcrafts.mediax.jai.operator.MatchCDFDescriptor 25 * @see com.lightcrafts.mediax.jai.operator.PiecewiseDescriptor 26 * @see PiecewiseOpImage 27 * 28 * 29 * @since EA4 30 */ 31 public class MatchCDFCRIF extends CRIFImpl { 32 /* 33 * Creates a piecewise mapping from an image with cumulative distribution 34 * function of pixel values CDFin to another given by CDFout. 35 */ createHistogramMap(float[] CDFin, float[] CDFout, double lowValue, double binWidth, int numBins, float[] abscissa, float[] ordinate)36 private static void createHistogramMap(float[] CDFin, float[] CDFout, 37 double lowValue, double binWidth, 38 int numBins, 39 float[] abscissa, 40 float[] ordinate) { 41 // Initialize the first abscissa and the output CDF index. 42 double x = lowValue; 43 int j = 0; 44 int jMax = numBins - 1; 45 46 // Generate one breakpoint for each bin. 47 for(int i = 0; i < numBins; i++) { 48 // Find the first output bin such that the output CDF is 49 // greater than or equal to the input CDF at the current bin. 50 float w = CDFin[i]; 51 while(CDFout[j] < w && j < jMax) j++; 52 53 // Set the breakpoint values. 54 abscissa[i] = (float)x; 55 ordinate[i] = (float)(j*binWidth); 56 57 // Increment the abscissa. 58 x += binWidth; 59 } 60 } 61 62 /** 63 * Create a set of breakpoints which will map the input histogram to 64 * an output histogram with the specified cumulative distribution function. 65 * 66 * @param histIn The input histogram. 67 * @param CDFOut The output CDF. 68 * @return A piecewise transform which will modify the input histogram 69 * to match the output CDF. 70 */ createSpecificationMap(Histogram histIn, float[][] CDFOut)71 private static float[][][] createSpecificationMap(Histogram histIn, 72 float[][] CDFOut) { 73 // Allocate the overall breakpoint array. 74 int numBands = histIn.getNumBands(); 75 float[][][] bp = new float[numBands][][]; 76 77 // Calculate a different set of breakpoints for each band. 78 float[] CDFin = null; 79 for(int band = 0; band < numBands; band++) { 80 // Allocate memory for the breakpoints for this band. 81 int numBins = histIn.getNumBins(band); 82 bp[band] = new float[2][]; 83 bp[band][0] = new float[numBins]; 84 bp[band][1] = new float[numBins]; 85 86 // Calculate the total count over all bins of this band. 87 int[] binsIn = histIn.getBins(band); 88 long binTotalIn = binsIn[0]; 89 for(int i = 1; i < numBins; i++) { 90 binTotalIn += binsIn[i]; 91 } 92 93 // Allocate memory for the CDF for this band only if needed. 94 if(CDFin == null || CDFin.length < numBins) { 95 CDFin = new float[numBins]; 96 } 97 98 // Calculate the Cumulative Distribution Function (CDF) for the 99 // input histogram for this band. 100 CDFin[0] = (float)binsIn[0]/binTotalIn; 101 for(int i = 1; i < numBins; i++) { 102 CDFin[i] = CDFin[i-1] + (float)binsIn[i]/binTotalIn; 103 } 104 105 // Calculate the mapping function. 106 double binWidth = 107 (histIn.getHighValue(band) - histIn.getLowValue(band))/numBins; 108 createHistogramMap(CDFin, 109 CDFOut.length > 1 ? CDFOut[band] : CDFOut[0], 110 histIn.getLowValue(band), 111 binWidth, numBins, bp[band][0], bp[band][1]); 112 } 113 114 return bp; 115 } 116 117 /** Constructor. */ MatchCDFCRIF()118 public MatchCDFCRIF() { 119 super("matchcdf"); 120 } 121 122 /** 123 * Creates a new instance of <code>PiecewiseOpImage</code> in the 124 * rendered layer. 125 * 126 * @param args The source image and the breakpoints. 127 * @param hints Optionally contains destination image layout. 128 */ create(ParameterBlock args, RenderingHints renderHints)129 public RenderedImage create(ParameterBlock args, 130 RenderingHints renderHints) { 131 // Get ImageLayout from renderHints if any. 132 ImageLayout layout = RIFUtil.getImageLayoutHint(renderHints); 133 134 135 // Derive breakpoints from the histogram and specified CDF. 136 RenderedImage src = args.getRenderedSource(0); 137 Histogram hist = (Histogram)src.getProperty("histogram"); 138 float[][] CDF = (float[][])args.getObjectParameter(0); 139 float[][][] bp = createSpecificationMap(hist, CDF); 140 141 return new PiecewiseOpImage(src, renderHints, layout, bp); 142 } 143 } 144