import ij.*; import ij.plugin.filter.PlugInFilter; import ij.process.*; import ij.gui.*; import java.awt.*; import java.util.*; /* This file contains a Java language implementation of the Fast Hartley Transform algorithm which is covered under United States Patent Number 4,646,256. This code may therefore be freely used and distributed only under the following conditions: 1) This header is included in every copy of the code; and 2) The code is used for noncommercial research purposes only. Firms using this code for commercial purposes may be infringing a United States patent and should contact the Office of Technology Licensing Stanford University 857 Serra Street, 2nd Floor Stanford, CA 94305-6225 (415) 723 0651 This implementation is based on Pascal code contibuted by Arlo Reeves. */ /** Fast Hartley Transform. */ public class FFT_ implements PlugInFilter { private ImagePlus imp; private float[] C; private float[] S; //private float[] fht; public int setup(String arg, ImagePlus imp) { this.imp = imp; return DOES_8G+ DOES_16+ DOES_32+NO_CHANGES; } public void run(ImageProcessor ip) { boolean inverse; if (!powerOf2Size(ip)) { IJ.error("A square, power of two size image or selection\n(128x128, 256x256, etc.) is required."); return; } ImageProcessor fht = (ImageProcessor)imp.getProperty("FHT"); if (fht!=null) { ip = fht; inverse = true; } else inverse = false; ImageProcessor ip2 = ip.crop(); if (!(ip2 instanceof FloatProcessor)) { ImagePlus imp2 = new ImagePlus("", ip2); new ImageConverter(imp2).convertToGray32(); ip2 = imp2.getProcessor(); } fft(ip2, inverse); } public boolean powerOf2Size(ImageProcessor ip) { Rectangle r = ip.getRoi(); return powerOf2(r.width) && r.width==r.height; } boolean powerOf2(int n) { int i=2; while(i 2) { // third + stages computed here gpSize = 4; numBfs = 2; numGps = numGps / 2; //IJ.write("FFT: dfht3 "+Nlog2+" "+numGps+" "+numBfs); for (stage=2; stage 2 */ if (inverse) { for (i=0; imax) max = r; } } if (min<1.0) min = 0f; else min = (float)Math.log(min); max = (float)Math.log(max); scale = (float)(253.0/(max-min)); for (int row=0; row 0; if passMode then ChangeValues(0,254,0) else ChangeValues(1,255,255); for i := 1 to 3 do Filter(UnweightedAvg, 0, t); UpdatePicWindow; ApplyFilter(rData); end; procedure doFFT(fftKind: fftType); var startTicks, maxN: LongInt; trect: rect; RealData: rImagePtr; doInverse: boolean; begin doInverse := fftKind <> ForewardFFT; if not PowerOf2Size then exit(doFFT); startTicks := tickCount; if info^.DataH = nil then begin if doInverse then begin PutError('A real image is required to do an inverse transform.'); AbortMacro; exit(doFFT); end; if not MakeRealImage then begin AbortMacro; exit(doFFT); end end else begin KillRoi; SetFFTWindowName(doInverse); end; hlock(info^.DataH); RealData := rImagePtr(info^.DataH^); ShowWatch; maxN := info^.PixelsPerLine; if not MakeSinCosTables(maxN) then exit(doFFT); AbortFFT := false; ShowMessage(CmdPeriodToStop); if doInverse then begin if fftKind = InverseFFTWithMask then doMasking(RealData) else if fftKind = InverseFFTWithFilter then ApplyFilter(RealData); rc2DFHT(RealData, true, maxN); if not AbortFFT then DisplayRealImage(RealData); end else begin rc2DFHT(RealData, false, maxN); if not AbortFFT then DisplayPowerSpectrum(RealData); end; if AbortFFT then UpdateMeter(-1, 'Hide'); hunlock(info^.dataH); UpdatePicWindow; SetRect(trect, 0, 0, maxN, maxN); ShowTime(startTicks, trect, ''); UpdateWindowsMenuItem; DisposePtr(ptr(C)); DisposePtr(ptr(S)); end; procedure RedisplayPowerSpectrum; var rData: rImagePtr; begin if info = noInfo then exit(RedisplayPowerSpectrum); KillRoi; if not PowerOf2Size then exit(RedisplayPowerSpectrum); if not isFFT then begin PutError('Real frequency domain image required.'); exit(RedisplayPowerSpectrum); end; hlock(info^.DataH); rData := rImagePtr(info^.DataH^); DisplayPowerSpectrum(rData); hunlock(info^.dataH); UpdatePicWindow; end; function arctan2 (x, y: extended): extended; { returns angle in the correct quadrant } begin if x = 0 then x := 1E-30; { Could be improved } if x > 0 then if y >= 0 then arctan2 := arctan(y / x) else arctan2 := arctan(y / x) + 2 * pi else arctan2 := arctan(y / x) + pi; end; procedure ShowFFTValues (hloc, vloc, ivalue: LongInt); var tPort: GrafPtr; hstart, vstart: integer; r, theta, center: extended; begin with info^ do begin hstart := InfoHStart; vstart := InfoVStart; GetPort(tPort); SetPort(InfoWindow); TextSize(9); TextFont(Monaco); TextMode(SrcCopy); if hloc < 0 then hloc := -hloc; center := pixelsPerLine div 2; r := sqrt(sqr(hloc - center) + sqr(vloc - center)); theta := arctan2(hloc - center, center - vloc); theta := theta * 180 / pi; MoveTo(xValueLoc, vstart); if SpatiallyCalibrated then begin DrawReal(pixelsPerLine / r / xScale, 6, 2); DrawString(xUnit); DrawString('/c '); DrawString('('); DrawReal(hloc - center, 4, 0); DrawString(')'); end else begin DrawReal(pixelsPerLine / r, 6, 2); DrawString('p/c '); DrawString('('); DrawReal(hloc - center, 4, 0); DrawString(')'); end; DrawString(' '); vloc := PicRect.bottom - vloc - 1; if vloc < 0 then vloc := -vloc; MoveTo(yValueLoc, vstart + 10); DrawReal(theta, 6, 2); TextMode(srcOr); DrawString('ç '); TextMode(srcCopy); DrawString('('); DrawReal(vloc - center + 1, 4, 0); DrawString(')'); DrawString(' '); MoveTo(zValueLoc, vstart + 20); if fit <> uncalibrated then begin DrawReal(cvalue[ivalue], 6, 2); DrawString(' ('); DrawLong(ivalue); DrawString(')'); end else DrawLong(ivalue); DrawString(' '); SetPort(tPort); end; end; end. {fft Unit} */