content: package edu.stanford.rsl.conrad.utils;
  
  import ij.process.FHT;
  import ij.process.FloatProcessor;
  import ij.process.ImageProcessor;
  
  
  /**
   * This class is currently unused as all transforms in OSCAR are now based on JTransforms
   * However some of these methods may come in handy when dealing with the ImageJ implementation of
   * the FHT.
   * 
   * Many of the methods are very similar to the ones in ij/plugin/FFT.java. If code was partially
   * taken from there this is declared in the comment before the method.
   * 
   * @author Andreas Maier
   *
   */
  public abstract class FHTUtil {
  	/**
  	 * Image is padded with 0. Code was partially taken from ij.plugin.FFT.java::pad(). 
  	 * 
  	 * Thanks for the inspiration!
  	 * 
  	 * @param ip the ImageProcessor to be padded.
  	 * @return the padded ImageProcessor.
  	 */
  	public static ImageProcessor padImageProcessor(ImageProcessor ip, int maxN) {
  		ImageProcessor ip2 = ip.createProcessor(maxN, maxN);
  		ip2.setValue(0);
  		ip2.fill();
  		ip2.insert(ip, 0, 0);
  		return ip2;
  	}
  
  	/**
  	 * Image is padded with 0. Size of padding is automatically determined. This means a slight increase in computation time. 
  	 * 
  	 * Code was partially taken from ij.plugin.FFT.java::pad().
  	 * Thanks for the inspiration!
  	 * 
  	 * @param ip the ImageProcessor to be padded.
  	 * @return the padded ImageProcessor.
  	 * 
  	 */
  	public static ImageProcessor padImageProcessor(ImageProcessor ip) {
  		int maxN = FFTUtil.getNextPowerOfTwo(Math.max(ip.getWidth(), ip.getHeight()));
  		ImageProcessor ip2 = ip.createProcessor(maxN, maxN);
  		ip2.setValue(0);
  		ip2.fill();
  		ip2.insert(ip, 0, 0);
  		return ip2;
  	}
  
  	/**
  	 * Converts real and imaginary parts of an FFT to Hartley domain.
  	 * @param real FloatProcessor with the real values
  	 * @param imag FloatProcessor with the imaginary values
  	 * @return the values in Hartley Domain
  	 * 
  	 */
  	public static FHT complexToFHT(FloatProcessor real, FloatProcessor imag){
  		FHT fht = new FHT(new FloatProcessor(real.getWidth(),real.getHeight()));
  		float [] fhtPixels = (float[]) fht.getPixels();
  		float [] imagPixels = (float[]) imag.getPixels();
  		float [] realPixels = (float[]) real.getPixels();
  		for(int j=0; j<fht.getHeight();j++){
  			cplxFHT(j,fht.getWidth(), realPixels, imagPixels, false, fhtPixels);
  		}
  		fht.swapQuadrants();
  		return fht;
  	}
  
  	/** Build FHT input for equivalent FFT input
  	 *   @author Joachim Wesner
  	 */
  	private static void cplxFHT(int row, int maxN, float[] re, float[] im, boolean reim, float[] fht) {
  		int base = row*maxN;
  		int offs = ((maxN-row)%maxN) * maxN;
  		if (!reim) {
  			for (int c=0; c<maxN; c++) {
  				int l =  offs + (maxN-c)%maxN;
  				fht[base+c] = ((re[base+c]+re[l]) - (im[base+c]-im[l]))*0.5f;
  			}
  		} else {
  			for (int c=0; c<maxN; c++) {
  				int l = offs + (maxN-c)%maxN;
  				fht[base+c] = ((im[base+c]+im[l]) + (re[base+c]-re[l]))*0.5f;
  			}
  		}
  	}
  
  	/**	 FFT real value of one row from 2D Hartley Transform.
  	 *	@author Joachim Wesner
  	 */
  	private static void FHTreal(int row, int maxN, float[] fht, float[] real) {
  		int base = row*maxN;
  		int offs = ((maxN-row)%maxN) * maxN;
  		for (int c=0; c<maxN; c++) {
  			real[base+c] = (fht[base+c] + fht[offs+((maxN-c)%maxN)])*0.5f;
  		}
  	}
  
  
  	/** FFT imag value of one row from 2D Hartley Transform.
  	 *	@author Joachim Wesner
  	 */
  	private static void FHTimag(int row, int maxN, float[] fht, float[] imag) {
  		int base = row*maxN;
  		int offs = ((maxN-row)%maxN) * maxN;
  		for (int c=0; c<maxN; c++) {
  			imag[base+c] = (-fht[base+c] + fht[offs+((maxN-c)%maxN)])*0.5f;
  		}
  	}
  
  	/**
  	 * Computes the imaginary values of an FFT given the values of an FHT.
  	 * 
  	 * @param fht the FHT as input
  	 * @return the imaginary values as FloatProcessor. Use .log() if you want an improved visualization of the result.
  	 */
  	public static FloatProcessor imaginaryFromFHT(FHT fht){
  		FHT img = new FHT(new FloatProcessor(fht.getWidth(),fht.getHeight()));
  		float [] fhtPixels = (float[]) fht.getPixels();
  		float [] imagPixels = (float[]) img.getPixels();
  		for(int j=0; j<fht.getHeight();j++){
  			FHTimag(j,fht.getWidth(), fhtPixels, imagPixels);
  		}
  		img.swapQuadrants();
  		return img;
  	}
  
  	/**
  	 * Computes the real values of an FFT given the values of an FHT.
  	 * 
  	 * @param fht the FHT as input
  	 * @return the real values as FloatProcessor. Use .log() if you want an improved visualization of the result.
  	 * 
  	 */
  	public static FloatProcessor realFromFHT(FHT fht){
  		FHT img = new FHT(new FloatProcessor(fht.getWidth(),fht.getHeight()));
  		float [] fhtPixels = (float[]) fht.getPixels();
  		float [] realPixels = (float[]) img.getPixels();
  		for(int j=0; j<fht.getHeight();j++){
  			FHTreal(j,fht.getWidth(), fhtPixels, realPixels);
  		}
  		img.swapQuadrants();
  		return img;
  	}
  
  	/**
  	 * Computes the power spectrum of an FFT given the values of an FHT.
  	 * 
  	 * @param fht the FHT as input
  	 * @return the power spectrum as FloatProcessor. Use .log() if you want an improved visualization of the result.
  	 * 
  	 */
  	public static ImageProcessor powerFromFHT(FHT fht){
  		ImageProcessor imag = imaginaryFromFHT(fht);
  		ImageProcessor real = realFromFHT(fht);
  		ImageProcessor power = new FloatProcessor(fht.getWidth(),fht.getHeight());
  		float [] realPixels = (float[]) real.getPixels();
  		float [] imagPixels = (float[]) imag.getPixels();
  		float [] powerPixels = (float []) power.getPixels();
  		for(int j=0; j<(fht.getHeight()*fht.getWidth());j++){
  			double value = Math.sqrt(Math.pow(imagPixels[j], 2) + Math.pow(realPixels[j], 2));
  			powerPixels[j] = (float) value;
  		}
  		return power;
  	}
  
  }
  /*
   * Copyright (C) 2010-2014  Andreas Maier
   * CONRAD is developed as an Open Source project under the GNU General Public License (GPL).
  */