$search
00001 00002 #include <blort/Tracker/ImageProcessor.h> 00003 #include <blort/TomGine/tgError.h> 00004 00005 using namespace Tracking; 00006 00007 00008 // Load and compile shaders and set parameters 00009 bool ImageProcessor::initShader(){ 00010 int id; 00011 float w = (float)m_width; 00012 float h = (float)m_height; 00013 float hi,lo; 00014 float sq2 = 1.0f/sqrt(2.0f); 00015 00016 // offsets of neighbouring pixels in texture coordinates 00017 GLfloat offX[9] = { -1.0f/w, 0.0, 1.0f/w, 00018 -1.0f/w, 0.0, 1.0f/w, 00019 -1.0f/w, 0.0, 1.0f/w }; 00020 GLfloat offY[9] = { 1.0f/h, 1.0f/h, 1.0f/h, 00021 0.0, 0.0, 0.0, 00022 -1.0f/h,-1.0f/h, -1.0f/h }; 00023 GLfloat dist[9] = { sq2, 1.0f, sq2, 00024 1.0f, 0.0f, 1.0f, 00025 sq2, 1.0f, sq2 }; 00026 GLfloat kernel[25] = { 2, 4, 5, 4, 2, 00027 4, 9, 12, 9, 4, 00028 5, 12, 15, 12, 5, 00029 4, 9, 12, 9, 4, 00030 2, 4, 5, 4, 2 }; 00031 hi = 10.0f/22; // = sqrt((3+10+3)^2 + (3+10+3)^2) = 22.6 00032 lo = 3.0f/22; 00033 GLfloat sobelX[9] = { -lo, 0.0f, lo, 00034 -hi, 0.0f, hi, 00035 -lo, 0.0f, lo }; 00036 // dont modify structure of sobelY -> division in sobel.frag 00037 GLfloat sobelY[9] = { lo, hi, lo, 00038 0.0f, 0.0f, 0.0f, 00039 -lo, -hi, -lo }; 00040 00041 // Gauss shader 00042 id = g_Resources->AddShader("gauss", NULL, "gauss.frag"); 00043 m_shadeGauss = g_Resources->GetShader(id); 00044 m_shadeGauss->bind(); 00045 m_shadeGauss->setUniform( "kernel", 25, kernel ); 00046 m_shadeGauss->setUniform( "width", w); 00047 m_shadeGauss->setUniform( "height", h); 00048 m_shadeGauss->unbind(); 00049 00050 // Sobel shader 00051 id = g_Resources->AddShader("sobel", NULL, "sobel.frag"); 00052 m_shadeSobel = g_Resources->GetShader(id); 00053 m_shadeSobel->bind(); 00054 m_shadeSobel->setUniform( "frame", 0 ); 00055 m_shadeSobel->setUniform( "mask", 1); 00056 m_shadeSobel->setUniform( "binary", false); 00057 m_shadeSobel->setUniform( "mOffsetX", mat3(offX), GL_FALSE ); 00058 m_shadeSobel->setUniform( "mOffsetY", mat3(offY), GL_FALSE ); 00059 m_shadeSobel->setUniform( "mSobelX", mat3(sobelX), GL_FALSE ); 00060 m_shadeSobel->setUniform( "mSobelY", mat3(sobelY), GL_FALSE ); 00061 m_shadeSobel->setUniform( "fThreshold", 0.01f ); 00062 m_shadeSobel->unbind(); 00063 00064 // Thinning shader 00065 id = g_Resources->AddShader("thinning", NULL, "thinning.frag"); 00066 m_shadeThinning = g_Resources->GetShader(id); 00067 m_shadeThinning->bind(); 00068 m_shadeThinning->setUniform( "frame", 0 ); 00069 m_shadeThinning->setUniform( "mask", 1); 00070 m_shadeThinning->setUniform( "mOffsetX", mat3(offX), GL_FALSE ); 00071 m_shadeThinning->setUniform( "mOffsetY", mat3(offY), GL_FALSE ); 00072 m_shadeThinning->setUniform( "fThreshold", 0.0f ); 00073 m_shadeThinning->unbind(); 00074 00075 // Spreading shader 00076 id = g_Resources->AddShader("spreading", NULL, "spreading.frag"); 00077 m_shadeSpreading = g_Resources->GetShader(id); 00078 m_shadeSpreading->bind(); 00079 m_shadeSpreading->setUniform( "mOffsetX", mat3(offX), GL_FALSE ); 00080 m_shadeSpreading->setUniform( "mOffsetY", mat3(offY), GL_FALSE ); 00081 m_shadeSpreading->setUniform( "mDistance", mat3(dist), GL_FALSE ); 00082 m_shadeSpreading->setUniform( "fThreshold", 0.01f ); 00083 m_shadeSpreading->setUniform( "fDistScale", 0.5f ); 00084 m_shadeSpreading->unbind(); 00085 00086 return true; 00087 } 00088 00089 // Display list for normal images (non-rectificating TexCoords) 00090 bool ImageProcessor::dlImage(){ 00091 // float x = float(m_width)*0.5f; 00092 // float y = float(m_height)*0.5f; 00093 // glBegin(GL_QUADS); 00094 // glColor3f(1.0f,1.0f,1.0f); 00095 // glTexCoord2f(0,0); glVertex3f(-x,-y, 0.0f); 00096 // glTexCoord2f(1,0); glVertex3f( x,-y, 0.0f); 00097 // glTexCoord2f(1,1); glVertex3f( x, y, 0.0f); 00098 // glTexCoord2f(0,1); glVertex3f(-x, y, 0.0f); 00099 // glEnd(); 00100 00101 float x = float(m_width); 00102 float y = float(m_height); 00103 glBegin(GL_QUADS); 00104 glColor3f(1.0f,1.0f,1.0f); 00105 glTexCoord2f(0,0); glVertex3f( 0, 0, 0.0f); 00106 glTexCoord2f(1,0); glVertex3f( x, 0, 0.0f); 00107 glTexCoord2f(1,1); glVertex3f( x, y, 0.0f); 00108 glTexCoord2f(0,1); glVertex3f( 0, y, 0.0f); 00109 glEnd(); 00110 00111 return true; 00112 } 00113 00114 bool ImageProcessor::dlImage(float x, float y, float w, float h){ 00115 00116 glBegin(GL_QUADS); 00117 glColor3f(1.0f,1.0f,1.0f); 00118 glTexCoord2f(0.0f,0.0f); glVertex3f(x, y, 0.0f); 00119 glTexCoord2f(1.0f,0.0f); glVertex3f(x+w, y, 0.0f); 00120 glTexCoord2f(1.0f,1.0f); glVertex3f(x+w, y+h, 0.0f); 00121 glTexCoord2f(0.0f,1.0f); glVertex3f(x, y+h, 0.0f); 00122 glEnd(); 00123 00124 return true; 00125 } 00126 00127 // Display list for flipping image upside down 00128 bool ImageProcessor::dlFlipUpsideDown(){ 00129 // float x = float(m_width>>1); 00130 // float y = float(m_height>>1); 00131 // 00132 // glBegin(GL_QUADS); 00133 // glTexCoord2f(0.0f,1.0f); glVertex3f(-x,-y, 0.0f); 00134 // glTexCoord2f(1.0f,1.0f); glVertex3f( x,-y, 0.0f); 00135 // glTexCoord2f(1.0f,0.0f); glVertex3f( x, y, 0.0f); 00136 // glTexCoord2f(0.0f,0.0f); glVertex3f(-x, y, 0.0f); 00137 // glEnd(); 00138 00139 float x = float(m_width); 00140 float y = float(m_height); 00141 00142 glBegin(GL_QUADS); 00143 glTexCoord2f(0.0f,1.0f); glVertex3f( 0, 0, 0.0f); 00144 glTexCoord2f(1.0f,1.0f); glVertex3f( x, 0, 0.0f); 00145 glTexCoord2f(1.0f,0.0f); glVertex3f( x, y, 0.0f); 00146 glTexCoord2f(0.0f,0.0f); glVertex3f( 0, y, 0.0f); 00147 glEnd(); 00148 00149 return true; 00150 } 00151 00152 // Display list for rectificating image (rectificating TexCoords) 00153 bool ImageProcessor::dlRectification(){ 00154 unsigned i,j,n=10; 00155 float x,y; 00156 unsigned w2 = m_width >> 1; 00157 unsigned h2 = m_height >> 1; 00158 00159 // Lens rectificated texture coordinates 00160 glBegin(GL_QUADS); 00161 for (i=0;i<w2;i+=n) { 00162 for (j=0;j<h2;j+=n) { 00163 float fi = float(i); 00164 float fj = float(j); 00165 transform(fi,fj,&x,&y); 00166 glTexCoord2f(x,y); 00167 glVertex3f(fi-w2,fj-h2,0.0f); 00168 00169 transform(fi+n,fj,&x,&y); 00170 glTexCoord2f(x,y); 00171 glVertex3f((fi+n)-w2,fj-h2,0.0f); 00172 00173 transform(fi+n,fj+n,&x,&y); 00174 glTexCoord2f(x,y); 00175 glVertex3f((fi+n)-w2,(fj+n)-h2,0.0f); 00176 00177 transform(fi,fj+n,&x,&y); 00178 glTexCoord2f(x,y); 00179 glVertex3f(fi-w2,(fj+n)-h2,0.0f); 00180 } 00181 } 00182 glEnd(); 00183 return true; 00184 } 00185 00186 // Gets rectificated texture coordinates ix, iy for pixel at position i,j 00187 bool ImageProcessor::transform(float i, float j, float *ix, float *iy){ 00188 float a,b,c,d; 00189 float x,y,xnew,ynew; 00190 float r,theta,rnew,thetanew; 00191 int w = m_width; 00192 int h = m_height; 00193 00194 x = i / (w*0.5f) - 1; 00195 y = j / (h*0.5f) - 1; 00196 r = sqrt(x*x+y*y); 00197 theta = atan2(y,x); 00198 00199 switch (m_lensMode) { 00200 case NONE: 00201 xnew = x; 00202 ynew = y; 00203 break; 00204 case BARREL: 00205 a = -0.005f; 00206 b = 0.0f; 00207 c = 0.0f; 00208 d = 1.0f; 00209 rnew = (a*r*r*r + b*r*r + c*r + d) * r; 00210 thetanew = theta; 00211 xnew = rnew * cos(thetanew); 00212 ynew = rnew * sin(thetanew); 00213 break; 00214 } 00215 *ix = (xnew + 1)*0.5f; 00216 *iy = (ynew + 1)*0.5f; 00217 00218 return true; 00219 } 00220 00221 ImageProcessor::ImageProcessor(){ 00222 m_shadeSobel = 0; 00223 m_shadeThinning = 0; 00224 m_shadeSpreading = 0; 00225 m_sum_init = false; 00226 } 00227 00228 ImageProcessor::~ImageProcessor(){ 00229 glDeleteLists(m_dlRect, 1); 00230 glDeleteLists(m_dlImage, 1); 00231 glDeleteLists(m_dlUpsideDown, 1); 00232 if(m_sum_init){ 00233 glDeleteFramebuffers(1, &fbo); 00234 glDeleteTextures(1,&fbo_tex); 00235 glDeleteTextures(1,&fbo_tex_depth); 00236 } 00237 } 00238 00239 // Set functions 00240 void ImageProcessor::setCamOrtho(){ 00241 m_cam_ortho.Activate(); 00242 } 00243 00244 // *** Image Processing functions *** 00245 void ImageProcessor::flipUpsideDown(Texture* source, Texture* result){ 00246 m_cam_ortho.Activate(); 00247 glEnable(GL_TEXTURE_2D); 00248 source->bind(); 00249 glCallList(m_dlUpsideDown); 00250 result->copyTexImage2D(source->getWidth(), source->getHeight()); 00251 glDisable(GL_TEXTURE_2D); 00252 } 00253 00254 void ImageProcessor::copy(Texture* source, Texture* result){ 00255 m_cam_ortho.Activate(); 00256 glEnable(GL_TEXTURE_2D); 00257 source->bind(); 00258 glCallList(m_dlImage); 00259 result->copyTexImage2D(source->getWidth(), source->getHeight()); 00260 glDisable(GL_TEXTURE_2D); 00261 } 00262 00263 void ImageProcessor::rectification(Texture* source, Texture* result){ 00264 m_cam_ortho.Activate(); 00265 glEnable(GL_TEXTURE_2D); 00266 source->bind(); 00267 glCallList(m_dlRect); 00268 result->copyTexImage2D(source->getWidth(), source->getHeight()); 00269 glDisable(GL_TEXTURE_2D); 00270 } 00271 00272 void ImageProcessor::gauss(Texture* source, Texture* result){ 00273 m_cam_ortho.Activate(); 00274 m_shadeGauss->bind(); 00275 glEnable(GL_TEXTURE_2D); 00276 source->bind(); 00277 glCallList(m_dlImage); 00278 result->copyTexImage2D(source->getWidth(), source->getHeight()); 00279 glDisable(GL_TEXTURE_2D); 00280 m_shadeGauss->unbind(); 00281 } 00282 00283 void ImageProcessor::sobel(Texture* source, Texture* result, float threshold, bool normalise, bool binary){ 00284 m_cam_ortho.Activate(); 00285 m_shadeSobel->bind(); 00286 m_shadeSobel->setUniform( "fThreshold", threshold ); 00287 m_shadeSobel->setUniform( "norm", normalise); 00288 m_shadeSobel->setUniform( "binary", binary); 00289 glEnable(GL_TEXTURE_2D); 00290 source->bind(); 00291 glCallList(m_dlImage); 00292 result->copyTexImage2D(source->getWidth(), source->getHeight()); 00293 glDisable(GL_TEXTURE_2D); 00294 m_shadeSobel->unbind(); 00295 } 00296 00297 void ImageProcessor::sobel(Texture* source, Texture* result, Texture* mask, float threshold, bool normalise, bool binary){ 00298 m_cam_ortho.Activate(); 00299 m_shadeSobel->bind(); 00300 m_shadeSobel->setUniform( "fThreshold", threshold ); 00301 m_shadeSobel->setUniform( "norm", normalise); 00302 m_shadeSobel->setUniform( "masked", true); 00303 m_shadeSobel->setUniform( "binary", binary); 00304 glEnable(GL_TEXTURE_2D); 00305 source->bind(0); 00306 mask->bind(1); 00307 glCallList(m_dlImage); 00308 result->copyTexImage2D(source->getWidth(), source->getHeight()); 00309 glDisable(GL_TEXTURE_2D); 00310 m_shadeSobel->unbind(); 00311 m_shadeSobel->setUniform( "masked", false); 00312 } 00313 00314 void ImageProcessor::thinning(Texture* source, Texture* result){ 00315 m_cam_ortho.Activate(); 00316 glEnable(GL_TEXTURE_2D); 00317 source->bind(); 00318 m_shadeThinning->bind(); 00319 glCallList(m_dlImage); 00320 m_shadeThinning->unbind(); 00321 result->copyTexImage2D(source->getWidth(), source->getHeight()); 00322 glDisable(GL_TEXTURE_2D); 00323 } 00324 00325 void ImageProcessor::thinning(Texture* source, Texture* result, Texture* mask){ 00326 m_cam_ortho.Activate(); 00327 m_shadeThinning->bind(); 00328 m_shadeThinning->setUniform( "masked", true); 00329 glEnable(GL_TEXTURE_2D); 00330 source->bind(0); 00331 mask->bind(1); 00332 glCallList(m_dlImage); 00333 result->copyTexImage2D(source->getWidth(), source->getHeight()); 00334 glDisable(GL_TEXTURE_2D); 00335 m_shadeThinning->setUniform( "masked", false); 00336 m_shadeThinning->unbind(); 00337 } 00338 00339 void ImageProcessor::spreading(Texture* source, Texture* result){ 00340 m_cam_ortho.Activate(); 00341 glEnable(GL_TEXTURE_2D); 00342 source->bind(); 00343 m_shadeSpreading->bind(); 00344 glCallList(m_dlImage); 00345 m_shadeSpreading->unbind(); 00346 result->copyTexImage2D(source->getWidth(), source->getHeight()); 00347 glDisable(GL_TEXTURE_2D);; 00348 } 00349 00350 void ImageProcessor::render(Texture* tex){ 00351 m_cam_ortho.Activate(); 00352 glEnable(GL_TEXTURE_2D); 00353 tex->bind(); 00354 glCallList(m_dlImage); 00355 glDisable(GL_TEXTURE_2D); 00356 } 00357 00358 void ImageProcessor::render(Texture* tex, int x, int y, unsigned w, unsigned h){ 00359 m_cam_ortho.Activate(); 00360 glEnable(GL_TEXTURE_2D); 00361 tex->bind(); 00362 dlImage((float)x, (float)y, (float)w, (float)h); 00363 glDisable(GL_TEXTURE_2D); 00364 } 00365 00366 GLenum ImageProcessor::avgInit(int res) 00367 { 00368 if(res < 16) 00369 ROS_DEBUG("[ImageProcessor::avgInit] Warning: resolution too low\n"); // doesn't make sense computing low number of sums on GPU 00370 00371 bool res_valid = false; 00372 for(unsigned i=4; i<13; i++) 00373 if(res == pow(2,i)) 00374 res_valid = true; 00375 00376 if(!res_valid) 00377 ROS_DEBUG("[ImageProcessor::avgInit] Warning: resolution must be power of 2 and in the range of 16 to 4048\n"); 00378 00379 fbo_res = res; 00380 00381 00382 glGenTextures(1, &fbo_tex_depth); 00383 glBindTexture(GL_TEXTURE_2D, fbo_tex_depth); 00384 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); 00385 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); 00386 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 00387 glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE); // for attaching to fbo texture must be mipmap complete 00388 // glTexImage2D( GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT32, fbo_res, fbo_res, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, NULL); 00389 00390 // Texture (=memory) for fbo 00391 glGenTextures(1, &fbo_tex); 00392 glBindTexture(GL_TEXTURE_2D, fbo_tex); 00393 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); 00394 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); 00395 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 00396 glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE); // for attaching to fbo texture must be mipmap complete 00397 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, fbo_res, fbo_res, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL); 00398 00399 00400 // fbo = framebuffer object 00401 glGenFramebuffers(1,&fbo); 00402 glBindFramebuffer(GL_FRAMEBUFFER, fbo); 00403 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, fbo_tex, 0); 00404 // glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, fbo_tex_depth, 0); 00405 00406 m_cam_ortho_fbo.Set( 0.0f, 0.0f, 1.0f, 00407 0.0f, 0.0f, 0.0f, 00408 0.0f, 1.0f, 0.0f, 00409 45.0f, fbo_res, fbo_res, 00410 0.0f, 1.0f, 00411 GL_ORTHO); 00412 00413 glBindFramebuffer(GL_FRAMEBUFFER, 0); 00414 00415 fbo_stage = ilog2(fbo_res); 00416 m_sum_init = true; 00417 00418 tgCheckFBError(GL_FRAMEBUFFER, "ImageProcessor::avgInit()"); 00419 return tgCheckError("ImageProcessor::avgInit()"); 00420 } 00421 00422 void ImageProcessor::avgActivate(){ 00423 if(m_sum_init){ 00424 glBindFramebuffer(GL_FRAMEBUFFER, fbo); 00425 tgCheckError("ImageProcessor::avgActivate() A"); 00426 glClearColor(0,0,0,0); 00427 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 00428 tgCheckError("ImageProcessor::avgActivate() B"); 00429 } 00430 } 00431 00432 void ImageProcessor::avgGet(float *avg, int lvl){ 00433 if(m_sum_init){ 00434 if(lvl==0){ 00435 // for some reason glGetTexImage doesen't get the value of the very last mipmap stage 00436 // float tmp[16]; 00437 // glBindTexture(GL_TEXTURE_2D, fbo_tex); 00438 // glGenerateMipmap(GL_TEXTURE_2D); 00439 // glGetTexImage(GL_TEXTURE_2D, fbo_stage-1, GL_RGBA, GL_FLOAT, tmp); 00440 // avg[0] = 0; 00441 // for(unsigned i=0; i<4; i++) 00442 // avg[0] += 0.25 * tmp[i]; 00443 ROS_DEBUG("[ImageProcessor::avgGet] Warning: not implemented\n"); 00444 }else{ 00445 glBindTexture(GL_TEXTURE_2D, fbo_tex); 00446 // glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGB16,0, 0, fbo_res,fbo_res,0); 00447 glGenerateMipmap(GL_TEXTURE_2D); 00448 glGetTexImage(GL_TEXTURE_2D, fbo_stage-lvl, GL_RED, GL_FLOAT, avg); 00449 tgCheckError("ImageProcessor::avgGet()"); 00450 } 00451 } 00452 } 00453 00454 void ImageProcessor::avgDeactivate(){ 00455 if(m_sum_init){ 00456 glBindFramebuffer(GL_FRAMEBUFFER, 0); 00457 } 00458 } 00459 00460 // Main initialisation function 00461 bool ImageProcessor::init(unsigned w, unsigned h){ 00462 00463 m_width = w; 00464 m_height = h; 00465 00466 // Initialise camera 00467 m_cam_ortho.Set( 0.0f, 0.0f, 1.0f, 00468 0.0f, 0.0f, 0.0f, 00469 0.0f, 1.0f, 0.0f, 00470 45.0f, w, h, 00471 0.1f, 10.0f, 00472 GL_ORTHO); 00473 00474 // Initialize shaders 00475 if(!initShader()) 00476 return false; 00477 00478 00479 // Setup display lists 00480 m_dlRect = glGenLists(1); 00481 m_lensMode = BARREL; 00482 glNewList(m_dlRect, GL_COMPILE); 00483 dlRectification(); 00484 glEndList(); 00485 00486 m_dlImage = glGenLists(1); 00487 glNewList(m_dlImage, GL_COMPILE); 00488 dlImage(); 00489 glEndList(); 00490 00491 m_dlUpsideDown = glGenLists(1); 00492 glNewList(m_dlUpsideDown, GL_COMPILE); 00493 dlFlipUpsideDown(); 00494 glEndList(); 00495 00496 return true; 00497 } 00498 00499