-
Notifications
You must be signed in to change notification settings - Fork 0
/
stereoGC.cpp
283 lines (257 loc) · 11 KB
/
stereoGC.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
// Author: Renaud Marlet
#include <Imagine/Images.h>
#include <iostream>
#include <algorithm>
#include "maxflow/graph.h"
using namespace std;
using namespace Imagine;
typedef Image<byte> byteImage;
typedef Image<double> doubleImage;
// Return image of mean intensity value over (2n+1)x(2n+1) patch
doubleImage meanImage(const doubleImage& I, int n) {
// Create image for mean values
int w = I.width(), h = I.height();
doubleImage IM(w,h);
// Compute patch area
double area = (2*n+1)*(2*n+1);
// For each pixel
for (int i=0; i<w; i++)
for (int j=0; j<h; j++) {
// If pixel is close to border (<n pixels) mean is meaningless
if (j-n<0 || j+n>=h || i-n<0 ||i+n>=w) {
IM(i,j)=0;
continue;
}
double sum = 0;
for(int x = i-n; x <= i+n; x++)
for (int y = j-n; y <= j+n; y++)
sum += I(x,y);
IM(i,j) = sum / area;
}
return IM;
}
// Compute correlation between two pixels in images 1 and 2
double correl(const doubleImage& I1, // Image 1
const doubleImage& I1M, // Image of mean value over patch
const doubleImage& I2, // Image2
const doubleImage& I2M, // Image of mean value over patch
int u1, int v1, // Pixel of interest in image 1
int u2, int v2, // Pixel of interest in image 2
int n) { // Half patch size
// Initialize correlation
double c = 0;
// For each pixel displacement in patch
for (int x=-n; x<=n; x++)
for(int y=-n; y<=n; y++)
c += (I1(u1+x,v1+y) - I1M(u1,v1)) * (I2(u2+x,v2+y) - I2M(u2,v2));
return c / ((2*n+1)*(2*n+1));
}
// Compute ZNCC between two patches in images 1 and 2
double zncc(const doubleImage& I1, // Image 1
const doubleImage& I1M, // Image of mean intensity value over patch
const doubleImage& I2, // Image2
const doubleImage& I2M, // Image of mean intensity value over patch
int u1, int v1, // Pixel of interest in image 1
int u2, int v2, // Pixel of interest in image 2
int n) { // Half patch size
double var1 = correl(I1, I1M, I1, I1M, u1, v1, u1, v1, n);
if (var1 == 0)
return 0;
double var2 = correl(I2, I2M, I2, I2M, u2, v2, u2, v2, n);
if (var2 == 0)
return 0;
return correl(I1, I1M, I2, I2M, u1, v1, u2, v2, n) / sqrt(var1 * var2);
}
// Load two rectified images.
// Compute the disparity of image 2 w.r.t. image 1.
// Display disparity map.
// Display 3D mesh of corresponding depth map.
//
// Images are clipped to focus on pixels visible in both images.
// OPTIMIZATION: to make the program faster, a zoom factor is used to
// down-sample the input images on the fly. For an image of size WxH, you will
// only look at pixels (n+zoom*i,n+zoom*j) with n the radius of patch.
int main() {
cout << "Loading images... " << flush;
byteImage I;
doubleImage I1,I2,I3,I4;
load(I, srcPath("face00R.png"));
I1 = I.getSubImage(IntPoint2(20,30), IntPoint2(430,420));
load(I, srcPath("face01R.png"));
I2 = I.getSubImage(IntPoint2(20,30), IntPoint2(480,420));
cout << I1.width() << endl ;
cout << "done" << endl;
cout << "Setting parameters... " << flush;
// Generic parameters
const int zoom = 2; // Zoom factor (to speedup computations)
const int n = 3; // Consider correlation patches of size (2n+1)*(2n+1)
const float lambdaf = 0.1; // Weight of regularization (smoothing) term
const int wcc = max(1+int(1/lambdaf),20); // Energy discretization precision [as we build a graph with 'int' weights]
const int lambda = lambdaf * wcc; // Weight of regularization (smoothing) term [must be >= 1]
const float sigma = 3; // Gaussian blur parameter for disparity
// Image-specific, hard-coded parameters for approximate 3D reconstruction,
// as real geometry before rectification is not known
const int dmin = 10; // Minmum disparity
const int dmax = 55; // Maximum disparity
const float fB = 40000; // Depth factor
const float db = 100; // Disparity base
cout << "done" << endl;
cout << "Displaying images... " << flush;
int w1 = I1.width(), w2 = I2.width(), h = I1.height();
openWindow(w1+w2, h);
display(grey(I1));
display(grey(I2), w1, 0);
cout << "done" << endl;
cout << "Constructing graph (be patient)... " << flush;
// Precompute images of mean intensity value over patch
doubleImage I1M = meanImage(I1,n), I2M = meanImage(I2,n);
// Zoomed image dimension, disregarding borders (strips of width equal to patch half-size)
const int nx = (w1 - 2*n) / zoom, ny = (h - 2*n) / zoom;
const int nd = dmax-dmin; // Disparity range
const int INF=1000000; // "Infinite" value for edge impossible to cut
// Create graph
// The graph library works with node numbers. To clarify the setting, create
// a formula to associate a unique node number to a triplet (x,y,d) of pixel
// coordinates and disparity.
// The library assumes an edge consists of a pair of oriented edges, one in
// each direction. Put correct weights to the edges, such as 0, INF, or a
// an intermediate weight.
/////------------------------------------------------------------
///// BEGIN CODE TO COMPLETE: define appropriate graph G
/////
Graph<int,int,int> G(nx*ny*nd, 3*nx*ny*nd);
G.add_node(nx*ny*nd);
int real_disparity = dmin;
for (int d=0;d<nd;d++) {
for (int j=0;j<ny;j++) {
for (int i=0;i<nx;i++) {
//create node id
int node_id = i+nx*j+nx*ny*d;
//create weights with ZNCC
double weight = wcc*min(1., pow(1-zncc(I1,I1M,I2,I2M,n+i*zoom,n+j*zoom,n+(i+real_disparity)*zoom,n+j*zoom, n),0.5));
if(d>0){
//connect layers
G.add_edge(node_id-nx*ny,node_id, weight,INF);
}
else{
//connect source
G.add_tweights(node_id,weight,0);
}
if(d==nd-1){
//connect sink
G.add_tweights(node_id,0,wcc*min(1.,pow(1-zncc(I1,I1M,I2,I2M,n+i*zoom,n+j*zoom,n+(i+real_disparity+1)*zoom,n+j*zoom, n),0.5)));
}
if(i>0){
//connect neighbors inside a layer
G.add_edge(node_id-1,node_id,3*lambda,3*lambda );
}
if(j>0){
//connect neighbors inside a layer
G.add_edge(node_id - nx,node_id,3*lambda,3*lambda);
}
}
}
real_disparity +=1;
}
///// END CODE TO BE COMPLETED
/////------------------------------------------------------------
cout << "done" << endl;
cout << "Computing minimum cut... " << flush;
int f = G.maxflow();
cout << "done" << endl << " max flow = " << f << endl;
cout << "Extracting disparity map from minimum cut... " << flush;
doubleImage D(nx,ny);
// For each pixel
for (int i=0;i<nx;i++) {
for (int j=0;j<ny;j++) {
///// Extract disparity from minimum cut
/////------------------------------------------------------------
///// BEGIN CODE TO BE COMPLETED: define disparity map D from graph G and minimum cut
/////
D(i,j)=dmin;
for (int d=0; d<nd ; d++){
if (G.what_segment(nx*ny*d+nx*j+i)==Graph<int,int,int>::SOURCE){
D(i,j)=d+1+dmin;
}
}
cout << D(i,j) << endl ;
///// END CODE TO BE COMPLETED
/////------------------------------------------------------------
}
}
cout << "done" << endl;
cout << "Displaying disparity map... " << flush;
display(enlarge(grey(D),zoom), n, n);
cout << "done" << endl;
cout << "Click to compute and display blured disparity map... " << flush;
click();
D=blur(D,sigma);
display(enlarge(grey(D),zoom),n,n);
cout << "done" << endl;
cout << "Click to compute depth map and 3D mesh renderings... " << flush;
click();
setActiveWindow( openWindow3D(512, 512, "3D") );
///// Compute 3D points
Array<FloatPoint3> p(nx*ny);
Array<Color> pcol(nx*ny);
for(int i=0; i<nx; i++)
for(int j=0; j<ny; j++) {
// Compute depth: magic constants depending on camera pose
float depth =fB / (db+D(i,j)-dmin);
p[i+nx*j] = FloatPoint3(float(i), float(j), -depth);
byte g = byte( I1(n+i*zoom,n+j*zoom) );
pcol[i+nx*j] = Color(g,g,g);
}
///// Create mesh from 3D points
Array<Triangle> t(2*(nx-1)*(ny-1));
Array<Color> tcol(2*(nx-1)*(ny-1));
for (int i=0; i<nx-1; i++)
for (int j=0; j<ny-1; j++) {
// Create triangles with next pixels in line/column
t[2*(i+j*(nx-1))] = Triangle(i+nx*j, i+1+nx*j, i+nx*(j+1));
t[2*(i+j*(nx-1))+1] = Triangle(i+1+nx*j, i+1+nx*(j+1), i+nx*(j+1));
tcol[2*(i+j*(nx-1))] = pcol[i+nx*j];
tcol[2*(i+j*(nx-1))+1] = pcol[i+nx*j];
}
// Create first mesh as textured with colors taken from original image
Mesh Mt(p.data(), nx*ny, t.data(), 2*(nx-1)*(ny-1), 0, 0, FACE_COLOR);
Mt.setColors(TRIANGLE, tcol.data());
// Create second mesh with artificial light
Mesh Mg(p.data(), nx*ny, t.data(), 2*(nx-1)*(ny-1), 0, 0,
CONSTANT_COLOR, SMOOTH_SHADING);
cout << "done" << endl;
// Display 3D mesh renderings
cout << "***** 3D mesh renderings *****" << endl;
cout << "- Button 1: toggle textured or gray rendering" << endl;
cout << "- SHIFT+Button 1: rotate" << endl;
cout << "- SHIFT+Button 3: translate" << endl;
cout << "- Mouse wheel: zoom" << endl;
cout << "- SHIFT+a: zoom out" << endl;
cout << "- SHIFT+z: zoom in" << endl;
cout << "- SHIFT+r: recenter camera" << endl;
cout << "- SHIFT+m: toggle solid/wire/points mode" << endl;
cout << "- Button 3: exit" << endl;
showMesh(Mt);
bool textured = true;
while (true) {
Event evt;
getEvent(5, evt);
// On mouse button 1
if (evt.type == EVT_BUT_ON && evt.button == 1) {
// Toggle textured rendering and gray rendering
if (textured) {
hideMesh(Mt,false);
showMesh(Mg,false);
} else {
hideMesh(Mg,false);
showMesh(Mt,false);
}
textured = !textured;
}
// On mouse button 3
if (evt.type == EVT_BUT_ON && evt.button == 3)
break;
}
endGraphics();
return 0;
}