001/*******************************************************************************
002 * This software is provided as a supplement to the authors' textbooks on digital
003 *  image processing published by Springer-Verlag in various languages and editions.
004 * Permission to use and distribute this software is granted under the BSD 2-Clause 
005 * "Simplified" License (see http://opensource.org/licenses/BSD-2-Clause). 
006 * Copyright (c) 2006-2016 Wilhelm Burger, Mark J. Burge. All rights reserved. 
007 * Visit http://imagingbook.com for additional details.
008 *******************************************************************************/
009
010package imagingbook.pub.dft;
011
012import ij.process.*;
013import imagingbook.lib.math.Complex;
014import imagingbook.pub.dft.Dft1d;
015
016//TODO: clean up creation of G (made instances of Complex immutable)!
017
018public class Dft2d {
019        final int width, height;
020        float[] Real;   //original image data
021        float[] Imag;
022        float[] Power;
023        float PowerMax;
024        boolean swapQu = true;
025        int scaleValue = 255;   
026        boolean forward = true;
027        
028        public Dft2d(FloatProcessor ip){
029                width = ip.getWidth();
030                height = ip.getHeight();
031                Real = (float[]) ip.getPixels();
032                Imag = new float[width*height];  // values are zero
033                doDft2d();
034                makePowerSpectrum();
035        }
036        
037        public Dft2d(FloatProcessor ip, boolean center){
038                this(ip);
039                swapQu = center;
040        }
041        
042        //------------------------------------------------
043        
044//      public void setForward() {
045//              forward = true;
046//      }
047        
048//      public void setInverse() {
049//              forward = false;
050//      }
051        
052        public float[] getReal() {
053                return Real;
054        }
055        
056        public float[] getImag(){
057                return Imag;
058        }
059        
060        public float[] getPower(){
061                return Power;
062        }
063        
064        //------------------------------------------------
065        
066        public void doDft2d () { // in-place 2D Dft
067                // do the rows:
068                Complex[] row = Complex.makeComplexVector(width);
069                Dft1d dftR = new Dft1d(width);
070                for (int v=0; v<height; v++){
071                        getRow(v,row);
072                        Complex[] rowDft = dftR.DFT(row, forward);
073                        putRow(v,rowDft);
074                }
075                // do the columns:
076                Complex[] col = Complex.makeComplexVector(height);
077                Dft1d dftC = new Dft1d(height);
078                for (int u=0; u<width; u++){
079                        getCol(u,col);
080                        Complex[] colDft = dftC.DFT(col,forward);
081                        putCol(u,colDft);
082                }
083        }
084        
085        void getRow(int v, Complex[] rowC){
086                int i = v*width; //start index of row v
087                for (int u=0; u<width; u++){
088//                      rowC[u].re = Real[i+u];
089//                      rowC[u].im = Imag[i+u];
090                        rowC[u] = new Complex(Real[i+u], Imag[i+u]);
091                }
092        }
093        
094        void putRow(int v, Complex[] rowC){
095                int i = v*width; //start index of row v
096                for (int u=0; u<width; u++){
097                        Real[i+u] = (float) rowC[u].re();
098                        Imag[i+u] = (float) rowC[u].im();
099                }
100        }
101        
102        void getCol(int u, Complex[] rowC){
103                for (int v=0; v<height; v++){
104//                      rowC[v].re = Real[v*width+u];
105//                      rowC[v].im = Imag[v*width+u];
106                        rowC[v] = new Complex(Real[v*width+u], Imag[v*width+u]);
107                }
108        }
109        
110        void putCol(int u, Complex[] rowC){
111                for (int v=0; v<height; v++){
112                        Real[v*width+u] = (float) rowC[v].re();
113                        Imag[v*width+u] = (float) rowC[v].im();
114                }
115        }
116        
117        //----------------------------------------------------
118        
119        void makePowerSpectrum(){
120                //computes the power spectrum 
121                Power = new float[Real.length];
122                PowerMax = 0.0f;
123                for (int i=0; i<Real.length; i++){
124                        double a = Real[i];
125                        double b = Imag[i];
126                        float p = (float) Math.sqrt(a*a + b*b);
127                        Power[i] = p;
128                        if (p>PowerMax)
129                                PowerMax = p;
130                }
131        }
132        
133        public ByteProcessor makePowerImage(){
134                ByteProcessor ip = new ByteProcessor(width,height);
135                byte[] pixels = (byte[]) ip.getPixels();
136                //PowerMax must be set
137                double max = Math.log(PowerMax+1.0);
138                double scale = 1.0;
139                if (scaleValue > 0)
140                        scale = scaleValue/max;
141                for (int i=0; i<pixels.length; i++){
142                        double p = Power[i];
143                        if (p<0) p = -p;
144                        double plog = Math.log(p+1.0);
145                        int pint = (int)(plog * scale);
146                        pixels[i] = (byte) (0xFF & pint);
147                }
148                if (swapQu) swapQuadrants(ip);
149                return ip;
150        }
151
152        //      ----------------------------------------------------
153
154        public void swapQuadrants (ImageProcessor ip) {
155                //swap quadrants Q1 <-> Q3, Q2 <-> Q4
156                // Q2 Q1
157                // Q3 Q4
158                ImageProcessor t1, t2;
159                int w = ip.getWidth();
160                int h = ip.getHeight();
161                int w2 = w/2;
162                int h2 = h/2;
163                
164                ip.setRoi(w2,0,w-w2,h2); // Q1
165                t1 = ip.crop();
166                
167                ip.setRoi(0,h2,w2,h-h2); //Q3
168                t2 = ip.crop();
169                
170                ip.insert(t1,0,h2); //swap Q1 <-> Q3
171                ip.insert(t2,w2,0);
172                
173                ip.setRoi(0,0,w2,h2); //Q2
174                t1 = ip.crop();
175                
176                ip.setRoi(w2,h2,w-w2,h-h2); //Q4
177                t2 = ip.crop();
178                
179                ip.insert(t1,w2,h2);
180                ip.insert(t2,0,0);
181        }
182
183}
184
185