Skip to content

Commit 4ba6216

Browse files
committed
add Gerchberg Saxton / Fourier Hologram
1 parent 4e290c2 commit 4ba6216

File tree

3 files changed

+264
-1
lines changed

3 files changed

+264
-1
lines changed

Filters.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,3 +34,4 @@
3434
5D22 rotate (90, 180, 270)
3535
5D23 nearest (nearest-neighbor 2x)
3636
5D24 tvzero (1x)
37+
5D25 Gerchberg-Saxton Phase Retrieval

Makefile

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ all: test PixelFilter \
4949
ultra2x super2x 2xscl des2x des \
5050
bilinear bilinearplus bilinearpp \
5151
hq2xn lq2xn epxb epxc eagle3xb \
52-
flip rotate nearest
52+
flip rotate nearest gs
5353

5454
PixelFilter:
5555
clang++ $(EXEC_FLAGS) PixelFilter.exe PixelFilter.cpp lodepng.cpp $(OPENCV_INCLUDES) $(OPENCV_LIBS)
@@ -453,6 +453,17 @@ else
453453
ln -sf libpixel++tvzero.so.$(FUL_VERSION) libpixel++tvzero.so
454454
endif
455455

456+
gs:
457+
clang++ $(CFLAGS_BASE) gs.cpp
458+
459+
ifeq ($(UNAME), Darwin)
460+
clang++ $(LFLAGS_LIB) libpixel++gs.$(FUL_VERSION).dylib gs.o -lfftw3
461+
ln -sf libpixel++gs.$(FUL_VERSION).dylib libpixel++gs.dylib
462+
else
463+
clang++ $(LFLAGS_LIB),libpixel++gs.so.$(MAJ_VERSION) -o libpixel++gs.so.$(FUL_VERSION) gs.o -lfftw3
464+
ln -sf libpixel++gs.so.$(FUL_VERSION) libpixel++gs.so
465+
endif
466+
456467
cleanup:
457468
rm -f *.o
458469

gs.cpp

Lines changed: 251 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,251 @@
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

Comments
 (0)