inlib
1.2.0
|
00001 // Copyright (C) 2010, Guy Barrand. All rights reserved. 00002 // See the file inlib.license for terms. 00003 00004 #ifndef inlib_img 00005 #define inlib_img 00006 00007 #ifdef INLIB_MEM 00008 #include "mem" 00009 #endif 00010 00011 #include <string> //memcpy 00012 #include <cstring> //memcpy 00013 #include "mnmx" 00014 00015 #include <vector> //concatenate 00016 00017 namespace inlib { 00018 00019 template <class T> 00020 class img { 00021 static const std::string& s_class() { 00022 static const std::string s_v("inlib::img"); 00023 return s_v; 00024 } 00025 public: 00026 img(unsigned int a_n) 00027 :m_w(0),m_h(0),m_n(a_n) 00028 ,m_buffer(0) 00029 ,m_owner(false) 00030 { 00031 #ifdef INLIB_MEM 00032 mem::increment(s_class().c_str()); 00033 #endif 00034 } 00035 img(unsigned int a_w,unsigned int a_h,unsigned int a_n, 00036 T* a_buffer,bool a_owner) 00037 :m_w(a_w),m_h(a_h),m_n(a_n) 00038 ,m_buffer(a_buffer) 00039 ,m_owner(a_owner) 00040 { 00041 #ifdef INLIB_MEM 00042 mem::increment(s_class().c_str()); 00043 #endif 00044 } 00045 virtual ~img() { 00046 if(m_owner) delete [] m_buffer; 00047 #ifdef INLIB_MEM 00048 mem::decrement(s_class().c_str()); 00049 #endif 00050 } 00051 public: 00052 img(const img& a_from) 00053 :m_w(a_from.m_w),m_h(a_from.m_h),m_n(a_from.m_n) 00054 ,m_buffer(0) 00055 ,m_owner(a_from.m_owner) 00056 { 00057 #ifdef INLIB_MEM 00058 mem::increment(s_class().c_str()); 00059 #endif 00060 if(m_owner) { 00061 unsigned int sz = m_w*m_h*m_n; 00062 if(!sz) return; 00063 m_buffer = new T[sz]; 00064 if(!m_buffer) { 00065 m_w = 0;m_h = 0;m_owner = false; 00066 return; //throw 00067 } 00068 ::memcpy(m_buffer,a_from.m_buffer,sz*sizeof(T)); 00069 } else { 00070 m_buffer = a_from.m_buffer; 00071 } 00072 } 00073 img& operator=(const img& a_from){ 00074 if(m_owner) delete [] m_buffer; 00075 m_buffer = 0; 00076 m_w = a_from.m_w; 00077 m_h = a_from.m_h; 00078 m_n = a_from.m_n; 00079 m_owner = a_from.m_owner; 00080 if(m_owner) { 00081 unsigned int sz = m_w*m_h*m_n; 00082 if(!sz) return *this; 00083 m_buffer = new T[sz]; 00084 if(!m_buffer) { 00085 m_w = 0;m_h = 0;m_owner = false; 00086 return *this; //throw 00087 } 00088 ::memcpy(m_buffer,a_from.m_buffer,sz*sizeof(T)); 00089 } else { 00090 m_buffer = a_from.m_buffer; 00091 } 00092 return *this; 00093 } 00094 public: 00095 bool operator==(const img& a_from) const {return equal(a_from);} 00096 bool operator!=(const img& a_from) const {return !operator==(a_from);} 00097 public: 00098 void transfer(img& a_from) { 00099 if(m_owner) delete [] m_buffer; 00100 m_w = a_from.m_w; 00101 m_h = a_from.m_h; 00102 //don't touch m_n 00103 m_buffer = a_from.m_buffer; 00104 m_owner = a_from.m_owner; 00105 // empty a_from : 00106 a_from.m_w = 0; 00107 a_from.m_h = 0; 00108 a_from.m_buffer = 0; 00109 a_from.m_owner = false; 00110 } 00111 00112 void clear() { 00113 if(m_owner) delete [] m_buffer; 00114 m_w = 0; 00115 m_h = 0; 00116 m_buffer = 0; 00117 m_owner = false; 00118 } 00119 void set(unsigned int a_w,unsigned int a_h, 00120 T* a_buffer,bool a_owner) { 00121 if(m_owner) delete [] m_buffer; 00122 m_w = a_w; 00123 m_h = a_h; 00124 //don't touch m_n 00125 m_buffer = a_buffer; 00126 m_owner = a_owner; 00127 } 00128 bool copy(const img& a_from){ 00129 if(m_owner) delete [] m_buffer; 00130 m_buffer = 0; 00131 m_w = a_from.m_w; 00132 m_h = a_from.m_h; 00133 m_n = a_from.m_n; 00134 unsigned int sz = m_w*m_h*m_n; 00135 if(!sz) { 00136 m_w = 0;m_h = 0;m_owner = false; 00137 return false; 00138 } 00139 m_buffer = new T[sz]; 00140 if(!m_buffer) { 00141 m_w = 0;m_h = 0;m_owner = false; 00142 return false; 00143 } 00144 ::memcpy(m_buffer,a_from.m_buffer,sz*sizeof(T)); 00145 m_owner = true; 00146 return true; 00147 } 00148 bool allocate(unsigned int a_w,unsigned int a_h){ 00149 if(m_owner) delete [] m_buffer; 00150 m_buffer = 0; 00151 unsigned int sz = a_w*a_h*m_n; 00152 if(!sz) { 00153 m_w = 0;m_h = 0;m_owner = false; 00154 return false; 00155 } 00156 m_w = a_w; 00157 m_h = a_h; 00158 m_buffer = new T[sz]; 00159 if(!m_buffer) { 00160 m_w = 0;m_h = 0;m_owner = false; 00161 return false; 00162 } 00163 m_owner = true; 00164 return true; 00165 } 00166 void make_empty() { 00167 if(m_owner) delete [] m_buffer; 00168 m_w = 0; 00169 m_h = 0; 00170 //don't touch m_n 00171 m_buffer = 0; 00172 m_owner = false; 00173 } 00174 bool equal(const img& a_from) const { 00175 if(m_w!=a_from.m_w) return false; 00176 if(m_h!=a_from.m_h) return false; 00177 if(m_n!=a_from.m_n) return false; 00178 //don't test ownership. 00179 unsigned int sz = m_w*m_h*m_n; 00180 T* pos = m_buffer; 00181 T* fpos = a_from.m_buffer; 00182 for(unsigned int index=0;index<sz;index++,pos++,fpos++) { 00183 if((*pos)!=(*fpos)) return false; 00184 } 00185 return true; 00186 } 00187 unsigned int width() const {return m_w;} 00188 unsigned int height() const {return m_h;} 00189 unsigned int bytes_per_pixel() const {return m_n;} 00190 unsigned int bpp() const {return m_n;} 00191 T* buffer() const {return m_buffer;} 00192 bool owner() const {return m_owner;} 00193 unsigned int size() const {return m_w*m_h*m_n*sizeof(T);} //bytes. 00194 public: 00195 bool expand(unsigned int a_factor,img<T>& a_res) const { 00196 if(a_res.m_n!=m_n) { 00197 a_res.make_empty(); 00198 return false; 00199 } 00200 if(!a_factor) { 00201 a_res.make_empty(); 00202 return false; 00203 } 00204 if(a_factor==1) { 00205 a_res.set(m_w,m_h,m_buffer,false); 00206 return true; 00207 } 00208 00209 unsigned int nw = m_w*a_factor; 00210 unsigned int nh = m_h*a_factor; 00211 00212 T* nb = new T[nh*nw*m_n]; 00213 if(!nb) { 00214 a_res.make_empty(); 00215 return false; 00216 } 00217 00218 for(unsigned int j=0;j<m_h;j++) { 00219 for(unsigned int i=0;i<m_w;i++) { 00220 //position in the original image. 00221 T* pos = m_buffer + j * (m_w * m_n) + i*m_n; 00222 00223 for(unsigned int fr=0;fr<a_factor;fr++) { 00224 for(unsigned int fc=0;fc<a_factor;fc++) { 00225 //position in the new image. 00226 T* npos = nb + (j*a_factor+fr) * (nw * m_n) + (i*a_factor+fc)*m_n; 00227 for(unsigned int ipix=0;ipix<m_n;ipix++) { 00228 *(npos+ipix) = *(pos+ipix); 00229 } 00230 } 00231 } 00232 00233 } 00234 } 00235 00236 a_res.set(nw,nh,nb,true); 00237 return true; 00238 } 00239 00240 bool contract(unsigned int a_factor,img<T>& a_res) const { 00241 // a_factor pixels are contracted in one. 00242 if(a_res.m_n!=m_n) { 00243 a_res.make_empty(); 00244 return false; 00245 } 00246 if(!a_factor) { 00247 a_res.make_empty(); 00248 return false; 00249 } 00250 if(a_factor==1) { 00251 a_res.set(m_w,m_h,m_buffer,false); 00252 return true; 00253 } 00254 00255 unsigned int nw = m_w/a_factor; 00256 unsigned int nh = m_h/a_factor; 00257 unsigned int sz = nh*nw*m_n; 00258 if(!sz) { 00259 a_res.make_empty(); 00260 return false; 00261 } 00262 00263 T* nb = new T[sz]; 00264 if(!nb) { 00265 a_res.make_empty(); 00266 return false; 00267 } 00268 00269 //T* npos = nb; 00270 //for(unsigned int ipix=0;ipix<sz;ipix++) {*npos = 125;npos++;} 00271 00272 double* pixels = new double[m_n]; //for mean value. 00273 if(!pixels) { 00274 delete [] nb; 00275 a_res.make_empty(); 00276 return false; 00277 } 00278 unsigned int nfac = a_factor*a_factor; 00279 00280 for(unsigned int j=0;j<nh;j++) { 00281 for(unsigned int i=0;i<nw;i++) { 00282 00283 // take mean value of a_factor*a_factor pixels : 00284 for(unsigned int ipix=0;ipix<m_n;ipix++) pixels[ipix] = 0; 00285 00286 for(unsigned int fr=0;fr<a_factor;fr++) { 00287 for(unsigned int fc=0;fc<a_factor;fc++) { 00288 T* pos = m_buffer + (j*a_factor+fr)*(m_w*m_n) +(i*a_factor+fc)*m_n; 00289 for(unsigned int ipix=0;ipix<m_n;ipix++) { 00290 pixels[ipix] += double(*pos);pos++; 00291 } 00292 } 00293 } 00294 for(unsigned int ipix=0;ipix<m_n;ipix++) { 00295 pixels[ipix] /= double(nfac); 00296 } 00297 00298 //position in the result image. 00299 T* npos = nb + j * (nw * m_n) + i*m_n; 00300 for(unsigned int ipix=0;ipix<m_n;ipix++) { 00301 *npos = T(pixels[ipix]);npos++; 00302 } 00303 } 00304 } 00305 00306 delete [] pixels; 00307 00308 a_res.set(nw,nh,nb,true); 00309 return true; 00310 } 00311 00312 bool get_part(unsigned int a_sx,unsigned int a_sy, 00313 unsigned int a_sw,unsigned int a_sh, 00314 img<T>& a_res) const { 00315 00316 if(a_res.m_n!=m_n) { 00317 a_res.make_empty(); 00318 return false; 00319 } 00320 00321 if((a_sx>=m_w)||(a_sy>=m_h)){ 00322 a_res.make_empty(); 00323 return false; 00324 } 00325 00326 // 012345 00327 unsigned int rw = inlib::mn<unsigned int>(m_w-a_sx,a_sw); 00328 unsigned int rh = inlib::mn<unsigned int>(m_h-a_sy,a_sh); 00329 if((!rw)||(!rh)) { 00330 a_res.make_empty(); 00331 return false; 00332 } 00333 00334 //printf("debug : %d %d\n",a_rw,a_rh); 00335 00336 T* rb = new T[rh*rw*m_n]; 00337 if(!rb) { 00338 a_res.make_empty(); 00339 return false; 00340 } 00341 00342 unsigned int rstride = rw * m_n; 00343 T* rpos = rb; 00344 00345 unsigned int stride = m_w * m_n; 00346 T* pos = m_buffer+a_sy*stride+a_sx*m_n; 00347 00348 for(unsigned int j=0;j<rh;j++,rpos+=rstride,pos+=stride) {//j=0 -> bottom. 00349 ::memcpy(rpos,pos,rstride*sizeof(T)); 00350 } 00351 00352 a_res.set(rw,rh,rb,true); 00353 return true; 00354 } 00355 00356 bool to_texture(bool a_expand, 00357 T a_pixel[], //size shoulde be a_img.m_n. 00358 img<T>& a_res) const { 00359 if(a_res.m_n!=m_n) { 00360 a_res.make_empty(); 00361 return false; 00362 } 00363 00364 if(a_expand) { 00365 // if a_w, a_h are not power of two, we expand 00366 // the image and fill new spaces with rgb. 00367 00368 // are a_w, a_h power of two ? 00369 unsigned int rw = 2; 00370 while(true) {if(rw>=m_w) break;rw *=2;} 00371 unsigned int rh = 2; 00372 while(true) {if(rh>=m_h) break;rh *=2;} 00373 00374 if((rw==m_w)&&(rh==m_h)) { 00375 a_res.set(m_w,m_h,m_buffer,false); //WARNING owner=false. 00376 return true; 00377 } 00378 00379 T* rb = new T[rh*rw*m_n]; 00380 if(!rb) { 00381 a_res.make_empty(); 00382 return false; 00383 } 00384 00385 // initialize with given color : 00386 for(unsigned int j=0;j<rh;j++) { //j=0 -> bottom. 00387 T* pos = rb + j * (rw * m_n); 00388 for(unsigned int i=0;i<rw;i++) { 00389 for(unsigned int n=0;n<m_n;n++) { 00390 *pos = a_pixel[n];pos++; //memcpy ? 00391 } 00392 } 00393 } 00394 00395 // center : 00396 unsigned int col = (rw-m_w)/2; 00397 unsigned int row = (rh-m_h)/2; 00398 00399 // copy original image in a centered part of the new one : 00400 for(unsigned int j=0;j<m_h;j++) { 00401 T* pos = m_buffer + j * (m_w * m_n); 00402 T* rpos = rb + (j+row) * (rw * m_n) + col*m_n; 00403 ::memcpy(rpos,pos,m_w*m_n*sizeof(T)); 00404 } 00405 00406 a_res.set(rw,rh,rb,true); 00407 00408 return true; 00409 } else { 00410 00411 // closest w,h power of two : 00412 unsigned int sw = 2; 00413 while(true) {if((sw*2)>m_w) break;sw *=2;} 00414 unsigned int sh = 2; 00415 while(true) {if((sh*2)>m_h) break;sh *=2;} 00416 00417 if((sw==m_w)&&(sh==m_h)) { 00418 a_res.set(m_w,m_h,m_buffer,false); //WARNING owner=false. 00419 return true; 00420 } 00421 00422 unsigned int sx = (m_w-sw)/2; 00423 unsigned int sy = (m_h-sh)/2; 00424 00425 return get_part(sx,sy,sw,sh,a_res); 00426 } 00427 00428 } 00429 00430 public: 00431 static bool concatenate(const std::vector< img<T> >& a_imgs, 00432 unsigned int a_cols,unsigned int a_rows, 00433 unsigned int a_bw,unsigned int a_bh, 00434 T a_bc, //border grey level. 00435 img<T>& a_res){ 00436 //not tested yet. 00437 00438 // We assume that size of a_imgs is a_cols*a_rows 00439 00440 // We should check that all a_imgs are consistents. 00441 00442 unsigned int num = a_cols*a_rows; 00443 if(!num) {a_res.make_empty();return false;} 00444 00445 unsigned int a_w = a_imgs[0].m_w; 00446 unsigned int a_h = a_imgs[0].m_h; 00447 unsigned int a_n = a_imgs[0].m_n; 00448 00449 if(a_res.m_n!=a_n) { 00450 a_res.make_empty(); 00451 return false; 00452 } 00453 00454 for(unsigned int index=1;index<num;index++) { 00455 if(a_imgs[index].m_n!=a_n) { 00456 a_res.make_empty(); 00457 return false; 00458 } 00459 if(a_imgs[index].m_w!=a_w) { 00460 a_res.make_empty(); 00461 return false; 00462 } 00463 if(a_imgs[index].m_h!=a_h) { 00464 a_res.make_empty(); 00465 return false; 00466 } 00467 } 00468 00469 unsigned wbw = a_w + 2*a_bw; 00470 unsigned hbh = a_h + 2*a_bh; 00471 00472 unsigned int rw = wbw * a_cols; 00473 unsigned int rh = hbh * a_rows; 00474 00475 //printf("debug : %d %d\n",rw,rh); 00476 00477 // on big concatenated image the below may fail : 00478 T* rb = new T[rh*rw*a_n]; 00479 if(!rb) { 00480 a_res.make_empty(); 00481 return false; 00482 } 00483 00484 unsigned int wbwn = wbw*a_n; 00485 unsigned int awn = a_w*a_n; 00486 00487 //copy tiles : 00488 unsigned int index = 0; 00489 for(unsigned int j=0;j<a_rows;j++) { 00490 for(unsigned int i=0;i<a_cols;i++) { 00491 T* tile = a_imgs[index].buffer(); 00492 00493 for(unsigned int r=0;r<hbh;r++) { 00494 T* pos = rb + (j*hbh+r)*rw*a_n + i*wbw*a_n; 00495 ::memset(pos,a_bc,wbwn*sizeof(T)); 00496 } 00497 00498 for(unsigned int r=0;r<a_h;r++) { 00499 T* pos = rb + (j*hbh+r+a_bh)*rw*a_n + (i*wbw+a_bw)*a_n; 00500 T* ptile = tile+r*awn; 00501 for(unsigned int c=0;c<awn;c++) *pos++ = *ptile++; 00502 } 00503 00504 index++; 00505 } 00506 } 00507 00508 a_res.set(rw,rh,rb,true); 00509 return true; 00510 } 00511 00512 protected: 00513 unsigned int m_w; 00514 unsigned int m_h; 00515 unsigned int m_n; 00516 T* m_buffer; 00517 bool m_owner; 00518 private: 00519 static void check_instantiation() { 00520 img<float> dummy(3); 00521 //dummy.width(); 00522 } 00523 }; 00524 00525 00526 typedef img<unsigned char> img_byte; 00527 00528 // NOTE : img_byte is ready for OpenGL glTexImage2D UNSIGNED_BYTE RGB. 00529 // For glTexImage2D, first row in m_buffer is bottom of image. 00530 00531 } 00532 00533 #endif