00001
00002 #include <blort/TomGine/tgImageProcessor.h>
00003 #include <blort/TomGine/tgError.h>
00004 #include <stdexcept>
00005
00006 using namespace TomGine;
00007
00008 tgImageProcessor::tgImageProcessor( const char *gauss_frag_file,
00009 const char *sobel_frag_file,
00010 const char *thinning_frag_file,
00011 const char *spreading_frag_file,
00012 unsigned img_width, unsigned img_height,
00013 int avg_resolution)
00014 {
00015 m_shadeGauss = new tgShader(NULL, gauss_frag_file, NULL);
00016 m_shadeSobel = new tgShader(NULL, sobel_frag_file, NULL);
00017 m_shadeThinning = new tgShader(NULL, thinning_frag_file, NULL);
00018 m_shadeSpreading = new tgShader(NULL, spreading_frag_file, NULL);
00019
00020 init(img_width, img_height);
00021 initShader((float)img_width, (float)img_height);
00022 initFBO(avg_resolution);
00023 tgCheckError("[tgImageProcessor::tgImageProcessor()]");
00024 }
00025
00026 tgImageProcessor::~tgImageProcessor(){
00027 if(glIsFramebuffer(fbo)) glDeleteFramebuffers(1, &fbo);
00028 if(glIsTexture(fbo_tex)) glDeleteTextures(1,&fbo_tex);
00029 if(glIsTexture(fbo_tex_depth)) glDeleteTextures(1,&fbo_tex_depth);
00030
00031 if(m_shadeGauss) delete(m_shadeGauss);
00032 if(m_shadeSobel) delete(m_shadeSobel);
00033 if(m_shadeThinning) delete(m_shadeThinning);
00034 if(m_shadeSpreading) delete(m_shadeSpreading);
00035 }
00036
00037
00038 void tgImageProcessor::init(unsigned width, unsigned height){
00039
00040 m_width = width;
00041 m_height = height;
00042
00043
00044 m_cam_ortho.Set( 0.0f, 0.0f, 1.0f,
00045 0.0f, 0.0f, 0.0f,
00046 0.0f, 1.0f, 0.0f,
00047 45.0f, m_width, m_height,
00048 0.1f, 10.0f,
00049 GL_ORTHO);
00050 }
00051
00052
00053 void tgImageProcessor::initShader(float w, float h){
00054 float sq2 = 1.0f/sqrt(2.0f);
00055
00056
00057 GLfloat offX[9] = { -1.0f/w, 0.0, 1.0f/w,
00058 -1.0f/w, 0.0, 1.0f/w,
00059 -1.0f/w, 0.0, 1.0f/w };
00060 GLfloat offY[9] = { 1.0f/h, 1.0f/h, 1.0f/h,
00061 0.0, 0.0, 0.0,
00062 -1.0f/h,-1.0f/h, -1.0f/h };
00063
00064
00065 GLfloat dist[9] = { sq2, 1.0f, sq2,
00066 1.0f, 0.0f, 1.0f,
00067 sq2, 1.0f, sq2 };
00068 GLfloat kernel[25] = { 2, 4, 5, 4, 2,
00069 4, 9, 12, 9, 4,
00070 5, 12, 15, 12, 5,
00071 4, 9, 12, 9, 4,
00072 2, 4, 5, 4, 2 };
00073 float hi = 10.0f/22;
00074 float lo = 3.0f/22;
00075 GLfloat sobelX[9] = { -lo, 0.0f, lo,
00076 -hi, 0.0f, hi,
00077 -lo, 0.0f, lo };
00078
00079 GLfloat sobelY[9] = { lo, hi, lo,
00080 0.0f, 0.0f, 0.0f,
00081 -lo, -hi, -lo };
00082
00083
00084 m_shadeGauss->bind();
00085 m_shadeGauss->setUniform( "kernel", 25, kernel );
00086 m_shadeGauss->setUniform( "width", w);
00087 m_shadeGauss->setUniform( "height", h);
00088 m_shadeGauss->unbind();
00089
00090
00091 m_shadeSobel->bind();
00092 m_shadeSobel->setUniform( "frame", 0 );
00093 m_shadeSobel->setUniform( "mask", 1);
00094 m_shadeSobel->setUniform( "binary", false);
00095 m_shadeSobel->setUniform( "mOffsetX", mat3(offX), GL_FALSE );
00096 m_shadeSobel->setUniform( "mOffsetY", mat3(offY), GL_FALSE );
00097 m_shadeSobel->setUniform( "mSobelX", mat3(sobelX), GL_FALSE );
00098 m_shadeSobel->setUniform( "mSobelY", mat3(sobelY), GL_FALSE );
00099 m_shadeSobel->setUniform( "fThreshold", 0.1f );
00100 m_shadeSobel->unbind();
00101
00102
00103 m_shadeThinning->bind();
00104 m_shadeThinning->setUniform( "frame", 0 );
00105 m_shadeThinning->setUniform( "mask", 1);
00106 m_shadeThinning->setUniform( "mOffsetX", mat3(offX), GL_FALSE );
00107 m_shadeThinning->setUniform( "mOffsetY", mat3(offY), GL_FALSE );
00108 m_shadeThinning->setUniform( "fThreshold", 0.1f );
00109 m_shadeThinning->unbind();
00110
00111
00112 m_shadeSpreading->bind();
00113 m_shadeSpreading->setUniform( "mOffsetX", mat3(offX), GL_FALSE );
00114 m_shadeSpreading->setUniform( "mOffsetY", mat3(offY), GL_FALSE );
00115 m_shadeSpreading->setUniform( "mDistance", mat3(dist), GL_FALSE );
00116 m_shadeSpreading->setUniform( "fThreshold", 0.1f );
00117 m_shadeSpreading->setUniform( "fDistScale", 0.5f );
00118 m_shadeSpreading->unbind();
00119 }
00120
00121 void tgImageProcessor::initFBO(int res)
00122 {
00123 if(res < 16)
00124 printf("[tgImageProcessor::avgInit] Warning: resolution too low\n");
00125
00126 bool res_valid = false;
00127 for(unsigned i=4; i<13; i++)
00128 if(res == pow(2,i))
00129 res_valid = true;
00130
00131 if(!res_valid)
00132 printf("[tgImageProcessor::avgInit] Warning: resolution must be power of 2 and in the range of 16 to 4048\n");
00133
00134 fbo_res = res;
00135
00136 glGenTextures(1, &fbo_tex_depth);
00137 glBindTexture(GL_TEXTURE_2D, fbo_tex_depth);
00138 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
00139 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
00140 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
00141 glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE);
00142
00143
00144
00145 glGenTextures(1, &fbo_tex);
00146 glBindTexture(GL_TEXTURE_2D, fbo_tex);
00147 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
00148 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
00149 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
00150 glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE);
00151 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, fbo_res, fbo_res, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
00152
00153
00154
00155 glGenFramebuffers(1,&fbo);
00156 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
00157 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, fbo_tex, 0);
00158
00159
00160 m_cam_ortho_fbo.Set( 0.0f, 0.0f, 1.0f,
00161 0.0f, 0.0f, 0.0f,
00162 0.0f, 1.0f, 0.0f,
00163 45.0f, fbo_res, fbo_res,
00164 0.0f, 1.0f,
00165 GL_ORTHO);
00166
00167 glBindFramebuffer(GL_FRAMEBUFFER, 0);
00168
00169 fbo_stage = ilog2(fbo_res);
00170 m_avg_init = true;
00171
00172 if( tgCheckFBError(GL_FRAMEBUFFER, "tgImageProcessor::avgInit()")!=GL_FRAMEBUFFER_COMPLETE ||
00173 tgCheckError("tgImageProcessor::avgInit()")!=GL_NO_ERROR)
00174 {
00175 std::string errmsg = std::string("[tgImageProcessor::initFBO()] Error generating frame buffer objects");
00176 throw std::runtime_error(errmsg.c_str());
00177 }
00178 }
00179
00180 void tgImageProcessor::drawQuad(float w, float h){
00181 glBegin(GL_QUADS);
00182 glTexCoord2f(0.0f,0.0f); glVertex3f( 0, 0, 0.0f);
00183 glTexCoord2f(1.0f,0.0f); glVertex3f( w, 0, 0.0f);
00184 glTexCoord2f(1.0f,1.0f); glVertex3f( w, h, 0.0f);
00185 glTexCoord2f(0.0f,1.0f); glVertex3f( 0, h, 0.0f);
00186 glEnd();
00187 }
00188
00189
00190 void tgImageProcessor::drawQuadUpsideDown(float w, float h){
00191 glBegin(GL_QUADS);
00192 glTexCoord2f(0.0f,1.0f); glVertex3f( 0, 0, 0.0f);
00193 glTexCoord2f(1.0f,1.0f); glVertex3f( w, 0, 0.0f);
00194 glTexCoord2f(1.0f,0.0f); glVertex3f( w, h, 0.0f);
00195 glTexCoord2f(0.0f,0.0f); glVertex3f( 0, h, 0.0f);
00196 glEnd();
00197 }
00198
00199
00200 void tgImageProcessor::setCamOrtho(){
00201 m_cam_ortho.Activate();
00202 }
00203
00204
00205 void tgImageProcessor::flipUpsideDown(const tgTexture& source, tgTexture& result){
00206 int w = source.GetWidth();
00207 int h = source.GetHeight();
00208 m_cam_ortho.Activate();
00209 glEnable(GL_TEXTURE_2D);
00210 source.Bind();
00211 drawQuadUpsideDown(w, h);
00212 result.CopyTexImage2D(w, h);
00213 glDisable(GL_TEXTURE_2D);
00214 }
00215
00216 void tgImageProcessor::copy(const tgTexture& source, tgTexture& result){
00217 int w = source.GetWidth();
00218 int h = source.GetHeight();
00219 m_cam_ortho.Activate();
00220 glEnable(GL_TEXTURE_2D);
00221 source.Bind();
00222 drawQuad(w,h);
00223 result.CopyTexImage2D(w, h);
00224 glDisable(GL_TEXTURE_2D);
00225 }
00226
00227 void tgImageProcessor::gauss(const tgTexture& source, tgTexture& result){
00228 int w = source.GetWidth();
00229 int h = source.GetHeight();
00230 m_cam_ortho.Activate();
00231 m_shadeGauss->bind();
00232 glEnable(GL_TEXTURE_2D);
00233 source.Bind();
00234 drawQuad(w,h);
00235 result.CopyTexImage2D(w, h);
00236 glDisable(GL_TEXTURE_2D);
00237 m_shadeGauss->unbind();
00238 }
00239
00240 void tgImageProcessor::sobel(const tgTexture& source, tgTexture& result, float threshold, bool normalise, bool binary){
00241 int w = source.GetWidth();
00242 int h = source.GetHeight();
00243 m_cam_ortho.Activate();
00244 m_shadeSobel->bind();
00245 m_shadeSobel->setUniform( "fThreshold", threshold );
00246 m_shadeSobel->setUniform( "norm", normalise);
00247 m_shadeSobel->setUniform( "binary", binary);
00248 glEnable(GL_TEXTURE_2D);
00249 source.Bind();
00250 drawQuad(w,h);
00251 result.CopyTexImage2D(w, h);
00252 glDisable(GL_TEXTURE_2D);
00253 m_shadeSobel->unbind();
00254 }
00255
00256 void tgImageProcessor::sobel(const tgTexture& source, tgTexture& result, tgTexture& mask, float threshold, bool normalise, bool binary){
00257 int w = source.GetWidth();
00258 int h = source.GetHeight();
00259 m_cam_ortho.Activate();
00260 m_shadeSobel->bind();
00261 m_shadeSobel->setUniform( "fThreshold", threshold );
00262 m_shadeSobel->setUniform( "norm", normalise);
00263 m_shadeSobel->setUniform( "masked", true);
00264 m_shadeSobel->setUniform( "binary", binary);
00265 glEnable(GL_TEXTURE_2D);
00266 source.Bind(0);
00267 mask.Bind(1);
00268 drawQuad(w,h);
00269 result.CopyTexImage2D(w, h);
00270 glDisable(GL_TEXTURE_2D);
00271 m_shadeSobel->unbind();
00272 m_shadeSobel->setUniform( "masked", false);
00273 }
00274
00275 void tgImageProcessor::thinning(const tgTexture& source, tgTexture& result){
00276 int w = source.GetWidth();
00277 int h = source.GetHeight();
00278 m_cam_ortho.Activate();
00279 m_shadeThinning->bind();
00280 glEnable(GL_TEXTURE_2D);
00281 source.Bind();
00282 drawQuad(w,h);
00283 result.CopyTexImage2D(w, h);
00284 glDisable(GL_TEXTURE_2D);
00285 m_shadeThinning->unbind();
00286 }
00287
00288 void tgImageProcessor::thinning(const tgTexture& source, tgTexture& result, tgTexture& mask){
00289 int w = source.GetWidth();
00290 int h = source.GetHeight();
00291 m_cam_ortho.Activate();
00292 m_shadeThinning->bind();
00293 m_shadeThinning->setUniform( "masked", true);
00294 glEnable(GL_TEXTURE_2D);
00295 source.Bind(0);
00296 mask.Bind(1);
00297 drawQuad(w,h);
00298 result.CopyTexImage2D(w, h);
00299 glDisable(GL_TEXTURE_2D);
00300 m_shadeThinning->setUniform( "masked", false);
00301 m_shadeThinning->unbind();
00302 }
00303
00304 void tgImageProcessor::spreading(const tgTexture& source, tgTexture& result){
00305 int w = source.GetWidth();
00306 int h = source.GetHeight();
00307 m_cam_ortho.Activate();
00308 m_shadeSpreading->bind();
00309 glEnable(GL_TEXTURE_2D);
00310 source.Bind();
00311 drawQuad(w,h);
00312 result.CopyTexImage2D(w, h);
00313 glDisable(GL_TEXTURE_2D);
00314 m_shadeSpreading->unbind();
00315 }
00316
00317 void tgImageProcessor::render(const tgTexture& tex){
00318 m_cam_ortho.Activate();
00319 glEnable(GL_TEXTURE_2D);
00320 tex.Bind();
00321 drawQuad(tex.GetWidth(), tex.GetHeight());
00322 glDisable(GL_TEXTURE_2D);
00323 }
00324
00325 void tgImageProcessor::avgActivate(){
00326 if(m_avg_init){
00327 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
00328 tgCheckError("tgImageProcessor::avgActivate() A");
00329 glClearColor(0,0,0,0);
00330 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
00331 tgCheckError("tgImageProcessor::avgActivate() B");
00332 }
00333 }
00334
00335 void tgImageProcessor::avgGet(float *avg, int lvl){
00336 if(m_avg_init){
00337 if(lvl==0){
00338
00339
00340
00341
00342
00343
00344
00345
00346 printf("[tgImageProcessor::avgGet] Warning: not implemented\n");
00347 }else{
00348 glBindTexture(GL_TEXTURE_2D, fbo_tex);
00349
00350 glGenerateMipmap(GL_TEXTURE_2D);
00351 glGetTexImage(GL_TEXTURE_2D, fbo_stage-lvl, GL_RED, GL_FLOAT, avg);
00352 tgCheckError("tgImageProcessor::avgGet()");
00353 }
00354 }
00355 }
00356
00357 void tgImageProcessor::avgDeactivate(){
00358 if(m_avg_init){
00359 glBindFramebuffer(GL_FRAMEBUFFER, 0);
00360 }
00361 }
00362
00363
00364
00365