123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485 |
- /*M///////////////////////////////////////////////////////////////////////////////////////
- //
- // IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
- //
- // By downloading, copying, installing or using the software you agree to this license.
- // If you do not agree to this license, do not download, install,
- // copy or use the software.
- //
- //
- // License Agreement
- // For Open Source Computer Vision Library
- //
- // Copyright (C) 2015, OpenCV Foundation, all rights reserved.
- // Third party copyrights are property of their respective owners.
- //
- // Redistribution and use in source and binary forms, with or without modification,
- // are permitted provided that the following conditions are met:
- //
- // * Redistribution's of source code must retain the above copyright notice,
- // this list of conditions and the following disclaimer.
- //
- // * Redistribution's in binary form must reproduce the above copyright notice,
- // this list of conditions and the following disclaimer in the documentation
- // and/or other materials provided with the distribution.
- //
- // * The name of the copyright holders may not be used to endorse or promote products
- // derived from this software without specific prior written permission.
- //
- // This software is provided by the copyright holders and contributors "as is" and
- // any express or implied warranties, including, but not limited to, the implied
- // warranties of merchantability and fitness for a particular purpose are disclaimed.
- // In no event shall the Intel Corporation or contributors be liable for any direct,
- // indirect, incidental, special, exemplary, or consequential damages
- // (including, but not limited to, procurement of substitute goods or services;
- // loss of use, data, or profits; or business interruption) however caused
- // and on any theory of liability, whether in contract, strict liability,
- // or tort (including negligence or otherwise) arising in any way out of
- // the use of this software, even if advised of the possibility of such damage.
- //
- //M*/
- #include "precomp.hpp"
- namespace cv {
- namespace structured_light {
- class CV_EXPORTS_W GrayCodePattern_Impl CV_FINAL : public GrayCodePattern
- {
- public:
- // Constructor
- explicit GrayCodePattern_Impl( const GrayCodePattern::Params ¶meters = GrayCodePattern::Params() );
- // Destructor
- virtual ~GrayCodePattern_Impl() CV_OVERRIDE {};
- // Generates the gray code pattern as a std::vector<Mat>
- bool generate( OutputArrayOfArrays patternImages ) CV_OVERRIDE;
- // Decodes the gray code pattern, computing the disparity map
- bool decode( const std::vector< std::vector<Mat> >& patternImages, OutputArray disparityMap, InputArrayOfArrays blackImages = noArray(),
- InputArrayOfArrays whiteImages = noArray(), int flags = DECODE_3D_UNDERWORLD ) const CV_OVERRIDE;
- // Returns the number of pattern images for the graycode pattern
- size_t getNumberOfPatternImages() const CV_OVERRIDE;
- // Sets the value for black threshold
- void setBlackThreshold( size_t val ) CV_OVERRIDE;
- // Sets the value for set the value for white threshold
- void setWhiteThreshold( size_t val ) CV_OVERRIDE;
- // Generates the images needed for shadowMasks computation
- void getImagesForShadowMasks( InputOutputArray blackImage, InputOutputArray whiteImage ) const CV_OVERRIDE;
- // For a (x,y) pixel of the camera returns the corresponding projector pixel
- bool getProjPixel(InputArrayOfArrays patternImages, int x, int y, CV_OUT Point &projPix) const CV_OVERRIDE;
- private:
- // Parameters
- Params params;
- // The number of images of the pattern
- size_t numOfPatternImages;
- // The number of row images of the pattern
- size_t numOfRowImgs;
- // The number of column images of the pattern
- size_t numOfColImgs;
- // Number between 0-255 that represents the minimum brightness difference
- // between the fully illuminated (white) and the non - illuminated images (black)
- size_t blackThreshold;
- // Number between 0-255 that represents the minimum brightness difference
- // between the gray-code pattern and its inverse images
- size_t whiteThreshold;
- // Computes the required number of pattern images, allocating the pattern vector
- void computeNumberOfPatternImages();
- // Computes the shadows occlusion where we cannot reconstruct the model
- void computeShadowMasks( InputArrayOfArrays blackImages, InputArrayOfArrays whiteImages,
- OutputArrayOfArrays shadowMasks ) const;
- // Converts a gray code sequence (~ binary number) to a decimal number
- int grayToDec( const std::vector<uchar>& gray ) const;
- };
- /*
- * GrayCodePattern
- */
- GrayCodePattern::Params::Params()
- {
- width = 1024;
- height = 768;
- }
- GrayCodePattern_Impl::GrayCodePattern_Impl( const GrayCodePattern::Params ¶meters ) :
- params( parameters )
- {
- computeNumberOfPatternImages();
- blackThreshold = 40; // 3D_underworld default value
- whiteThreshold = 5; // 3D_underworld default value
- }
- bool GrayCodePattern_Impl::generate( OutputArrayOfArrays pattern )
- {
- std::vector<Mat>& pattern_ = *( std::vector<Mat>* ) pattern.getObj();
- pattern_.resize( numOfPatternImages );
- for( size_t i = 0; i < numOfPatternImages; i++ )
- {
- pattern_[i] = Mat( params.height, params.width, CV_8U );
- }
- uchar flag = 0;
- for( int j = 0; j < params.width; j++ ) // rows loop
- {
- int rem = 0, num = j, prevRem = j % 2;
- for( size_t k = 0; k < numOfColImgs; k++ ) // images loop
- {
- num = num / 2;
- rem = num % 2;
- if( ( rem == 0 && prevRem == 1 ) || ( rem == 1 && prevRem == 0) )
- {
- flag = 1;
- }
- else
- {
- flag = 0;
- }
- for( int i = 0; i < params.height; i++ ) // rows loop
- {
- uchar pixel_color = ( uchar ) flag * 255;
- pattern_[2 * numOfColImgs - 2 * k - 2].at<uchar>( i, j ) = pixel_color;
- if( pixel_color > 0 )
- pixel_color = ( uchar ) 0;
- else
- pixel_color = ( uchar ) 255;
- pattern_[2 * numOfColImgs - 2 * k - 1].at<uchar>( i, j ) = pixel_color; // inverse
- }
- prevRem = rem;
- }
- }
- for( int i = 0; i < params.height; i++ ) // rows loop
- {
- int rem = 0, num = i, prevRem = i % 2;
- for( size_t k = 0; k < numOfRowImgs; k++ )
- {
- num = num / 2;
- rem = num % 2;
- if( (rem == 0 && prevRem == 1) || (rem == 1 && prevRem == 0) )
- {
- flag = 1;
- }
- else
- {
- flag = 0;
- }
- for( int j = 0; j < params.width; j++ )
- {
- uchar pixel_color = ( uchar ) flag * 255;
- pattern_[2 * numOfRowImgs - 2 * k + 2 * numOfColImgs - 2].at<uchar>( i, j ) = pixel_color;
- if( pixel_color > 0 )
- pixel_color = ( uchar ) 0;
- else
- pixel_color = ( uchar ) 255;
- pattern_[2 * numOfRowImgs - 2 * k + 2 * numOfColImgs - 1].at<uchar>( i, j ) = pixel_color;
- }
- prevRem = rem;
- }
- }
- return true;
- }
- bool GrayCodePattern_Impl::decode( const std::vector< std::vector<Mat> >& patternImages, OutputArray disparityMap,
- InputArrayOfArrays blackImages, InputArrayOfArrays whitheImages, int flags ) const
- {
- const std::vector<std::vector<Mat> >& acquired_pattern = patternImages;
- if( flags == DECODE_3D_UNDERWORLD )
- {
- // Computing shadows mask
- std::vector<Mat> shadowMasks;
- computeShadowMasks( blackImages, whitheImages, shadowMasks );
- int cam_width = acquired_pattern[0][0].cols;
- int cam_height = acquired_pattern[0][0].rows;
- Point projPixel;
- // Storage for the pixels of the two cams that correspond to the same pixel of the projector
- std::vector<std::vector<std::vector<Point> > > camsPixels;
- camsPixels.resize( acquired_pattern.size() );
- // TODO: parallelize for (k and j)
- for( size_t k = 0; k < acquired_pattern.size(); k++ )
- {
- camsPixels[k].resize( params.height * params.width );
- for( int i = 0; i < cam_width; i++ )
- {
- for( int j = 0; j < cam_height; j++ )
- {
- //if the pixel is not shadowed, reconstruct
- if( shadowMasks[k].at<uchar>( j, i ) )
- {
- //for a (x,y) pixel of the camera returns the corresponding projector pixel by calculating the decimal number
- bool error = getProjPixel( acquired_pattern[k], i, j, projPixel );
- if( error )
- {
- continue;
- }
- camsPixels[k][projPixel.x * params.height + projPixel.y].push_back( Point( i, j ) );
- }
- }
- }
- }
- std::vector<Point> cam1Pixs, cam2Pixs;
- Mat& disparityMap_ = *( Mat* ) disparityMap.getObj();
- disparityMap_ = Mat( cam_height, cam_width, CV_64F, double( 0 ) );
- double number_of_pixels_cam1 = 0;
- double number_of_pixels_cam2 = 0;
- for( int i = 0; i < params.width; i++ )
- {
- for( int j = 0; j < params.height; j++ )
- {
- cam1Pixs = camsPixels[0][i * params.height + j];
- cam2Pixs = camsPixels[1][i * params.height + j];
- if( cam1Pixs.size() == 0 || cam2Pixs.size() == 0 )
- continue;
- Point p1;
- Point p2;
- double sump1x = 0;
- double sump2x = 0;
- number_of_pixels_cam1 += cam1Pixs.size();
- number_of_pixels_cam2 += cam2Pixs.size();
- for( int c1 = 0; c1 < (int) cam1Pixs.size(); c1++ )
- {
- p1 = cam1Pixs[c1];
- sump1x += p1.x;
- }
- for( int c2 = 0; c2 < (int) cam2Pixs.size(); c2++ )
- {
- p2 = cam2Pixs[c2];
- sump2x += p2.x;
- }
- sump2x /= cam2Pixs.size();
- sump1x /= cam1Pixs.size();
- for( int c1 = 0; c1 < (int) cam1Pixs.size(); c1++ )
- {
- p1 = cam1Pixs[c1];
- disparityMap_.at<double>( p1.y, p1.x ) = ( double ) (sump2x - sump1x);
- }
- sump2x = 0;
- sump1x = 0;
- }
- }
- return true;
- } // end if flags
- return false;
- }
- // Computes the required number of pattern images
- void GrayCodePattern_Impl::computeNumberOfPatternImages()
- {
- numOfColImgs = ( size_t ) ceil( log( double( params.width ) ) / log( 2.0 ) );
- numOfRowImgs = ( size_t ) ceil( log( double( params.height ) ) / log( 2.0 ) );
- numOfPatternImages = 2 * numOfColImgs + 2 * numOfRowImgs;
- }
- // Returns the number of pattern images to project / decode
- size_t GrayCodePattern_Impl::getNumberOfPatternImages() const
- {
- return numOfPatternImages;
- }
- // Computes the shadows occlusion where we cannot reconstruct the model
- void GrayCodePattern_Impl::computeShadowMasks( InputArrayOfArrays blackImages, InputArrayOfArrays whiteImages,
- OutputArrayOfArrays shadowMasks ) const
- {
- std::vector<Mat>& whiteImages_ = *( std::vector<Mat>* ) whiteImages.getObj();
- std::vector<Mat>& blackImages_ = *( std::vector<Mat>* ) blackImages.getObj();
- std::vector<Mat>& shadowMasks_ = *( std::vector<Mat>* ) shadowMasks.getObj();
- shadowMasks_.resize( whiteImages_.size() );
- int cam_width = whiteImages_[0].cols;
- int cam_height = whiteImages_[0].rows;
- // TODO: parallelize for
- for( int k = 0; k < (int) shadowMasks_.size(); k++ )
- {
- shadowMasks_[k] = Mat( cam_height, cam_width, CV_8U );
- for( int i = 0; i < cam_width; i++ )
- {
- for( int j = 0; j < cam_height; j++ )
- {
- double white = whiteImages_[k].at<uchar>( Point( i, j ) );
- double black = blackImages_[k].at<uchar>( Point( i, j ) );
- if( abs(white - black) > blackThreshold )
- {
- shadowMasks_[k].at<uchar>( Point( i, j ) ) = ( uchar ) 1;
- }
- else
- {
- shadowMasks_[k].at<uchar>( Point( i, j ) ) = ( uchar ) 0;
- }
- }
- }
- }
- }
- // Generates the images needed for shadowMasks computation
- void GrayCodePattern_Impl::getImagesForShadowMasks( InputOutputArray blackImage, InputOutputArray whiteImage ) const
- {
- Mat& blackImage_ = *( Mat* ) blackImage.getObj();
- Mat& whiteImage_ = *( Mat* ) whiteImage.getObj();
- blackImage_ = Mat( params.height, params.width, CV_8U, Scalar( 0 ) );
- whiteImage_ = Mat( params.height, params.width, CV_8U, Scalar( 255 ) );
- }
- // For a (x,y) pixel of the camera returns the corresponding projector's pixel
- bool GrayCodePattern_Impl::getProjPixel( InputArrayOfArrays patternImages, int x, int y, Point &projPix ) const
- {
- std::vector<Mat>& _patternImages = *( std::vector<Mat>* ) patternImages.getObj();
- std::vector<uchar> grayCol;
- std::vector<uchar> grayRow;
- bool error = false;
- int xDec, yDec;
- // process column images
- for( size_t count = 0; count < numOfColImgs; count++ )
- {
- // get pixel intensity for regular pattern projection and its inverse
- double val1 = _patternImages[count * 2].at<uchar>( Point( x, y ) );
- double val2 = _patternImages[count * 2 + 1].at<uchar>( Point( x, y ) );
- // check if the intensity difference between the values of the normal and its inverse projection image is in a valid range
- if( abs(val1 - val2) < whiteThreshold )
- error = true;
- // determine if projection pixel is on or off
- if( val1 > val2 )
- grayCol.push_back( 1 );
- else
- grayCol.push_back( 0 );
- }
- xDec = grayToDec( grayCol );
- // process row images
- for( size_t count = 0; count < numOfRowImgs; count++ )
- {
- // get pixel intensity for regular pattern projection and its inverse
- double val1 = _patternImages[count * 2 + numOfColImgs * 2].at<uchar>( Point( x, y ) );
- double val2 = _patternImages[count * 2 + numOfColImgs * 2 + 1].at<uchar>( Point( x, y ) );
- // check if the intensity difference between the values of the normal and its inverse projection image is in a valid range
- if( abs(val1 - val2) < whiteThreshold )
- error = true;
- // determine if projection pixel is on or off
- if( val1 > val2 )
- grayRow.push_back( 1 );
- else
- grayRow.push_back( 0 );
- }
- yDec = grayToDec( grayRow );
- if( (yDec >= params.height || xDec >= params.width) )
- {
- error = true;
- }
- projPix.x = xDec;
- projPix.y = yDec;
- return error;
- }
- // Converts a gray code sequence (~ binary number) to a decimal number
- int GrayCodePattern_Impl::grayToDec( const std::vector<uchar>& gray ) const
- {
- int dec = 0;
- uchar tmp = gray[0];
- if( tmp )
- dec += ( int ) pow( ( float ) 2, int( gray.size() - 1 ) );
- for( int i = 1; i < (int) gray.size(); i++ )
- {
- // XOR operation
- tmp = tmp ^ gray[i];
- if( tmp )
- dec += (int) pow( ( float ) 2, int( gray.size() - i - 1 ) );
- }
- return dec;
- }
- // Sets the value for black threshold
- void GrayCodePattern_Impl::setBlackThreshold( size_t val )
- {
- blackThreshold = val;
- }
- // Sets the value for white threshold
- void GrayCodePattern_Impl::setWhiteThreshold( size_t val )
- {
- whiteThreshold = val;
- }
- // Creates the GrayCodePattern instance
- Ptr<GrayCodePattern> GrayCodePattern::create( const GrayCodePattern::Params& params )
- {
- return makePtr<GrayCodePattern_Impl>( params );
- }
- // Creates the GrayCodePattern instance
- // alias for scripting
- Ptr<GrayCodePattern> GrayCodePattern::create( int width, int height )
- {
- Params params;
- params.width = width;
- params.height = height;
- return makePtr<GrayCodePattern_Impl>( params );
- }
- }
- }
|