example.hpp
Go to the documentation of this file.
00001 // License: Apache 2.0. See LICENSE file in root directory.
00002 // Copyright(c) 2015 Intel Corporation. All Rights Reserved.
00003 
00004 #define GLFW_INCLUDE_GLU
00005 #include <GLFW/glfw3.h>
00006 
00007 #include <sstream>
00008 #include <vector>
00009 
00010 inline void make_depth_histogram(uint8_t rgb_image[640*480*3], const uint16_t depth_image[], int width, int height)
00011 {
00012     static uint32_t histogram[0x10000];
00013     memset(histogram, 0, sizeof(histogram));
00014 
00015     for(int i = 0; i < width*height; ++i) ++histogram[depth_image[i]];
00016     for(int i = 2; i < 0x10000; ++i) histogram[i] += histogram[i-1]; // Build a cumulative histogram for the indices in [1,0xFFFF]
00017     for(int i = 0; i < width*height; ++i)
00018     {
00019         if(uint16_t d = depth_image[i])
00020         {
00021             int f = histogram[d] * 255 / histogram[0xFFFF]; // 0-255 based on histogram location
00022             rgb_image[i*3 + 0] = 255 - f;
00023             rgb_image[i*3 + 1] = 0;
00024             rgb_image[i*3 + 2] = f;
00025         }
00026         else
00027         {
00028             rgb_image[i*3 + 0] = 20;
00029             rgb_image[i*3 + 1] = 5;
00030             rgb_image[i*3 + 2] = 0;
00031         }
00032     }
00033 }
00034 
00036 // Simple font loading code //
00038 
00039 #include "third_party/stb_easy_font.h"
00040 
00041 inline int get_text_width(const char * text)
00042 {
00043     return stb_easy_font_width((char *)text);
00044 }
00045 
00046 inline void draw_text(int x, int y, const char * text)
00047 {
00048     char buffer[60000]; // ~300 chars
00049     glEnableClientState(GL_VERTEX_ARRAY);
00050     glVertexPointer(2, GL_FLOAT, 16, buffer);
00051     glDrawArrays(GL_QUADS, 0, 4*stb_easy_font_print((float)x, (float)(y-7), (char *)text, nullptr, buffer, sizeof(buffer)));
00052     glDisableClientState(GL_VERTEX_ARRAY);
00053 }
00054 
00056 // Image display code //
00058 
00059 class texture_buffer
00060 {
00061     GLuint texture;
00062     double last_timestamp;
00063     std::vector<uint8_t> rgb;
00064 
00065     int fps, num_frames;
00066     double next_time;
00067 
00068 public:
00069     texture_buffer() : texture(), last_timestamp(-1), fps(), num_frames(), next_time(1000) {}
00070 
00071     GLuint get_gl_handle() const { return texture; }
00072 
00073     void upload(const void * data, int width, int height, rs::format format, int stride = 0)
00074     {
00075         // If the frame timestamp has changed since the last time show(...) was called, re-upload the texture
00076         if(!texture) glGenTextures(1, &texture);
00077         glBindTexture(GL_TEXTURE_2D, texture);
00078         stride = stride == 0 ? width : stride;
00079         glPixelStorei(GL_UNPACK_ROW_LENGTH, stride);
00080         switch(format)
00081         {
00082         case rs::format::any:
00083         throw std::runtime_error("not a valid format");
00084         case rs::format::z16:
00085         case rs::format::disparity16:
00086             rgb.resize(stride * height * 3);
00087             make_depth_histogram(rgb.data(), reinterpret_cast<const uint16_t *>(data), stride, height);
00088             glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, stride, height, 0, GL_RGB, GL_UNSIGNED_BYTE, rgb.data());
00089             
00090             break;
00091         case rs::format::xyz32f:
00092             glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_FLOAT, data);
00093             break;
00094         case rs::format::yuyv: // Display YUYV by showing the luminance channel and packing chrominance into ignored alpha channel
00095             glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, data);
00096             break;
00097         case rs::format::rgb8: case rs::format::bgr8: // Display both RGB and BGR by interpreting them RGB, to show the flipped byte ordering. Obviously, GL_BGR could be used on OpenGL 1.2+
00098             glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, data);
00099             break;
00100         case rs::format::rgba8: case rs::format::bgra8: // Display both RGBA and BGRA by interpreting them RGBA, to show the flipped byte ordering. Obviously, GL_BGRA could be used on OpenGL 1.2+
00101             glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
00102             break;
00103         case rs::format::y8:
00104             glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB,  width, height, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, data);
00105             break;
00106         case rs::format::y16:
00107             glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_LUMINANCE, GL_UNSIGNED_SHORT, data);
00108             break;
00109         case rs::format::raw8:
00110             glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, width, height, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, data);
00111             break;
00112         case rs::format::raw10:
00113             {
00114                 // Visualize Raw10 by performing a naive downsample. Each 2x2 block contains one red pixel, two green pixels, and one blue pixel, so combine them into a single RGB triple.
00115                 rgb.clear(); rgb.resize(width/2 * height/2 * 3);
00116                 auto out = rgb.data(); auto in0 = reinterpret_cast<const uint8_t *>(data), in1 = in0 + width*5/4;
00117                 for(int y=0; y<height; y+=2)
00118                 {
00119                     for(int x=0; x<width; x+=4)
00120                     {
00121                         *out++ = in0[0]; *out++ = (in0[1] + in1[0]) / 2; *out++ = in1[1]; // RGRG -> RGB RGB
00122                         *out++ = in0[2]; *out++ = (in0[3] + in1[2]) / 2; *out++ = in1[3]; // GBGB
00123                         in0 += 5; in1 += 5;
00124                     }
00125                     in0 = in1; in1 += width*5/4;
00126                 }
00127                 glPixelStorei(GL_UNPACK_ROW_LENGTH, width / 2);        // Update row stride to reflect post-downsampling dimensions of the target texture
00128                 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width/2, height/2, 0, GL_RGB, GL_UNSIGNED_BYTE, rgb.data());
00129             }
00130             break;
00131         case rs::format::raw16:
00132             // All RAW formats will be treated and displayed as Greyscale images
00133             glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_LUMINANCE, GL_UNSIGNED_SHORT, data);
00134             break;
00135         default:
00136             {
00137                 std::stringstream ss;
00138                 ss << rs_format_to_string((rs_format)format) << " pixel format is not supported by the demo";
00139                 throw std::runtime_error(ss.str().c_str());
00140             }
00141         }
00142         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
00143         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
00144         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
00145         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
00146         glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
00147         glBindTexture(GL_TEXTURE_2D, 0);
00148     }
00149 
00150     void upload(rs::device & dev, rs::stream stream)
00151     {
00152         if (stream <= rs::stream::fisheye)
00153             assert(dev.is_stream_enabled(stream));
00154 
00155         const double timestamp = dev.get_frame_timestamp(stream);
00156         if(timestamp != last_timestamp)
00157         {
00158             upload(dev.get_frame_data(stream), dev.get_stream_width(stream), dev.get_stream_height(stream), dev.get_stream_format(stream));
00159             last_timestamp = timestamp;
00160 
00161             ++num_frames;
00162             if(timestamp >= next_time)
00163             {
00164                 fps = num_frames;
00165                 num_frames = 0;
00166                 next_time += 1000;
00167             }
00168         }
00169     }
00170 
00171     void upload(rs::frame& frame)
00172     {
00173         const double timestamp = frame.get_timestamp();
00174         if(timestamp != last_timestamp)
00175         {
00176             upload(frame.get_data(), frame.get_width(), frame.get_height(), frame.get_format(), (frame.get_stride() * 8) / frame.get_bpp());
00177             last_timestamp = timestamp;
00178 
00179             ++num_frames;
00180             if(timestamp >= next_time)
00181             {
00182                 fps = num_frames;
00183                 num_frames = 0;
00184                 next_time += 1000;
00185             }
00186         }
00187     }
00188 
00189     void show(float rx, float ry, float rw, float rh) const
00190     {
00191         glBindTexture(GL_TEXTURE_2D, texture);
00192         glEnable(GL_TEXTURE_2D);
00193         glBegin(GL_QUADS);
00194         glTexCoord2f(0, 0); glVertex2f(rx,    ry   );
00195         glTexCoord2f(1, 0); glVertex2f(rx+rw, ry   );
00196         glTexCoord2f(1, 1); glVertex2f(rx+rw, ry+rh);
00197         glTexCoord2f(0, 1); glVertex2f(rx,    ry+rh);
00198         glEnd();
00199         glDisable(GL_TEXTURE_2D);
00200         glBindTexture(GL_TEXTURE_2D, 0);
00201     }
00202 
00203     void print(int x, int y, const char * text)
00204     {
00205         char buffer[20000]; // ~100 chars
00206 
00207         glEnableClientState(GL_VERTEX_ARRAY);
00208         glVertexPointer(2, GL_FLOAT, 16, buffer);
00209         glDrawArrays(GL_QUADS, 0, 4*stb_easy_font_print((float)x, (float)y, (char *)text, nullptr, buffer, sizeof(buffer)));
00210         glDisableClientState(GL_VERTEX_ARRAY);
00211     }
00212 
00213     void show(rs::device & dev, rs::stream stream, int rx, int ry, int rw, int rh)
00214     {
00215         if((stream <= rs::stream::fisheye) && (!dev.is_stream_enabled(stream))) return;
00216 
00217         upload(dev, stream);
00218         
00219         int width = dev.get_stream_width(stream), height = dev.get_stream_height(stream);
00220         float h = (float)rh, w = (float)rh * width / height;
00221         if(w > rw)
00222         {
00223             float scale = rw/w;
00224             w *= scale;
00225             h *= scale;
00226         }
00227 
00228         show(rx + (rw - w)/2, ry + (rh - h)/2, w, h);
00229         std::ostringstream ss; ss << stream << ": " << width << " x " << height << " " << dev.get_stream_format(stream) << " (" << fps << "/" << dev.get_stream_framerate(stream) << ")" << ", F#: " << dev.get_frame_number(stream);
00230         glColor3f(0,0,0);
00231         draw_text(rx+9, ry+17, ss.str().c_str());
00232         glColor3f(1,1,1);
00233         draw_text(rx+8, ry+16, ss.str().c_str());
00234     }
00235 
00236     void show(rs::stream stream, rs::format format, int stream_framerate, unsigned long long frame_number, double timestamp, int rx, int ry, int rw, int rh, int width, int height)
00237     {
00238         show(rx, ry, rw, rh, width, height);
00239 
00240         std::ostringstream ss; ss << stream << ": " << width << " x " << height << " " << format << " (" << fps << "/" << stream_framerate << ")" << ", F#: " << frame_number << ", TS: " << timestamp;
00241         glColor3f(0,0,0);
00242         draw_text(rx+9, ry+17, ss.str().c_str());
00243         glColor3f(1,1,1);
00244         draw_text(rx+8, ry+16, ss.str().c_str());
00245     }
00246 
00247     void show(int rx, int ry, int rw, int rh, int width, int height)
00248     {
00249         float h = (float)rh, w = (float)rh * width / height;
00250         if (w > rw)
00251         {
00252             float scale = rw / w;
00253             w *= scale;
00254             h *= scale;
00255         }
00256 
00257         show(rx + (rw - w) / 2, ry + (rh - h) / 2, w, h);
00258     }
00259 
00260     void show(const void * data, int width, int height, rs::format format, const std::string & caption, int rx, int ry, int rw, int rh)
00261     {
00262         if(!data) return;
00263 
00264         upload(data, width, height, format);
00265         
00266         float h = (float)rh, w = (float)rh * width / height;
00267         if(w > rw)
00268         {
00269             float scale = rw/w;
00270             w *= scale;
00271             h *= scale;
00272         }
00273 
00274         show(rx + (rw - w)/2, ry + (rh - h)/2, w, h);
00275 
00276         std::ostringstream ss; ss << caption << ": " << width << " x " << height << " " << format;
00277         glColor3f(0,0,0);
00278         draw_text(rx+9, ry+17, ss.str().c_str());
00279         glColor3f(1,1,1);
00280         draw_text(rx+8, ry+16, ss.str().c_str());
00281     }
00282 };
00283 
00284 inline void draw_depth_histogram(const uint16_t depth_image[], int width, int height)
00285 {
00286     static uint8_t rgb_image[640*480*3];
00287     make_depth_histogram(rgb_image, depth_image, width, height);
00288     glDrawPixels(width, height, GL_RGB, GL_UNSIGNED_BYTE, rgb_image);
00289 }


librealsense
Author(s): Sergey Dorodnicov , Mark Horn , Reagan Lopez
autogenerated on Tue Jun 25 2019 19:54:38