27 #include <opencv2/opencv.hpp>
31 #include <Math/Math3d.h>
32 #include <Image/ByteImage.h>
33 #include <Image/ImageProcessor.h>
34 #include <Image/IplImageAdaptor.h>
35 #include <Image/StereoMatcher.h>
36 #include <Calibration/StereoCalibration.h>
37 #include <Calibration/Calibration.h>
38 #include <Calibration/Rectification.h>
39 #include <Threading/Threading.h>
41 #include <opencv2/calib3d.hpp>
50 static void doStereoSGBM(
int minDisparity,
int numDisparities,
int nSADWindowSize,
int P1,
int P2,
int disp12MaxDiff,
51 cv::Mat leftInput, cv::Mat rightInput, cv::Mat output)
54 int uniquenessRatio = 0;
55 int speckleWindowSize = 0;
57 #if CV_MAJOR_VERSION == 2
59 cv::StereoSGBM stereoSGBM(minDisparity, numDisparities, nSADWindowSize, P1, P2, disp12MaxDiff, preFilterCap, uniquenessRatio, speckleWindowSize, speckleRange, fullDP);
60 stereoSGBM(leftInput, rightInput, output);
62 cv::Ptr<cv::StereoSGBM> stereoSGBM = cv::StereoSGBM::create(minDisparity, numDisparities, nSADWindowSize, P1, P2, disp12MaxDiff, preFilterCap, uniquenessRatio, speckleWindowSize, speckleRange, cv::StereoSGBM::MODE_SGBM);
63 stereoSGBM->compute(leftInput, rightInput, output);
67 void GetPointsFromDisparity(
const CByteImage* pImageLeftColor,
const CByteImage* pImageRightColor,
const CByteImage* pImageLeftGrey,
const CByteImage* pImageRightGrey,
68 const int nDisparityPointDistance, pcl::PointCloud<pcl::PointXYZRGBA>& aPointsFromDisparity, CByteImage* pDisparityImage,
69 const int imageWidth,
const int imageHeight, CStereoCalibration* pStereoCalibration,
bool imagesAreUndistorted,
const bool smoothDisparities)
72 CByteImage* pRectifiedImageLeftGrey, *pRectifiedImageRightGrey, *pRectifiedImageLeftGreyHalfsize, *pRectifiedImageRightGreyHalfsize, *pRectifiedImageLeftGreyQuartersize, *pRectifiedImageRightGreyQuartersize;
73 IplImage* pRectifiedIplImageLeft, *pRectifiedIplImageRight, *pRectifiedIplImageLeftHalfsize, *pRectifiedIplImageRightHalfsize, *pRectifiedIplImageLeftQuartersize, *pRectifiedIplImageRightQuartersize;
74 CByteImage* pRectifiedImageLeftColorGaussFiltered;
75 cv::Mat mDispImg, mDispImgHalfsize, mDispImgQuartersize;
76 bool bGreyImagesReady =
false;
77 bool bGreyImagesHalfsizeReady =
false;
78 bool bGreyImagesQuartersizeReady =
false;
79 const int nPenaltyDispDiffOneFactor = 8;
80 const int nPenaltyDispDiffBiggerOneFactor = 32;
82 CStereoMatcher* pStereoMatcher =
new CStereoMatcher();
83 CStereoCalibration* pStereoCalibrationCopy =
new CStereoCalibration(*pStereoCalibration);
84 pStereoMatcher->InitCameraParameters(pStereoCalibrationCopy,
false);
86 const int nDispMin = pStereoMatcher->GetDisparityEstimate(8000);
87 const int nDispMax = pStereoMatcher->GetDisparityEstimate(400);
89 const int imageOverlapCutoffLeft = 0;
90 const int imageOverlapCutoffRight = 0;
91 const int imageOverlapCutoffTop = 0;
92 const int imageOverlapCutoffBottom = 0;
94 const bool fillHoles =
false;
97 #pragma omp parallel sections
101 const CByteImage* ppOriginalImages[2];
102 ppOriginalImages[0] = pImageLeftGrey;
103 ppOriginalImages[1] = pImageRightGrey;
104 pRectifiedImageLeftGrey =
new CByteImage(imageWidth, imageHeight, CByteImage::eGrayScale);
105 pRectifiedImageRightGrey =
new CByteImage(imageWidth, imageHeight, CByteImage::eGrayScale);
106 CByteImage* ppRectifiedImages[2];
107 ppRectifiedImages[0] = pRectifiedImageLeftGrey;
108 ppRectifiedImages[1] = pRectifiedImageRightGrey;
110 CRectification* pRectification =
new CRectification(
true, !imagesAreUndistorted);
111 pRectification->Init(pStereoCalibration);
112 pRectification->Rectify(ppOriginalImages, ppRectifiedImages);
114 pRectifiedIplImageLeft = IplImageAdaptor::Adapt(pRectifiedImageLeftGrey);
115 pRectifiedIplImageRight = IplImageAdaptor::Adapt(pRectifiedImageRightGrey);
116 bGreyImagesReady =
true;
119 pRectifiedImageLeftGreyHalfsize =
new CByteImage(imageWidth / 2, imageHeight / 2, CByteImage::eGrayScale);
120 pRectifiedImageRightGreyHalfsize =
new CByteImage(imageWidth / 2, imageHeight / 2, CByteImage::eGrayScale);
121 ::ImageProcessor::Resize(pRectifiedImageLeftGrey, pRectifiedImageLeftGreyHalfsize);
122 ::ImageProcessor::Resize(pRectifiedImageRightGrey, pRectifiedImageRightGreyHalfsize);
124 pRectifiedIplImageLeftHalfsize = IplImageAdaptor::Adapt(pRectifiedImageLeftGreyHalfsize);
125 pRectifiedIplImageRightHalfsize = IplImageAdaptor::Adapt(pRectifiedImageRightGreyHalfsize);
126 bGreyImagesHalfsizeReady =
true;
129 pRectifiedImageLeftGreyQuartersize =
new CByteImage(imageWidth / 4, imageHeight / 4, CByteImage::eGrayScale);
130 pRectifiedImageRightGreyQuartersize =
new CByteImage(imageWidth / 4, imageHeight / 4, CByteImage::eGrayScale);
131 ::ImageProcessor::Resize(pRectifiedImageLeftGrey, pRectifiedImageLeftGreyQuartersize);
132 ::ImageProcessor::Resize(pRectifiedImageRightGrey, pRectifiedImageRightGreyQuartersize);
134 pRectifiedIplImageLeftQuartersize = IplImageAdaptor::Adapt(pRectifiedImageLeftGreyQuartersize);
135 pRectifiedIplImageRightQuartersize = IplImageAdaptor::Adapt(pRectifiedImageRightGreyQuartersize);
136 bGreyImagesQuartersizeReady =
true;
138 delete pRectification;
143 const CByteImage* ppOriginalImages[2];
144 ppOriginalImages[0] = pImageLeftColor;
145 ppOriginalImages[1] = pImageRightColor;
146 CByteImage* pRectifiedImageLeftColor =
new CByteImage(imageWidth, imageHeight, CByteImage::eRGB24);
147 CByteImage* pRectifiedImageRightColor =
new CByteImage(imageWidth, imageHeight, CByteImage::eRGB24);
148 CByteImage* ppRectifiedImages[2];
149 ppRectifiedImages[0] = pRectifiedImageLeftColor;
150 ppRectifiedImages[1] = pRectifiedImageRightColor;
152 CRectification* pRectification =
new CRectification(
true, !imagesAreUndistorted);
153 pRectification->Init(pStereoCalibration);
154 pRectification->Rectify(ppOriginalImages, ppRectifiedImages);
156 pRectifiedImageLeftColorGaussFiltered =
new CByteImage(imageWidth, imageHeight, CByteImage::eRGB24);
157 ::ImageProcessor::GaussianSmooth3x3(pRectifiedImageLeftColor, pRectifiedImageLeftColorGaussFiltered);
159 delete pRectifiedImageLeftColor;
160 delete pRectifiedImageRightColor;
161 delete pRectification;
169 while (!bGreyImagesReady)
171 Threading::YieldThread();
188 const cv::Mat mLeftImg = cv::cvarrToMat(pRectifiedIplImageLeft);
189 const cv::Mat mRightImg = cv::cvarrToMat(pRectifiedIplImageRight);
190 const int nSADWindowSize = 7;
191 const int nPenaltyDispDiffOne = nPenaltyDispDiffOneFactor * 3 * nSADWindowSize * nSADWindowSize;
192 const int nPenaltyDispDiffBiggerOne = nPenaltyDispDiffBiggerOneFactor * 3 * nSADWindowSize * nSADWindowSize;
194 doStereoSGBM(1, 8 * 16, nSADWindowSize, nPenaltyDispDiffOne, nPenaltyDispDiffBiggerOne, 4, mLeftImg, mRightImg, mDispImg);
200 while (!bGreyImagesHalfsizeReady)
202 Threading::YieldThread();
205 const cv::Mat mLeftImg = cv::cvarrToMat(pRectifiedIplImageLeftHalfsize);
206 const cv::Mat mRightImg = cv::cvarrToMat(pRectifiedIplImageRightHalfsize);
207 const int nSADWindowSize = 7;
208 const int nPenaltyDispDiffOne = nPenaltyDispDiffOneFactor * 3 * nSADWindowSize * nSADWindowSize;
209 const int nPenaltyDispDiffBiggerOne = nPenaltyDispDiffBiggerOneFactor * 3 * nSADWindowSize * nSADWindowSize;
210 doStereoSGBM(1, 4 * 16, nSADWindowSize, nPenaltyDispDiffOne, nPenaltyDispDiffBiggerOne, 4, mLeftImg, mRightImg, mDispImgHalfsize);
216 while (!bGreyImagesQuartersizeReady)
218 Threading::YieldThread();
221 const cv::Mat mLeftImg = cv::cvarrToMat(pRectifiedIplImageLeftQuartersize);
222 const cv::Mat mRightImg = cv::cvarrToMat(pRectifiedIplImageRightQuartersize);
223 const int nSADWindowSize = 7;
224 const int nPenaltyDispDiffOne = nPenaltyDispDiffOneFactor * 3 * nSADWindowSize * nSADWindowSize;
225 const int nPenaltyDispDiffBiggerOne = nPenaltyDispDiffBiggerOneFactor * 3 * nSADWindowSize * nSADWindowSize;
227 doStereoSGBM(1, 4 * 16, nSADWindowSize, nPenaltyDispDiffOne, nPenaltyDispDiffBiggerOne, 4, mLeftImg, mRightImg, mDispImgQuartersize);
233 float* pDisparities =
new float[imageWidth * imageHeight];
234 #pragma omp parallel for schedule(static, 80)
235 for (
int i = 0; i < imageHeight; i++)
237 for (
int j = 0; j < imageWidth; j++)
239 int nDispFullsize = mDispImg.at<
short>(i, j) / 16;
240 int nDispHalfsize = 2 * mDispImgHalfsize.at<
short>(i / 2, j / 2) / 16;
241 int nDispQuartersize = 4 * mDispImgQuartersize.at<
short>(i / 4, j / 4) / 16;
245 int nNumValidDisparities = 0;
247 if ((nDispFullsize > nDispMin) && (nDispFullsize < nDispMax))
249 nDisp += nDispFullsize;
250 nNumValidDisparities++;
253 if ((nDispHalfsize > nDispMin) && (nDispHalfsize < nDispMax))
255 nDisp += nDispHalfsize;
256 nNumValidDisparities++;
259 if ((nDispQuartersize > nDispMin) && (nDispQuartersize < nDispMax))
261 nDisp += nDispQuartersize;
262 nNumValidDisparities++;
265 if (nNumValidDisparities > 0)
267 fDisp = (
float)nDisp / (
float)nNumValidDisparities;
270 pDisparities[i * imageWidth + j] = fDisp;
278 std::vector<int> pDisparitiesCopy(imageWidth * imageHeight);
280 for (
int i = 0; i < imageHeight * imageWidth; i++)
282 pDisparitiesCopy[i] = pDisparities[i];
285 const int nMargin = 10;
286 const int nHoleFillingAveragingRadius = 5;
288 for (
int i = nMargin; i < imageHeight - nMargin; i++)
290 for (
int j = nMargin; j < imageWidth - nMargin; j++)
292 if (pDisparitiesCopy[i * imageWidth + j] == 0)
295 int nNumValidDisparities = 0;
297 for (
int k = -nHoleFillingAveragingRadius; k <= nHoleFillingAveragingRadius; k++)
299 for (
int l = -nHoleFillingAveragingRadius; l <= nHoleFillingAveragingRadius; l++)
301 if (pDisparitiesCopy[(i + k)*imageWidth + (j + l)] > 0)
303 nSum += pDisparitiesCopy[(i + k) * imageWidth + (j + l)];
304 nNumValidDisparities++;
309 if (nNumValidDisparities > 0)
311 pDisparities[i * imageWidth + j] = nSum / nNumValidDisparities;
321 float* pSmoothedDisparity = pDisparities;
323 if (smoothDisparities)
325 pSmoothedDisparity =
new float[imageWidth * imageHeight];
326 float* pSmoothedDisparity1 =
new float[imageWidth * imageHeight];
327 float* pSmoothedDisparity2 =
new float[imageWidth * imageHeight];
328 float* pSmoothedDisparity3 =
new float[imageWidth * imageHeight];
329 float* pSmoothedDisparity4 =
new float[imageWidth * imageHeight];
331 #pragma omp parallel sections
354 for (
int i = 0; i < imageWidth * imageHeight; i++)
356 pSmoothedDisparity[i] = 0.8f * pDisparities[i] + 0.15f * pSmoothedDisparity1[i] + 0.05f * pSmoothedDisparity2[i];
359 delete[] pSmoothedDisparity1;
360 delete[] pSmoothedDisparity2;
361 delete[] pSmoothedDisparity3;
362 delete[] pSmoothedDisparity4;
367 for (
int i = 0; i < imageHeight; i++)
369 for (
int j = 0; j < imageWidth; j++)
371 if (i < imageOverlapCutoffTop || i >= imageHeight - imageOverlapCutoffBottom || j < imageOverlapCutoffLeft || j > imageWidth - imageOverlapCutoffRight)
373 pSmoothedDisparity[i * imageWidth + j] = 0;
383 CByteImage* pRectifiedDisparityImage =
new CByteImage(imageWidth, imageHeight, CByteImage::eGrayScale);
385 for (
int i = 0; i < imageHeight; i++)
387 for (
int j = 0; j < imageWidth; j++)
389 int nDisp = pSmoothedDisparity[i * imageWidth + j];
390 pRectifiedDisparityImage->pixels[i * imageWidth + j] = (nDisp > 255) ? 255 : nDisp;
395 ::ImageProcessor::Zero(pDisparityImage);
396 Vec2d vRectPos, vUnRectPos;
397 Mat3d mRectificationHomography = pStereoCalibration->rectificationHomographyLeft;
399 for (
int i = 0; i < imageHeight; i++)
401 for (
int j = 0; j < imageWidth; j++)
405 Math2d::ApplyHomography(mRectificationHomography, vRectPos, vUnRectPos);
407 if (0 <= vUnRectPos.y && vUnRectPos.y < imageHeight && 0 <= vUnRectPos.x && vUnRectPos.x < imageWidth)
409 pDisparityImage->pixels[(int)vUnRectPos.y * imageWidth + (
int)vUnRectPos.x] = pRectifiedDisparityImage->pixels[i * imageWidth + j];
414 FillHolesGray(pDisparityImage, pRectifiedDisparityImage, imageWidth, imageHeight, 1);
415 FillHolesGray(pRectifiedDisparityImage, pDisparityImage, imageWidth, imageHeight, 1);
416 delete pRectifiedDisparityImage;
421 Vec2d vImgPointLeft, vImgPointRight;
423 const float fDispMin = nDispMin;
424 const float fDispMax = nDispMax;
425 aPointsFromDisparity.width = ceil((
float)imageWidth / (
float)nDisparityPointDistance);
426 aPointsFromDisparity.height = ceil((
float)imageHeight / (
float)nDisparityPointDistance);
427 aPointsFromDisparity.resize(aPointsFromDisparity.width * aPointsFromDisparity.height);
431 for (
int i = 0; i < imageHeight; i += nDisparityPointDistance)
433 for (
int j = 0; j < imageWidth; j += nDisparityPointDistance,
index++)
436 float fDisp = pSmoothedDisparity[i * imageWidth + j];
438 if ((fDisp > fDispMin) && (fDisp < fDispMax))
442 vImgPointRight.x = j - fDisp;
443 vImgPointRight.y = i;
445 pStereoCalibration->Calculate3DPoint(vImgPointLeft, vImgPointRight, vPoint3D,
true,
false);
448 aPointsFromDisparity.points[
index].x = vPoint3D.x;
449 aPointsFromDisparity.points[
index].y = vPoint3D.y;
450 aPointsFromDisparity.points[
index].z = vPoint3D.z;
451 aPointsFromDisparity.points[
index].r = pRectifiedImageLeftColorGaussFiltered->pixels[3 * (i * imageWidth + j)];
452 aPointsFromDisparity.points[
index].g = pRectifiedImageLeftColorGaussFiltered->pixels[3 * (i * imageWidth + j) + 1];
453 aPointsFromDisparity.points[
index].b = pRectifiedImageLeftColorGaussFiltered->pixels[3 * (i * imageWidth + j) + 2];
454 aPointsFromDisparity.points[
index].a = 1.0f;
468 aPointsFromDisparity.points[
index].x = 0;
469 aPointsFromDisparity.points[
index].y = 0;
470 aPointsFromDisparity.points[
index].z = 0;
471 aPointsFromDisparity.points[
index].r = 0;
472 aPointsFromDisparity.points[
index].g = 0;
473 aPointsFromDisparity.points[
index].b = 0;
474 aPointsFromDisparity.points[
index].a = 0;
479 delete pRectifiedImageLeftGrey;
480 delete pRectifiedImageRightGrey;
481 delete pRectifiedImageLeftGreyHalfsize;
482 delete pRectifiedImageRightGreyHalfsize;
483 delete pRectifiedImageLeftGreyQuartersize;
484 delete pRectifiedImageRightGreyQuartersize;
485 delete pRectifiedImageLeftColorGaussFiltered;
486 delete pStereoMatcher;
487 delete pStereoCalibrationCopy;
488 cvReleaseImageHeader(&pRectifiedIplImageLeft);
489 cvReleaseImageHeader(&pRectifiedIplImageRight);
491 if (pSmoothedDisparity != pDisparities)
493 delete[] pSmoothedDisparity;
496 delete[] pDisparities;
502 void FillHolesGray(
const CByteImage* pInputImage, CByteImage* pOutputImage,
const int imageWidth,
const int imageHeight,
const int nRadius)
505 for (
int i = 0; i < imageWidth * imageHeight; i++)
507 pOutputImage->pixels[i] = pInputImage->pixels[i];
510 for (
int i = nRadius; i < imageHeight - nRadius; i++)
512 for (
int j = nRadius; j < imageWidth - nRadius; j++)
514 int nIndex = i * imageWidth + j;
516 if (pInputImage->pixels[nIndex] == 0)
521 for (
int l = -nRadius; l <= nRadius; l++)
523 for (
int k = -nRadius; k <= nRadius; k++)
525 int nTempIndex = nIndex + l * imageWidth + k;
527 if (pInputImage->pixels[nTempIndex] != 0)
529 nSum += pInputImage->pixels[nTempIndex];
537 pOutputImage->pixels[nIndex] = nSum / nNumPixels;
550 for (
int i = 0; i < imageWidth * imageHeight; i++)
552 pSmoothedDisparity[i] = pInputDisparity[i];
555 for (
int i = nRadius; i < imageHeight - nRadius; i++)
557 for (
int j = nRadius; j < imageWidth - nRadius; j++)
559 int nIndex = i * imageWidth + j;
561 if (pInputDisparity[nIndex] != 0)
566 for (
int l = -nRadius; l <= nRadius; l++)
568 for (
int k = -nRadius; k <= nRadius; k++)
570 int nTempIndex = nIndex + l * imageWidth + k;
572 if (pInputDisparity[nTempIndex] != 0)
574 fSum += pInputDisparity[nTempIndex];
580 pSmoothedDisparity[nIndex] = fSum / (
float)nNumPixels;