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