KJB
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
img.h
Go to the documentation of this file.
1 // img.h - general support for images and image sequences
3 // Author: Doron Tal
4 // Date Created: May, 1993
5 // Date Last Modified: Aug, 2000
6 
8 //
9 // Both classes in this file are template classes, therefore this
10 // header file contains implementation as well as declarations, no
11 // associated '.cpp' file exists.
12 //
13 // Author: Doron Tal
14 // Date Created: June, 1994
15 
16 #ifndef _IMG_H
17 #define _IMG_H
18 
19 #include <assert.h>
20 #include <memory.h>
21 #include <stdlib.h>
22 #include <vector>
23 #include <string>
24 #include "wrap_dtlib_cpp/utils.h"
25 
26 /*
27  * Kobus: We have run into trouble with 32 bit centric code in this
28  * distribution. I have changed some long's to kjb_int32's. The immediate
29  * problem is that the segmentation maps can get written out as 64 bit integers.
30 */
31 #include "l/l_sys_def.h"
32 
33 #warning "[Code police] Do not put 'using namespace' in global scope of header."
34 using namespace std;
35 #warning "[Code police] Do not put 'using namespace' in global scope of header."
36 using namespace kjb_c;
37 
38 
39 namespace DTLib {
40 
41  // forward declaration
42  template <class T> class CImgVec;
43 
45  // Class CImg is a data structure for raster images supporting
46  // regions of interest. A few miscellaneous functions are
47  // included: initialization, indexing, I/O, type conversions (byte
48  // and float only are supported), basic math and thresholding
49  // functions and more.
50 
51  template <class T> class CImg
52  {
53  public:
55  // CONSTRUCTORS / DESTRUCTORS
57 
58  // Generic constructor. Create an empty image object.
59  CImg();
60 
61  // Destructor
62  ~CImg();
63 
64  // Create an image and allocate space for its buffer ('Width' x
65  // 'Height). The region of interest is the entire image. If
66  // 'bMakeBuf' is true, allocate image buffer memory without
67  // initializing, otherwise do not allocate memory. If 'bZero' is
68  // true, and you are allocating memory, zero the memory.
69  CImg(const int Width, const int Height,
70  const bool bMakeBuf = true, const bool bZero = false);
71 
72  // Create image from a supplied Buffer 'pBuf' (size 'Height' x
73  // 'Width'). If 'bCopy' is true, allocate a buffer and copy
74  // 'pBuf' over, otherwise, just make the pointer to this's buffer
75  // point to 'pBuf' and do not allocate.
76  CImg(const T* pBuf, const int Width, const int Height,
77  const bool bCopy = false);
78 
79  // Copy constructor - copy from given BYTE image 'Img'. Create a
80  // float or BYTE Img from a BYTE Img, 'iImg'. If 'bCopy' is true,
81  // copy (ROI only) from 'Img' into this, otherwise, allocate
82  // memory for a new buffer without initializing it, just creating
83  // an image that's the same in every respect (but its buffer) as
84  // 'Img'.
85  // CImg(CImg<BYTE>& Img, const bool bCopy);
86 
87  // float version of above
88  // CImg(CImg<float>& Img, const bool bCopy);
89 
90  // as above, but generic
91  CImg(CImg<T>& Img, const bool bCopy);
92 
93  // Copy constructor - create an image from the ROI of 'InImg',
94  // taking as much from InImg as possible outside of this ROI so as
95  // to pad e.g. if ROI of InImg is whole image, this will be just a
96  // perfect replica of InImg.
97  CImg(CImg<T> &InImg, const int& Padding = 0);
98 
99  // construct from a single frame of supplied sequence 'ImgVec'
100  // 'bCopy' as above
101  CImg(CImgVec<T>& ImgVec, const int& iFrame,
102  const bool& bCopy = false);
103 
104  // concatenate together all frames of sequence and construct from
105  // that, copying over data
106  CImg(CImgVec<T>& ImgVec, const int& nCols, const int& nRows);
107 
109  // ACCESS FUNCTIONS
111 
112  // Get a pixel Value, given coords.
113  inline T GetPix(const int& x, const int& y);
114 
115  // get ith pixel, treating entire image as a vector
116  inline T GetPix(const int& i);
117 
118  // Set a pixel Value, given coords.
119  inline void SetPix(const int& x, const int& y, const T& Val);
120 
121  // same as above but using 'i', the pixel index into m_pBuffer,
122  // PRECOND: 'i' in [0, m_nPixels)
123  inline void SetPix(const int& i, const T& Val);
124 
125  inline void AddToPix(const int& x, const int& y, const T& Val);
126 
127  // Sets the pointer to the image buffer 'pBuf' (of size 'Height' x
128  // 'Width'). If 'bCopy' is true, allocate a buffer and copy
129  // 'pBuf' over, otherwise, just make the pointer to this's buffer
130  // point to 'pBuf' and do not allocate.
131  void Set_pBuffer(const T* pBuf, const int Width, const int Height,
132  const bool bCopy = false);
133 
134  // returns image Width
135  inline int Width() const { return m_Width; }
136 
137  // returns image Height
138  inline int Height() const { return m_Height; }
139 
140  // returns the number of pixels in the image
141  inline int nPixels() const { return m_nPixels; }
142 
143  // returns whether this image's buffer should be deleted upon
144  // exit or not
145  inline bool bDelete() { return m_bDelete; }
146 
147  // returns pointer to the image buffer
148  inline T* pBuffer() { return m_pBuffer; }
149 
150  // returns a pointer to the image region of interest (ROI)
151  inline T* pROI() { return m_pROI; }
152 
153  // The following example will clarify the five member access
154  // functions below -- they are used to construct loops that traverse
155  // the ROI, loops on ROI should look like:
156  //
157  // T* pROI = Img.pROI();
158  // for (y = Img.ROIStartY(); y < Img.ROIEndY();
159  // y++, pROI += Img.ROISkipCOls()) {
160  // for (x = Img.ROIStartX(); y < Img.ROIEndX(); x++, pROI++) {
161  // ...
162  inline int ROIStartX() { return m_ROIStartX; }
163  inline int ROIEndX() { return m_ROIEndX; }
164  inline int ROIStartY() { return m_ROIStartY; }
165  inline int ROIEndY() { return m_ROIEndY; }
166  inline int ROISkipCols() { return m_ROISkipCols; }
167 
168  // returns width of the region of interest
169  inline int ROIWidth() { return m_ROIWidth; }
170 
171  // returns height of the region of interest
172  inline int ROIHeight() { return m_ROIHeight; }
173 
174  // returns number we need to add to the image buffer's pointer
175  // in order to point to the first pixel in the roi
176  inline int ROIOffset() { return m_ROIOffset; }
177 
178  // returns the ROI size
179  inline int ROISize() { return m_ROISize; }
180 
182  // GENERAL DIAGNOSTICS FUNCTIONS
184 
185  // report some info about *this
186  void Report();
187 
188  // Is this Img empty or not? 'empty' means that the memory for the
189  // Img Buffer (m_pBuffer) has not allocated.
190  inline bool IsEmpty() { return (m_pBuffer == NULL); }
191  inline bool IsNotEmpty() { return (m_pBuffer != NULL); }
192 
194  // INPUT / OUTPUT FUNCTIONS
196 
197  // Read and write from/to a file, return success status
198  bool ReadRaw(const char* strFilename);
199  bool WriteRaw(const char* strFilename);
200 
202  // REGION OF INTEREST FUNCTIONS
204 
205  // Clear region of interest (ROI).
206  void ClearROI();
207 
208  // Change region of interest (ROI).
209  void ChangeROI(const int StartX, const int EndX,
210  const int StartY, const int EndY);
211 
212  // Change region of interest (ROI). If the ROI is outside the
213  // Img, we crop it to fit the Img.
214  void SafeChangeROI(const int StartX, const int EndX,
215  const int StartY, const int EndY);
216 
217  // Reduce ROI inwards from all sides by N pixels
218  void ReduceROI(int N = 1);
219 
220  // Set the pixel Values of the background (outside of ROI) to 'Val'
221  void SetOutROIVal(const T& Val);
222 
223  // As Above, but set separately for each rectangle
224  void SetOutROIVal(const T& TopVal, const T& BotVal,
225  const T& LeftVal, const T& RightVal);
226 
227  // reflect image inside ROI into region outside ROI, reflecting
228  // diagonally at the corners
229  void ReflectToROI();
230 
231  // Set the pixel Values in ROI to 'Val'
232  void SetROIVal(const T& Val);
233 
234  // Enlarge ROI as much as possible
235  void OutPadROI(const int& Padding);
236 
238  // IMAGE TYPE OPERATIONS
240 
241  // PRECOND: ROI of this is the same width & height as ROI of
242  // 'ByteImg'.
243  // POSTCOND: Convert float image (this) into byte image 'ByteImg',
244  // scaling everything to be in [0, 255]. Only works on float
245  // images. BGVal is assigned to all pixels in 'ByteImg' that are
246  // not in its ROI.
247  void f2b(CImg<BYTE> &ByteImg, BYTE BGVal = 0);
248 
249  // Same as Above, but here, instead of computing the Min and Max
250  // of the float Img, we supply them as arguments, for speed.
251  void f2b(CImg<BYTE> &ByteImg, float Min, float Max, BYTE BGVal = 0);
252 
253  // As Above, but just using casting, no rescaling done in
254  // conversion.
255  void f2bNoscale(CImg<BYTE> &ByteImg, BYTE BGVal = 0);
256 
257  // Convert byte image (this) into float image 'ByteImg' by casting.
258  void b2f(CImg<float> &FloatImg, float BGVal = 0.0f);
259 
260  // Convert int image (this) into float image 'ByteImg' by casting.
261  void i2f(CImg<float> &FloatImg, float BGVal = 0.0f);
262 
263  // ***TODO***: get rid of above two functions everywhere in the
264  // library. this subsumes the above two functions
265  void ToFloat(CImg<float> &FloatImg, float BGVal = 0.0f);
266 
268  // IMAGE BUFFER OPERATIONS
270 
271  // this can be used to reduce the size of the image without having
272  // to reallocate the buffer, using old buffer, just reset all other
273  // image parameters to pretend we have a smaller buffer. also, sets
274  // ROI to full image.
275  void ReduceSize(const int& NewWidth, const int& NewHeight);
276 
277  // reduce size of image inwards by N pixels
278  void Crop(const int& N);
279 
280  // Clear out the Img - deallocate Buffer.
281  void FreeMemory();
282 
283  // Copy pixel Values from a Buffer, ROI must agree with Buffer's
284  // size, Height and Width.
285  void CopyFromBuf(T* pBuf);
286 
287  // as above, but only copying while withing supplied bounds
288  void CopyFromBuf(T* pBuf, const int& StartX, const int& EndX,
289  const int& StartY, const int& EndY);
290 
291  // Copy pixel Values to a Buffer, ROI must agree with Buffer's size,
292  // Height and Width.
293  void CopyToBuf(T* pBuf);
294 
295  // Attach the Img to a Buffer according to Img's member
296  // functions assumes m_pBuffer doesn't point to an Img that needs
297  // to be freed later.
298  void Attach(T* pBuf);
299 
300  // As Above, but resetting all Img members
301  void Attach(T* pBuf, const int Width, const int Height,
302  const bool bDelete = false);
303 
304  // returns the pointer to the image, sets the current pointer to
305  // the image (i.e. this->m_pBuffer) to NULL
306  T* Detach();
307 
309  // VARIOUS STATISTICS
311 
312  // Return the Minimum pixel index in 'x' and 'y' and the Value of
313  // that pixel in 'Val' - searching in ROI only.
314  void Minpix(int &x, int &y, T& Val);
315 
316  // Return the Maximum pixel index in 'x' and 'y' and the Value of
317  // that pixel in 'Val' - searching in ROI only.
318  void Maxpix(int &x, int &y, T& Val);
319 
320  // Same as Above, but doesn't return coordinates.
321  void Maxpix(T& Val);
322 
323  // Return Both the Minimum and the Maximum Values (no coordinates).
324  void MinMax(T& Min, T& Max);
325 
326  void ReportMinMax();
327 
328  // Return the mean Value of the ROI pixels.
329  float MeanLuminance();
330 
331  // Return the mean luMinance in 'mu' and the variance in 'sig'
332  // of the ROI pixels.
333  void MuSig(float &mu, float &sig);
334 
335  // Returns the sum of absolute Values of all filters.
336  float SumAbs();
337 
339  // NORMALIZATION FUNCTIONS
341 
342  // Normalize the Img (floats only) ROI by subtracting the ROI mean
343  // from each pixel and dividing by the ROI Sigma.
344  void Normalize(bool full_range = false);
345 
346  // Change the range of pixel Values in the Img linearly.
347  void ChangeRange(const BYTE& NewMin, const BYTE& NewMax);
348  void ChangeRange(const float& NewMin, const float& NewMax);
349 
350  void FixThetaRanges(const bool& bHalfPhase = true);
351 
352  // PRECOND: MuImg is the same as TImg w/no ROI - Both are size of
353  // this's ROI. Result is in MuImg = the mean filter of this of size
354  // dx * dy. This method uses (a) separable x and y mean filter
355  // kernels, (b) running averages to compute the mean.
356  void MuFilter(CImg<float> &MuImg, CImg<float> &TImg, int dx, int dy);
357 
358  // Wrapper for Above if you're only doing Above once in your program
359  // and you don't need to reuse the temporary storage that's supplied
360  // Above.
361  void MuFilter(CImg<float> &MuImg, int dx, int dy);
362 
363  // Same as Above, but returns Sigma Img in SigImg as well, 'UImg'
364  // is another temporary Img.
365  void MuSigFilter(CImg<float> &MuImg, CImg<float> &SigImg,
366  CImg<float> &TImg, CImg<float> &UImg,
367  int dx, int dy);
368 
369  // Wrapper for Above if you're only doing Above once in your program
370  // and you don't need to reuse the temporary storage that's supplied
371  // Above.
372  void MuSigFilter(CImg<float> &MuImg, CImg<float> &SigImg,
373  int dx,int dy);
374 
375  // Take this Img's and pad it with 'Left' zeros on the Left and
376  // 'Top' zeros from the Top with Value 'Val'. Now embed the Img
377  // in 'DestImg' and zero-out the Bottom and Right areas where this
378  // Img doesn't reach.
379  void Pad(CImg<T>& DestImg, const int Left, const int Top,
380  const T& Val = (T)0);
381 
382  // Extract a portion of this Img, starting at x = 'Left' and y =
383  // 'Top' and going to the Right 'DestImg.Width()' pixels and to the
384  // Bottom 'DestImg.Height()' pixels. The extracted region fills up
385  // DestImg completely and it is Left with full ROI.
386  void Extract(CImg<T> &DestImg, const int& Left = 0, const int& Top =0);
387 
388  void Square();
389 
390  void Zero();
391 
392  // Multiply 'Img' with this one (looking at ROI only). PRECOND: ROI
393  // of 'Img' must be the same as this's ROI. Result is returned in
394  // 'Img'. Works for float images only.
395  void Mul(CImg<T>& Img);
396  // Multiply all Values of this Img by Val and return result in
397  // Val. Works for float images only.
398  void Mul(const T& Val);
399 
400  // Divide this by Img Img.
401  void Div(CImg<T>& Img);
402  // Divide this by Value Val.
403  void Div(const T& Val);
404 
405  // Add Img to this.
406  void Add(CImg<T>& Img);
407  // Add Val to this.
408  void Add(const T& Val);
409 
410  // Subtract Img from this.
411  void Sub(CImg<T>& Img);
412  // Subtract Val from this.
413  void Sub(const T& Val);
414 
415  // Negate in place.
416  void Neg();
417 
418  // Compute log(a+z), where 'a' and 'z' are *real* numbers and
419  // 'a' is Value of each pixel in ROI, and 'z' is a user
420  // supplied argument.
421  void Log(const float& z = 0.0f);
422 
423  // Or 'this' with 'Img' (so ROIs must be the same size) and
424  // return the result in this. If the Img is a float Img, then
425  // a Value exactly equal to 0.0 is considered false while
426  // anything else is true. If, at any pixel, one of the images
427  // ('this' or 'Img') is nonzero, then asign this pixel in
428  // 'this' the Value Val.
429  void HardOR(CImg<T>& Img, const T& Val = (T)255);
430 
431  // Same as HardOR(), but rather than setting a true pixel to
432  // some Value, keep the Value that made it true.
433  void SoftOR(CImg<T>& Img);
434 
435  // Same as 'HardOR()' but it's an AND.
436  void HardAND(CImg<T>& Img, const T& Val = (T)255);
437 
438  // Same as 'SoftOR()' but it's an AND.
439  void SoftAND(CImg<T>& Img);
440 
441  // Pixels in 'Img' whose Value is Below 'Thresh' are set to
442  // 'Below', other pixels are Left untouched. ROI is
443  // considered. In place version.
444  //void SoftThresh(const T Thresh, const T Below = (T)0);
445 
446  // Pixels in 'Img' whose Value is Below 'Thresh' are set to
447  // 'Below', other pixels are set to 'Above'. ROI is
448  // considered. In place version.
449  //void HardThresh(const T Thresh, const T Below = (T)0,
450  // const T Above = (T)255);
451 
452  // Just swap the pointers with the input Img's pointers, keep
453  // all else the same.
454  void SwapPointers(CImg<T> &InImg);
455 
456  // resize and affine transform to new size (with bilin. interp.)
457  void SwapAll(CImg<T>& InImg);
458 
459  // Normalize ROI of Img by L1-norm of ROI
460  void NormalizeL1();
461 
462  // Return the L2-norm of pixels in ROI.
463  float L2Norm();
464 
465  // Returns the number of non-zero elements in ROI
466  kjb_int32 nNonZeros();
467 
468  // sqrt all values of image pixels in ROI
469  void Sqrt();
470 
471  // converting values between 0 and infinity to a probability
472  // bet. 0 and 1
473  void Val2Probability(const float& Sigma);
474 
475  void CopyPixelsFromImgROI(CImg<T>& Img);
476 
477  protected:
478 
479  T* m_pBuffer; // pointer to the Img
480  int m_Width; // number of columns in Img
481  int m_Height; // number of rows in Img
482  int m_nPixels; // number of pixels in Img
483  bool m_bDelete; // should we dealocate Buffer on destroy?
484 
485  // Region of Interest (ROI) data members
486  T* m_pROI; // points to ROI first pix (m_pBuffer+m_ROIOffset)
487  int m_ROIStartX; // first ROI col (indexed)
488  int m_ROIStartY; // first ROI row (indexed)
489  int m_ROIEndX; // last ROI column (not indexed)
490  int m_ROIEndY; // last ROI row (not indexed, for loops)
491  int m_ROISkipCols; // # of pixels to skip at end of y-loop
492 
493  int m_ROIWidth; // number of columns in ROI
494  int m_ROIHeight; // number of rows in ROI
495  int m_ROIOffset; // ROI start-offset from first pixel of an Img
496  int m_ROISize; // number of pixels in ROI
497  };
498 
500  // IMAGE VECTOR CLASS -- A SEQUENCE OF IMAGES
502 
503  // the class CImgVec is a much more basic data structure, used for
504  // image sequences.
505 
506  template <class T> class CImgVec
507  {
508  public:
509  CImgVec();
510 
511  CImgVec(T** ppBuffers, const int nFrames, const int Width,
512  const int Height, bool bDelete = false);
513 
514  // subsection 'InImg' into nCols x nRows parts and create a
515  // sequence out of the sections if 'Padding' is nonzero, add a
516  // padded region around each stored image of the sequence, but
517  // only if the padding extends into the image of 'InImg', and
518  // when it extends out of the boundaries of InImg, then don't
519  // pad there. If 'Padding' is nonzero, the amount of padding
520  // as described above is specified 'Padding', also, the ROIs
521  // of the images in the sequence are set such that these ROIs
522  // comprise exactly the image of 'InImg'.
523  CImgVec(CImg<T>& InImg, const int& nCols, const int& nRows,
524  const int& Padding = 0);
525 
526  ~CImgVec();
527 
529  // ACCESS FUNCTIONS
531 
532  inline int Width() { return m_Width; }
533  inline int Height() { return m_Height; }
534  inline int nFrames() {
535  assert(m_nFrames == (int)m_vecImgs.size()); return m_nFrames; }
536  inline int FrameSize() { return m_FrameSize; }
537  inline int TotalSize() { return m_TotalSize; }
538 
539  inline CImg<T>* GetImg(const int& i) { return m_vecImgs[i]; }
540  inline T* pBuffer(const int& i) {return m_vecImgs[i]->pBuffer(); }
541  inline typename vector<CImg<T>*>::iterator itImgs() {return m_vecImgs.begin();}
542 
544 
545  void Empty();
546 
547  void Attach(T** ppBuffers, const int nFrames, const int Width,
548  const int Height, bool bDelete = false);
549 
550  bool Allocate(const int nFrames, const int Width, const int Height,
551  bool bZero = false);
552 
553  void FreeMemory();
554 
555  void CopyROI(CImg<T>& Img);
556 
557  // Change the range of pixel Values in the image linearly.
558  void ChangeRange(const T& NewMin, const T& NewMax);
559 
560  void FixThetaRanges(const bool& bHalfPhase = true);
561 
562  bool IsEmpty();
563 
564  protected:
565 
566  int m_Width;
567  int m_Height;
571 
572  vector<CImg<T>*> m_vecImgs;
573 
574  // Region of Interest (ROI) data members
575  int m_ROIStartX; // first ROI col (indexed)
576  int m_ROIStartY; // first ROI row (indexed)
577  int m_ROIEndX; // last ROI column (not indexed)
578  int m_ROIEndY; // last ROI row (not indexed, for loops)
579  int m_ROIWidth; // number of columns in ROI
580  int m_ROIHeight; // number of rows in ROI
581  int m_ROISkipCols; // # of pixels to skip at end of y-loop
582  int m_ROIOffset; // ROI start-offset from first pixel of an Img
583  int m_ROISize; // number of pixels in ROI
584 
585  };
586 
590 
591  template <class T>
592  void CImg<T>::Set_pBuffer(const T* pBuf, const int Width,
593  const int Height, const bool bCopy)
594  {
595  m_ROISize = m_nPixels = Height*Width;
596  if (bCopy) {
597  m_pBuffer = new T[m_nPixels];
598  T* ip = (T*)pBuf;
599  T* op = (T*)m_pBuffer;
600  for (int i = 0; i < m_nPixels; i++, ip++, op++) *op = *ip;
601  m_bDelete = true;
602  } // if bCopy
603  else {
604  m_pBuffer = (T*)pBuf;
605  m_bDelete = false;
606  } // else
607  m_pROI = m_pBuffer;
608  m_ROIHeight = m_ROIEndY = m_Height = Height;
609  m_ROIWidth = m_ROIEndX = m_Width = Width;
610  m_ROISize = m_nPixels = Height*Width;
611  m_ROIOffset = m_ROISkipCols = m_ROIStartX = m_ROIStartY = 0;
612  }
613 
614  template <class T>
616  {
617  m_Width = m_Height = m_ROIStartX = m_ROIEndX = m_ROIWidth =
618  m_ROIStartY = m_ROIEndY = m_ROIHeight = m_ROISize =
619  m_ROIOffset = m_ROISkipCols = m_nPixels = 0;
620  m_bDelete = false;
621  m_pBuffer = m_pROI = NULL;
622  }
623 
624  template <class T>
626  {
627  if (m_bDelete) zap(m_pBuffer);
628 
630  //Added by Prasad
631  //This is to check the correct usage of delete operator for arrays.
632  //if (m_bDelete)
633  //{
634  // if (m_pBuffer)
635  // {
636  // delete[] m_pBuffer;
637  // m_pBuffer = NULL;
638  // m_bDelete = false;
639  // }
640  //}
641  }
642 
644  // Create an image and allocate space for its Buffer Construct a new
645  // 'Width' x 'Height' Img, with ROI = entire Img. If 'bMakeBuf'
646  // is true, allocate Img memory without initializing, otherwise
647  // leave the m_pBuffer and m_pROI NULL;
648 
649  template <class T>
650  CImg<T>::CImg(const int Width, const int Height,
651  const bool bMakeBuf, const bool bZero)
652  {
653  m_ROIHeight = m_ROIEndY = m_Height = Height;
654  m_ROIWidth = m_ROIEndX = m_Width = Width;
655  m_ROISize = m_nPixels = Height*Width;
656  m_ROIOffset = m_ROISkipCols = m_ROIStartX = m_ROIStartY = 0;
657  if (bMakeBuf) {
658  m_pROI = (m_pBuffer = new T[m_nPixels]);
659  m_bDelete = true;
660  if (bZero) memset(m_pBuffer, 0, m_nPixels*sizeof(T));
661  } // if bMakeBuf
662  else {
663  m_bDelete = false;
664  m_pROI = (m_pBuffer = NULL);
665  } // if bMakeBuf .. else
666  }
667 
669  // Create Img from a supplied Buffer 'Buf' of Height 'Height' &
670  // Width 'Width'. If 'bCopy' is true, first allocate a new Img
671  // Buffer and then bCopy over the Img pointed to by 'pROI' into
672  // it, otherwise, just make the created Img's pointer point to the
673  // Buffer supplied in 'Buf'. When the Img is destroyed, its
674  // Buffer will not be deallocated if 'bCopy' == false, but will be
675  // deallocated if 'bCopy' == true.
676 
677  template <class T>
678  CImg<T>::CImg(const T* pBuf, const int Width, const int Height,
679  const bool bCopy)
680  {
681  Set_pBuffer(pBuf, Width, Height, bCopy);
682  }
683 
685  // Copy constructor - copy from given BYTE Img 'Img'. Create a
686  // float or BYTE Img from a BYTE Img, 'iImg'. If 'bCopy' is
687  // true, copy (ROI only) from 'Img' into this, otherwise, allocate
688  // memory for an Img without initializing it.
689  // float version - copy from float Img to (this) float Img
690  template <class T>
691  inline CImg<T>::CImg(CImg<T>& TImg, const bool bCopy)
692  {
693  m_Height = TImg.Height();
694  m_Width = TImg.Width();
695  m_nPixels = TImg.nPixels();
696  m_ROIStartY = TImg.ROIStartY();
697  m_ROIStartX = TImg.ROIStartX();
698  m_ROIEndY = TImg.ROIEndY();
699  m_ROIEndX = TImg.ROIEndX();
700  m_ROIHeight = TImg.ROIHeight();
701  m_ROIWidth = TImg.ROIWidth();
702  m_ROISkipCols = TImg.ROISkipCols();
703  m_ROIOffset = TImg.ROIOffset();
704  m_ROISize = TImg.ROISize();
705  m_pBuffer = new T[m_nPixels];
706  m_pROI = (T*)m_pBuffer+m_ROIOffset;
707  m_bDelete = true;
708  if (bCopy) {
709  // copy the ROI of 'TImg' over, converting to Ts
710  T *fp = TImg.pROI();
711  T *myfp = m_pROI;
712  for (int y = m_ROIStartY; y < m_ROIEndY;
713  y++, fp += m_ROISkipCols, myfp += m_ROISkipCols)
714  for (int x = m_ROIStartX; x < m_ROIEndX;
715  x++, fp++, myfp++)
716  *myfp = *fp;
717  } // if bCopy
718  }
719 
721 
722  // ***TODO***: get rid of code repetition bet. this function and one
723  // below
724 
725  template <class T>
726  inline CImg<T>::CImg(CImg<T>& InImg, const int& Padding)
727  {
728  const int InStartX = InImg.ROIStartX(), InStartY = InImg.ROIStartY();
729  const int InEndX = InImg.ROIEndX(), InEndY = InImg.ROIEndY();
730 
731  // the following variables tell us how much (up to Padding) we are
732  // allowed to go left, right, top, bottom in our padding
733  int LeftPad, TopPad, RightPad, BotPad;
734  LeftPad = TopPad = RightPad = BotPad = Padding; // start assuming this
735  if (m_ROIStartX-Padding < 0) LeftPad = m_ROIStartX; // too much to left
736  if (m_ROIStartY-Padding < 0) TopPad = m_ROIStartY; //too much above
737  if (m_ROIEndX+Padding > m_Width) RightPad = m_Width-m_ROIEndX; // right
738  if (m_ROIEndY+Padding> m_Height) BotPad = m_Height-m_ROIEndY; // below
739 
740  const int InROIWidth = InImg.ROIWidth();
741  const int InROIHeight = InImg.ROIHeight();
742  m_Width = InROIWidth+LeftPad+RightPad;
743  m_Height = InROIHeight+TopPad+BotPad;
744  m_nPixels = m_Width*m_Height;
745  m_pBuffer = new T[m_nPixels];
746  m_bDelete = true;
747  ChangeROI(0, m_Width, 0, m_Height);
748  InImg.ChangeROI(InStartX-LeftPad, InEndX+RightPad,
749  InStartY-TopPad, InEndY+BotPad);
750  InImg.CopyToBuf(m_pBuffer);
751  // change InImg ROI back to what it was..
752  InImg.ChangeROI(InStartX, InEndX, InStartY, InEndY);
753  // set the ROI of this to be the right one
754  ChangeROI(LeftPad, LeftPad+InROIWidth, TopPad, TopPad+InROIHeight);
755  }
756 
758 
759  template <class T>
760  inline void CImg<T>::OutPadROI(const int& Padding)
761  {
762  // the following variables tell us how much (up to Padding) we are
763  // allowed to go left, right, top, bottom in our padding
764  int LeftPad, TopPad, RightPad, BotPad;
765  LeftPad = TopPad = RightPad = BotPad = Padding; // start assuming this
766  if (m_ROIStartX-Padding < 0) LeftPad = m_ROIStartX; // too much to left
767  if (m_ROIStartY-Padding < 0) TopPad = m_ROIStartY; //too much above
768  if (m_ROIEndX+Padding > m_Width) RightPad = m_Width-m_ROIEndX; // right
769  if (m_ROIEndY+Padding> m_Height) BotPad = m_Height-m_ROIEndY; // below
770 
771  ChangeROI(m_ROIStartX-LeftPad, m_ROIEndX+RightPad,
772  m_ROIStartY-TopPad, m_ROIEndY+BotPad);
773  }
774 
776  // concatenate together all frames of sequence and construct from
777  // that, copying over data
778 
779  template <class T>
780  inline CImg<T>::CImg(CImgVec<T>& ImgVec, const int& iFrame,
781  const bool& bCopy)
782  {
783  m_Height = ImgVec.Height();
784  m_Width = ImgVec.Width();
785  m_nPixels = m_Width*m_Height;
786  m_ROIStartY = ImgVec.ROIStartY();
787  m_ROIStartX = ImgVec.ROIStartX();
788  m_ROIEndY = ImgVec.ROIEndY();
789  m_ROIEndX = ImgVec.ROIEndX();
790  m_ROIHeight = ImgVec.ROIHeight();
791  m_ROIWidth = ImgVec.ROIWidth();
792  m_ROISkipCols = ImgVec.ROISkipCols();
793  m_ROIOffset = ImgVec.ROIOffset();
794  m_ROISize = ImgVec.ROISize();
795  if (bCopy) {
796  // create buffer if we're to copy stuff
797  m_pBuffer = new T[m_nPixels];
798  // copy the ROI of 'ImgVec' over, converting to floats
799  T* pSeq = ImgVec.m_vecImgs[iFrame]->m_pBuffer;
800  T* pImg = m_pROI;
801  for (int y = m_ROIStartY; y < m_ROIEndY;
802  y++, pSeq += m_ROISkipCols, pImg += m_ROISkipCols)
803  for (int x = m_ROIStartX; x < m_ROIEndX;
804  x++, pSeq++, pImg++)
805  *pImg = *pSeq;
806  m_bDelete = true;
807  } // if bCopy
808  else {
809  m_pBuffer = ImgVec.m_vecImgs[iFrame]->m_pBuffer;
810  m_bDelete = false;
811  }
812  m_pROI = m_pBuffer+m_ROIOffset;
813  }
814 
816 
817  // concatenate together all frames of sequence and construct from
818  // that, copying over data
819 
820  template <class T>
821  inline CImg<T>::CImg(CImgVec<T>& ImgVec,
822  const int& nCols, const int& nRows)
823  {
824  m_Width = 0;
825  m_Height = 0;
826  int i = 0;
827  for (int row = 0; row < nRows; row++) {
828  for (int col = 0; col < nCols; col++, i++) {
829  if (row == 0) m_Width += (ImgVec.GetImg(i))->ROIWidth();
830  if (col == 0) m_Height += (ImgVec.GetImg(i))->ROIHeight();
831  }
832  }
833 
834  m_nPixels = m_Width*m_Height;
835  m_pBuffer = new T[m_nPixels];
836  m_bDelete = true;
837  m_pROI = m_pBuffer;
838  m_ROIHeight = m_ROIEndY = m_Height;
839  m_ROIWidth = m_ROIEndX = m_Width;
840  m_ROISize = m_nPixels;
841  m_ROIOffset = m_ROISkipCols = m_ROIStartX = m_ROIStartY = 0;
842  i = 0;
843  int StartX = 0, StartY = 0, EndX, EndY;
844  for (int row = 0; row < nRows; row++) {
845  for (int col = 0; col < nCols; col++, i++) {
846 
847  const int InROIWidth = (ImgVec.GetImg(i))->ROIWidth();
848  const int InROIHeight = (ImgVec.GetImg(i))->ROIHeight();
849 
850  EndX = StartX+InROIWidth;
851  EndY = StartY+InROIHeight;
852  ChangeROI(StartX, EndX, StartY, EndY);
853 
854  const int InStartX = (ImgVec.GetImg(i))->ROIStartX();
855  const int InStartY = (ImgVec.GetImg(i))->ROIStartY();
856  const int InEndX = (ImgVec.GetImg(i))->ROIEndX();
857  const int InEndY = (ImgVec.GetImg(i))->ROIEndY();
858  const int InSkip = (ImgVec.GetImg(i))->ROISkipCols();
859  T* pInROI = (ImgVec.GetImg(i))->pROI();
860  T* pOutROI = m_pROI;
861  for (int y = InStartY; y < InEndY; y++, pInROI += InSkip,
862  pOutROI += m_ROISkipCols) {
863  for (int x = InStartX; x < InEndX; x++, pInROI++,
864  pOutROI++) {
865  *pOutROI = *pInROI;
866  } // for (x ..
867  } // for (y ..
868  StartX = EndX;
869  } // for (col ..
870  StartX = 0;
871  StartY = EndY;
872  }
873  }
874 
876 
877  void report_int(const std::string& msg, int value);
878 
880 
881  template <class T>
882  inline void CImg<T>::Report()
883  {
884  report_int("m_Width = ",m_Width);
885  report_int("m_Height = ",m_Height);
886  report_int("m_nPixels = ",m_nPixels);
887  report_int("m_ROIStartY = ",m_ROIStartY);
888  report_int("m_ROIStartX = ",m_ROIStartX);
889  report_int("m_ROIEndY = ",m_ROIEndY);
890  report_int("m_ROIEndX = ",m_ROIEndX);
891  report_int("m_ROIHeight = ",m_ROIHeight);
892  report_int("m_ROIWidth = ",m_ROIWidth);
893  report_int("m_ROISkipCols = ",m_ROISkipCols);
894  report_int("m_ROIOffset = ",m_ROIOffset);
895  report_int("m_ROISize = ",m_ROISize);
896  report_int("m_pBuffer = ",m_pBuffer);
897  report_int("m_bDelete = ",m_bDelete);
898  }
899 
901 
902  template <class T>
903  T CImg<T>::GetPix(const int& x, const int& y)
904  {
905  return m_pBuffer[y*m_Width+x];
906  }
907 
908  template <class T>
909  T CImg<T>::GetPix(const int& i)
910  {
911  return m_pBuffer[i];
912  }
913 
914 
916 
917  template <class T>
918  void CImg<T>::SetPix(const int& x, const int& y, const T& Val)
919  {
920  m_pBuffer[y*m_Width+x] = Val;
921  }
922 
924 
925  template <class T>
926  void CImg<T>::SetPix(const int& i, const T& Val)
927  {
928  m_pBuffer[i] = Val;
929  }
930 
932 
933  template <class T>
934  void CImg<T>::AddToPix(const int& x, const int& y, const T& Val)
935  {
936  m_pBuffer[y*m_Width+x] += Val;
937  }
938 
940 
941  template <class T>
943  {
944  if (IsNotEmpty()) {
945  zap(m_pBuffer);
946  m_pBuffer = m_pROI = NULL;
947  m_bDelete = false;
948  }
949  }
950 
952 
953  // Read and write from/to a file, return success status
954 
955  template <class T>
956  bool CImg<T>::ReadRaw(const char* strFilename)
957  {
958  FILE *fh;
959  if ((fh = fopen(strFilename, "r")) == NULL) return false;
960  else return ((int)fread(m_pBuffer, sizeof(T), m_nPixels, fh) ==
961  m_nPixels);
962  }
963 
964  template <class T>
965  bool CImg<T>::WriteRaw(const char* strFilename)
966  {
967  FILE *fh;
968  if ((fh = fopen(strFilename, "w")) == NULL) return false;
969  else return ((int)fwrite(m_pBuffer,sizeof(T), m_nPixels, fh) ==
970  m_nPixels);
971  }
972 
974  // Clear region of interest (ROI).
975 
976  template <class T>
978  {
979  m_ROIHeight = m_ROIEndY = m_Height;
980  m_ROIWidth = m_ROIEndX = m_Width;
981  m_nPixels = m_Width*m_Height;
982  m_ROISize = m_nPixels;
983  m_ROIOffset = m_ROISkipCols = m_ROIStartX = m_ROIStartY = 0;
984  m_pROI = m_pBuffer;
985  }
986 
988 
989  template <class T>
990  void CImg<T>::ReduceSize(const int& NewWidth, const int& NewHeight)
991  {
992  assert(m_Width >= NewWidth);
993  assert(m_Height >= NewHeight);
994 
995  m_Height = m_ROIHeight = m_ROIEndY = NewHeight;
996  m_Width = m_ROIWidth = m_ROIEndX = NewWidth;
997  m_nPixels = m_ROISize = NewWidth*NewHeight;
998  m_ROIOffset = m_ROISkipCols = m_ROIStartX = m_ROIStartY = 0;
999  m_pROI = m_pBuffer;
1000  }
1001 
1003  // Change region of interest (ROI).
1004 
1005  template <class T>
1006  void CImg<T>::ChangeROI(const int StartX, const int EndX,
1007  const int StartY, const int EndY)
1008  {
1009  m_ROIStartX = StartX;
1010  m_ROIEndX = EndX;
1011  m_ROIStartY = StartY;
1012  m_ROIEndY = EndY;
1013  m_ROIHeight = EndY-StartY;
1014  m_ROIWidth = EndX-StartX;
1015  m_ROISkipCols = m_Width-m_ROIWidth;
1016  m_ROIOffset = StartY*m_Width+StartX;
1017  m_ROISize = m_ROIHeight*m_ROIWidth;
1018  m_pROI = (T*)m_pBuffer+m_ROIOffset;
1019  }
1020 
1022  //Change region of interest (ROI). If the ROI is outside the Img,
1023  //we crop it to fit the Img.
1024 
1025  template <class T>
1026  void CImg<T>::SafeChangeROI(int StartX, int EndX,
1027  int StartY, int EndY)
1028  {
1029  if (StartX < 0) StartX = 0;
1030  if (EndX > m_Width) EndX = m_Width;
1031  if (StartY < 0) StartY = 0;
1032  if (EndY > m_Height) EndY = m_Height;
1033  m_ROIStartX = StartX;
1034  m_ROIEndX = EndX;
1035  m_ROIStartY = StartY;
1036  m_ROIEndY = EndY;
1037  m_ROIHeight = EndY-StartY;
1038  m_ROIWidth = EndX-StartX;
1039  m_ROISkipCols = m_Width-m_ROIWidth;
1040  m_ROIOffset = StartY*m_Width+StartX;
1041  m_ROISize = m_ROIHeight*m_ROIWidth;
1042  m_pROI = (T*)m_pBuffer+m_ROIOffset;
1043  }
1044 
1046  // Reduce ROI inwards from all sides by N pixels
1047 
1048  template <class T>
1050  {
1051  ChangeROI(m_ROIStartX+N, m_ROIEndX-N, m_ROIStartY+N, m_ROIEndY-N);
1052  }
1053 
1055  // Reduce ROI inwards from all sides by N pixels
1056 
1057  template <class T>
1058  void CImg<T>::Crop(const int& N)
1059  {
1060  ReduceROI(N);
1061  CImg<T> CroppedImg(m_ROIWidth, m_ROIHeight);
1062  CopyToBuf(CroppedImg.m_pBuffer);
1063  SwapPointers(CroppedImg);
1064  ReduceSize(m_ROIWidth, m_ROIHeight);
1065  }
1066 
1068  // Set the pixel Values of the ROI to 'Val'
1069 
1070  template <class T>
1071  void CImg<T>::SetROIVal(const T& Val)
1072  {
1073  T* pROI = m_pROI;
1074  for (int y = m_ROIStartY; y < m_ROIEndY;
1075  y++, pROI += m_ROISkipCols)
1076  for (int x = m_ROIStartX; x < m_ROIEndX; x++, pROI++)
1077  *pROI = Val;
1078  }
1079 
1081  // Set the pixel Values of the region outside the ROI to 'Val'
1082 
1083  template <class T>
1084  void CImg<T>::SetOutROIVal(const T& Val)
1085  {
1086  int yoffset, x, y;
1087  for (y = 0; y < m_ROIStartY; y++) { // Top horiz. rectangle
1088  yoffset = y*m_Width;
1089  for (x = 0; x < m_Width; x++)
1090  m_pBuffer[yoffset+x] = Val;
1091  }
1092  for (y = m_ROIEndY; y < m_Height; y++) { // Bot horiz. rectangle
1093  yoffset = y*m_Width;
1094  for (x = 0; x < m_Width; x++)
1095  m_pBuffer[yoffset+x] = Val;
1096  }
1097  for (y = m_ROIStartY; y < m_ROIEndY; y++) { // Left vert. rectangle
1098  yoffset = y*m_Width;
1099  for (x = 0; x < m_ROIStartX; x++)
1100  m_pBuffer[yoffset+x] = Val;
1101  }
1102  for (y = m_ROIStartY; y < m_ROIEndY; y++) { // Right vert. rectangle
1103  yoffset = y*m_Width;
1104  for (x = m_ROIEndX; x < m_Width; x++)
1105  m_pBuffer[yoffset+x] = Val;
1106  }
1107  }
1108 
1109  template <class T>
1110  void CImg<T>::SetOutROIVal(const T& TopVal, const T& BotVal,
1111  const T& LeftVal, const T& RightVal)
1112  {
1113  int yoffset, x, y;
1114  for (y = 0; y < m_ROIStartY; y++) { // Top horiz. rectangle
1115  yoffset = y*m_Width;
1116  for (x = 0; x < m_Width; x++)
1117  m_pBuffer[yoffset+x] = TopVal;
1118  }
1119  for (y = m_ROIEndY; y < m_Height; y++) { // Bot horiz. rectangle
1120  yoffset = y*m_Width;
1121  for (x = 0; x < m_Width; x++)
1122  m_pBuffer[yoffset+x] = BotVal;
1123  }
1124  for (y = m_ROIStartY; y < m_ROIEndY; y++) { // Left vert. rectangle
1125  yoffset = y*m_Width;
1126  for (x = 0; x < m_ROIStartX; x++)
1127  m_pBuffer[yoffset+x] = LeftVal;
1128  }
1129  for (y = m_ROIStartY; y < m_ROIEndY; y++) { // Right vert. rectangle
1130  yoffset = y*m_Width;
1131  for (x = m_ROIEndX; x < m_Width; x++)
1132  m_pBuffer[yoffset+x] = RightVal;
1133  }
1134  }
1135 
1137 
1138  template <class T>
1140  {
1141  int yoffset, yoffset2, x, x2, y;
1142  const int StartX2 = m_ROIStartX+m_ROIStartX;
1143  const int StartY2 = m_ROIStartY+m_ROIStartY;
1144  const int EndX2 = m_ROIEndX+m_ROIEndX;
1145  const int EndY2 = m_ROIEndY+m_ROIEndY;
1146 
1147  for (y = 0; y < m_ROIStartY; y++) { // Top horiz. rectangle
1148  yoffset = y*m_Width;
1149  yoffset2 = (StartY2-y-1)*m_Width;
1150  for (x = 0; x < m_Width; x++)
1151  m_pBuffer[yoffset+x] = m_pBuffer[yoffset2+x];
1152  }
1153  for (y = m_ROIEndY; y < m_Height; y++) { // Bot horiz. rectangle
1154  yoffset = y*m_Width;
1155  yoffset2 = (EndY2-y-1)*m_Width;
1156  for (x = 0; x < m_Width; x++)
1157  m_pBuffer[yoffset+x] = m_pBuffer[yoffset2+x];
1158  }
1159  for (y = m_ROIStartY; y < m_ROIEndY; y++) { // Left vert. rectangle
1160  yoffset = y*m_Width;
1161  for (x = 0; x < m_ROIStartX; x++) {
1162  x2 = StartX2-x-1;
1163  m_pBuffer[yoffset+x] = m_pBuffer[yoffset+x2];
1164  }
1165  }
1166  for (y = m_ROIStartY; y < m_ROIEndY; y++) { // Right vert. rectangle
1167  yoffset = y*m_Width;
1168  for (x = m_ROIEndX; x < m_Width; x++) {
1169  x2 = EndX2-x-1;
1170  m_pBuffer[yoffset+x] = m_pBuffer[yoffset+x2];
1171  }
1172  }
1173 
1175 
1176  for (y = 0; y < m_ROIStartY; y++) { // Top left box
1177  yoffset = y*m_Width;
1178  yoffset2 = (StartY2-y-1)*m_Width;
1179  for (x = 0; x < m_ROIStartX; x++) {
1180  x2 = StartX2-x-1;
1181  m_pBuffer[yoffset+x] = m_pBuffer[yoffset2+x2];
1182  }
1183  }
1184 
1185  for (y = m_ROIEndY; y < m_Height; y++) { // Bot left box
1186  yoffset = y*m_Width;
1187  yoffset2 = (EndY2-y-1)*m_Width;
1188  for (x = 0; x < m_ROIStartX; x++) {
1189  x2 = StartX2-x-1;
1190  m_pBuffer[yoffset+x] = m_pBuffer[yoffset2+x2];
1191  }
1192  }
1193 
1194  for (y = 0; y < m_ROIStartY; y++) { // Top right box
1195  yoffset = y*m_Width;
1196  yoffset2 = (StartY2-y-1)*m_Width;
1197  for (x = m_ROIEndX; x < m_Width; x++) {
1198  x2 = EndX2-x-1;
1199  m_pBuffer[yoffset+x] = m_pBuffer[yoffset2+x2];
1200  }
1201  }
1202 
1203  for (y = m_ROIEndY; y < m_Height; y++) { // Bot right box
1204  yoffset = y*m_Width;
1205  yoffset2 = (EndY2-y-1)*m_Width;
1206  for (x = m_ROIEndX; x < m_Width; x++) {
1207  x2 = EndX2-x-1;
1208  m_pBuffer[yoffset+x] = m_pBuffer[yoffset2+x2];
1209  }
1210  }
1211  }
1212 
1214  // Copy pixel Values from a Buffer, ROI must agree with Buffer's
1215  // size, Height and Width.
1216 
1217  template <class T>
1218  void CImg<T>::CopyFromBuf(T* pBuf)
1219  {
1220  T* pFrmBuf = pBuf;
1221  T* pROI = m_pROI;
1222  for (int y = m_ROIStartY; y < m_ROIEndY; y++, pROI += m_ROISkipCols)
1223  for (int x = m_ROIStartX; x < m_ROIEndX; x++, pROI++, pFrmBuf++)
1224  *pROI = *pFrmBuf;
1225  }
1226 
1228 
1229  template <class T>
1230  void CImg<T>::CopyFromBuf(T* pBuf, const int& StartX, const int& EndX,
1231  const int& StartY, const int& EndY)
1232  {
1233  T* pFrmBuf = pBuf;
1234  T* pROI = m_pROI;
1235  for (int y = m_ROIStartY; y < m_ROIEndY; y++, pROI += m_ROISkipCols) {
1236  for (int x = m_ROIStartX; x < m_ROIEndX; x++, pROI++, pFrmBuf++) {
1237  if ((x >= StartX) &&
1238  (x < EndX) &&
1239  (y >= StartY) &&
1240  (y < EndY)) {
1241  *pROI = *pFrmBuf;
1242  }
1243  }
1244  }
1245  }
1246 
1248  // Copy pixel Values to a Buffer, ROI must agree with Buffer's
1249  // size, Height and Width.
1250 
1251  template <class T>
1252  void CImg<T>::CopyToBuf(T* pBuf)
1253  {
1254  T* pBuf2 = pBuf;
1255  T* pROI = m_pROI;
1256  for (int y = m_ROIStartY; y < m_ROIEndY; y++, pROI += m_ROISkipCols)
1257  for (int x = m_ROIStartX; x < m_ROIEndX; x++, pROI++, pBuf2++)
1258  *pBuf2 = *pROI;
1259  }
1260 
1262  // Attach the Img to a Buffer according to Img's member
1263  // functions assumes m_pBuffer doesn't point to an Img that needs
1264  // to be freed later.
1265 
1266  template <class T>
1267  inline void CImg<T>::Attach(T* pBuf)
1268  {
1269  m_pBuffer = pBuf;
1270  m_pROI = (T*)m_pBuffer+m_ROIOffset;
1271  m_bDelete = false;
1272  }
1273 
1275  // As Above, but resetting all Img members.
1276 
1277  template <class T>
1278  inline void CImg<T>::Attach(T* pBuf, const int Width, const int Height,
1279  const bool bDelete)
1280  {
1281  m_ROIHeight = m_ROIEndY = m_Height = Height;
1282  m_ROIWidth = m_ROIEndX = m_Width = Width;
1283  m_ROISize = m_nPixels = Height*Width;
1284  m_ROIOffset = m_ROISkipCols = m_ROIStartX = m_ROIStartY = 0;
1285  if (m_bDelete) zap(m_pBuffer);
1286  m_pROI = m_pBuffer = pBuf;
1287  m_bDelete = bDelete;
1288  }
1289 
1291 
1292  template <class T>
1293  inline T* CImg<T>::Detach()
1294  {
1295  m_bDelete = false;
1296  return m_pBuffer;
1297  }
1298 
1300  // Convert float Img (this) into byte Img 'ByteImg', scaling according
1301  // to Max and Min Values. Only works on float images, set pixels outside
1302  // ROI to 'BGVal'.
1303 
1304  template <> inline void CImg<float>::f2b(CImg<BYTE> &ByteImg,BYTE BGVal)
1305  {
1306  // compute Max and Min
1307  float *inp = m_pROI;
1308  float Max = CONST_MIN_FLOAT, Min = CONST_MAX_FLOAT, TmpF;
1309  int x, y;
1310  // compute Min and Max
1311  for (y = m_ROIStartY; y < m_ROIEndY; y++, inp += m_ROISkipCols)
1312  for (x = m_ROIStartX; x < m_ROIEndX; x++, inp++) {
1313  if ((TmpF = *inp) > Max) Max = TmpF;
1314  if (TmpF < Min) Min = TmpF;
1315  }
1316  // scale and convert to bytes
1317  inp = m_pROI;
1318  BYTE *pOut = ByteImg.pROI();
1319  const int pOut_rskip = ByteImg.ROISkipCols();
1320  float factor = 255.0f/(Max-Min);
1321  for (y = m_ROIStartY; y < m_ROIEndY;
1322  y++, inp += m_ROISkipCols, pOut += pOut_rskip)
1323  for (x = m_ROIStartX; x < m_ROIEndX; x++, inp++, pOut++)
1324  *pOut = (BYTE)((*inp-Min)*factor);
1325  ByteImg.SetOutROIVal(BGVal);
1326  }
1327 
1329  // As Above, but using only casting, no rescaling done in conversion.
1330 
1331  template <> inline void CImg<float>::f2bNoscale(CImg<BYTE> &ByteImg,BYTE BGVal)
1332  {
1333  // compute Max and Min
1334  float *inp = m_pROI;
1335  BYTE *pOut = ByteImg.pROI();
1336  int x, y;
1337  for (y = m_ROIStartY; y < m_ROIEndY;
1338  y++, inp += m_ROISkipCols, pOut += m_ROISkipCols)
1339  for (x = m_ROIStartX; x < m_ROIEndX; x++, inp++, pOut++)
1340  *pOut = (BYTE)*inp;
1341  ByteImg.SetOutROIVal(BGVal);
1342  }
1343 
1345  // Same as Above, but here, instead of computing the Min and Max of the
1346  // float Img, we supply them as arguments
1347 
1348  template <> inline void CImg<float>::f2b(CImg<BYTE> &ByteImg, float Min,
1349  float Max, BYTE BGVal)
1350  {
1351  // scale and convert to bytes
1352  float *inp = m_pROI;
1353  BYTE *pOut = ByteImg.pROI();
1354  float factor = 255.0f/(Max-Min);
1355  float m = Min;
1356  for (int y = m_ROIStartY; y < m_ROIEndY;
1357  y++, inp += m_ROISkipCols, pOut += m_ROISkipCols)
1358  for (int x = m_ROIStartX; x < m_ROIEndX; x++, inp++, pOut++) {
1359  *pOut = (BYTE)((*inp-m)*factor);
1360  }
1361  ByteImg.SetOutROIVal(BGVal);
1362  }
1363 
1365  // Convert byte Img (this) into float Img 'ByteImg' by casting.
1366 
1367  template <> inline void CImg<BYTE>::b2f(CImg<float> &FloatImg, float BGVal)
1368  {
1369  BYTE *inp = m_pROI;
1370  float *pOut = FloatImg.pROI();
1371  const int OutSkip = FloatImg.ROISkipCols();
1372  for (int y = m_ROIStartY; y < m_ROIEndY; y++, inp += m_ROISkipCols,
1373  pOut += OutSkip)
1374  for (int x = m_ROIStartX; x < m_ROIEndX; x++, inp++, pOut++)
1375  *pOut = (float)*inp;
1376  FloatImg.SetOutROIVal(BGVal);
1377  }
1378 
1380  // Convert int Img (this) into float Img by casting.
1381 
1382  template <> inline void CImg<int>::i2f(CImg<float> &FloatImg, float BGVal)
1383  {
1384  int* pIn = m_pROI;
1385  float* pOut = FloatImg.pROI();
1386  for (int y = m_ROIStartY; y < m_ROIEndY;
1387  y++, pIn += m_ROISkipCols,
1388  pOut += m_ROISkipCols)
1389  for (int x = m_ROIStartX; x < m_ROIEndX; x++, pIn++, pOut++)
1390  *pOut = (float)*pIn;
1391  FloatImg.SetOutROIVal(BGVal);
1392  }
1393 
1395 
1396  template <class T>
1397  void CImg<T>::ToFloat(CImg<float> &FloatImg, float BGVal)
1398  {
1399  T* pIn = m_pROI;
1400  float* pOut = FloatImg.pROI();
1401  for (int y = m_ROIStartY; y < m_ROIEndY; y++, pIn += m_ROISkipCols,
1402  pOut += m_ROISkipCols)
1403  for (int x = m_ROIStartX; x < m_ROIEndX; x++, pIn++, pOut++)
1404  *pOut = (float)*pIn;
1405  FloatImg.SetOutROIVal(BGVal);
1406  }
1407 
1409  // Return the Minimum pixel index in 'x' and 'y' and the Value
1410  // of that pixel in 'Val' - searching in ROI only
1411 
1412  template <class T>
1413  void CImg<T>::Minpix(int &x, int &y, T& Val)
1414  {
1415  Val = *m_pROI; // make Val the first element in the ROI
1416  T* pROI = m_pROI;
1417  for (int yy = m_ROIStartY; yy < m_ROIEndY;
1418  yy++, pROI += m_ROISkipCols)
1419  for (int xx = m_ROIStartX; xx < m_ROIEndX; xx++, pROI++) {
1420  T* Tmp = *pROI;
1421  if (Tmp < Val) {
1422  Val = Tmp;
1423  x = xx;
1424  y = yy;
1425  } // if
1426  } // for xx
1427  }
1428 
1430  // Return the Maximum pixel index in 'x' and 'y' and the Value
1431  // of that pixel in 'Val' - searching in ROI only
1432 
1433  template <class T>
1434  void CImg<T>::Maxpix(int &x, int &y, T& Val)
1435  {
1436  Val = *m_pROI; // make Val the first element in the ROI
1437  T* pROI = m_pROI;
1438  for (int yy = m_ROIStartY; yy < m_ROIEndY;
1439  yy++, pROI += m_ROISkipCols)
1440  for (int xx = m_ROIStartX; xx < m_ROIEndX; xx++, pROI++) {
1441  T Tmp = *pROI;
1442  if (Tmp > Val) {
1443  Val = Tmp;
1444  x = xx;
1445  y = yy;
1446  } // if
1447  } // for xx
1448  }
1449 
1451 
1452  // Same as Above, but doesn't return coordinates.
1453 
1454  template <class T>
1455  void CImg<T>::Maxpix(T& Val)
1456  {
1457  Val = *m_pROI; // make Val the first element in the ROI
1458  T Tmp, *pROI = m_pROI;
1459  for (int yy = m_ROIStartY; yy < m_ROIEndY;
1460  yy++, pROI += m_ROISkipCols)
1461  for (int xx = m_ROIStartX; xx < m_ROIEndX; xx++, pROI++)
1462  if ((Tmp = *pROI) > Val) Val = Tmp;
1463  }
1464 
1466  // Return Both the Minimum and the Maximum Values (no coordinates).
1467 
1468  template <class T>
1469  void CImg<T>::MinMax(T& Min, T& Max)
1470  {
1471  Min = *m_pROI; // make Val the first element in the ROI
1472  Max = *m_pROI; // make Val the first element in the ROI
1473  T* pROI = m_pROI;
1474  for (int y = m_ROIStartY; y < m_ROIEndY;
1475  y++, pROI += m_ROISkipCols)
1476  for (int x = m_ROIStartX; x < m_ROIEndX; x++, pROI++) {
1477  T Tmp = *pROI;
1478  if (Tmp >= Max) Max = Tmp;
1479  if (Tmp < Min) Min = Tmp;
1480  } // for x
1481  }
1482 
1484 
1485  template <class T>
1487  {
1488  T Min = *m_pROI; // make Val the first element in the ROI
1489  T Max = *m_pROI; // make Val the first element in the ROI
1490  T* pROI = m_pROI;
1491  for (int y = m_ROIStartY; y < m_ROIEndY;
1492  y++, pROI += m_ROISkipCols) {
1493  for (int x = m_ROIStartX; x < m_ROIEndX; x++, pROI++) {
1494  T Tmp = *pROI;
1495  if (Tmp >= Max) Max = Tmp;
1496  if (Tmp < Min) Min = Tmp;
1497  } // for x
1498  }
1499  report_int("Min = ", Min);
1500  report_int("Max = ", Max);
1501  }
1502 
1504  // Return the mean Value of the ROI pixels.
1505 
1506  // BYTE version
1507  template <> inline float CImg<BYTE>::MeanLuminance()
1508  {
1509  BYTE* pROI = m_pROI;
1510  int sum = 0;
1511  for (int y = m_ROIStartY; y < m_ROIEndY;
1512  y++, pROI += m_ROISkipCols)
1513  for (int x = m_ROIStartX; x < m_ROIEndX; x++, pROI++)
1514  sum += (int)*pROI;
1515  return (float)sum/(float)m_ROISize;
1516  }
1517 
1518  // float version
1519  template <> inline float CImg<float>::MeanLuminance()
1520  {
1521  float* pROI = m_pROI;
1522  float sum = 0;
1523  for (int y = m_ROIStartY; y < m_ROIEndY;
1524  y++, pROI += m_ROISkipCols)
1525  for (int x = m_ROIStartX; x < m_ROIEndX; x++, pROI++)
1526  sum += *pROI;
1527  return sum/(float)m_ROISize;
1528  }
1529 
1531  // Return the mean luMinance in 'mu' and the variance in 'sig'
1532  // of the ROI pixels.
1533 
1534  // BYTE version
1535  template <> inline void CImg<BYTE>::MuSig(float &mu, float &sig)
1536  {
1537  BYTE* pROI = m_pROI;
1538  int imu = 0, isigsqr = 0;
1539  for (int yy = m_ROIStartY; yy < m_ROIEndY;
1540  yy++, pROI += m_ROISkipCols)
1541  for (int xx = m_ROIStartX; xx < m_ROIEndX; xx++, pROI++) {
1542  int TmpI = *pROI;
1543  imu += TmpI;
1544  isigsqr += SQR(TmpI);
1545  } // for x
1546  float count = (float)m_ROISize;
1547  mu = (float)imu/count;
1548  sig = (float)sqrt((double)((float)isigsqr/count-SQR(mu)));
1549  }
1550 
1551  // float version
1552  template <> inline void CImg<float>::MuSig(float &mu, float &sig)
1553  {
1554  float* pROI = m_pROI;
1555  float fmu = 0, fsigsqr = 0;
1556  for (int y = m_ROIStartY; y < m_ROIEndY;
1557  y++, pROI += m_ROISkipCols)
1558  for (int x = m_ROIStartX; x < m_ROIEndX; x++, pROI++) {
1559  float TmpF = *pROI;
1560  fmu += TmpF;
1561  fsigsqr += SQR(TmpF);
1562  } // for x
1563  float count = (float)m_ROISize;
1564  mu = fmu/count;
1565  sig = (float)sqrt((double)(fsigsqr/count-SQR(mu)));
1566  }
1567 
1569  // Return the mean luMinance in 'mu' and the variance in 'sig'
1570  // of the ROI pixels.
1571 
1572  // BYTE version
1573  template <> inline float CImg<BYTE>::SumAbs()
1574  {
1575  BYTE* pROI = m_pROI;
1576  kjb_int32 Sum;
1577  for (int yy = m_ROIStartY; yy < m_ROIEndY;
1578  yy++, pROI += m_ROISkipCols)
1579  for (int xx = m_ROIStartX; xx < m_ROIEndX; xx++, pROI++)
1580  {
1581  /* Kobus. Before 06/11/18, there was no "*" in front of pROI.
1582  * This looks like a latent bug. so I added the "*".
1583  */
1584  Sum += (kjb_int32)(*pROI);
1585  }
1586 
1587  return (float)Sum;
1588  }
1589 
1590  // float version
1591  template <> inline float CImg<float>::SumAbs()
1592  {
1593  float* pROI = m_pROI;
1594  float Sum = 0.0f;
1595  for (int y = m_ROIStartY; y < m_ROIEndY;
1596  y++, pROI += m_ROISkipCols)
1597  for (int x = m_ROIStartX; x < m_ROIEndX; x++, pROI++) {
1598  float TmpF = *pROI;
1599  if (TmpF > 0.0f) Sum += TmpF;
1600  else Sum -= TmpF;
1601  } // for (int x = m_ROIStartX; x < m_ROIEndX; x++, pROI++) {
1602  return Sum;
1603  }
1604 
1606  // Normalize the Img (floats only) ROI by subtracting the ROI mean
1607  // from each pixel and dividing by the ROI Sigma.
1608 
1609  // float version
1610  template <> inline void CImg<float>::Normalize(bool full_range)
1611  {
1612  float mu, sig;
1613  MuSig(mu, sig);
1614  float* pROI = m_pROI;
1615  float factor = 1.0f/sig;
1616  for (int y = m_ROIStartY; y < m_ROIEndY;
1617  y++, pROI += m_ROISkipCols)
1618  for (int x = m_ROIStartX; x < m_ROIEndX; x++, pROI++)
1619  *pROI = (*pROI-mu)*factor;
1620  }
1621 
1622  // BYTE version
1623  template <> inline void CImg<BYTE>::Normalize(bool full_range)
1624  {
1625  if (full_range) { // not getting rid of any Values
1626  CImg<float> TmpFloatImg(m_Width, m_Height);
1627  TmpFloatImg.ChangeROI(m_ROIStartX, m_ROIEndX,
1628  m_ROIStartY, m_ROIEndY);
1629  b2f(TmpFloatImg);
1630  TmpFloatImg.Normalize(); // float normalization
1631  // now make sure that 0.0f in the float Img is 127.5 in the
1632  // byte Img, and stretch the Values as much as possible in
1633  // the byte Img so that the entire 0-255 range is used, at least
1634  // in one direction (Above or Below 127)
1635  float Min, Max; TmpFloatImg.MinMax(Min, Max);
1636  if (-Min > Max) Max = -Min; // now Max = largest-magnitude flank
1637  float* fp = TmpFloatImg.pROI();
1638  BYTE *bp = m_pROI;
1639  const float factor = 127.5f/Max;
1640  for (int y = m_ROIStartY; y < m_ROIEndY;
1641  y++, fp += m_ROISkipCols, bp += m_ROISkipCols)
1642  for (int x = m_ROIStartX; x < m_ROIEndX; x++, fp++, bp++)
1643  *bp = (BYTE)(*fp*factor+127.5f);
1644  } // if (full_range) ..
1645  else { // another rescaling method from floats to bytes, faster
1646  // but you may lose some pixels
1647  float mu, sig;
1648  MuSig(mu, sig);
1649  BYTE* pROI = m_pROI;
1650  float factor = 50.0f/sig;
1651  for (int y = m_ROIStartY; y < m_ROIEndY;
1652  y++, pROI += m_ROISkipCols)
1653  for (int x = m_ROIStartX; x < m_ROIEndX; x++, pROI++) {
1654  float TmpF = ((float)*pROI-mu)*factor+127.5f;
1655  if (TmpF < 0.0f) *pROI = 0;
1656  else if (TmpF > 255.0f) *pROI = 255;
1657  else *pROI = (BYTE)TmpF;
1658  } // for x
1659  } // else
1660  }
1661 
1663  // Change the range of pixel Values in the Img linearly.
1664 
1665  // byte version *** UNTESTED ***
1666  template <> inline void CImg<BYTE>:: ChangeRange(const BYTE& NewMin,
1667  const BYTE& NewMax)
1668  {
1669  BYTE OldMinByte, OldMaxByte;
1670  float OldMin, NewMinR, OldMax, Factor;
1671  float OldRange, NewRange;
1672  BYTE* pROI;
1673 
1674  NewMinR = (float)NewMin;
1675  MinMax(OldMinByte, OldMaxByte);
1676  OldMin = (float)OldMinByte;
1677  OldMax = (float)OldMaxByte;
1678  OldRange = OldMax-OldMin;
1679 
1680  if (OldRange == 0) { // one-valued image
1681  pROI = m_pROI;
1682  const BYTE Val = (BYTE)((float)(NewMax-NewMin)*0.5f);
1683  for (int y = m_ROIStartY; y < m_ROIEndY;
1684  y++, pROI += m_ROISkipCols)
1685  for (int x = m_ROIStartX; x < m_ROIEndX; x++, pROI++)
1686  *pROI = Val;
1687  }
1688  else {
1689  NewRange = (float)NewMax-(float)NewMin;
1690  Factor = NewRange/OldRange;
1691  pROI = m_pROI;
1692  for (int y = m_ROIStartY; y < m_ROIEndY;
1693  y++, pROI += m_ROISkipCols)
1694  for (int x = m_ROIStartX; x < m_ROIEndX; x++, pROI++)
1695  *pROI = (BYTE)((*pROI-OldMin)*Factor+NewMin);
1696  }
1697  }
1698 
1699  // float version
1700  template <> inline void CImg<float>:: ChangeRange(const float& NewMin,
1701  const float& NewMax)
1702  {
1703  float OldMin, NewMinR, OldMax, Factor;
1704  float OldRange, NewRange;
1705  float* pROI;
1706 
1707  NewMinR = NewMin;
1708  MinMax(OldMin, OldMax);
1709  OldRange = OldMax-OldMin;
1710 
1711  if (OldRange == 0) { // one-valued image
1712  pROI = m_pROI;
1713  Factor = (NewMax-NewMin)/2.0f; // average of requested range
1714  for (int y = m_ROIStartY; y < m_ROIEndY;
1715  y++, pROI += m_ROISkipCols)
1716  for (int x = m_ROIStartX; x < m_ROIEndX; x++, pROI++)
1717  *pROI = Factor;
1718  }
1719  else {
1720  NewRange = NewMax-NewMin;
1721  Factor = NewRange/OldRange;
1722  pROI = m_pROI;
1723  for (int y = m_ROIStartY; y < m_ROIEndY;
1724  y++, pROI += m_ROISkipCols)
1725  for (int x = m_ROIStartX; x < m_ROIEndX; x++, pROI++)
1726  *pROI = (*pROI-OldMin)*Factor+NewMin;
1727  }
1728  }
1729 
1731 
1732  // float version
1733  template <> inline void CImg<float>:: FixThetaRanges(const bool& bHalfPhase)
1734  {
1735  float* pROI = m_pROI;
1736  for (int y = m_ROIStartY; y < m_ROIEndY;
1737  y++, pROI += m_ROISkipCols)
1738  for (int x = m_ROIStartX; x < m_ROIEndX; x++, pROI++)
1739  FixThetaRange(*pROI, bHalfPhase);
1740  }
1741 
1743  // PRECOND: MuImg is the same as TImg w/no ROI - Both are size of
1744  // this's ROI, TImg is a temporary integer Img. Result is in
1745  // MuImg = the mean filter of this of size dx * dy. This method
1746  // uses (a) separable x and y mean filter kernels, (b) running
1747  // averages to compute the mean.
1748 
1749  template <class T>
1751  CImg<float> &TImg, int dx, int dy)
1752  {
1753  const int hdx = dx/2, hdx2 = (dx-1)/2, hdy = dy/2, hdy2 = (dy-1)/2;;
1754  T* ip = m_pROI;
1755  float *tp = TImg.m_pBuffer;
1756  for (int y = m_ROIStartY; y < m_ROIEndY;
1757  y++, ip += m_Width, tp += m_ROIWidth) {
1758  T* ip2 = ip;
1759  float mean = 0.0f;
1760  for (int i = 0; i < dx; i++, ip2++) mean += (float)*ip2;
1761  float *tp2 = tp+hdx;
1762  int x, xe = m_ROIEndX-hdx2;
1763  for (x = m_ROIStartX+hdx; x < xe; x++, ip2++, tp2++) {
1764  *tp2 = mean;
1765  mean -= *(ip2-dx);
1766  mean += *ip2;
1767  } // for x
1768  } // for y
1769  tp = TImg.m_pBuffer;
1770  float *mup = MuImg.m_pBuffer;
1771  const float boxarea = (float)(dx*dy);
1772  for (int x = m_ROIStartX; x < m_ROIEndX; x++, tp++, mup++) {
1773  float *tp2 = tp, mean = 0.0f;
1774  int ys = m_ROIStartY+hdy, ye = m_ROIEndY-hdy2, i;
1775  for (i = 0; i < dy; i++, tp2 += m_ROIWidth) mean += (float)*tp2;
1776  float *mup2 = mup+hdy*m_ROIWidth;
1777  for (int y = ys; y < ye;
1778  y++, tp2 += m_ROIWidth, mup2 += m_ROIWidth) {
1779  const int dyoff = dy*m_ROIWidth;
1780  *mup2 = (float)mean/boxarea;
1781  mean -= *(tp2-dyoff);
1782  mean += *tp2;
1783  } // for x
1784  } // for y
1785  // clear borders
1786  MuImg.ChangeROI(hdx, m_ROIWidth-hdx2, hdy, m_ROIHeight-hdy2);
1787  MuImg.SetOutROIVal(0.0f);
1788  MuImg.ChangeROI(0, m_ROIWidth, 0, m_ROIHeight);
1789  }
1790 
1791  // Wrapper for Above if you're only doing Above once in your program
1792  // and you don't need to reuse the temporary storage that's supplied
1793  // Above.
1794 
1795  template <class T>
1796  void CImg<T>::MuFilter(CImg<float> &MuImg, int dx, int dy)
1797  {
1798  CImg<float> TImg(MuImg.Width(), MuImg.Height());
1799  MuFilter(MuImg, TImg, dx, dy);
1800  }
1801 
1803  // Same as Above, but returns Sigma Img in SigImg as well, 'UImg' is
1804  // another temporary Img.
1805 
1806  template <class T>
1807  inline void CImg<T>::MuSigFilter(CImg<float> &MuImg, CImg<float> &SigImg,
1808  CImg<float> &TImg, CImg<float> &UImg,
1809  int dx, int dy)
1810  {
1811  const int hdx = dx/2, hdy = dy/2;
1812  T* ip = m_pROI;
1813  float *tp = TImg.m_pBuffer, *up = UImg.m_pBuffer;;
1814  for (int y = m_ROIStartY; y < m_ROIEndY;
1815  y++, ip += m_Width, tp += m_ROIWidth, up += m_ROIWidth) {
1816  T* ip2 = ip;
1817  float mean = 0.0f, sig = 0.0f;
1818  for (int i = 0; i < dx; i++, ip2++) {
1819  float TmpF = (float)*ip2;
1820  mean += TmpF;
1821  sig += SQR(TmpF);
1822  } // for i
1823  float *tp2 = tp+hdx;
1824  float *up2 = up+hdx;
1825  int x, xe = m_ROIEndX-dx;
1826  for (x = 0; x < xe; x++, ip2++, tp2++, up2++) {
1827  *tp2 = mean;
1828  *up2 = sig;
1829  float before = (float)*(ip2-dx), after = (float)*ip2;
1830  mean -= before;
1831  mean += after;
1832  sig -= SQR(before);
1833  sig += SQR(after);
1834  } // for x
1835  } // for y
1836  tp = TImg.m_pBuffer;
1837  up = UImg.m_pBuffer;
1838  float *mup = MuImg.m_pBuffer;
1839  float *sigp = SigImg.m_pBuffer;
1840  const float boxarea = (float)(dx*dy);
1841  for (int x = m_ROIStartX; x < m_ROIEndX; x++, tp++,mup++,up++,sigp++) {
1842  float *tp2 = tp, *up2 = up, mean = 0.0f, sig = 0.0f;
1843  int ye = m_ROIEndY-dy, i;
1844  for (i = 0; i < dy; i++, tp2 += m_ROIWidth, up2 += m_ROIWidth) {
1845  mean += *tp2;
1846  sig += *up2;
1847  } // for i
1848  float *mup2 = mup+hdy*m_ROIWidth;
1849  float *sigp2 = sigp+hdy*m_ROIWidth;
1850  for (int y = 0; y < ye; y++, tp2 += m_ROIWidth,mup2 += m_ROIWidth,
1851  up2 += m_ROIWidth, sigp2 += m_ROIWidth) {
1852  const int dyoff = dy*m_ROIWidth;
1853  float mu = (float)mean/boxarea;
1854  *mup2 = mu;
1855  *sigp2 = (float)sqrt((double)(sig/boxarea-SQR(mu)));
1856  mean -= *(tp2-dyoff);
1857  mean += *tp2;
1858  sig -= *(up2-dyoff);
1859  sig += *up2;
1860  } // for x
1861  } // for y
1862  // clear borders
1863  MuImg.ChangeROI(hdx, m_ROIWidth-dx+hdx, hdy, m_ROIHeight-dy+hdy);
1864  MuImg.SetOutROIVal(0.0f);
1865  MuImg.ChangeROI(0, m_ROIWidth, 0, m_ROIHeight);
1866  SigImg.ChangeROI(hdx, m_ROIWidth-dx+hdx, hdy, m_ROIHeight-dy+hdy);
1867  SigImg.SetOutROIVal(0.0f);
1868  SigImg.ChangeROI(0, m_ROIWidth, 0, m_ROIHeight);
1869  }
1870 
1871  // Wrapper for Above if you're only doing Above once in your program
1872  // and you don't need to reuse the temporary storage that's supplied
1873  // Above.
1874 
1875  template <class T>
1877  int dx, int dy)
1878  {
1879  int w = MuImg.Width(), h = MuImg.Height();
1880  CImg<float> TImg(w, h);
1881  CImg<float> UImg(w, h);
1882  MuSigFilter(MuImg, SigImg, TImg, UImg, dx, dy);
1883  }
1884 
1886  // Take this Img's and pad it with 'Left' zeros on the Left
1887  // and 'Top' zeros from the Top with Value 'Val'. Now embed the
1888  // Img in 'DestImg' and zero-out the Bottom and Right areas
1889  // where this Img doesn't reach.
1890 
1891  template <class T>
1892  void CImg<T>::Pad(CImg<T> &DestImg, const int Left, const int Top,
1893  const T& Val)
1894  {
1895  const int StartX = DestImg.ROIStartX(), StartY = DestImg.ROIStartY(),
1896  EndX = DestImg.ROIEndX(), EndY = DestImg.ROIEndY();
1897  DestImg.ChangeROI(Left, Left+m_Width, Top, Top+m_Height);
1898  DestImg.CopyFromBuf(m_pBuffer);
1899  DestImg.SetOutROIVal(Val);
1900  DestImg.ChangeROI(StartX, EndX, StartY, EndY);
1901  }
1902 
1904  // Extract a portion of this Img, starting at x = 'Left' and
1905  // y = 'Top' and going to the Right 'DestImg.Width()' pixels
1906  // and to the Bottom 'DestImg.Height()' pixels. The extracted
1907  // region fills up DestImg completely and it is Left with full ROI.
1908 
1909  template <class T>
1910  void CImg<T>::Extract(CImg<T> &DestImg, const int& Left, const int& Bot)
1911  {
1912  const int StartX = m_ROIStartX, StartY = m_ROIStartY,
1913  EndX = m_ROIEndX, EndY = m_ROIEndY;
1914  ChangeROI(Left, Left+DestImg.Width(), Bot, Bot+DestImg.Height());
1915  CopyToBuf(DestImg.m_pBuffer);
1916  ChangeROI(StartX, EndX, StartY, EndY);
1917  }
1918 
1920 
1921  template <> inline void CImg<float>::Square()
1922  {
1923  float *pROI = m_pROI;
1924  const int sk = m_ROISkipCols;
1925  for (int y = m_ROIStartY; y < m_ROIEndY; y++, pROI += sk)
1926  for (int x = m_ROIStartX; x < m_ROIEndX; x++, pROI++) {
1927  const float Val = *pROI;
1928  *pROI *= Val;;
1929  }
1930  }
1931 
1933 
1934  template <class T>
1936  {
1937  memset(m_pBuffer, 0, m_Width*m_Height*sizeof(T));
1938  }
1939 
1941  // Multiply 'Img' with this one (looking at ROI only). PRECOND:
1942  // ROI of 'Img' must be the same Width and Height as this's ROI.
1943  // Result is returned in this. Works for T images only.
1944 
1945  template <class T>
1947  {
1948  T *pROI = m_pROI, *pOtherROI= Img.pROI();
1949  int x, y, EndX = m_ROIEndX, sk1 = m_ROISkipCols,
1950  sk2 = Img.ROISkipCols();
1951  for (y = m_ROIStartY; y < m_ROIEndY; y++, pROI += sk1, pOtherROI+= sk2)
1952  for (x = m_ROIStartX; x < EndX; x++, pROI++, pOtherROI++)
1953  *pROI *= *pOtherROI;
1954  }
1955 
1957  // Multiply all Values of this Img by Val and return result in
1958  // this. Works for T images only.
1959 
1960  template <class T>
1961  void CImg<T>::Mul(const T& Val)
1962  {
1963  T *pROI = m_pROI;
1964  int x, y, EndX = m_ROIEndX, EndY = m_ROIEndY, sk = m_ROISkipCols;
1965  for (y = m_ROIStartY; y < EndY; y++, pROI += sk)
1966  for (x = m_ROIStartX; x < EndX; x++, pROI++)
1967  *pROI *= Val;
1968  }
1969 
1971  // Divide this by Img Img.
1972 
1973  template <class T>
1975  {
1976  T *pROI = m_pROI, *pOtherROI= Img.pROI();
1977  int x, y, EndX = m_ROIEndX,
1978  sk1 = m_ROISkipCols, sk2 = Img.ROISkipCols();
1979  for (y = m_ROIStartY; y < m_ROIEndY; y++, pROI += sk1, pOtherROI+= sk2)
1980  for (x = m_ROIStartX; x < EndX; x++, pROI++, pOtherROI++)
1981  *pROI /= *pOtherROI;
1982  }
1983 
1985  // Divide this by Value Val.
1986 
1987  template <class T>
1988  void CImg<T>::Div(const T& Val)
1989  {
1990  T *pROI = m_pROI;
1991  int x, y, EndX = m_ROIEndX, EndY = m_ROIEndY, sk = m_ROISkipCols;
1992  const float factor = 1.0f/Val;
1993  for (y = m_ROIStartY; y < EndY; y++, pROI += sk)
1994  for (x = m_ROIStartX; x < EndX; x++, pROI++)
1995  *pROI *= factor;
1996  }
1997 
1999  // Add Img to this.
2000 
2001  template <class T>
2003  {
2004  T *pROI = m_pROI, *pOtherROI= Img.pROI();
2005  int x, y, EndX = m_ROIEndX,
2006  sk1 = m_ROISkipCols, sk2 = Img.ROISkipCols();
2007  for (y = m_ROIStartY; y < m_ROIEndY; y++, pROI += sk1, pOtherROI+= sk2)
2008  for (x = m_ROIStartX; x < EndX; x++, pROI++, pOtherROI++)
2009  *pROI += *pOtherROI;
2010  }
2011 
2013  // Add Val to this.
2014 
2015  template <class T>
2016  void CImg<T>::Add(const T& Val)
2017  {
2018  T *pROI = m_pROI;
2019  int x, y, EndX = m_ROIEndX, EndY = m_ROIEndY, sk = m_ROISkipCols;
2020  for (y = m_ROIStartY; y < EndY; y++, pROI += sk)
2021  for (x = m_ROIStartX; x < EndX; x++, pROI++)
2022  *pROI += Val;
2023  }
2024 
2026  // Subtract Img from this.
2027 
2028  template <class T>
2030  {
2031  T *pROI = m_pROI, *pOtherROI= Img.pROI();
2032  int x, y, EndX = m_ROIEndX,
2033  sk1 = m_ROISkipCols, sk2 = Img.ROISkipCols();
2034  for (y = m_ROIStartY; y < m_ROIEndY; y++, pROI += sk1, pOtherROI+= sk2)
2035  for (x = m_ROIStartX; x < EndX; x++, pROI++, pOtherROI++)
2036  *pROI -= *pOtherROI;
2037  }
2038 
2040  // Subtract Val from this.
2041 
2042  template <class T>
2043  void CImg<T>::Sub(const T& Val)
2044  {
2045  T *pROI = m_pROI;
2046  int x, y, EndX = m_ROIEndX, EndY = m_ROIEndY, sk = m_ROISkipCols;
2047  for (y = m_ROIStartY; y < EndY; y++, pROI += sk)
2048  for (x = m_ROIStartX; x < EndX; x++, pROI++)
2049  *pROI -= Val;
2050  }
2051 
2053  // Negate in place.
2054 
2055  // BYTE version (untested)
2056  template <> inline void CImg<BYTE>::Neg()
2057  {
2058  BYTE* pROI = m_pROI;
2059  for (int y = m_ROIStartY; y < m_ROIEndY;
2060  y++, pROI += m_ROISkipCols)
2061  for (int x = m_ROIStartX; x < m_ROIEndX; x++, pROI++)
2062  *pROI = (BYTE)255-(*pROI);
2063  }
2064 
2065  // general version
2066  template <class T>
2068  {
2069  T* pROI = m_pROI;
2070  for (int y = m_ROIStartY; y < m_ROIEndY;
2071  y++, pROI += m_ROISkipCols)
2072  for (int x = m_ROIStartX; x < m_ROIEndX; x++, pROI++)
2073  *pROI = -(*pROI);
2074  }
2075 
2077  // Compute log(a+z), where 'a' is Value of each pixel in ROI, and 'z'
2078  // is a user supplied argument.
2079 
2080  // float version
2081  template <> inline void CImg<float>::Log(const float& z)
2082  {
2083  float* pROI = m_pROI;
2084  for (int y = m_ROIStartY; y < m_ROIEndY;
2085  y++, pROI += m_ROISkipCols)
2086  for (int x = m_ROIStartX; x < m_ROIEndX; x++, pROI++) {
2087  float Val = *pROI+z;
2088  if (Val <= 0.0f) *pROI = -99999.9f;
2089  else *pROI = (float)log(Val);
2090  }
2091  }
2092 
2094  // Or 'this' with 'Img' (so ROIs must be the same size) and return the
2095  // result in this. If the Img is a float Img, then a Value exactly
2096  // equal to 0.0 is considered false while anything else is true. If,
2097  // at any pixel, one of the images ('this' or 'Img') is nonzero, then
2098  // asign this pixel in 'this' the Value Val.
2099 
2100  template <class T>
2101  void CImg<T>::HardOR(CImg<T>& Img, const T& Val)
2102  {
2103  T* pROI = m_pROI, *pOtherROI= Img.pROI(), ZeroVal = (T)0;
2104  int x, y, EndX = m_ROIEndX, sk1 = m_ROISkipCols,
2105  sk2 = Img.ROISkipCols();
2106  for (y = m_ROIStartY; y < m_ROIEndY; y++, pROI += sk1, pOtherROI+= sk2)
2107  for (x = m_ROIStartX; x < EndX; x++, pROI++, pOtherROI++)
2108  if ((*pROI != ZeroVal) || (*pOtherROI!= ZeroVal)) *pROI = Val;
2109  // no need for 'else *pROI = (T)0;' bec. we're putting things
2110  // back in 'this' which is already 0 in these places
2111  }
2112 
2114  // Same as HardOR(), but rather than setting a true pixel to some
2115  // Value, keep the Value that made it true.
2116 
2117  template <class T>
2119  {
2120  T* pROI = m_pROI, *pOtherROI= Img.pROI(), ZeroVal = (T)0;
2121  int x, y, EndX = m_ROIEndX, sk1 = m_ROISkipCols,
2122  sk2 = Img.ROISkipCols();
2123  for (y = m_ROIStartY; y < m_ROIEndY; y++, pROI += sk1, pOtherROI+= sk2)
2124  for (x = m_ROIStartX; x < EndX; x++, pROI++, pOtherROI++)
2125  if ((*pROI == ZeroVal) && (*pOtherROI != ZeroVal))
2126  *pROI = *pOtherROI;
2127  // no need for 'else *pROI = (T)0;' bec. we're putting things
2128  // back in 'this' which is already 0 in these places
2129  }
2130 
2132  // Same as 'HardOR()' but it's an AND
2133 
2134  template <class T>
2135  void CImg<T>::HardAND(CImg<T>& Img, const T& Val)
2136  {
2137  T* pROI = m_pROI, *pOtherROI= Img.pROI(), ZeroVal = (T)0;
2138  int x, y, EndX = m_ROIEndX, sk1 = m_ROISkipCols,
2139  sk2 = Img.ROISkipCols();
2140  for (y = m_ROIStartY; y < m_ROIEndY; y++, pROI += sk1, pOtherROI+= sk2)
2141  for (x = m_ROIStartX; x < EndX; x++, pROI++, pOtherROI++)
2142  if ((*pROI != ZeroVal) && (*pOtherROI!= ZeroVal)) *pROI = Val;
2143  else *pROI = (T)0;
2144  }
2145 
2147  // Same as 'HardOR()' but it's an AND
2148 
2149  template <class T>
2151  {
2152  T* pROI = m_pROI, *pOtherROI= Img.pROI(), ZeroVal = (T)0;
2153  int x, y, EndX = m_ROIEndX, sk1 = m_ROISkipCols,
2154  sk2 = Img.ROISkipCols();
2155  for (y = m_ROIStartY; y < m_ROIEndY; y++, pROI += sk1, pOtherROI+= sk2)
2156  for (x = m_ROIStartX; x < EndX; x++, pROI++, pOtherROI++)
2157  if (*pOtherROI== ZeroVal) *pROI = (T)0;
2158  }
2159 
2161  // Pixels in 'Img' whose Value is Below 'Thresh' are set to 'Below',
2162  // other pixels are Left untouched. ROI is considered. In place version.
2163 
2164  /*template <class T>
2165  void CImg<T>::SoftThresh(const T Thresh, const T Below)
2166  {
2167  T* pROI = m_pROI;
2168  int x, y, EndX = m_ROIEndX, EndY = m_ROIEndY, sk = m_ROISkipCols;
2169  for (y = m_ROIStartY; y < EndY; y++, pROI += sk)
2170  for (x = m_ROIStartX; x < EndX; x++, pROI++)
2171  if (*pROI <= Thresh) *pROI = Below;
2172  }*/
2173 
2175  // Pixels in 'Img' whose Value is Below 'Thresh' are set to 'Below',
2176  // other pixels are set to 'Above'. ROI is considered. In place version.
2177 
2178  /*template <class T>
2179  void CImg<T>::HardThresh(const T Thresh, const T Below, const T Above)
2180  {
2181  T* pROI = m_pROI;
2182  int x, y, EndX = m_ROIEndX, EndY = m_ROIEndY, sk = m_ROISkipCols;
2183  for (y = m_ROIStartY; y < EndY; y++, pROI += sk)
2184  for (x = m_ROIStartX; x < m_ROIEndX; x++, pROI++)
2185  if (*pROI > Thresh) *pROI = Above;
2186  else *pROI = Below;
2187  }*/
2188 
2190  // Just swap the pointers with the input Img's pointers, keep all
2191  // else the same.
2192 
2193  template <class T>
2195  {
2196  T* pTmp;
2197  pTmp = m_pBuffer;
2198  m_pBuffer = InImg.m_pBuffer;
2199  InImg.m_pBuffer = pTmp;
2200  pTmp = m_pROI;
2201  m_pROI = InImg.pROI();
2202  InImg.m_pROI = pTmp;
2203  }
2204 
2206 
2207  template <class T>
2209  {
2210  SwapPointers(InImg);
2211  m_Width = InImg.m_Width;
2212  m_Height = InImg.m_Height;
2213  m_nPixels = InImg.m_nPixels;
2214  m_bDelete = InImg.m_bDelete;
2215  m_ROIStartX = InImg.m_ROIStartX;
2216  m_ROIStartY = InImg.m_ROIStartY;
2217  m_ROIEndX = InImg.m_ROIEndX;
2218  m_ROIEndY = InImg.m_ROIEndY;
2219  m_ROISkipCols = InImg.m_ROISkipCols;
2220  m_ROIWidth = InImg.m_ROIWidth;
2221  m_ROIHeight = InImg.m_ROIHeight;
2222  m_ROIOffset = InImg.m_ROIOffset;
2223  m_ROISize = InImg.m_ROISize;
2224  }
2225 
2227  // Normalize ROI of Img by L1-norm of ROI
2228  // float version only
2229 
2230  template <> inline void CImg<float>::NormalizeL1()
2231  {
2232  Div(SumAbs());
2233  }
2234 
2236  // Return the L2-norm of pixels in ROI.
2237 
2238  // BYTE version
2239  template <> inline float CImg<BYTE>::L2Norm()
2240  {
2241  BYTE* pROI = m_pROI;
2242  kjb_int32 sumofsquares = 0;
2243  for (int y = m_ROIStartY; y < m_ROIEndY;
2244  y++, pROI += m_ROISkipCols)
2245  for (int x = m_ROIStartX; x < m_ROIEndX; x++, pROI++) {
2246  const kjb_int32 Val = (kjb_int32)*pROI;
2247  sumofsquares += Val*Val;
2248  }
2249  return (float)sqrt((float)sumofsquares);
2250  }
2251 
2252  // float version
2253  template <> inline float CImg<float>::L2Norm()
2254  {
2255  float* pROI = m_pROI;
2256  float sumofsquares = 0;
2257  for (int y = m_ROIStartY; y < m_ROIEndY;
2258  y++, pROI += m_ROISkipCols)
2259  for (int x = m_ROIStartX; x < m_ROIEndX; x++, pROI++) {
2260  const float Val = *pROI;
2261  sumofsquares += Val*Val;
2262  }
2263  return (float)sqrt(sumofsquares);
2264  }
2265 
2267 
2268  template <class T>
2270  {
2271  const int StartX = m_ROIStartX, EndX = m_ROIEndX,
2272  StartY = m_ROIStartY, EndY = m_ROIEndY, sk = m_ROISkipCols;
2273  T* pBuffer = m_pBuffer;
2274  kjb_int32 nPoints = 0;
2275  for (int y = StartY; y < EndY; y++, pBuffer += sk)
2276  for (int x = StartX; x < EndX; x++, pBuffer++)
2277  if (*pBuffer != (T)0) nPoints++;
2278  return nPoints;
2279  }
2280 
2282 
2283  template <> inline void CImg<float>::Sqrt()
2284  {
2285  const int StartX = m_ROIStartX, EndX = m_ROIEndX,
2286  StartY = m_ROIStartY, EndY = m_ROIEndY, sk = m_ROISkipCols;
2287  float* pBuffer = m_pBuffer;
2288  for (int y = StartY; y < EndY; y++, pBuffer += sk)
2289  for (int x = StartX; x < EndX; x++, pBuffer++)
2290  if (*pBuffer) *pBuffer = (float)sqrt((float)*pBuffer);
2291  }
2292 
2294 
2295  // float version only
2296  template <> inline void CImg<float>::Val2Probability(const float& Sigma)
2297  {
2298  const float MinusOneOverSigma = -1.0f/Sigma;
2299  const int StartX = m_ROIStartX, EndX = m_ROIEndX,
2300  StartY = m_ROIStartY, EndY = m_ROIEndY, sk = m_ROISkipCols;
2301  float* pBuffer = m_pBuffer;
2302  for (int y = StartY; y < EndY; y++, pBuffer += sk)
2303  for (int x = StartX; x < EndX; x++, pBuffer++)
2304  if (*pBuffer)
2305  *pBuffer = 1.0f-(float)exp(*pBuffer*MinusOneOverSigma);
2306  }
2307 
2309 
2310  template <class T>
2312  {
2313  const int InStartX = Img.ROIStartX(), InStartY = Img.ROIStartY();
2314  const int InEndX = Img.ROIEndX(), InEndY = Img.ROIEndY();
2315  const int InSkip = Img.ROISkipCols();
2316 
2317  T* pOutROI = m_pROI;
2318  T* pInROI = Img.pROI();
2319  for (int y = InStartY; y < InEndY; y++, pInROI += InSkip,
2320  pOutROI += m_ROISkipCols) {
2321  for (int x = InStartX; x < InEndX; x++, pInROI++, pOutROI++) {
2322  *pOutROI = *pInROI;
2323  }
2324  }
2325  }
2326 
2328 
2329  template <class T>
2331  {
2332  Empty();
2333  }
2334 
2336 
2337  template <class T>
2338  CImgVec<T>::CImgVec(T** ppBuffers, const int nFrames, const int Width,
2339  const int Height, bool bDelete)
2340  {
2341  Attach(ppBuffers, nFrames, Width, Height, bDelete);
2342  }
2343 
2345 
2346  template <class T>
2347  CImgVec<T>::CImgVec(CImg<T>& InImg, const int& nCols, const int& nRows,
2348  const int& Padding)
2349  {
2350  m_nFrames = nRows*nCols;
2351 
2352  m_ROIWidth = m_ROIEndX = m_Width = 0;
2353  m_ROIHeight = m_ROIEndY = m_Height = 0;
2354  m_ROISize = m_FrameSize = 0;
2355  m_ROIOffset = m_ROISkipCols = m_ROIStartX = m_ROIStartY = 0;
2356  m_TotalSize = 0;
2357 
2358  const int InOrigStartX = InImg.ROIStartX();
2359  const int InOrigStartY = InImg.ROIStartY();
2360  const int InOrigEndX = InImg.ROIEndX();
2361  const int InOrigEndY = InImg.ROIEndY();
2362 
2363  const int InWidth = InImg.Width(), InHeight = InImg.Height();
2364  const int AvSubWidth = InWidth/nCols, AvSubHeight = InHeight/nRows;
2365 
2366  const int HalfAvSubWidth = AvSubWidth/2;
2367  const int HalfAvSubHeight = AvSubHeight/2;
2368 
2369  for (int row = 0; row < nRows; row++) {
2370  int InStartX, InStartY, InEndX, InEndY;
2371 
2372  InStartY = row*AvSubHeight;
2373  InEndY = (row+1)*AvSubHeight;
2374  if (InEndY > InHeight-HalfAvSubHeight) InEndY = InHeight;
2375 
2376  for (int col = 0; col < nCols; col++) {
2377  InStartX = col*AvSubWidth;
2378  InEndX = (col+1)*AvSubWidth;
2379  if (InEndX > InWidth-HalfAvSubWidth) InEndX = InWidth;
2380 
2381  if (InEndX > InWidth-HalfAvSubWidth) InEndX = InWidth;
2382  InImg.ChangeROI(InStartX, InEndX, InStartY, InEndY);
2383 
2384  // cerr << "row = " << row << "; col = " << col << endl;
2385  // InImg.Report();
2386  CImg<float>* pSubImg = new CImg<float>(InImg, Padding);
2387  // pSubImg->Report();
2388  // cerr << "-----------------------------" << endl;
2389  m_vecImgs.push_back(pSubImg);
2390  } // for (col ..
2391  } // for (row ..
2392  // restore InImg ROI
2393  InImg.ChangeROI(InOrigStartX, InOrigEndX, InOrigStartY, InOrigEndY);
2394  }
2395 
2397 
2398  template <class T>
2400  {
2401  FreeMemory();
2402  }
2403 
2405 
2406  template <class T>
2408  {
2409  m_ROIWidth = m_ROIEndX = m_Width = 0;
2410  m_ROIHeight = m_ROIEndY = m_Height = 0;
2411  m_ROISize = m_FrameSize = 0;
2412  m_ROIOffset = m_ROISkipCols = m_ROIStartX = m_ROIStartY = 0;
2413  m_TotalSize = 0;
2414  m_nFrames = 0;
2415  FreeMemory();
2416  }
2417 
2419 
2420  template <class T>
2421  void CImgVec<T>:: Attach(T** ppBuffers, const int nFrames, const int Width,
2422  const int Height, bool bDelete)
2423  {
2424  m_ROIWidth = m_ROIEndX = m_Width = Width;
2425  m_ROIHeight = m_ROIEndY = m_Height = Height;
2426  m_ROISize = m_FrameSize = Width*Height;
2427  m_ROIOffset = m_ROISkipCols = m_ROIStartX = m_ROIStartY = 0;
2428  m_TotalSize = m_FrameSize*nFrames;
2429  m_nFrames = nFrames;
2430  for (int i = 0; i < nFrames; i++)
2431  m_vecImgs.push_back(new CImg<T>(ppBuffers[i], Width, Height,
2432  bDelete));
2433  }
2434 
2436 
2437  template <class T>
2439  {
2440  if (!m_vecImgs.empty()) {
2441  for (int i = 0; i < m_nFrames; i++)
2442  zap(m_vecImgs[i]);
2443  m_vecImgs.clear();
2444  }
2445  }
2446 
2448 
2449  template <class T>
2450  bool CImgVec<T>::Allocate (const int nFrames,const int Width,
2451  const int Height, bool bZero)
2452  {
2453  m_ROIWidth = m_ROIEndX = m_Width = m_Width = Width;
2454  m_ROIHeight = m_ROIEndY = m_Height = Height;
2455  m_ROISize = m_FrameSize = Width*Height;
2456  m_ROIOffset = m_ROISkipCols = m_ROIStartX = m_ROIStartY = 0;
2457  m_TotalSize = m_FrameSize*nFrames;
2458  m_nFrames = nFrames;
2459  // m_vecImgs.reserve(nFrames);
2460  for (int i = 0; i < nFrames; i++) {
2461  CImg<T>* pImg = new CImg<T>(Width, Height, true, bZero);
2462  if (pImg == NULL) return false;
2463  m_vecImgs.push_back(pImg);
2464  }
2465  return true;
2466  }
2467 
2469 
2470  template <class T>
2472  {
2473  m_ROIStartX = Img.ROIStartX();
2474  m_ROIStartY = Img.ROIStartY();
2475  m_ROIEndX = Img.ROIEndX();
2476  m_ROIEndY = Img.ROIEndY();
2477  m_ROIWidth = Img.ROIWidth();
2478  m_ROIHeight = Img.ROIHeight();
2479  m_ROISkipCols = Img.ROISkipCols();
2480  m_ROIOffset = Img.ROIOffset();
2481  m_ROISize = Img.ROISize();
2482  }
2483 
2485 
2486  template <class T>
2487  inline void CImgVec<T>::ChangeRange(const T& NewMin, const T& NewMax)
2488  {
2489  for (int i = 0; i < m_nFrames; i++)
2490  m_vecImgs[i]->ChangeRange(NewMin, NewMax);
2491  }
2492 
2494 
2495  template <> inline void CImgVec<float>::FixThetaRanges(const bool& bHalfPhase)
2496  {
2497  for (int i = 0; i < m_nFrames; i++)
2498  m_vecImgs[i]->FixThetaRanges(bHalfPhase);
2499  }
2500 
2502 
2503  template <class T>
2505  {
2506  return (m_nFrames == 0);
2507  }
2508 
2512 
2517 
2521  typedef CImg<int>* IntCImgPtr;
2522 
2523  typedef vector<CImg<BYTE>*>::iterator ByteImgVecIter;
2524  typedef vector<CImg<kjb_int32>*>::iterator LongImgVecIter;
2525  typedef vector<CImg<float>*>::iterator FloatImgVecIter;
2526  typedef vector<CImg<int>*>::iterator IntImgVecIter;
2527 
2528 } // namespace DTLib {
2529 
2530 #endif /* #ifndef _IMG_H */
#define zap(x)
Definition: utils.h:137
int m_ROIEndY
Definition: img.h:490
int m_nFrames
Definition: img.h:568
int m_ROIWidth
Definition: img.h:493
int nPixels() const
Definition: img.h:141
int m_ROISkipCols
Definition: img.h:581
float Max(float *pBuf, int Size)
Definition: utils.cpp:90
int m_Width
Definition: img.h:480
int m_ROIHeight
Definition: img.h:580
int m_ROIStartY
Definition: img.h:488
int Height()
Definition: img.h:533
void report_int(const std::string &msg, int value)
Definition: img.cpp:27
void FixThetaRange(float &Theta, const bool &bHalfPhase=true)
Definition: utils.cpp:261
void MinMax(T &Min, T &Max)
Definition: img.h:1469
vector< CImg< kjb_int32 > * >::iterator LongImgVecIter
Definition: img.h:2524
int ROIWidth()
Definition: img.h:169
int ROIEndX()
Definition: img.h:163
int m_Height
Definition: img.h:567
void ChangeROI(const int StartX, const int EndX, const int StartY, const int EndY)
Definition: img.h:1006
void CopyFromBuf(T *pBuf)
Definition: img.h:1218
int m_FrameSize
Definition: img.h:569
CImgVec< float > * FloatCImgVecPtr
Definition: img.h:2520
int m_ROIStartX
Definition: img.h:487
int ROIEndY()
Definition: img.h:165
CImg< float > * FloatCImgPtr
Definition: img.h:2515
int m_Width
Definition: img.h:566
int ROIStartY()
Definition: img.h:164
int m_TotalSize
Definition: img.h:570
Value_type mean(Iterator begin, Iterator end, const Value_type &)
Definition: prob_stat.h:56
Definition: img.h:51
int m_ROIEndY
Definition: img.h:578
int FrameSize()
Definition: img.h:536
int Width() const
Definition: img.h:135
bool IsNotEmpty()
Definition: img.h:191
vector< CImg< BYTE > * >::iterator ByteImgVecIter
Definition: img.h:2523
void CopyToBuf(T *pBuf)
Definition: img.h:1252
int ROISkipCols()
Definition: img.h:166
vector< CImg< int > * >::iterator IntImgVecIter
Definition: img.h:2526
int m_ROISize
Definition: img.h:583
void SetOutROIVal(const T &Val)
Definition: img.h:1084
int Width()
Definition: img.h:532
int ROISize()
Definition: img.h:179
int m_ROIWidth
Definition: img.h:579
int m_ROISkipCols
Definition: img.h:491
#define Square(a, x, y)
Definition: triangle.c:4036
x
Definition: APPgetLargeConnectedEdges.m:100
#define CONST_MIN_FLOAT
Definition: utils.h:20
CImgVec< BYTE > * ByteCImgVecPtr
Definition: img.h:2518
#define BYTE
Definition: utils.h:96
void Normalize(bool full_range=false)
int TotalSize()
Definition: img.h:537
T * m_pROI
Definition: img.h:486
int m_ROIStartY
Definition: img.h:576
Definition: img.h:42
int ROIOffset()
Definition: img.h:176
count
Definition: APPgetLargeConnectedEdges.m:71
CImg< int > * IntCImgPtr
Definition: img.h:2516
sum(zmx.*zmy) sum(zmy.^2)]
x2
Definition: APPgetLargeConnectedEdges.m:123
int m_Height
Definition: img.h:481
int m_ROIStartX
Definition: img.h:575
bool bDelete()
Definition: img.h:145
int Height() const
Definition: img.h:138
int m_nPixels
Definition: img.h:482
int m_ROIHeight
Definition: img.h:494
CImgVec< kjb_int32 > * LongCImgVecPtr
Definition: img.h:2519
int ROIStartX()
Definition: img.h:162
T * m_pBuffer
Definition: img.h:479
CImg< kjb_int32 > * LongCImgPtr
Definition: img.h:2514
bool m_bDelete
Definition: img.h:483
int m_ROISize
Definition: img.h:496
get the indices of edges in each direction for i
Definition: APPgetLargeConnectedEdges.m:48
#define SQR(x)
Definition: utils.h:99
for m
Definition: APPgetLargeConnectedEdges.m:64
CImg< BYTE > * ByteCImgPtr
TYPES.
Definition: img.h:2513
int ROIHeight()
Definition: img.h:172
vector< CImg< float > * >::iterator FloatImgVecIter
Definition: img.h:2525
vector< CImg< T > * >::iterator itImgs()
Definition: img.h:541
int m_ROIEndX
Definition: img.h:577
int m_ROIEndX
Definition: img.h:489
int m_ROIOffset
Definition: img.h:495
float Min(float *pBuf, int Size)
Definition: utils.cpp:107
#define CONST_MAX_FLOAT
Definition: utils.h:17
T * pBuffer()
Definition: img.h:148
bool IsEmpty()
Definition: img.h:190
T * pROI()
Definition: img.h:151
int nFrames()
Definition: img.h:534
int m_ROIOffset
Definition: img.h:582
CImg< T > * GetImg(const int &i)
Definition: img.h:539
T * pBuffer(const int &i)
Definition: img.h:540
vector< CImg< T > * > m_vecImgs
Definition: img.h:572