181 |
jakw |
1 |
//
|
|
|
2 |
// Two Frequency Phase Shifting using the Heterodyne Principle
|
|
|
3 |
//
|
|
|
4 |
// This implementation follows "Reich, Ritter, Thesing, White light heterodyne principle for 3D-measurement", SPIE (1997)
|
|
|
5 |
// Different from the paper, it uses only two different frequencies.
|
|
|
6 |
//
|
182 |
jakw |
7 |
// The number of periods in the primary frequency can be chosen freely, but small changes can have a considerable impact on quality.
|
181 |
jakw |
8 |
// The number of phase shifts can be chosen freely (min. 3), and higher values reduce the effects of image noise. They also allow us to filter bad points based on energy at non-primary frequencies.
|
|
|
9 |
//
|
|
|
10 |
|
128 |
jakw |
11 |
#include "AlgorithmPhaseShiftTwoFreq.h"
|
4 |
jakw |
12 |
#include <math.h>
|
|
|
13 |
|
|
|
14 |
#include "cvtools.h"
|
182 |
jakw |
15 |
#include "algorithmtools.h"
|
4 |
jakw |
16 |
|
231 |
jakw |
17 |
#include <omp.h>
|
|
|
18 |
|
143 |
jakw |
19 |
static unsigned int nStepsPrimary = 16; // number of shifts/steps in primary
|
|
|
20 |
static unsigned int nStepsSecondary = 8; // number of shifts/steps in secondary
|
190 |
jakw |
21 |
static float nPeriodsPrimary = 40; // primary period
|
4 |
jakw |
22 |
|
128 |
jakw |
23 |
AlgorithmPhaseShiftTwoFreq::AlgorithmPhaseShiftTwoFreq(unsigned int _screenCols, unsigned int _screenRows) : Algorithm(_screenCols, _screenRows){
|
4 |
jakw |
24 |
|
72 |
jakw |
25 |
// Set N
|
118 |
jakw |
26 |
N = 2+nStepsPrimary+nStepsSecondary;
|
72 |
jakw |
27 |
|
190 |
jakw |
28 |
// Determine the secondary (wider) period to fulfill the heterodyne condition
|
|
|
29 |
float nPeriodsSecondary = nPeriodsPrimary + 1;
|
74 |
jakw |
30 |
|
70 |
jakw |
31 |
// all on pattern
|
|
|
32 |
cv::Mat allOn(1, screenCols, CV_8UC3, cv::Scalar::all(255));
|
|
|
33 |
patterns.push_back(allOn);
|
|
|
34 |
|
|
|
35 |
// all off pattern
|
|
|
36 |
cv::Mat allOff(1, screenCols, CV_8UC3, cv::Scalar::all(0));
|
|
|
37 |
patterns.push_back(allOff);
|
|
|
38 |
|
74 |
jakw |
39 |
// Primary encoding patterns
|
118 |
jakw |
40 |
for(unsigned int i=0; i<nStepsPrimary; i++){
|
192 |
jakw |
41 |
float phase = 2.0*CV_PI/nStepsPrimary * i;
|
190 |
jakw |
42 |
float pitch = screenCols/nPeriodsPrimary;
|
70 |
jakw |
43 |
cv::Mat patternI(1,1,CV_8U);
|
|
|
44 |
patternI = computePhaseVector(screenCols, phase, pitch);
|
|
|
45 |
patterns.push_back(patternI.t());
|
|
|
46 |
}
|
4 |
jakw |
47 |
|
74 |
jakw |
48 |
// Secondary encoding patterns
|
118 |
jakw |
49 |
for(unsigned int i=0; i<nStepsSecondary; i++){
|
192 |
jakw |
50 |
float phase = 2.0*CV_PI/nStepsSecondary * i;
|
190 |
jakw |
51 |
float pitch = screenCols/nPeriodsSecondary;
|
72 |
jakw |
52 |
cv::Mat patternI(1,1,CV_8U);
|
70 |
jakw |
53 |
patternI = computePhaseVector(screenCols, phase, pitch);
|
|
|
54 |
patterns.push_back(patternI.t());
|
4 |
jakw |
55 |
}
|
|
|
56 |
|
72 |
jakw |
57 |
|
4 |
jakw |
58 |
}
|
|
|
59 |
|
128 |
jakw |
60 |
cv::Mat AlgorithmPhaseShiftTwoFreq::getEncodingPattern(unsigned int depth){
|
4 |
jakw |
61 |
return patterns[depth];
|
|
|
62 |
}
|
|
|
63 |
|
233 |
- |
64 |
|
|
|
65 |
struct StereoRectifyier {
|
|
|
66 |
cv::Mat map0X, map0Y, map1X, map1Y;
|
|
|
67 |
cv::Mat R0, R1, P0, P1, QRect;
|
|
|
68 |
};
|
|
|
69 |
static void getStereoRectifyier(const SMCalibrationParameters &calibration,
|
|
|
70 |
const cv::Size& frameSize,
|
|
|
71 |
StereoRectifyier& stereoRect);
|
|
|
72 |
static void determineAmplitudePhaseEnergy(std::vector<cv::Mat>& frames,
|
|
|
73 |
cv::Mat& amplitude, cv::Mat& phase, cv::Mat& energy);
|
|
|
74 |
static void collectPhases(const cv::Mat& phasePrimary, const cv::Mat& phaseSecondary,
|
|
|
75 |
cv::Mat& phase);
|
|
|
76 |
static void matchPhaseMaps(const cv::Mat& occlusion0, const cv::Mat& occlusion1,
|
|
|
77 |
const cv::Mat& phase0, const cv::Mat& phase1,
|
|
|
78 |
std::vector<cv::Vec2f>& q0, std::vector<cv::Vec2f>& q1);
|
|
|
79 |
static void triangulate(const StereoRectifyier& stereoRect,
|
|
|
80 |
const std::vector<cv::Vec2f>& q0,
|
|
|
81 |
const std::vector<cv::Vec2f>& q1,
|
|
|
82 |
std::vector<cv::Point3f>& Q);
|
|
|
83 |
|
|
|
84 |
|
207 |
flgw |
85 |
void AlgorithmPhaseShiftTwoFreq::get3DPoints(const SMCalibrationParameters & calibration, const std::vector<cv::Mat>& frames0, const std::vector<cv::Mat>& frames1, std::vector<cv::Point3f>& Q, std::vector<cv::Vec3b>& color){
|
4 |
jakw |
86 |
|
70 |
jakw |
87 |
assert(frames0.size() == N);
|
|
|
88 |
assert(frames1.size() == N);
|
|
|
89 |
|
233 |
- |
90 |
StereoRectifyier stereoRect;
|
|
|
91 |
getStereoRectifyier(calibration, cv::Size(frames0[0].cols, frames0[0].rows), stereoRect);
|
231 |
jakw |
92 |
|
233 |
- |
93 |
// // Erode occlusion masks
|
|
|
94 |
// cv::Mat strel = cv::getStructuringElement(cv::MORPH_ELLIPSE, cv::Size(5,5));
|
|
|
95 |
|
|
|
96 |
cv::Mat up0, up1;
|
|
|
97 |
cv::Mat occlusion0, occlusion1;
|
|
|
98 |
cv::Mat color0, color1;
|
|
|
99 |
|
|
|
100 |
#pragma omp parallel sections
|
231 |
jakw |
101 |
{
|
233 |
- |
102 |
#pragma omp section
|
|
|
103 |
{
|
70 |
jakw |
104 |
|
233 |
- |
105 |
// Gray-scale and remap/rectify
|
|
|
106 |
std::vector<cv::Mat> frames0Rect(N);
|
178 |
jakw |
107 |
|
233 |
- |
108 |
for(unsigned int i=0; i<N; i++){
|
|
|
109 |
cv::Mat temp;
|
|
|
110 |
cv::cvtColor(frames0[i], temp, CV_BayerBG2GRAY);
|
|
|
111 |
cv::remap(temp, frames0Rect[i], stereoRect.map0X, stereoRect.map0Y, CV_INTER_LINEAR);
|
|
|
112 |
}
|
207 |
flgw |
113 |
|
233 |
- |
114 |
// Occlusion masks
|
|
|
115 |
cv::subtract(frames0Rect[0], frames0Rect[1], occlusion0);
|
|
|
116 |
occlusion0 = (occlusion0 > 25) & (occlusion0 < 250);
|
182 |
jakw |
117 |
|
233 |
- |
118 |
// Decode camera0
|
|
|
119 |
std::vector<cv::Mat> frames0Primary(frames0Rect.begin()+2, frames0Rect.begin()+2+nStepsPrimary);
|
|
|
120 |
std::vector<cv::Mat> frames0Secondary(frames0Rect.begin()+2+nStepsPrimary, frames0Rect.end());
|
70 |
jakw |
121 |
|
233 |
- |
122 |
frames0Rect.clear();
|
182 |
jakw |
123 |
|
233 |
- |
124 |
cv::Mat amplitude0Primary, amplitude0Secondary;
|
|
|
125 |
cv::Mat up0Primary, up0Secondary;
|
|
|
126 |
cv::Mat energy0Primary, energy0Secondary;
|
|
|
127 |
determineAmplitudePhaseEnergy(frames0Primary,
|
|
|
128 |
amplitude0Primary, up0Primary, energy0Primary);
|
|
|
129 |
determineAmplitudePhaseEnergy(frames0Secondary,
|
|
|
130 |
amplitude0Secondary, up0Secondary, energy0Secondary);
|
207 |
flgw |
131 |
|
233 |
- |
132 |
collectPhases(up0Primary, up0Secondary, up0);
|
231 |
jakw |
133 |
|
233 |
- |
134 |
// Threshold on energy at primary frequency
|
|
|
135 |
occlusion0 = occlusion0 & (amplitude0Primary > 5.0*nStepsPrimary);
|
|
|
136 |
// Threshold on energy ratios
|
|
|
137 |
occlusion0 = occlusion0 & (amplitude0Primary > 0.25*energy0Primary);
|
|
|
138 |
occlusion0 = occlusion0 & (amplitude0Secondary > 0.25*energy0Secondary);
|
231 |
jakw |
139 |
|
233 |
- |
140 |
// // Erode occlusion masks
|
|
|
141 |
// cv::erode(occlusion0, occlusion0, strel);
|
231 |
jakw |
142 |
|
233 |
- |
143 |
// Threshold on gradient of phase
|
|
|
144 |
cv::Mat edges0;
|
|
|
145 |
cv::Sobel(up0, edges0, -1, 1, 1, 5);
|
|
|
146 |
occlusion0 = occlusion0 & (abs(edges0) < 10);
|
182 |
jakw |
147 |
|
233 |
- |
148 |
#ifdef SM_DEBUG
|
|
|
149 |
cvtools::writeMat(up0Primary, "up0Primary.mat", "up0Primary");
|
|
|
150 |
cvtools::writeMat(up0Secondary, "up0Secondary.mat", "up0Secondary");
|
|
|
151 |
cvtools::writeMat(up0, "up0.mat", "up0");
|
|
|
152 |
cvtools::writeMat(amplitude0Primary, "amplitude0Primary.mat", "amplitude0Primary");
|
|
|
153 |
cvtools::writeMat(amplitude0Secondary, "amplitude0Secondary.mat", "amplitude0Secondary");
|
|
|
154 |
cvtools::writeMat(energy0Primary, "energy0Primary.mat", "energy0Primary");
|
|
|
155 |
cvtools::writeMat(energy0Secondary, "energy0Secondary.mat", "energy0Secondary");
|
|
|
156 |
cvtools::writeMat(edges0, "edges0.mat", "edges0");
|
|
|
157 |
cvtools::writeMat(occlusion0, "occlusion0.mat", "occlusion0");
|
|
|
158 |
#endif
|
182 |
jakw |
159 |
|
233 |
- |
160 |
}
|
|
|
161 |
#pragma omp section
|
|
|
162 |
{
|
70 |
jakw |
163 |
|
233 |
- |
164 |
// Gray-scale and remap
|
|
|
165 |
std::vector<cv::Mat> frames1Rect(N);
|
200 |
jakw |
166 |
|
233 |
- |
167 |
for(unsigned int i=0; i<N; i++){
|
|
|
168 |
cv::Mat temp;
|
|
|
169 |
cv::cvtColor(frames1[i], temp, CV_BayerBG2GRAY);
|
|
|
170 |
cv::remap(temp, frames1Rect[i], stereoRect.map1X, stereoRect.map1Y, CV_INTER_LINEAR);
|
|
|
171 |
}
|
182 |
jakw |
172 |
|
233 |
- |
173 |
// Occlusion masks
|
|
|
174 |
cv::subtract(frames1Rect[0], frames1Rect[1], occlusion1);
|
|
|
175 |
occlusion1 = (occlusion1 > 25) & (occlusion1 < 250);
|
|
|
176 |
|
|
|
177 |
// Decode camera1
|
|
|
178 |
std::vector<cv::Mat> frames1Primary(frames1Rect.begin()+2, frames1Rect.begin()+2+nStepsPrimary);
|
|
|
179 |
std::vector<cv::Mat> frames1Secondary(frames1Rect.begin()+2+nStepsPrimary, frames1Rect.end());
|
|
|
180 |
|
|
|
181 |
frames1Rect.clear();
|
|
|
182 |
|
|
|
183 |
cv::Mat amplitude1Primary, amplitude1Secondary;
|
|
|
184 |
cv::Mat up1Primary, up1Secondary;
|
|
|
185 |
cv::Mat energy1Primary, energy1Secondary;
|
|
|
186 |
determineAmplitudePhaseEnergy(frames1Primary,
|
|
|
187 |
amplitude1Primary, up1Primary, energy1Primary);
|
|
|
188 |
determineAmplitudePhaseEnergy(frames1Secondary,
|
|
|
189 |
amplitude1Secondary, up1Secondary, energy1Secondary);
|
|
|
190 |
|
|
|
191 |
collectPhases(up1Primary, up1Secondary, up1);
|
|
|
192 |
|
|
|
193 |
// Threshold on energy at primary frequency
|
|
|
194 |
occlusion1 = occlusion1 & (amplitude1Primary > 5.0*nStepsPrimary);
|
|
|
195 |
// Threshold on energy ratios
|
|
|
196 |
occlusion1 = occlusion1 & (amplitude1Primary > 0.25*energy1Primary);
|
|
|
197 |
occlusion1 = occlusion1 & (amplitude1Secondary > 0.25*energy1Secondary);
|
|
|
198 |
|
|
|
199 |
// // Erode occlusion masks
|
|
|
200 |
// cv::erode(occlusion1, occlusion1, strel);
|
|
|
201 |
|
|
|
202 |
|
|
|
203 |
// Threshold on gradient of phase
|
|
|
204 |
cv::Mat edges1;
|
|
|
205 |
cv::Sobel(up1, edges1, -1, 1, 1, 5);
|
|
|
206 |
occlusion1 = occlusion1 & (abs(edges1) < 10);
|
|
|
207 |
|
|
|
208 |
#ifdef SM_DEBUG
|
|
|
209 |
cvtools::writeMat(up1Primary, "up1Primary.mat", "up1Primary");
|
|
|
210 |
cvtools::writeMat(up1Secondary, "up1Secondary.mat", "up1Secondary");
|
|
|
211 |
cvtools::writeMat(up1, "up1.mat", "up1");
|
|
|
212 |
cvtools::writeMat(amplitude1Primary, "amplitude1Primary.mat", "amplitude1Primary");
|
|
|
213 |
cvtools::writeMat(amplitude1Secondary, "amplitude1Secondary.mat", "amplitude1Secondary");
|
|
|
214 |
cvtools::writeMat(energy1Primary, "energy1Primary.mat", "energy1Primary");
|
|
|
215 |
cvtools::writeMat(energy1Secondary, "energy1Secondary.mat", "energy1Secondary");
|
|
|
216 |
cvtools::writeMat(edges1, "edges1.mat", "edges1");
|
|
|
217 |
cvtools::writeMat(occlusion1, "occlusion1.mat", "occlusion1");
|
|
|
218 |
#endif
|
|
|
219 |
|
|
|
220 |
}
|
182 |
jakw |
221 |
}
|
|
|
222 |
|
207 |
flgw |
223 |
|
233 |
- |
224 |
// Match phase maps
|
185 |
jakw |
225 |
|
233 |
- |
226 |
// camera0 against camera1
|
|
|
227 |
std::vector<cv::Vec2f> q0, q1;
|
|
|
228 |
matchPhaseMaps(occlusion0, occlusion1, up0, up1, q0, q1);
|
231 |
jakw |
229 |
|
233 |
- |
230 |
size_t nMatches = q0.size();
|
|
|
231 |
|
|
|
232 |
if(nMatches < 1){
|
|
|
233 |
Q.resize(0);
|
|
|
234 |
color.resize(0);
|
|
|
235 |
|
|
|
236 |
return;
|
231 |
jakw |
237 |
}
|
207 |
flgw |
238 |
{
|
233 |
- |
239 |
// color debayer and remap/rectify
|
182 |
jakw |
240 |
|
233 |
- |
241 |
cv::cvtColor(frames1[0], color1, CV_BayerBG2RGB);
|
|
|
242 |
cv::remap(color1, color1, stereoRect.map1X, stereoRect.map1Y, CV_INTER_LINEAR);
|
207 |
flgw |
243 |
|
233 |
- |
244 |
#ifdef SM_DEBUG
|
|
|
245 |
cvtools::writeMat(color0, "color0.mat", "color0");
|
|
|
246 |
cvtools::writeMat(color1, "color1.mat", "color1");
|
|
|
247 |
#endif
|
|
|
248 |
|
|
|
249 |
// Retrieve color information
|
|
|
250 |
color.resize(nMatches);
|
|
|
251 |
for(unsigned int i=0; i<nMatches; i++){
|
|
|
252 |
|
|
|
253 |
cv::Vec3b c0 = color0.at<cv::Vec3b>(int(q0[i][1]), int(q0[i][0]));
|
|
|
254 |
cv::Vec3b c1 = color1.at<cv::Vec3b>(int(q1[i][1]), int(q1[i][0]));
|
|
|
255 |
|
|
|
256 |
color[i] = 0.5*c0 + 0.5*c1;
|
|
|
257 |
}
|
231 |
jakw |
258 |
}
|
207 |
flgw |
259 |
|
233 |
- |
260 |
// Triangulate points
|
|
|
261 |
triangulate(stereoRect, q0, q1, Q);
|
207 |
flgw |
262 |
|
233 |
- |
263 |
}
|
207 |
flgw |
264 |
|
233 |
- |
265 |
void getStereoRectifyier(const SMCalibrationParameters &calibration, const cv::Size& frameSize, StereoRectifyier& stereoRect){
|
231 |
jakw |
266 |
|
233 |
- |
267 |
// cv::stereoRectify segfaults unless R is double precision
|
|
|
268 |
cv::Mat R, T;
|
|
|
269 |
cv::Mat(calibration.R1).convertTo(R, CV_64F);
|
|
|
270 |
cv::Mat(calibration.T1).convertTo(T, CV_64F);
|
182 |
jakw |
271 |
|
233 |
- |
272 |
cv::stereoRectify(calibration.K0, calibration.k0,
|
|
|
273 |
calibration.K1, calibration.k1,
|
|
|
274 |
frameSize, R, T,
|
|
|
275 |
stereoRect.R0, stereoRect.R1,
|
|
|
276 |
stereoRect.P0, stereoRect.P1,
|
|
|
277 |
stereoRect.QRect, 0);
|
182 |
jakw |
278 |
|
233 |
- |
279 |
// Interpolation maps (lens distortion and rectification)
|
|
|
280 |
cv::initUndistortRectifyMap(calibration.K0, calibration.k0,
|
|
|
281 |
stereoRect.R0, stereoRect.P0,
|
|
|
282 |
frameSize, CV_32F,
|
|
|
283 |
stereoRect.map0X, stereoRect.map0Y);
|
|
|
284 |
cv::initUndistortRectifyMap(calibration.K1, calibration.k1,
|
|
|
285 |
stereoRect.R1, stereoRect.P1,
|
|
|
286 |
frameSize, CV_32F,
|
|
|
287 |
stereoRect.map1X, stereoRect.map1Y);
|
|
|
288 |
}
|
70 |
jakw |
289 |
|
233 |
- |
290 |
void determineAmplitudePhaseEnergy(std::vector<cv::Mat>& frames,
|
|
|
291 |
cv::Mat& amplitude, cv::Mat& phase, cv::Mat& energy) {
|
|
|
292 |
|
|
|
293 |
std::vector<cv::Mat> fourier = getDFTComponents(frames);
|
|
|
294 |
|
|
|
295 |
cv::phase(fourier[2], -fourier[3], phase);
|
|
|
296 |
|
200 |
jakw |
297 |
// Signal energy at unit frequency
|
233 |
- |
298 |
cv::magnitude(fourier[2], -fourier[3], amplitude);
|
200 |
jakw |
299 |
|
182 |
jakw |
300 |
// Collected signal energy at higher frequencies
|
233 |
- |
301 |
energy = cv::Mat(phase.rows, phase.cols, CV_32F, cv::Scalar(0.0));
|
182 |
jakw |
302 |
|
233 |
- |
303 |
for(unsigned int i=0; i<frames.size()-1; i++){
|
182 |
jakw |
304 |
cv::Mat magnitude;
|
233 |
- |
305 |
cv::magnitude(fourier[i*2 + 2], fourier[i*2 + 3], magnitude);
|
|
|
306 |
cv::add(energy, magnitude, energy, cv::noArray(), CV_32F);
|
182 |
jakw |
307 |
}
|
|
|
308 |
|
233 |
- |
309 |
frames.clear();
|
|
|
310 |
}
|
70 |
jakw |
311 |
|
233 |
- |
312 |
void collectPhases(const cv::Mat& phasePrimary, const cv::Mat& phaseSecondary,
|
|
|
313 |
cv::Mat& phase) {
|
|
|
314 |
cv::Mat phaseEquivalent = phaseSecondary - phasePrimary;
|
|
|
315 |
phaseEquivalent = cvtools::modulo(phaseEquivalent, 2.0*CV_PI);
|
|
|
316 |
phase = unwrapWithCue(phasePrimary, phaseEquivalent, nPeriodsPrimary);
|
|
|
317 |
phase *= phasePrimary.cols/(2.0*CV_PI);
|
|
|
318 |
}
|
207 |
flgw |
319 |
|
231 |
jakw |
320 |
|
233 |
- |
321 |
void matchPhaseMaps(const cv::Mat& occlusion0, const cv::Mat& occlusion1,
|
|
|
322 |
const cv::Mat& phase0, const cv::Mat& phase1,
|
|
|
323 |
std::vector<cv::Vec2f>& q0, std::vector<cv::Vec2f>& q1) {
|
231 |
jakw |
324 |
|
|
|
325 |
#pragma omp parallel for
|
233 |
- |
326 |
for(int row=0; row<occlusion0.rows; row++){
|
|
|
327 |
for(int col=0; col<occlusion0.cols; col++){
|
70 |
jakw |
328 |
|
178 |
jakw |
329 |
if(!occlusion0.at<char>(row,col))
|
70 |
jakw |
330 |
continue;
|
|
|
331 |
|
233 |
- |
332 |
float phase0i = phase0.at<float>(row,col);
|
|
|
333 |
for(int col1=0; col1<phase1.cols-1; col1++){
|
70 |
jakw |
334 |
|
178 |
jakw |
335 |
if(!occlusion1.at<char>(row,col1) || !occlusion1.at<char>(row,col1+1))
|
70 |
jakw |
336 |
continue;
|
|
|
337 |
|
233 |
- |
338 |
float phase1Left = phase1.at<float>(row,col1);
|
|
|
339 |
float phase1Right = phase1.at<float>(row,col1+1);
|
70 |
jakw |
340 |
|
233 |
- |
341 |
bool match = (phase1Left <= phase0i)
|
|
|
342 |
&& (phase0i <= phase1Right)
|
|
|
343 |
&& (phase0i-phase1Left < 1.0)
|
|
|
344 |
&& (phase1Right-phase0i < 1.0)
|
|
|
345 |
&& (phase1Right-phase1Left > 0.1);
|
70 |
jakw |
346 |
|
233 |
- |
347 |
if(match){
|
70 |
jakw |
348 |
|
233 |
- |
349 |
float col1i = col1 + (phase0i-phase1Left)/(phase1Right-phase1Left);
|
|
|
350 |
|
231 |
jakw |
351 |
#pragma omp critical
|
|
|
352 |
{
|
178 |
jakw |
353 |
q0.push_back(cv::Point2f(col, row));
|
|
|
354 |
q1.push_back(cv::Point2f(col1i, row));
|
231 |
jakw |
355 |
}
|
71 |
jakw |
356 |
break;
|
70 |
jakw |
357 |
}
|
|
|
358 |
}
|
|
|
359 |
}
|
|
|
360 |
}
|
|
|
361 |
|
207 |
flgw |
362 |
}
|
70 |
jakw |
363 |
|
233 |
- |
364 |
void triangulate(const StereoRectifyier& stereoRect,
|
|
|
365 |
const std::vector<cv::Vec2f>& q0,
|
|
|
366 |
const std::vector<cv::Vec2f>& q1,
|
|
|
367 |
std::vector<cv::Point3f>& Q) {
|
70 |
jakw |
368 |
|
233 |
- |
369 |
// cv::Mat QMatHomogenous, QMat;
|
|
|
370 |
// cv::triangulatePoints(P0, P1, q0, q1, QMatHomogenous);
|
|
|
371 |
// cvtools::convertMatFromHomogeneous(QMatHomogenous, QMat);
|
70 |
jakw |
372 |
|
233 |
- |
373 |
// // Undo rectification
|
|
|
374 |
// cv::Mat R0Inv;
|
|
|
375 |
// cv::Mat(R0.t()).convertTo(R0Inv, CV_32F);
|
|
|
376 |
// QMat = R0Inv*QMat;
|
230 |
jakw |
377 |
|
233 |
- |
378 |
// cvtools::matToPoints3f(QMat, Q);
|
231 |
jakw |
379 |
|
|
|
380 |
|
|
|
381 |
// Triangulate by means of disparity projection
|
|
|
382 |
Q.resize(q0.size());
|
233 |
- |
383 |
cv::Matx44f QRectx = cv::Matx44f(stereoRect.QRect);
|
|
|
384 |
cv::Matx33f R0invx = cv::Matx33f(cv::Mat(stereoRect.R0.t()));
|
231 |
jakw |
385 |
|
|
|
386 |
#pragma omp parallel for
|
233 |
- |
387 |
for(unsigned int i=0; i < q0.size(); i++){
|
|
|
388 |
float disparity = q0[i][0] - q1[i][0];
|
231 |
jakw |
389 |
cv::Vec4f Qih = QRectx*cv::Vec4f(q0[i][0], q0[i][1], disparity, 1.0);
|
233 |
- |
390 |
float winv = float(1.0) / Qih[3];
|
231 |
jakw |
391 |
Q[i] = R0invx * cv::Point3f(Qih[0]*winv, Qih[1]*winv, Qih[2]*winv);
|
|
|
392 |
}
|
4 |
jakw |
393 |
}
|