Skip to content

Commit b2c445a

Browse files
committed
Reintroduce GrayCodePattern::getProjPixel to allow for tests to pass, fixup NaN values in projector mapping
This commit reintroduces a faster and improved version of getProjPixel to allow for tests that relied on it to pass, and it also fixes an issue with NaN values appearing in projector mapping when a pixel wasn't seen by either one of the cameras.
1 parent 8a4e1c2 commit b2c445a

File tree

2 files changed

+109
-8
lines changed

2 files changed

+109
-8
lines changed

modules/structured_light/include/opencv2/structured_light/graycodepattern.hpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,19 @@ class CV_EXPORTS_W GrayCodePattern : public StructuredLightPattern
128128
*/
129129
CV_WRAP
130130
virtual void getImagesForShadowMasks( InputOutputArray blackImage, InputOutputArray whiteImage ) const = 0;
131+
132+
/** @brief For a (x,y) pixel of a camera returns the corresponding projector pixel.
133+
*
134+
* The function decodes each pixel in the pattern images acquired by a camera into their corresponding decimal numbers representing the projector's column and row,
135+
* providing a mapping between camera's and projector's pixel.
136+
*
137+
* @param patternImages The pattern images acquired by the camera, stored in a grayscale vector < Mat >.
138+
* @param x x coordinate of the image pixel.
139+
* @param y y coordinate of the image pixel.
140+
* @param projPix Projector's pixel corresponding to the camera's pixel: projPix.x and projPix.y are the image coordinates of the projector's pixel corresponding to the pixel being decoded in a camera.
141+
*/
142+
CV_WRAP
143+
virtual bool getProjPixel(InputArrayOfArrays patternImages, int x, int y, CV_OUT Point& projPix) const = 0;
131144
};
132145

133146
//! @}

modules/structured_light/src/graycodepattern.cpp

Lines changed: 96 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,8 @@ class CV_EXPORTS_W GrayCodePattern_Impl CV_FINAL : public GrayCodePattern
7171
// Generates the images needed for shadowMasks computation
7272
void getImagesForShadowMasks( InputOutputArray blackImage, InputOutputArray whiteImage ) const CV_OVERRIDE;
7373

74+
bool getProjPixel(InputArrayOfArrays patternImages, int x, int y, Point& projPix) const CV_OVERRIDE;
75+
7476
private:
7577
// Parameters
7678
Params params;
@@ -245,8 +247,10 @@ bool GrayCodePattern_Impl::decode(const std::vector< std::vector<Mat> >& pattern
245247
cv::divide(sumX[0], counts_64F[0], avgX[0]);
246248
cv::divide(sumX[1], counts_64F[1], avgX[1]);
247249

250+
// Handle invalid pixels (e.g. not seen by one of the cameras) by setting them to zero.
251+
cv::Mat invalidPixels = counts[0] == 0 | counts[1] == 0;
252+
248253
Mat projectorDisparity = avgX[1] - avgX[0];
249-
Mat validProjectorPixels = (counts[0] > 0) & (counts[1] > 0);
250254

251255
Mat& disparityMap_ = *(Mat*)disparityMap.getObj();
252256
Mat map_x(cam_height, cam_width, CV_32F);
@@ -257,16 +261,11 @@ bool GrayCodePattern_Impl::decode(const std::vector< std::vector<Mat> >& pattern
257261
projMapChannels[0].convertTo(map_x, CV_32F); // Projector x-coordinates
258262
projMapChannels[1].convertTo(map_y, CV_32F); // Projector y-coordinates
259263

260-
cv::remap(projectorDisparity, disparityMap_, map_x, map_y,
261-
INTER_NEAREST, BORDER_CONSTANT, Scalar(0));
264+
projectorDisparity.setTo(Scalar(0.0), invalidPixels);
262265

263-
// Remap the validity mask and invert it to get the final invalid mask.
264-
Mat validCameraPixels;
265-
cv::remap(validProjectorPixels, validCameraPixels, map_x, map_y,
266+
cv::remap(projectorDisparity, disparityMap_, map_x, map_y,
266267
INTER_NEAREST, BORDER_CONSTANT, Scalar(0));
267268

268-
Mat invalidMask;
269-
cv::bitwise_not(validCameraPixels, invalidMask);
270269
return true;
271270
}
272271

@@ -353,6 +352,95 @@ void GrayCodePattern_Impl::populateFastPatternImages(const std::vector<std::vect
353352
}
354353
}
355354

355+
static int grayToDec(const std::vector<uchar>& gray)
356+
{
357+
if (gray.empty())
358+
{
359+
return 0;
360+
}
361+
362+
int dec = 0;
363+
uchar prev_binary_bit = 0;
364+
for (size_t i = 0; i < gray.size(); ++i)
365+
{
366+
uchar current_binary_bit = prev_binary_bit ^ gray[i];
367+
dec = (dec << 1) | current_binary_bit;
368+
prev_binary_bit = current_binary_bit;
369+
}
370+
return dec;
371+
}
372+
373+
bool GrayCodePattern_Impl::getProjPixel(InputArrayOfArrays patternImages, int x, int y, Point& projPix) const
374+
{
375+
std::vector<Mat>& patternImagesVec = *(std::vector<Mat>*)patternImages.getObj();
376+
const int rows = patternImagesVec[0].rows;
377+
const int cols = patternImagesVec[0].cols;
378+
379+
std::vector<uchar> grayCol(numOfColImgs);
380+
std::vector<uchar> grayRow(numOfRowImgs);
381+
382+
auto decode_pixel = [&](auto dummy_type_ptr) -> bool
383+
{
384+
using T = typename std::remove_pointer<decltype(dummy_type_ptr)>::type;
385+
bool error = false;
386+
387+
for (size_t k = 0; k < numOfColImgs; ++k)
388+
{
389+
T val1 = patternImagesVec[k * 2].at<T>(y, x);
390+
T val2 = patternImagesVec[k * 2 + 1].at<T>(y, x);
391+
392+
if (std::abs(static_cast<double>(val1) - static_cast<double>(val2)) < whiteThreshold)
393+
{
394+
error = true;
395+
}
396+
grayCol[k] = (val1 > val2);
397+
}
398+
399+
size_t base_idx = 2 * numOfColImgs;
400+
for (size_t k = 0; k < numOfRowImgs; ++k)
401+
{
402+
T val1 = patternImagesVec[base_idx + k * 2].at<T>(y, x);
403+
T val2 = patternImagesVec[base_idx + k * 2 + 1].at<T>(y, x);
404+
405+
if (std::abs(static_cast<double>(val1) - static_cast<double>(val2)) < whiteThreshold)
406+
{
407+
error = true;
408+
}
409+
grayRow[k] = (val1 > val2);
410+
}
411+
return error;
412+
};
413+
414+
bool error = false;
415+
int depth = patternImagesVec[0].depth();
416+
417+
switch (depth)
418+
{
419+
case CV_8U:
420+
error = decode_pixel((uchar*)nullptr);
421+
break;
422+
case CV_16U:
423+
error = decode_pixel((ushort*)nullptr);
424+
break;
425+
default:
426+
CV_Error(Error::StsUnsupportedFormat, "Image depth not supported, only CV_8U and CV_16U");
427+
}
428+
429+
int xDec = grayToDec(grayCol);
430+
int yDec = grayToDec(grayRow);
431+
432+
if (yDec >= params.height || xDec >= params.width)
433+
{
434+
error = true;
435+
}
436+
437+
projPix.x = xDec;
438+
projPix.y = yDec;
439+
440+
return error;
441+
}
442+
443+
356444
// For a (x,y) pixel of the camera returns the corresponding projector's pixel
357445
bool GrayCodePattern_Impl::getProjPixelFast( const std::vector<Mat>& fastColImages, const std::vector<Mat>& fastRowImages, int x, int y, Point &projPix) const
358446
{

0 commit comments

Comments
 (0)