Warning, /include/Geant4/tools/img is written in an unsupported language. File is not indexed.
0001 // Copyright (C) 2010, Guy Barrand. All rights reserved.
0002 // See the file tools.license for terms.
0003
0004 #ifndef tools_img
0005 #define tools_img
0006
0007 #include <string> //memcpy
0008 #include <cstring> //memcpy
0009 #include "mnmx"
0010 #include "S_STRING"
0011
0012 #include <vector> //concatenate
0013
0014 namespace tools {
0015
0016 template <class T>
0017 class img {
0018 public:
0019 TOOLS_T_SCLASS(T,tools::img)
0020 public:
0021 img()
0022 :m_w(0),m_h(0),m_n(0)
0023 ,m_buffer(0)
0024 ,m_owner(false)
0025 {
0026 }
0027 img(unsigned int a_w,unsigned int a_h,unsigned int a_n,T* a_buffer,bool a_owner)
0028 :m_w(a_w),m_h(a_h),m_n(a_n)
0029 ,m_buffer(a_buffer)
0030 ,m_owner(a_owner)
0031 {
0032 }
0033 virtual ~img() {
0034 if(m_owner) delete [] m_buffer;
0035 }
0036 public:
0037 img(const img& a_from)
0038 :m_w(a_from.m_w),m_h(a_from.m_h),m_n(a_from.m_n)
0039 ,m_buffer(0)
0040 ,m_owner(a_from.m_owner)
0041 {
0042 if(m_owner) {
0043 unsigned int sz = m_w*m_h*m_n;
0044 if(!sz) return;
0045 m_buffer = new T[sz];
0046 if(!m_buffer) {
0047 m_w = 0;m_h = 0;m_n = 0;m_owner = false;
0048 return; //throw
0049 }
0050 ::memcpy(m_buffer,a_from.m_buffer,sz*sizeof(T));
0051 } else {
0052 m_buffer = a_from.m_buffer;
0053 }
0054 }
0055 img& operator=(const img& a_from){
0056 if(&a_from==this) return *this;
0057 if(m_owner) delete [] m_buffer;
0058 m_buffer = 0;
0059 m_w = a_from.m_w;
0060 m_h = a_from.m_h;
0061 m_n = a_from.m_n;
0062 m_owner = a_from.m_owner;
0063 if(m_owner) {
0064 unsigned int sz = m_w*m_h*m_n;
0065 if(!sz) return *this;
0066 m_buffer = new T[sz];
0067 if(!m_buffer) {
0068 m_w = 0;m_h = 0;m_n = 0;m_owner = false;
0069 return *this; //throw
0070 }
0071 ::memcpy(m_buffer,a_from.m_buffer,sz*sizeof(T));
0072 } else {
0073 m_buffer = a_from.m_buffer;
0074 }
0075 return *this;
0076 }
0077 public:
0078 bool operator==(const img& a_from) const {return equal(a_from);}
0079 bool operator!=(const img& a_from) const {return !operator==(a_from);}
0080 public:
0081 void set(unsigned int a_w,unsigned int a_h,unsigned int a_n,T* a_buffer,bool a_owner) {
0082 if(m_owner) delete [] m_buffer;
0083 m_w = a_w;
0084 m_h = a_h;
0085 m_n = a_n;
0086 m_buffer = a_buffer;
0087 m_owner = a_owner;
0088 }
0089 bool copy(unsigned int a_w,unsigned int a_h,unsigned int a_n,T* a_buffer) {
0090 if(m_owner) delete [] m_buffer;
0091 m_buffer = 0;
0092 m_w = a_w;
0093 m_h = a_h;
0094 m_n = a_n;
0095 unsigned int sz = m_w*m_h*m_n;
0096 if(!sz) {
0097 m_w = 0;m_h = 0;m_n = 0;m_owner = false;
0098 return false;
0099 }
0100 m_buffer = new T[sz];
0101 if(!m_buffer) {
0102 m_w = 0;m_h = 0;m_n = 0;m_owner = false;
0103 return false;
0104 }
0105 ::memcpy(m_buffer,a_buffer,sz*sizeof(T));
0106 m_owner = true;
0107 return true;
0108 }
0109 void make_empty(bool a_delete = true) {
0110 if(m_owner && a_delete) delete [] m_buffer;
0111 m_w = 0;
0112 m_h = 0;
0113 m_n = 0;
0114 m_buffer = 0;
0115 m_owner = false;
0116 }
0117 bool is_empty() const {
0118 if(!m_w) return true;
0119 if(!m_h) return true;
0120 if(!m_n) return true;
0121 if(!m_buffer) return true;
0122 return false;
0123 }
0124 bool equal(const img& a_from) const {
0125 if(m_w!=a_from.m_w) return false;
0126 if(m_h!=a_from.m_h) return false;
0127 if(m_n!=a_from.m_n) return false;
0128 //don't test ownership.
0129 unsigned int sz = m_w*m_h*m_n;
0130 T* pos = m_buffer;
0131 T* fpos = a_from.m_buffer;
0132 for(unsigned int index=0;index<sz;index++,pos++,fpos++) {
0133 if((*pos)!=(*fpos)) return false;
0134 }
0135 return true;
0136 }
0137 unsigned int width() const {return m_w;}
0138 unsigned int height() const {return m_h;}
0139 unsigned int bytes_per_pixel() const {return m_n;}
0140 const T* buffer() const {return m_buffer;}
0141 T* buffer() {return m_buffer;}
0142 bool owner() const {return m_owner;}
0143 unsigned int size() const {return m_w*m_h*m_n*sizeof(T);} //bytes.
0144 public:
0145 bool pixel(unsigned int a_i,unsigned a_j,std::vector<T>& a_pixel) const {
0146 if((!m_w)||(!m_h)||(a_i>=m_w)||(a_j>=m_h)) {
0147 a_pixel.clear();
0148 return false;
0149 }
0150 a_pixel.resize(m_n);
0151 T* pos = m_buffer + a_j * (m_w * m_n) + a_i*m_n;
0152 for(unsigned int ipix=0;ipix<m_n;ipix++) {
0153 a_pixel[ipix] = *(pos+ipix);
0154 }
0155 return true;
0156 }
0157
0158 bool contract(unsigned int a_w,unsigned int a_h,img<T>& a_res,bool a_force_res_owner = true) const {
0159 //optimized version of contract_raw().
0160
0161 if((a_w==m_w)&&(a_h==m_h)) {
0162 if(a_force_res_owner) {
0163 a_res.copy(m_w,m_h,m_n,m_buffer);
0164 } else {
0165 a_res.set(m_w,m_h,m_n,m_buffer,false);
0166 }
0167 return true;
0168 }
0169
0170 size_t sz = a_h*a_w*m_n;
0171 if(!sz) {
0172 a_res.make_empty();
0173 return false;
0174 }
0175
0176 T* rb = new T[sz];
0177 if(!rb) {
0178 a_res.make_empty();
0179 return false;
0180 }
0181
0182 double* pixels = new double[m_n]; //for mean value.
0183 if(!pixels) {
0184 delete [] rb;
0185 a_res.make_empty();
0186 return false;
0187 }
0188 {for(unsigned int ipix=0;ipix<m_n;ipix++) pixels[ipix] = 0;}
0189
0190 unsigned int wfac = (unsigned int)(double(m_w)/double(a_w));
0191 unsigned int hfac = (unsigned int)(double(m_h)/double(a_h));
0192 if(!wfac) wfac = 1;
0193 if(!hfac) hfac = 1;
0194
0195 double wfac_hfac = wfac*hfac;
0196
0197 T* hpos;T* pos;T* hrpos;T* rpos;T* hhpos;T* _pos;double* ppos;
0198 unsigned int i,j,fr,fc,ipix,i0;
0199 unsigned int astride = a_w * m_n;
0200 unsigned int mstride = m_w * m_n;
0201 unsigned int wfacstride = wfac * m_n;
0202
0203 for(j=0;j<a_h;j++) {
0204 hrpos = rb + j * astride;
0205 hhpos = m_buffer + j*hfac*mstride;
0206 for(i=0;i<a_w;i++) {
0207
0208 // take mean value of wfac*hfac pixels :
0209
0210 i0 = i*wfacstride;
0211
0212 hpos = hhpos;
0213 for(fr=0;fr<hfac;fr++,hpos+=mstride) {
0214 _pos = hpos + i0;
0215 for(fc=0;fc<wfac;fc++,_pos+=m_n) {
0216 pos = _pos;
0217 ppos = pixels;
0218 for(ipix=0;ipix<m_n;ipix++,pos++,ppos++) {
0219 *ppos += double(*pos)/wfac_hfac;
0220 }
0221 }
0222 }
0223
0224 //position in the result image.
0225 rpos = hrpos + i*m_n;
0226 ppos = pixels;
0227 for(ipix=0;ipix<m_n;ipix++,rpos++,ppos++) {
0228 *rpos = T(*ppos);
0229 *ppos = 0;
0230 }
0231 }
0232 }
0233
0234 delete [] pixels;
0235
0236 a_res.set(a_w,a_h,m_n,rb,true);
0237 return true;
0238 }
0239
0240 bool contract(unsigned int a_factor,img<T>& a_res,bool a_force_res_owner = true) const {
0241 // a_factor pixels are contracted in one.
0242 unsigned int nw = m_w/a_factor;
0243 unsigned int nh = m_h/a_factor;
0244 return contract(nw,nh,a_res,a_force_res_owner);
0245 }
0246
0247 bool get_part(unsigned int a_sx,unsigned int a_sy,unsigned int a_sw,unsigned int a_sh,img<T>& a_res) const {
0248
0249 if((a_sx>=m_w)||(a_sy>=m_h)){
0250 a_res.make_empty();
0251 return false;
0252 }
0253
0254 // 012345
0255 unsigned int rw = min_of<unsigned int>(m_w-a_sx,a_sw);
0256 unsigned int rh = min_of<unsigned int>(m_h-a_sy,a_sh);
0257 unsigned int sz = rh*rw*m_n;
0258 if(!sz) {
0259 a_res.make_empty();
0260 return false;
0261 }
0262
0263 T* rb = new T[sz];
0264 if(!rb) {
0265 a_res.make_empty();
0266 return false;
0267 }
0268
0269 unsigned int rstride = rw * m_n;
0270 T* rpos = rb;
0271
0272 unsigned int stride = m_w * m_n;
0273 T* pos = m_buffer+a_sy*stride+a_sx*m_n;
0274
0275 for(unsigned int j=0;j<rh;j++,rpos+=rstride,pos+=stride) {//j=0 -> bottom.
0276 ::memcpy(rpos,pos,rstride*sizeof(T));
0277 }
0278
0279 a_res.set(rw,rh,m_n,rb,true);
0280 return true;
0281 }
0282
0283 bool to_texture(bool a_expand,
0284 const T a_pixel[], //size shoulde be a_img.m_n.
0285 img<T>& a_res,bool a_res_force_owner = true) const {
0286
0287 //NOTE : pixels of the original image are not expanded or shrinked.
0288
0289 if((!m_w)||(!m_h)) {
0290 a_res.make_empty();
0291 return false;
0292 }
0293
0294 // in case (m_w==1)||(m_h==1), expand the pixel
0295 // up to the closest power of 2 ?
0296
0297 if((m_w==1)||(m_h==1)||a_expand) {
0298 // find closest power of two upper than m_w, m_h :
0299 unsigned int rw = 2;
0300 while(true) {if(rw>=m_w) break;rw *=2;}
0301 unsigned int rh = 2;
0302 while(true) {if(rh>=m_h) break;rh *=2;}
0303
0304 if((rw==m_w)&&(rh==m_h)) { //exact match.
0305 if(a_res_force_owner) {
0306 a_res.copy(m_w,m_h,m_n,m_buffer);
0307 } else {
0308 a_res.set(m_w,m_h,m_n,m_buffer,false); //WARNING owner=false.
0309 }
0310 return true;
0311 }
0312
0313 // we expand the image and fill new spaces with a_pixel.
0314
0315 T* rb = 0;
0316 bool res_set = true;
0317 if(a_res.owner()&&(a_res.size()==(rh*rw*m_n))) {
0318 // a_res has already the right allocation.
0319 rb = a_res.buffer();
0320 res_set = false;
0321 } else {
0322 rb = new T[rh*rw*m_n];
0323 if(!rb) {
0324 a_res.make_empty();
0325 return false;
0326 }
0327 }
0328
0329 unsigned int num = rw*m_n;
0330
0331 // initialize with given color :
0332 {T* pos = rb;
0333 for(unsigned int i=0;i<rw;i++,pos+=m_n) {
0334 ::memcpy(pos,a_pixel,m_n*sizeof(T));
0335 }
0336 unsigned int sz = num*sizeof(T);
0337 for(unsigned int j=1;j<rh;j++,pos+=num) { //j=0 -> bottom.
0338 ::memcpy(pos,rb,sz);
0339 }}
0340
0341 // center :
0342 unsigned int col = (rw-m_w)/2;
0343 unsigned int row = (rh-m_h)/2;
0344
0345 unsigned int mnum = m_w*m_n;
0346
0347 // copy original image in a centered part of the new one :
0348 {T* pos = m_buffer;
0349 T* rpos = rb+row*num+col*m_n;
0350 unsigned int sz = mnum*sizeof(T);
0351 for(unsigned int j=0;j<m_h;j++,pos+=mnum,rpos+=num) {
0352 ::memcpy(rpos,pos,sz);
0353 }}
0354
0355 if(res_set) a_res.set(rw,rh,m_n,rb,true);
0356
0357 return true;
0358 } else {
0359 // then m_w>=2 and m_h>=2
0360
0361 // find closest power of two lower than m_w, m_h :
0362 unsigned int sw = 2;
0363 while(true) {if((sw*2)>m_w) break;sw *=2;}
0364 unsigned int sh = 2;
0365 while(true) {if((sh*2)>m_h) break;sh *=2;}
0366
0367 if((sw==m_w)&&(sh==m_h)) { //exact match.
0368 if(a_res_force_owner) {
0369 a_res.copy(m_w,m_h,m_n,m_buffer);
0370 } else {
0371 a_res.set(m_w,m_h,m_n,m_buffer,false); //WARNING owner=false.
0372 }
0373 return true;
0374 }
0375
0376 unsigned int sx = (m_w-sw)/2;
0377 unsigned int sy = (m_h-sh)/2;
0378
0379 return get_part(sx,sy,sw,sh,a_res);
0380 }
0381
0382 }
0383
0384 bool check_gl_limit(unsigned int a_GL_MAX_TEXTURE_SIZE,img<T>& a_res) const {
0385 // if ret true and a_res.is_empty(), "this" does not exceeds the limit.
0386 // if ret true and !a_res.is_empty(), "this" exceeds the limit and a new fitting image is returned in a_res.
0387 // if ret false, "this" exceeds the limit but something went wrong in building a_res.
0388 unsigned int tw = m_w;
0389 unsigned int th = m_h;
0390 if((tw<=a_GL_MAX_TEXTURE_SIZE)&&(th<=a_GL_MAX_TEXTURE_SIZE)) {
0391 a_res.make_empty();
0392 return true;
0393 }
0394 unsigned int fac = 2;
0395 while(true) {
0396 unsigned int pw = tw/fac;
0397 unsigned int ph = th/fac;
0398 if((pw<=a_GL_MAX_TEXTURE_SIZE)&&(ph<=a_GL_MAX_TEXTURE_SIZE)) {
0399 if(!contract(fac,a_res)) {
0400 a_res.make_empty();
0401 return false;
0402 }
0403 return true;
0404 }
0405 fac *= 2;
0406 }
0407 a_res.make_empty();
0408 return false;
0409 }
0410
0411 bool bw2x(unsigned int a_n,img<T>& a_res) const {
0412 //expect a bw img.
0413 if(m_n!=1) return false;
0414
0415 a_res.make_empty();
0416 if(a_n<m_n) return false;
0417 unsigned int sz = m_w*m_h*a_n;
0418 if(!sz) return false;
0419
0420 a_res.m_buffer = new T[sz];
0421 if(!a_res.m_buffer) return false;
0422 a_res.m_owner = true;
0423 a_res.m_w = m_w;
0424 a_res.m_h = m_h;
0425 a_res.m_n = a_n;
0426
0427 for(unsigned int j=0;j<m_h;j++) {
0428 for(unsigned int i=0;i<m_w;i++) {
0429 //position in the original image.
0430 T* pos = m_buffer + j * (m_w * m_n) + i*m_n;
0431
0432 T* rpos = a_res.m_buffer + j * (m_w * a_n) + i*a_n;
0433
0434 for(unsigned int ipix=0;ipix<a_n;ipix++) {
0435 *(rpos+ipix) = *pos;
0436 }
0437
0438 }
0439 }
0440
0441 return true;
0442 }
0443
0444 bool rgb2rgba(img<T>& a_res,const T& a_pixel) const {
0445 if(m_n!=3) return false;
0446
0447 unsigned int n = 4;
0448
0449 a_res.make_empty();
0450 unsigned int sz = m_w*m_h*n;
0451 if(!sz) return false;
0452
0453 a_res.m_buffer = new T[sz];
0454 if(!a_res.m_buffer) return false;
0455 a_res.m_owner = true;
0456 a_res.m_w = m_w;
0457 a_res.m_h = m_h;
0458 a_res.m_n = n;
0459
0460 for(unsigned int j=0;j<m_h;j++) {
0461 for(unsigned int i=0;i<m_w;i++) {
0462 //position in the original image.
0463 T* pos = m_buffer + j * (m_w * m_n) + i*m_n;
0464
0465 T* rpos = a_res.m_buffer + j * (m_w * n) + i*n;
0466
0467 *(rpos+0) = *(pos+0);
0468 *(rpos+1) = *(pos+1);
0469 *(rpos+2) = *(pos+2);
0470 *(rpos+3) = a_pixel;
0471
0472 }
0473 }
0474
0475 return true;
0476 }
0477
0478 protected:
0479 unsigned int m_w;
0480 unsigned int m_h;
0481 unsigned int m_n;
0482 T* m_buffer;
0483 bool m_owner;
0484
0485 private: static void check_instantiation() {img<float> dummy;}
0486 };
0487
0488 // NOTE : img_byte is ready for OpenGL glTexImage2D UNSIGNED_BYTE RGB.
0489 // For glTexImage2D, first row in m_buffer is bottom of image.
0490 typedef img<unsigned char> img_byte;
0491
0492 }
0493
0494 #endif