#include "structured_light.h" #include #include #include namespace sl { const float PIXEL_UNCERTAIN = std::numeric_limits::quiet_NaN(); const unsigned short BIT_UNCERTAIN = 0xffff; } bool sl::decode_pattern(const std::vector & images, cv::Mat & pattern_image, cv::Mat & min_max_image, cv::Size const& projector_size, unsigned flags, const cv::Mat & direct_light, unsigned m) { // for(int i = 0; i < images.size(); i++) { // std::cout<(images.size()); int v_bits = 1; int h_bits = 1; for (int i=(1< Initial images have different size: \n"; return false; } if (robust && gray_image1.size()!=direct_light.size()) { //different size std::cout << " --> Direct Component image has different size: \n"; return false; } pattern_image = cv::Mat(gray_image1.size(), CV_32FC2); min_max_image = cv::Mat(gray_image1.size(), CV_8UC2); } //sanity check if (gray_image1.size()!=pattern_image.size()) { //different size std::cout << " --> Image 1 has different size, image pair " << t << " (skipped!)\n"; continue; } if (gray_image2.size()!=pattern_image.size()) { //different size std::cout << " --> Image 2 has different size, image pair " << t << " (skipped!)\n"; continue; } //compare for (int h=0; h(h); const unsigned char * row2 = gray_image2.ptr(h); const cv::Vec2b * row_light = (robust ? direct_light.ptr(h) : NULL); cv::Vec2f * pattern_row = pattern_image.ptr(h); cv::Vec2b * min_max_row = min_max_image.ptr(h); for (int w=0; wmin_max[1] || value2>min_max[1]) { min_max[1] = (value1>value2?value1:value2); } if (!robust) { // [simple] pattern bit assignment if (value1>value2) { //set bit n to 1 pattern[channel] += (1<Lg) { return (value1>value2 ? 1 : 0); } if (value1<=Ld && value2>=Lg) { return 0; } if (value1>=Lg && value2<=Ld) { return 1; } return BIT_UNCERTAIN; } void sl::convert_pattern(cv::Mat & pattern_image, cv::Size const& projector_size, const int offset[2], bool binary) { if (pattern_image.rows==0) { //no pattern image return; } if (pattern_image.type()!=CV_32FC2) { return; } if (binary) { std::cout << "Converting binary code to gray\n"; } else { std::cout << "Converting gray code to binary\n"; } for (int h=0; h(h); for (int w=0; w(pattern[0]); pattern[0] = binaryToGray(p, offset[0]) + (pattern[0] - p); } if (!INVALID(pattern[1])) { int p = static_cast(pattern[1]); pattern[1] = binaryToGray(p, offset[1]) + (pattern[1] - p); } } else { if (!INVALID(pattern[0])) { int p = static_cast(pattern[0]); int code = grayToBinary(p, offset[0]); if (code<0) {code = 0;} else if (code>=projector_size.width) {code = projector_size.width - 1;} pattern[0] = code + (pattern[0] - p); } if (!INVALID(pattern[1])) { int p = static_cast(pattern[1]); int code = grayToBinary(p, offset[1]); if (code<0) {code = 0;} else if (code>=projector_size.height) {code = projector_size.height - 1;} pattern[1] = code + (pattern[1] - p); } } } } } cv::Mat sl::estimate_direct_light(const std::vector & images, float b) { static const unsigned COUNT = 10; // max number of images unsigned count = static_cast(images.size()); if (count<1) { //no images return cv::Mat(); } std::cout << " --- estimate_direct_light START ---\n"; if (count>COUNT) { count = COUNT; std::cout << "WARNING: Using only " << COUNT << " of " << count << std::endl; } for (unsigned i=0; i(h)(h); } cv::Vec2b * row_light = direct_light.ptr(h); for (unsigned w=0; static_cast(w)row[i][w]) Lmin = row[i][w]; } int Ld = static_cast(b1*(Lmax - Lmin) + 0.5); int Lg = static_cast(b2*(Lmin - b*Lmax) + 0.5); row_light[w][0] = (Lg>0 ? static_cast(Ld) : Lmax); row_light[w][1] = (Lg>0 ? static_cast(Lg) : 0); //std::cout << "Ld=" << (int)row_light[w][0] << " iTotal=" <<(int) row_light[w][1] << std::endl; } } std::cout << " --- estimate_direct_light END ---\n"; return direct_light; } cv::Mat sl::get_gray_image(cv::Mat img) { if (img.channels() > 1) { //gray scale cv::Mat gray_image; cvtColor(img, gray_image, cv::COLOR_BGR2GRAY); return gray_image; } cv::Mat res = img.clone(); return res; } /* From Wikipedia: http://en.wikipedia.org/wiki/Gray_code The purpose of this function is to convert an unsigned binary number to reflected binary Gray code. */ static unsigned util_binaryToGray(unsigned num) { return (num>>1) ^ num; } /* From Wikipedia: http://en.wikipedia.org/wiki/Gray_code The purpose of this function is to convert a reflected binary Gray code number to a binary number. */ static unsigned util_grayToBinary(unsigned num, unsigned numBits) { for (unsigned shift = 1; shift < numBits; shift <<= 1) { num ^= num >> shift; } return num; } int sl::binaryToGray(int value) {return util_binaryToGray(value);} inline int sl::binaryToGray(int value, unsigned offset) {return util_binaryToGray(value + offset);} inline int sl::grayToBinary(int value, unsigned offset) {return (util_grayToBinary(value, 32) - offset);} cv::Mat sl::colorize_pattern(const cv::Mat & pattern_image, unsigned set, float max_value) { if (pattern_image.rows==0) { //empty image return cv::Mat(); } if (pattern_image.type()!=CV_32FC2) { //invalid image type return cv::Mat(); } if (set!=0 && set!=1) { return cv::Mat(); } cv::Mat image(pattern_image.size(), CV_8UC3); float max_t = max_value; float n = 4.f; float dt = 255.f/n; for (int h=0; h(h); cv::Vec3b * row2 = image.ptr(h); for (int w=0; wmax_value || INVALID(row1[w][set])) { //invalid value: use grey row2[w] = cv::Vec3b(128, 128, 128); continue; } //display float t = row1[w][set]*255.f/max_t; float c1 = 0.f, c2 = 0.f, c3 = 0.f; if (t<=1.f*dt) { //black -> red float c = n*(t-0.f*dt); c1 = c; //0-255 c2 = 0.f; //0 c3 = 0.f; //0 } else if (t<=2.f*dt) { //red -> red,green float c = n*(t-1.f*dt); c1 = 255.f; //255 c2 = c; //0-255 c3 = 0.f; //0 } else if (t<=3.f*dt) { //red,green -> green float c = n*(t-2.f*dt); c1 = 255.f-c; //255-0 c2 = 255.f; //255 c3 = 0.f; //0 } else if (t<=4.f*dt) { //green -> blue float c = n*(t-3.f*dt); c1 = 0.f; //0 c2 = 255.f-c; //255-0 c3 = c; //0-255 } row2[w] = cv::Vec3b(static_cast(c3), static_cast(c2), static_cast(c1)); } } return image; }