|
| 1 | +#define _USE_MATH_DEFINES |
| 2 | +#include <algorithm> |
| 3 | +#include <cmath> |
| 4 | +#include <cstdlib> |
| 5 | +#include <cstring> |
| 6 | +#include <fftw3.h> |
| 7 | + |
| 8 | +#include "includes/FilterCommon.h" |
| 9 | + |
| 10 | +extern "C" |
| 11 | +{ |
| 12 | + static unsigned char* ScaledImage = NULL; |
| 13 | + |
| 14 | + const int FilterID = 0x5D25; |
| 15 | + const char* FilterName = "Gerchberg-Saxton"; |
| 16 | + const char* FilterDescription = "Generate Fourier Hologram"; |
| 17 | + |
| 18 | + bool ComparisonThreshold = false; |
| 19 | + const int FilterScaleX = 1; |
| 20 | + const int FilterScaleY = 1; |
| 21 | + |
| 22 | + const int Re = 0; |
| 23 | + const int Im = 1; |
| 24 | + |
| 25 | + #include "includes/Init.h" |
| 26 | + |
| 27 | + double* Double(int Length, double val) |
| 28 | + { |
| 29 | + auto dbl = (double*)malloc(Length * sizeof(double)); |
| 30 | + |
| 31 | + if (dbl != NULL) |
| 32 | + { |
| 33 | + for (auto x = 0; x < Length; x++) |
| 34 | + { |
| 35 | + dbl[x] = val; |
| 36 | + } |
| 37 | + } |
| 38 | + |
| 39 | + return dbl; |
| 40 | + } |
| 41 | + |
| 42 | + fftw_complex* Complex(int Length, double val) |
| 43 | + { |
| 44 | + auto dbl = (fftw_complex*)fftw_malloc(Length * sizeof(fftw_complex)); |
| 45 | + |
| 46 | + if (dbl != NULL) |
| 47 | + { |
| 48 | + for (auto x = 0; x < Length; x++) |
| 49 | + { |
| 50 | + dbl[x][Re] = val; |
| 51 | + dbl[x][Im] = 0.0; |
| 52 | + } |
| 53 | + } |
| 54 | + |
| 55 | + return dbl; |
| 56 | + } |
| 57 | + |
| 58 | + fftw_complex* Copy(unsigned char* input, int xdim, int ydim) |
| 59 | + { |
| 60 | + auto cmplx = (fftw_complex*)fftw_malloc(xdim * ydim * sizeof(fftw_complex)); |
| 61 | + |
| 62 | + if (cmplx != NULL) |
| 63 | + { |
| 64 | + for (auto y = 0; y < ydim; y++) |
| 65 | + { |
| 66 | + for (auto x = 0; x < xdim; x++) |
| 67 | + { |
| 68 | + auto index = y * xdim + x; |
| 69 | + |
| 70 | + cmplx[index][Re] = Luminance(CLR(input, xdim, ydim, x, y)); |
| 71 | + cmplx[index][Im] = Luminance(CLR(input, xdim, ydim, x, y)); |
| 72 | + } |
| 73 | + } |
| 74 | + } |
| 75 | + |
| 76 | + return cmplx; |
| 77 | + } |
| 78 | + |
| 79 | + void Source(fftw_complex** source, int xdim, int ydim) |
| 80 | + { |
| 81 | + auto size = xdim * ydim; |
| 82 | + |
| 83 | + *source = Complex(size, 0.0); |
| 84 | + |
| 85 | + if (source) |
| 86 | + { |
| 87 | + // create source field |
| 88 | + for (auto index = 0; index < size; index++) |
| 89 | + { |
| 90 | + (*source)[index][Re] = 1.0; |
| 91 | + } |
| 92 | + } |
| 93 | + } |
| 94 | + |
| 95 | + void Shift(fftw_complex* complex, int sizex, int sizey) |
| 96 | + { |
| 97 | + fftw_complex temp; |
| 98 | + auto midx = sizex / 2; |
| 99 | + auto midy = sizey / 2; |
| 100 | + |
| 101 | + for (auto y = 0; y < midy; y++) |
| 102 | + { |
| 103 | + for (auto x = 0; x < midx; x++) |
| 104 | + { |
| 105 | + // Exchange 1st and 4th quadrant |
| 106 | + temp[Re] = complex[y * sizex + x][Re]; |
| 107 | + complex[y * sizex + x][Re] = complex[(midy + y) * sizex + (midx + x)][Re]; |
| 108 | + complex[(midy + y) * sizex + (midx + x)][Re] = temp[Re]; |
| 109 | + |
| 110 | + temp[Im] = complex[y * sizex + x][Im]; |
| 111 | + complex[y * sizex + x][Im] = complex[(midy + y) * sizex + (midx + x)][Im]; |
| 112 | + complex[(midy + y) * sizex + (midx + x)][Im] = temp[Im]; |
| 113 | + |
| 114 | + // Exchange 2nd and 3rd quadrant |
| 115 | + temp[Re] = complex[y * sizex + (midx + x)][Re]; |
| 116 | + complex[y * sizex + (midx + x)][Re] = complex[(midy + y) * sizex + x][Re]; |
| 117 | + complex[(midy + y) * sizex + x][Re] = temp[Re]; |
| 118 | + |
| 119 | + temp[Im] = complex[y * sizex + (midx + x)][Im]; |
| 120 | + complex[y * sizex + (midx + x)][Im] = complex[(midy + y) * sizex + x][Im]; |
| 121 | + complex[(midy + y) * sizex + x][Im] = temp[Im]; |
| 122 | + } |
| 123 | + } |
| 124 | + } |
| 125 | + |
| 126 | + double Rsqrt(double x) |
| 127 | + { |
| 128 | + return 1.0 / sqrt(x); |
| 129 | + } |
| 130 | + |
| 131 | + void ComputePhase(fftw_complex* input, fftw_complex* phase, int size) |
| 132 | + { |
| 133 | + for (auto index = 0; index < size; index++) |
| 134 | + { |
| 135 | + auto pf = Rsqrt(input[index][Re] * input[index][Re] + input[index][Im] * input[index][Im]); |
| 136 | + |
| 137 | + phase[index][Re] = input[index][Re] * pf; |
| 138 | + phase[index][Im] = input[index][Im] * pf; |
| 139 | + } |
| 140 | + } |
| 141 | + |
| 142 | + void ComputePhaseAndMakeComplexField(fftw_complex* input, fftw_complex* amplitude, fftw_complex* ComplexField, int size) |
| 143 | + { |
| 144 | + for (int index = 0; index < size; index++) |
| 145 | + { |
| 146 | + auto pf = Rsqrt(input[index][Re] * input[index][Re] + input[index][Im] * input[index][Im]); |
| 147 | + |
| 148 | + auto phase_re = input[index][Re] * pf; |
| 149 | + auto phase_im = input[index][Im] * pf; |
| 150 | + |
| 151 | + ComplexField[index][Re] = amplitude[index][Re] * phase_re - amplitude[index][Im] * phase_im; |
| 152 | + ComplexField[index][Im] = amplitude[index][Re] * phase_im + amplitude[index][Im] * phase_re; |
| 153 | + } |
| 154 | + } |
| 155 | + |
| 156 | + double Mod(double a, double m) |
| 157 | + { |
| 158 | + return a - m * floor(a / m); |
| 159 | + } |
| 160 | + |
| 161 | + void Apply(int argc, void** argv) |
| 162 | + { |
| 163 | + if (argc >= 4) |
| 164 | + { |
| 165 | + auto Input = ((unsigned char*)(argv[0])); |
| 166 | + auto srcx = *((int*)(argv[1])); |
| 167 | + auto srcy = *((int*)(argv[2])); |
| 168 | + auto Ngs = *((int*)(argv[3])); |
| 169 | + |
| 170 | + Ngs = Ngs < 1 ? 1 : Ngs; |
| 171 | + Ngs = Ngs > 1000 ? 1000 : Ngs; |
| 172 | + |
| 173 | + Init(srcx, srcy); |
| 174 | + |
| 175 | + auto Channels = 3; |
| 176 | + |
| 177 | + // FFT plans |
| 178 | + fftw_plan fwdplan, invplan; |
| 179 | + |
| 180 | + auto size = srcx * srcy; |
| 181 | + |
| 182 | + // temporary complex arrays to hold intermediate results |
| 183 | + auto result = Complex(size, 0.0); |
| 184 | + auto source = Complex(size, 0.0); |
| 185 | + auto d_temp = Complex(size, 0.0); |
| 186 | + auto d_result = Complex(size, 0.0); |
| 187 | + |
| 188 | + Source(&source, srcx, srcy); |
| 189 | + |
| 190 | + // 2D Forward plan |
| 191 | + fwdplan = fftw_plan_dft_2d(srcy, srcx, d_temp, d_result, FFTW_FORWARD, FFTW_MEASURE); |
| 192 | + |
| 193 | + // 2D Inverse plan |
| 194 | + invplan = fftw_plan_dft_2d(srcy, srcx, d_temp, d_result, FFTW_BACKWARD, FFTW_MEASURE); |
| 195 | + |
| 196 | + auto resized = Copy(Input, srcx, srcy); |
| 197 | + |
| 198 | + Shift(resized, srcx, srcy); |
| 199 | + |
| 200 | + // --------------------- |
| 201 | + // -- GS PHASE -- |
| 202 | + // --------------------- |
| 203 | + |
| 204 | + // Get initial estimate of the phase |
| 205 | + fftw_execute_dft(invplan, resized, d_result); |
| 206 | + |
| 207 | + for (auto iter = 0; iter < Ngs; iter++) |
| 208 | + { |
| 209 | + // Apply source constraints |
| 210 | + ComputePhaseAndMakeComplexField(d_result, source, d_temp, size); |
| 211 | + |
| 212 | + // perform forward transform |
| 213 | + fftw_execute_dft(fwdplan, d_temp, d_result); |
| 214 | + |
| 215 | + // Apply target constraints |
| 216 | + ComputePhaseAndMakeComplexField(d_result, resized, d_temp, size); |
| 217 | + |
| 218 | + // perform backward transform |
| 219 | + fftw_execute_dft(invplan, d_temp, d_result); |
| 220 | + } |
| 221 | + |
| 222 | + // ----- extract GS PHASE |
| 223 | + ComputePhase(d_result, result, size); |
| 224 | + |
| 225 | + for (auto index = 0; index < size; index++) |
| 226 | + { |
| 227 | + auto angle = Mod(atan2(result[index][Im], result[index][Re]), 2.0 * M_PI); |
| 228 | + |
| 229 | + unsigned char c = (unsigned char)(255.0 * angle / (2.0 * M_PI)); |
| 230 | + |
| 231 | + ScaledImage[index * Channels] = c; |
| 232 | + ScaledImage[index * Channels + 1] = c; |
| 233 | + ScaledImage[index * Channels + 2] = c; |
| 234 | + } |
| 235 | + |
| 236 | + // Destroy plans |
| 237 | + fftw_destroy_plan(invplan); |
| 238 | + fftw_destroy_plan(fwdplan); |
| 239 | + |
| 240 | + // FFTW clean-up |
| 241 | + fftw_cleanup(); |
| 242 | + |
| 243 | + // free memory |
| 244 | + fftw_free(resized); |
| 245 | + fftw_free(d_result); |
| 246 | + fftw_free(d_temp); |
| 247 | + fftw_free(result); |
| 248 | + fftw_free(source); |
| 249 | + } |
| 250 | + } |
| 251 | +} |
0 commit comments