00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046 #include <new>
00047
00048 #include "StereoMatcher.h"
00049
00050 #include "Image/ByteImage.h"
00051 #include "Calibration/StereoCalibration.h"
00052 #include "Calibration/Calibration.h"
00053 #include "Math/Math2d.h"
00054 #include "Math/Math3d.h"
00055
00056 #include <stdlib.h>
00057 #include <math.h>
00058 #include <stdio.h>
00059 #include <float.h>
00060
00061
00062
00063
00064
00065
00066
00067 CStereoMatcher::CStereoMatcher()
00068 {
00069 m_pStereoCalibration = new CStereoCalibration();
00070 m_bOwnStereoCalibrationObject = true;
00071 }
00072
00073 CStereoMatcher::~CStereoMatcher()
00074 {
00075 if (m_bOwnStereoCalibrationObject)
00076 delete m_pStereoCalibration;
00077 }
00078
00079
00080
00081
00082
00083
00084 bool CStereoMatcher::LoadCameraParameters(const char *pFileName)
00085 {
00086 if (!m_bOwnStereoCalibrationObject)
00087 m_pStereoCalibration = new CStereoCalibration();
00088
00089 return m_pStereoCalibration->LoadCameraParameters(pFileName);
00090 }
00091
00092 void CStereoMatcher::InitCameraParameters(CStereoCalibration *pStereoCalibration, bool bCloneCalibration)
00093 {
00094 if (bCloneCalibration)
00095 {
00096 if (!m_bOwnStereoCalibrationObject)
00097 m_pStereoCalibration = new CStereoCalibration();
00098
00099 m_pStereoCalibration->Set(*pStereoCalibration);
00100 m_bOwnStereoCalibrationObject = true;
00101 }
00102 else
00103 {
00104 if (m_bOwnStereoCalibrationObject)
00105 delete m_pStereoCalibration;
00106
00107 m_pStereoCalibration = pStereoCalibration;
00108 m_bOwnStereoCalibrationObject = false;
00109 }
00110 }
00111
00112 int CStereoMatcher::GetDisparityEstimate(const float z)
00113 {
00114 const Vec3d z_vector = { 0, 0, z };
00115 Vec3d p;
00116 m_pStereoCalibration->GetLeftCalibration()->CameraToWorldCoordinates(z_vector, p);
00117
00118 Vec2d left, right;
00119 m_pStereoCalibration->GetLeftCalibration()->WorldToImageCoordinates(p, left, false);
00120 m_pStereoCalibration->GetRightCalibration()->WorldToImageCoordinates(p, right, false);
00121
00122 return int(fabsf(left.x - right.x));
00123 }
00124
00125 int CStereoMatcher::Match(const CByteImage *pLeftImage, const CByteImage *pRightImage, int x, int y, int nWindowSize,
00126 int d1, int d2, Vec2d &result, Vec3d &result_3d, float fThreshold, bool bInputImagesAreUndistorted)
00127 {
00128 if (pLeftImage->width != pRightImage->width || pLeftImage->height != pRightImage->height ||
00129 pLeftImage->type != CByteImage::eGrayScale || pRightImage->type != CByteImage::eGrayScale)
00130 {
00131 printf("error: input images do not match for CStereoMatcher::Match\n");
00132 return -100000;
00133 }
00134
00135 float *values_ = new float[4 * pLeftImage->width];
00136 float *values = values_ + 2 * pLeftImage->width;
00137
00138 int best_d = SingleZNCC(pLeftImage, pRightImage, x, y, nWindowSize, d1 - 1, d2 + 1, values);
00139
00140 if (best_d > -100000 && best_d >= d1 && best_d <= d2 && values[best_d] > fThreshold)
00141 {
00142 const float y0 = values[best_d - 1];
00143 const float y1 = values[best_d];
00144 const float y2 = values[best_d + 1];
00145 const float xmin = (y0 - y2) / (2.0f * (y0 - 2.0f * y1 + y2));
00146 const float disparity = fabsf(xmin) < 0.5f ? best_d + xmin : best_d;
00147
00148 float m, c;
00149 const Vec2d point_left = { float(x), float(y) };
00150 m_pStereoCalibration->CalculateEpipolarLineInRightImage(point_left, m, c);
00151
00152 result.x = x - disparity;
00153 result.y = m * (x - disparity) + c;
00154
00155 m_pStereoCalibration->Calculate3DPoint(point_left, result, result_3d, false, !bInputImagesAreUndistorted);
00156 }
00157 else
00158 {
00159
00160 if (best_d > -100000 && best_d >= d1 && best_d <= d2)
00161 best_d = -100003;
00162 }
00163
00164 delete [] values_;
00165
00166 return best_d;
00167 }
00168
00169 int CStereoMatcher::MatchZSAD(const CByteImage *pLeftImage, const CByteImage *pRightImage, int x, int y, int nWindowSize,
00170 int d1, int d2, Vec2d &result, Vec3d &result_3d, float fThreshold, bool bInputImagesAreUndistorted)
00171 {
00172 if (pLeftImage->width != pRightImage->width || pLeftImage->height != pRightImage->height ||
00173 pLeftImage->type != CByteImage::eGrayScale || pRightImage->type != CByteImage::eGrayScale)
00174 {
00175 printf("error: input images do not match for CStereoMatcher::MatchSAD\n");
00176 return -100000;
00177 }
00178
00179 float *values_ = new float[4 * pLeftImage->width];
00180 float *values = values_ + 2 * pLeftImage->width;
00181
00182 int best_d = SingleZSAD(pLeftImage, pRightImage, x, y, nWindowSize, d1 - 1, d2 + 1, values);
00183
00184 if (best_d > -100000 && best_d >= d1 && best_d <= d2 && 255.0f * values[best_d] < fThreshold)
00185 {
00186 const float y0 = values[best_d - 1];
00187 const float y1 = values[best_d];
00188 const float y2 = values[best_d + 1];
00189 const float xmin = (y0 - y2) / (2.0f * (y0 - 2.0f * y1 + y2));
00190 const float disparity = fabsf(xmin) < 0.5f ? best_d + xmin : best_d;
00191
00192 float m, c;
00193 const Vec2d point_left = { float(x), float(y) };
00194 m_pStereoCalibration->CalculateEpipolarLineInRightImage(point_left, m, c);
00195
00196 result.x = x - disparity;
00197 result.y = m * (x - disparity) + c;
00198
00199 m_pStereoCalibration->Calculate3DPoint(point_left, result, result_3d, false, !bInputImagesAreUndistorted);
00200 }
00201 else
00202 {
00203
00204 if (best_d > -100000 && best_d >= d1 && best_d <= d2)
00205 best_d = -100003;
00206 }
00207
00208 delete [] values_;
00209
00210 return best_d;
00211 }
00212
00213
00214 int CStereoMatcher::SingleZNCC(const CByteImage *pInputImageLeft, const CByteImage *pInputImageRight, int x, int y, int nWindowSize, int d1, int d2, float *values)
00215 {
00216 const int width = pInputImageLeft->width;
00217 const int height = pInputImageLeft->height;
00218 const int w2 = nWindowSize / 2;
00219
00220 if (x < w2 || x >= width - w2 || y < w2 || y >= height - w2)
00221 return -100001;
00222
00223 const unsigned char *input_left = pInputImageLeft->pixels;
00224 const unsigned char *input_right = pInputImageRight->pixels;
00225 const int nVectorLength = nWindowSize * nWindowSize;
00226
00227 float *vector1 = new float[nVectorLength];
00228 float *vector2 = new float[nVectorLength];
00229
00230 const int offset = (y - w2) * width + (x - w2);
00231 const int diff = width - nWindowSize;
00232 const Vec2d camera_point = { float(x), float(y) };
00233
00234
00235 float mean = 0.0f;
00236 for (int yy = 0, offset2 = offset, offset3 = 0; yy < nWindowSize; yy++, offset2 += diff)
00237 for (int x = 0; x < nWindowSize; x++, offset2++, offset3++)
00238 {
00239 vector1[offset3] = input_left[offset2];
00240 mean += vector1[offset3];
00241 }
00242 mean /= nVectorLength;
00243
00244
00245 int k;
00246 float factor = 0.0f;
00247 for (k = 0; k < nVectorLength; k++)
00248 {
00249 vector1[k] -= mean;
00250 factor += vector1[k] * vector1[k];
00251 }
00252
00253 if (factor < 60 * nVectorLength)
00254 {
00255 delete [] vector1;
00256 delete [] vector2;
00257 return -100002;
00258 }
00259
00260 factor = 1.0f / sqrtf(factor);
00261 for (k = 0; k < nVectorLength; k++)
00262 vector1[k] *= factor;
00263
00264 float best_value = -FLT_MAX;
00265 int d, best_d = -100004;
00266
00267 const int max_d = d2 < x ? d2 : x;
00268
00269 float m, c;
00270 m_pStereoCalibration->CalculateEpipolarLineInRightImage(camera_point, m, c);
00271
00272
00273 for (d = d1; d <= max_d; d++)
00274 {
00275 const int xx = x - d;
00276 const int yy = int(m * xx + c + 0.5f);
00277
00278 if (xx < w2 || xx >= width - w2 || yy < w2 || yy >= height - w2)
00279 continue;
00280
00281 const int offset_right = (yy - w2) * width + (xx - w2);
00282
00283
00284 float mean = 0.0f;
00285 for (int y = 0, offset2 = offset_right, offset3 = 0; y < nWindowSize; y++, offset2 += diff)
00286 for (int x = 0; x < nWindowSize; x++, offset2++, offset3++)
00287 {
00288 vector2[offset3] = input_right[offset2];
00289 mean += vector2[offset3];
00290
00291 }
00292 mean /= nVectorLength;
00293
00294
00295 float factor = 0.0f;
00296 for (k = 0; k < nVectorLength; k++)
00297 {
00298 vector2[k] -= mean;
00299 factor += vector2[k] * vector2[k];
00300 }
00301
00302 if (factor < 60 * nVectorLength)
00303 continue;
00304
00305 factor = 1.0f / sqrtf(factor);
00306 for (k = 0; k < nVectorLength; k++)
00307 vector2[k] *= factor;
00308
00309 float value = 0.0f;
00310 for (k = 0; k < nVectorLength; k++)
00311 value += vector1[k] * vector2[k];
00312
00313
00314 values[d] = value;
00315
00316
00317 if (value > best_value)
00318 {
00319 best_value = value;
00320 best_d = d;
00321 }
00322 }
00323
00324 delete [] vector1;
00325 delete [] vector2;
00326
00327 return best_d;
00328 }
00329
00330 int CStereoMatcher::SingleZSAD(const CByteImage *pInputImageLeft, const CByteImage *pInputImageRight, int x, int y, int nWindowSize, int d1, int d2, float *values)
00331 {
00332 const int width = pInputImageLeft->width;
00333 const int height = pInputImageLeft->height;
00334 const int w2 = nWindowSize / 2;
00335
00336 if (x < w2 || x >= width - w2 || y < w2 || y >= height - w2)
00337 return -100001;
00338
00339 const unsigned char *input_left = pInputImageLeft->pixels;
00340 const unsigned char *input_right = pInputImageRight->pixels;
00341 const int nVectorLength = nWindowSize * nWindowSize;
00342
00343 int *vector1 = new int[nVectorLength];
00344 int *vector2 = new int[nVectorLength];
00345
00346 const int offset = (y - w2) * width + (x - w2);
00347 const int diff = width - nWindowSize;
00348 const Vec2d camera_point = { float(x), float(y) };
00349
00350
00351 int mean1 = 0;
00352 for (int yy = 0, offset2 = offset, offset3 = 0; yy < nWindowSize; yy++, offset2 += diff)
00353 for (int x = 0; x < nWindowSize; x++, offset2++, offset3++)
00354 {
00355 vector1[offset3] = input_left[offset2];
00356 mean1 += vector1[offset3];
00357 }
00358 mean1 /= nVectorLength;
00359
00360
00361 float best_value = FLT_MAX;
00362 int d, best_d = -100004;
00363
00364 const int max_d = d2 < x ? d2 : x;
00365
00366 float m, c;
00367 m_pStereoCalibration->CalculateEpipolarLineInRightImage(camera_point, m, c);
00368
00369
00370 for (d = d1; d <= max_d; d++)
00371 {
00372 const int xx = x - d;
00373 const int yy = int(m * xx + c + 0.5f);
00374
00375 if (xx < w2 || xx >= width - w2 || yy < w2 || yy >= height - w2)
00376 continue;
00377
00378 const int offset_right = (yy - w2) * width + (xx - w2);
00379
00380
00381 int mean2 = 0;
00382 for (int y = 0, offset2 = offset_right, offset3 = 0; y < nWindowSize; y++, offset2 += diff)
00383 for (int x = 0; x < nWindowSize; x++, offset2++, offset3++)
00384 {
00385 vector2[offset3] = input_right[offset2];
00386 mean2 += vector2[offset3];
00387
00388 }
00389 mean2 /= nVectorLength;
00390
00391 int value_int = 0;
00392 for (int k = 0; k < nVectorLength; k++)
00393 value_int += abs((vector1[k] - mean1) - (vector2[k] - mean2));
00394 const float value = float(value_int) / (nVectorLength * 255.0f);
00395
00396
00397 values[d] = value;
00398
00399
00400 if (value < best_value)
00401 {
00402 best_value = value;
00403 best_d = d;
00404 }
00405 }
00406
00407 delete [] vector1;
00408 delete [] vector2;
00409
00410 return best_d;
00411 }