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).
*/