home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 4 / Apprentice-Release4.iso / Source Code / Pascal / Applications / NIH Image 1.59 / 1.59 Source / fft.p < prev    next >
Encoding:
Text File  |  1995-10-10  |  16.8 KB  |  714 lines  |  [TEXT/MPPS]

  1. unit fft;
  2.  
  3. {
  4. This file contains a Pascal language implementation of the 
  5. Fast Hartley Transform algorithm which is covered under
  6. United States Patent Number 4,646,256.
  7.  
  8. This code may therefore be freely used and distributed only
  9. under the following conditions:
  10.  
  11.         1)  This header is included in every copy of the code; and
  12.         2)  The code is used for noncommercial research purposes only.
  13.  
  14.  Firms using this code for commercial purposes will be infringing a United
  15.  States patent and should contact the
  16.  
  17.                     Office of Technology Licensing
  18.                     Stanford University
  19.                     857 Serra Street, 2nd Floor
  20.                     Stanford, CA   94305-6225
  21.                     (415) 723 0651
  22.  
  23. This implementation is based on Pascal code contibuted
  24. by Arlo Reeves (arlo@apple.com).
  25. }
  26.  
  27. interface
  28.     uses
  29.         Memory, QuickDraw, Packages, Menus, Events, Fonts, ToolUtils, globals, Utilities, Graphics, Filters, Analysis;
  30.  
  31.     procedure doFFT(fftKind: fftType);
  32.     procedure DisplayPowerSpectrum(x: rImagePtr);
  33.     function   isPowerOf2 (x: LongInt): boolean;
  34.     procedure SetFFTWindowName(doInverse: boolean);
  35.     procedure RedisplayPowerSpectrum;
  36.     procedure doSwapQuadrants;
  37.  
  38.  
  39. implementation
  40.  
  41.     const
  42.         UpdateTicks = 10; {Show progress 6 times/sec}
  43.         
  44.     var
  45.         AbortFFT: boolean;
  46.         C, S: rLinePtr;
  47.  
  48.  
  49.     function log2 (x: LongInt): LongInt;
  50.         var
  51.             count: LongInt;
  52.     begin
  53.         count := 15;
  54.         while not BTST(x, count) do
  55.             count := count - 1;
  56.         log2 := count;
  57.     end;
  58.     
  59.  
  60.     function BitRevX (x, bitlen: LongInt): LongInt;
  61.         var
  62.             i: LongInt;
  63.             temp: longint;
  64.     begin
  65.         temp := 0;
  66.         for i := 0 to bitlen do
  67.             if BTST(x, i) then
  68.                 BSET(temp, bitlen - i - 1);
  69.         BitRevX := LoWord(temp);
  70.     end;
  71.     
  72.  
  73.     procedure BitRevRArr (x: rLinePtr; bitlen, maxN: LongInt);
  74.         var
  75.             i: LongInt;
  76.             tempArr: rLineType;
  77.     begin
  78.         for i := 0 to maxN - 1 do
  79.             tempArr[i] := x^[BitRevX(i, bitlen)];
  80.         BlockMove(@tempArr, x, maxN * SizeOf(real));
  81.     end;
  82.     
  83.  
  84.     procedure transposeR (x: rImagePtr; maxN: LongInt);
  85.         var
  86.             r, c: LongInt;
  87.             rTemp: real;
  88.     begin
  89.         for r := 0 to maxN - 1 do
  90.             for c := r to maxN - 1 do
  91.                 if r <> c then
  92.                     begin
  93.                         rTemp := x^[ r * maxN + c];
  94.                         x^[ r * maxN + c] := x^[c * maxN + r];
  95.                         x^[c * maxN + r] := rTemp;
  96.                     end;
  97.     end;
  98.     
  99.  
  100.     procedure FHTps (r, maxN: LongInt; inMat: rImagePtr;  var outArr: rLineType);
  101. { Power Spectrum of one row from 2D Hartley Transform }
  102.         var
  103.             c, base: LongInt;
  104.     begin
  105.         base := r * maxN;
  106.         for c := 0 to maxN - 1 do
  107.             outArr[c] := (sqr(inMat^[base + c]) + sqr(inMat^[((maxN - r) mod maxN) * maxN + (maxN - c) mod maxN])) / 2;
  108.     end;
  109.  
  110.  
  111.     procedure dfht3 (x: rLinePtr; inverse: boolean; maxN: LongInt);
  112.     { an optimized real FHT }
  113.         var
  114.             i, stage, gpNum, gpIndex, gpSize, numGps, Nlog2: LongInt;
  115.             bfNum, numBfs: LongInt;
  116.             Ad0, Ad1, Ad2, Ad3, Ad4, CSAd: LongInt;
  117.             rt1, rt2, rt3, rt4: real;
  118.     begin
  119.         Nlog2 := log2(maxN);
  120.         BitRevRArr(x, Nlog2, maxN);            { bitReverse the input array }
  121.  
  122.         gpSize := 2;                        { first & second stages - do radix 4 butterflies once thru }
  123.         numGps := maxN div 4;
  124.         for gpNum := 0 to numGps - 1 do
  125.             begin
  126.                 Ad1 := gpNum * 4;
  127.                 Ad2 := Ad1 + 1;
  128.                 Ad3 := Ad1 + gpSize;
  129.                 Ad4 := Ad2 + gpSize;
  130.                 rt1 := x^[Ad1] + x^[Ad2];            { a + b }
  131.                 rt2 := x^[Ad1] - x^[Ad2];            { a - b }
  132.                 rt3 := x^[Ad3] + x^[Ad4];            { c + d }
  133.                 rt4 := x^[Ad3] - x^[Ad4];            { c - d }
  134.                 x^[Ad1] := rt1 + rt3;                { a + b + (c + d ) }
  135.                 x^[Ad2] := rt2 + rt4;                { a - b + (c - d ) }
  136.                 x^[Ad3] := rt1 - rt3;                { a + b - (c + d ) }
  137.                 x^[Ad4] := rt2 - rt4;                { a - b - (c - d ) }
  138.             end;
  139.  
  140.         if Nlog2 > 2 then
  141.             begin                        { third + stages computed here }
  142.                 gpSize := 4;
  143.                 numBfs := 2;
  144.                 numGps := numGps div 2;
  145.                 for stage := 2 to Nlog2 - 1 do
  146.                     begin
  147.                         for gpNum := 0 to numGps - 1 do
  148.                             begin
  149.                                 Ad0 := gpNum * gpSize * 2;
  150.                                 Ad1 := Ad0;                            { 1st butterfly is different from others - no mults needed }
  151.                                 Ad2 := Ad1 + gpSize;
  152.                                 Ad3 := Ad1 + gpSize div 2;
  153.                                 Ad4 := Ad3 + gpSize;
  154.                                 rt1 := x^[Ad1];
  155.                                 x^[Ad1] := x^[Ad1] + x^[Ad2];
  156.                                 x^[Ad2] := rt1 - x^[Ad2];
  157.                                 rt1 := x^[Ad3];
  158.                                 x^[Ad3] := x^[Ad3] + x^[Ad4];
  159.                                 x^[Ad4] := rt1 - x^[Ad4];
  160.                                 for bfNum := 1 to numBfs - 1 do
  161.                                     begin        { subsequent BF's dealt with together }
  162.                                         Ad1 := bfNum + Ad0;
  163.                                         Ad2 := Ad1 + gpSize;
  164.                                         Ad3 := gpSize - bfNum + Ad0;
  165.                                         Ad4 := Ad3 + gpSize;
  166.  
  167.                                         CSAd := bfNum * numGps;
  168.                                         rt1 := x^[Ad2] * C^[CSAd] + x^[Ad4] * S^[CSAd];
  169.                                         rt2 := x^[Ad4] * C^[CSAd] - x^[Ad2] * S^[CSAd];
  170.  
  171.                                         x^[Ad2] := x^[Ad1] - rt1;
  172.                                         x^[Ad1] := x^[Ad1] + rt1;
  173.                                         x^[Ad4] := x^[Ad3] + rt2;
  174.                                         x^[Ad3] := x^[Ad3] - rt2;
  175.  
  176.                                     end;         { for bfNum := 0 to ... }
  177.                             end;            { for gpNum := 0 to ... }
  178.                         gpSize := gpSize * 2;
  179.                         numBfs := numBfs * 2;
  180.                         numGps := numGps div 2;
  181.                     end;
  182.             end;        { if }
  183.  
  184.         if inverse then
  185.             for i := 0 to maxN - 1 do
  186.                 x^[i] := x^[i] / maxN;
  187.     end;
  188.  
  189.  
  190.     procedure rc2Dfht (x: rImagePtr; inverse: boolean; maxN: LongInt);
  191. { Row-column 2D FHT }
  192.         var
  193.             row, col, mRow, mCol, NextTicks: LongInt;
  194.             A, B, C, D, E: real;
  195.             theRow: rLinePtr;
  196.     begin
  197.         NextTicks := TickCount + UpdateTicks;
  198.         for row := 0 to maxN - 1 do begin
  199.             theRow := rLinePtr(ord4(x) + row * maxN * SizeOf(real));
  200.             dfht3(theRow, inverse, maxN);
  201.             if TickCount > nextTicks then begin
  202.                 UpdateMeter(round(row/maxN * 50.0), 'Computing FHT');
  203.                 nextTicks := TickCount + updateTicks;
  204.                 if CommandPeriod then begin
  205.                         beep;
  206.                         AbortFFT := true;
  207.                         exit(rc2Dfht)
  208.                     end;
  209.             end;
  210.         end;
  211.         transposeR(x, maxN);
  212.         for row := 0 to maxN - 1 do begin
  213.             theRow := rLinePtr(ord4(x) + row * maxN * SizeOf(real));
  214.             dfht3(theRow, inverse, maxN);
  215.             if TickCount > nextTicks then begin
  216.                 UpdateMeter(round(row/maxN * 50.0) + 50, 'Computing FHT');
  217.                 nextTicks := TickCount + updateTicks;
  218.                 if CommandPeriod then begin
  219.                         beep;
  220.                         AbortFFT := true;
  221.                         exit(rc2Dfht)
  222.                     end;
  223.             end;
  224.         end;
  225.         transposeR(x, maxN);
  226.         for row := 0 to maxN div 2 do             { Now calculate actual Hartley transform }
  227.             for col := 0 to maxN div 2 do
  228.                 begin
  229.                     mRow := (maxN - row) mod maxN;
  230.                     mCol := (maxN - col) mod maxN;
  231.                     A := x^[row * maxN + col];                        { see Bracewell, 'Fast 2D Hartley Transf.' IEEE Procs. 9/86 }
  232.                     B := x^[mRow * maxN + col];
  233.                     C := x^[row * maxN + mCol];
  234.                     D := x^[mRow * maxN + mCol];
  235.                     E := ((A + D) - (B + C)) / 2;
  236.                     x^[row * maxN + col] := A - E;
  237.                     x^[mRow * maxN + col] := B + E;
  238.                     x^[row * maxN + mCol] := C + E;
  239.                     x^[mRow * maxN + mCol] := D - E;
  240.                 end;
  241.         UpdateMeter(-1, 'Hide Meter');
  242.     end;
  243.     
  244.     
  245. procedure SwapQuadrants;
  246. {Swap quadrants 1 and 3 and quadrants 2 and 4 so the}
  247. {power spectrum origin is at the center of the image.}
  248. {2 1}
  249. {3 4}
  250. var
  251.     row, col, halfMaxN, tmp, maxN: LongInt;
  252.     line1, line2: LineType;
  253. begin
  254.     maxN := info^.PixelsPerLine;
  255.     halfMaxN := maxN div 2;
  256.     for row:= 0 to halfMaxN -1 do begin
  257.         GetLine(0, row, maxN, line1);
  258.         GetLine(0, row + halfMaxN, maxN, line2);
  259.         for col := 0 to halfMaxN -1 do begin
  260.             tmp := line1[col];
  261.             line1[col] := line1[col + halfMaxN];
  262.             line1[col + halfMaxN] := tmp;
  263.             tmp := line2[col];
  264.             line2[col] := line2[col + halfMaxN];
  265.             line2[col + halfMaxN] := tmp;
  266.         end;
  267.         PutLine(0, row, maxN, line2);
  268.         PutLine(0, row + halfMaxN, maxN, line1);
  269.     end;
  270. end;
  271.  
  272.  
  273.     
  274.     procedure DisplayRealImage(x: rImagePtr);
  275.         var
  276.             row, col, i, base, maxN: LongInt;
  277.             r, min, max, scale: real;
  278.             line: lineType;
  279.     begin
  280.         maxN := info^.PixelsPerLine;
  281.         min := 1e99;
  282.         max := -1e99;
  283.         i := 1;
  284.         for row := 0 to maxN - 1 do begin
  285.             base := row * maxN;
  286.             for col := 0 to maxN - 1 do begin
  287.                     r := x^[base + col];
  288.                     if r < min then min := r;
  289.                     if r > max then max := r;
  290.             end;
  291.         end;
  292.         scale := 253.0 / (max - min);
  293.         for row := 0 to maxN - 1 do begin
  294.                 base := row * maxN;
  295.                 for col := 0 to maxN - 1 do begin
  296.                         r := x^[base + col];
  297.                         line[col] := round((r - min) * scale) + 1;
  298.                 end;
  299.                 PutLine(0, row, maxN, line);
  300.             end;
  301.     end;
  302.  
  303.  
  304.     procedure DisplayPSUsingBuffer(fht, ps: rImagePtr; var rLine: rLineType);
  305.     var
  306.         row, col, base, nextTicks, maxN: LongInt;
  307.         r, min, max, scale: real;
  308.         line: lineType;
  309.         
  310.     begin
  311.         maxN := info^.PixelsPerLine;
  312.         nextTicks := TickCount + updateTicks;
  313.         min := 1e99;
  314.         max := -1e99;
  315.         for row := 0 to maxN - 1 do begin
  316.             FHTps (row, maxN, fht, rLine);
  317.             base := row * maxN;
  318.             for col := 0 to maxN - 1 do begin
  319.                     r := rLine[col];
  320.                     if r < min then min := r;
  321.                     if r > max then max := r;
  322.                     ps^[base + col] := r;
  323.             end;
  324.             if TickCount > nextTicks then begin
  325.                 UpdateMeter(round(row/maxN * 80.0), 'Computing Power Spectrum');
  326.                 nextTicks := TickCount + updateTicks;
  327.                 if CommandPeriod then begin
  328.                         beep;
  329.                         AbortFFT := true;
  330.                         exit(DisplayPSUsingBuffer)
  331.                     end;
  332.             end;
  333.         end;
  334.         if min < 1.0 then
  335.             min := 0.0
  336.         else
  337.             min := ln(min);
  338.         max := ln(max);
  339.         scale := 253.0 / (max - min);
  340.         for row := 0 to maxN - 1 do begin
  341.                 base := row * maxN;
  342.                 for col := 0 to maxN - 1 do begin
  343.                         r := ps^[base + col];
  344.                         if r < 1.0 then
  345.                             r := 0.0
  346.                         else
  347.                             r := ln(r);
  348.                         line[col] := round((r - min) * scale) + 1;
  349.                 end;
  350.                 PutLine(0, row, maxN, line);
  351.                 if TickCount > nextTicks then begin
  352.                     UpdateMeter(round(row/maxN * 20.0 ) + 80, 'Computing Power Spectrum');
  353.                     nextTicks := TickCount + updateTicks;
  354.                     if CommandPeriod then begin
  355.                             beep;
  356.                             AbortFFT := true;
  357.                             exit(DisplayPSUsingBuffer)
  358.                         end;
  359.                 end;
  360.             end;
  361.         SwapQuadrants;
  362.         UpdateMeter(-1, 'Hide Meter');
  363.     end;    
  364.     
  365.     
  366.     procedure DisplayPowerSpectrum(fht: rImagePtr);
  367.     var
  368.         row, col, nextTicks, maxN: LongInt;
  369.         r, min, max, scale: real;
  370.         line: lineType;
  371.         rLine: rLineType;
  372.         tempH: handle;
  373.         ps: rImagePtr;
  374.     begin
  375.         maxN := info^.PixelsPerLine;
  376.         tempH := GetBigHandle(maxN * maxN * SizeOf(real));
  377.         if tempH <> nil then begin
  378.             hlock(tempH);
  379.             ps := rImagePtr(tempH^);
  380.             DisplayPSUsingBuffer(fht, ps, rLine);
  381.             hunlock(tempH);
  382.             DisposeHandle(tempH);
  383.             exit(DisplayPowerSpectrum);
  384.         end;
  385.         min := 1e99;
  386.         max := -1e99;
  387.         nextTicks := TickCount + updateTicks;
  388.         for row := 0 to maxN - 1 do begin
  389.             FHTps (row, maxN, fht, rLine);
  390.             for col := 0 to maxN - 1 do begin
  391.                     r := rLine[col];
  392.                     if r < min then min := r;
  393.                     if r > max then max := r;
  394.             end;
  395.             if TickCount > nextTicks then begin
  396.                 UpdateMeter(round(row/maxN * 35.0), 'Computing Power Spectrum');
  397.                 nextTicks := TickCount + updateTicks;
  398.                 if CommandPeriod then begin
  399.                         beep;
  400.                         AbortFFT := true;
  401.                         exit(DisplayPowerSpectrum)
  402.                     end;
  403.             end;
  404.         end;
  405.         if min < 1.0 then
  406.             min := 0.0
  407.         else
  408.             min := ln(min);
  409.         max := ln(max);
  410.         scale := 253.0 / (max - min);
  411.         for row := 0 to maxN - 1 do begin
  412.                 FHTps (row, maxN, fht, rLine);
  413.                 for col := 0 to maxN - 1 do begin
  414.                         r := rLine[col];
  415.                         if r < 1.0 then
  416.                             r := 0.0
  417.                         else
  418.                             r := ln(r);
  419.                         line[col] := round((r - min) * scale) + 1;
  420.                 end;
  421.                 PutLine(0, row, maxN, line);
  422.                 if TickCount > nextTicks then begin
  423.                     UpdateMeter(round(row/maxN * 65.0 ) + 35, 'Computing Power Spectrum');
  424.                     nextTicks := TickCount + updateTicks;
  425.                     if CommandPeriod then begin
  426.                             beep;
  427.                             AbortFFT := true;
  428.                             exit(DisplayPowerSpectrum)
  429.                         end;
  430.                 end;
  431.             end;
  432.         SwapQuadrants;
  433.         UpdateMeter(-1, 'Hide Meter');
  434.     end;
  435.  
  436.  
  437. procedure ConvertToReal;
  438. var
  439.     row, col, i, sum, base: LongInt;
  440.     width, height: LongInt;
  441.     mean, pixelCount: real;
  442.     line: LineType;
  443.     DataP: rImagePtr;
  444. begin
  445.     with info^ do begin
  446.         width := pixelsPerLine;
  447.         height := nLines;
  448.         hlock(DataH);
  449.         DataP := rImagePtr(DataH^);
  450.     end;
  451.     UpdateMeter(0, 'Converting to Real');
  452.     {
  453.     GetRectHistogram;
  454.     sum := 0;
  455.     pixelCount := width * height;
  456.     for i := 0 to 255 do
  457.         sum := sum + histogram[i] * i;
  458.     mean := sum / pixelCount;
  459.     }
  460.     for row:= 0 to height - 1 do begin
  461.         GetLine(0, row, width, line);
  462.         base := row * width;
  463.         for col := 0 to width - 1 do
  464.             DataP^[base + col] := line[col] {- mean};
  465.     end;
  466.     hunlock(info^.DataH);
  467. end;
  468.  
  469.  
  470. function isPowerOf2 (x: LongInt): boolean;
  471. var
  472.     i, sum: integer;
  473. begin
  474. sum := 0;
  475. x := abs(x);
  476. for i := 0 to 15 do
  477.     sum := sum + ord(BTST(x, i));
  478. IsPowerOf2 := (sum <= 1);
  479. end;
  480.  
  481.  
  482. function PowerOf2Size: boolean;
  483. var
  484.     width, height: LongInt;
  485.  
  486.     procedure fail;
  487.     begin
  488.          PutError('A square, power of two size image or selection (128x128, 256x256, etc.) required.');
  489.          AbortMacro;
  490.          PowerOf2Size := false;
  491.          exit(PowerOf2Size);
  492.     end;
  493.  
  494. begin
  495.     with info^ do begin
  496.         if info = noInfo then
  497.             fail;
  498.         width := pixelsPerLine;
  499.         height := nLines;
  500.         if RoiShowing and (roiType = rectRoi) then with roiRect do begin
  501.             width := right - left;
  502.             height := bottom - top;
  503.         end;
  504.         if not isPowerOf2(width) or (width <> height) then
  505.             fail;
  506.         if width < 4 then begin
  507.                 PutMessage('Sequence Length must be >= 4.');
  508.                 PowerOf2Size := true;
  509.                 exit(PowerOf2Size);
  510.             end;
  511.         PowerOf2Size := true;
  512.     end;
  513. end;
  514.  
  515.  
  516. function MakeSinCosTables(maxN: LongInt): boolean;
  517. var
  518.     i: LongInt;
  519.     theta, dTheta: real;
  520. begin
  521.     C := rLinePtr(NewPtr(SizeOf(rLineType)));
  522.     S := rLinePtr(NewPtr(SizeOf(rLineType)));
  523.     if (C = nil) or (S = nil) then begin
  524.         MakeSinCosTables := false;
  525.         PutError('Out of Memory');
  526.         exit(MakeSinCosTables);
  527.     end;
  528.     theta := 0;
  529.     dTheta := 2 * pi / maxN;
  530.     for i := 0 to maxN div 4 - 1 do
  531.         begin
  532.             C^[i] := cos(theta);
  533.             S^[i] := sin(theta);
  534.             theta := theta + dTheta;
  535.         end;
  536.         MakeSinCosTables := true;
  537. end;
  538.  
  539.  
  540. function MakeRealImage: boolean;
  541. var
  542.     TempH: handle;
  543.     maxN: LongInt;
  544. begin
  545.     maxN := info^.PixelsPerLine;
  546.     tempH := GetBigHandle(maxN * maxN * SizeOf(real));
  547.     if TempH = nil then begin
  548.         PutMemoryAlert;
  549.         MakeRealImage := false;
  550.         exit(MakeRealImage);
  551.     end;
  552.     if not Duplicate(StringOf('FFT ', nPics + 1:1), false) then begin
  553.         DisposeHandle(handle(TempH));
  554.         exit(MakeRealImage);
  555.     end;
  556.     UpdatePicWindow;
  557.     info^.DataH := tempH;
  558.     ConvertToReal;
  559.     UpdateTitleBar;
  560.     MakeRealImage := true;
  561. end;
  562.  
  563.  
  564. procedure SetFFTWindowName(doInverse: boolean);
  565. begin
  566.     with info^ do begin
  567.         if doInverse then
  568.             title := StringOf('Inverse FFT ', picNum:1)
  569.         else
  570.             title := StringOf('FFT ', picNum:1);
  571.         UpdateWindowsMenuItem;
  572.         UpdateTitleBar;
  573.     end;
  574. end;
  575.  
  576.  
  577. procedure ApplyFilter(rData: rImagePtr);
  578. var
  579.     row, col, width, height, base, i: LongInt;
  580.     line: LineType;
  581.     passMode: boolean;
  582.     t:FateTable;
  583. begin
  584.     SwapQuadrants;
  585.     with info^ do begin
  586.         width := pixelsPerLine;
  587.         height := nLines;
  588.     end;
  589.     for row:= 0 to height - 1 do begin
  590.         GetLine(0, row, width, line);
  591.         base := row * width;
  592.         for col := 0 to width - 1 do
  593.             rData^[base + col] := line[col]/255.0 * rData^[base + col];
  594.     end;
  595. end;
  596.  
  597.  
  598. procedure doMasking(rData: rImagePtr);
  599. var
  600.     row, col, width, height, base, i: LongInt;
  601.     line: LineType;
  602.     passMode: boolean;
  603.     t:FateTable;
  604. begin
  605.     GetRectHistogram;
  606.     if (histogram[0] = 0) and (histogram[255] = 0) then
  607.         exit(doMasking);
  608.     UpdateMeter(0, 'Masking');
  609.     passMode := histogram[255] <> 0;
  610.     if passMode then
  611.         ChangeValues(0,254,0)
  612.     else
  613.         ChangeValues(1,255,255);
  614.     for i := 1 to 3 do
  615.         Filter(UnweightedAvg, 0, t);
  616.     UpdatePicWindow;
  617.     ApplyFilter(rData);
  618. end;
  619.  
  620.  
  621.     procedure doFFT(fftKind: fftType);
  622.     var
  623.         startTicks, maxN: LongInt;
  624.         trect: rect;
  625.         RealData: rImagePtr;
  626.         doInverse: boolean;
  627.     begin
  628.             doInverse := fftKind <> ForewardFFT;
  629.             if not PowerOf2Size then
  630.                 exit(doFFT);
  631.             startTicks := tickCount;
  632.             if info^.DataH = nil then begin
  633.                 if doInverse then begin
  634.                     PutError('A real image is required to do an inverse transform.');
  635.                      AbortMacro;
  636.                     exit(doFFT);
  637.                 end;
  638.                 if not MakeRealImage then begin
  639.                      AbortMacro;
  640.                     exit(doFFT);
  641.                 end
  642.             end else begin
  643.                 KillRoi;
  644.                 SetFFTWindowName(doInverse);
  645.             end;
  646.             hlock(info^.DataH);
  647.             RealData := rImagePtr(info^.DataH^);
  648.             ShowWatch;
  649.             maxN := info^.PixelsPerLine;
  650.             if not MakeSinCosTables(maxN) then
  651.                 exit(doFFT);
  652.             AbortFFT := false;
  653.             ShowMessage(CmdPeriodToStop);
  654.             if doInverse then begin
  655.                 if fftKind = InverseFFTWithMask then 
  656.                     doMasking(RealData)
  657.                 else if fftKind = InverseFFTWithFilter then
  658.                     ApplyFilter(RealData);
  659.                 rc2DFHT(RealData, true, maxN);
  660.                 if not AbortFFT then
  661.                     DisplayRealImage(RealData);
  662.             end else begin
  663.                 rc2DFHT(RealData, false, maxN);
  664.                 if not AbortFFT then
  665.                     DisplayPowerSpectrum(RealData);
  666.             end;
  667.             if AbortFFT then
  668.                 UpdateMeter(-1, 'Hide');
  669.             hunlock(info^.dataH);
  670.             UpdatePicWindow;
  671.             SetRect(trect, 0, 0, maxN, maxN);
  672.             ShowTime(startTicks, trect, '');
  673.             UpdateWindowsMenuItem;
  674.             DisposePtr(ptr(C));
  675.             DisposePtr(ptr(S));
  676.     end;
  677.     
  678.  
  679. procedure RedisplayPowerSpectrum;
  680.     var
  681.         rData: rImagePtr;
  682.     begin
  683.             if info = noInfo then
  684.                 exit(RedisplayPowerSpectrum);
  685.             KillRoi;
  686.             if not PowerOf2Size then
  687.                 exit(RedisplayPowerSpectrum);
  688.             if info^.DataH = nil then begin
  689.                     PutError('Real image required.');
  690.                     exit(RedisplayPowerSpectrum);
  691.                 end;
  692.             hlock(info^.DataH);
  693.             rData := rImagePtr(info^.DataH^);
  694.             DisplayPowerSpectrum(rData);
  695.             hunlock(info^.dataH);
  696.             UpdatePicWindow;
  697.     end;
  698.  
  699.  
  700.     Procedure doSwapQuadrants;
  701.     begin
  702.         if info = noInfo then
  703.             exit(doSwapQuadrants);
  704.         KillRoi;
  705.         if not PowerOf2Size then
  706.             exit(doSwapQuadrants);
  707.         SetupUndo;
  708.         WhatToUndo := UndoEdit;
  709.         SwapQuadrants;
  710.         UpdatePicWindow;
  711.     end;
  712.  
  713.  
  714. end. {fft Unit}