graycodepattern.cpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485
  1. /*M///////////////////////////////////////////////////////////////////////////////////////
  2. //
  3. // IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
  4. //
  5. // By downloading, copying, installing or using the software you agree to this license.
  6. // If you do not agree to this license, do not download, install,
  7. // copy or use the software.
  8. //
  9. //
  10. // License Agreement
  11. // For Open Source Computer Vision Library
  12. //
  13. // Copyright (C) 2015, OpenCV Foundation, all rights reserved.
  14. // Third party copyrights are property of their respective owners.
  15. //
  16. // Redistribution and use in source and binary forms, with or without modification,
  17. // are permitted provided that the following conditions are met:
  18. //
  19. // * Redistribution's of source code must retain the above copyright notice,
  20. // this list of conditions and the following disclaimer.
  21. //
  22. // * Redistribution's in binary form must reproduce the above copyright notice,
  23. // this list of conditions and the following disclaimer in the documentation
  24. // and/or other materials provided with the distribution.
  25. //
  26. // * The name of the copyright holders may not be used to endorse or promote products
  27. // derived from this software without specific prior written permission.
  28. //
  29. // This software is provided by the copyright holders and contributors "as is" and
  30. // any express or implied warranties, including, but not limited to, the implied
  31. // warranties of merchantability and fitness for a particular purpose are disclaimed.
  32. // In no event shall the Intel Corporation or contributors be liable for any direct,
  33. // indirect, incidental, special, exemplary, or consequential damages
  34. // (including, but not limited to, procurement of substitute goods or services;
  35. // loss of use, data, or profits; or business interruption) however caused
  36. // and on any theory of liability, whether in contract, strict liability,
  37. // or tort (including negligence or otherwise) arising in any way out of
  38. // the use of this software, even if advised of the possibility of such damage.
  39. //
  40. //M*/
  41. #include "precomp.hpp"
  42. namespace cv {
  43. namespace structured_light {
  44. class CV_EXPORTS_W GrayCodePattern_Impl CV_FINAL : public GrayCodePattern
  45. {
  46. public:
  47. // Constructor
  48. explicit GrayCodePattern_Impl( const GrayCodePattern::Params &parameters = GrayCodePattern::Params() );
  49. // Destructor
  50. virtual ~GrayCodePattern_Impl() CV_OVERRIDE {};
  51. // Generates the gray code pattern as a std::vector<Mat>
  52. bool generate( OutputArrayOfArrays patternImages ) CV_OVERRIDE;
  53. // Decodes the gray code pattern, computing the disparity map
  54. bool decode( const std::vector< std::vector<Mat> >& patternImages, OutputArray disparityMap, InputArrayOfArrays blackImages = noArray(),
  55. InputArrayOfArrays whiteImages = noArray(), int flags = DECODE_3D_UNDERWORLD ) const CV_OVERRIDE;
  56. // Returns the number of pattern images for the graycode pattern
  57. size_t getNumberOfPatternImages() const CV_OVERRIDE;
  58. // Sets the value for black threshold
  59. void setBlackThreshold( size_t val ) CV_OVERRIDE;
  60. // Sets the value for set the value for white threshold
  61. void setWhiteThreshold( size_t val ) CV_OVERRIDE;
  62. // Generates the images needed for shadowMasks computation
  63. void getImagesForShadowMasks( InputOutputArray blackImage, InputOutputArray whiteImage ) const CV_OVERRIDE;
  64. // For a (x,y) pixel of the camera returns the corresponding projector pixel
  65. bool getProjPixel(InputArrayOfArrays patternImages, int x, int y, CV_OUT Point &projPix) const CV_OVERRIDE;
  66. private:
  67. // Parameters
  68. Params params;
  69. // The number of images of the pattern
  70. size_t numOfPatternImages;
  71. // The number of row images of the pattern
  72. size_t numOfRowImgs;
  73. // The number of column images of the pattern
  74. size_t numOfColImgs;
  75. // Number between 0-255 that represents the minimum brightness difference
  76. // between the fully illuminated (white) and the non - illuminated images (black)
  77. size_t blackThreshold;
  78. // Number between 0-255 that represents the minimum brightness difference
  79. // between the gray-code pattern and its inverse images
  80. size_t whiteThreshold;
  81. // Computes the required number of pattern images, allocating the pattern vector
  82. void computeNumberOfPatternImages();
  83. // Computes the shadows occlusion where we cannot reconstruct the model
  84. void computeShadowMasks( InputArrayOfArrays blackImages, InputArrayOfArrays whiteImages,
  85. OutputArrayOfArrays shadowMasks ) const;
  86. // Converts a gray code sequence (~ binary number) to a decimal number
  87. int grayToDec( const std::vector<uchar>& gray ) const;
  88. };
  89. /*
  90. * GrayCodePattern
  91. */
  92. GrayCodePattern::Params::Params()
  93. {
  94. width = 1024;
  95. height = 768;
  96. }
  97. GrayCodePattern_Impl::GrayCodePattern_Impl( const GrayCodePattern::Params &parameters ) :
  98. params( parameters )
  99. {
  100. computeNumberOfPatternImages();
  101. blackThreshold = 40; // 3D_underworld default value
  102. whiteThreshold = 5; // 3D_underworld default value
  103. }
  104. bool GrayCodePattern_Impl::generate( OutputArrayOfArrays pattern )
  105. {
  106. std::vector<Mat>& pattern_ = *( std::vector<Mat>* ) pattern.getObj();
  107. pattern_.resize( numOfPatternImages );
  108. for( size_t i = 0; i < numOfPatternImages; i++ )
  109. {
  110. pattern_[i] = Mat( params.height, params.width, CV_8U );
  111. }
  112. uchar flag = 0;
  113. for( int j = 0; j < params.width; j++ ) // rows loop
  114. {
  115. int rem = 0, num = j, prevRem = j % 2;
  116. for( size_t k = 0; k < numOfColImgs; k++ ) // images loop
  117. {
  118. num = num / 2;
  119. rem = num % 2;
  120. if( ( rem == 0 && prevRem == 1 ) || ( rem == 1 && prevRem == 0) )
  121. {
  122. flag = 1;
  123. }
  124. else
  125. {
  126. flag = 0;
  127. }
  128. for( int i = 0; i < params.height; i++ ) // rows loop
  129. {
  130. uchar pixel_color = ( uchar ) flag * 255;
  131. pattern_[2 * numOfColImgs - 2 * k - 2].at<uchar>( i, j ) = pixel_color;
  132. if( pixel_color > 0 )
  133. pixel_color = ( uchar ) 0;
  134. else
  135. pixel_color = ( uchar ) 255;
  136. pattern_[2 * numOfColImgs - 2 * k - 1].at<uchar>( i, j ) = pixel_color; // inverse
  137. }
  138. prevRem = rem;
  139. }
  140. }
  141. for( int i = 0; i < params.height; i++ ) // rows loop
  142. {
  143. int rem = 0, num = i, prevRem = i % 2;
  144. for( size_t k = 0; k < numOfRowImgs; k++ )
  145. {
  146. num = num / 2;
  147. rem = num % 2;
  148. if( (rem == 0 && prevRem == 1) || (rem == 1 && prevRem == 0) )
  149. {
  150. flag = 1;
  151. }
  152. else
  153. {
  154. flag = 0;
  155. }
  156. for( int j = 0; j < params.width; j++ )
  157. {
  158. uchar pixel_color = ( uchar ) flag * 255;
  159. pattern_[2 * numOfRowImgs - 2 * k + 2 * numOfColImgs - 2].at<uchar>( i, j ) = pixel_color;
  160. if( pixel_color > 0 )
  161. pixel_color = ( uchar ) 0;
  162. else
  163. pixel_color = ( uchar ) 255;
  164. pattern_[2 * numOfRowImgs - 2 * k + 2 * numOfColImgs - 1].at<uchar>( i, j ) = pixel_color;
  165. }
  166. prevRem = rem;
  167. }
  168. }
  169. return true;
  170. }
  171. bool GrayCodePattern_Impl::decode( const std::vector< std::vector<Mat> >& patternImages, OutputArray disparityMap,
  172. InputArrayOfArrays blackImages, InputArrayOfArrays whitheImages, int flags ) const
  173. {
  174. const std::vector<std::vector<Mat> >& acquired_pattern = patternImages;
  175. if( flags == DECODE_3D_UNDERWORLD )
  176. {
  177. // Computing shadows mask
  178. std::vector<Mat> shadowMasks;
  179. computeShadowMasks( blackImages, whitheImages, shadowMasks );
  180. int cam_width = acquired_pattern[0][0].cols;
  181. int cam_height = acquired_pattern[0][0].rows;
  182. Point projPixel;
  183. // Storage for the pixels of the two cams that correspond to the same pixel of the projector
  184. std::vector<std::vector<std::vector<Point> > > camsPixels;
  185. camsPixels.resize( acquired_pattern.size() );
  186. // TODO: parallelize for (k and j)
  187. for( size_t k = 0; k < acquired_pattern.size(); k++ )
  188. {
  189. camsPixels[k].resize( params.height * params.width );
  190. for( int i = 0; i < cam_width; i++ )
  191. {
  192. for( int j = 0; j < cam_height; j++ )
  193. {
  194. //if the pixel is not shadowed, reconstruct
  195. if( shadowMasks[k].at<uchar>( j, i ) )
  196. {
  197. //for a (x,y) pixel of the camera returns the corresponding projector pixel by calculating the decimal number
  198. bool error = getProjPixel( acquired_pattern[k], i, j, projPixel );
  199. if( error )
  200. {
  201. continue;
  202. }
  203. camsPixels[k][projPixel.x * params.height + projPixel.y].push_back( Point( i, j ) );
  204. }
  205. }
  206. }
  207. }
  208. std::vector<Point> cam1Pixs, cam2Pixs;
  209. Mat& disparityMap_ = *( Mat* ) disparityMap.getObj();
  210. disparityMap_ = Mat( cam_height, cam_width, CV_64F, double( 0 ) );
  211. double number_of_pixels_cam1 = 0;
  212. double number_of_pixels_cam2 = 0;
  213. for( int i = 0; i < params.width; i++ )
  214. {
  215. for( int j = 0; j < params.height; j++ )
  216. {
  217. cam1Pixs = camsPixels[0][i * params.height + j];
  218. cam2Pixs = camsPixels[1][i * params.height + j];
  219. if( cam1Pixs.size() == 0 || cam2Pixs.size() == 0 )
  220. continue;
  221. Point p1;
  222. Point p2;
  223. double sump1x = 0;
  224. double sump2x = 0;
  225. number_of_pixels_cam1 += cam1Pixs.size();
  226. number_of_pixels_cam2 += cam2Pixs.size();
  227. for( int c1 = 0; c1 < (int) cam1Pixs.size(); c1++ )
  228. {
  229. p1 = cam1Pixs[c1];
  230. sump1x += p1.x;
  231. }
  232. for( int c2 = 0; c2 < (int) cam2Pixs.size(); c2++ )
  233. {
  234. p2 = cam2Pixs[c2];
  235. sump2x += p2.x;
  236. }
  237. sump2x /= cam2Pixs.size();
  238. sump1x /= cam1Pixs.size();
  239. for( int c1 = 0; c1 < (int) cam1Pixs.size(); c1++ )
  240. {
  241. p1 = cam1Pixs[c1];
  242. disparityMap_.at<double>( p1.y, p1.x ) = ( double ) (sump2x - sump1x);
  243. }
  244. sump2x = 0;
  245. sump1x = 0;
  246. }
  247. }
  248. return true;
  249. } // end if flags
  250. return false;
  251. }
  252. // Computes the required number of pattern images
  253. void GrayCodePattern_Impl::computeNumberOfPatternImages()
  254. {
  255. numOfColImgs = ( size_t ) ceil( log( double( params.width ) ) / log( 2.0 ) );
  256. numOfRowImgs = ( size_t ) ceil( log( double( params.height ) ) / log( 2.0 ) );
  257. numOfPatternImages = 2 * numOfColImgs + 2 * numOfRowImgs;
  258. }
  259. // Returns the number of pattern images to project / decode
  260. size_t GrayCodePattern_Impl::getNumberOfPatternImages() const
  261. {
  262. return numOfPatternImages;
  263. }
  264. // Computes the shadows occlusion where we cannot reconstruct the model
  265. void GrayCodePattern_Impl::computeShadowMasks( InputArrayOfArrays blackImages, InputArrayOfArrays whiteImages,
  266. OutputArrayOfArrays shadowMasks ) const
  267. {
  268. std::vector<Mat>& whiteImages_ = *( std::vector<Mat>* ) whiteImages.getObj();
  269. std::vector<Mat>& blackImages_ = *( std::vector<Mat>* ) blackImages.getObj();
  270. std::vector<Mat>& shadowMasks_ = *( std::vector<Mat>* ) shadowMasks.getObj();
  271. shadowMasks_.resize( whiteImages_.size() );
  272. int cam_width = whiteImages_[0].cols;
  273. int cam_height = whiteImages_[0].rows;
  274. // TODO: parallelize for
  275. for( int k = 0; k < (int) shadowMasks_.size(); k++ )
  276. {
  277. shadowMasks_[k] = Mat( cam_height, cam_width, CV_8U );
  278. for( int i = 0; i < cam_width; i++ )
  279. {
  280. for( int j = 0; j < cam_height; j++ )
  281. {
  282. double white = whiteImages_[k].at<uchar>( Point( i, j ) );
  283. double black = blackImages_[k].at<uchar>( Point( i, j ) );
  284. if( abs(white - black) > blackThreshold )
  285. {
  286. shadowMasks_[k].at<uchar>( Point( i, j ) ) = ( uchar ) 1;
  287. }
  288. else
  289. {
  290. shadowMasks_[k].at<uchar>( Point( i, j ) ) = ( uchar ) 0;
  291. }
  292. }
  293. }
  294. }
  295. }
  296. // Generates the images needed for shadowMasks computation
  297. void GrayCodePattern_Impl::getImagesForShadowMasks( InputOutputArray blackImage, InputOutputArray whiteImage ) const
  298. {
  299. Mat& blackImage_ = *( Mat* ) blackImage.getObj();
  300. Mat& whiteImage_ = *( Mat* ) whiteImage.getObj();
  301. blackImage_ = Mat( params.height, params.width, CV_8U, Scalar( 0 ) );
  302. whiteImage_ = Mat( params.height, params.width, CV_8U, Scalar( 255 ) );
  303. }
  304. // For a (x,y) pixel of the camera returns the corresponding projector's pixel
  305. bool GrayCodePattern_Impl::getProjPixel( InputArrayOfArrays patternImages, int x, int y, Point &projPix ) const
  306. {
  307. std::vector<Mat>& _patternImages = *( std::vector<Mat>* ) patternImages.getObj();
  308. std::vector<uchar> grayCol;
  309. std::vector<uchar> grayRow;
  310. bool error = false;
  311. int xDec, yDec;
  312. // process column images
  313. for( size_t count = 0; count < numOfColImgs; count++ )
  314. {
  315. // get pixel intensity for regular pattern projection and its inverse
  316. double val1 = _patternImages[count * 2].at<uchar>( Point( x, y ) );
  317. double val2 = _patternImages[count * 2 + 1].at<uchar>( Point( x, y ) );
  318. // check if the intensity difference between the values of the normal and its inverse projection image is in a valid range
  319. if( abs(val1 - val2) < whiteThreshold )
  320. error = true;
  321. // determine if projection pixel is on or off
  322. if( val1 > val2 )
  323. grayCol.push_back( 1 );
  324. else
  325. grayCol.push_back( 0 );
  326. }
  327. xDec = grayToDec( grayCol );
  328. // process row images
  329. for( size_t count = 0; count < numOfRowImgs; count++ )
  330. {
  331. // get pixel intensity for regular pattern projection and its inverse
  332. double val1 = _patternImages[count * 2 + numOfColImgs * 2].at<uchar>( Point( x, y ) );
  333. double val2 = _patternImages[count * 2 + numOfColImgs * 2 + 1].at<uchar>( Point( x, y ) );
  334. // check if the intensity difference between the values of the normal and its inverse projection image is in a valid range
  335. if( abs(val1 - val2) < whiteThreshold )
  336. error = true;
  337. // determine if projection pixel is on or off
  338. if( val1 > val2 )
  339. grayRow.push_back( 1 );
  340. else
  341. grayRow.push_back( 0 );
  342. }
  343. yDec = grayToDec( grayRow );
  344. if( (yDec >= params.height || xDec >= params.width) )
  345. {
  346. error = true;
  347. }
  348. projPix.x = xDec;
  349. projPix.y = yDec;
  350. return error;
  351. }
  352. // Converts a gray code sequence (~ binary number) to a decimal number
  353. int GrayCodePattern_Impl::grayToDec( const std::vector<uchar>& gray ) const
  354. {
  355. int dec = 0;
  356. uchar tmp = gray[0];
  357. if( tmp )
  358. dec += ( int ) pow( ( float ) 2, int( gray.size() - 1 ) );
  359. for( int i = 1; i < (int) gray.size(); i++ )
  360. {
  361. // XOR operation
  362. tmp = tmp ^ gray[i];
  363. if( tmp )
  364. dec += (int) pow( ( float ) 2, int( gray.size() - i - 1 ) );
  365. }
  366. return dec;
  367. }
  368. // Sets the value for black threshold
  369. void GrayCodePattern_Impl::setBlackThreshold( size_t val )
  370. {
  371. blackThreshold = val;
  372. }
  373. // Sets the value for white threshold
  374. void GrayCodePattern_Impl::setWhiteThreshold( size_t val )
  375. {
  376. whiteThreshold = val;
  377. }
  378. // Creates the GrayCodePattern instance
  379. Ptr<GrayCodePattern> GrayCodePattern::create( const GrayCodePattern::Params& params )
  380. {
  381. return makePtr<GrayCodePattern_Impl>( params );
  382. }
  383. // Creates the GrayCodePattern instance
  384. // alias for scripting
  385. Ptr<GrayCodePattern> GrayCodePattern::create( int width, int height )
  386. {
  387. Params params;
  388. params.width = width;
  389. params.height = height;
  390. return makePtr<GrayCodePattern_Impl>( params );
  391. }
  392. }
  393. }