KSquare Utilities
Raster.cpp
Go to the documentation of this file.
1 /* Raster.cpp -- Class for one raster image.
2  * Copyright (C) 1994-2014 Kurt Kramer
3  * For conditions of distribution and use, see copyright notice in KKB.h
4  */
5 #include "FirstIncludes.h"
6 
7 #include <memory>
8 #include <math.h>
9 #include <limits.h>
10 #include <fstream>
11 #include <map>
12 #include <string.h>
13 #include <string>
14 #include <iostream>
15 #include <vector>
16 
17 #include "MemoryDebug.h"
18 
19 using namespace std;
20 
21 #if defined(FFTW_AVAILABLE)
22 # include <fftw3.h>
23 //#else
24 //# include "kku_fftw.h"
25 #endif
26 # include "kku_fftw.h"
27 
28 #include "Raster.h"
29 
30 #include "KKBaseTypes.h"
31 #include "Blob.h"
32 #include "BMPImage.h"
33 #include "Compressor.h"
34 #include "ConvexHull.h"
35 #include "EigenVector.h"
36 #include "GoalKeeper.h"
37 #include "Histogram.h"
38 #include "ImageIO.h"
39 #include "KKException.h"
40 #include "kku_fftw.h"
41 #include "Matrix.h"
42 #include "MorphOpBinarize.h"
43 #include "MorphOpDilation.h"
44 #include "MorphOpErosion.h"
45 #include "MorphOpStretcher.h"
46 #include "OSservices.h"
47 #include "SimpleCompressor.h"
48 #include "MorphOpSobel.h"
49 using namespace KKB;
50 
51 
52 volatile GoalKeeperPtr Raster::goalKeeper = NULL;
53 volatile bool Raster::rasterInitialized = false;
54 
55 
57 {
58  switch (c) {
59  case ColorChannels::Red: return "Red";
60  case ColorChannels::Green: return "Green";
61  case ColorChannels::Blue: return "Blue";
62  default:
63  return "";
64  }
65 }
66 
67 
69 {
70  char c = tolower(s.FirstChar());
71  if (c == 'r') return ColorChannels::Red;
72  if (c == 'g') return ColorChannels::Green;
73  if (c == 'b') return ColorChannels::Blue;
74  return ColorChannels::Green;
75 }
76 
77 
78 
80 {
82 
84  if (!rasterInitialized)
85  {
86  rasterInitialized = true;
87  atexit (Raster::FinalCleanUp);
88  }
90 }
91 
92 
94 {
96  goalKeeper = NULL;
97 }
98 
99 
100 
101 
102 /**
103  * @brief Supports the tracking down of memory leaks in Raster; it will be called every time a new instance of a 'Raster' object is created.
104  */
107 {
108  /*
109  if (!rasterInitialized)
110  Initialize ();
111 
112  goalKeeper->StartBlock ();
113 
114  map<RasterPtr, RasterPtr>::iterator idx;
115  idx = allocatedRasterInstances.find (r);
116  if (idx != allocatedRasterInstances.end ())
117  {
118  cerr << std::endl << "Raster::AddRasterInstance ***ERROR*** Raster Instance[" << r << "] Already in list." << std::endl << std::endl;
119  }
120  else
121  {
122  allocatedRasterInstances.insert (pair<RasterPtr, RasterPtr> (r, r));
123  }
124  goalKeeper->EndBlock ();
125  */
126 }
127 
128 
130 {
131  /*
132  if (!rasterInitialized)
133  Initialize ();
134 
135  goalKeeper->StartBlock ();
136 
137  map<RasterPtr, RasterPtr>::iterator idx;
138  idx = allocatedRasterInstances.find (r);
139  if (idx == allocatedRasterInstances.end ())
140  {
141  cerr << std::endl << "Raster::RemoveRasterInstance ***ERROR*** Raster Instance[" << r << "] Not Found." << std::endl << std::endl;
142  }
143  else
144  {
145  allocatedRasterInstances.erase (idx);
146  }
147  goalKeeper->EndBlock ();
148  */
149 } /* RemoveRasterInstance */
150 
151 
152 
154 {
155  map<RasterPtr, RasterPtr>::iterator idx;
156  for (idx = allocatedRasterInstances.begin (); idx != allocatedRasterInstances.end (); ++idx)
157  {
158  RasterPtr r = idx->first;
159  cout << r << "\t"
160  << r->Height () << "\t"
161  << r->Width () << "\t"
162  << r->FileName ()
163  << std::endl;
164  }
165 } /* PrintOutListOfAllocatedrasterInstances */
166 
167 
168 
169 
170 //typedef enum
171 //{
172 // Cross,
173 // Square
174 //} MaskShapes;
175 
176 
177 //kkint32 biases[] = {1, // CROSS3
178 // 2, // CROSS5
179 // 1, // SQUARE3
180 // 2, // SQUARE5
181 // 3, // SQUARE7
182 // 4, // SQUARE9
183 // 5 // SQUARE11
184 // };
185 
186 
187 //kkint32 maskShapes[] = {Cross, // CROSS3
188 // Cross, // CROSS5
189 // Square, // SQUARE3
190 // Square, // SQUARE5
191 // Square, // SQUARE7
192 // Square, // SQUARE9
193 // Square // SQUARE11
194 // };
195 
196 
197 
198 //****************************************************************************************
199 //* Used to help quickly calculate a Intensity Histogram of a image. The image has 8 *
200 //* levels of gray scale, from 0 -> 7. *
201 //****************************************************************************************
202 // 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3
203 // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
205  {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0 - 31
206  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 31 - 63
207  2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // 64 - 95
208  3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // 96 - 127
209  4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, // 128 - 159
210  5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, // 160 - 191
211  6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, // 192 - 223
212  7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7 // 224 - 255
213  };
214 
216  {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0 - 31
217  2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // 31 - 63
218  4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, // 64 - 95
219  6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // 96 - 127
220  8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, // 128 - 159
221  10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, // 160 - 191
222  12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, // 192 - 223
223  14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15 // 224 - 255
224  };
225 
226 
227 
228 inline
230 {
231  if (x1 < x2)
232  return x1;
233  else
234  return x2;
235 }
236 
237 
238 
239 inline
241  kkint32 x4, kkint32 x5, kkint32 x6
242  )
243 {
244  kkint32 r;
245 
246  if (x1 > x2)
247  r = x1;
248  else
249  r = x2;
250 
251  if (x3 > r) r = x3;
252  if (x4 > r) r = x4;
253  if (x5 > r) r = x5;
254  if (x6 > r) r = x6;
255 
256  return r;
257 } /* Max6 */
258 
259 
260 
261 inline
263  kkint32 x4, kkint32 x5, kkint32 x6,
264  kkint32 x7, kkint32 x8, kkint32 x9
265  )
266 {
267  kkint32 r;
268 
269  if (x1 > x2)
270  r = x1;
271  else
272  r = x2;
273 
274  if (x3 > r) r = x3;
275  if (x4 > r) r = x4;
276  if (x5 > r) r = x5;
277  if (x6 > r) r = x6;
278  if (x7 > r) r = x7;
279  if (x8 > r) r = x8;
280  if (x9 > r) r = x9;
281 
282  return r;
283 } /* Max9 */
284 
285 
286 
289  backgroundPixelTH (31),
290  blobIds (NULL),
291  centroidCol (0.0f),
292  centroidRow (0.0f),
293  color (false),
294  fileName (),
296  foregroundPixelValue (255),
297  fourierMag (NULL),
298  fourierMagArea (NULL),
299  height (0),
300  maxPixVal (0),
301  title (),
302  totPixels (0),
303  weOwnRasterData (true),
304  width (0),
305 
306  redArea (NULL),
307  greenArea (NULL),
308  blueArea (NULL),
309 
310  red (NULL),
311  green (NULL),
312  blue (NULL)
313 {
314 }
315 
316 
317 
319  kkint32 _width
320  ):
321 
323  backgroundPixelTH (31),
324  blobIds (NULL),
325  centroidCol (0.0f),
326  centroidRow (0.0f),
327  color (false),
328  divisor (1),
329  fileName (),
331  foregroundPixelValue (255),
332  fourierMag (NULL),
333  fourierMagArea (NULL),
334  height (_height),
335  maxPixVal (0),
336  title (),
337  totPixels (_height * _width),
338  weOwnRasterData (true),
339  width (_width),
340 
341  redArea (NULL),
342  greenArea (NULL),
343  blueArea (NULL),
344 
345  red (NULL),
346  green (NULL),
347  blue (NULL)
348 
349 {
350  AddRasterInstance (this);
351  AllocateImageArea ();
352 }
353 
354 
355 
357  kkint32 _width,
358  bool _color
359  ):
360 
362  backgroundPixelTH (31),
363  blobIds (NULL),
364  centroidCol (0.0f),
365  centroidRow (0.0f),
366  color (_color),
367  divisor (1),
368  fileName (),
370  foregroundPixelValue (255),
371  fourierMag (NULL),
372  fourierMagArea (NULL),
373  height (_height),
374  maxPixVal (0),
375  title (),
376  totPixels (_height * _width),
377  weOwnRasterData (true),
378  width (_width),
379 
380  redArea (NULL),
381  greenArea (NULL),
382  blueArea (NULL),
383 
384  red (NULL),
385  green (NULL),
386  blue (NULL)
387 
388 {
389  AddRasterInstance (this);
390  if (color)
391  {
392  backgroundPixelValue = 255;
394  backgroundPixelTH = 255 - 31;
395  }
396 
397  AllocateImageArea ();
398 }
399 
400 
401 /**
402  *@brief Constructs a Raster from a BMP image loaded from disk.
403  *@details If BMP Image is a gray-scale value pixel values will be reversed. See description of gray-scale constructor.
404  */
405 Raster::Raster (const BmpImage& _bmpImage):
406 
408  backgroundPixelTH (31),
409  blobIds (NULL),
410  centroidCol (0.0f),
411  centroidRow (0.0f),
412  color (false),
413  divisor (1),
414  fileName (_bmpImage.FileName ()),
416  foregroundPixelValue (255),
417  fourierMag (NULL),
418  fourierMagArea (NULL),
419  height (_bmpImage.Height ()),
420  maxPixVal (0),
421  title (),
422  totPixels (_bmpImage.Height () * _bmpImage.Width ()),
423  weOwnRasterData (true),
424  width (_bmpImage.Width ()),
425 
426  redArea (NULL),
427  greenArea (NULL),
428  blueArea (NULL),
429 
430  red (NULL),
431  green (NULL),
432  blue (NULL)
433 
434 {
435  AddRasterInstance (this);
436  color = _bmpImage.Color ();
437  AllocateImageArea ();
438 
439  kkint32 row;
440 
441  for (row = 0; row < height; row++)
442  {
443  const uchar* imageRow = _bmpImage.ImageRow (row);
444  memcpy (green[row], imageRow, width);
445  if (color)
446  {
447  const uchar* blueRow = _bmpImage.BlueRow (row);
448  memcpy (blue[row], blueRow, width);
449 
450  const uchar* redRow = _bmpImage.RedRow (row);
451  memcpy (red[row], redRow, width);
452  }
453  }
454 }
455 
456 
457 
458 
459 
460 Raster::Raster (const Raster& _raster):
461 
464  blobIds (NULL),
465  centroidCol (_raster.centroidCol),
466  centroidRow (_raster.centroidRow),
467  color (_raster.color),
468  divisor (1),
469  fileName (_raster.fileName),
472  fourierMag (NULL),
473  fourierMagArea (NULL),
474  height (_raster.height),
475  maxPixVal (_raster.maxPixVal),
476  title (),
477  totPixels (_raster.totPixels),
478  weOwnRasterData (true),
479  width (_raster.width),
480 
481  redArea (NULL),
482  greenArea (NULL),
483  blueArea (NULL),
484 
485  red (NULL),
486  green (NULL),
487  blue (NULL)
488 
489 {
490  AddRasterInstance (this);
491 
492  AllocateImageArea ();
493  if (!greenArea) throw KKException ("Raster::Raster Failed to allocate 'greenArea'.");
494  memcpy (greenArea, _raster.greenArea, totPixels);
495 
496  if (color)
497  {
498  if (!redArea) throw KKException("Raster::Raster Allocation of 'redArea' failed.");
499  if (!blueArea) throw KKException("Raster::Raster Allocation of 'blueArea' failed.");
500  memcpy (redArea, _raster.redArea, totPixels);
501  memcpy (blueArea, _raster.blueArea, totPixels);
502  }
503 
504  if (_raster.fourierMagArea)
505  {
506  AllocateFourierMagnitudeTable ();
507  if (!fourierMagArea) throw KKException ("Raster::Raster Allocation of 'fourierMagArea' failed.");
508  memcpy (fourierMagArea, _raster.fourierMagArea, sizeof (float) * totPixels);
509  }
510 }
511 
512 
513 
514 Raster::Raster (const Raster& _raster,
515  kkint32 _row,
516  kkint32 _col,
517  kkint32 _height,
518  kkint32 _width
519  ):
520 
523  blobIds (NULL),
524  centroidCol (-1.0f),
525  centroidRow (-1.0f),
526  color (_raster.color),
527  divisor (1),
528  fileName (),
531  fourierMag (NULL),
532  fourierMagArea (NULL),
533  height (_height),
534  maxPixVal (0),
535  title (),
536  totPixels (_height * _width),
537  weOwnRasterData (true),
538  width (_width),
539 
540  redArea (NULL),
541  greenArea (NULL),
542  blueArea (NULL),
543 
544  red (NULL),
545  green (NULL),
546  blue (NULL)
547 
548 {
549  AddRasterInstance (this);
550 
551  green = _raster.GetSubSet (_raster.green, _row, _col, _height, _width);
552  greenArea = green[0];
553 
554  if (color)
555  {
556  red = _raster.GetSubSet (_raster.red, _row, _col, _height, _width);
557  redArea = red[0];
558 
559  blue = _raster.GetSubSet (_raster.blue, _row, _col, _height, _width);
560  blueArea = blue[0];
561  }
562 }
563 
564 
565 
566 Raster::Raster (const Raster& _raster,
567  MaskTypes _mask,
568  kkint32 _row,
569  kkint32 _col
570  ):
571 
574  blobIds (NULL),
575  centroidCol (-1),
576  centroidRow (-1),
577  color (false),
578  divisor (1),
579  fileName (),
582  fourierMag (NULL),
583  fourierMagArea (NULL),
584  height (MorphOp::Biases (_mask) * 2 + 1),
585  maxPixVal (0),
586  title (),
587  totPixels (0),
588  weOwnRasterData (true),
589  width (MorphOp::Biases (_mask) * 2 + 1),
590 
591  redArea (NULL),
592  greenArea (NULL),
593  blueArea (NULL),
594 
595  red (NULL),
596  green (NULL),
597  blue (NULL)
598 
599 {
600  AddRasterInstance (this);
601 
602  totPixels = height * width;
603 
604  kkint32 r = _row - MorphOp::Biases (_mask);
605  kkint32 c = _col - MorphOp::Biases (_mask);
606 
607  green = _raster.GetSubSet (_raster.green, r, c, height, width);
608  greenArea = green[0];
609  if (color)
610  {
611  red = _raster.GetSubSet (_raster.red, r, c, height, width);
612  redArea = red[0];
613 
614  blue = _raster.GetSubSet (_raster.blue, r, c, height, width);
615  blueArea = blue[0];
616  }
617 }
618 
619 
620 
621 
622 Raster::Raster (const KKStr& _fileName,
623  bool& validFile
624  ):
625 
627  backgroundPixelTH (31),
628  blobIds (NULL),
629  centroidCol (-1),
630  centroidRow (-1),
631  color (false),
632  divisor (1),
633  fileName (_fileName),
635  foregroundPixelValue (255),
636  fourierMag (NULL),
637  fourierMagArea (NULL),
638  height (0),
639  maxPixVal (0),
640  title (),
641  totPixels (0),
642  weOwnRasterData (true),
643  width (0),
644 
645  redArea (NULL),
646  greenArea (NULL),
647  blueArea (NULL),
648 
649  red (NULL),
650  green (NULL),
651  blue (NULL)
652 
653 {
654  AddRasterInstance (this);
655 
656  validFile = true;
657 
659 
660  if (!r)
661  {
662  validFile = false;
663  delete r;
664  r = NULL;
665  return;
666  }
667 
668  red = r->Red ();
669  green = r->Green ();
670  blue = r->Blue ();
671  height = r->Height ();
672  width = r->Width ();
673  redArea = r->redArea;
675  blueArea = r->blueArea;
678  color = r->color;
680 
681  r->weOwnRasterData = false;
682  weOwnRasterData = true;
683  delete r;
684 }
685 
686 
687 
688 
690  kkint32 _width,
691  uchar* _grayScaleData,
692  uchar** _grayScaleRows
693  ):
695  backgroundPixelTH (31),
696  blobIds (NULL),
697  centroidCol (0.0f),
698  centroidRow (0.0f),
699  color (false),
700  divisor (1),
701  fileName (),
703  foregroundPixelValue (255),
704  fourierMag (NULL),
705  fourierMagArea (NULL),
706  height (_height),
707  maxPixVal (0),
708  title (),
709  totPixels (_height * _width),
710  weOwnRasterData (false),
711  width (_width),
712 
713  redArea (NULL),
714  greenArea (_grayScaleData),
715  blueArea (NULL),
716 
717  red (NULL),
718  green (_grayScaleRows),
719  blue (NULL)
720 
721 {
722  AddRasterInstance (this);
723 }
724 
725 
726 
728  kkint32 _width,
729  const uchar* _grayScaleData
730  ):
732  backgroundPixelTH (31),
733  blobIds (NULL),
734  centroidCol (0.0f),
735  centroidRow (0.0f),
736  color (false),
737  divisor (1),
738  fileName (),
740  foregroundPixelValue (255),
741  fourierMag (NULL),
742  fourierMagArea (NULL),
743  height (_height),
744  maxPixVal (0),
745  title (),
746  totPixels (_height * _width),
747  weOwnRasterData (true),
748  width (_width),
749 
750  redArea (NULL),
751  greenArea (NULL),
752  blueArea (NULL),
753 
754  red (NULL),
755  green (NULL),
756  blue (NULL)
757 
758 {
759  AddRasterInstance (this);
760  AllocateImageArea ();
761  if (!greenArea) throw KKException ("Raster::Raster Failed to allocate 'greenArea'.");
762  memcpy (greenArea, _grayScaleData, totPixels);
763 }
764 
765 
767  kkint32 _width,
768  const uchar* _redChannel,
769  const uchar* _greenChannel,
770  const uchar* _blueChannel
771  ):
773  backgroundPixelTH (31),
774  blobIds (NULL),
775  centroidCol (0.0f),
776  centroidRow (0.0f),
777  color (true),
778  divisor (1),
779  fileName (),
781  foregroundPixelValue (255),
782  fourierMag (NULL),
783  fourierMagArea (NULL),
784  height (_height),
785  maxPixVal (0),
786  title (),
787  totPixels (_height * _width),
788  weOwnRasterData (true),
789  width (_width),
790 
791  redArea (NULL),
792  greenArea (NULL),
793  blueArea (NULL),
794 
795  red (NULL),
796  green (NULL),
797  blue (NULL)
798 
799 {
800  AddRasterInstance (this);
801  AllocateImageArea ();
802  if ((!_redChannel) || (!_greenChannel) || (!_blueChannel))
803  {
804  KKB::KKStr errMsg;
805  errMsg << "Raster::Raster ***ERROR*** One of the provided channels is 'NULL'.";
806  cerr << std::endl << std::endl << errMsg << std::endl << std::endl;
807  throw KKException (errMsg);
808  }
809 
810  if ((!redArea) || (!greenArea) || (!blueArea))
811  {
812  KKB::KKStr errMsg;
813  errMsg << "Raster::Raster ***ERROR*** Not all channels were allocated.";
814  cerr << std::endl << std::endl << errMsg << std::endl << std::endl;
815  throw KKException(errMsg);
816  }
817 
818  memcpy (redArea, _redChannel, totPixels);
819  memcpy (greenArea, _greenChannel, totPixels);
820  memcpy (blueArea, _blueChannel, totPixels);
821 }
822 
823 
824 
825 
827 {
829  CleanUpMemory ();
830 }
831 
832 
833 
834 void Raster::CleanUpMemory ()
835 {
836  if (weOwnRasterData)
837  {
838  delete green;
839  delete greenArea;
840  delete red;
841  delete redArea;
842  delete blue;
843  delete blueArea;
844  }
845 
846  green = NULL;
847  greenArea = NULL;
848  red = NULL;
849  redArea = NULL;
850  blue = NULL;
851  blueArea = NULL;
852 
853  if (fourierMagArea)
854  {
855  delete fourierMagArea; fourierMagArea = NULL;
856  delete fourierMag; fourierMag = NULL;
857  }
858 
859  DeleteExistingBlobIds ();
860 }
861 
862 
863 
865 {
866  kkint32 blobIdsMem = 0;
867  if (blobIds)
868  blobIdsMem = sizeof(kkint32) * totPixels + sizeof (kkint32*) * height;
869 
870  kkint32 fourierMem = 0;
871  if (fourierMagArea)
872  fourierMem = sizeof (float) * totPixels + sizeof (float*) * height;
873 
874  kkint32 pixelMem = totPixels + sizeof (uchar*) * height;
875  if (color)
876  pixelMem = pixelMem * 3;
877 
878  kkint32 memoryConsumedEstimated =
879  sizeof (uchar) * 4 +
880  sizeof (float) * 2 +
881  sizeof (bool) * 2 +
882  sizeof (kkint32) * 4 +
883  sizeof (kkint32**) * 1 +
884  sizeof (uchar*) * 3 +
885  sizeof (uchar**) * 3 +
886  sizeof (float*) * 1 +
887  sizeof (float**) * 1 +
889  blobIdsMem +
890  fourierMem +
891  pixelMem;
892 
893  return memoryConsumedEstimated;
894 }
895 
896 
897 
898 void Raster::ReSize (kkint32 _height,
899  kkint32 _width,
900  bool _color
901  )
902 {
903  CleanUpMemory ();
904  height = _height;
905  width = _width;
906  color = _color;
907  AllocateImageArea ();
908 }
909 
910 
911 
912 
913 
914 
915 
916 
917 void Raster::Initialize (kkint32 _height,
918  kkint32 _width,
919  uchar* _grayScaleData,
920  uchar** _grayScaleRows,
921  bool _takeOwnership
922  )
923 {
924  CleanUpMemory ();
925  height = _height;
926  width = _width;
927  totPixels = height * width;
928  color = false;
929 
930  if (_grayScaleData == NULL)
931  throw KKException ("Raster::Initialize _grayScaleData == NULL");
932 
933  if (_grayScaleRows == NULL)
934  throw KKException ("Raster::Initialize _grayScaleRows == NULL");
935 
936  greenArea = _grayScaleData;
937  green = _grayScaleRows;
938 
939  weOwnRasterData = _takeOwnership;
940 }
941 
942 
943 
944 void Raster::Initialize (kkint32 _height,
945  kkint32 _width,
946  uchar* _redArea,
947  uchar** _red,
948  uchar* _greenArea,
949  uchar** _green,
950  uchar* _blueArea,
951  uchar** _blue,
952  bool _takeOwnership
953  )
954 {
955  CleanUpMemory ();
956  height = _height;
957  width = _width;
958  color = true;
959 
960  totPixels = height * width;
961 
962  if ((_red == NULL) || (_redArea == NULL) ||
963  (_green == NULL) || (_greenArea == NULL) ||
964  (_blue == NULL) || (_blueArea == NULL)
965  )
966  throw KKException ("Raster::Initialize One or more of the Color channels == NULL");
967 
968  redArea = _redArea; red = _red;
969  greenArea = _greenArea; green = _green;
970  blueArea = _blueArea; blue = _blue;
971 
972  weOwnRasterData = _takeOwnership;
973 }
974 
975 
976 
977 
979 {
980  CleanUpMemory ();
983  blobIds = otherRaster.blobIds;
984  centroidCol = otherRaster.centroidCol;
985  centroidRow = otherRaster.centroidRow;
986  color = otherRaster.color;
987  divisor = otherRaster.divisor;
988  fileName = otherRaster.fileName;
991  fourierMag = otherRaster.fourierMag;
992  fourierMagArea = otherRaster.fourierMagArea;
993  height = otherRaster.height;
994  maxPixVal = otherRaster.maxPixVal;
995  title = otherRaster.title;
996  totPixels = otherRaster.totPixels;
997  weOwnRasterData = otherRaster.weOwnRasterData;
998  width = otherRaster.width;
999  redArea = otherRaster.redArea;
1000  greenArea = otherRaster.greenArea;
1001  blueArea = otherRaster.blueArea;
1002  red = otherRaster.red;
1003  green = otherRaster.green;
1004  blue = otherRaster.blue;
1005  otherRaster.weOwnRasterData = false;
1006  otherRaster.fourierMagArea = NULL;
1007  otherRaster.fourierMag = NULL;
1008  otherRaster.blobIds = NULL;
1009 } /* TakeOwnershipOfAnotherRastersData */
1010 
1011 
1012 
1013 
1015  kkint32 width,
1016  bool color
1017  ) const
1018 {
1019  return new Raster (height, width, color);
1020 }
1021 
1022 
1023 
1024 RasterPtr Raster::AllocateARasterInstance (const Raster& r) const
1025 {
1026  return new Raster (r);
1027 }
1028 
1029 
1030 
1031 RasterPtr Raster::AllocateARasterInstance (const Raster& _raster, /**< Source Raster */
1032  kkint32 _row, /**< Starting Row in '_raster' to copy from. */
1033  kkint32 _col, /**< Starting Col in '_raster' to copy from. */
1034  kkint32 _height, /**< Height of resultant raster. Will start from '_row' */
1035  kkint32 _width /**< Width of resultant raster. */
1036  ) const
1037 {
1038  return new Raster (_raster, _row, _col, _height, _width);
1039 }
1040 
1041 
1042 
1043 
1044 bool Raster::ForegroundPixel (uchar pixel) const
1045 {
1046  if (backgroundPixelValue < 125)
1047  return (pixel > backgroundPixelTH);
1048  else
1049  return (pixel < backgroundPixelTH);
1050 } /* ForegroundPixel */
1051 
1052 
1053 
1055  kkint32 col
1056  ) const
1057 {
1058  return (ForegroundPixel (green[row][col]));
1059 } /* ForegroundPixel */
1060 
1061 
1062 
1063 bool Raster::BackgroundPixel (uchar pixel) const
1064 {
1065  if (backgroundPixelValue < 125)
1066  return (pixel <= backgroundPixelTH);
1067  else
1068  return (pixel >= backgroundPixelTH);
1069 } /* ForegroundPixel */
1070 
1071 
1072 
1073 
1075  kkint32 col
1076  ) const
1077 {
1078  if (backgroundPixelValue < 125)
1079  return (green[row][col] <= backgroundPixelTH);
1080  else
1081  return (green[row][col] >= backgroundPixelTH);
1082 } /* ForegroundPixel */
1083 
1084 
1085 
1087 {
1088  kkint32 totalBackgroundPixels = 0;
1089  for (kkint32 x = 0; x < totPixels; ++x)
1090  {
1091  if (greenArea[x] > backgroundPixelTH)
1092  ++totalBackgroundPixels;
1093  }
1094  return totalBackgroundPixels;
1095 } /* TotalBackgroundPixels */
1096 
1097 
1098 
1099 
1100 float Raster::CentroidCol () const
1101 {
1102  if (centroidCol >= 0)
1103  return centroidCol;
1104 
1105  float centroidColWeighted;
1106  float centroidRowWeighted;
1107 
1108  kkint32 weight = 0;
1109  CalcCentroid (totPixels, weight, centroidRow, centroidCol, centroidRowWeighted, centroidColWeighted);
1110 
1111  return centroidCol;
1112 }
1113 
1114 
1115 
1116 float Raster::CentroidRow () const
1117 {
1118  if (centroidRow >= 0)
1119  return centroidRow;
1120 
1121  float centroidColWeighted;
1122  float centroidRowWeighted;
1123  kkint32 weight = 0;
1124  CalcCentroid (totPixels, weight, centroidRow, centroidCol, centroidRowWeighted, centroidColWeighted);
1125  return centroidRow;
1126 }
1127 
1128 
1129 
1130 
1132  kkint32 padding
1133  )
1134 {
1135  kkint32 oldWidth = image.Width ();
1136  kkint32 oldHeight = image.Height ();
1137 
1138  kkint32 newWidth = oldWidth + 2 * padding;
1139  kkint32 newHeight = oldHeight + 2 * padding;
1140 
1141  RasterPtr paddedRaster = new Raster (newHeight, newWidth, false);
1142 
1143  //const uchar** oldRows = image.Image ();
1144 
1145  uchar** newRows = paddedRaster->green;
1146 
1147  kkint32 newRow = padding;
1148  kkint32 row;
1149  kkint32 col;
1150 
1151  kkint32 paddedForgroudPixelCount = 0;
1152 
1153  for (row = 0; row < oldHeight; row++)
1154  {
1155  const uchar* oldRow = image.ImageRow (row);
1156 
1157  kkint32 newCol = padding;
1158  for (col = 0; col < oldWidth; col++)
1159  {
1160  if (oldRow[col] > 0)
1161  paddedForgroudPixelCount++;
1162 
1163  newRows[newRow][newCol] = oldRow[col];
1164  newCol++;
1165  }
1166 
1167  newRow++;
1168  }
1169 
1170  paddedRaster->foregroundPixelCount = paddedForgroudPixelCount;
1171 
1172  return paddedRaster;
1173 } /* CreatePaddedRaster */
1174 
1175 
1176 
1177 RasterPtr Raster::ReversedImage ()
1178 {
1179  RasterPtr result = AllocateARasterInstance (*this);
1180  result->ReverseImage ();
1181  return result;
1182 } /* ReversedImage */
1183 
1184 
1185 
1186 
1187 RasterPtr Raster::StreatchImage (float rowFactor,
1188  float colFactor
1189  ) const
1190 {
1191  MorphOpStretcher streatcher (rowFactor, colFactor);
1192  return streatcher.PerformOperation (this);
1193 }
1194 
1195 
1196 
1197 
1199 {
1200  kkint32 x = 0;
1201 
1202  for (x = 0; x < totPixels; x++)
1203  {
1204  greenArea[x] = 255 - greenArea[x];
1205  if (color)
1206  {
1207  redArea[x] = 255 - redArea[x];
1208  blueArea[x] = 255 - blueArea[x];
1209  }
1210  }
1211 
1212  uchar temp = backgroundPixelValue;
1214  foregroundPixelValue = temp;
1216 } /* ReversedImage */
1217 
1218 
1219 void Raster::AllocateImageArea ()
1220 {
1221  CleanUpMemory ();
1222 
1223  totPixels = height * width;
1224  greenArea = new uchar [totPixels];
1225  if (!greenArea)
1226  {
1227  cerr << std::endl << std::endl
1228  << "Raster::AllocateImageArea ***ERROR*** Error allocating memory" << std::endl
1229  << std::endl;
1230  osDisplayWarning ("Raster::AllocateImageArea ***ERROR*** Error allocating memory");
1231 
1232  greenArea = NULL;
1233  return;
1234  }
1235 
1236  memset (greenArea, backgroundPixelValue, totPixels);
1237  green = new uchar*[height];
1238 
1239  if (color)
1240  {
1241  redArea = new uchar [totPixels];
1242  memset (redArea, backgroundPixelValue, totPixels);
1243 
1244  blueArea = new uchar [totPixels];
1245  memset (blueArea, backgroundPixelValue, totPixels);
1246 
1247  red = new uchar*[height];
1248  blue = new uchar*[height];
1249  }
1250 
1251  kkint32 row;
1252  uchar* greenPtr = greenArea;
1253  uchar* redPtr = redArea;
1254  uchar* bluePtr = blueArea;
1255 
1256  for (row = 0; row < height; row++)
1257  {
1258  green[row] = greenPtr;
1259  greenPtr = greenPtr + width;
1260 
1261  if (color)
1262  {
1263  red[row] = redPtr;
1264  redPtr = redPtr + width;
1265 
1266  blue[row] = bluePtr;
1267  bluePtr = bluePtr + width;
1268  }
1269  }
1270 } /* AllocateImageArea */
1271 
1272 
1273 void Raster::AllocateFourierMagnitudeTable ()
1274 {
1275  fourierMagArea = new float[totPixels];
1276  fourierMag = new float*[height];
1277 
1278  float* rowPtr = fourierMagArea;
1279 
1280  for (kkint32 row = 0; row < height; row++)
1281  {
1282  fourierMag[row] = rowPtr;
1283  rowPtr = rowPtr + width;
1284  }
1285 } /* AllocateFourierMagnitudeTable */
1286 
1287 
1288 
1290 
1291 {
1292  if ((row < 0) ||
1293  (row >= height) ||
1294  (col < 0) ||
1295  (col >= width))
1296  {
1297  cerr << "Raster::GetPixelValue *** ERROR ***, Raster Dimensions Exceeded." << std::endl;
1298  cerr << " Height[" << height << "] Width[" << width << "]." << std::endl;
1299  cerr << " Row[" << row << "] Col[" << col << "]." << std::endl;
1300  exit (-1);
1301  }
1302 
1303  return green[row][col];
1304 } /* GetPixelValue */
1305 
1306 
1307 
1309  kkint32 col,
1310  uchar& r,
1311  uchar& g,
1312  uchar& b
1313  ) const
1314 {
1315  if ((row < 0) ||
1316  (row >= height) ||
1317  (col < 0) ||
1318  (col >= width))
1319  {
1320  cerr << "Raster::GetPixelValue *** ERROR ***, Raster Dimensions Exceeded." << std::endl;
1321  cerr << " Height[" << height << "] Width[" << width << "]." << std::endl;
1322  cerr << " Row[" << row << "] Col[" << col << "]." << std::endl;
1323  exit (-1);
1324  }
1325 
1326  g = green [row][col];
1327 
1328  if (color)
1329  {
1330  r = red [row][col];
1331  b = blue [row][col];
1332  }
1333  else
1334  {
1335  r = 0;
1336  b = 0;
1337  }
1338 } /* GetPixelValue */
1339 
1340 
1341 
1342 
1344  kkint32 col,
1345  PixelValue& p
1346  ) const
1347 {
1348  GetPixelValue (row, col, p.r, p.g, p.b);
1349 } /* GetPixelValue */
1350 
1351 
1352 
1353 
1354 
1355 
1357  kkint32 row,
1358  kkint32 col
1359  ) const
1360 {
1361  if ((row < 0) ||
1362  (row >= height) ||
1363  (col < 0) ||
1364  (col >= width))
1365  {
1366  cerr << "Raster::GetPixelValue *** ERROR ***, Raster Dimensions Exceeded." << std::endl;
1367  cerr << " Height[" << height << "] Width[" << width << "]." << std::endl;
1368  cerr << " Row[" << row << "] Col[" << col << "]." << std::endl;
1369  exit (-1);
1370  }
1371 
1372  if (channel == ColorChannels::Green)
1373  return green [row][col];
1374 
1375  if (!color)
1376  {
1377  cerr << "***ERROR*** Raster::GetPixelValue *** ERROR ***, Not a Color Raster." << std::endl;
1378  exit (-1);
1379  }
1380 
1381  if (channel == ColorChannels::Red)
1382  return red [row][col];
1383  else
1384  return blue[row][col];
1385 } /* GetPixelValue */
1386 
1387 
1388 
1389 
1391  kkint32 col,
1392  uchar pixVal
1393  )
1394 {
1395  if ((row < 0) ||
1396  (row >= height) ||
1397  (col < 0) ||
1398  (col >= width))
1399  {
1400  cerr << "***ERROR*** Raster::SetPixelValue *** ERROR ***, Raster Dimensions Exceeded." << std::endl;
1401  cerr << " Height[" << height << "] Width[" << width << "]." << std::endl;
1402  cerr << " Row[" << row << "] Col[" << col << "]." << std::endl;
1403  return;
1404  }
1405 
1406  green[row][col] = pixVal;
1407 } /* SetPixelValue */
1408 
1409 
1410 
1411 
1412 
1414  kkint32 col,
1415  const PixelValue& pixVal
1416  )
1417 {
1418  if ((row < 0) ||
1419  (row >= height) ||
1420  (col < 0) ||
1421  (col >= width))
1422  {
1423  cerr << "***ERROR*** Raster::SetPixelValue *** ERROR ***, Raster Dimensions Exceeded." << std::endl;
1424  cerr << " Height[" << height << "] Width[" << width << "]." << std::endl;
1425  cerr << " Row[" << row << "] Col[" << col << "]." << std::endl;
1426  return;
1427  }
1428 
1429  green[row][col] = pixVal.g;
1430  if (color)
1431  {
1432  red [row][col] = pixVal.r;
1433  blue [row][col] = pixVal.b;
1434  }
1435 } /* SetPixelValue */
1436 
1437 
1438 
1439 
1440 void Raster::SetPixelValue (const Point& point,
1441  const PixelValue& pixVal
1442  )
1443 {
1444  SetPixelValue (point.Row (), point.Col (), pixVal);
1445 } /* SetPixelValue */
1446 
1447 
1448 
1449 
1451  kkint32 col,
1452  uchar r,
1453  uchar g,
1454  uchar b
1455  )
1456 {
1457  if ((row < 0) ||
1458  (row >= height) ||
1459  (col < 0) ||
1460  (col >= width))
1461  {
1462  cerr << "***ERROR*** Raster::SetPixelValue *** ERROR ***, Raster Dimensions Exceeded." << std::endl;
1463  cerr << " Height[" << height << "] Width[" << width << "]." << std::endl;
1464  cerr << " Row[" << row << "] Col[" << col << "]." << std::endl;
1465  return;
1466  }
1467 
1468  green[row][col] = g;
1469  if (color)
1470  {
1471  red [row][col] = r;
1472  blue [row][col] = b;
1473  }
1474 } /* SetPixelValue */
1475 
1476 
1477 
1478 
1480  kkint32 row,
1481  kkint32 col,
1482  uchar pixVal
1483  )
1484 {
1485  if ((row < 0) ||
1486  (row >= height) ||
1487  (col < 0) ||
1488  (col >= width))
1489  {
1490  cerr << "***ERROR*** Raster::SetPixelValue *** ERROR ***, Raster Dimensions Exceeded." << std::endl;
1491  cerr << " Height[" << height << "] Width[" << width << "]." << std::endl;
1492  cerr << " Row[" << row << "] Col[" << col << "]." << std::endl;
1493  return;
1494  }
1495 
1496  if (channel == ColorChannels::Green)
1497  {
1498  green[row][col] = pixVal;
1499  return;
1500  }
1501 
1502  if (!color)
1503  {
1504  cerr << "***ERROR*** Raster::SetPixelValue *** ERROR ***, Not a Color Raster." << std::endl;
1505  }
1506 
1507  if (channel == ColorChannels::Red)
1508  red [row][col] = pixVal;
1509  else
1510  blue [row][col] = pixVal;
1511 
1512 } /* SetPixelValue */
1513 
1514 
1515 
1517 {
1518  for (kkint32 edgeIdx = 0; edgeIdx < edgeWidth; ++edgeIdx)
1519  {
1520  kkint32 topRow = edgeIdx;
1521  kkint32 botRow = height - (edgeIdx + 1);
1522 
1523  for (int c = 0; c < width; ++c)
1524  {
1525  if (ForegroundPixel (topRow, c) || ForegroundPixel (botRow, c))
1526  return true;
1527  }
1528 
1529  kkint32 leftCol = edgeIdx;
1530  kkint32 rightCol = width - (1 + edgeIdx);
1531 
1532  for (int r = 0; r < height; ++r)
1533  {
1534  if (ForegroundPixel (r, leftCol) || ForegroundPixel (r, rightCol))
1535  return true;
1536  }
1537  }
1538  return false;
1539 } /* AreThereEdgePixels */
1540 
1541 
1542 
1543 void Raster::DrawGrid (float pixelsPerMinor,
1544  kkuint32 minorsPerMajor,
1545  const PixelValue& hashColor,
1546  const PixelValue& gridColor
1547  )
1548 {
1549  int x = 0;
1550 
1551  int hashLen = 4;
1552 
1553  // Horizontal Hash Marks
1554 
1555  //kkint32 horzOffset = (width - (kkint32)(((float)width / pixelsPerMinor) * pixelsPerMinor) / 2);
1556  while (true)
1557  {
1558  int hashPos = (int)((float)x * pixelsPerMinor + 0.5f); // + horzOffset;
1559  if (hashPos >= (height - hashLen))
1560  break;
1561 
1562  if ((x % minorsPerMajor) == 0)
1563  hashLen = 10;
1564  else
1565  hashLen = 6;
1566 
1567  FillRectangle (hashPos, 0, hashPos + 2, hashLen - 1, hashColor);
1568  FillRectangle (hashPos, width - hashLen, hashPos + 2, width - 1, hashColor);
1569  DrawLine (hashPos + 1, 0, hashPos + 1, width - 1, gridColor, 0.2f);
1570  x++;
1571  }
1572 
1573  x = 0;
1574 
1575  // Vertical Hash Marks
1576  // kkint32 vertOffset = (height - (kkint32)((height / pixelsPerMinor) * pixelsPerMinor) / 2);
1577  while (true)
1578  {
1579  int hashPos = (int)((float)x * pixelsPerMinor + 0.5f); // + vertOffset;
1580  if (hashPos >= width)
1581  break;
1582 
1583  if ((x % minorsPerMajor) == 0)
1584  hashLen = 8;
1585  else
1586  hashLen = 4;
1587 
1588  FillRectangle (0, hashPos, hashLen - 1, hashPos + 2, hashColor);
1589  FillRectangle (height - hashLen, hashPos, height - 1, hashPos + 2, hashColor);
1590  DrawLine (0, hashPos + 1, height - 1, hashPos + 1, gridColor, 0.2f);
1591 
1592  x++;
1593  }
1594 } /* DrawGrid */
1595 
1596 
1597 
1598 
1599 
1600 inline
1601 void Raster::CalcDialatedValue (kkint32 row,
1602  kkint32 col,
1603  kkint32& totVal,
1604  uchar& numNeighbors
1605  ) const
1606 {
1607  if ((row < 0) || (row >= height))
1608  return;
1609 
1610  if ((col < 0) || (col >= width))
1611  return;
1612 
1613  if (ForegroundPixel (green[row][col]))
1614  {
1615  numNeighbors++;
1616  totVal = totVal + green[row][col];
1617  }
1618 } /* CalcDialatedValue */
1619 
1620 
1621 
1622 
1623 RasterPtr Raster::CreateDilatedRaster () const
1624 {
1625  kkint32 row;
1626  kkint32 col;
1627 
1628  kkint32 resultForegroundPixelCount = 0;
1629 
1630  RasterPtr result = AllocateARasterInstance (*this);
1631 
1632  uchar** resultRows = result->green;
1633 
1634  kkint32 totValue = 0;
1635  uchar numNeighbors = 0;
1636 
1637  uchar* resultRow = NULL;
1638 
1639  for (row = 0; row < height; row++)
1640  {
1641  resultRow = resultRows[row];
1642  for (col = 0; col < width; col++)
1643  {
1644  if (BackgroundPixel (resultRow[col]))
1645  {
1646  // Since we are a blank cell we want our value to be set to the average value of our occupied neighbors.
1647  totValue = 0;
1648  numNeighbors = 0;
1649 
1650  CalcDialatedValue (row - 1, col - 1, totValue, numNeighbors);
1651  CalcDialatedValue (row - 1, col, totValue, numNeighbors);
1652  CalcDialatedValue (row - 1, col + 1, totValue, numNeighbors);
1653 
1654  CalcDialatedValue (row , col - 1, totValue, numNeighbors);
1655  CalcDialatedValue (row , col + 1, totValue, numNeighbors);
1656 
1657  CalcDialatedValue (row + 1, col - 1, totValue, numNeighbors);
1658  CalcDialatedValue (row + 1, col , totValue, numNeighbors);
1659  CalcDialatedValue (row + 1, col + 1, totValue, numNeighbors);
1660 
1661  if (numNeighbors > 0)
1662  {
1663  resultRow[col] = (uchar)(totValue / numNeighbors);
1664  resultForegroundPixelCount++;
1665  }
1666  }
1667  else
1668  {
1669  resultForegroundPixelCount++;
1670  }
1671  }
1672  }
1673 
1674  result->foregroundPixelCount = resultForegroundPixelCount;
1675  return result;
1676 } /* CreateDilatedRaster */
1677 
1678 
1679 
1680 
1682 {
1683  RasterPtr tempRaster = CreateDilatedRaster ();
1684 
1685  delete greenArea;
1686  delete green;
1687 
1688  greenArea = tempRaster->greenArea;
1689  green = tempRaster->green;
1690 
1691  tempRaster->greenArea = NULL;
1692  tempRaster->green = NULL;
1693 
1695 
1696  delete tempRaster;
1697 } /* Dilation */
1698 
1699 
1700 
1701 
1702 RasterPtr Raster::CreateDilatedRaster (MaskTypes mask) const
1703 {
1704  kkint32 row;
1705  kkint32 col;
1706 
1707  RasterPtr result = AllocateARasterInstance (*this);
1708 
1709  uchar** resultRows = result->green;
1710 
1711  //uchar numNeighbors = 0;
1712 
1713  //for (row = 1; row < (height - 1); row++)
1714  //{
1715  // for (col = 1; col < (width - 1); col++)
1716  // {
1717  // if (resultRows[row][col] == 0)
1718  // {
1719  // resultRows[row][col] = Hit (mask, row, col);
1720  // }
1721  // }
1722  //}
1723 
1724  kkint32 resultForegroundPixelCount = 0;
1725  uchar* resultRow = NULL;
1726  uchar pixelValue;
1727  for (row = 0; row < height; row++)
1728  {
1729  resultRow = resultRows[row];
1730  for (col = 0; col < width; col++)
1731  {
1732  if (BackgroundPixel (resultRow[col]))
1733  {
1734  pixelValue = Hit (mask, row, col);
1735  resultRow[col] = pixelValue;
1736  if (!BackgroundPixel (pixelValue))
1737  resultForegroundPixelCount++;
1738  }
1739  else
1740  {
1741  resultForegroundPixelCount++;
1742  }
1743  }
1744  }
1745 
1746  result->foregroundPixelCount = resultForegroundPixelCount;
1747 
1748  return result;
1749 } /* CreateDilatedRaster */
1750 
1751 
1752 
1753 
1754 
1755 void Raster::Dilation (MaskTypes mask)
1756 {
1757  RasterPtr tempRaster = CreateDilatedRaster (mask);
1758 
1759  delete greenArea;
1760  delete green;
1761 
1763 
1764  greenArea = tempRaster->greenArea;
1765  green = tempRaster->green;
1766 
1767  tempRaster->greenArea = NULL;
1768  tempRaster->green = NULL;
1769 
1770  delete tempRaster;
1771 } /* Dilation */
1772 
1773 
1774 
1775 
1777  kkuint16 _structureSize,
1778  kkint32 _foregroundCountTH
1779  )
1780 {
1781  MorphOpDilation dialator (_structure, _structureSize);
1782  dialator.ForegroundCountTH (_foregroundCountTH);
1783  RasterPtr tempRaster = dialator.PerformOperation (this);
1784 
1785  delete greenArea;
1786  delete green;
1787 
1789 
1790  greenArea = tempRaster->greenArea;
1791  green = tempRaster->green;
1792 
1793  tempRaster->greenArea = NULL;
1794  tempRaster->green = NULL;
1795 
1796  delete tempRaster;
1797 } /* Dilation */
1798 
1799 
1800 
1801 
1802 
1803 
1804 void Raster::Dilation (RasterPtr dest) const
1805 {
1806  if ((dest->Height () != height) || (dest->Width () != width) || (dest->Color () != color))
1808 
1809  uchar* srcArea = GreenArea ();
1810  uchar** srcRows = Green ();
1811 
1812  uchar* destArea = dest->GreenArea ();
1813  uchar** destRows = dest->Green ();
1814 
1815  memset (destArea, 0, totPixels);
1816  kkint32 pixelCount = 0;
1817 
1818  int c, r;
1819 
1820  // Take care of Top and Bottom rows.
1821  {
1822  uchar* srcRow0 = srcRows[0];
1823  uchar* srcRow1 = srcRows[1];
1824  uchar* srcRowBot0 = srcRows[height - 1];
1825  uchar* srcRowBot1 = srcRows[height - 2];
1826 
1827  uchar* destRow0 = destRows[0];
1828  uchar* destRowBot = destRows[height - 1];
1829  for (c = 1; c < (width - 1); ++c)
1830  {
1831  if ((srcRow0[c - 1] > backgroundPixelTH) || (srcRow0[c] > backgroundPixelTH) || (srcRow0[c + 1] > backgroundPixelTH) ||
1832  (srcRow1[c - 1] > backgroundPixelTH) || (srcRow1[c] > backgroundPixelTH) || (srcRow1[c + 1] > backgroundPixelTH)
1833  )
1834  {
1835  destRow0[c] = 255;
1836  ++pixelCount;
1837  }
1838 
1839  if ((srcRowBot0[c - 1] > backgroundPixelTH) || (srcRowBot0[c + 1] > backgroundPixelTH) ||
1840  (srcRowBot1[c - 1] > backgroundPixelTH) || (srcRowBot1[c] > backgroundPixelTH) || (srcRowBot1[c + 1] > backgroundPixelTH)
1841  )
1842  {
1843  destRowBot[c] = 255;
1844  ++pixelCount;
1845  }
1846  }
1847  }
1848 
1849 
1850  // Take care of left and right columns
1851  {
1852  for (r = 1; r < (height - 1); ++r)
1853  {
1854  if ((srcRows[r - 1][0] > backgroundPixelTH) || (srcRows[r - 1][1] > backgroundPixelTH) ||
1855  (srcRows[r ][0] > backgroundPixelTH) || (srcRows[r ][1] > backgroundPixelTH) ||
1856  (srcRows[r + 1][0] > backgroundPixelTH) || (srcRows[r + 1][1] > backgroundPixelTH)
1857  )
1858  {
1859  destRows[r][0] = 255;
1860  ++pixelCount;
1861  }
1862 
1863 
1864  if ((srcRows[r - 1][width - 1] > backgroundPixelTH) || (srcRows[r - 1][width - 2] > backgroundPixelTH) ||
1865  (srcRows[r ][width - 1] > backgroundPixelTH) || (srcRows[r ][width - 2] > backgroundPixelTH) ||
1866  (srcRows[r + 1][width - 1] > backgroundPixelTH) || (srcRows[r + 1][width - 2] > backgroundPixelTH)
1867  )
1868  {
1869  destRows[r][width - 1] = 255;
1870  ++pixelCount;
1871  }
1872  }
1873  }
1874 
1875 
1876  // Take care of main Body
1877  {
1878  for (r = 1; r < (height - 1); ++r)
1879  {
1880  uchar* srcRow0 = srcRows[r - 1];
1881  uchar* srcRow1 = srcRows[r ];
1882  uchar* srcRow2 = srcRows[r + 1];
1883 
1884  for (c = 1; c < (width - 1); ++c)
1885  {
1886  if ((srcRow0[c - 1] > backgroundPixelTH) || (srcRow0[c] > backgroundPixelTH) || (srcRow0[c + 1] > backgroundPixelTH) ||
1887  (srcRow1[c - 1] > backgroundPixelTH) || (srcRow1[c] > backgroundPixelTH) || (srcRow1[c + 1] > backgroundPixelTH) ||
1888  (srcRow2[c - 1] > backgroundPixelTH) || (srcRow2[c] > backgroundPixelTH) || (srcRow2[c + 1] > backgroundPixelTH)
1889  )
1890  {
1891  destRows[r][c] = 255;
1892  ++pixelCount;
1893  }
1894  }
1895  }
1896  }
1897 
1898  dest->foregroundPixelCount = pixelCount;
1899 } /* Dilation */
1900 
1901 
1902 
1903 
1904 
1906  MaskTypes mask
1907  )
1908  const
1909 {
1910  if ((dest->Height () != height) || (dest->Width () != width) || (dest->Color () != color))
1912 
1913  uchar* destArea = dest->GreenArea ();
1914  uchar** destRows = dest->Green ();
1915 
1916  memset (destArea, 0, totPixels);
1917  kkint32 pixelCount = 0;
1918 
1919  int c, r;
1920 
1921 
1922  // Take care of main Body
1923  {
1924  for (r = 0; r < height; ++r)
1925  {
1926  for (c = 0; c < width; ++c)
1927  {
1928  if (IsThereANeighbor (mask, r, c))
1929  {
1930  destRows[r][c] = 255;
1931  ++pixelCount;
1932  }
1933  }
1934  }
1935  }
1936 
1937  dest->foregroundPixelCount = pixelCount;
1938 } /* Dilation */
1939 
1940 
1941 
1942 
1943 
1944 
1945 
1946 
1948  kkint32 tlCol,
1949  kkint32 brRow,
1950  kkint32 brCol,
1951  const PixelValue& fillColor
1952  )
1953 {
1954  tlRow = Min (tlRow, height - 1);
1955  brRow = Min (brRow, height - 1);
1956 
1957  tlCol = Min (tlCol, width - 1);
1958  brCol = Min (brCol, width - 1);
1959 
1960  for (kkint32 row = tlRow; row <= brRow; ++row)
1961  {
1962  if (color)
1963  {
1964  uchar* rowRed = red [row];
1965  uchar* rowGreen = green [row];
1966  uchar* rowBlue = blue [row];
1967  for (kkint32 col = tlCol; col <= brCol; ++col)
1968  {
1969  rowRed [col] = fillColor.r;
1970  rowGreen[col] = fillColor.g;
1971  rowBlue [col] = fillColor.b;
1972  }
1973  }
1974  else
1975  {
1976  uchar* rowGreen = green[row];
1977  for (kkint32 col = tlCol; col <= brCol; ++col)
1978  rowGreen[col] = fillColor.g;
1979  }
1980  }
1981 } /* FillRectangle */
1982 
1983 
1984 
1985 
1986 void Raster::FillHoleGrow (kkint32 _row,
1987  kkint32 _col
1988  )
1989 {
1990  PointList expandList (true);
1991 
1992  expandList.PushOnBack (new Point (_row, _col));
1993 
1994  while (expandList.QueueSize () > 0)
1995  {
1996  PointPtr nextPixel = expandList.PopFromFront ();
1997 
1998  kkint32 r = nextPixel->Row ();
1999  kkint32 c = nextPixel->Col ();
2000 
2001  green[r][c] = foregroundPixelValue;
2002 
2003  if (r > 0)
2004  {
2005  if (BackgroundPixel (green[r - 1][c]))
2006  {
2007  green[r - 1][c] = foregroundPixelValue;
2008  expandList.PushOnBack (new Point (r - 1, c));
2009  }
2010  }
2011 
2012  if (r < (height - 1))
2013  {
2014  if (BackgroundPixel (green[r + 1][c]))
2015  {
2016  green[r + 1][c] = foregroundPixelValue;
2017  expandList.PushOnBack (new Point (r + 1, c));
2018  }
2019  }
2020 
2021  if (c > 0)
2022  {
2023  if (BackgroundPixel (green[r][c - 1]))
2024  {
2025  green[r][c - 1] = foregroundPixelValue;
2026  expandList.PushOnBack (new Point (r, c - 1));
2027  }
2028  }
2029 
2030  if (c < (width - 1))
2031  {
2032  if (BackgroundPixel (green[r][c + 1]))
2033  {
2034  green[r][c + 1] = foregroundPixelValue;
2035  expandList.PushOnBack (new Point (r, c + 1));
2036  }
2037  }
2038 
2039  delete nextPixel; nextPixel = NULL;
2040  }
2041 } /* FillHoleGrow */
2042 
2043 
2044 
2045 
2046 
2048 {
2049  kkint32 r;
2050  kkint32 c;
2051  Raster mask (*this);
2052 
2053  uchar** maskRows = mask.green;
2054 
2055  kkint32 lastRow = height - 1;
2056  kkint32 lastCol = width - 1;
2057 
2058  for (c = 0; c < width; c++)
2059  {
2060  if (BackgroundPixel (maskRows[0][c]))
2061  mask.FillHoleGrow (0, c);
2062 
2063  if (BackgroundPixel (maskRows[lastRow][c]))
2064  mask.FillHoleGrow (lastRow, c);
2065  }
2066 
2067  for (r = 0; r < height; r++)
2068  {
2069  if (BackgroundPixel (maskRows[r][0]))
2070  mask.FillHoleGrow (r, 0);
2071 
2072  if (BackgroundPixel (maskRows[r][lastCol]))
2073  mask.FillHoleGrow (r, lastCol);
2074  }
2075 
2076  // Now that we know what pixels are background that are connected to one of the boarders, any other white pixel
2077  // must be in a hole inside the image.
2079  uchar* curRow = NULL;
2080  for (r = 0; r < height; r++)
2081  {
2082  curRow = green[r];
2083  for (c = 0; c < width; c++)
2084  {
2085  if (BackgroundPixel (curRow[c]))
2086  {
2087  if (BackgroundPixel (maskRows[r][c]))
2088  {
2089  curRow[c] = foregroundPixelValue;
2091  }
2092  }
2093  else
2094  {
2096  }
2097  }
2098  }
2099 
2101 } /* FillHole */
2102 
2103 
2104 
2105 
2106 
2108 {
2109  if ((mask->Height () != height) | (mask->Width () != width))
2110  mask->ReSize (height, width, false);
2111 
2112  uchar* srcArea = this->GreenArea ();
2113  uchar** srcRows = this->Green ();
2114 
2115  uchar* maskArea = mask->GreenArea ();
2116  uchar** maskRows = mask->Green ();
2117 
2118  memset (maskArea, 0, totPixels);
2119 
2120  kkint32 c, r, x;
2121 
2122  for (x = 0; x < totPixels; ++x)
2123  {
2124  if (srcArea[x] > backgroundPixelTH)
2125  maskArea[x] = 255;
2126  }
2127 
2128  {
2129  // Check Top and Bottom Mask Rows for background pixels and flag them as having access to the border.
2130  uchar* rowTop = maskRows[0];
2131  uchar* rowBot = maskRows[height - 1];
2132 
2133  for (c = 0; c < width; ++c)
2134  {
2135  if (rowTop[c] == 0)
2136  rowTop[c] = 1;
2137  if (rowBot[c] == 0)
2138  rowBot[c] = 1;
2139  }
2140  }
2141 
2142  {
2143  // Check Left and Right columns for background pixels and flag them as having access to the border.
2144  uchar* leftCol = maskArea;
2145  uchar* rightCol = maskArea + (width - 1);
2146  for (r = 0; r < height; ++r)
2147  {
2148  if (*leftCol == 0)
2149  *leftCol = 1;
2150  if (*rightCol == 0)
2151  *rightCol = 1;
2152 
2153  leftCol += width;
2154  rightCol += width;
2155  }
2156  }
2157 
2158 
2159  // We will not iteratively scan the Mask image for pixels that have access top the edge of the image.
2160  // We will repeat the following loop until no pixels get flagged.
2161  bool fillInFound = false;
2162  do
2163  {
2164  fillInFound = false;
2165 
2166  // Scan from TopLeft to BotRight
2167  uchar* rowPrev = maskArea;
2168  uchar* rowCur = rowPrev + width;
2169  uchar* rowNext = rowCur + width;
2170 
2171  for (r = 1; r < (height - 1); ++r)
2172  {
2173  for (c = 1; c < (width - 1); ++c)
2174  {
2175  if (rowCur[c] == 0)
2176  {
2177  if ((rowPrev[c ] == 1) ||
2178  (rowCur [c - 1] == 1) ||
2179  (rowCur [c + 1] == 1) ||
2180  (rowNext[c ] == 1)
2181  )
2182  {
2183  rowCur[c] = 1;
2184  fillInFound = true;
2185  }
2186  }
2187  }
2188 
2189  rowPrev += width;
2190  rowCur += width;
2191  rowNext += width;
2192  }
2193 
2194 
2195  // Scan from Bot-Right to Top-Left
2196  rowPrev = maskRows[height - 1];
2197  rowCur = rowPrev - width;
2198  rowNext = rowCur - width;
2199 
2200  for (r = (height - 2); r > 0; --r)
2201  {
2202  for (c = (width - 2); c > 0; --c)
2203  {
2204  if (rowCur[c] == 0)
2205  {
2206  if ((rowPrev[c ] == 1) ||
2207  (rowCur [c - 1] == 1) ||
2208  (rowCur [c + 1] == 1) ||
2209  (rowNext[c ] == 1)
2210  )
2211  {
2212  rowCur[c] = 1;
2213  fillInFound = true;
2214  }
2215  }
2216  }
2217 
2218  rowPrev -= width;
2219  rowCur -= width;
2220  rowNext -= width;
2221  }
2222  } while (fillInFound);
2223 
2224 
2225  // At this point the only pixels in the mask image that contain a '0' are the ones that are in holes.
2226  // We will now fill the corresponding pixel locations in the original image with the ForegroundPixelValue.
2227  for (x = 0; x < totPixels; ++x)
2228  {
2229  if (maskArea[x] == 0)
2230  {
2231  srcArea[x] = foregroundPixelValue;
2233  }
2234  }
2235 } /* FillHole */
2236 
2237 
2238 
2239 
2240 
2241 void Raster::Erosion ()
2242 {
2243  Raster origRaster (*this);
2244 
2245  uchar** origRows = origRaster.green;
2246 
2248 
2249  kkint32 r;
2250  kkint32 c;
2251 
2252  kkint32 lastRow = height - 1;
2253  kkint32 lastCol = width - 1;
2254 
2255  uchar* rowLast = NULL;
2256  uchar* rowCur = NULL;
2257  uchar* rowNext = NULL;
2258 
2259  for (r = 1; r < lastRow; r++)
2260  {
2261  rowLast = origRows[r - 1];
2262  rowCur = origRows[r ];
2263  rowNext = origRows[r + 1];
2264 
2265  for (c = 1; c < lastCol; c++)
2266  {
2267  if (!BackgroundPixel (green[r][c]))
2268  {
2269  if ((rowLast [c - 1] <= backgroundPixelTH) ||
2270  (rowLast [c] <= backgroundPixelTH) ||
2271  (rowLast [c + 1] <= backgroundPixelTH) ||
2272 
2273  (rowCur [c - 1] <= backgroundPixelTH) ||
2274  (rowCur [c + 1] <= backgroundPixelTH) ||
2275 
2276  (rowNext [c - 1] <= backgroundPixelTH) ||
2277  (rowNext [c] <= backgroundPixelTH) ||
2278  (rowNext [c + 1] <= backgroundPixelTH))
2279  {
2280  green[r][c] = backgroundPixelValue;
2281  }
2282  else
2283  {
2285  }
2286  }
2287  }
2288  }
2289 } /* Erosion */
2290 
2291 
2292 
2293 
2294 void Raster::Erosion (MaskTypes mask)
2295 {
2296  kkint32 r;
2297  kkint32 c;
2298 
2299  kkint32 bias = MorphOp::Biases (mask);
2300 
2301  kkint32 maskRowStart = 0 - bias;
2302  kkint32 maskRowEnd = 0 + bias;
2303  kkint32 maskColStart = 0 - bias;
2304  kkint32 maskColEnd = 0 + bias;
2305  kkint32 maskRow;
2306  kkint32 maskCol;
2307  bool fit = false;
2308 
2310  Raster tempRaster (*this);
2311  uchar** tempGreen = tempRaster.Green ();
2312  uchar* tempRowData = NULL;
2313  StructureType m = MorphOp::MaskShapes (mask);
2314 
2315  for (r = 0; r < height; r++)
2316  {
2317  maskColStart = 0 - bias;
2318  maskColEnd = 0 + bias;
2319 
2320  tempRowData = tempGreen[r];
2321 
2322  for (c = 0; c < width; c++)
2323  {
2324  if (ForegroundPixel (green[r][c]))
2325  {
2326  fit = true;
2327  if ((maskRowStart < 0) || (maskRowEnd >= height) || (maskColStart < 0) || (maskColStart >= width))
2328  fit = false;
2329 
2330  else if (m == StructureType::stSquare)
2331  {
2332  for (maskRow = maskRowStart; ((maskRow <= maskRowEnd) && fit); maskRow++)
2333  {
2334  tempRowData = tempGreen[maskRow];
2335  for (maskCol = maskColStart; maskCol <= maskColEnd; maskCol++)
2336  {
2337  if (BackgroundPixel (tempRowData[maskCol]))
2338  {
2339  fit = false;
2340  break;
2341  }
2342  }
2343  }
2344  }
2345  else
2346  {
2347  // Cross Structure
2348  for (maskRow = maskRowStart; maskRow <= maskRowEnd; maskRow++)
2349  {
2350  if (BackgroundPixel (tempGreen[maskRow][c]))
2351  {
2352  fit = false;
2353  break;
2354  }
2355  }
2356 
2357  tempRowData = tempGreen[maskRow];
2358  for (maskCol = maskColStart; maskCol <= maskColEnd; maskCol++)
2359  {
2360  if (BackgroundPixel (tempRowData[maskCol]))
2361  {
2362  fit = false;
2363  break;
2364  }
2365  }
2366  }
2367 
2368  if (!fit)
2369  green[r][c] = backgroundPixelValue;
2370  else
2372  }
2373 
2374  maskColStart++;
2375  maskColEnd++;
2376  } /* End of for(c) */
2377 
2378  maskRowStart++;
2379  maskRowEnd++;
2380  } /* End of for(r) */
2381 
2382 } /* Erosion */
2383 
2384 
2385 
2386 
2387 
2389  kkuint16 _structureSize,
2390  kkint32 _backgroundCountTH
2391  )
2392 {
2393  MorphOpErosion eroder (_structure, _structureSize);
2394  eroder.BackgroundCountTH (_backgroundCountTH);
2395  RasterPtr tempRaster = eroder.PerformOperation (this);
2396  delete greenArea;
2397  delete green;
2399 
2400  greenArea = tempRaster->greenArea;
2401  green = tempRaster->green;
2402 
2403  tempRaster->greenArea = NULL;
2404  tempRaster->green = NULL;
2405 
2406  delete tempRaster;
2407 } /* Erosion */
2408 
2409 
2410 
2411 void Raster::Erosion (RasterPtr dest) const
2412 {
2413  if ((dest->Height () != height) | (dest->Width () != width))
2414  dest->ReSize (height, width, false);
2415 
2416  uchar* destArea = dest->GreenArea ();
2417  uchar** destRows = dest->Green ();
2418 
2419  uchar* srcArea = greenArea;
2420  uchar** srcRows = green;
2421 
2422  kkint32 totalArea = this->TotPixels ();
2423 
2424  memset (destArea, 0, totPixels);
2425  kkint32 pixelCount = 0;
2426 
2427  int c, r;
2428 
2429  // Take care of Top and Bottom rows.
2430  {
2431  uchar* srcRow0 = srcRows[0];
2432  uchar* srcRow1 = srcRows[1];
2433  uchar* srcRowBot0 = srcRows[height - 1];
2434  uchar* srcRowBot1 = srcRows[height - 2];
2435 
2436  uchar* destRow0 = destRows[0];
2437  uchar* destRowBot = destRows[height - 1];
2438  for (c = 1; c < (width - 1); ++c)
2439  {
2440  if ((srcRow0[c - 1] > backgroundPixelTH) && (srcRow0[c] > backgroundPixelTH) && (srcRow0[c + 1] > backgroundPixelTH) &&
2441  (srcRow1[c - 1] > backgroundPixelTH) && (srcRow1[c] > backgroundPixelTH) && (srcRow1[c + 1] > backgroundPixelTH)
2442  )
2443  {
2444  destRow0[c] = 255;
2445  ++pixelCount;
2446  }
2447 
2448  if ((srcRowBot0[c - 1] > backgroundPixelTH) && (srcRowBot0[c + 1] > backgroundPixelTH) &&
2449  (srcRowBot1[c - 1] > backgroundPixelTH) && (srcRowBot1[c] > backgroundPixelTH) && (srcRowBot1[c + 1] > backgroundPixelTH)
2450  )
2451  {
2452  destRowBot[c] = 255;
2453  ++pixelCount;
2454  }
2455  }
2456  }
2457 
2458 
2459  // Take care of left and right columns
2460  {
2461  for (r = 1; r < (height - 1); ++r)
2462  {
2463  if ((srcRows[r - 1][0] > backgroundPixelTH) && (srcRows[r - 1][1] > backgroundPixelTH) &&
2464  (srcRows[r ][0] > backgroundPixelTH) && (srcRows[r ][1] > backgroundPixelTH) &&
2465  (srcRows[r + 1][0] > backgroundPixelTH) && (srcRows[r + 1][1] > backgroundPixelTH)
2466  )
2467  {
2468  destRows[r][0] = 255;
2469  ++pixelCount;
2470  }
2471 
2472 
2473  if ((srcRows[r - 1][width - 1] > backgroundPixelTH) && (srcRows[r - 1][width - 2] > backgroundPixelTH) &&
2474  (srcRows[r ][width - 1] > backgroundPixelTH) && (srcRows[r ][width - 2] > backgroundPixelTH) &&
2475  (srcRows[r + 1][width - 1] > backgroundPixelTH) && (srcRows[r + 1][width - 2] > backgroundPixelTH)
2476  )
2477  {
2478  destRows[r][width - 1] = 255;
2479  ++pixelCount;
2480  }
2481  }
2482  }
2483 
2484 
2485  // Take care of main Body
2486  {
2487  for (r = 1; r < (height - 1); ++r)
2488  {
2489  uchar* srcRow0 = srcRows[r - 1];
2490  uchar* srcRow1 = srcRows[r ];
2491  uchar* srcRow2 = srcRows[r + 1];
2492 
2493  for (c = 1; c < (width - 1); ++c)
2494  {
2495  if ((srcRow0[c - 1] > backgroundPixelTH) && (srcRow0[c] > backgroundPixelTH) && (srcRow0[c + 1] > backgroundPixelTH) &&
2496  (srcRow1[c - 1] > backgroundPixelTH) && (srcRow1[c] > backgroundPixelTH) && (srcRow1[c + 1] > backgroundPixelTH) &&
2497  (srcRow2[c - 1] > backgroundPixelTH) && (srcRow2[c] > backgroundPixelTH) && (srcRow2[c + 1] > backgroundPixelTH)
2498  )
2499  {
2500  destRows[r][c] = 255;
2501  ++pixelCount;
2502  }
2503  }
2504  }
2505  }
2506 
2507  dest->foregroundPixelCount = pixelCount;
2508 } /* Erosion*/
2509 
2510 
2511 
2512 
2513 
2515  MaskTypes mask
2516  )
2517  const
2518 {
2519  if ((dest->Height () != height) | (dest->Width () != width))
2520  dest->ReSize (height, width, false);
2521 
2522  uchar* destArea = dest->GreenArea ();
2523  uchar** destRows = dest->Green ();
2524 
2525  memset (destArea, 0, totPixels);
2526  kkint32 pixelCount = 0;
2527 
2528  int c, r;
2529 
2530  // Take care of main Body
2531  {
2532  for (r = 0; r < height; ++r)
2533  {
2534  uchar* rowData = green[r];
2535  for (c = 0; c < width; ++c)
2536  {
2537  if (ForegroundPixel (rowData[c]))
2538  {
2539  if (Fit (mask, r, c))
2540  {
2541  destRows[r][c] = 255;
2542  ++pixelCount;
2543  }
2544  }
2545  }
2546  }
2547  }
2548 
2549  dest->foregroundPixelCount = pixelCount;
2550 } /* Erosion*/
2551 
2552 
2553 
2554 
2555 
2556 
2557 
2558 void Raster::ErosionChanged (MaskTypes mask,
2559  kkint32 row,
2560  kkint32 col
2561  )
2562 {
2563  kkint32 r;
2564  kkint32 c;
2565 
2566  kkint32 bias = MorphOp::Biases (mask);
2567 
2568  kkint32 maskRowStart ;
2569  kkint32 maskRowEnd ;
2570  kkint32 maskColStart ;
2571  kkint32 maskColEnd ;
2572  maskRowStart = 0 - bias;
2573  maskRowEnd = 0+ bias;
2574  maskColStart = 0 - bias;
2575  maskColEnd = 0 + bias;
2576 
2577  kkint32 maskRow;
2578  kkint32 maskCol;
2579  bool fit;
2580 
2582  Raster tempRaster (*this);
2583  uchar** tempGreen = tempRaster.Green ();
2584  uchar* tempRowData = NULL;
2585  StructureType m = MorphOp::MaskShapes (mask);
2586 
2587  for (r = row- 150; r < row+150; r++)
2588  {
2589  if (r<0)
2590  r =0;
2591  maskColStart = 0 - bias;
2592  maskColEnd = 0 + bias;
2593 
2594  tempRowData = tempGreen[r];
2595 
2596  for (c = col - 10; c < col + 10; c++)
2597  {
2598  if (c < 0)
2599  c = 0;
2600  // cout << maskColStart <<" ";
2601 
2602  if (ForegroundPixel (green[r][c]))
2603  {
2604  fit = true;
2605  if ((maskRowStart < row - 100) ||
2606  (maskRowEnd >= row + 100) ||
2607  (maskColStart < col - 10) ||
2608  (maskColStart >= col + 10)
2609  )
2610  {
2611  fit = false;
2612  }
2613 
2614  else if (m == StructureType::stSquare)
2615  {
2616  for (maskRow = row - 150; ((maskRow <= row + 150) && fit); maskRow++)
2617  {
2618  tempRowData = tempGreen[maskRow];
2619  for (maskCol = col - 10; maskCol <= col + 10 ; maskCol++)
2620  {
2621  if (BackgroundPixel (tempRowData[maskCol]))
2622  {
2623  fit = false;
2624  break;
2625  }
2626  }
2627  }
2628  }
2629 
2630  else
2631  {
2632  // Cross Structure
2633  for (maskRow = row-20; maskRow <= row+20; maskRow++)
2634  {
2635  if (BackgroundPixel (tempGreen[maskRow][c]))
2636  {
2637  fit = false;
2638  break;
2639  }
2640  }
2641 
2642  tempRowData = tempGreen[maskRow];
2643  for (maskCol = col-20; maskCol <= col+20; maskCol++)
2644  {
2645  if (BackgroundPixel (tempRowData[maskCol]))
2646  {
2647  fit = false;
2648  break;
2649  }
2650  }
2651  }
2652 
2653  if (!fit)
2654  green[r][c] = backgroundPixelValue;
2655  else
2657  }
2658 
2659  maskColStart++;
2660  maskColEnd++;
2661  } /* End of for(c) */
2662 
2663  maskRowStart++;
2664  maskRowEnd++;
2665  } /* End of for(r) */
2666 
2667 } /* ErosionChanged */
2668 
2669 
2670 
2671 void Raster::ErosionChanged1 (MaskTypes mask,
2672  kkint32 row,
2673  kkint32 col
2674  )
2675 {
2676  kkint32 r;
2677  kkint32 c;
2678 
2679  kkint32 bias = MorphOp::Biases (mask);
2680 
2681  kkint32 maskRowStart = 0;
2682  kkint32 maskRowEnd = 0;
2683  kkint32 maskColStart = 0;
2684  kkint32 maskColEnd = 0;
2685 
2686  maskRowStart = 0 - bias;
2687  maskRowEnd = 0 + bias;
2688  maskColStart = 0 - bias;
2689  maskColEnd = 0 + bias;
2690 
2691  kkint32 maskRow;
2692  kkint32 maskCol;
2693  bool fit;
2694 
2696 
2697  Raster tempRaster (*this);
2698 
2699  uchar** tempGreen = tempRaster.Green ();
2700  uchar* tempRowData = NULL;
2701  StructureType m = MorphOp::MaskShapes (mask);
2702 
2703  for (r = row- 20; r < row+20; r++)
2704  {
2705  if (r < 0)
2706  r =0;
2707 
2708  maskColStart = 0 - bias;
2709  maskColEnd = 0 + bias;
2710 
2711  tempRowData = tempGreen[r];
2712 
2713  for (c = col - 150; c < col + 150; c++)
2714  {
2715  if (c < 0)
2716  c=0;
2717  // cout << maskColStart <<" ";
2718 
2719  if (ForegroundPixel (green[r][c]))
2720  {
2721  fit = true;
2722  if ((maskRowStart < row - 50) ||
2723  (maskRowEnd >= row + 50) ||
2724  (maskColStart < col - 100) ||
2725  (maskColStart >= col+100)
2726  )
2727  {
2728  fit = false;
2729  }
2730 
2731  else if (m == StructureType::stSquare)
2732  {
2733  for (maskRow = row - 20; ((maskRow <= row + 20) && fit); maskRow++)
2734  {
2735  tempRowData = tempGreen[maskRow];
2736  for (maskCol = col - 150; maskCol <= col + 150 ; maskCol++)
2737  {
2738  if (BackgroundPixel (tempRowData[maskCol]))
2739  {
2740  fit = false;
2741  break;
2742  }
2743  }
2744  }
2745  }
2746 
2747  else
2748  {
2749  // Cross Structure
2750  for (maskRow = row-20; maskRow <= row+20; maskRow++)
2751  {
2752  if (BackgroundPixel (tempGreen[maskRow][c]))
2753  {
2754  fit = false;
2755  break;
2756  }
2757  }
2758 
2759  tempRowData = tempGreen[maskRow];
2760  for (maskCol = col-20; maskCol <= col+20; maskCol++)
2761  {
2762  if (BackgroundPixel (tempRowData[maskCol]))
2763  {
2764  fit = false;
2765  break;
2766  }
2767  }
2768  }
2769 
2770  if (!fit)
2771  green[r][c] = backgroundPixelValue;
2772  else
2774  }
2775 
2776  maskColStart++;
2777  maskColEnd++;
2778  } /* End of for(c) */
2779 
2780  maskRowStart++;
2781  maskRowEnd++;
2782  } /* End of for(r) */
2783 } /* ErosionChanged1 */
2784 
2785 
2786 
2787 void Raster::ErosionBoundary (MaskTypes mask,
2788  kkint32 blobrowstart,
2789  kkint32 blobrowend,
2790  kkint32 blobcolstart,
2791  kkint32 blobcolend
2792  )
2793 {
2794  kkint32 r;
2795  kkint32 c;
2796 
2797  kkint32 bias = MorphOp::Biases (mask);
2798 
2799  kkint32 maskRowStart = 0 - bias;
2800  kkint32 maskRowEnd = 0 + bias;
2801  kkint32 maskColStart = 0 - bias;
2802  kkint32 maskColEnd = 0 + bias;
2803 
2804  kkint32 maskRow = 0;
2805  kkint32 maskCol = 0;
2806  bool fit = false;
2807 
2809  Raster tempRaster (*this);
2810 
2811  uchar** tempGreen = tempRaster.Green ();
2812  uchar* tempRowData = NULL;
2813 
2814  StructureType m = MorphOp::MaskShapes (mask);
2815 
2816  for (r = 0; r < height; r++)
2817  {
2818  //if ((r>= blobrowstart+30) && (r<= blobrowend-30))
2819  // {
2820  // }
2821  // else
2822  // {
2823  maskColStart = 0 - bias;
2824  maskColEnd = 0 + bias;
2825 
2826  tempRowData = tempGreen[r];
2827 
2828  for (c = 0; c < width; c++)
2829  {
2830  if ((c >= blobcolstart + 100) && (c <= blobcolend - 100))
2831  {
2832  }
2833  else
2834  {
2835  if (ForegroundPixel (green[r][c]))
2836  {
2837  fit = true;
2838  if ((maskRowStart < 0) ||
2839  (maskRowEnd >= height) ||
2840  (maskColStart < 0) ||
2841  (maskColStart >= width)
2842  )
2843  {
2844  fit = false;
2845  }
2846 
2847  else if (m == StructureType::stSquare)
2848  {
2849  for (maskRow = maskRowStart; ((maskRow <= maskRowEnd) && fit); maskRow++)
2850  {
2851  tempRowData = tempGreen[maskRow];
2852  for (maskCol = maskColStart; maskCol <= maskColEnd; maskCol++)
2853  {
2854  if (BackgroundPixel (tempRowData[maskCol]))
2855  {
2856  fit = false;
2857  break;
2858  }
2859  }
2860  }
2861  }
2862  else
2863  {
2864  // Cross Structure
2865  for (maskRow = maskRowStart; maskRow <= maskRowEnd; maskRow++)
2866  {
2867  if (BackgroundPixel (tempGreen[maskRow][c]))
2868  {
2869  fit = false;
2870  break;
2871  }
2872  }
2873 
2874  tempRowData = tempGreen[maskRow];
2875  for (maskCol = maskColStart; maskCol <= maskColEnd; maskCol++)
2876  {
2877  if (BackgroundPixel (tempRowData[maskCol]))
2878  {
2879  fit = false;
2880  break;
2881  }
2882  }
2883  }
2884 
2885  if (!fit)
2886  green[r][c] = backgroundPixelValue;
2887  else
2889  }
2890 
2891  maskColStart++;
2892  maskColEnd++;
2893  }
2894  } /* End of for(c) */
2895 
2896  maskRowStart++;
2897  maskRowEnd++;
2898  //}
2899  } /* End of for(r) */
2900 
2901 } /* ErosionBoundary */
2902 
2903 
2904 
2905 
2906 RasterPtr Raster::CreateErodedImage (MaskTypes mask) const
2907 {
2908  kkint32 r;
2909  kkint32 c;
2910 
2911  RasterPtr erodedRaster = AllocateARasterInstance (*this);
2912 
2913  uchar* srcRow = NULL;
2914  uchar** destGreen = erodedRaster->Green ();
2915  uchar* destRow = NULL;
2916 
2917  kkint32 erodedForegroundPixelCount = foregroundPixelCount;
2918 
2919  for (r = 0; r < height; ++r)
2920  {
2921  destRow = destGreen[r];
2922  srcRow = green[r];
2923 
2924  for (c = 0; c < width; ++c)
2925  {
2926  if (ForegroundPixel (srcRow[c]))
2927  {
2928  if (!Fit (mask, r, c))
2929  {
2930  destRow[c] = backgroundPixelValue;
2931  erodedForegroundPixelCount--;
2932  }
2933  }
2934  } /* for (c) */
2935  } /* for (r) */
2936 
2937  erodedRaster->foregroundPixelCount = erodedForegroundPixelCount;
2938 
2939  return erodedRaster;
2940 } /* Erosion */
2941 
2942 
2943 
2944 void Raster::Opening ()
2945 {
2946  Erosion ();
2947  Dilation ();
2948 } /* Opening */
2949 
2950 
2951 
2952 void Raster::Opening (MaskTypes mask)
2953 {
2954  Erosion (mask);
2955  Dilation (mask);
2956 } /* Open */
2957 
2958 
2959 
2960 
2961 void Raster::Closing ()
2962 {
2963  Dilation ();
2964  Erosion ();
2965 } /* Open */
2966 
2967 
2968 
2969 
2970 
2971 void Raster::Closing (MaskTypes mask)
2972 {
2973  Dilation (mask);
2974  Erosion (mask);
2975 } /* Open */
2976 
2977 
2978 
2979 
2980 
2981 inline
2982 bool Raster::CompletlyFilled3By3 (kkint32 row,
2983  kkint32 col
2984  ) const
2985 {
2986  if (row > 0)
2987  {
2988  if (col > 0)
2989  {
2990  if (BackgroundPixel (green[row - 1][col - 1]))
2991  return false;
2992  }
2993 
2994  if (BackgroundPixel (green[row - 1][col]))
2995  return false;
2996 
2997  if (col < (width - 1))
2998  {
2999  if (BackgroundPixel (green[row - 1][col + 1]))
3000  return false;
3001  }
3002  }
3003 
3004  if (col > 0)
3005  {
3006  if (BackgroundPixel (green[row][col - 1]))
3007  return false;
3008  }
3009 
3010  if (BackgroundPixel (green[row][col]))
3011  return false;
3012 
3013  if (col < (width - 1))
3014  {
3015  if (BackgroundPixel (green[row][col + 1]))
3016  return false;
3017  }
3018 
3019  if (row < height - 1)
3020  {
3021  if (col > 0)
3022  {
3023  if (BackgroundPixel (green[row + 1][col - 1]))
3024  return false;
3025  }
3026 
3027  if (BackgroundPixel (green[row + 1][col]))
3028  return false;
3029 
3030  if (row < (width - 1))
3031  {
3032  if (BackgroundPixel (green[row + 1][col + 1]))
3033  return false;
3034  }
3035  }
3036 
3037  return true;
3038 } /* CompletlyFilled3By3 */
3039 
3040 
3041 
3042 
3043 void Raster::Edge ()
3044 {
3045  Raster orig (*this);
3046  orig.Edge (this);
3047 } /* Edge */
3048 
3049 
3050 
3051 
3052 void Raster::Edge (RasterPtr dest)
3053 {
3054  if ((dest->Height () != height) | (dest->Width () != width))
3055  dest->ReSize (height, width, false);
3056 
3057  kkint32 r;
3058  kkint32 c;
3059 
3060  kkint32 lastRow = height - 1;
3061  kkint32 lastCol = width - 1;
3062 
3063  uchar** origRows = Green ();
3064 
3065  uchar* origRowLast = NULL;
3066  uchar* origRowCur = NULL;
3067  uchar* origRowNext = NULL;
3068 
3069  kkint32 pixelCount = 0;
3070 
3071  uchar* destArea = dest->GreenArea ();
3072  uchar** destRows = dest->Green ();
3073 
3074  for (r = 1; r < lastRow; ++r)
3075  {
3076  origRowLast = origRows[r - 1];
3077  origRowCur = origRows[r];
3078  origRowNext = origRows[r + 1];
3079 
3080  uchar* destRow = destRows[r];
3081 
3082  for (c = 1; c < lastCol; c++)
3083  {
3084  if (ForegroundPixel (origRowCur[c]))
3085  {
3086  if ((ForegroundPixel (origRowLast [c - 1])) &&
3087  (ForegroundPixel (origRowLast [c] )) &&
3088  (ForegroundPixel (origRowLast [c + 1])) &&
3089  (ForegroundPixel (origRowCur [c - 1])) &&
3090  (ForegroundPixel (origRowCur [c] )) &&
3091  (ForegroundPixel (origRowCur [c + 1])) &&
3092  (ForegroundPixel (origRowNext [c - 1])) &&
3093  (ForegroundPixel (origRowNext [c] )) &&
3094  (ForegroundPixel (origRowNext [c + 1]))
3095  )
3096  {
3097  destRow[c] = backgroundPixelValue;
3098  }
3099  else
3100  {
3101  destRow[c] = foregroundPixelValue;
3102  ++pixelCount;
3103  }
3104  }
3105  }
3106  }
3107 
3108  dest->foregroundPixelCount = pixelCount;
3109 } /* Edge */
3110 
3111 
3112 
3113 
3114 
3115 inline
3117  kkint32 col
3118  ) const
3119 {
3120  if ((row < 0) || (row >= height) ||
3121  (col < 0) || (col >= width))
3122  return -1;
3123 
3124  if (!blobIds)
3125  return -1;
3126 
3127  return blobIds[row][col];
3128 }
3129 
3130 
3131 
3132 kkint32 Raster::NearestNeighborUpperLeft (kkint32 row,
3133  kkint32 col,
3134  kkint32 dist
3135  )
3136 {
3137  kkint32 nearestBlob = -1;
3138  kkint32 c, r, startCol, blobID;
3139 
3140  startCol = col - 1;
3141 
3142  for (r = row - dist; r < row; ++r)
3143  {
3144  if (r >= 0)
3145  {
3146  for (c = startCol; c <= col; ++c)
3147  {
3148  if (c >= 0)
3149  {
3150  blobID = BlobId (r, c);
3151  if (blobID > nearestBlob)
3152  nearestBlob = blobID;
3153  }
3154  }
3155  }
3156 
3157  startCol--;
3158  }
3159 
3160  return nearestBlob;
3161 } /* NearestNeighborUpperLeft */
3162 
3163 
3164 
3165 
3166 inline
3167 kkint32 Raster::NearestNeighborUpperRight (kkint32 row,
3168  kkint32 col,
3169  kkint32 dist
3170  )
3171 {
3172  kkint32 nearestBlob = -1;
3173  kkint32 r, c, endCol, blobID;
3174 
3175  endCol = col + 1;
3176  for (r = row - dist; r < row; ++r)
3177  {
3178  if (r >= 0)
3179  {
3180  if (endCol >= width)
3181  endCol = width - 1;
3182 
3183  for (c = col + 1; c <= endCol; ++c)
3184  {
3185  blobID = BlobId (r, c);
3186  if (blobID > nearestBlob)
3187  nearestBlob = blobID;
3188  }
3189  }
3190 
3191  endCol++;
3192  }
3193 
3194  return nearestBlob;
3195 } /* NearestNeighborUpperRight */
3196 
3197 
3198 
3199 
3200 BlobListPtr Raster::ExtractBlobs (kkint32 dist)
3201 {
3202  uchar* curRow = NULL;
3203  kkint32* curRowBlobIds = NULL;
3204 
3205  kkint32 col = 2;
3206  kkint32 row = 2;
3207 
3208  BlobPtr curBlob = NULL;
3209  kkint32 curBlobId = 0;
3210  kkint32 nearBlobId = 0;
3211 
3212  kkint32 blankColsInARow = 0;
3213 
3214  AllocateBlobIds ();
3215 
3216  BlobListPtr blobs = new BlobList (true);
3217 
3218  for (row = 0; row < height; ++row)
3219  {
3220  curRow = green[row];
3221  curRowBlobIds = blobIds[row];
3222 
3223  curBlob = NULL;
3224 
3225  col = 0;
3226  while (col < width)
3227  {
3228  if (ForegroundPixel (curRow[col]))
3229  {
3230  blankColsInARow = 0;
3231 
3232  nearBlobId = NearestNeighborUpperLeft (row, col, dist);
3233  if (nearBlobId < 0)
3234  nearBlobId = NearestNeighborUpperRight (row, col, dist);
3235 
3236 
3237  if (curBlob)
3238  {
3239  if (nearBlobId >= 0)
3240  {
3241  if (nearBlobId != curBlobId)
3242  {
3243  curBlob = blobs->MergeIntoSingleBlob (curBlob, nearBlobId, blobIds);
3244  curBlobId = curBlob->Id ();
3245  }
3246  }
3247 
3248  curRowBlobIds[col] = curBlobId;
3249  curBlob->colRight = Max (curBlob->colRight, col);
3250  curBlob->rowBot = Max (curBlob->rowBot, row);
3251  curBlob->pixelCount++;
3252  }
3253  else
3254  {
3255  // No Current Blob
3256  if (nearBlobId >= 0)
3257  {
3258  curBlob = blobs->LookUpByBlobId (nearBlobId);
3259  if (curBlob)
3260  curBlobId = curBlob->id;
3261  else
3262  {
3263  // If we get to this point there is something wrong with the 'blobs' data structure; for every blobId
3264  // specified in blobIds(via nearBlobId) there should be a entry in 'blobs'.
3265  curBlob = blobs->NewBlob(row, col);
3266  if (!curBlob) throw KKException(" Raster::ExtractBlobs curBlob == NULL");
3267 
3268  curBlobId = curBlob->id;
3269  }
3270  }
3271  else
3272  {
3273  curBlob = blobs->NewBlob (row, col);
3274  if (!curBlob)
3275  {
3276  KKStr errMsg = "Raster::ExtractBlobs ***ERROR*** allocation of new 'curBlob' failed.";
3277  cerr << endl << errMsg << endl << endl;
3278  throw KKException (errMsg);
3279  }
3280  curBlobId = curBlob->id;
3281  }
3282 
3283  curRowBlobIds[col] = curBlobId;
3284  curBlob->colLeft = Min (curBlob->colLeft, col);
3285  curBlob->colRight = Max (curBlob->colRight, col);
3286  curBlob->rowBot = Max (curBlob->rowBot, row);
3287  curBlob->rowTop = Min (curBlob->rowTop, row);
3288  curBlob->pixelCount++;
3289  }
3290  }
3291  else
3292  {
3293  // Background Pixel
3294  if (curBlob)
3295  {
3296  nearBlobId = NearestNeighborUpperLeft (row, col, dist);
3297 
3298  if (nearBlobId >= 0)
3299  {
3300  if (nearBlobId != curBlobId)
3301  {
3302  curBlob = blobs->MergeIntoSingleBlob (curBlob, nearBlobId, blobIds);
3303  curBlobId = curBlob->Id ();
3304  }
3305  }
3306  }
3307 
3308  blankColsInARow++;
3309  if (blankColsInARow > dist)
3310  {
3311  curBlob = NULL;
3312  curBlobId = -1;
3313  }
3314  }
3315 
3316  col++;
3317  }
3318  }
3319 
3320  return blobs;
3321 } /* ExtractBlobs */
3322 
3323 
3324 
3325 
3326 
3327 /**
3328  @brief Returns image where each blob is labeled with a different color.
3329  @details Only useful if 'ExtractBlobs' was performed on this instance.
3330  */
3331 RasterPtr Raster::CreateColorWithBlobsLabeldByColor (BlobListPtr blobs)
3332 {
3334  if (blobs == NULL)
3335  return colorImage;
3336 
3337  if (blobIds == NULL)
3338  return colorImage;
3339 
3340  BlobList::iterator idx;
3341  for (idx = blobs->begin (); idx != blobs->end (); ++idx)
3342  {
3343  BlobPtr blob = idx->second;
3344  kkint32 blobId = blob->Id ();
3345  kkint32 row = 0, col = 0;
3346 
3347  PixelValue color;
3348  switch (blobId % 8)
3349  {
3350  case 0: color = PixelValue::Red; break;
3351  case 1: color = PixelValue::Green; break;
3352  case 2: color = PixelValue::Blue; break;
3353  case 3: color = PixelValue::Yellow; break;
3354  case 4: color = PixelValue::Orange; break;
3355  case 5: color = PixelValue::Magenta; break;
3356  case 6: color = PixelValue::Purple; break;
3357  case 7: color = PixelValue::Teal; break;
3358  }
3359 
3360  kkint32 rowStart = Min (blob->RowTop (), height - 1);
3361  kkint32 rowEnd = Min (blob->RowBot (), height - 1);
3362  kkint32 colStart = Min (blob->ColLeft (), width - 1);
3363  kkint32 colEnd = Min (blob->ColRight (), width - 1);
3364 
3365  for (row = rowStart; row <= rowEnd; ++row)
3366  {
3367  for (col = colStart; col <= colEnd; ++col)
3368  {
3369  if (blobIds[row][col] == blobId)
3370  {
3371  colorImage->SetPixelValue (row, col, color);
3372  }
3373  }
3374  }
3375  }
3376 
3377  return colorImage;
3378 } /* CreateColorWithBlobsLabeldByColor*/
3379 
3380 
3381 
3383  BlobListPtr blobs
3384  )
3385 {
3387  if (blobs == NULL)
3388  return resultImage;
3389 
3390  if (blobIds == NULL)
3391  return resultImage;
3392 
3393  BlobList::iterator idx;
3394  for (idx = blobs->begin (); idx != blobs->end (); ++idx)
3395  {
3396  BlobPtr blob = idx->second;
3397  kkint32 blobId = blob->Id ();
3398  kkint32 row = 0, col = 0;
3399 
3400  kkint32 rowStart = Min (blob->RowTop (), height - 1);
3401  kkint32 rowEnd = Min (blob->RowBot (), height - 1);
3402  kkint32 colStart = Min (blob->ColLeft (), width - 1);
3403  kkint32 colEnd = Min (blob->ColRight (), width - 1);
3404 
3405  PixelValue pixelValue;
3406 
3407  for (row = rowStart; row <= rowEnd; ++row)
3408  {
3409  for (col = colStart; col <= colEnd; ++col)
3410  {
3411  if (blobIds[row][col] == blobId)
3412  {
3413  origImage->GetPixelValue (row, col, pixelValue);
3414  resultImage->SetPixelValue (row, col, pixelValue);
3415  }
3416  }
3417  }
3418  }
3419 
3420  return resultImage;
3421 } /* CreateFromOrginalImageWithSpecifidBlobsOnly*/
3422 
3423 
3424 
3425 
3426 
3427 void Raster::DeleteExistingBlobIds ()
3428 {
3429  if (blobIds != NULL)
3430  {
3431  // Already been allocated, just need to reset then
3432  for (kkint32 row = 0; row < height; row++)
3433  {
3434  delete blobIds[row];
3435  blobIds[row] = NULL;
3436  }
3437 
3438  delete blobIds;
3439  blobIds = NULL;
3440  }
3441 } /* DeleteExistingBlobIds */
3442 
3443 
3444 
3445 void Raster::AllocateBlobIds ()
3446 {
3447  kkint32 row, col;
3448 
3449  DeleteExistingBlobIds ();
3450 
3451  blobIds = new kkint32*[height];
3452 
3453  for (row = 0; row < height; row++)
3454  {
3455  blobIds[row] = new kkint32[width];
3456  for (col = 0; col < width; col++)
3457  {
3458  blobIds[row][col] = -1;
3459  }
3460  }
3461 } /* AllocateBlobIds */
3462 
3463 
3464 
3465 
3466 void Raster::ConnectedComponent (uchar connectedComponentDist)
3467 {
3468  if (connectedComponentDist < 1)
3469  connectedComponentDist = 3;
3470 
3471  kkint32 row = 0, col = 0;
3472 
3473  BlobListPtr blobs = ExtractBlobs (connectedComponentDist);
3474 
3475  BlobPtr largestBlob = blobs->LocateLargestBlob ();
3476  if (largestBlob)
3477  {
3478  kkint32 blobId = largestBlob->Id ();
3479 
3480  uchar* newImageArea = new uchar[totPixels];
3481  memset (newImageArea, 0, totPixels);
3482  uchar* newImageAreaPtr = newImageArea;
3483 
3484  uchar** newRows = new uchar*[height];
3485 
3486  for (row = 0; row < height; row++)
3487  {
3488  newRows[row] = newImageAreaPtr;
3489 
3490  for (col = 0; col < width; col++)
3491  {
3492  if (blobIds[row][col] == blobId)
3493  {
3494  newRows[row][col] = green[row][col];
3495  }
3496  }
3497 
3498  newImageAreaPtr = newImageAreaPtr + width;
3499  }
3500 
3501  delete green;
3502  delete greenArea;
3503 
3504  greenArea = newImageArea;
3505  green = newRows;
3506  }
3507 
3508  for (row = 0; row < height; row++)
3509  delete blobIds[row];
3510  delete blobIds;
3511  blobIds = NULL;
3512 
3513  delete blobs; blobs = NULL;
3514 
3515  return;
3516 } /* ConnectedComponent */
3517 
3518 
3519 
3520 
3521 
3522 void Raster::ReduceToMostCompleteBlob (uchar connectedComponentDist)
3523 {
3524  if (connectedComponentDist < 1)
3525  connectedComponentDist = 3;
3526 
3527  kkint32 row = 0, col = 0;
3528 
3529  BlobListPtr blobs = ExtractBlobs (connectedComponentDist);
3530 
3531  BlobPtr largestBlob = blobs->LocateMostComplete ();
3532  if (largestBlob)
3533  {
3534  kkint32 blobId = largestBlob->Id ();
3535 
3536  uchar* newImageArea = new uchar[totPixels];
3537  memset (newImageArea, 0, totPixels);
3538  uchar* newImageAreaPtr = newImageArea;
3539 
3540  uchar** newRows = new uchar*[height];
3541 
3542  for (row = 0; row < height; row++)
3543  {
3544  newRows[row] = newImageAreaPtr;
3545 
3546  for (col = 0; col < width; col++)
3547  {
3548  if (blobIds[row][col] == blobId)
3549  {
3550  newRows[row][col] = green[row][col];
3551  }
3552  }
3553 
3554  newImageAreaPtr = newImageAreaPtr + width;
3555  }
3556 
3557  delete green;
3558  delete greenArea;
3559 
3560  greenArea = newImageArea;
3561  green = newRows;
3562  }
3563 
3564  for (row = 0; row < height; row++)
3565  delete blobIds[row];
3566  delete blobIds;
3567  blobIds = NULL;
3568 
3569  delete blobs; blobs = NULL;
3570 
3571  return;
3572 } /* ReduceToMostCompleteBlob */
3573 
3574 
3575 
3576 
3578 {
3579  uchar* curRow = NULL;
3580  kkint32* curRowBlobIds = NULL;
3581  kkint32* prevRowBlobIds = NULL;
3582 
3583  kkint32 col = 2;
3584  kkint32 row = 2;
3585 
3586  BlobPtr curBlob = NULL;
3587  kkint32 curBlobId = 0;
3588  kkint32 nearBlobId = 0;
3589 
3590  kkint32 blankColsInARow = 0;
3591 
3592  // Initialize Blob ID's
3593 
3594  blobIds = new kkint32*[height];
3595 
3596  for (row = 0; row < height; row++)
3597  {
3598  blobIds[row] = new kkint32[width];
3599  for (col = 0; col < width; col++)
3600  {
3601  blobIds[row][col] = -1;
3602  }
3603  }
3604 
3605  BlobListPtr blobs = new BlobList (true);
3606 
3607  for (row = 1; row < height - 1; row++)
3608  {
3609  curRow = green[row];
3610  curRowBlobIds = blobIds[row];
3611  prevRowBlobIds = blobIds[row - 1];
3612 
3613 
3614  curBlob = NULL;
3615 
3616  col = 1;
3617  while (col < (width - 1))
3618  {
3619  if (ForegroundPixel (curRow[col]))
3620  {
3621  blankColsInARow = 0;
3622 
3623  nearBlobId = Max (prevRowBlobIds[col - 1],
3624  prevRowBlobIds[col],
3625  prevRowBlobIds[col + 1]
3626  );
3627  if (curBlob)
3628  {
3629  if (nearBlobId >= 0)
3630  {
3631  if (nearBlobId != curBlobId)
3632  {
3633  blobs->MergeBlobIds (curBlob, nearBlobId, blobIds);
3634  }
3635  }
3636 
3637  curRowBlobIds[col] = curBlobId;
3638  curBlob->colRight = Max (curBlob->colRight, col);
3639  curBlob->rowBot = Max (curBlob->rowBot, row);
3640  curBlob->pixelCount++;
3641  }
3642  else
3643  {
3644  // No Current Blob
3645  if (nearBlobId >= 0)
3646  {
3647  curBlob = blobs->LookUpByBlobId (nearBlobId);
3648  curBlobId = curBlob->id;
3649  }
3650  else
3651  {
3652  curBlob = blobs->NewBlob (row, col);
3653  curBlobId = curBlob->id;
3654  }
3655 
3656  curRowBlobIds[col] = curBlobId;
3657  curBlob->colLeft = Min (curBlob->colLeft, col);
3658  curBlob->colRight = Max (curBlob->colRight, col);
3659  curBlob->rowBot = Max (curBlob->rowBot, row);
3660  curBlob->rowTop = Min (curBlob->rowTop, row);
3661  curBlob->pixelCount++;
3662  }
3663  }
3664  else
3665  {
3666  blankColsInARow++;
3667  curBlob = NULL;
3668  curBlobId = -1;
3669  }
3670 
3671  col++;
3672  }
3673  }
3674 
3675  BlobPtr largestBlob = blobs->LocateLargestBlob ();
3676  if (largestBlob)
3677  {
3678  kkint32 blobId = largestBlob->Id ();
3679 
3680  uchar* newImageArea = new uchar[totPixels];
3681  memset (newImageArea, 0, totPixels);
3682  uchar* newImageAreaPtr = newImageArea;
3683 
3684  uchar** newRows = new uchar*[height];
3685 
3686  for (row = 0; row < height; row++)
3687  {
3688  newRows[row] = newImageAreaPtr;
3689 
3690  for (col = 0; col < width; col++)
3691  {
3692  if (blobIds[row][col] == blobId)
3693  {
3694  newRows[row][col] = green[row][col];
3695  }
3696  }
3697 
3698  newImageAreaPtr = newImageAreaPtr + width;
3699  }
3700 
3701  delete green;
3702  delete greenArea;
3703 
3704  greenArea = newImageArea;
3705  green = newRows;
3706  }
3707 
3708  for (row = 0; row < height; row++)
3709  delete blobIds[row];
3710  delete blobIds;
3711  blobIds = NULL;
3712 
3713  delete blobs; blobs = NULL;
3714 
3715  return;
3716 } /* ConnectedComponent8Conected */
3717 
3718 
3719 
3720 
3721 
3722 RasterPtr Raster::ExtractABlobTightly (const BlobPtr blob,
3723  kkint32 padding
3724  ) const
3725 {
3726  if (blob == NULL)
3727  return NULL;
3728 
3729  RasterPtr blobRaster = AllocateARasterInstance (blob->Height () + 2 * padding, blob->Width () + 2 * padding, color);
3730 
3731  kkint32 blobRow = padding;
3732  kkint32 blobCol = padding;
3733 
3734  kkint32 row = 0;
3735  kkint32 col = 0;
3736 
3737  for (row = blob->rowTop; row <= blob->rowBot; row++)
3738  {
3739  blobCol = padding;
3740  for (col = blob->colLeft; col <= blob->colRight; col++)
3741  {
3742  if (blobIds[row][col] == blob->id)
3743  {
3744  blobRaster->green[blobRow][blobCol] = green[row][col];
3745  if (color)
3746  {
3747  blobRaster->red [blobRow][blobCol] = red [row][col];
3748  blobRaster->blue[blobRow][blobCol] = blue[row][col];
3749  }
3750  }
3751  blobCol++;
3752  }
3753  blobRow++;
3754  }
3755  return blobRaster;
3756 } /* ExtractABlobTightly */
3757 
3758 
3759 
3760 
3761 RasterPtr Raster::ExtractABlob (const BlobPtr blob) const
3762 {
3764 
3765  kkint32 row;
3766  kkint32 col;
3767 
3768  for (row = blob->rowTop; row <= blob->rowBot; row++)
3769  {
3770  for (col = blob->colLeft; col <= blob->colRight; col++)
3771  {
3772  if (blobIds[row][col] == blob->id)
3773  {
3774  blobRaster->green[row][col] = green[row][col];
3775  if (color)
3776  {
3777  blobRaster->red [row][col] = red [row][col];
3778  blobRaster->blue[row][col] = blue[row][col];
3779  }
3780  }
3781  }
3782  }
3783 
3784  return blobRaster;
3785 } /* ExtractABlob */
3786 
3787 
3788 
3790 {
3791  kkint32 r, c;
3792 
3793  kkint32 area = 0;
3794 
3795  maxPixVal = 0;
3796 
3797  uchar pixVal;
3798 
3799  for (r = 0; r < height; r++)
3800  {
3801  for (c = 0; c < width; c++)
3802  {
3803  pixVal = green[r][c];
3804 
3805  if (ForegroundPixel (pixVal))
3806  {
3807  area++;
3808 
3809  if (pixVal > maxPixVal)
3810  maxPixVal = pixVal;
3811  }
3812  }
3813  }
3814 
3815  foregroundPixelCount = area;
3816 
3817  return area;
3818 } /* CalcArea */
3819 
3820 
3821 
3822 
3823 
3824 
3826  kkuint32 intensityHistBuckets[8]
3827  )
3828 {
3829  kkint32 c;
3830  kkint32 r;
3831  kkint32 x;
3832 
3833  // We first need to determine what background pixels are not part of the image. We assume
3834  // that any background pixels that are connected to the border of the image are not part
3835  // of the image.
3836  Raster mask (*this);
3837  mask.FillHole ();
3838 
3839 
3840  area = 0;
3841  for (x = 0; x < 8; x++)
3842  intensityHistBuckets[x] = 0;
3843 
3844 
3845  // Now that we know what pixels are background that are connected to
3846  // one of the boarders, any other white pixel must be in a hole inside
3847  // the image.
3848  uchar* curRow = NULL;
3849  uchar* curMaskRow = NULL;
3850  uchar pixVal;
3851  for (r = 0; r < height; r++)
3852  {
3853  curMaskRow = mask.green[r];
3854  curRow = green[r];
3855  for (c = 0; c < width; c++)
3856  {
3857  if (ForegroundPixel (curMaskRow[c]))
3858  {
3859  area++;
3860  pixVal = curRow[c];
3861  if (pixVal > maxPixVal)
3862  maxPixVal = pixVal;
3863  intensityHistBuckets[freqHistBucketIdx[pixVal]]++;
3864  }
3865  }
3866  }
3867 } /* CalcAreaAndIntensityHistogramWhite */
3868 
3869 
3870 
3871 
3873  kkuint32 intensityHistBuckets[8]
3874  )
3875  const
3876 {
3877  kkint32 r, c;
3878 
3879  area = 0;
3880 
3881  for (kkint32 x = 0; x < 8; x++)
3882  intensityHistBuckets[x] = 0;
3883 
3884  maxPixVal = 0;
3885 
3886  uchar pixVal;
3887 
3888  for (r = 0; r < height; r++)
3889  {
3890  for (c = 0; c < width; c++)
3891  {
3892  pixVal = green[r][c];
3893 
3894  if (ForegroundPixel (pixVal))
3895  {
3896  area++;
3897 
3898  if (pixVal > maxPixVal)
3899  maxPixVal = pixVal;
3900 
3901  intensityHistBuckets[freqHistBucketIdx[pixVal]]++;
3902  }
3903  }
3904  }
3905 
3906  foregroundPixelCount = area;
3907 } /* CalcAreaAndIntensityHistogram */
3908 
3909 
3910 
3911 
3913  float& weightedSize,
3914  kkuint32 intensityHistBuckets[8],
3915  kkint32& areaWithWhiteSpace,
3916  kkuint32 intensityHistBucketsWhiteSpace[8]
3917  )
3918  const
3919 {
3920  kkint32 x;
3921 
3922  // We first need to determine what background pixels are not part of the image. We assume
3923  // that any background pixels that are connected to the border of the image are not part
3924  // of the image.
3925  Raster mask (*this);
3926  mask.FillHole ();
3927 
3928  long totalPixelValues = 0;
3929 
3930  area = 0;
3931  weightedSize = 0.0f;
3932  areaWithWhiteSpace = 0;
3933 
3934 
3935  for (x = 0; x < 8; x++)
3936  {
3937  intensityHistBuckets[x] = 0;
3938  intensityHistBucketsWhiteSpace[x] = 0;
3939  }
3940 
3941 
3942  maxPixVal = 0;
3943  uchar pixVal;
3944 
3945  uchar* maskGreenArea = mask.GreenArea ();
3946 
3947  for (x = 0; x < totPixels; x++)
3948  {
3949  pixVal = greenArea [x];
3950  if (ForegroundPixel (maskGreenArea[x]))
3951  {
3952  areaWithWhiteSpace++;
3953  if (pixVal > maxPixVal)
3954  maxPixVal = pixVal;
3955  intensityHistBucketsWhiteSpace[freqHistBucketIdx[pixVal]]++;
3956 
3957  if (ForegroundPixel (pixVal))
3958  {
3959  area++;
3960  intensityHistBuckets[freqHistBucketIdx[pixVal]]++;
3961  totalPixelValues += pixVal;
3962  }
3963  }
3964  }
3965 
3966  foregroundPixelCount = area;
3967 
3968  weightedSize = (float)totalPixelValues / (float)maxPixVal;
3969 } /* CalcAreaAndIntensityFeatures */
3970 
3971 
3972 
3973 
3974 
3976  float& weighedSize,
3977  kkuint32 intensityHistBuckets[16]
3978  )
3979 {
3980  kkint32 x;
3981 
3982  long totalPixelValues = 0;
3983 
3984  area = 0;
3985  weighedSize = 0.0f;
3986  maxPixVal = 0;
3987 
3988  for (x = 0; x < 16; x++)
3989  {
3990  intensityHistBuckets[x] = 0;
3991  }
3992 
3993  maxPixVal = 0;
3994  uchar pixVal;
3995 
3996  for (x = 0; x < totPixels; x++)
3997  {
3998  pixVal = greenArea [x];
3999  if (pixVal > maxPixVal)
4000  maxPixVal = pixVal;
4001  if (ForegroundPixel (pixVal))
4002  {
4003  area++;
4004  intensityHistBuckets[freqHist16BucketIdx[pixVal]]++;
4005  totalPixelValues += pixVal;
4006  }
4007  }
4008 
4009  foregroundPixelCount = area;
4010 
4011  weighedSize = (float)totalPixelValues / (float)maxPixVal;
4012 } /* CalcAreaAndIntensityFeatures16 */
4013 
4014 
4015 
4016 
4017 
4019  float& weightedSize,
4020  kkuint32 intensityHistBuckets[8]
4021  )
4022  const
4023 {
4024  kkint32 x;
4025 
4026  long totalPixelValues = 0;
4027 
4028  area = 0;
4029  weightedSize = 0.0f;
4030 
4031  for (x = 0; x < 8; x++)
4032  intensityHistBuckets[x] = 0;
4033 
4034  maxPixVal = 0;
4035  uchar pixVal;
4036 
4037  for (x = 0; x < totPixels; x++)
4038  {
4039  pixVal = greenArea [x];
4040  if (pixVal > 0)
4041  {
4042  if (pixVal > maxPixVal)
4043  maxPixVal = pixVal;
4044  area++;
4045  intensityHistBuckets[freqHistBucketIdx[pixVal]]++;
4046  totalPixelValues += pixVal;
4047  }
4048  }
4049 
4050  foregroundPixelCount = area;
4051 
4052  weightedSize = (float)totalPixelValues / (float)255.0f;
4053 } /* CalcAreaAndIntensityFeatures */
4054 
4055 
4056 
4057 
4058 
4059 
4060 float Raster::CalcWeightedArea () const
4061 {
4062  kkint32 r, c;
4063 
4064  float area = 0;
4065 
4066  uchar pixVal = 0;
4067  kkint32 maxPixValFound = 0;
4068 
4069  //foregroundPixelCount = 0;
4070 
4071  for (r = 0; r < height; r++)
4072  {
4073  for (c = 0; c < width; c++)
4074  {
4075  pixVal = green[r][c];
4076  if (ForegroundPixel (pixVal))
4077  {
4078  area = area + (float)pixVal;
4079  if (pixVal > maxPixValFound)
4080  maxPixValFound = pixVal;
4081  }
4082  }
4083  }
4084 
4085  area = area / (float)maxPixValFound;
4086 
4087  return area;
4088 } /* CalcWeightedArea */
4089 
4090 
4091 
4092 
4093 
4094 /**
4095  *@brief returns in 'features' the 8 central moments as defined by Hu plus eccentricity in the eight bucket.
4096  *@details See M. K. Hu, Visual pattern recognition by moment invariants IRE Trans; Inform. Theory, vol. IT, no. 8, pp. 179�187, 1962.
4097  *@param[in] features A array with 9 elements (0 through 8) that will receive the 8 central moments as defined by HU plus eccentricity
4098  * in the eighth element.
4099  */
4100 void Raster::CentralMoments (float features[9]) const
4101 {
4102  kkint64 m00, m10, m01;
4103  Moment (m00, m10, m01);
4104 
4105  centroidCol = (float)m10 / (float)m00; // Center Col
4106  centroidRow = (float)m01 / (float)m00; // Center Row
4107 
4109 
4110  float cm00 = (float)m00;
4111  float gamma2 = (float)m00 * (float)m00;
4112  float gamma3 = gamma2 * (float)sqrt ((float)m00);
4113 
4114  float cm20 = 0.0;
4115  float cm02 = 0.0;
4116  float cm11 = 0.0;
4117 
4118  float cm30 = 0.0;
4119  float cm03 = 0.0;
4120  float cm12 = 0.0;
4121  float cm21 = 0.0;
4122 
4123  {
4124  float cm = 0.0;
4125  kkint32 col;
4126  kkint32 row;
4127 
4128  float deltaCol = 0.0f;
4129  float deltaRow = 0.0f;
4130 
4131  for (row = 0; row < height; ++row)
4132  {
4133  deltaRow = row - centroidRow;
4134  float rowPow0 = 1.0;
4135  float rowPow1 = deltaRow;
4136  float rowPow2 = deltaRow * deltaRow;
4137  float rowPow3 = rowPow2 * deltaRow;
4138  uchar* rowData = green[row];
4139  for (col = 0; col < width; ++col)
4140  {
4141  if (rowData[col] > backgroundPixelTH)
4142  {
4143  deltaCol = (float)col - centroidCol;
4144  float colPow0 = 1.0f;
4145  float colPow1 = deltaCol;
4146  float colPow2 = deltaCol * deltaCol;
4147  float colPow3 = colPow2 * deltaCol;
4148 
4149  cm20 += colPow2 * rowPow0;
4150  cm02 += colPow0 * rowPow2;
4151  cm11 += colPow1 * rowPow1;
4152  cm30 += colPow3 * rowPow0;
4153  cm03 += colPow0 * rowPow3;
4154 
4155  cm12 += colPow1 * rowPow2;
4156  cm21 += colPow2 * rowPow1;
4157  }
4158  }
4159  }
4160  }
4161 
4162  cm20 = cm20 / gamma2;
4163  cm02 = cm02 / gamma2;
4164  cm11 = cm11 / gamma2;
4165 
4166  cm30 = cm30 / gamma3;
4167  cm03 = cm03 / gamma3;
4168  cm12 = cm12 / gamma3;
4169  cm21 = cm21 / gamma3;
4170 
4171  features[0] = cm00;
4172 
4173  features[1] = cm20 + cm02;
4174 
4175  features[2] = (cm20 - cm02) * (cm20 - cm02) +
4176  4.0f * cm11 * cm11;
4177 
4178  features[3] = (cm30 - 3.0f * cm12) * (cm30 - 3.0f * cm12) +
4179  (3.0f * cm21 - cm03) * (3.0f * cm21 - cm03);
4180 
4181  features[4] = (cm30 + cm12) * (cm30 + cm12) + (cm21 + cm03) * (cm21 + cm03);
4182 
4183  features[5] = (cm30 - 3.0f * cm12) * (cm30 + cm12) * ((cm30 + cm12) * (cm30 + cm12) -
4184  3.0f * (cm21 + cm03) * (cm21 + cm03)) + (3.0f * cm21 - cm03) * (cm21 + cm03) *
4185  (3.0f * (cm30 + cm12) * (cm30 + cm12) - (cm21 + cm03) * (cm21 + cm03));
4186 
4187  features[6] = (cm20 - cm02) *
4188  ((cm30 + cm12) * (cm30 + cm12) - (cm21 + cm03) * (cm21 + cm03))
4189  + 4.0f * cm11 * (cm30 + cm12) * (cm21 + cm03);
4190 
4191  features[7] = (3.0f * cm21 - cm03) * (cm30 + cm12) *
4192  ((cm30 + cm12) * (cm30 + cm12) - 3.0f * (cm21 + cm03) * (cm21 + cm03) )
4193  -(cm30 - 3.0f * cm12) * (cm21 + cm03) *
4194  (3.0f * (cm30 + cm12) * (cm30 + cm12) - (cm21 + cm03) * (cm21 + cm03) );
4195 
4196  //added by baishali to calculate eccentricity
4197  features[8] = (((cm20 - cm02) * (cm20 - cm02)) -
4198  (4.0f * cm11 * cm11))/((cm20 + cm02) * (cm20 + cm02));
4199 
4200 
4201  return;
4202 } /* CentralMoments */
4203 
4204 
4205 
4206 
4207 void Raster::Moment (kkint64& m00,
4208  kkint64& m10,
4209  kkint64& m01
4210  ) const
4211 {
4212  m00 = 0;
4213  m10 = 0;
4214  m01 = 0;
4215 
4216  kkint32 col;
4217  kkint32 row;
4218 
4219  for (row = 0; row < height; ++row)
4220  {
4221  uchar* rowData = green[row];
4222  for (col = 0; col < width; ++col)
4223  {
4224  if (rowData[col] > backgroundPixelTH)
4225  {
4226  ++m00;
4227  m10 = m10 + col;
4228  m01 = m01 + row;
4229  }
4230  }
4231  }
4232 } /* Moment */
4233 
4234 
4235 
4236 
4237 /**
4238  *@brief Similar to 'CentralMoments' except each pixel position is weighted by its intensity value.
4239  *@details See M. K. Hu, Visual pattern recognition by moment invariants IRE Trans; Inform. Theory, vol. IT, no. 8, pp. 179, 187, 1962.
4240  *@param[in] features A array with 9 elements (0 through 8) that will receive the 8 central moments as defined by HU plus eccentricity
4241  * in the eighth element.
4242  */
4243 void Raster::CentralMomentsWeighted (float features[9]) const
4244 {
4245 
4246  float m00, m10, m01;
4247  MomentWeighted (m00, m10, m01);
4248 
4249  float ew = m10 / m00;
4250  float eh = m01 / m00;
4251 
4252  float cm00 = m00;
4253  float gamma2 = m00 * m00;
4254  float gamma3 = gamma2 * (float)sqrt (m00);
4255 
4256  float cm20 = 0.0f;
4257  float cm02 = 0.0f;
4258  float cm11 = 0.0f;
4259 
4260  float cm30 = 0.0f;
4261  float cm03 = 0.0f;
4262  float cm12 = 0.0f;
4263  float cm21 = 0.0f;
4264 
4265  {
4266  float cm = 0.0;
4267  kkint32 col;
4268  kkint32 row;
4269 
4270  kkint32 maxPixVal = 0;
4271 
4272  for (row = 0; row < height; ++row)
4273  {
4274  uchar* rowData = green[row];
4275  float deltaRow = row - eh;
4276 
4277  float rowPow0 = 1;
4278  float rowPow1 = deltaRow;
4279  float rowPow2 = deltaRow * deltaRow;
4280  float rowPow3 = rowPow2 * deltaRow;
4281 
4282  for (col = 0; col < width; ++col)
4283  {
4284  uchar pv = rowData[col];
4285  if (pv > backgroundPixelTH)
4286  {
4287  if (pv > maxPixVal)
4288  maxPixVal = pv;
4289 
4290  float deltaCol = col - ew;
4291  float colPow0 = 1;
4292  float colPow1 = deltaCol;
4293  float colPow2 = deltaCol * deltaCol;
4294  float colPow3 = colPow2 * deltaCol;
4295 
4296  float pvFloat = (float)pv;
4297 
4298  cm20 += pvFloat * colPow2 * rowPow0;
4299  cm02 += pvFloat * colPow0 * rowPow2;
4300  cm30 += pvFloat * colPow3 * rowPow0;
4301  cm03 += pvFloat * colPow0 * rowPow3;
4302  cm12 += pvFloat * colPow1 * rowPow2;
4303  cm21 += pvFloat * colPow2 * rowPow1;
4304  }
4305  }
4306  }
4307 
4308  cm20 = cm20 / (float)maxPixVal;
4309  cm02 = cm02 / (float)maxPixVal;
4310  cm30 = cm30 / (float)maxPixVal;
4311  cm03 = cm03 / (float)maxPixVal;
4312  cm12 = cm12 / (float)maxPixVal;
4313  cm21 = cm21 / (float)maxPixVal;
4314  }
4315 
4316  cm20 = cm20 / gamma2;
4317  cm02 = cm02 / gamma2;
4318  cm11 = cm11 / gamma2;
4319 
4320  cm30 = cm30 / gamma3;
4321  cm03 = cm03 / gamma3;
4322  cm12 = cm12 / gamma3;
4323  cm21 = cm21 / gamma3;
4324 
4325  features[0] = cm00;
4326 
4327  features[1] = cm20 + cm02;
4328 
4329  features[2] = (cm20 - cm02) * (cm20 - cm02) + (float)4.0 * cm11 * cm11;
4330 
4331  features[3] = (cm30 - (float)3.0 * cm12) *
4332  (cm30 - (float)3.0 * cm12) +
4333  ((float)3.0 * cm21 - cm03) *
4334  ((float)3.0 * cm21 - cm03);
4335 
4336  features[4] = (cm30 + cm12) * (cm30 + cm12) + (cm21 + cm03) * (cm21 + cm03);
4337 
4338  features[5] = (cm30 - (float)3.0 * cm12) * (cm30 + cm12) *
4339  ((cm30 + cm12) * (cm30 + cm12) -
4340  (float)3.0 * (cm21 + cm03) * (cm21 + cm03)) +
4341  ((float)3.0 * cm21 - cm03) * (cm21 + cm03) *
4342  ((float)3.0 * (cm30 + cm12) * (cm30 + cm12) -
4343  (cm21 + cm03) * (cm21 + cm03));
4344 
4345  features[6] = (cm20 - cm02) *
4346  (
4347  (cm30 + cm12) * (cm30 + cm12) -
4348  (cm21 + cm03) * (cm21 + cm03)
4349  ) +
4350  (float)4.0 * cm11 * (cm30 + cm12) * (cm21 + cm03);
4351 
4352  features[7] = ((float)3.0 * cm21 - cm03) *
4353  (cm30 + cm12) * ((cm30 + cm12) *
4354  (cm30 + cm12) - (float)3.0 *
4355  (cm21 + cm03) * (cm21 + cm03)) -
4356  (cm30 - (float)3.0 * cm12) *
4357  (cm21 + cm03) * ((float)3.0 *
4358  (cm30 + cm12) * (cm30 + cm12) -
4359  (cm21 + cm03) * (cm21 + cm03));
4360 
4361 //added by Baishali to calculate eccentricity
4362  features[8] = (float)((((cm20 - cm02) * (cm20 - cm02)) -
4363  (4.0 * cm11 * cm11))/((cm20 + cm02) * (cm20 + cm02)));
4364 
4365  return;
4366 } /* CentralMomentsWeighted */
4367 
4368 
4369 
4370 
4371 
4372 
4373 void Raster::MomentWeighted (float& m00,
4374  float& m10,
4375  float& m01
4376  ) const
4377 {
4378  m00 = 0.0f;
4379  m10 = 0.0f;
4380  m01 = 0.0f;
4381 
4382  kkint64 m00Int = 0;
4383  kkint64 m10Int = 0;
4384  kkint64 m01Int = 0;
4385 
4386  kkint32 col;
4387  kkint32 row;
4388 
4389  kkint32 maxPixVal = 0;
4390 
4391  for (row = 0; row < height; ++row)
4392  {
4393  uchar* rowData = green[row];
4394  for (col = 0; col < width; ++col)
4395  {
4396  uchar pv = rowData[col];
4397  if (pv > backgroundPixelTH)
4398  {
4399  m00Int += pv;
4400  m10Int = m10Int + col * pv;
4401  m01Int = m01Int + row * pv;
4402 
4403  if (pv > maxPixVal)
4404  maxPixVal = pv;
4405  }
4406  }
4407  }
4408 
4409  m00 = (float)m00Int / (float)maxPixVal;
4410  m10 = (float)m10Int / (float)maxPixVal;
4411  m01 = (float)m01Int / (float)maxPixVal;
4412 
4413  return;
4414 } /* MomentWeighted */
4415 
4416 
4417 
4418 void Raster::ComputeCentralMoments (kkint32& foregroundPixelCount,
4419  float& weightedPixelCount,
4420  float centralMoments[9],
4421  float centralMomentsWeighted[9]
4422  )
4423  const
4424 {
4425  kkint64 m00, m10, m01;
4426  float mw00, mw10, mw01;
4427  Moments (m00, m10, m01, mw00, mw10, mw01);
4428 
4429  foregroundPixelCount = (kkint32)m00;
4430  weightedPixelCount = mw00;
4431 
4432  centroidCol = (float)m10 / (float)m00;
4433  centroidRow = (float)m01 / (float)m00;
4434 
4435  float centroidColW = mw10 / mw00;
4436  float centroidRowW = mw01 / mw00;
4437 
4438  float cm00 = (float)m00;
4439  float gamma2 = (float)m00 * (float)m00;
4440  float gamma3 = gamma2 * (float)sqrt ((float)m00);
4441 
4442  float cm20 = 0.0;
4443  float cm02 = 0.0;
4444  float cm11 = 0.0;
4445 
4446  float cm30 = 0.0;
4447  float cm03 = 0.0;
4448  float cm12 = 0.0;
4449  float cm21 = 0.0;
4450 
4451  float cmw00 = mw00;
4452  float gammaW2 = (float)mw00 * (float)mw00;
4453  float gammaW3 = (float)gammaW2 * (float)sqrt ((float)mw00);
4454 
4455  float cmw20 = 0.0f;
4456  float cmw02 = 0.0f;
4457  float cmw11 = 0.0f;
4458 
4459  float cmw30 = 0.0f;
4460  float cmw03 = 0.0f;
4461  float cmw12 = 0.0f;
4462  float cmw21 = 0.0f;
4463 
4464  {
4465  float cmw = 0.0;
4466  float cm = 0.0;
4467  kkint32 col;
4468  kkint32 row;
4469 
4470  float deltaCol = 0.0f;
4471  float deltaRow = 0.0f;
4472 
4473  kkint32 maxPixVal = 0;
4474 
4475  for (row = 0; row < height; ++row)
4476  {
4477  uchar* rowData = green[row];
4478 
4479  float deltaRow = row - centroidRow;
4480  float deltaRowW = row - centroidRowW;
4481 
4482  float rowPow0 = 1.0;
4483  float rowPow1 = deltaRow;
4484  float rowPow2 = deltaRow * deltaRow;
4485  float rowPow3 = rowPow2 * deltaRow;
4486 
4487  float rowPowW0 = 1;
4488  float rowPowW1 = deltaRowW;
4489  float rowPowW2 = deltaRowW * deltaRowW;
4490  float rowPowW3 = rowPowW2 * deltaRowW;
4491 
4492  for (col = 0; col < width; ++col)
4493  {
4494  uchar pv = rowData[col];
4495  if (pv > backgroundPixelTH)
4496  {
4497  float deltaCol = col - centroidCol;
4498 
4499  float colPow0 = 1.0f;
4500  float colPow1 = deltaCol;
4501  float colPow2 = deltaCol * deltaCol;
4502  float colPow3 = colPow2 * deltaCol;
4503 
4504  cm20 += colPow2 * rowPow0;
4505  cm02 += colPow0 * rowPow2;
4506  cm11 += colPow1 * rowPow1;
4507  cm30 += colPow3 * rowPow0;
4508  cm03 += colPow0 * rowPow3;
4509 
4510  cm12 += colPow1 * rowPow2;
4511  cm21 += colPow2 * rowPow1;
4512 
4513  if (pv > maxPixVal)
4514  maxPixVal = pv;
4515 
4516  float deltaColW = col - centroidColW;
4517  float colPowW0 = 1;
4518  float colPowW1 = deltaColW;
4519  float colPowW2 = deltaColW * deltaColW;
4520  float colPowW3 = colPowW2 * deltaColW;
4521 
4522  cmw20 += colPowW2 * rowPowW0;
4523  cmw02 += colPowW0 * rowPowW2;
4524  cmw30 += colPowW3 * rowPowW0;
4525  cmw03 += colPowW0 * rowPowW3;
4526  cmw12 += colPowW1 * rowPowW2;
4527  cmw21 += colPowW2 * rowPowW1;
4528  }
4529  }
4530  }
4531 
4532  cmw20 = cmw20 / (float)maxPixVal;
4533  cmw02 = cmw02 / (float)maxPixVal;
4534  cmw30 = cmw30 / (float)maxPixVal;
4535  cmw03 = cmw03 / (float)maxPixVal;
4536  cmw12 = cmw12 / (float)maxPixVal;
4537  cmw21 = cmw21 / (float)maxPixVal;
4538  }
4539 
4540  cm20 = cm20 / gamma2;
4541  cm02 = cm02 / gamma2;
4542  cm11 = cm11 / gamma2;
4543 
4544  cm30 = cm30 / gamma3;
4545  cm03 = cm03 / gamma3;
4546  cm12 = cm12 / gamma3;
4547  cm21 = cm21 / gamma3;
4548 
4549  cmw20 = cmw20 / gammaW2;
4550  cmw02 = cmw02 / gammaW2;
4551  cmw11 = cmw11 / gammaW2;
4552 
4553  cmw30 = cmw30 / gammaW3;
4554  cmw03 = cmw03 / gammaW3;
4555  cmw12 = cmw12 / gammaW3;
4556  cmw21 = cmw21 / gammaW3;
4557 
4558 
4559  centralMoments[0] = cm00;
4560 
4561  centralMoments[1] = cm20 + cm02;
4562 
4563  centralMoments[2] = (cm20 - cm02) * (cm20 - cm02) +
4564  4.0f * cm11 * cm11;
4565 
4566  centralMoments[3] = (cm30 - 3.0f * cm12) * (cm30 - 3.0f * cm12) +
4567  (3.0f * cm21 - cm03) * (3.0f * cm21 - cm03);
4568 
4569  centralMoments[4] = (cm30 + cm12) * (cm30 + cm12) + (cm21 + cm03) * (cm21 + cm03);
4570 
4571  centralMoments[5] = (cm30 - 3.0f * cm12) * (cm30 + cm12) * ((cm30 + cm12) * (cm30 + cm12) -
4572  3.0f * (cm21 + cm03) * (cm21 + cm03)) + (3.0f * cm21 - cm03) * (cm21 + cm03) *
4573  (3.0f * (cm30 + cm12) * (cm30 + cm12) - (cm21 + cm03) * (cm21 + cm03));
4574 
4575  centralMoments[6] = (cm20 - cm02) *
4576  ((cm30 + cm12) * (cm30 + cm12) - (cm21 + cm03) * (cm21 + cm03))
4577  + 4.0f * cm11 * (cm30 + cm12) * (cm21 + cm03);
4578 
4579  centralMoments[7] = (3.0f * cm21 - cm03) * (cm30 + cm12) *
4580  ((cm30 + cm12) * (cm30 + cm12) - 3.0f * (cm21 + cm03) * (cm21 + cm03) )
4581  -(cm30 - 3.0f * cm12) * (cm21 + cm03) *
4582  (3.0f * (cm30 + cm12) * (cm30 + cm12) - (cm21 + cm03) * (cm21 + cm03) );
4583 
4584  //added by baishali to calculate eccentricity
4585  centralMoments[8] = (((cm20 - cm02) * (cm20 - cm02)) -
4586  (4.0f * cm11 * cm11))/((cm20 + cm02) * (cm20 + cm02));
4587 
4588 
4589 
4590  centralMomentsWeighted[0] = cmw00;
4591 
4592  centralMomentsWeighted[1] = cmw20 + cmw02;
4593 
4594  centralMomentsWeighted[2] = (cmw20 - cmw02) * (cmw20 - cmw02) + (float)4.0 * cmw11 * cmw11;
4595 
4596  centralMomentsWeighted[3] = (cmw30 - (float)3.0 * cmw12) *
4597  (cmw30 - (float)3.0 * cmw12) +
4598  ((float)3.0 * cmw21 - cmw03) *
4599  ((float)3.0 * cmw21 - cmw03);
4600 
4601  centralMomentsWeighted[4] = (cmw30 + cmw12) * (cmw30 + cmw12) + (cmw21 + cmw03) * (cmw21 + cmw03);
4602 
4603  centralMomentsWeighted[5] = (cmw30 - (float)3.0 * cmw12) * (cmw30 + cmw12) *
4604  ((cmw30 + cmw12) * (cmw30 + cmw12) -
4605  (float)3.0 * (cmw21 + cmw03) * (cmw21 + cmw03)) +
4606  ((float)3.0 * cmw21 - cmw03) * (cmw21 + cmw03) *
4607  ((float)3.0 * (cmw30 + cmw12) * (cmw30 + cmw12) -
4608  (cmw21 + cmw03) * (cmw21 + cmw03));
4609 
4610  centralMomentsWeighted[6] = (cmw20 - cmw02) *
4611  (
4612  (cmw30 + cmw12) * (cmw30 + cmw12) -
4613  (cmw21 + cmw03) * (cmw21 + cmw03)
4614  ) +
4615  (float)4.0 * cmw11 * (cmw30 + cmw12) * (cmw21 + cmw03);
4616 
4617  centralMomentsWeighted[7] = ((float)3.0 * cmw21 - cmw03) *
4618  (cmw30 + cmw12) * ((cmw30 + cmw12) *
4619  (cmw30 + cmw12) - (float)3.0 *
4620  (cmw21 + cmw03) * (cmw21 + cmw03)) -
4621  (cmw30 - (float)3.0 * cmw12) *
4622  (cmw21 + cmw03) * ((float)3.0 *
4623  (cmw30 + cmw12) * (cmw30 + cmw12) -
4624  (cmw21 + cmw03) * (cmw21 + cmw03));
4625 
4626 //added by baishali to calculate eccentricity
4627  centralMomentsWeighted[8] = (float)((((cmw20 - cmw02) * (cmw20 - cmw02)) -
4628  (4.0 * cmw11 * cmw11))/((cmw20 + cmw02) * (cmw20 + cmw02)));
4629 
4630  return;
4631 } /* CentralMoments */
4632 
4633 
4634 
4635 
4636 
4637 
4638 
4639 
4640 
4641 void Raster::Moments (kkint64& m00,
4642  kkint64& m10,
4643  kkint64& m01,
4644  float& mw00,
4645  float& mw10,
4646  float& mw01
4647  ) const
4648 {
4649  m00 = 0;
4650  m10 = 0;
4651  m01 = 0;
4652 
4653  mw00 = 0.0f;
4654  mw10 = 0.0f;
4655  mw01 = 0.0f;
4656 
4657  kkint64 m00Int = 0;
4658  kkint64 m10Int = 0;
4659  kkint64 m01Int = 0;
4660 
4661  kkint32 col = 0;
4662  kkint32 row = 0;
4663 
4664  kkint32 maxPixVal = 0;
4665 
4666  for (row = 0; row < height; ++row)
4667  {
4668  uchar* rowData = green[row];
4669  for (col = 0; col < width; ++col)
4670  {
4671  uchar pv = rowData[col];
4672  if (pv > backgroundPixelTH)
4673  {
4674  m00Int += pv;
4675  m10Int = m10Int + col * pv;
4676  m01Int = m01Int + row * pv;
4677 
4678  if (pv > maxPixVal)
4679  maxPixVal = pv;
4680 
4681  ++m00;
4682  m10 = m10 + col;
4683  m01 = m01 + row;
4684  }
4685  }
4686  }
4687 
4688  mw00 = (float)m00Int / (float)maxPixVal;
4689  mw10 = (float)m10Int / (float)maxPixVal;
4690  mw01 = (float)m01Int / (float)maxPixVal;
4691 
4692  return;
4693 } /* Moments */
4694 
4695 
4696 
4697 
4698 
4699 /**
4700  *@brief Returns back a two dimension array that is a copy of the specified region in the image.
4701  *@details The caller will take ownership of the two dimensional array created.
4702  */
4704  kkint32 _row,
4705  kkint32 _col,
4706  kkint32 _height,
4707  kkint32 _width
4708  ) const
4709 {
4710  kkint32 endR = _row + _height - 1;
4711  kkint32 endC = _col + _width - 1;
4712 
4713  if ((_row < 0) || (endR >= height) ||
4714  (_col < 0) || (endC >= width))
4715  {
4716  cerr << "***ERROR***, Raster::Raster *** ERROR ***, Index's Exceed Raster Bounds" << std::endl;
4717  cerr << " Raster Dimensions[" << width << ", " << height << "]." << std::endl;
4718  cerr << " Requested Coordinates [" << _row << ", " << _col << "], "
4719  << " Height[" << _height << "], Width[" << _width << "]."
4720  << std::endl;
4721  //WaitForEnter ();
4722  exit (-1);
4723  }
4724 
4725  kkint32 row = 0;
4726  kkint32 col = 0;
4727 
4728  kkint32 totalPixelArea = _height * _width;
4729  uchar* subSetArea = new uchar[totalPixelArea];
4730 
4731  uchar** subSet = new uchar*[_height];
4732 
4733  for (row = 0; row < _height; row++)
4734  {
4735  subSet[row] = subSetArea;
4736  for (col = 0; col < _width; col++)
4737  {
4738  subSet[row][col] = _src[_row + row][_col + col];
4739  }
4740  subSetArea = subSetArea + _width;
4741  }
4742 
4743  return subSet;
4744 } /* GetSubSet */
4745 
4746 
4747 
4748 
4749 /**
4750  *@brief Returns true if all the pixels covered by the specified mask are Foreground pixels.
4751  *@see Erosion, Dilation, Closing, Opening, MaskType
4752  */
4753 bool Raster::Fit (MaskTypes mask,
4754  kkint32 row,
4755  kkint32 col
4756  ) const
4757 {
4758  kkint32 bias = MorphOp::Biases (mask);
4759  kkint32 r, c;
4760  kkint32 rStart = row - bias;
4761  kkint32 rEnd = row + bias;
4762  kkint32 cStart = col - bias;
4763  kkint32 cEnd = col + bias;
4764 
4765  if (rStart < 0) rStart = 0;
4766  if (rEnd >= height) rEnd = height - 1;
4767  if (cStart < 0) cStart = 0;
4768  if (cEnd >= width) cEnd = width - 1;
4769 
4770  if (MorphOp::MaskShapes (mask) == StructureType::stSquare)
4771  {
4772  for (r = rStart; r <= rEnd; r++)
4773  {
4774  uchar* rowData = green[r];
4775  for (c = cStart; c <= cEnd; c++)
4776  {
4777  if (BackgroundPixel (rowData[c]))
4778  return false;
4779  }
4780  }
4781  }
4782 
4783  else
4784  {
4785  for (r = rStart; r <= rEnd; r++)
4786  {
4787  if (BackgroundPixel (green[r][col]))
4788  return false;
4789  }
4790 
4791  uchar* rowData = green[row];
4792  for (c = cStart; c <= cEnd; c++)
4793  {
4794  if (BackgroundPixel (rowData[c]))
4795  return false;
4796  }
4797  }
4798 
4799  return true;
4800 } /* Fit */
4801 
4802 
4803 
4804 
4805 
4806 
4807 /**
4808  *@brief Returns true if any one of the pixels covered by the specified mask are Foreground pixels.
4809  *@see Erosion, Dilation, Closing, Opening, MaskType
4810  */
4811 bool Raster::IsThereANeighbor (MaskTypes mask,
4812  kkint32 row,
4813  kkint32 col
4814  ) const
4815 {
4816  kkint32 bias = MorphOp::Biases (mask);
4817  kkint32 r, c;
4818  kkint32 rStart = row - bias;
4819  kkint32 rEnd = row + bias;
4820  kkint32 cStart = col - bias;
4821  kkint32 cEnd = col + bias;
4822 
4823  if (rStart < 0) rStart = 0;
4824  if (rEnd >= height) rEnd = height - 1;
4825  if (cStart < 0) cStart = 0;
4826  if (cEnd >= width) cEnd = width - 1;
4827 
4828  if (MorphOp::MaskShapes (mask) == StructureType::stSquare)
4829  {
4830  for (r = rStart; r <= rEnd; r++)
4831  {
4832  uchar* rowData = green[r];
4833  for (c = cStart; c <= cEnd; c++)
4834  {
4835  if (this->ForegroundPixel (rowData[c]))
4836  return true;
4837  }
4838  }
4839  }
4840 
4841  else
4842  {
4843  for (r = rStart; r <= rEnd; r++)
4844  {
4845  if (ForegroundPixel (green[r][col]))
4846  return true;
4847  }
4848 
4849  uchar* rowData = green[row];
4850  for (c = cStart; c <= cEnd; c++)
4851  {
4852  if (ForegroundPixel (rowData[c]))
4853  return true;
4854  }
4855  }
4856 
4857  return false;
4858 } /* IsThereANeighbor */
4859 
4860 
4861 
4862 
4863 /**
4864  *@brief Used by morphological operators to determine the average pixel value of the foreground pixels that the specifies mask covers.
4865  *@see Erosion, Dilation, Closing, Opening, MaskType
4866  */
4867 uchar Raster::Hit (MaskTypes mask,
4868  kkint32 row,
4869  kkint32 col
4870  ) const
4871 {
4872  kkint32 maskBias = MorphOp::Biases (mask);
4873  if ((row < maskBias) ||
4874  (row + maskBias >= height) ||
4875  (col < maskBias) ||
4876  (col + maskBias >= width))
4877  {
4878  //return 0;
4879  }
4880 
4881  uchar pixVal = 0;
4882  kkint32 totPixVal = 0;
4883  kkint16 numOfHits = 0;
4884 
4885  kkint32 startRow = Max (row - maskBias, (kkint32)0);
4886  kkint32 endRow = Min (row + maskBias, height - 1);
4887  kkint32 startCol = Max (col - maskBias, (kkint32)0);
4888  kkint32 endCol = Min (col + maskBias, width - 1);
4889 
4890  kkint32 r, c;
4891 
4892  if (MorphOp::MaskShapes (mask) == StructureType::stSquare)
4893  {
4894  for (r = startRow; r <= endRow; r++)
4895  {
4896  for (c = startCol; c < endCol; c++)
4897  {
4898  pixVal = green[r][c];
4899 
4900  if (ForegroundPixel (pixVal))
4901  {
4902  numOfHits++;
4903  totPixVal = totPixVal + pixVal;
4904  }
4905  }
4906  }
4907  }
4908 
4909  else
4910  {
4911  for (r = startRow, c = startCol; r <= endRow; r++, c++)
4912  {
4913  pixVal = green[r][col];
4914  if (ForegroundPixel (pixVal))
4915  {
4916  numOfHits++;
4917  totPixVal = totPixVal + pixVal;
4918  }
4919 
4920  pixVal = green[row][c];
4921  if (ForegroundPixel (pixVal))
4922  {
4923  numOfHits++;
4924  totPixVal = totPixVal + pixVal;
4925  }
4926  }
4927  }
4928 
4929 
4930  if (numOfHits == 0)
4931  return 0;
4932  else
4933  return (uchar)(totPixVal / numOfHits);
4934 } /* Hit */
4935 
4936 
4937 
4938 
4939 RasterPtr Raster::FastFourierKK () const
4940 {
4941 
4942  KK_DFT2D_Float plan (height, width, true);
4943  KK_DFT2D_Float::DftComplexType** dest;
4944  KK_DFT2D_Float::DftComplexType* destArea;
4945  plan.AllocateArray (destArea, dest);
4946 
4947  if (destArea == NULL)
4948  {
4949  std::cerr
4950  << std::endl << std::endl
4951  << "Raster::FastFourierKK ***ERROR*** Allocation of 'dest' failed'" << std::endl
4952  << " totPixels[" << totPixels << "]" << std::endl
4953  << " FileName[" << fileName << "]" << std::endl
4954  << std::endl;
4955  return NULL;
4956  }
4957 
4958  plan.Transform (green, dest);
4959 
4960  RasterPtr fourierImage = AllocateARasterInstance (height, width, false);
4961 
4962  uchar* destData = fourierImage->greenArea;
4963 
4964  fourierImage->AllocateFourierMagnitudeTable ();
4965  float* fourierMagArray = fourierImage->fourierMagArea;
4966 
4967  float mag = 0.0f;
4968 
4969  float maxAmplitude = 0.0f;
4970 
4971  kkint32 idx = 0;
4972  for (kkint32 row = 0; row < height; row++ )
4973  {
4974  for (kkint32 col = 0; col < width; col++ )
4975  {
4976  double r = dest[row][col].real ();
4977  double i = dest[row][col].imag ();
4978 
4979  mag = (float)(sqrt (r * r + i * i));
4980  if (mag > maxAmplitude)
4981  maxAmplitude = mag;
4982 
4983  fourierMagArray[idx] = mag; // kk 2004-May-18
4984  ++idx;
4985  }
4986  }
4987 
4988  float maxAmplitudeLog = log (maxAmplitude);
4989 
4990  idx = 0;
4991  for (idx = 0; idx < totPixels; idx++ )
4992  {
4993  // mag = (float)sqrt (dest[idx].re * dest[idx].re + dest[idx].im * dest[idx].im); // kk 2004-May-18
4994  mag = fourierMagArray[idx]; // kk 2004-May-18
4995 
4996  // destData[idx] = (uchar)(dest[idx].re * maxPixVal / maxAmplitude);
4997 
4998  // kk 2004-May-18
4999  // Changed the above line to use the constant 255 instead of maxPixVal,
5000  // If we have an image who's maxPixVal is less than 255 then the values
5001  // being calculated for the Fourier features will not be consistent.
5002  // destData[idx] = (uchar)(dest[idx].re * 255 / maxAmplitude);
5003  destData[idx] = (uchar)(log (fourierMagArray[idx]) * 255.0f / maxAmplitudeLog);
5004  }
5005 
5006  delete dest; dest = NULL;
5007  delete destArea; destArea = NULL;
5008 
5009  return fourierImage;
5010 } /* FastFourierKK */
5011 
5012 
5013 
5014 
5015 
5016 RasterPtr Raster::FastFourier () const
5017 {
5018  #if defined(FFTW_AVAILABLE)
5019  fftwf_complex* src = NULL;
5020  fftwf_complex* dest = NULL;
5021  fftwf_plan plan = NULL;
5022  #else
5023  KK_DFT2D_Float plan (height, width, true);
5024 
5025  KK_DFT2D_Float::DftComplexType* srcArea = NULL;
5026  KK_DFT2D_Float::DftComplexType** src = NULL;
5027 
5028  KK_DFT2D_Float::DftComplexType* destArea = NULL;
5029  KK_DFT2D_Float::DftComplexType** dest = NULL;
5030  #endif
5031 
5032  if (totPixels <= 0)
5033  {
5034  cerr << std::endl << std::endl
5035  << "Raster::FastFourier ***ERROR*** totPixels == 0." << std::endl
5036  << " FileName[" << this->FileName () << "]" << std::endl
5037  << std::endl;
5038  return NULL;
5039  }
5040 
5041  kkint32 col;
5042  kkint32 row;
5043 
5044  kkint32 idx = 0;
5045 
5046  #if defined(FFTW_AVAILABLE)
5047  src = (fftwf_complex*)fftwf_malloc (sizeof (fftwf_complex) * totPixels);
5048  dest = (fftwf_complex*)fftwf_malloc (sizeof (fftwf_complex) * totPixels);
5049  #else
5050  plan.AllocateArray (srcArea, src);
5051  plan.AllocateArray (destArea, dest);
5052  #endif
5053 
5054  if (src == NULL)
5055  {
5056  std::cerr
5057  << std::endl << std::endl
5058  << "Raster::FastFourier ***ERROR*** Allocation of 'src' failed'" << std::endl
5059  << " totPixels[" << totPixels << "]" << std::endl
5060  << " FileName[" << fileName << "]" << std::endl
5061  << std::endl;
5062  return NULL;
5063  }
5064 
5065  if (dest == NULL)
5066  {
5067  std::cerr
5068  << std::endl << std::endl
5069  << "Raster::FastFourier ***ERROR*** Allocation of 'dest' failed'" << std::endl
5070  << " totPixels[" << totPixels << "]" << std::endl
5071  << " FileName[" << fileName << "]" << std::endl
5072  << std::endl;
5073  return NULL;
5074  }
5075 
5076  // float scalingFact = (float)255.0 / maxPixVal; // kk 2004-May-18
5077 
5078  for (row = 0; row < height; row++ )
5079  {
5080  for (col = 0; col < width; col++ )
5081  {
5082  // src[idx].re = (float)green[row][col] * scalingFact;
5083  #if defined(FFTW_AVAILABLE)
5084  src[idx][0] = (float)green[row][col];
5085  src[idx][1] = 0.0;
5086  #else
5087  srcArea[idx].real ((float)greenArea[idx]);
5088  srcArea[idx].imag (0.0);
5089  #endif
5090  idx++;
5091  }
5092  }
5093 
5094  #if defined(FFTW_AVAILABLE)
5095  plan = fftwCreateTwoDPlan (height, width, src, dest, FFTW_FORWARD, FFTW_ESTIMATE);
5096  fftwf_execute (plan);
5097  fftwDestroyPlan (plan);
5098  #else
5099  plan.Transform (src, dest);
5100  #endif
5101 
5102 
5103  RasterPtr fourierImage = new Raster (height, width);
5104 
5105  uchar* destData = fourierImage->greenArea;
5106 
5107  fourierImage->AllocateFourierMagnitudeTable ();
5108  float* fourierMagArray = fourierImage->fourierMagArea;
5109 
5110  float mag = (float)0;
5111 
5112  float maxAmplitude = (float)0;
5113 
5114  for (idx = 0; idx < totPixels; idx++)
5115  {
5116  #if defined(FFTW_AVAILABLE)
5117  float real = dest[idx][0];
5118  float imag = dest[idx][1];
5119  #else
5120  float real = destArea[idx].real ();
5121  float imag = destArea[idx].imag ();
5122  #endif
5123 
5124  // mag = (float)log10 (sqrt (real * real + imag * imag));
5125  mag = (float)(sqrt (real * real + imag * imag));
5126 
5127  if (mag > maxAmplitude)
5128  maxAmplitude = mag;
5129 
5130  fourierMagArray[idx] = mag; // kk 2004-May-18
5131  }
5132 
5133  float maxAmplitudeLog = log (maxAmplitude);
5134 
5135  idx = 0;
5136  for (idx = 0; idx < totPixels; idx++ )
5137  {
5138  // mag = (float)sqrt (dest[idx].re * dest[idx].re + dest[idx].im * dest[idx].im); // kk 2004-May-18
5139  mag = fourierMagArray[idx]; // kk 2004-May-18
5140 
5141  // destData[idx] = (uchar)(dest[idx].re * maxPixVal / maxAmplitude);
5142 
5143  // kk 2004-May-18
5144  // Changed the above line to use the constant 255 instead of maxPixVal,
5145  // If we have an image who's maxPixVal is less than 255 then the values
5146  // being calculated for the Fourier features will not be consistent.
5147  // destData[idx] = (uchar)(dest[idx].re * 255 / maxAmplitude);
5148  destData[idx] = (uchar)(log (fourierMagArray[idx]) * 255.0f / maxAmplitudeLog);
5149  }
5150 
5151  #if defined(FFTW_AVAILABLE)
5152  fftwf_free (src); src = NULL;
5153  fftwf_free (dest); dest = NULL;
5154  #else
5155  plan.DestroyArray (srcArea, src);
5156  plan.DestroyArray (destArea, dest);
5157  #endif
5158 
5159  return fourierImage;
5160 } /* FastFourier */
5161 
5162 
5163 
5164 
5165 RasterPtr Raster::SwapQuadrants () const
5166 {
5167  RasterPtr result = AllocateARasterInstance (*this);
5168 
5169  kkint32 leftStart = (kkint32)(width / 2);
5170  kkint32 bottomStart = (kkint32)(height / 2);
5171 
5172  kkint32 r1, c1;
5173  kkint32 r2, c2;
5174 
5175  for (r1 = 0, r2 = bottomStart; (r1 < bottomStart) && (r2 < height); r1++, r2++)
5176  {
5177  for (c1 = 0, c2 = leftStart; (c1 < leftStart) && (c2 < width); c1++, c2++)
5178  {
5179  result->green[r1][c1] = green[r2][c2];
5180  result->green[r2][c2] = green[r1][c1];
5181  result->green[r1][c2] = green[r2][c1];
5182  result->green[r2][c1] = green[r1][c2];
5183 
5184  if (result->red)
5185  {
5186  result->red[r1][c1] = red[r2][c2];
5187  result->red[r2][c2] = red[r1][c1];
5188  result->red[r1][c2] = red[r2][c1];
5189  result->red[r2][c1] = red[r1][c2];
5190  }
5191 
5192  if (result->blue)
5193  {
5194  result->blue[r1][c1] = blue[r2][c2];
5195  result->blue[r2][c2] = blue[r1][c1];
5196  result->blue[r1][c2] = blue[r2][c1];
5197  result->blue[r2][c1] = blue[r1][c2];
5198  }
5199 
5200  if (result->fourierMag)
5201  {
5202  result->fourierMag[r1][c1] = fourierMag[r2][c2];
5203  result->fourierMag[r2][c2] = fourierMag[r1][c1];
5204  result->fourierMag[r1][c2] = fourierMag[r2][c1];
5205  result->fourierMag[r2][c1] = fourierMag[r1][c2];
5206  }
5207  }
5208  }
5209 
5210  return result;
5211 } /* SwapQuadrants */
5212 
5213 
5214 
5215 
5216 void Raster::FourierExtractFeatures (float fourierFeatures[5]) const
5217 {
5218  if (!fourierMagArea)
5219  {
5220  cerr << std::endl
5221  << "*** ERROR *** This Raster image is not the result of a fast Fourier" << std::endl
5222  << std::endl;
5224  exit (-1);
5225  }
5226 
5227  float cr = height / (float)2.0;
5228  float cw = width / (float)2.0;
5229 
5230  float crSqr = cr * cr;
5231  float cwSqr = cw * cw;
5232 
5233  //float diagLen = crSqr + cwSqr;
5234  float r1Len = crSqr / (float)4.0 + cwSqr / (float)4.0;
5235 
5236  float r2Len = (float)((9.0 / 16.0) * crSqr + (9.0 / 16.0) * cwSqr); // 3/ 4 ths Len
5237 
5238  float r3Len = (float)((81.0 / 100.0) * crSqr + (81.0 / 100.0) * cwSqr); // 9/10 ths Len
5239 
5240  float r4Len = (float)((361.0 / 400.0) * crSqr + (361.0 / 400.0) * cwSqr); // 19/20 ths Len
5241 
5242  fourierFeatures[0] = (float)0.0;
5243  fourierFeatures[1] = (float)0.0;
5244  fourierFeatures[2] = (float)0.0;
5245  fourierFeatures[3] = (float)0.0;
5246  fourierFeatures[4] = (float)0.0;
5247 
5248  kkint32 count[5];
5249 
5250  count[0] = 0;
5251  count[1] = 0;
5252  count[2] = 0;
5253  count[3] = 0;
5254  count[4] = 0;
5255 
5256  kkint32 row;
5257  kkint32 col;
5258 
5259  float deltaRow;
5260  float deltaRowSqr = (float)0.0;
5261 
5262  float deltaCol;
5263  float deltaColSqr = (float)0.0;
5264 
5265  float distFromCent;
5266 
5267  for (row = 0 ; row < height; row++)
5268  {
5269  deltaRow = cr - (float)row;
5270  deltaRowSqr = deltaRow * deltaRow;
5271 
5272  for (col = 0; col < (kkint32)cw; col++)
5273  {
5274  deltaCol = cw - (float)col;
5275  deltaColSqr = deltaCol * deltaCol;
5276 
5277  distFromCent = deltaRowSqr + deltaColSqr;
5278 
5279  if (distFromCent < r1Len)
5280  {
5281  fourierFeatures[0] = fourierFeatures[0] + fourierMag[row][col];
5282  count[0]++;
5283  }
5284 
5285  else if (distFromCent < r2Len)
5286  {
5287  fourierFeatures[1] = fourierFeatures[1] + fourierMag[row][col];
5288  count[1]++;
5289  }
5290 
5291  else if (distFromCent < r3Len)
5292  {
5293  fourierFeatures[2] = fourierFeatures[2] + fourierMag[row][col];
5294  count[2]++;
5295  }
5296 
5297  else if (distFromCent < r4Len)
5298  {
5299  fourierFeatures[3] = fourierFeatures[3] + fourierMag[row][col];
5300  count[3]++;
5301  }
5302  else
5303  {
5304  fourierFeatures[4] = fourierFeatures[4] + fourierMag[row][col];
5305  count[4]++;
5306  }
5307  }
5308  }
5309 
5310  kkint32 x;
5311 
5312  for (x = 0; x < 5; x++)
5313  {
5314  fourierFeatures[x] = fourierFeatures[x] / count[x];
5315  }
5316 } /* ExtractFourierFeatures */
5317 
5318 
5319 
5320 /**
5321  *@brief Returns the difference between two angles in degrees.
5322  *@details Given two angles, will determine the angular distance
5323  * between them, going from the ang1 to ang2. A positive
5324  * delta indicates that ang2 is in front of ang1, negative
5325  * means it is behind ang1. The result can be from -180
5326  * to +180 degrees.
5327  */
5328 float DeltaAngle (float ang1,
5329  float ang2
5330  )
5331 {
5332  float deltaAng = ang2 - ang1;
5333 
5334  while (deltaAng > 180.0)
5335  deltaAng = deltaAng - (float)360.0;
5336 
5337  if (deltaAng < -180.0)
5338  deltaAng = deltaAng + (float)360;
5339 
5340  return deltaAng;
5341 } /* DeltaAngle */
5342 
5343 
5344 
5345 const
5346 MovDir movements[8] = {{-1, 0}, // Up
5347  {-1, 1}, // Up-Right
5348  { 0, 1}, // Right
5349  { 1, 1}, // Down-Right
5350  { 1, 0}, // Down
5351  { 1, -1}, // Down-Left
5352  { 0, -1}, // Left,
5353  {-1, -1} // Up-Left
5354  };
5355 
5356 
5357 void Raster::FollowContour (float countourFreq[5]) const
5358 {
5359  // startRow and startCol is assumed to come from the left (6)
5360 
5361  kkint32 startRow = 0;
5362  kkint32 startCol = 0;
5363 
5364  kkint32 lastDir = 1; // Last Movement was Up-Right
5365 
5366  kkint32 nextRow = 0;
5367  kkint32 nextCol = 0;
5368 
5369  kkint32 fromDir = 0;
5370 
5371  kkint32 edgeLen = 0;
5372 
5373  kkint32 maxNumOfAngles = 2 * height * width;
5374  kkint32 numOfAngles = 0;
5375 
5376 
5377  kkint32 x;
5378  kkint32 count[5];
5379 
5380  for (x = 0; x < 5; x++)
5381  {
5382  countourFreq[x] = 0.0;
5383  count[x] = 0;
5384  }
5385 
5386 
5387 
5388 
5389 
5390  #if defined(FFTW_AVAILABLE)
5391  fftw_complex* src = (fftw_complex*)fftw_malloc (sizeof (fftw_complex) * maxNumOfAngles);
5392  #else
5393  KK_DFT1D_Float::DftComplexType* src = new KK_DFT1D_Float::DftComplexType[maxNumOfAngles];
5394  #endif
5395 
5396  startRow = height / 2;
5397  startCol = 0;
5398 
5399  while ((startCol < width) && (BackgroundPixel (green[startRow][startCol])))
5400  {
5401  startCol++;
5402  }
5403 
5404  // if (green[startRow][startCol] == 0)
5405  if (startCol >= width)
5406  {
5407  // We did not find a Pixel in the Middle Row(height / 2) so now we will
5408  // scan the image row, by row, Left to Right until we find an occupied
5409  // pixel.
5410 
5411  bool found = false;
5412  kkint32 row;
5413  kkint32 col;
5414 
5415  for (row = 0; ((row < height) && (!found)); row++)
5416  {
5417  for (col = 0; ((col < width) && (!found)); col++)
5418  {
5419  if (ForegroundPixel (green[row][col]))
5420  {
5421  found = true;
5422  startRow = row;
5423  startCol = col;
5424  }
5425  }
5426  }
5427 
5428  if (!found)
5429  {
5430  return;
5431  }
5432  }
5433 
5434  kkint32 curRow = startRow;
5435  kkint32 curCol = startCol;
5436 
5437  bool nextPixelFound = false;
5438 
5439  kkint32 nextDir;
5440 
5441  do
5442  {
5443  edgeLen++;
5444 
5445  fromDir = lastDir + 4;
5446  if (fromDir > 7)
5447  fromDir = fromDir - 8;
5448 
5449  nextPixelFound = false;
5450 
5451  nextDir = fromDir + 2;
5452  while (!nextPixelFound)
5453  {
5454  if (nextDir > 7)
5455  nextDir = nextDir - 8;
5456 
5457  nextRow = curRow + movements[nextDir].row;
5458  nextCol = curCol + movements[nextDir].col;
5459 
5460  if ((nextRow < 0) ||
5461  (nextRow >= height) ||
5462  (nextCol < 0) ||
5463  (nextCol >= width)
5464  )
5465  {
5466  nextDir++;
5467  }
5468  else if (ForegroundPixel (green[nextRow][nextCol]))
5469  {
5470  nextPixelFound = true;
5471  }
5472  else
5473  {
5474  nextDir++;
5475  }
5476  }
5477 
5478  if (numOfAngles >= maxNumOfAngles)
5479  {
5480  kkint32 newMaxNumOfAngles = maxNumOfAngles * 2;
5481 
5482  #if defined(FFTW_AVAILABLE)
5483  fftw_complex* newSrc = (fftw_complex*)fftw_malloc (sizeof (fftw_complex) * newMaxNumOfAngles);
5484  #else
5485  KK_DFT1D_Float::DftComplexType* newSrc = new KK_DFT1D_Float::DftComplexType[newMaxNumOfAngles];
5486  #endif
5487 
5488  kkint32 x;
5489  for (x = 0; x < maxNumOfAngles; x++)
5490  {
5491  #if defined(FFTW_AVAILABLE)
5492  newSrc[x][0] = src[x][0];
5493  newSrc[x][1] = src[x][1];
5494  #else
5495  newSrc[x].real (src[x].real ());
5496  newSrc[x].imag (src[x].imag ());
5497  #endif
5498  }
5499 
5500  #ifdef FFTW3_H
5501  fftw_free (src);
5502  #else
5503  delete src;
5504  #endif
5505 
5506  src = newSrc;
5507  maxNumOfAngles = newMaxNumOfAngles;
5508  }
5509 
5510  #if defined(FFTW_AVAILABLE)
5511  src[numOfAngles][0] = nextRow;
5512  src[numOfAngles][1] = nextCol;
5513  #else
5514  src[x].real ((float)nextRow);
5515  src[x].imag ((float)nextCol);
5516  #endif
5517 
5518 
5519  // sqrt ((float)(nextRow * nextRow + nextCol * nextCol));
5520  numOfAngles++;
5521 
5522  lastDir = nextDir;
5523  curRow = nextRow;
5524  curCol = nextCol;
5525  } while ((curRow != startRow) || (curCol != startCol));
5526 
5527 
5528  #if defined(FFTW_AVAILABLE)
5529  fftw_complex* dest = (fftw_complex*)fftw_malloc (sizeof (fftw_complex) * maxNumOfAngles);
5530  fftw_plan plan;
5531  plan = fftw_plan_dft_1d (numOfAngles, src, dest, FFTW_FORWARD, FFTW_ESTIMATE);
5532  fftw_execute (plan);
5533  fftw_destroy_plan(plan);
5534  #else
5535  KK_DFT1D_Float plan(numOfAngles, true);
5536  KK_DFT1D_Float::DftComplexType* dest = new KK_DFT1D_Float::DftComplexType[maxNumOfAngles];
5537  plan.Transform(src, dest);
5538  #endif
5539 
5540 
5541  float middle = (float)(numOfAngles / 2.0);
5542  float r1 = (float)(middle / 2.0);
5543  float r2 = (float)(middle * ( 3.0 / 4.0));
5544  float r3 = (float)(middle * ( 7.0 / 8.0));
5545  float r4 = (float)(middle * (15.0 / 16.0));
5546 
5547  float deltaX;
5548  float mag;
5549 
5550  for (x = 0; x < numOfAngles; x++)
5551  {
5552  #if defined(FFTW_AVAILABLE)
5553  mag = (float)log (sqrt (dest[x][0] * dest[x][0] + dest[x][1] * dest[x][1]));
5554  #else
5555  mag = (float)log (sqrt (dest[x].real () * dest[x].real () + dest[x].imag () * dest[x].imag ()));
5556  #endif
5557 
5558  deltaX = (float)fabs ((float)x - middle);
5559 
5560  if (deltaX < r1)
5561  {
5562  countourFreq[0] = countourFreq[0] + mag;
5563  count[0]++;
5564  }
5565 
5566  else if (deltaX < r2)
5567  {
5568  countourFreq[1] = countourFreq[1] + mag;
5569  count[1]++;
5570  }
5571 
5572  else if (deltaX < r3)
5573  {
5574  countourFreq[2] = countourFreq[2] + mag;
5575  count[2]++;
5576  }
5577 
5578  else if (deltaX < r4)
5579  {
5580  countourFreq[3] = countourFreq[3] + mag;
5581  count[3]++;
5582  }
5583 
5584  else
5585  {
5586  countourFreq[4] = countourFreq[4] + mag;
5587  count[4]++;
5588  }
5589  }
5590 
5591 
5592  for (x = 0; x < 5; x++)
5593  countourFreq[x] = countourFreq[x] / (float)count[x];
5594 
5595  #if defined(FFTW_AVAILABLE)
5596  fftw_free (src);
5597  fftw_free (dest);
5598  #else
5599  delete[] src;
5600  delete[] dest;
5601  #endif
5602 } /* FollowContour */
5603 
5604 
5605 
5606 
5607 
5608 
5609 
5610 void Raster::CalcOrientationAndEigerRatio (float& eigenRatio,
5611  float& orientationAngle
5612  )
5613 {
5614 #ifdef WIN32
5615 
5616  float centroidColWeighted;
5617  float centroidRowWeighted;
5618 
5619  kkint32 size;
5620  kkint32 weight;
5621 
5622  CalcCentroid (size, weight, centroidRow, centroidCol, centroidRowWeighted, centroidColWeighted);
5623 
5624  double cov[2][2];
5625 
5626  cov[0][0] = 0.0;
5627  cov[0][1] = 0.0;
5628  cov[1][0] = 0.0;
5629  cov[1][1] = 0.0;
5630 
5631  kkint32 col;
5632  uchar pixVal;
5633  kkint32 row;
5634 
5635  double colOffset = 0.0;
5636  double rowOffset = 0.0;
5637  double rowOffsetSquare = 0.0;
5638 
5639  for (row = 0; row < height; row++)
5640  {
5641  rowOffset = double (row) - centroidRow;
5642  rowOffsetSquare = rowOffset * rowOffset;
5643 
5644  for (col = 0; col < width; col++)
5645  {
5646  pixVal = green[row][col];
5647 
5648  if (ForegroundPixel (pixVal))
5649  {
5650  colOffset = double (col) - centroidCol;
5651  cov[0][0] += (colOffset * colOffset);
5652  cov[1][1] += (rowOffsetSquare);
5653  cov[0][1] += (colOffset * rowOffset);
5654  }
5655  }
5656  }
5657 
5658  cov[1][0] = cov[0][1];
5659  cov[0][0] /= size;
5660  cov[0][1] /= size;
5661  cov[1][0] /= size;
5662  cov[1][1] /= size;
5663 
5664  double origCov00 = cov[0][0];
5665  double origCov11 = cov[1][1];
5666  double origCov10 = cov[1][0];
5667 
5668  double d[2];
5669  double e[2];
5670 
5671  d[0] = 0.0;
5672  d[1] = 0.0;
5673  e[0] = 0.0;
5674  e[1] = 0.0;
5675 
5676  Tred2 (2, cov, d, e);
5677 
5678  tqli (2, d, e, cov);
5679 
5680  double ang0;
5681 
5682  if (fabs (d[0]) > fabs (d[1]))
5683  {
5684  ang0 = atan2 (cov[0][0], cov[1][0]);
5685  eigenRatio = (d[0] == 0.0) ? 9999.0f : float (d[1] / d[0]);
5686  }
5687  else
5688  {
5689  ang0 = atan2 (cov[0][1], cov[1][1]);
5690  eigenRatio = (d[1] == 0.0) ? 9999.0f : float (d[0] / d[1]);
5691  }
5692  //double ang1 = RadToDeg * atan2 (cov[0][1], cov[1][1]);
5693 
5694  orientationAngle = float (-ang0 - 1.57079632679f);
5695  if (fabs (orientationAngle) > 1.57079632679f)
5696  {
5697  if (orientationAngle < 0.0)
5698  orientationAngle += float (PIE);
5699  else
5700  orientationAngle -= float (PIE);
5701  }
5702 
5703 
5704  //if (d[0] == 0.0)
5705  // eigenRatio = (float)9999.0;
5706  //else
5707  // eigenRatio = (float) (d[1] / d[0]);
5708 
5709 
5710  if (origCov10 == 0)
5711  {
5712  // Appears we have a image that is standing up Straight,
5713  // but may be fatter than it is tall.
5714  if (origCov00 > origCov11)
5715  {
5716  orientationAngle = 0.0f;
5717  }
5718  else
5719  {
5720  orientationAngle = 1.57079632679f;
5721  }
5722  }
5723 
5724  return;
5725 
5726 #endif
5727 } /* CalcOrientation */
5728 
5729 
5730 
5731 
5732 RasterPtr Raster::Rotate (float turnAngle)
5733 {
5734 
5735  kkint32 diag = (kkint32)sqrt ((float)(Height () * Height () + Width () * Width ())) + 10;
5736  kkint32 halfDiag = (diag + 1) / 2;
5737 
5738  // J( x+width(J)/2, y+height(J)/2 )= I( A11x+A12y+b1, A21x+A22y+b2 ),
5739  // C:\Program Files\OpenCV\docs\ref\OpenCVRef_ImageProcessing.htm
5740  // Example. Using cvGetQuadrangeSubPix for image rotation
5741 
5742 
5743  RasterPtr rotatedImage = AllocateARasterInstance (diag, diag, false);
5744 
5745  float a11 = (float)(cos (-turnAngle));
5746  float a12 = (float)(sin (-turnAngle));
5747  float b1 = width * 0.5f;
5748 
5749  float a21 = -a12;
5750  float a22 = a11;
5751  float b2 = height * 0.5f;
5752 
5753  kkint32 centDestCol = 0;
5754  kkint32 centDestRow = 0;
5755 
5756  kkint32 srcCol;
5757  kkint32 srcRow;
5758 
5759  kkint32 destX;
5760  kkint32 destY;
5761 
5762 
5763  for (centDestRow = -halfDiag; centDestRow < halfDiag; centDestRow++)
5764  {
5765  for (centDestCol = -halfDiag; centDestCol < halfDiag; centDestCol++)
5766  {
5767  srcRow = (kkint32)((float)(a21 * centDestCol) + (float)(a22 * centDestRow) + b2 + 0.5);
5768  if ((srcRow >= 0) && (srcRow < height))
5769  {
5770  srcCol = (kkint32)((float)(a11 * centDestCol) + (float)(a12 * centDestRow) + b1 + 0.5);
5771 
5772  if ((srcCol >= 0) && (srcCol < width))
5773  {
5774  uchar pixVal = GetPixelValue (srcRow, srcCol);
5775  if (pixVal > 0)
5776  {
5777  destY = centDestRow + halfDiag;
5778  destX = centDestCol + halfDiag;
5779  rotatedImage->SetPixelValue (destY, destX, pixVal);
5780  }
5781  }
5782  }
5783  }
5784  }
5785 
5786  return rotatedImage;
5787 } /* Rotate */
5788 
5789 
5790 
5791 
5793  kkint32 width,
5794  Point& rotatedPoint,
5795  float turnAngle
5796  )
5797  const
5798 {
5799  kkint32 diag = (kkint32)sqrt ((float)(height * height + width * width)) + 10;
5800 
5801  float a11 = (float)(cos (-turnAngle));
5802  float a12 = (float)(sin (-turnAngle));
5803  float b1 = width * 0.5f;
5804 
5805  float a21 = -a12;
5806  float a22 = a11;
5807  float b2 = height * 0.5f;
5808 
5809  kkint32 halfDiag = (diag + 1) / 2;
5810 
5811  kkint32 centDestRow = rotatedPoint.Row () - halfDiag;
5812  kkint32 centDestCol = rotatedPoint.Col () - halfDiag;
5813 
5814  kkint32 srcY = (kkint32)((float)(a21 * centDestCol) + (float)(a22 * centDestRow) + b2 + 0.5);
5815  kkint32 srcX = (kkint32)((float)(a11 * centDestCol) + (float)(a12 * centDestRow) + b1 + 0.5);
5816 
5817  return Point (srcY, srcX);
5818 } /* RotateDerivePreRotatedPoint */
5819 
5820 
5821 
5822 
5824  kkint32& tlCol,
5825  kkint32& brRow,
5826  kkint32& brCol
5827  ) const
5828 {
5829  tlRow = INT_MAX;
5830  tlCol = INT_MAX;
5831 
5832  brRow = INT_MIN;
5833  brCol = INT_MIN;
5834 
5835  kkint32 col = 0;
5836  kkint32 row = 0;
5837 
5838  bool firstPixelFound = false;
5839 
5840  // lets 1st find the very 1st Pixel Used.
5841  while (row < height)
5842  {
5843  while (col < width)
5844  {
5845  if (ForegroundPixel (green[row][col]))
5846  {
5847  tlRow = row;
5848  tlCol = col;
5849  brRow = row;
5850  brCol = col;
5851  firstPixelFound = true;
5852  break;
5853  }
5854 
5855  col++;
5856  }
5857 
5858  if (firstPixelFound)
5859  break;
5860 
5861  row++; col = 0;
5862  }
5863 
5864 
5865  if (!firstPixelFound)
5866  {
5867  // We have a Blank Image.
5868  tlRow = tlCol = brRow = brCol = -1;
5869  return;
5870  }
5871 
5872  while (row < height)
5873  {
5874  // Lets find 1st Pixel used in Row.
5875  while ((col < width) && (BackgroundPixel (green[row][col])))
5876  {
5877  col++;
5878  }
5879 
5880  if (col < width)
5881  {
5882  // We have some Data on this row.
5883 
5884  brRow = row;
5885 
5886  if (col < tlCol)
5887  tlCol = col;
5888 
5889  kkint32 lastColUsed = 0;
5890 
5891  while (col < width)
5892  {
5893  if (ForegroundPixel (green[row][col]))
5894  {
5895  lastColUsed = col;
5896  }
5897 
5898  col++;
5899  }
5900 
5901  if (lastColUsed > brCol)
5902  brCol = lastColUsed;
5903  }
5904 
5905  row++; col = 0;
5906  }
5907 
5908  return;
5909 
5910 } /* FindBoundingBox */
5911 
5912 
5913 uchar Raster::DeltaMagnitude (uchar c1, uchar c2)
5914 {
5915  if (c1 > c2)
5916  return c1 - c2;
5917  else
5918  return c2 - c1;
5919 }
5920 
5921 
5922 
5923 
5925 {
5926  kkint32 resultHeight = Max (height, r.Height ());
5927  kkint32 resultWidth = Max (width, r.Width ());
5928 
5929  RasterPtr result = new Raster (resultHeight, resultWidth, color);
5930 
5931  uchar** otherRed = r.Red ();
5932  uchar** otherGreen = r.Green ();
5933  uchar** otherBlue = r.Blue ();
5934 
5935  uchar** resultRed = result->Red ();
5936  uchar** resultGreen = result->Green ();
5937  uchar** resultBlue = result->Blue ();
5938 
5939  kkint32 minHeight = Min (height, r.Height ());
5940  kkint32 minWidth = Min (width, r.Width ());
5941 
5942  kkint32 resultTotPixels = resultHeight * resultWidth;
5943 
5944  memset (result->GreenArea (), 255, resultTotPixels);
5945  if (color)
5946  {
5947  memset (result->RedArea (), 255, resultTotPixels);
5948  memset (result->BlueArea (), 255, resultTotPixels);
5949  }
5950 
5951  for (kkint32 r = 0; r < minHeight; ++r)
5952  {
5953  for (kkint32 c = 0; c < minWidth; ++c)
5954  {
5955  // resultGreen[r][c] = DeltaMagnitude (green[r][c], otherGreen[r][c]);
5956  int deltaC = DeltaMagnitude (green[r][c], otherGreen[r][c]);
5957  if (deltaC > 0)
5958  deltaC = Min (255, deltaC + 64);
5959  resultGreen[r][c] = deltaC;
5960 
5961  if (color)
5962  {
5963  resultRed [r][c] = DeltaMagnitude (red [r][c], otherRed [r][c]);
5964  resultBlue[r][c] = DeltaMagnitude (blue[r][c], otherBlue[r][c]);
5965  }
5966  }
5967  }
5968 
5969  return result;
5970 } /* FindMagnitudeDifferences */
5971 
5972 
5973 
5974 
5975 
5976 
5978  kkint32& weight,
5979  float& rowCenter,
5980  float& colCenter,
5981  float& rowCenterWeighted,
5982  float& colCenterWeighted
5983  ) const
5984 {
5985  size = 0;
5986  weight = 0;
5987  rowCenter = 0;
5988  colCenter = 0;
5989  rowCenterWeighted = 0;
5990  colCenterWeighted = 0;
5991 
5992  kkint32 row;
5993  kkint32 col;
5994 
5995  uchar intensity;
5996 
5997  for (row = 0; row < height; row++)
5998  {
5999  for (col = 0; col < width; col++)
6000  {
6001  intensity = green[row][col];
6002 
6003  if (intensity > 0)
6004  {
6005  rowCenter += row;
6006  colCenter += col;
6007  size++;
6008 
6009  rowCenterWeighted += row * intensity;
6010  colCenterWeighted += col * intensity;
6011  weight += intensity;
6012  }
6013  }
6014  }
6015 
6016  rowCenter /= size;
6017  colCenter /= size;
6018 
6019  this->centroidCol = colCenter;
6020  this->centroidRow = rowCenter;
6021 
6022  rowCenterWeighted /= weight;
6023  colCenterWeighted /= weight;
6024 } /* CalcCentroid */
6025 
6026 
6027 
6028 RasterPtr Raster::CreateColor () const
6029 {
6030  if (color)
6031  return new Raster (*this);
6032 
6033  RasterPtr colorImage = new Raster (height, width, true);
6034 
6035  uint x = 0;
6036  PixelValue pv[256];
6037  for (x = 0; x < 256; ++x)
6038  {
6039  pv[x] = PixelValue::FromHSI ((float)x, 1.0f, 1.0f);
6040  }
6041 
6042  for (int r = 0; r < height; ++r)
6043  {
6044  uchar* rowData = green[r];
6045  for (int c = 0; c < width; ++c)
6046  {
6047  uchar intensity = rowData[c];
6048  if (intensity == 0)
6049  colorImage->SetPixelValue (r, c, PixelValue::White);
6050  else
6051  colorImage->SetPixelValue (r, c, pv[rowData[c]]);
6052  }
6053  }
6054 
6055  return colorImage;
6056 }
6057 
6058 
6059 
6060 RasterPtr Raster::CreateGrayScale () const
6061 {
6062  if (!color)
6063  {
6064  // Already a gray-scale image, Just return copy of self.
6065  return (AllocateARasterInstance (*this));
6066  }
6067 
6068  kkint32 h = height;
6069  kkint32 w = width;
6070 
6071  RasterPtr grayRaster = AllocateARasterInstance (h, w, false);
6072  uchar* grayPtr = grayRaster->GreenArea ();
6073  uchar* redPtr = redArea;
6074  uchar* greenPtr = greenArea;
6075  uchar* bluePtr = blueArea;
6076 
6077  for (kkint32 x = 0; x < totPixels; ++x, ++grayPtr, ++redPtr, ++greenPtr, ++bluePtr)
6078  {
6079  *grayPtr = (uchar)((kkuint32)((0.30f) * (float)(*redPtr) +
6080  (0.59f) * (float)(*greenPtr) +
6081  (0.11f) * (float)(*bluePtr)
6082  )
6083  );
6084  }
6085  return grayRaster;
6086 } /* CreateGrayScale */
6087 
6088 
6089 
6090 
6092 {
6093  HistogramPtr histogram = new KKB::Histogram (0, 256, 1.0, false);
6094 
6095  kkint32 row, col;
6096 
6097  for (row = 0; row < height; row++)
6098  {
6099  for (col = 0; col < width; col++)
6100  {
6101  histogram->Increment (green[row][col]);
6102  }
6103  }
6104 
6105  return histogram;
6106 } /* HistogramGrayscale */
6107 
6108 
6109 
6111 {
6112  uchar* data = NULL;
6113  if (color)
6114  {
6115  switch (channel)
6116  {
6117  case ColorChannels::Red: data = redArea; break;
6118  case ColorChannels::Green: data = greenArea; break;
6119  case ColorChannels::Blue: data = blueArea; break;
6120  }
6121  }
6122 
6123  if (!data)
6124  {
6125  KKStr errMsg (128);
6126  errMsg << "Raster::Histogram ***ERROR*** channel: " << ColorChannelToKKStr (channel) << " Is not defined.";
6127  cerr << endl << errMsg << endl << endl;
6128  throw KKException (errMsg);
6129  }
6130 
6131  HistogramPtr histogram = new KKB::Histogram (0, 256, 1.0, false);
6132  for (kkint32 x = 0; x < totPixels; x++)
6133  {
6134  histogram->Increment (*data);
6135  ++data;
6136  }
6137 
6138  return histogram;
6139 } /* Histogram */
6140 
6141 
6142 
6143 RasterPtr Raster::HistogramEqualizedImage () const
6144 {
6145  HistogramPtr grayScaleHistogram = HistogramGrayscale ();
6146  HistogramPtr equalizedHistogram = grayScaleHistogram->Equalized ();
6147  delete grayScaleHistogram;
6148  grayScaleHistogram = NULL;
6149  RasterPtr equalizedImage = HistogramEqualizedImage (equalizedHistogram);
6150  delete equalizedHistogram;
6151 
6152  return equalizedImage;
6153 } /* HistogramEqualizedImage */
6154 
6155 
6156 
6157 
6158 
6159 RasterPtr Raster::HistogramEqualizedImage (HistogramPtr equalizedHistogram) const
6160 {
6161  if (equalizedHistogram->NumOfBuckets () != 256)
6162  {
6163  cerr << std::endl
6164  << "**** ERROR **** Histogram Does not have 256 Buckets["
6165  << equalizedHistogram->NumOfBuckets () << "]" << std::endl
6166  << std::endl;
6168  exit (-1);
6169  }
6170 
6171 
6172  kkint32* equalizedMapTable = equalizedHistogram->EqualizedMapTable ();
6173 
6174  if (!equalizedMapTable)
6175  {
6176  cerr << std::endl
6177  << "**** ERROR **** Histogram Does not have EqualizeMapTable." << std::endl
6178  << std::endl;
6180  exit (-1);
6181  }
6182 
6183  RasterPtr equalizedImage = AllocateARasterInstance (height, width, false);
6184 
6185  uchar** dest = equalizedImage->Rows ();
6186 
6187  kkint32 row, col;
6188 
6189  for (row = 0; row < height; row++)
6190  {
6191  for (col = 0; col < width; col++)
6192  {
6193  dest[row][col] = (uchar)(equalizedMapTable[green[row][col]]);
6194  }
6195  }
6196 
6197  return equalizedImage;
6198 } /* HistogramEqualizedImage */
6199 
6200 
6201 
6202 
6203 RasterPtr Raster::HistogramGrayscaleImage () const
6204 {
6205  HistogramPtr histogram = NULL;
6206 
6207  if (color)
6208  {
6209  RasterPtr gsImage = this->CreateGrayScale ();
6210  histogram = gsImage->HistogramGrayscale ();
6211  delete gsImage;
6212  gsImage = NULL;
6213  }
6214  else
6215  {
6216  histogram = HistogramGrayscale ();
6217  }
6218 
6219  RasterPtr histogramImage = histogram->CreateGraph ();
6220  delete histogram;
6221  histogram = NULL;
6222  return histogramImage;
6223 } /* HistogramGrayscaleImage */
6224 
6225 
6226 
6227 RasterPtr Raster::HistogramImage (ColorChannels channel) const
6228 {
6229  HistogramPtr histogram = Histogram (channel);
6230  RasterPtr histogramImage = histogram->CreateGraph ();
6231  delete histogram;
6232  histogram = NULL;
6233  return histogramImage;
6234 } /* HistogramImage */
6235 
6236 
6237 
6238 
6239 void Raster::DrawLine (kkint32 bpRow, kkint32 bpCol,
6240  kkint32 epRow, kkint32 epCol
6241  )
6242 {
6243  DrawLine (bpRow, bpCol,
6244  epRow, epCol,
6245  255
6246  );
6247 }
6248 
6249 
6250 
6251 
6252 
6253 void Raster::DrawLine (kkint32 bpRow, kkint32 bpCol,
6254  kkint32 epRow, kkint32 epCol,
6255  uchar pixelVal
6256  )
6257 {
6258  DrawLine (bpRow, bpCol, epRow, epCol, pixelVal, pixelVal, pixelVal);
6259 } /* DrawLine */;
6260 
6261 
6262 
6263 
6264 void Raster::DrawLine (kkint32 bpRow, kkint32 bpCol,
6265  kkint32 epRow, kkint32 epCol,
6266  uchar r,
6267  uchar g,
6268  uchar b
6269  )
6270 {
6271 
6272  if ((bpRow < 0) || (bpRow >= height) ||
6273  (bpCol < 0) || (bpCol >= width) ||
6274  (epRow < 0) || (epRow >= height) ||
6275  (epCol < 0) || (epCol >= width)
6276  )
6277  {
6278  cerr << std::endl
6279  << "*** WARNING ***"
6280  << "Raster::DrawLine, Out of Raster Boundaries Height[" << height << "] width[" << width << "]." << std::endl
6281  << " BeginPoint" << Point (bpRow, bpCol) << " EndPoint" << Point (epRow, epCol) << "." << std::endl
6282  << std::endl;
6283  return;
6284  }
6285 
6286  kkint32 deltaY = epRow - bpRow;
6287  kkint32 deltaX = epCol - bpCol;
6288 
6289  kkint32 row, col;
6290 
6291  if (deltaY == 0)
6292  {
6293  // We have a Straight Horizontal Line
6294 
6295  row = bpRow;
6296 
6297  kkint32 startCol;
6298  kkint32 endCol;
6299 
6300  if (bpCol < epCol)
6301  {
6302  startCol = bpCol;
6303  endCol = epCol;
6304  }
6305  else
6306  {
6307  startCol = epCol;
6308  endCol = bpCol;
6309  }
6310 
6311  for (col = startCol; col <= endCol; col++)
6312  {
6313  green[row][col] = g;
6314  if (color)
6315  {
6316  red [row][col] = r;
6317  blue[row][col] = b;
6318  }
6319  }
6320 
6321  return;
6322  }
6323 
6324  if (deltaX == 0)
6325  {
6326  // We have a Straight Vertical Line
6327 
6328  col = bpCol;
6329 
6330  kkint32 startRow;
6331  kkint32 endRow;
6332 
6333  if (bpRow < epRow)
6334  {
6335  startRow = bpRow;
6336  endRow = epRow;
6337  }
6338  else
6339  {
6340  startRow = epRow;
6341  endRow = bpRow;
6342  }
6343 
6344  for (row = startRow; row <= endRow; row++)
6345  {
6346  green[row][col] = g;
6347  if (color)
6348  {
6349  red [row][col] = r;
6350  blue[row][col] = b;
6351  }
6352  }
6353 
6354  return;
6355  }
6356 
6357  float m = (float)deltaY / (float)deltaX;
6358 
6359  float c = bpRow - m * bpCol;
6360 
6361  if (fabs (m) < 0.5)
6362  {
6363  kkint32 startCol;
6364  kkint32 endCol;
6365 
6366  if (bpCol < epCol)
6367  {
6368  startCol = bpCol;
6369  endCol = epCol;
6370  }
6371  else
6372  {
6373  startCol = epCol;
6374  endCol = bpCol;
6375  }
6376 
6377  for (col = startCol; col <= endCol; col++)
6378  {
6379  row = (kkint32)(m * col + c + 0.5);
6380  green[row][col] = g;
6381  if (color)
6382  {
6383  red [row][col] = r;
6384  blue[row][col] = b;
6385  }
6386  }
6387  }
6388  else
6389  {
6390  kkint32 startRow;
6391  kkint32 endRow;
6392 
6393  if (bpRow < epRow)
6394  {
6395  startRow = bpRow;
6396  endRow = epRow;
6397  }
6398  else
6399  {
6400  startRow = epRow;
6401  endRow = bpRow;
6402  }
6403 
6404  for (row = startRow; row <= endRow; row++)
6405  {
6406  col = (kkint32)(((row - c) / m) + 0.5);
6407  green[row][col] = g;
6408  if (color)
6409  {
6410  red [row][col] = r;
6411  blue[row][col] = b;
6412  }
6413  }
6414  }
6415 } /* DrawLine */;
6416 
6417 
6418 
6419 uchar MergeAlpfaBeta (float alpha,
6420  uchar alphaPixel,
6421  float beta,
6422  uchar betaPixel
6423  )
6424 {
6425  int newPixelValue = (int)(0.5f + alpha * (float)alphaPixel + beta * (float)betaPixel);
6426  if (newPixelValue > 255)
6427  newPixelValue = 255;
6428  return (uchar)newPixelValue;
6429 }
6430 
6431 
6433  kkint32 col,
6434  const PixelValue& pv,
6435  float alpha
6436  )
6437 {
6438  if ((row < 0) || (row >= height) || (col < 0) || (col >= width))
6439  return;
6440 
6441  float beta = 1.0f - alpha;
6442 
6443  green[row][col] = Min (255, (int)(0.5f + alpha * (float)pv.g + beta * (float)green[row][col]));
6444  if (color)
6445  {
6446  red [row][col] = Min (255, (int)(0.5f + alpha * (float)pv.r + beta * (float)red [row][col]));
6447  blue[row][col] = Min (255, (int)(0.5f + alpha * (float)pv.b + beta * (float)blue[row][col]));
6448  }
6449 }
6450 
6451 
6452 
6454  kkint32 col,
6455  const PixelValue pv,
6456  float alpha
6457  )
6458 {
6459  PaintPoint (row - 2, col, pv, alpha);
6460 
6461  PaintPoint (row - 1, col - 1, pv, alpha);
6462  PaintPoint (row - 1, col, pv, alpha);
6463  PaintPoint (row - 1, col + 1, pv, alpha);
6464 
6465  PaintPoint (row, col - 2, pv, alpha);
6466  PaintPoint (row, col - 1, pv, alpha);
6467  PaintPoint (row, col, pv, alpha);
6468  PaintPoint (row, col + 1, pv, alpha);
6469  PaintPoint (row, col + 2, pv, alpha);
6470 
6471  PaintPoint (row + 1, col - 1, pv, alpha);
6472  PaintPoint (row + 1, col, pv, alpha);
6473  PaintPoint (row + 1, col + 1, pv, alpha);
6474 
6475  PaintPoint (row + 2, col, pv, alpha);
6476 }
6477 
6478 
6479 void Raster::DrawLine (kkint32 bpRow, kkint32 bpCol,
6480  kkint32 epRow, kkint32 epCol,
6481  uchar r,
6482  uchar g,
6483  uchar b,
6484  float alpha
6485  )
6486 {
6487  float beta = 1.0f - alpha;
6488 
6489  if ((bpRow < 0) || (bpRow >= height) ||
6490  (bpCol < 0) || (bpCol >= width) ||
6491  (epRow < 0) || (epRow >= height) ||
6492  (epCol < 0) || (epCol >= width)
6493  )
6494  {
6495  cerr << std::endl
6496  << "*** WARNING ***"
6497  << "Raster::DrawLine, Out of Raster Boundaries Height[" << height << "] width[" << width << "]." << std::endl
6498  << " BeginPoint" << Point (bpRow, bpCol) << " EndPoint" << Point (epRow, epCol) << "." << std::endl
6499  << std::endl;
6500  return;
6501  }
6502 
6503  kkint32 deltaY = epRow - bpRow;
6504  kkint32 deltaX = epCol - bpCol;
6505 
6506  kkint32 row, col;
6507 
6508  if (deltaY == 0)
6509  {
6510  // We have a Straight Horizontal Line
6511 
6512  row = bpRow;
6513 
6514  kkint32 startCol;
6515  kkint32 endCol;
6516 
6517  if (bpCol < epCol)
6518  {
6519  startCol = bpCol;
6520  endCol = epCol;
6521  }
6522  else
6523  {
6524  startCol = epCol;
6525  endCol = bpCol;
6526  }
6527 
6528  for (col = startCol; col <= endCol; col++)
6529  {
6530  green[row][col] = MergeAlpfaBeta (alpha, g, beta, green[row][col]);
6531  if (color)
6532  {
6533  red [row][col] = MergeAlpfaBeta (alpha, r, beta, red [row][col]);
6534  blue[row][col] = MergeAlpfaBeta (alpha, b, beta, blue[row][col]);
6535  }
6536  }
6537 
6538  return;
6539  }
6540 
6541  if (deltaX == 0)
6542  {
6543  // We have a Straight Vertical Line
6544 
6545  col = bpCol;
6546 
6547  kkint32 startRow;
6548  kkint32 endRow;
6549 
6550  if (bpRow < epRow)
6551  {
6552  startRow = bpRow;
6553  endRow = epRow;
6554  }
6555  else
6556  {
6557  startRow = epRow;
6558  endRow = bpRow;
6559  }
6560 
6561  for (row = startRow; row <= endRow; row++)
6562  {
6563  green[row][col] = MergeAlpfaBeta (alpha, g, beta, green[row][col]);
6564  if (color)
6565  {
6566  red [row][col] = MergeAlpfaBeta (alpha, r, beta, red [row][col]);
6567  blue[row][col] = MergeAlpfaBeta (alpha, b, beta, blue[row][col]);
6568  }
6569  }
6570 
6571  return;
6572  }
6573 
6574  float m = (float)deltaY / (float)deltaX;
6575 
6576  float c = bpRow - m * bpCol;
6577 
6578  if (fabs (m) < 0.5)
6579  {
6580  kkint32 startCol;
6581  kkint32 endCol;
6582 
6583  if (bpCol < epCol)
6584  {
6585  startCol = bpCol;
6586  endCol = epCol;
6587  }
6588  else
6589  {
6590  startCol = epCol;
6591  endCol = bpCol;
6592  }
6593 
6594  for (col = startCol; col <= endCol; col++)
6595  {
6596  row = (kkint32)(m * col + c + 0.5);
6597  green[row][col] = MergeAlpfaBeta (alpha, g, beta, green[row][col]);
6598  if (color)
6599  {
6600  red [row][col] = MergeAlpfaBeta (alpha, r, beta, red [row][col]);
6601  blue[row][col] = MergeAlpfaBeta (alpha, b, beta, blue[row][col]);
6602  }
6603  }
6604  }
6605  else
6606  {
6607  kkint32 startRow;
6608  kkint32 endRow;
6609 
6610  if (bpRow < epRow)
6611  {
6612  startRow = bpRow;
6613  endRow = epRow;
6614  }
6615  else
6616  {
6617  startRow = epRow;
6618  endRow = bpRow;
6619  }
6620 
6621  for (row = startRow; row <= endRow; row++)
6622  {
6623  col = (kkint32)(((row - c) / m) + 0.5);
6624  green[row][col] = MergeAlpfaBeta (alpha, g, beta, green[row][col]);
6625  if (color)
6626  {
6627  red [row][col] = MergeAlpfaBeta (alpha, r, beta, red [row][col]);
6628  blue[row][col] = MergeAlpfaBeta (alpha, b, beta, blue[row][col]);
6629  }
6630  }
6631  }
6632 } /* DrawLine */;
6633 
6634 
6635 
6636 void Raster::DrawFatLine (Point startPoint,
6637  Point endPoint,
6638  PixelValue pv,
6639  float alpha
6640  )
6641 {
6642  kkint32 bpRow = startPoint.Row ();
6643  kkint32 bpCol = startPoint.Col ();
6644  kkint32 epRow = endPoint.Row ();
6645  kkint32 epCol = endPoint.Col ();
6646 
6647  if ((bpRow < 0) || (bpRow >= height) ||
6648  (bpCol < 0) || (bpCol >= width) ||
6649  (epRow < 0) || (epRow >= height) ||
6650  (epCol < 0) || (epCol >= width)
6651  )
6652  {
6653  cerr << std::endl
6654  << "*** WARNING ***"
6655  << "Raster::DrawFatLine, Out of Raster Boundaries Height[" << height << "] width[" << width << "]." << std::endl
6656  << " BeginPoint" << startPoint << " EndPoint" << endPoint << "." << std::endl
6657  << std::endl;
6658  return;
6659  }
6660 
6661  kkint32 deltaY = epRow - bpRow;
6662  kkint32 deltaX = epCol - bpCol;
6663 
6664  kkint32 row, col;
6665 
6666  if (deltaY == 0)
6667  {
6668  // We have a Straight Horizontal Line
6669 
6670  row = bpRow;
6671 
6672  kkint32 startCol;
6673  kkint32 endCol;
6674 
6675  if (bpCol < epCol)
6676  {
6677  startCol = bpCol;
6678  endCol = epCol;
6679  }
6680  else
6681  {
6682  startCol = epCol;
6683  endCol = bpCol;
6684  }
6685 
6686  for (col = startCol; col <= endCol; col++)
6687  PaintFatPoint (row, col, pv, alpha);
6688 
6689  return;
6690  }
6691 
6692  if (deltaX == 0)
6693  {
6694  // We have a Straight Vertical Line
6695 
6696  col = bpCol;
6697 
6698  kkint32 startRow;
6699  kkint32 endRow;
6700 
6701  if (bpRow < epRow)
6702  {
6703  startRow = bpRow;
6704  endRow = epRow;
6705  }
6706  else
6707  {
6708  startRow = epRow;
6709  endRow = bpRow;
6710  }
6711 
6712  for (row = startRow; row <= endRow; row++)
6713  PaintFatPoint (row, col, pv, alpha);
6714 
6715  return;
6716  }
6717 
6718  float m = (float)deltaY / (float)deltaX;
6719 
6720  float c = bpRow - m * bpCol;
6721 
6722  if (fabs (m) < 0.5)
6723  {
6724  kkint32 startCol;
6725  kkint32 endCol;
6726 
6727  if (bpCol < epCol)
6728  {
6729  startCol = bpCol;
6730  endCol = epCol;
6731  }
6732  else
6733  {
6734  startCol = epCol;
6735  endCol = bpCol;
6736  }
6737 
6738  for (col = startCol; col <= endCol; col++)
6739  {
6740  row = (kkint32)(m * col + c + 0.5);
6741  PaintFatPoint (row, col, pv, alpha);
6742  }
6743  }
6744  else
6745  {
6746  kkint32 startRow;
6747  kkint32 endRow;
6748 
6749  if (bpRow < epRow)
6750  {
6751  startRow = bpRow;
6752  endRow = epRow;
6753  }
6754  else
6755  {
6756  startRow = epRow;
6757  endRow = bpRow;
6758  }
6759 
6760  for (row = startRow; row <= endRow; row++)
6761  {
6762  col = (kkint32)(((row - c) / m) + 0.5);
6763  PaintFatPoint (row, col, pv, alpha);
6764  }
6765  }
6766 } /* DrawFatLine */;
6767 
6768 
6769 
6770 
6771 void Raster::DrawLine (kkint32 bpRow, kkint32 bpCol,
6772  kkint32 epRow, kkint32 epCol,
6773  PixelValue pixelVal
6774  )
6775 {
6776  DrawLine (bpRow, bpCol, epRow, epCol, pixelVal.r, pixelVal.g, pixelVal.b);
6777 } /* DrawLine */;
6778 
6779 
6780 
6781 
6782 void Raster::DrawLine (kkint32 bpRow, kkint32 bpCol,
6783  kkint32 epRow, kkint32 epCol,
6784  PixelValue pixelVal,
6785  float alpha
6786  )
6787 {
6788  DrawLine (bpRow, bpCol, epRow, epCol, pixelVal.r, pixelVal.g, pixelVal.b, alpha);
6789 } /* DrawLine */;
6790 
6791 
6792 
6793 
6794 void Raster::DrawLine (const Point& beginPoint,
6795  const Point& endPoint,
6796  uchar pixelVal
6797  )
6798 {
6799  DrawLine (beginPoint.Row (), beginPoint.Col (),
6800  endPoint.Row (), endPoint.Col (),
6801  pixelVal
6802  );
6803 } /* DrawLine */
6804 
6805 
6806 
6807 void Raster::DrawLine (const Point& beginPoint,
6808  const Point& endPoint,
6809  const PixelValue& pixelVal
6810  )
6811 {
6812  DrawLine (beginPoint.Row (), beginPoint.Col (),
6813  endPoint.Row (), endPoint.Col (),
6814  pixelVal
6815  );
6816 
6817 } /* DrawLine */
6818 
6819 
6820 
6821 
6822 void Raster::DrawPointList (const PointList& borderPixs,
6823  const PixelValue& pixelValue
6824  )
6825 {
6826  DrawPointList (Point ((kkint32)0, (kkint32)0), borderPixs, pixelValue.r, pixelValue.g, pixelValue.b);
6827 }
6828 
6829 
6831  const PointList& borderPixs,
6832  const PixelValue& pixelValue
6833  )
6834 {
6835  DrawPointList (offset, borderPixs, pixelValue.r, pixelValue.g, pixelValue.b);
6836 }
6837 
6838 
6839 
6840 
6841 void Raster::DrawPointList (const PointList& borderPixs,
6842  uchar redVal,
6843  uchar greenVal,
6844  uchar blueVal
6845  )
6846 {
6847  DrawPointList (Point ((kkint32)0, (kkint32)0), borderPixs, redVal, greenVal, blueVal);
6848 } /* DrawPointList */
6849 
6850 
6851 
6852 
6854  const PointList& borderPixs,
6855  uchar redVal,
6856  uchar greenVal,
6857  uchar blueVal
6858  )
6859 {
6860  PointList::const_iterator pIDX;
6861 
6862  PointPtr pixel = NULL;
6863 
6864  kkint32 row, col;
6865 
6866  for (pIDX = borderPixs.begin (); pIDX != borderPixs.end (); pIDX++)
6867  {
6868  pixel = *pIDX;
6869  row = pixel->Row () + offset.Row ();
6870  col = pixel->Col () + offset.Col ();
6871 
6872  if ((row < height) &&
6873  (row >= 0) &&
6874  (col < width) &&
6875  (col >= 0)
6876  )
6877  {
6878  green[row][col] = greenVal;
6879  if (color)
6880  {
6881  red [row][col] = redVal;
6882  blue[row][col] = blueVal;
6883  }
6884  }
6885  else
6886  {
6887  continue;
6888  }
6889  }
6890 } /* DrawPointList */
6891 
6892 
6893 
6895  const PointList& borderPixs,
6896  const PixelValue& pixelValue,
6897  const PixelValue& linePixelValue
6898  )
6899 {
6900  PointList::const_iterator pIDX;
6901 
6902  PointPtr pixel = NULL;
6903  PointPtr lastPoint = NULL;
6904 
6905  kkint32 row = 0, col = 0;
6906 
6907  for (pIDX = borderPixs.begin (); pIDX != borderPixs.end (); pIDX++)
6908  {
6909  pixel = *pIDX;
6910  if (lastPoint)
6911  {
6912  kkint32 deltaRow = lastPoint->Row () - pixel->Row ();
6913  kkint32 deltaCol = lastPoint->Col () - pixel->Col ();
6914 
6915  kkint32 distSquared = deltaRow * deltaRow + deltaCol * deltaCol;
6916 
6917  if (distSquared > 5)
6918  {
6919  // We need to draw a line between the two points.
6920  DrawLine (*lastPoint + offset, *pixel + offset, linePixelValue);
6921  }
6922  }
6923 
6924  if (pixel != NULL)
6925  {
6926  row = pixel->Row () + offset.Row ();
6927  col = pixel->Col () + offset.Col ();
6928  }
6929 
6930  if ((row < height) && (col < width) &&
6931  (row >= 0) && (col >= 0)
6932  )
6933  {
6934  green[row][col] = pixelValue.g;
6935  if (color)
6936  {
6937  red [row][col] = pixelValue.r;
6938  blue[row][col] = pixelValue.b;
6939  }
6940  }
6941 
6942  lastPoint = pixel;
6943  }
6944 } /* DrawPointList */
6945 
6946 
6947 
6948 void Raster::DrawDot (const Point& point,
6949  const PixelValue& color,
6950  kkint32 size // Diameter in Pixels of Dot
6951  )
6952 {
6953  SetPixelValue (point, color);
6954 
6955  double radius = (double)size / 2.0;
6956  double radiusSquared = radius * radius;
6957 
6958  kkint32 left = Max ((kkint32)0, (kkint32)floor ((double)point.Col () - radius));
6959  kkint32 right = Min ((kkint32)(width - 1), (kkint32)ceil ((double)point.Col () + radius));
6960 
6961  kkint32 bot = Max ((kkint32)0, (kkint32)floor ((double)point.Row () - radius));
6962  kkint32 top = Min ((kkint32)(height - 1), (kkint32)ceil ((double)point.Row () + radius));
6963 
6964  kkint32 row, col;
6965 
6966  for (row = bot; row <= top; row++)
6967  {
6968  kkint32 deltaRow = row - point.Row ();
6969  kkint32 deltaRowSquared = deltaRow * deltaRow;
6970 
6971  if (deltaRowSquared <= radiusSquared)
6972  {
6973  for (col = left; col <= right; col++)
6974  {
6975  kkint32 deltaCol = col - point.Col ();
6976  double distFromCenterSquares = deltaRowSquared + deltaCol * deltaCol;
6977 
6978  if (distFromCenterSquares <= radiusSquared)
6979  {
6980  // we are within the dot.
6981  SetPixelValue (row, col, color);
6982  }
6983  }
6984  }
6985  }
6986 } /* DrawDot */
6987 
6988 
6989 
6990 
6991 void Raster::DrawCircle (float centerRow,
6992  float centerCol,
6993  float radius,
6994  const PixelValue& pixelValue
6995  )
6996 {
6997  kkint32 row, col;
6998  float x, y;
6999 
7000  float start = -(float)ceil (radius);
7001  float end = +(float)floor (radius);
7002 
7003  float radiusSquare = radius * radius;
7004 
7005  for (x = start; x <= end; x++)
7006  {
7007  y = (float)sqrt (radiusSquare - (x * x));
7008  col = (kkint32)(x + centerCol + 0.5);
7009  row = (kkint32)(centerRow + 0.5 + y);
7010  SetPixelValue (row, col, pixelValue);
7011 
7012  row = (kkint32)(centerRow + 0.5 - y);
7013  SetPixelValue (row, col, pixelValue);
7014 
7015 
7016  row = (kkint32)(x + centerRow + 0.5);
7017  col = (kkint32)(centerCol + 0.5 + y);
7018  SetPixelValue (row, col, pixelValue);
7019 
7020  col = (kkint32)(centerCol + 0.5 - y);
7021  SetPixelValue (row, col, pixelValue);
7022 
7023  }
7024 } /* DrawCircle */
7025 
7026 
7027 
7028 
7029 
7030 void Raster::DrawCircle (float centerRow,
7031  float centerCol,
7032  float radius,
7033  float startAngle,
7034  float endAngle,
7035  const PixelValue& pixelValue
7036  )
7037 {
7038  float row, col;
7039 
7040  while (startAngle < 0.0f)
7041  startAngle += (float)TwoPie;
7042 
7043  while (startAngle >= (float)TwoPie)
7044  startAngle -= (float)TwoPie;
7045 
7046  while (endAngle < startAngle)
7047  endAngle += (float)TwoPie;
7048 
7049  while ((endAngle - startAngle) >= (float)TwoPie)
7050  endAngle -= (float)TwoPie;
7051 
7052  float angle = startAngle;
7053  float angleIncrement = asin (0.5f / radius);
7054 
7055  while (angle <= endAngle)
7056  {
7057  // 1st Determine Which Quarter we r in
7058 
7059  float qtrAngle = angle;
7060  while (qtrAngle > (float)TwoPie)
7061  qtrAngle -= (float)TwoPie;
7062 
7063  row = -(radius * cos (angle));
7064  col = (radius * sin (angle));
7065 
7066  kkint32 adjRow = (kkint32)(centerRow + row + 0.5f);
7067  kkint32 adjCol = (kkint32)(centerCol + col + 0.5f);
7068 
7069  if ((adjRow >= 0) && (adjRow < height) &&
7070  (adjCol >= 0) && (adjCol < width))
7071  SetPixelValue ((kkint32)(centerRow + row + 0.5f), (kkint32)(centerCol + col + 0.5f), pixelValue);
7072 
7073  angle += angleIncrement;
7074  }
7075 } /* DrawCircle */
7076 
7077 
7078 
7079 
7080 
7081 void Raster::DrawCircle (const Point& point,
7082  kkint32 radius,
7083  const PixelValue& color
7084  )
7085 {
7086  DrawCircle ((float)point.Row (),
7087  (float)point.Col (),
7088  (float)radius,
7089  color
7090  );
7091 } /* DrawCircle */
7092 
7093 
7094 
7095 
7096 
7097 
7098 
7099 
7100 void Raster::SmoothImageChannel (uchar** src,
7101  uchar** dest,
7102  kkint32 maskSize
7103  ) const
7104 {
7105  kkint32 row, col;
7106 
7107  kkint32 firstMaskRow, firstMaskCol;
7108  kkint32 lastMaskRow, lastMaskCol;
7109 
7110  kkint32 maskRow, maskCol;
7111 
7112  kkint32 maskOffset = maskSize / 2;
7113 
7114  for (row = 0; row < height; row++)
7115  {
7116  firstMaskRow = row - maskOffset;
7117  lastMaskRow = firstMaskRow + maskSize - 1;
7118 
7119  firstMaskRow = Max ((kkint32)0, firstMaskRow);
7120  lastMaskRow = Min (lastMaskRow, (kkint32)(height - 1));
7121 
7122  for (col = 0; col < width; col++)
7123  {
7124  firstMaskCol = col - maskOffset;
7125  lastMaskCol = firstMaskCol + maskSize - 1;
7126  firstMaskCol = Max (firstMaskCol, (kkint32)0);
7127  lastMaskCol = Min (lastMaskCol, (kkint32)(width - 1));
7128 
7129  kkint32 total = 0;
7130  kkint32 numOfCells = 0;
7131 
7132  for (maskRow = firstMaskRow; maskRow <= lastMaskRow; maskRow++)
7133  {
7134  for (maskCol = firstMaskCol; maskCol <= lastMaskCol; maskCol++)
7135  {
7136  total += src[maskRow][maskCol];
7137  numOfCells++;
7138  }
7139  }
7140 
7141  dest[row][col] = (uchar)((kkint32)((float)((float)total / (float)numOfCells) + 0.5f));
7142  }
7143  }
7144 
7145  return;
7146 } /* SmoothImageChannel */
7147 
7148 
7149 
7150 
7151 
7152 RasterPtr Raster::CreateSmoothImage (kkint32 maskSize) const
7153 {
7154  RasterPtr result = AllocateARasterInstance (*this);
7155  if (maskSize < 2)
7156  return result;
7157 
7158  if (red)
7159  SmoothImageChannel (red, result->Red (), maskSize);
7160 
7161  if (green)
7162  SmoothImageChannel (green, result->Green (), maskSize);
7163 
7164  if (blue)
7165  SmoothImageChannel (blue, result->Blue (), maskSize);
7166 
7167  return result;
7168 } /* CreateSmoothImage */
7169 
7170 
7171 
7172 
7173 
7174 template<typename T>
7175 T FindKthValue (T* values,
7176  kkint32 arraySize,
7177  kkint32 Kth
7178  )
7179 {
7180  T pv;
7181  kkint32 left = 0;
7182  kkint32 right = arraySize - 1;
7183 
7184 
7185  kkint32 pivotIndex = right;
7186 
7187  kkint32 partitionIndex = -1;
7188 
7189  T temp;
7190 
7191  while (partitionIndex != Kth)
7192  {
7193  pv = values[pivotIndex];
7194 
7195  partitionIndex = left;
7196  for (kkint32 i = left; i < right; i++)
7197  {
7198  if (values[i] <= pv)
7199  {
7200  if (i != partitionIndex)
7201  {
7202  temp = values[i];
7203  values[i] = values[partitionIndex];
7204  values[partitionIndex] = temp;
7205  }
7206  partitionIndex = partitionIndex + 1;
7207  }
7208  }
7209 
7210  temp = values[partitionIndex];
7211  values[partitionIndex] = values[right];
7212  values[right] = temp;
7213 
7214  if (Kth < partitionIndex)
7215  right = partitionIndex - 1;
7216  else
7217  left = partitionIndex + 1;
7218 
7219  pivotIndex = right;
7220  }
7221 
7222  return values[Kth];
7223 } /* FindKthValue */
7224 
7225 
7226 
7227 
7228 
7229 RasterPtr Raster::CreateSmoothedMediumImage (kkint32 maskSize) const
7230 {
7231  RasterPtr result = AllocateARasterInstance (*this);
7232  if (maskSize < 2)
7233  return result;
7234 
7235  uchar** destR = result->Red ();
7236  uchar** destG = result->Green ();
7237  uchar** destB = result->Blue ();
7238 
7239  kkint32 maxCandidates = maskSize * maskSize;
7240  uchar* candidatesRed = NULL;
7241  uchar* candidatesGreen = new uchar[maxCandidates];
7242  uchar* candidatesBlue = NULL;
7243  if (color)
7244  {
7245  candidatesRed = new uchar[maxCandidates];
7246  candidatesBlue = new uchar[maxCandidates];
7247  }
7248 
7249  kkint32 numCandidates = 0;
7250  kkint32 middleCandidate = 0;
7251 
7252  kkint32 row, col;
7253 
7254  kkint32 firstMaskRow, firstMaskCol;
7255  kkint32 lastMaskRow, lastMaskCol;
7256 
7257  kkint32 maskRow, maskCol;
7258 
7259  kkint32 maskOffset = maskSize / 2;
7260 
7261  //uchar* srcRow = NULL;
7262 
7263  for (row = 0; row < height; row++)
7264  {
7265  firstMaskRow = row - maskOffset;
7266  lastMaskRow = firstMaskRow + maskSize - 1;
7267 
7268  firstMaskRow = Max ((kkint32)0, firstMaskRow);
7269  lastMaskRow = Min (lastMaskRow, (kkint32)(height - 1));
7270 
7271  for (col = 0; col < width; col++)
7272  {
7273  firstMaskCol = col - maskOffset;
7274  lastMaskCol = firstMaskCol + maskSize - 1;
7275  firstMaskCol = Max (firstMaskCol, (kkint32)0);
7276  lastMaskCol = Min (lastMaskCol, (kkint32)(width - 1));
7277 
7278  //if (ForegroundPixel (row, col))
7279  //{
7280  numCandidates = 0;
7281 
7282  for (maskRow = firstMaskRow; maskRow <= lastMaskRow; maskRow++)
7283  {
7284  for (maskCol = firstMaskCol; maskCol <= lastMaskCol; maskCol++)
7285  {
7286  //if (ForegroundPixel (maskRow, maskCol))
7287  //{
7288  candidatesGreen[numCandidates] = green[maskRow][maskCol];
7289  if (color)
7290  {
7291  candidatesRed[numCandidates] = green[maskRow][maskCol];
7292  candidatesBlue[numCandidates] = green[maskRow][maskCol];
7293  }
7294  numCandidates++;
7295  //}
7296  }
7297  }
7298 
7299  middleCandidate = numCandidates / 2;
7300  uchar medium = FindKthValue (candidatesGreen, numCandidates, middleCandidate);
7301  destG[row][col] = medium;
7302 
7303  if (color)
7304  {
7305  medium = FindKthValue (candidatesRed, numCandidates, middleCandidate);
7306  destR[row][col] = medium;
7307  medium = FindKthValue (candidatesBlue, numCandidates, middleCandidate);
7308  destB[row][col] = medium;
7309  }
7310  //}
7311  }
7312  }
7313 
7314  delete[] candidatesRed; candidatesRed = NULL;
7315  delete[] candidatesGreen; candidatesGreen = NULL;
7316  delete[] candidatesBlue; candidatesBlue = NULL;
7317 
7318  return result;
7319 } /* CreateSmoothedMediumImage */
7320 
7321 
7322 
7323 
7324 
7325 
7326 RasterPtr Raster::HalfSize ()
7327 {
7328  kkint32 hHeight = kkint32 (height / 2);
7329  kkint32 hWidth = kkint32 (width / 2);
7330 
7331  RasterPtr halfSize = AllocateARasterInstance (hHeight, hWidth, color);
7332 
7333  kkint32 row = 0;
7334  kkint32 col = 0;
7335  kkint32 hRow, hCol;
7336  for (hRow = 0; hRow < hHeight; hRow++)
7337  {
7338  col = 0;
7339  for (hCol = 0; hCol < hWidth; hCol++)
7340  {
7341  halfSize->SetPixelValue (hRow, hCol, green[row][col]);
7342  if (color)
7343  {
7344  halfSize->SetPixelValue (ColorChannels::Red, hRow, hCol, red [row][col]);
7345  halfSize->SetPixelValue (ColorChannels::Blue, hRow, hCol, blue[row][col]);
7346  }
7347 
7348  col += 2;
7349  }
7350 
7351  row += 2;
7352  }
7353 
7354  return halfSize;
7355 } /* HalfSize */
7356 
7357 
7358 
7359 
7360 
7361 RasterPtr Raster::ReduceByEvenMultiple (kkint32 multiple) const
7362 {
7363  // We will pad one extra pixel top, bot, left, and right.
7364  // This is necessary because some feature calculations assume that there edge rows are empty.
7365 
7366  kkint32 nHeight = kkint32 (height / multiple) + 2;
7367  kkint32 nWidth = kkint32 (width / multiple) + 2;
7368 
7369  kkint32 row = 0;
7370  kkint32 col = 0;
7371  kkint32 nRow, nCol;
7372 
7373  kkuint32** workRaster = new kkuint32*[nHeight];
7374  uchar** workDivisor = new uchar*[nHeight];
7375  kkuint32* workRow = NULL;
7376 
7377  uchar* workDivisorRow = NULL;
7378 
7379  for (nRow = 0; nRow < nHeight; nRow++)
7380  {
7381  workRow = new kkuint32[nWidth];
7382  workRaster[nRow] = workRow;
7383 
7384  workDivisorRow = new uchar[nWidth];
7385  workDivisor[nRow] = workDivisorRow;
7386 
7387  for (nCol = 0; nCol < nWidth; nCol++)
7388  {
7389  workRow[nCol] = 0;
7390  workDivisorRow[nCol] = 0;
7391  }
7392  }
7393 
7394  nRow = 1;
7395  kkint32 intermediateRow = 0;
7396  kkint32 intermediateCol = 0;
7397  uchar* srcRow = NULL;
7398 
7399  for (row = 0; row < height; row++)
7400  {
7401  srcRow = green[row];
7402  intermediateCol = 0;
7403  nCol = 1;
7404  workRow = workRaster[nRow];
7405  workDivisorRow = workDivisor[nRow];
7406 
7407  for (col = 0; col < width; col++)
7408  {
7409  workRow[nCol] += srcRow[col];
7410  workDivisorRow[nCol]++;
7411 
7412  intermediateCol++;
7413  if (intermediateCol >= multiple)
7414  {
7415  intermediateCol = 0;
7416  nCol++;
7417  }
7418  }
7419 
7420  intermediateRow++;
7421  if (intermediateRow >= multiple)
7422  {
7423  intermediateRow = 0;
7424  nRow++;
7425  }
7426  }
7427 
7428  RasterPtr reducedRaster = AllocateARasterInstance (nHeight, nWidth, false);
7429 
7430  uchar* destRow = NULL;
7431 
7432  kkint32 newPixelVal = 0;
7433  kkint32 nMaxPixVal = 0;
7434  kkint32 nForegroundPixelCount = 0;
7435 
7436  for (nRow = 0; nRow < nHeight; nRow++)
7437  {
7438  destRow = (reducedRaster->Green ())[nRow];
7439  workRow = workRaster[nRow];
7440  workDivisorRow = workDivisor[nRow];
7441 
7442  for (nCol = 0; nCol < nWidth; nCol++)
7443  {
7444  newPixelVal = workRow[nCol];
7445  if (newPixelVal > 0)
7446  {
7447  nForegroundPixelCount++;
7448  newPixelVal = (kkint32)(0.5f + (float)(newPixelVal) / (float)(workDivisorRow[nCol]));
7449  destRow[nCol] = (uchar)(newPixelVal);
7450  if (newPixelVal > nMaxPixVal)
7451  nMaxPixVal = newPixelVal;
7452  }
7453  }
7454 
7455  delete workRaster[nRow];
7456  delete workDivisor[nRow];
7457  workRaster[nRow] = NULL;
7458  workDivisor[nRow] = NULL;
7459  }
7460  delete[] workRaster;
7461  workRaster = NULL;
7462  delete[] workDivisor;
7463  workDivisor = NULL;
7464 
7465  reducedRaster->ForegroundPixelCount (nForegroundPixelCount);
7466  reducedRaster->MaxPixVal ((uchar)nMaxPixVal);
7467 
7468  return reducedRaster;
7469 } /* ReduceByEvenMultiple */
7470 
7471 
7472 
7473 RasterPtr Raster::ReduceByFactor (float factor) const // 0 < factor <= 1.0
7474 {
7475  if (factor <= 0.0f)
7476  factor = 0.1f;
7477 
7478  else if (factor > 1.0f)
7479  factor = 1.0f;
7480 
7481  kkint32 c, r;
7482 
7483  kkint32 newR;
7484 
7485  kkint32 newHeight = (kkint32)(height * factor + 0.5f);
7486  kkint32 newWidth = (kkint32)(width * factor + 0.5f);
7487  if (newHeight < 2)
7488  newHeight = 2;
7489 
7490  if (newWidth < 2)
7491  newWidth = 2;
7492 
7493  kkint32 newTotal = newHeight * newWidth;
7494 
7495  float* accumulatorAreaGreen = new float[newTotal];
7496  float* accumulatorAreaRed = NULL;
7497  float* accumulatorAreaBlue = NULL;
7498  if (color)
7499  {
7500  accumulatorAreaRed = new float[newTotal];
7501  accumulatorAreaBlue = new float[newTotal];
7502  memset (accumulatorAreaRed, 0, newTotal * sizeof (float));
7503  memset (accumulatorAreaBlue, 0, newTotal * sizeof (float));
7504  }
7505 
7506  float* divisorArea = new float[newTotal];
7507 
7508  memset (accumulatorAreaGreen, 0, newTotal * sizeof (float));
7509  memset (divisorArea, 0, newTotal * sizeof (float));
7510 
7511  float** accumulatorRed = NULL;
7512  float** accumulatorGreen = new float*[newHeight];
7513  float** accumulatorBlue = NULL;
7514 
7515  if (color)
7516  {
7517  accumulatorRed = new float*[newHeight];
7518  accumulatorBlue = new float*[newHeight];
7519  }
7520 
7521 
7522  float** divisor = new float*[newHeight];
7523 
7524  float* rowFactor = new float[height + 1];
7525  float* colFactor = new float[width + 1];
7526 
7527  for (r = 0; r < height; r++)
7528  rowFactor[r] = r * factor;
7529  rowFactor[height] = (float)newHeight;
7530 
7531  for (c = 0; c < width; c++)
7532  colFactor[c] = c * factor;
7533  colFactor[width] = (float)newWidth;
7534 
7535  float* arPtr = accumulatorAreaRed;
7536  float* agPtr = accumulatorAreaGreen;
7537  float* abPtr = accumulatorAreaBlue;
7538  float* daPtr = divisorArea;
7539  for (newR = 0; newR < newHeight; newR++)
7540  {
7541  accumulatorGreen [newR] = agPtr;
7542  divisor [newR] = daPtr;
7543  agPtr += newWidth;
7544  daPtr += newWidth;
7545 
7546  if (color)
7547  {
7548  accumulatorRed [newR] = arPtr;
7549  accumulatorBlue[newR] = abPtr;
7550  arPtr += newWidth;
7551  abPtr += newWidth;
7552  }
7553  }
7554 
7555  uchar rValue = 0, gValue = 0, bValue = 0;
7556 
7557  for (r = 0; r < height; r++)
7558  {
7559  kkint32 thisRow = (kkint32)rowFactor[r];
7560  if (thisRow >= newHeight)
7561  thisRow = newHeight - 1;
7562 
7563  kkint32 nextRow = (kkint32)rowFactor[r + 1];
7564  if (nextRow >= newHeight)
7565  nextRow = newHeight - 1;
7566 
7567  float amtThisRow = 1.0f;
7568  float amtNextRow = 0.0f;
7569 
7570  if (nextRow > thisRow)
7571  {
7572  amtThisRow = (float)nextRow - rowFactor[r];
7573  amtNextRow = 1.0f - amtThisRow;
7574  }
7575 
7576  for (c = 0; c < width; c++)
7577  {
7578  gValue = green[r][c];
7579  if (color)
7580  {
7581  rValue = red [r][c];
7582  bValue = blue[r][c];
7583  }
7584 
7585  kkint32 thisCol = (kkint32)colFactor[c];
7586  if (thisCol >= newWidth)
7587  thisCol = newWidth - 1;
7588 
7589  kkint32 nextCol = (kkint32)colFactor[c + 1];
7590  if (nextCol >= newWidth)
7591  nextCol = newWidth - 1;
7592 
7593  float amtThisCol = 1.0f;
7594  float amtNextCol = 0.0f;
7595 
7596  if (nextCol > thisCol)
7597  {
7598  amtThisCol = (float)nextCol - colFactor[c];
7599  amtNextCol = 1.0f - amtThisCol;
7600  }
7601 
7602  accumulatorGreen[thisRow][thisCol] += gValue * amtThisRow * amtThisCol;
7603  if (color)
7604  {
7605  accumulatorRed [thisRow][thisCol] += rValue * amtThisRow * amtThisCol;
7606  accumulatorBlue[thisRow][thisCol] += bValue * amtThisRow * amtThisCol;
7607  }
7608 
7609  divisor [thisRow][thisCol] += amtThisRow * amtThisCol;
7610 
7611  if (nextRow > thisRow)
7612  {
7613  accumulatorGreen[nextRow][thisCol] += gValue * amtNextRow * amtThisCol;
7614  if (color)
7615  {
7616  accumulatorRed [nextRow][thisCol] += rValue * amtNextRow * amtThisCol;
7617  accumulatorBlue[nextRow][thisCol] += bValue * amtNextRow * amtThisCol;
7618  }
7619  divisor [nextRow][thisCol] += amtNextRow * amtThisCol;
7620 
7621  if (nextCol > thisCol)
7622  {
7623  accumulatorGreen[nextRow][nextCol] += gValue * amtNextRow * amtNextCol;
7624  if (color)
7625  {
7626  accumulatorRed [nextRow][nextCol] += rValue * amtNextRow * amtNextCol;
7627  accumulatorBlue[nextRow][nextCol] += bValue * amtNextRow * amtNextCol;
7628  }
7629  divisor [nextRow][nextCol] += amtNextRow * amtNextCol;
7630  }
7631  }
7632  else
7633  {
7634  if (nextCol > thisCol)
7635  {
7636  accumulatorGreen[thisRow][nextCol] += gValue * amtThisRow * amtNextCol;
7637  if (color)
7638  {
7639  accumulatorRed [thisRow][nextCol] += rValue * amtThisRow * amtNextCol;
7640  accumulatorBlue[thisRow][nextCol] += bValue * amtThisRow * amtNextCol;
7641  }
7642  divisor [thisRow][nextCol] += amtThisRow * amtNextCol;
7643  }
7644  }
7645  } /* for (c) */
7646  } /* for (r) */
7647 
7648  kkint32 x;
7649  RasterPtr reducedRaster = AllocateARasterInstance (newHeight, newWidth, color);
7650  uchar* newRedArea = reducedRaster->RedArea ();
7651  uchar* newGreenArea = reducedRaster->GreenArea ();
7652  uchar* newBlueArea = reducedRaster->BlueArea ();
7653  for (x = 0; x < newTotal; x++)
7654  {
7655  if (divisorArea[x] == 0.0f)
7656  {
7657  newGreenArea[x] = 0;
7658  if (color)
7659  {
7660  newRedArea [x] = 0;
7661  newBlueArea[x] = 0;
7662  }
7663  }
7664  else
7665  {
7666  newGreenArea[x] = (uchar)(accumulatorAreaGreen[x] / divisorArea[x] + 0.5f);
7667  if (color)
7668  {
7669  newRedArea [x] = (uchar)(accumulatorAreaRed [x] / divisorArea[x] + 0.5f);
7670  newBlueArea[x] = (uchar)(accumulatorAreaBlue[x] / divisorArea[x] + 0.5f);
7671  }
7672  }
7673 
7674  }
7675 
7676  delete[] accumulatorAreaRed; accumulatorAreaRed = NULL;
7677  delete[] accumulatorAreaGreen; accumulatorAreaGreen = NULL;
7678  delete[] accumulatorAreaBlue; accumulatorAreaBlue = NULL;
7679 
7680  delete[] divisorArea; divisorArea = NULL;
7681 
7682  delete[] accumulatorRed; accumulatorRed = NULL;
7683  delete[] accumulatorGreen; accumulatorGreen = NULL;
7684  delete[] accumulatorBlue; accumulatorBlue = NULL;
7685  delete[] divisor; divisor = NULL;
7686 
7687  delete[] rowFactor; rowFactor = NULL;
7688  delete[] colFactor; colFactor = NULL;
7689 
7690  return reducedRaster;
7691 } /* ReduceByFactor */
7692 
7693 
7694 
7695 
7696 RasterPtr Raster::SobelEdgeDetector () const
7697 {
7698  MorphOpSobel sobel;
7699  return sobel.PerformOperation (this);
7700 } /* SobelEdgeDetector */
7701 
7702 
7703 
7704 
7706  uchar max
7707  ) const
7708 {
7709  MorphOpBinarize binarizer (min, max);
7710  RasterPtr result = binarizer.PerformOperation (this);
7711  return result;
7712 } /* BinarizeByThreshold */
7713 
7714 
7715 
7716 
7718 {
7719  if (!color)
7720  return AllocateARasterInstance (*this);
7721 
7723 
7724  uchar* src = NULL;
7725 
7726  KKStr rootName = osGetRootName (FileName ());
7727 
7728  if (channel == ColorChannels::Red)
7729  {
7730  r->FileName (rootName + "_Red.bmp") ;
7731  src = RedArea ();
7732  }
7733 
7734  else if (channel == ColorChannels::Green)
7735  {
7736  r->FileName (rootName + "_Green.bmp") ;
7737  src = GreenArea ();
7738  }
7739 
7740  else
7741  {
7742  r->FileName (rootName + "_Blue.bmp") ;
7743  src = BlueArea ();
7744  }
7745 
7746  uchar* dest = r->GreenArea ();
7747 
7748  memcpy (dest, src, totPixels);
7749 
7750  return r;
7751 } /* ExtractChannel */
7752 
7753 
7754 
7755 
7756 /**
7757  *@brief Extracts the pixel locations where the 'mask' images pixel location is a foreground pixel.
7758  */
7760 {
7761  RasterPtr result = new Raster (height, width, color);
7765 
7766  if (!mask)
7767  return result;
7768 
7769  int heighToUse = Min (height, mask->Height ());
7770  int widthToUse = Min (width, mask->Width ());
7771 
7772  uchar maskBackgroundValue = mask->BackgroundPixelValue ();
7773  uchar maskBackgroundTH = mask->BackgroundPixelTH ();
7774 
7775 
7776  for (int row = 0; row < heighToUse; ++row)
7777  {
7778  uchar* maskRow = (mask->Green ())[row];
7779 
7780  uchar* resultGreenRow = (result->Green ())[row];
7781  uchar* srcGreenRow = green[row];
7782 
7783  uchar* resultRedRow = NULL;
7784  uchar* srcRedRow = NULL;
7785 
7786  uchar* resultBlueRow = NULL;
7787  uchar* srcBlueRow = NULL;
7788 
7789  if (color)
7790  {
7791  resultRedRow = (result->Red ())[row];
7792  srcRedRow = red[row];
7793  resultBlueRow = (result->Blue ())[row];
7794  srcBlueRow = blue[row];
7795  }
7796 
7797  for (int col = 0; col < widthToUse; ++col)
7798  {
7799  bool backgroundPix = (maskBackgroundValue < 125) ? (maskRow[col] <= maskBackgroundTH) : (maskRow[col] >= maskBackgroundTH);
7800  bool usePixel = !backgroundPix;
7801  if (usePixel)
7802  {
7803  resultGreenRow[col] = srcGreenRow[col];
7804  if (color)
7805  {
7806  resultRedRow [col] = srcRedRow [col];
7807  resultBlueRow[col] = srcBlueRow [col];
7808  }
7809  }
7810  }
7811  }
7812  return result;
7813 } /* ExtractUsingMask */
7814 
7815 
7816 
7817 
7818 
7819 
7820 //*******************************************************************************
7821 //* Wrote this method to deal with pollution sample particles, needed to help *
7822 //* segment out particles from a very noisy background. *
7823 //******************************************************************************
7824 RasterPtr Raster::SegmentImage (bool save)
7825 {
7826  KKStr rootName = osGetRootName (fileName);
7827  KKStr dirName = "c:\\Temp\\PolutionImages\\" + rootName;
7828  if (save)
7829  osCreateDirectoryPath (dirName);
7830  osAddLastSlash (dirName);
7831 
7832  KKStr baseName = dirName + rootName;
7833 
7834  if (save)
7835  SaveImage (*this, baseName + "_Orig.bmp");
7836 
7837  bool imageIsWhiteOnBlack = false;
7838 
7839  kkint32 r, c;
7840 
7841  float threshold;
7842 
7843  float backgroundValue;
7844  float forgroundValue;
7845 
7846  RasterPtr gsImage = NULL;
7847 
7848  if (Color ())
7849  {
7850  gsImage = CreateGrayScale ();
7851 
7855 
7856  delete redPart;
7857  delete greenPart;
7858  delete bluePart;
7859  }
7860  else
7861  {
7862  gsImage = AllocateARasterInstance (*this);
7863  }
7864 
7865  RasterPtr mask = NULL;
7866 
7867  RasterPtr smoothedImage = gsImage->CreateSmoothImage ();
7868  {
7869  // Now lets determine if white or black background
7870 
7871  uchar** g = smoothedImage->Rows ();
7872 
7873  kkint32 totalOfPixelVals = 0;
7874  kkint32 count = 0;
7875 
7876  kkint32 lastRow = Height () - 1;
7877  kkint32 lastCol = Width () - 1;
7878 
7879  for (c = 0; c < Width (); c++)
7880  {
7881  totalOfPixelVals += g[0][c];
7882  totalOfPixelVals += g[lastRow][c];
7883  count += 2;
7884  }
7885 
7886  for (r = 0; r < Height (); r++)
7887  {
7888  totalOfPixelVals += g[r][0];
7889  totalOfPixelVals += g[r][lastCol];
7890  count += 2;
7891  }
7892 
7893  threshold = (float)totalOfPixelVals / (float)count;
7894 
7895  imageIsWhiteOnBlack = (threshold < (float)175.0);
7896  }
7897 
7898  imageIsWhiteOnBlack = false;
7899 
7900  if (imageIsWhiteOnBlack)
7901  {
7902  gsImage->BackgroundPixelValue (0);
7903  gsImage->ForegroundPixelValue (255);
7904  }
7905  else
7906  {
7907  gsImage->BackgroundPixelValue (255);
7908  gsImage->ForegroundPixelValue (0);
7909  }
7910 
7911  if (save)
7912  {
7913  SaveImage (*gsImage, baseName + "_GrayScale.bmp");
7914  SaveImage (*smoothedImage, baseName + "_Smoothed.bmp");
7915  }
7916 
7917 
7918  {
7919  HistogramPtr grayScaleHistogram = smoothedImage->HistogramGrayscale ();
7920 
7921  if (save)
7922  {
7923  grayScaleHistogram->Save (baseName + "_Histogram.txt");
7924  grayScaleHistogram->SaveGraphImage (baseName + "_Histogram.bmp");
7925  }
7926 
7927  HistogramPtr grayScaleHistogramSmoothed = grayScaleHistogram->Smooth (4);
7928 
7929  if (save)
7930  {
7931  grayScaleHistogramSmoothed->Save (baseName + "_HistogramSmoothed.txt");
7932  grayScaleHistogramSmoothed->SaveGraphImage (baseName + "_HistogramSmoothed.bmp");
7933  }
7934 
7935  uchar** g = smoothedImage->Rows ();
7936 
7937  if (imageIsWhiteOnBlack)
7938  {
7939  backgroundValue = grayScaleHistogramSmoothed->AverageOfMaxBucketInRange (0, 120);
7940  forgroundValue = grayScaleHistogramSmoothed->AverageOfMaxBucketInRange (130, 255);
7941  //threshold = grayScaleHistogramSmoothed->AverageOfMinBucketInRange (backgroundValue, forgroundValue);
7942  //threshold = backgroundValue + 10;
7943  threshold = (float)(backgroundValue + forgroundValue) / 2.0f;
7944  }
7945  else
7946  {
7947  backgroundValue = grayScaleHistogramSmoothed->AverageOfMaxBucketInRange (130, 255);
7948  forgroundValue = grayScaleHistogramSmoothed->AverageOfMaxBucketInRange (0, 120);
7949  //threshold = grayScaleHistogramSmoothed->AverageOfMinBucketInRange (forgroundValue, backgroundValue);
7950  //threshold = backgroundValue - 10;
7951  threshold = (float)(backgroundValue + forgroundValue) / 2.0f;
7952  }
7953 
7954  //threshold = (backgroundValue + forgroundValue) / (float)2.0;
7955 
7958  mask->ForegroundPixelValue (255);
7959 
7960  for (r = 0; r < Height (); r++)
7961  {
7962  for (c = 0; c < Width (); c++)
7963  {
7964  if (imageIsWhiteOnBlack)
7965  {
7966  if (g[r][c] > threshold)
7967  mask->SetPixelValue (r, c, 255);
7968  else
7969  mask->SetPixelValue (r, c, 0);
7970  }
7971  else
7972  {
7973  // Image is Black on White
7974  if (g[r][c] < threshold)
7975  mask->SetPixelValue (r, c, 255);
7976  else
7977  mask->SetPixelValue (r, c, 0);
7978  }
7979  }
7980  }
7981 
7982  delete grayScaleHistogramSmoothed;
7983  delete grayScaleHistogram;
7984  }
7985 
7986  if (save)
7987  SaveImage (*mask, baseName + "_Mask_" + StrFormatInt ((kkint32)threshold, "zz0") + ".bmp");
7988 
7990  destRaster->BackgroundPixelValue (255);
7991  destRaster->ForegroundPixelValue (0);
7992 
7993  for (r = 0; r < Height (); r++)
7994  {
7995  for (c = 0; c < Width (); c++)
7996  {
7997  if (mask->GetPixelValue (r, c) >= 150)
7998  {
7999  if (imageIsWhiteOnBlack)
8000  destRaster->SetPixelValue (r, c, gsImage->GetPixelValue (r, c));
8001  else
8002  destRaster->SetPixelValue (r, c, 255 - gsImage->GetPixelValue (r, c));
8003  }
8004  else
8005  {
8006  destRaster->SetPixelValue (r, c, 255);
8007  }
8008  }
8009  }
8010 
8011 
8012  delete gsImage;
8013  delete mask;
8014 
8015 
8016  if (save)
8017  SaveImage (*destRaster, baseName + "_Segmented.bmp");
8018 
8019  return destRaster;
8020 } /* SegmentImage */
8021 
8022 
8023 
8024 
8026  kkint32 numRowSplits
8027  ) const
8028 {
8029  if ((numColSplits < 1) || (numColSplits >= width))
8030  return NULL;
8031 
8032  if ((numRowSplits < 1) || (numRowSplits >= height))
8033  return NULL;
8034 
8035  RasterListPtr parts = new RasterList (true);
8036 
8037  kkint32 partStartingCol = 0;
8038  kkint32 partStartingRow = 0;
8039 
8040  // because the image might not divide evenly we may have to do some
8041  // adjusting, possibly loosing some rows and columns off the edges.
8042  kkint32 partWidth = (kkint32)((float)(width / numColSplits) + 0.5);
8043  kkint32 colsNeeded = numColSplits * partWidth;
8044  if (colsNeeded > width)
8045  {
8046  partWidth--;
8047  partStartingCol = (width - (partWidth * numColSplits)) / 2;
8048  }
8049 
8050  kkint32 partHeight = (kkint32)((float)(height / numRowSplits) + 0.5);
8051  kkint32 rowsNeeded = numRowSplits * partHeight;
8052  if (rowsNeeded > height)
8053  {
8054  partWidth--;
8055  rowsNeeded = numRowSplits * partHeight;
8056  partStartingRow = (height -rowsNeeded) / 2;
8057  }
8058 
8059  kkint32 splitRow;
8060  kkint32 splitCol;
8061 
8062  kkint32 partStartRow = partStartingRow;
8063 
8064  for (splitRow = 0; splitRow < numRowSplits; splitRow++)
8065  {
8066  kkint32 partEndRow = partStartRow + partHeight - 1;
8067 
8068  kkint32 partStartCol = partStartingCol;
8069 
8070  for (splitCol = 0; splitCol < numColSplits; splitCol++)
8071  {
8072  kkint32 partEndCol = partStartCol + partWidth - 1;
8073 
8074  RasterPtr part = new Raster (*this, partStartRow, partStartCol, partHeight, partWidth);
8075 
8076  parts->PushOnBack (part);
8077 
8078  partStartCol = partEndCol + 1;
8079  }
8080 
8081  partStartRow = partEndRow + 1;
8082  }
8083 
8084  return parts;
8085 } /* SplitImageIntoEqualParts */
8086 
8087 
8088 
8090 {
8091  Raster origRaster (*this);
8092 
8093  uchar** origGreen = origRaster.green;
8094 
8095  kkint32 r;
8096  kkint32 c;
8097 
8098  kkint32 firstRow = 1;
8099  kkint32 firstCol = 1;
8100  kkint32 lastRow = height - 1;
8101  kkint32 lastCol = width - 1;
8102 
8103  for (r = firstRow; r < lastRow; r++)
8104  {
8105  for (c = firstCol; c < lastCol; c++)
8106  {
8107  if (ForegroundPixel (green[r][c]))
8108  {
8109  // We have a foreground Pixel.
8110 
8111  if ((BackgroundPixel (origGreen[r - 1][c - 1])) &&
8112  (BackgroundPixel (origGreen[r - 1][c] )) &&
8113  (BackgroundPixel (origGreen[r - 1][c + 1])) &&
8114  (BackgroundPixel (origGreen[r ][c - 1])) &&
8115  (BackgroundPixel (origGreen[r ][c + 1])))
8116  {
8117  // Top Spur
8118  green[r][c] = backgroundPixelValue;
8119  }
8120 
8121  else
8122  if ((BackgroundPixel (origGreen[r - 1][c - 1])) &&
8123  (BackgroundPixel (origGreen[r ][c - 1])) &&
8124  (BackgroundPixel (origGreen[r + 1][c + 1])) &&
8125  (BackgroundPixel (origGreen[r - 1][c ])) &&
8126  (BackgroundPixel (origGreen[r + 1][c ])))
8127  {
8128  // Left Spur
8129  green[r][c] = backgroundPixelValue;
8130  }
8131 
8132  else
8133  if ((BackgroundPixel (origGreen[r + 1][c - 1])) &&
8134  (BackgroundPixel (origGreen[r + 1][c ])) &&
8135  (BackgroundPixel (origGreen[r + 1][c + 1])) &&
8136  (BackgroundPixel (origGreen[r ][c - 1])) &&
8137  (BackgroundPixel (origGreen[r ][c + 1])))
8138  {
8139  // Bottom Spur
8140  green[r][c] = backgroundPixelValue;
8141  }
8142 
8143  else
8144  if ((BackgroundPixel (origGreen[r - 1][c + 1])) &&
8145  (BackgroundPixel (origGreen[r ][c + 1])) &&
8146  (BackgroundPixel (origGreen[r + 1][c + 1])) &&
8147  (BackgroundPixel (origGreen[r - 1][c ])) &&
8148  (BackgroundPixel (origGreen[r + 1][c ])))
8149  {
8150  // Right Spur
8151  green[r][c] = backgroundPixelValue;
8152  }
8153  }
8154  }
8155  }
8156 } /* ErodeSpurs */
8157 
8158 
8159 
8160 
8161 //****************************************************************
8162 //* The following ThinningCode was lifted out of a IPL98
8163 //* Library and modified to conform with this object.
8164 //***************************************************************
8165 //
8166 // The Image Processing Library 98, IPL98
8167 // by Ren Dencker Eriksen - edr@mip.sdu.dk
8168 //
8169 // from module "~\ipl98\source\ipl98\kernel_c\algorithms\kernel_morphology.c"
8170 //
8171 
8172 //#define DEBUG_ThinContour
8173 
8174 #if defined(DEBUG_ThinContour)
8175  kkint32 rasterGlobalHeight = 0;
8176  kkint32 rasterGlobalWidth = 0;
8177 #endif
8178 
8179 
8180 bool k_ThinningStep2cdTests (uchar m_Matrix22[][3]);
8181 
8182 bool k_ThinningStep1cdTests (uchar m_Matrix22[][3]);
8183 
8184 bool k_ThinningCheckTransitions (uchar m_Matrix22[][3]);
8185 
8186 
8187 RasterPtr Raster::ThinContour () const
8188 {
8189  #if defined(DEBUG_ThinContour)
8190  cout << std::endl << std::endl
8191  << "Raster::ThinContour" << std::endl
8192  << std::endl;
8193 
8194  rasterGlobalHeight = height;
8195  rasterGlobalWidth = width;
8196  #endif
8197 
8198 
8199  bool PointsRemoved = false;
8200  uchar m_Matrix22[3][3];
8201 
8202  kkint32 Iter = 0;
8203  kkint32 prem1;
8204  kkint32 prem2;
8205  kkint32 iCountX, iCountY;
8206  kkint32 pntinpic=0;
8207 
8208 
8209  PointList pointList (true);
8210  PointList removeList (true);
8211 
8212  //ContourFollower contourFollwer (*this);
8213  //PointListPtr borderPixs = contourFollower.GenerateContourList (blob);
8214 
8215  RasterPtr workRaster = AllocateARasterInstance (*this);
8216  workRaster->ConnectedComponent (3);
8217 
8218  uchar** workGreen = workRaster->Green ();
8219  workRaster->ErodeSpurs ();
8220  // workRaster->Dilation ();
8221 
8222  // k_SetBorder(1,1,pImg);
8223  PointsRemoved = false;
8224  Iter++;
8225 
8226 
8227  /* step 1 Collecting the Black point in a list */
8228  prem1 = prem2 = 0;
8229 
8230 
8231  kkint32 minCol, maxCol, minRow, maxRow;
8232 
8233  workRaster->FindBoundingBox (minRow,
8234  minCol,
8235  maxRow,
8236  maxCol
8237  );
8238 
8239  if ((minRow > maxRow) || (minRow < 0) || (minCol < 0))
8240  {
8241  #if defined(DEBUG_ThinContour)
8242  cout << std::endl << std::endl
8243  << "Raster::ThinContour 'FindBoundingBox'" << std::endl
8244  << " minRow[" << minRow << "] maxRow[" << maxRow << "]" << std::endl
8245  << std::endl;
8246  cout.flush ();
8247  #endif
8248  // We must have a empty raster. In this case there is nothing else we can do.
8249  return workRaster;
8250  }
8251 
8252  for (iCountY = minRow; iCountY <= maxRow; iCountY++)
8253  {
8254  minCol = 999999;
8255  maxCol = -1;
8256 
8257  for (kkint32 x = 0; x < width; x++)
8258  {
8259  if (ForegroundPixel (workGreen[iCountY][x]))
8260  {
8261  maxCol = Max (maxCol, x);
8262  minCol = Min (minCol, x);
8263  }
8264  }
8265 
8266  for (iCountX = minCol; iCountX <= maxCol; iCountX++)
8267  {
8268  if (ForegroundPixel (workGreen[iCountY][iCountX]))
8269  {
8270  PointPtr tempPoint = new Point (iCountY, iCountX);
8271  pntinpic++;
8272 
8273  if (ThinningSearchNeighbors (iCountX, iCountY, workGreen, &m_Matrix22[0]) &&
8274  k_ThinningCheckTransitions (&m_Matrix22[0]) &&
8275  k_ThinningStep1cdTests (&m_Matrix22[0])
8276  )
8277  {
8278  prem1++;
8279  PointsRemoved = true;
8280  removeList.PushOnBack (tempPoint);
8281  }
8282  else
8283  {
8284  pointList.PushOnBack (tempPoint);
8285  }
8286  }
8287  }
8288  }
8289 
8290  #if defined(DEBUG_ThinContour)
8291  cout << "Total black points:" << pntinpic << "\n";
8292  cout.flush ();
8293  #endif
8294 
8295 
8296  /* Set all pixels positions in RemoveList in image to white */
8297  {
8298  PointPtr pixel = removeList.PopFromFront ();
8299  while (pixel)
8300  {
8301  workGreen[pixel->Row ()][pixel->Col ()] = backgroundPixelValue;
8302  delete pixel;
8303  pixel = removeList.PopFromFront ();
8304  }
8305  }
8306 
8307  removeList.DeleteContents ();
8308 
8309 
8310  /* step 2 after step 1 which inserted points in list */
8311  if (PointsRemoved)
8312  {
8313  #if defined(DEBUG_ThinContour)
8314  cout << "PointsRemoved = true" << pntinpic << "\n";
8315  cout.flush ();
8316  #endif
8317 
8318  PointPtr tempPoint = NULL;
8319 
8320  for (iCountX = 0; iCountX < pointList.QueueSize (); iCountX++)
8321  {
8322  tempPoint = pointList.IdxToPtr (iCountX);
8323  if (tempPoint == NULL)
8324  continue;
8325 
8326  if (ThinningSearchNeighbors (tempPoint->Col (), tempPoint->Row (), workGreen, &m_Matrix22[0]) &&
8327  k_ThinningCheckTransitions (&m_Matrix22[0]) &&
8328  k_ThinningStep2cdTests (&m_Matrix22[0])
8329  )
8330  {
8331  prem2++;
8332  PointsRemoved = true;
8333 
8334  //pointList.DeleteEntry (iCountX);
8335  pointList.SetIdxToPtr (iCountX, NULL);
8336  removeList.PushOnBack (tempPoint);
8337  //iCountX--; /* Must decrease iCountX when a point has been removed */
8338  }
8339  }
8340  }
8341 
8342  /* Set all pixels positions in RemoveList in image to white */
8343  {
8344  PointPtr pixel = removeList.PopFromFront ();
8345  while (pixel)
8346  {
8347  workGreen[pixel->Row ()][pixel->Col ()] = backgroundPixelValue;
8348  delete pixel;
8349  pixel = removeList.PopFromFront ();
8350  }
8351  }
8352 
8353  removeList.DeleteContents ();
8354  #if defined(DEBUG_ThinContour)
8355  cout << "Iteration " << Iter << ": Points removed: " << prem1 << " + " << prem2 << " = " << prem1+prem2 << "\n";
8356  cout.flush ();
8357  #endif
8358 
8359  #if defined(DEBUG_ThinContour)
8360  cout << std::endl << "ThinContour Starting Step 1 PointsRemoved[" << (PointsRemoved?"True":"False") << "]" << "\n";
8361  cout.flush ();
8362  #endif
8363  /* step 1 */
8364  while (PointsRemoved)
8365  {
8366  PointPtr tempPoint = NULL;
8367 
8368  prem1 = prem2 = 0;
8369 
8370  Iter++;
8371  PointsRemoved = false;
8372 
8373  for (iCountX = 0; iCountX < pointList.QueueSize (); iCountX++)
8374  {
8375  tempPoint = pointList.IdxToPtr (iCountX);
8376  if (tempPoint == NULL)
8377  continue;
8378 
8379  if ((ThinningSearchNeighbors (tempPoint->Col (), tempPoint->Row (), workGreen, &m_Matrix22[0])) &&
8380  (k_ThinningCheckTransitions (&m_Matrix22[0])) &&
8381  (k_ThinningStep1cdTests (&m_Matrix22[0]))
8382  )
8383  {
8384  prem1++;
8385  PointsRemoved = true;
8386 
8387  /*k_RemovePosFromGroupSlow(iCountX,&PointList);*/
8388 
8389  //pointList.DeleteEntry (iCountX);
8390  pointList.SetIdxToPtr (iCountX, NULL);
8391  removeList.PushOnBack (tempPoint);
8392  //iCountX--; /* Must decrease iCountX when a point has been removed */
8393  }
8394  }
8395 
8396  /* Set all pixels positions in Remove List in image to white */
8397  #if defined(DEBUG_ThinContour)
8398  cout << "Set all pixels positions in Remove List in image to white. removeList.size()=[" << removeList.size () << "]" << "\n";
8399  cout.flush ();
8400  #endif
8401 
8402  {
8403  PointPtr pixel = removeList.PopFromFront ();
8404  while (pixel)
8405  {
8406  workGreen[pixel->Row ()][pixel->Col ()] = backgroundPixelValue;
8407  delete pixel;
8408  pixel = removeList.PopFromFront ();
8409  }
8410 
8411  removeList.DeleteContents ();
8412  }
8413 
8414 
8415  #if defined(DEBUG_ThinContour)
8416  cout << "ThinContour Starting Step 2" << "\n";
8417  cout.flush ();
8418  #endif
8419  /* step 2 */
8420  for (iCountX = 0; iCountX < pointList.QueueSize (); iCountX++)
8421  {
8422  tempPoint = pointList.IdxToPtr (iCountX);
8423  if (tempPoint == NULL)
8424  continue;
8425 
8426  if (ThinningSearchNeighbors (tempPoint->Col (), tempPoint->Row (), workGreen, &m_Matrix22[0]) &&
8427  k_ThinningCheckTransitions (&m_Matrix22[0]) &&
8428  k_ThinningStep2cdTests (&m_Matrix22[0])
8429  )
8430  {
8431  prem2++;
8432  PointsRemoved = true;
8433 
8434  /*k_RemovePosFromGroupSlow(iCountX,&PointList);*/
8435  //pointList.DeleteEntry (iCountX);
8436  pointList.SetIdxToPtr (iCountX, NULL);
8437  removeList.PushOnBack (tempPoint);
8438  //iCountX--; /* Must decrease iCountX when a point has been removed */
8439  }
8440  }
8441 
8442 
8443  #if defined(DEBUG_ThinContour)
8444  cout << "ThinContour LastStep in loop" << "\n";
8445  cout.flush ();
8446  #endif
8447 
8448  /* Set all pixels positions in RemoveList in image to white */
8449  {
8450  PointPtr pixel = removeList.PopFromFront ();
8451  while (pixel)
8452  {
8453  workGreen[pixel->Row ()][pixel->Col ()] = backgroundPixelValue;
8454  delete pixel;
8455  pixel = removeList.PopFromFront ();
8456  }
8457 
8458  removeList.DeleteContents ();
8459  }
8460 
8461  #if defined(DEBUG_ThinContour)
8462  cout << "Iteration " << Iter << ": Points removed: " << prem1 << " + " << prem2 << " = " << prem1 + prem2 << "\n";
8463  cout.flush ();
8464  #endif
8465 
8466  }
8467 
8468  #if defined(DEBUG_ThinContour)
8469  cout << "ThinContour Ready to Exit; going to DeleteContents of 'pointList' and 'removeList'." << "\n";
8470  cout.flush ();
8471  #endif
8472 
8473 
8474  pointList.DeleteContents ();
8475  removeList.DeleteContents ();
8476 
8477  #if defined(DEBUG_ThinContour)
8478  cout << "ThinContour Exiting'." << "\n";
8479  cout.flush ();
8480  #endif
8481 
8482  return workRaster;
8483 } /* ThinContour */
8484 
8485 
8486 
8487 
8488 
8489 
8490 
8491 /* performs the tests (c') and (d') in step 2 as explained in Gonzales and Woods page 493 */
8492 
8493 bool k_ThinningStep2cdTests (uchar m_Matrix22[][3])
8494 {
8495  if ((m_Matrix22[1][0] + m_Matrix22[2][1] + m_Matrix22[0][1]) &&
8496  (m_Matrix22[1][0] + m_Matrix22[1][2] + m_Matrix22[0][1])
8497  )
8498  return true;
8499  else
8500  return false;
8501 }
8502 
8503 
8504 
8505 /* performs the tests (c) and (d) in step 1 as explained in Gonzales and Woods page 492 */
8506 
8507 bool k_ThinningStep1cdTests (uchar m_Matrix22[][3])
8508 {
8509  if ((m_Matrix22[1][0] + m_Matrix22[2][1] + m_Matrix22[1][2]) &&
8510  (m_Matrix22[2][1] + m_Matrix22[1][2] + m_Matrix22[0][1])
8511  )
8512  return true;
8513  else
8514  return false;
8515 }
8516 
8517 
8518 
8519 /* returns true if there is exactly one transition in the region around the actual pixel */
8520 bool k_ThinningCheckTransitions(uchar m_Matrix22[][3])
8521 {
8522  kkint32 iTransitions=0;
8523 
8524  if ((m_Matrix22[0][0]==1) && (m_Matrix22[1][0]==0)){
8525  ++iTransitions;}
8526 
8527  if ((m_Matrix22[1][0]==1) && (m_Matrix22[2][0]==0)){
8528  ++iTransitions;}
8529 
8530  if ((m_Matrix22[2][0]==1) && (m_Matrix22[2][1]==0)){
8531  ++iTransitions;}
8532 
8533  if ((m_Matrix22[2][1]==1) && (m_Matrix22[2][2]==0)){
8534  ++iTransitions;}
8535 
8536  if ((m_Matrix22[2][2]==1) && (m_Matrix22[1][2]==0)){
8537  ++iTransitions;}
8538 
8539  if ((m_Matrix22[1][2]==1) && (m_Matrix22[0][2]==0)){
8540  ++iTransitions;}
8541 
8542  if ((m_Matrix22[0][2]==1) && (m_Matrix22[0][1]==0)){
8543  ++iTransitions;}
8544 
8545  if ((m_Matrix22[0][1]==1) && (m_Matrix22[0][0]==0)){
8546  ++iTransitions;}
8547 
8548  if (iTransitions==1)
8549  return true;
8550  else
8551  return false;
8552 } /* k_ThinningCheckTransitions */
8553 
8554 
8555 
8556 
8557 
8558 bool Raster::ThinningSearchNeighbors (kkint32 x, // column
8559  kkint32 y, // row
8560  uchar** g,
8561  uchar m_Matrix22[][3]
8562  )
8563  const
8564 /* As (a) in Gonzales and Woods, between 2 and 6 black neighbors */
8565 {
8566  #if defined(DEBUG_ThinContour)
8567  if ((x < 1) || (x >= (rasterGlobalWidth - 1)))
8568  {
8569  cout << "\n"
8570  << "k_ThinningSearchNeighbors x[" << x << "] is to close to the edge." << "\n"
8571  << "\n";
8572  }
8573 
8574  if ((y < 1) || (y >= (rasterGlobalHeight - 1)))
8575  {
8576  cout << "\n"
8577  << "k_ThinningSearchNeighbors y[" << y << "] is to close to the edge." << "\n"
8578  << "\n";
8579  }
8580  #endif
8581 
8582 
8583  kkint32 BlackNeighbor = 0;
8584  //added by baishali
8585  if ((y == 0) || (x == 0) || (y >= height) || (x >= width))
8586  { }
8587  else
8588  {
8589  m_Matrix22[0][0] = (g[y - 1][x - 1] > 0) ? 0:1;
8590  m_Matrix22[1][0] = (g[y - 1][x ] > 0) ? 0:1;
8591  m_Matrix22[2][0] = (g[y - 1][x + 1] > 0) ? 0:1;
8592  m_Matrix22[0][1] = (g[y ][x - 1] > 0) ? 0:1;
8593  m_Matrix22[2][1] = (g[y ][x + 1] > 0) ? 0:1;
8594  m_Matrix22[0][2] = (g[y + 1][x - 1] > 0) ? 0:1;
8595  m_Matrix22[1][2] = (g[y + 1][x ] > 0) ? 0:1;
8596  m_Matrix22[2][2] = (g[y + 1][x + 1] > 0) ? 0:1;
8597  m_Matrix22[1][1] = (g[y ][x ] > 0) ? 0:1;
8598  }
8599 
8600  if (m_Matrix22[0][0] == 0) {++BlackNeighbor;}
8601  if (m_Matrix22[1][0] == 0) {++BlackNeighbor;}
8602  if (m_Matrix22[2][0] == 0) {++BlackNeighbor;}
8603  if (m_Matrix22[0][1] == 0) {++BlackNeighbor;}
8604  if (m_Matrix22[2][1] == 0) {++BlackNeighbor;}
8605  if (m_Matrix22[0][2] == 0) {++BlackNeighbor;}
8606  if (m_Matrix22[1][2] == 0) {++BlackNeighbor;}
8607  if (m_Matrix22[2][2] == 0) {++BlackNeighbor;}
8608 
8609 
8610  if ((BlackNeighbor >= 2) && (BlackNeighbor <= 6))
8611  return true;
8612  else
8613  return false;
8614 } /* k_ThinningSearchNeighbors */
8615 
8616 
8617 
8618 
8619 RasterPtr Raster::TightlyBounded (kkuint32 borderPixels) const
8620 {
8621  kkint32 tlRow = 0;
8622  kkint32 tlCol = 0;
8623  kkint32 brRow = 0;
8624  kkint32 brCol = 0;
8625 
8626  FindBoundingBox (tlRow, tlCol, brRow, brCol);
8627  if ((tlRow > brRow) || (tlCol > brCol))
8628  {
8629  if (borderPixels < 1)
8630  borderPixels = 1;
8631  return AllocateARasterInstance (borderPixels * 2, borderPixels * 2, color);
8632  }
8633 
8634  kkint32 newHeight = (brRow - tlRow) + borderPixels * 2 + + 1;
8635  kkint32 newWidth = (brCol - tlCol) + borderPixels * 2 + + 1;
8636 
8637  RasterPtr result = AllocateARasterInstance (newHeight, newWidth, color);
8638 
8639  uchar** newRed = result->Red ();
8640  uchar** newGreen = result->Green ();
8641  uchar** newBlue = result->Blue ();
8642 
8643  kkint32 oldR, oldC;
8644 
8645  kkint32 newR = borderPixels;
8646  for (oldR = tlRow; oldR <= brRow; oldR++)
8647  {
8648  kkint32 newC = borderPixels;
8649  for (oldC = tlCol; oldC < brCol; oldC++)
8650  {
8651  newGreen[newR][newC] = green[oldR][oldC];
8652  if (color)
8653  {
8654  newRed [newR][newC] = red [oldR][oldC];
8655  newBlue[newR][newC] = blue[oldR][oldC];
8656  }
8657 
8658  newC++;
8659  }
8660  newR++;
8661  }
8662 
8663  return result;
8664 } /* TightlyBounded */
8665 
8666 
8667 
8668 
8669 RasterPtr Raster::Transpose () const
8670 {
8671  RasterPtr result = new Raster (width, height, color);
8672 
8673  uchar** resultRed = result->Red ();
8674  uchar** resultGreen = result->Green ();
8675  uchar** resultBlue = result->Blue ();
8676 
8677  for (kkint32 row = 0; row < height; ++row)
8678  {
8679  for (kkint32 col = 0; col < width; ++col)
8680  {
8681  resultGreen[col][row] = green[row][col];
8682  if (color)
8683  {
8684  resultRed [col][row] = red [row][col];
8685  resultBlue[col][row] = blue[row][col];
8686  }
8687  }
8688  }
8689 
8690  return result;
8691 }
8692 
8693 
8694 
8695 
8696 RasterPtr Raster::ToColor () const
8697 {
8698  if (color)
8699  return AllocateARasterInstance (*this);
8700 
8702 
8703  if (this->ForegroundPixelValue () < 100)
8704  {
8705  //
8706  memcpy (r->RedArea (), greenArea, totPixels);
8707  memcpy (r->GreenArea (), greenArea, totPixels);
8708  memcpy (r->BlueArea (), greenArea, totPixels);
8709  }
8710  else
8711  {
8712  uchar* srcGreen = greenArea;
8713  uchar* targetRed = r->RedArea ();
8714  uchar* targetGreen = r->GreenArea ();
8715  uchar* targetBlue = r->BlueArea ();
8716  for (kkint32 x = 0; x < this->totPixels; ++x)
8717  {
8718  uchar pc = (255 - *srcGreen);
8719  *targetRed = pc;
8720  *targetGreen = pc;
8721  *targetBlue = pc;
8722 
8723  ++srcGreen;
8724  ++targetRed;
8725  ++targetGreen;
8726  ++targetBlue;
8727  }
8728  }
8729 
8730  return r;
8731 } /* ToColor */
8732 
8733 
8734 
8735 RasterPtr Raster::BandPass (float lowerFreqBound, /**< Number's between 0.0 and 1.0 */
8736  float upperFreqBound, /**< Represent percentage. */
8737  bool retainBackground
8738  )
8739 {
8740  #if defined(FFTW_AVAILABLE)
8741  fftwf_complex* src = NULL;
8742  fftwf_complex* dest = NULL;
8743  fftwf_plan plan = NULL;
8744  src = (fftwf_complex*)fftwf_malloc (sizeof (fftwf_complex) * totPixels);
8745  dest = (fftwf_complex*)fftwf_malloc (sizeof (fftwf_complex) * totPixels);
8746  #else
8747  KK_DFT2D_Float* forwardPlan = new KK_DFT2D_Float (height, width, true);
8748 
8749  KK_DFT2D_Float::DftComplexType* srcArea = NULL;
8750  KK_DFT2D_Float::DftComplexType** src = NULL;
8751 
8752  KK_DFT2D_Float::DftComplexType* destArea = NULL;
8753  KK_DFT2D_Float::DftComplexType** dest = NULL;
8754 
8755  forwardPlan->AllocateArray (srcArea, src);
8756  forwardPlan->AllocateArray (destArea, dest);
8757  #endif
8758 
8759  kkint32 col;
8760  kkint32 row;
8761 
8762  kkint32 idx = 0;
8763 
8764 
8765  double centerCol = (double)width / 2.0;
8766  double centerRow = (double)height / 2.0;
8767 
8768  uchar smallestPixelVal = 255;
8769  uchar largestPixelVal = 0;
8770  uchar pixelVal = 0;
8771 
8772  // float scalingFact = (float)255.0 / maxPixVal; // kk 2004-May-18
8773 
8774  for (row = 0; row < height; row++ )
8775  {
8776  for (col = 0; col < width; col++ )
8777  {
8778  pixelVal = green[row][col];
8779  if (pixelVal < smallestPixelVal)
8780  smallestPixelVal = pixelVal;
8781  if (pixelVal > largestPixelVal)
8782  largestPixelVal = pixelVal;
8783 
8784  // src[idx].re = (float)green[row][col] * scalingFact; // kk 2004-May-18
8785 
8786  #if defined(FFTW_AVAILABLE)
8787  src[idx][0] = (float)green[row][col]; // kk 2004-May-18
8788  src[idx][1] = 0.0;
8789  #else
8790  if (color)
8791  {
8792  srcArea[idx].real ((float)(0.39f * redArea[idx] + 0.59f * greenArea[idx] + 0.11f * blueArea[idx]) / 3.0f);
8793  }
8794  else
8795  {
8796  srcArea[idx].real ((float)greenArea[idx]);
8797  }
8798  srcArea[idx].imag (0.0f);
8799  #endif
8800 
8801  idx++;
8802  }
8803  }
8804 
8805  double pixelValRange = largestPixelVal - smallestPixelVal;
8806 
8807 
8808  #if defined(FFTW_AVAILABLE)
8809  plan = fftwCreateTwoDPlan (height, width, src, dest, FFTW_FORWARD, FFTW_ESTIMATE);
8810  fftwf_execute (plan);
8811  fftwDestroyPlan (plan);
8812  #else
8813  forwardPlan->Transform (src, dest);
8814  delete forwardPlan;
8815  forwardPlan = NULL;
8816  #endif
8817 
8818  // Will now perform the BandPass portion; that is we will ZERO out all
8819  // data that does not fall within the frequency range specified by
8820  // 'lowerFreqBound' and 'upperFreqBound'.
8821 
8822  double deltaRow = 0.0;
8823  double deltaRowSquared = 0.0;
8824  double deltaCol = 0.0;
8825  double deltaColSquared = 0.0;
8826 
8827 
8828  // Because the lower frequencies are further away from the center than higher frequencies
8829  // the 'lowerFreqBoundDistFromCenter' will be greater than 'upperFreqBoundDistFromCenter'
8830 
8831  double zzz = sqrt ((double)(centerCol * centerCol + centerRow * centerRow));
8832 
8833  double lowerFreqBoundDistFromCenter = (1.0 - (double)lowerFreqBound) * (double)zzz;
8834  double upperFreqBoundDistFromCenter = (1.0 - (double)upperFreqBound) * (double)zzz;
8835 
8836  double lowerFreqBoundDistFromCenterSquared = (lowerFreqBoundDistFromCenter * lowerFreqBoundDistFromCenter + 0.1f);
8837  double upperFreqBoundDistFromCenterSquared = (upperFreqBoundDistFromCenter * upperFreqBoundDistFromCenter - 0.1f);
8838 
8839  idx = 0;
8840 
8841  for (row = 0; row < height; row++ )
8842  {
8843  deltaRow = (double)row - centerRow;
8844  deltaRowSquared = deltaRow * deltaRow;
8845 
8846  for (col = 0; col < width; col++ )
8847  {
8848  deltaCol = (double)col - centerCol;
8849  deltaColSquared = deltaCol* deltaCol;
8850 
8851  double distFromCenterSquared = deltaRowSquared + deltaColSquared;
8852 
8853  if ((distFromCenterSquared > lowerFreqBoundDistFromCenterSquared) ||
8854  (distFromCenterSquared < upperFreqBoundDistFromCenterSquared)
8855  )
8856  {
8857  // We are out of the band so this data does not get passed through.
8858  #if defined(FFTW_AVAILABLE)
8859  dest[idx][0] = 0.0f;
8860  dest[idx][1] = 0.0f;
8861  #else
8862  destArea[idx].real (0.0f);
8863  destArea[idx].imag (0.0f);
8864  #endif
8865  }
8866  idx++;
8867  }
8868  }
8869 
8870  #if defined(FFTW_AVAILABLE)
8871  plan = fftwCreateTwoDPlan (height, width, src, dest, FFTW_BACKWARD, FFTW_ESTIMATE);
8872  fftwf_execute (plan);
8873  fftwDestroyPlan (plan);
8874  #else
8875  KK_DFT2D_Float* reversePlan = new KK_DFT2D_Float (height, width, false);
8876  reversePlan->Transform (dest, src);
8877  #endif
8878 
8879  // We now need to transform the Fourier results back to GreayScale.
8880  double smallestNum;
8881  double largestNum;
8882 
8883  #if defined(FFTW_AVAILABLE)
8884  smallestNum = largestNum = src[0][0];
8885  #else
8886  smallestNum = largestNum = srcArea[0].real ();
8887  #endif
8888 
8889  {
8890  double zed = 0;
8891  for (idx = 0; idx < totPixels; idx++)
8892  {
8893  #if defined(FFTW_AVAILABLE)
8894  zed = src[idx][0];
8895  #else
8896  zed = srcArea[idx].real ();
8897  #endif
8898 
8899  if (zed < smallestNum)
8900  smallestNum = zed;
8901  else if (zed > largestNum)
8902  largestNum = zed;
8903  }
8904  }
8905 
8906  double range = largestNum - smallestNum;
8907 
8908 
8910  uchar* destData = result->greenArea;
8911 
8912  {
8913  idx = 0;
8914  double zed = 0;
8915  for (idx = 0; idx < totPixels; idx++)
8916  {
8917  if (retainBackground && BackgroundPixel (greenArea[idx]))
8918  {
8919  // Since in the original source image this pixel was a background pixel; we will
8920  // continue to let it be one.
8921  destData[idx] = backgroundPixelValue;
8922  }
8923  else
8924  {
8925  #if defined(FFTW_AVAILABLE)
8926  zed = src[idx][0];
8927  #else
8928  zed = srcArea[idx].real ();
8929  #endif
8930  destData[idx] = smallestPixelVal + Min (largestPixelVal, (uchar)(0.5 + pixelValRange * (zed - smallestNum) / range));
8931  }
8932  }
8933  }
8934 
8935  #if defined(FFTW_AVAILABLE)
8936  fftwf_free (src);
8937  fftwf_free (dest);
8938  #else
8939  reversePlan->DestroyArray (srcArea, src);
8940  reversePlan->DestroyArray (destArea, dest);
8941  delete reversePlan;
8942  reversePlan = NULL;
8943  #endif
8944 
8945  return result;
8946 } /* BandPass */
8947 
8948 
8949 
8951 {
8952  if (QueueSize () < 1)
8953  return NULL;
8954 
8955  kkint32 x;
8956 
8957  RasterPtr firstRaster = IdxToPtr (0);
8958  kkint32 height = firstRaster->Height ();
8959  kkint32 width = firstRaster->Height ();
8960  kkint32 totPixels = height * width;
8961 
8962  kkuint32* totGreenArea = new kkuint32[totPixels];
8963  memset (totGreenArea, 0, totPixels * sizeof (kkuint32));
8964 
8965  kkint32 idx = 0;
8966  kkint32 rastersAdded = 0;
8967 
8968  for (idx = 0; idx < QueueSize (); idx++)
8969  {
8970  RasterPtr raster = IdxToPtr (idx);
8971  if ((raster->Height () != height) ||
8972  (raster->Width () != width)
8973  )
8974  {
8975  continue;
8976  }
8977 
8978  if (raster->Color ())
8979  {
8980  uchar* redArea = raster->RedArea ();
8981  uchar* greenArea = raster->GreenArea ();
8982  uchar* blueArea = raster->BlueArea ();
8983  for (x = 0; x < totPixels; x++)
8984  {
8985  totGreenArea[x] += (kkuint32)((float)redArea[x] * 0.39f +
8986  (float)greenArea[x] * 0.59f +
8987  (float)blueArea[x] * 0.11f +
8988  0.5f
8989  );
8990  }
8991  }
8992  else
8993  {
8994  uchar* greenArea = raster->GreenArea ();
8995  for (x = 0; x < totPixels; x++)
8996  totGreenArea[x] += greenArea[x];
8997  }
8998 
8999  rastersAdded++;
9000  }
9001 
9002  RasterPtr smoothedRaster = firstRaster->AllocateARasterInstance (height, width, false);
9003 
9004  uchar* newGreenArea = smoothedRaster->GreenArea ();
9005  for (x = 0; x < totPixels; x++)
9006  newGreenArea[x] = (uchar) (totGreenArea[x] / rastersAdded);
9007 
9008  delete[] totGreenArea;
9009 
9010  return smoothedRaster;
9011 } /* CreateSmoothedFrame */
9012 
9013 
9014 
9015 
9016 uchar* Raster::SimpleCompression (kkuint32& buffLen) const // Will create a compress image using 'SimpleCompression'
9017 {
9018  kkint32 totalPixs = height * width;
9019 
9020  SimpleCompressor compressor (totalPixs);
9021 
9022  compressor.Add16BitInt (height);
9023  compressor.Add16BitInt (width);
9024 
9025  kkint32 x;
9026  for (x = 0; x < totalPixs; x++)
9027  compressor.AddByte (greenArea[x]);
9028 
9029  return compressor.CreateCompressedBuffer (buffLen);
9030 } /* SimpleCompression */
9031 
9032 
9033 
9034 // Creates a raster from a compressedBuff created by 'SimpleCompression'
9035 RasterPtr Raster::FromSimpleCompression (const uchar* compressedBuff,
9036  kkuint32 compressedBuffLen
9037  )
9038 {
9039  // I expect simple run length compressed data to be passed in. The data was originally
9040  // compressed by SimpleCompressor and we will use the same class to decompress.
9041 
9042  // The format of the uncompressed data is very simple.
9043  // Bytes Description
9044  // 0 thru 1: Height 2 byte integer.
9045  // 2 thru 3: Width 2 byte integer.
9046  //
9047  // 4 thru (Hight * Width) - 1: Raster Data
9048  // Row 0 : (consists of 'Width' bytes.)
9049  // Row 1 : ( "" "" "" "" )
9050  // -- --- --- ----
9051  // Row Height - 1 : (Last row of image)
9052  //
9053  // Each byte in the raster represents one pixel 0 - 255 gray-scale; where 0=background.
9054 
9055  kkuint32 unCompressedSize = 0;
9056 
9057  if (compressedBuff == NULL)
9058  {
9059  ofstream f ("c:\\Temp\\Raster_FromSimpleCompression.txt", ios_base::app);
9060 
9061  f << std::endl
9062  << "DateTime" << "\t" << osGetLocalDateTime () << "\t"
9063  << "(compressedBuff==NULL)"
9064  << std::endl;
9065 
9066  f.flush ();
9067  f.close ();
9068  return new Raster (20, 20, false);
9069  }
9070 
9071  uchar* uncompressedBuff = SimpleCompressor::Decompress (compressedBuff, compressedBuffLen, unCompressedSize);
9072  if (uncompressedBuff == NULL)
9073  {
9074  ofstream f ("c:\\Temp\\Raster_FromSimpleCompression.txt", ios_base::app);
9075 
9076  f << std::endl
9077  << "DateTime" << "\t" << osGetLocalDateTime () << "\t"
9078  << "(uncompressedBuff==NULL)" << "\t"
9079  << "unCompressedSize" << "\t" << unCompressedSize
9080  << std::endl;
9081  f.flush ();
9082  f.close ();
9083  return new Raster (20, 20, false);
9084  }
9085 
9086  // The first Four Bytes have the image Height, and Width.
9087 
9088  kkint32 height = uncompressedBuff[0] * 256 + uncompressedBuff[1];
9089  kkint32 width = uncompressedBuff[2] * 256 + uncompressedBuff[3];
9090 
9091  if ((height < 1) || (height > 1000) || (width < 1) || (width > 1000))
9092  {
9093  ofstream f ("c:\\Temp\\Raster_FromSimpleCompression.txt", ios_base::app);
9094 
9095  f << std::endl
9096  << "DateTime" << "\t" << osGetLocalDateTime () << "\t"
9097  << "unCompressedSize" << "\t" << unCompressedSize << "\t"
9098  << "Height" << "\t" << height << "\t"
9099  << "Width" << "\t" << width
9100  << std::endl;
9101 
9102  f << (kkint32)compressedBuff [0] << "\t"
9103  << (kkint32)compressedBuff [1] << "\t"
9104  << (kkint32)compressedBuff [2] << "\t"
9105  << (kkint32)compressedBuff [3] << "\t"
9106  << (kkint32)compressedBuff [4] << "\t"
9107  << (kkint32)compressedBuff [5] << "\t"
9108  << (kkint32)compressedBuff [6] << "\t"
9109  << (kkint32)compressedBuff [7] << "\t"
9110  << (kkint32)compressedBuff [8] << "\t"
9111  << (kkint32)compressedBuff [9] << "\t"
9112  << (kkint32)compressedBuff[10]
9113  << std::endl;
9114 
9115  f.flush ();
9116  f.close ();
9117  return new Raster (20, 20, false);
9118  }
9119 
9120  kkuint32 totalPixels = height * width;
9121  if (unCompressedSize > (totalPixels + 4))
9122  {
9123  ofstream f ("c:\\Temp\\Raster_FromSimpleCompression.txt", ios_base::app);
9124 
9125  f << std::endl
9126  << "DateTime" << "\t" << osGetLocalDateTime () << "\t"
9127  << "unCompressedSize" << "\t" << unCompressedSize << "\t"
9128  << "totalPixels" << "\t" << totalPixels << "\t"
9129  << "Height" << "\t" << height << "\t"
9130  << "Width" << "\t" << width
9131  << std::endl;
9132 
9133  f << (kkint32)compressedBuff [0] << "\t"
9134  << (kkint32)compressedBuff [1] << "\t"
9135  << (kkint32)compressedBuff [2] << "\t"
9136  << (kkint32)compressedBuff [3] << "\t"
9137  << (kkint32)compressedBuff [4] << "\t"
9138  << (kkint32)compressedBuff [5] << "\t"
9139  << (kkint32)compressedBuff [6] << "\t"
9140  << (kkint32)compressedBuff [7] << "\t"
9141  << (kkint32)compressedBuff [8] << "\t"
9142  << (kkint32)compressedBuff [9] << "\t"
9143  << (kkint32)compressedBuff[10]
9144  << std::endl;
9145 
9146  f.flush ();
9147  f.close ();
9148  }
9149 
9150 
9151  RasterPtr result = new Raster (height, width, false);
9152  uchar* greenArea = result->GreenArea ();
9153 
9154  kkuint32 nextIdx = 4;
9155  kkuint32 greanAreaIdx = 0;
9156 
9157  while ((nextIdx < (kkuint32)unCompressedSize) && (greanAreaIdx < totalPixels))
9158  {
9159  greenArea[greanAreaIdx] = uncompressedBuff[nextIdx];
9160  nextIdx++;
9161  greanAreaIdx++;
9162  }
9163 
9164  delete uncompressedBuff;
9165  uncompressedBuff = NULL;
9166 
9167  return result;
9168 } /* FromSimpleCompression */
9169 
9170 
9171 
9172 uchar* Raster::ToCompressor (kkuint32& compressedBuffLen) const
9173 {
9174  // Will first write Rater data to a buffer that will be compressed by zlib by the Compressor class.
9175  // 0 - 3: Height: high order to low order
9176  // 4 - 7: Width: high order to low order
9177  // 8 - 8: Color 0 = Gray-scale, 1 = Color
9178  // 9 - 8 + (Height * Width) Green Channel
9179  // xxxxx Red Channel
9180  // xxxxx Blue Channel
9181  kkuint32 totalDataNeeded = totPixels + (color ? (2 * totPixels) : 0) + 9;
9182  uchar* buff = new uchar[totalDataNeeded];
9183  if (!buff)
9184  return NULL;
9185 
9186  memset (buff, 0, totalDataNeeded);
9187 
9188  kkuint32 h = (kkuint32)height;
9189  buff[0] = h % 256; h = h / 256;
9190  buff[1] = h % 256; h = h / 256;
9191  buff[2] = h % 256; h = h / 256;
9192  buff[3] = h % 256; h = h / 256;
9193 
9194 
9195  kkuint32 w = (kkuint32)width;
9196 
9197  buff[4] = w % 256; w = w / 256;
9198  buff[5] = w % 256; w = w / 256;
9199  buff[6] = w % 256; w = w / 256;
9200  buff[7] = w % 256; w = w / 256;
9201 
9202  buff[8] = (color ? 1 : 0);
9203 
9204  kkint32 buffIdx = 9;
9205  kkint32 x = 0;
9206  for (x = 0; x < totPixels; x++, buffIdx++)
9207  buff[buffIdx] = greenArea[x];
9208 
9209  if (color)
9210  {
9211  for (x = 0; x < totPixels; x++, buffIdx++)
9212  buff[buffIdx] = redArea[x];
9213 
9214  for (x = 0; x < totPixels; x++, buffIdx++)
9215  buff[buffIdx] = blueArea[x];
9216  }
9217 
9218  compressedBuffLen = 0;
9219  uchar* compressedBuff = (uchar*)Compressor::CreateCompressedBuffer (buff, totalDataNeeded, compressedBuffLen);
9220  delete[] buff; buff = NULL;
9221  return compressedBuff;
9222 } /* ToCompressor */
9223 
9224 
9225 
9226 
9227 
9228 RasterPtr Raster::FromCompressor (const uchar* compressedBuff, // Creates a raster from a compressedBuff created by 'Compressor'(zlib)
9229  kkuint32 compressedBuffLen
9230  )
9231 {
9232  kkuint32 unCompressedBuffLen = 0;
9233  uchar* unCompressedBuff = (uchar*)Compressor::Decompress (compressedBuff, compressedBuffLen, unCompressedBuffLen);
9234  if (!unCompressedBuff)
9235  return NULL;
9236 
9237  if (unCompressedBuffLen < 10)
9238  {
9239  cerr << std::endl << std::endl << "Raster::FromCompressor Compressor did not return any data." << std::endl;
9240  return NULL;
9241  }
9242 
9243  // 0 - 3: Height: high order to low order
9244  // 4 - 7: Width: high order to low order
9245  // 8 - 8: Color 0 = Gray-- scale, 1 = Color
9246  // 9 - 8 + (Height * Width) Green Channel
9247  // xxxxx Red Channel
9248  // xxxxx Blue Channel
9249 
9250  kkuint32 height = 0;
9251  kkuint32 width = 0;
9252  height = unCompressedBuff[0] + unCompressedBuff[1] * 256 + unCompressedBuff[2] * 256 * 256 + unCompressedBuff[3] * 256 * 256 * 256;
9253  width = unCompressedBuff[4] + unCompressedBuff[5] * 256 + unCompressedBuff[6] * 256 * 256 + unCompressedBuff[7] * 256 * 256 * 256;
9254 
9255  bool color = (unCompressedBuff[8] == 1);
9256 
9257  kkuint32 totalPixels = height * width;
9258  if ((totalPixels > (100 * 1024 * 1024)) || (height < 1) || (width < 1))
9259  {
9260  cerr << std::endl << std::endl << "Raster::FromCompressor Height[" << height << "] Width[" << width << "] is not valid." << std::endl << std::endl;
9261  delete unCompressedBuff;
9262  unCompressedBuff = NULL;
9263  return NULL;
9264  }
9265 
9266  kkuint32 totalDataNeeded = totalPixels + (color ? (2 * totalPixels) : 0) + 9;
9267  if (totalDataNeeded > unCompressedBuffLen)
9268  {
9269  cerr << std::endl << std::endl
9270  << "Raster::FromCompressor Height[" << height << "] Width[" << width << "] Color[" << (color ? "Yes" : "No") << "]" << std::endl
9271  << " requires TotalDataNeeded[" << totalDataNeeded << "] but UnCompressedBuffLen[" << unCompressedBuffLen << "]" << std::endl
9272  << std::endl;
9273  delete unCompressedBuff;
9274  unCompressedBuff = NULL;
9275  return NULL;
9276  }
9277 
9278 
9279  RasterPtr r = new Raster ((kkint32)height, (kkint32)width, color);
9280 
9281  kkuint32 nextIdx = 9;
9282  kkuint32 x;
9283 
9284  uchar* greenArea = r->GreenArea ();
9285  for (x = 0; x < totalPixels; x++, nextIdx++)
9286  greenArea[x] = unCompressedBuff[nextIdx];
9287 
9288  if (color)
9289  {
9290  uchar* redArea = r->RedArea ();
9291  for (x = 0; x < totalPixels; x++, nextIdx++)
9292  redArea[x] = unCompressedBuff[nextIdx];
9293 
9294  uchar* blueArea = r->BlueArea ();
9295  for (x = 0; x < totalPixels; x++, nextIdx++)
9296  blueArea[x] = unCompressedBuff[nextIdx];
9297  }
9298 
9299  delete unCompressedBuff;
9300  unCompressedBuff = NULL;
9301 
9302  return r;
9303 } /* FromCompressor */
9304 
9305 
9306 
9307 
9308 RasterPtr Raster::Padded (kkint32 padding)
9309 {
9310  kkint32 newHeight = height + padding * 2;
9311  kkint32 newWidth = width + padding * 2;
9312 
9313  kkint32 r, c;
9314 
9315  RasterPtr paddedRaster = AllocateARasterInstance (newHeight, newWidth, false);
9316 
9317  for (r = 0; r < height; r++)
9318  {
9319  for (c = 0; c < width; c++)
9320  {
9321  paddedRaster->SetPixelValue (r + padding, c + padding, this->GetPixelValue (r, c));
9322  }
9323  }
9324 
9325  return paddedRaster;
9326 } /* Padded */
9327 
9328 
9329 
9330 
9332 {
9333  kkint32 row, col, x, y;
9334 
9335  double prefix = 1.0 / (2.0 * PIE * sigma * sigma);
9336  double twoSigmaSquared = 2.0 * sigma * sigma;
9337 
9338 
9339  // Determine size of kernel
9340  double z = 100;
9341  kkint32 delta = 0;
9342  while (true)
9343  {
9344  z = 256.0 * prefix * exp (-(delta * delta / twoSigmaSquared));
9345  if (z < 1.0)
9346  {
9347  delta--;
9348  break;
9349  }
9350  ++delta;
9351  }
9352 
9353  kkint32 len = delta * 2 + 1;
9354 
9355  MatrixPtr kernel = new Matrix (len, len);
9356 
9357  double total = 0.0;
9358  x = -delta;
9359  for (row = 0; row < len; row++, x++)
9360  {
9361  y = -delta;
9362  for (col = 0; col < len; col++, y++)
9363  {
9364  double v = exp (-( (x * x + y * y) / twoSigmaSquared));
9365  (*kernel)[row][col] = v;
9366  total += v;
9367  }
9368  }
9369 
9370  for (row = 0; row < len; row++)
9371  {
9372  for (col = 0; col < len; col++)
9373  {
9374  (*kernel)[row][col] = ((*kernel)[row][col] / total);
9375  }
9376  }
9377 
9378  return kernel;
9379 } /* BuildGaussian2dKernel */
9380 
9381 
9382 
9383 void Raster::SmoothUsingKernel (Matrix& kernel,
9384  uchar** src,
9385  uchar** dest
9386  ) const
9387 {
9388  kkint32 row, col;
9389  kkint32 kernelSideLen = kernel.NumOfCols ();
9390  kkint32 delta = kernelSideLen / 2;
9391 
9392  double** kernalData = kernel.Data ();
9393 
9394  for (row = 0; row < height; row++)
9395  {
9396  kkint32 maskTop = row - delta;
9397  for (col = 0; col < width; col++)
9398  {
9399  kkint32 maskLeft = col - delta;
9400  kkint32 maskRow = maskTop;
9401  double total = 0.0;
9402  double kernelTotal = 0.0;
9403  for (kkint32 kernelRow = 0; (kernelRow < kernelSideLen) && (maskRow < height); kernelRow++, maskRow++)
9404  {
9405  if (maskRow >= 0)
9406  {
9407  double* kernalRowData = kernalData[kernelRow];
9408 
9409  kkint32 maskCol = maskLeft;
9410  for (kkint32 kernelCol = 0; (kernelCol < kernelSideLen) && (maskCol < width); kernelCol++, maskCol++)
9411  {
9412  if (maskCol >= 0)
9413  {
9414  double fact = kernalRowData[kernelCol];
9415  total += fact * (float)(src[maskRow][maskCol]);
9416  kernelTotal += fact;
9417  }
9418  }
9419  }
9420  }
9421 
9422  total = total / kernelTotal;
9423 
9424  dest[row][col] = (uchar)((kkint32)(total + 0.5));
9425  }
9426  }
9427 } /* SmoothUsingKernel */
9428 
9429 
9430 
9431 
9432 
9433 RasterPtr Raster::CreateGaussianSmoothedImage (float sigma) const
9434 {
9435  MatrixPtr kernel = BuildGaussian2dKernel (sigma);
9436 
9437  RasterPtr result = AllocateARasterInstance (*this);
9438 
9439  SmoothUsingKernel (*kernel, this->green, result->green);
9440  if (color)
9441  {
9442  SmoothUsingKernel (*kernel, red, result->red);
9443  SmoothUsingKernel (*kernel, blue, result->blue);
9444  }
9445 
9446  delete kernel;
9447  kernel = NULL;
9448 
9449  return result;
9450 } /* CreateGaussianSmoothedImage */
9451 
9452 
9453 
9454 
9455 RasterPtr Raster::ThresholdInHSI (float thresholdH,
9456  float thresholdS,
9457  float thresholdI,
9458  float distance,
9459  const PixelValue& flagValue
9460  )
9461 {
9462  PixelValue color (0, 0, 0);
9463  //Vec<float,3> white(255,255,255);
9464  float tempH, tempS, tempI;
9465  float y, x, r, xOriginalPoint, yOriginalPoint;
9466 
9467  // converts from polar coordinates to Cartesian coordinates. Hue is an angle and Saturation is a distance from an origin.
9468  // xOriginalPoint and yOriginalPoint are the threshold point coordinates (origin)
9469  xOriginalPoint = thresholdS * cos (thresholdH);
9470  yOriginalPoint = thresholdS * sin (thresholdH);
9471 
9472  RasterPtr resultingImage = AllocateARasterInstance (*this);
9473 
9474  for (kkint32 m = 0; m < height; m++)
9475  {
9476  for (kkint32 n = 0; n < width; n++)
9477  {
9478  GetPixelValue (m, n, color);
9479  color.ToHSI (tempH, tempS, tempI);
9480 
9481  // Convert from Cartesian polar coordinates to Cartesian coordinates. These are the Cartesian coordinates of the
9482  // current pixel
9483  x = tempS * cos (tempH);
9484  y = tempS * sin (tempH);
9485 
9486  // Calculate the distance from the threshold initial point to the current pixel color using
9487  // the euclidean distance
9488  r = (float)(sqrt (pow (xOriginalPoint - x, 2) + pow (yOriginalPoint - y, 2) + pow (thresholdI - tempI, 2)));
9489 
9490  if (r <= distance)
9491  resultingImage->SetPixelValue (m, n, color);
9492  else
9493  resultingImage->SetPixelValue (m, n, flagValue);
9494  }
9495  }
9496 
9497  return resultingImage;
9498 } /* ThresholdingHSI */
9499 
9500 
9501 
9502 
9503 RasterPtr Raster::CreateGrayScaleKLT () const
9504 {
9505  if (!color)
9506  {
9507  // Already a Gray-scale image, nothing much to do.
9508  return AllocateARasterInstance (*this);
9509  }
9510 
9511  kkuint32 x = 0;
9512 
9513  MatrixPtr cov = new Matrix (3, 3);
9514  {
9515  // Build a covariance matrix.
9516  kkint32 col = 0, row = 0;
9517 
9518  double* totals = new double[3];
9519  double* means = new double[3];
9520  double** centeredVals = new double*[3];
9521  for (col = 0; col < 3; ++col)
9522  {
9523  totals[col] = 0.0;
9524  means [col] = 0.0;
9525  centeredVals[col] = new double[totPixels];
9526  }
9527 
9528  for (row = 0; row < totPixels; ++row)
9529  {
9530  totals[0] += (double)redArea [row];
9531  totals[1] += (double)greenArea [row];
9532  totals[2] += (double)blueArea [row];
9533  }
9534 
9535  for (col = 0; col < 3; ++col)
9536  means[col] = totals[col] / (double)totPixels;
9537 
9538  for (row = 0; row < totPixels; ++row)
9539  {
9540  centeredVals[0][row] = (double)redArea [row] - means[0];
9541  centeredVals[1][row] = (double)greenArea [row] - means[1];
9542  centeredVals[2][row] = (double)blueArea [row] - means[2];
9543  }
9544 
9545  for (kkint32 varIdxX = 0; varIdxX < 3; ++varIdxX)
9546  {
9547  double* varXs = centeredVals[varIdxX];
9548  for (kkint32 varIdxY = varIdxX; varIdxY < 3; ++varIdxY)
9549  {
9550  // Calculate the covariance between chanIdx0 and chanIdx1
9551 
9552  double* varYs = centeredVals[varIdxY];
9553  double total = 0.0f;
9554  for (row = 0; row < totPixels; ++row)
9555  total += varXs[row] * varYs[row];
9556  (*cov)[varIdxX][varIdxY] = total / (double)(totPixels - 1);
9557  (*cov)[varIdxY][varIdxX] = (*cov)[varIdxX][varIdxY];
9558  }
9559  }
9560 
9561  for (col = 0; col < 3; col++)
9562  {
9563  delete[] centeredVals[col];
9564  centeredVals[col] = NULL;
9565  }
9566  delete[] centeredVals; centeredVals = NULL;
9567  delete[] means; means = NULL;
9568  delete[] totals; totals = NULL;
9569  }
9570 
9571  MatrixPtr eigenVectors = NULL;
9572  VectorDouble* eigenValues = NULL;
9573 
9574  cov->EigenVectors (eigenVectors, eigenValues);
9575  if (!eigenVectors)
9576  {
9577  cerr << std::endl << std::endl
9578  << "Raster::CreateGrayScaleKLT ***ERROR*** Could not derive Eigen Vectors of covariance matrix." << std::endl
9579  << std::endl;
9580  delete cov;
9581  cov = NULL;
9582  return NULL;
9583  }
9584 
9585  kkint32 eigenValueMaxIdx = 0;
9586  double eigenValueMax = (*eigenValues)[0];
9587  for (x = 1; x < eigenValues->size (); ++x)
9588  {
9589  if ((*eigenValues)[x] > eigenValueMax)
9590  {
9591  eigenValueMaxIdx = x;
9592  eigenValueMax = (*eigenValues)[x];
9593  }
9594  }
9595 
9596  VectorDouble eigenVector = eigenVectors->GetCol (eigenValueMaxIdx);
9597  // We are now going to do Matrix multiplication between the original image and the eigenVector
9598  // but since the eigen vector may have negative values the resultant numbers can be negative for
9599  // some pixels and a magnitude greater than 255. We will place temporarily into a floating
9600  // array, after which we will use the adjustment value and scaling factor.
9601  double redFact = eigenVector[0];
9602  double greenFact = eigenVector[1];
9603  double blueFact = eigenVector[2];
9604  double adjVal = 0.0;
9605 
9606  double valMin = DBL_MAX;
9607  double valMax = DBL_MIN;
9608  double* adjChannel = new double [totPixels];
9609  for (kkint32 y = 0; y < totPixels; ++y)
9610  {
9611  adjVal = (double)redArea [y] * redFact +
9612  (double)greenArea[y] * greenFact +
9613  (double)blueArea [y] * blueFact;
9614  if (adjVal < valMin) valMin = adjVal;
9615  if (adjVal > valMax) valMax = adjVal;
9616  adjChannel[y] = adjVal;
9617  }
9618 
9619  if (valMax <= valMin) valMax = valMin + 1.0; // This would only happen if the whole image had the same GrayScale value.
9620 
9621  //double adjScaleFact = 256.0 / (1 + valMax - valMin);
9622  double adjScaleFact = 255.0 / (valMax - valMin);
9623 
9625  {
9626  uchar* resultArea = result->GreenArea ();
9627  for (kkint32 y = 0; y < totPixels; ++y)
9628  {
9629  resultArea[y] = (uchar)Min ((kkint32)((adjChannel[y] - valMin) * adjScaleFact + 0.5), (kkint32)255);
9630  }
9631  }
9632  delete[] adjChannel; adjChannel = NULL;
9633  delete cov; cov = NULL;
9634  delete eigenValues; eigenValues = NULL;
9635  delete eigenVectors; eigenVectors = NULL;
9636 
9637  return result;
9638 } /* CreateGrayScaleKLT */
9639 
9640 
9641 
9642 
9643 RasterPtr Raster::CreateGrayScaleKLTOnMaskedArea (const Raster& mask) const
9644 {
9645  if (!color)
9646  {
9647  // Already a Gray-scale image, nothing much to do.
9648  return AllocateARasterInstance (*this);
9649  }
9650 
9651  if ((mask.Height () != height) || (mask.Width () != width))
9652  {
9653  cerr << std::endl << std::endl
9654  << "Raster::CreateGrayScaleKLTOnMaskedArea ***ERROR*** Mask image dimensions must match !!!!" << std::endl
9655  << " Our[" << height << "," << width << "] Mask[" << mask.height << "," << mask.width << "]." << std::endl
9656  << std::endl;
9657  return NULL;
9658  }
9659 
9660  uchar* maskArea = mask.GreenArea ();
9661  uchar maskTh = mask.backgroundPixelTH;
9662 
9663  kkint32 totalMaskPixels = mask.TotalBackgroundPixels ();
9664 
9665  MatrixPtr cov = new Matrix (3, 3);
9666  {
9667  // Build a covariance matrix.
9668  kkint32 col = 0, row = 0;
9669 
9670  double* totals = new double[3];
9671  double* means = new double[3];
9672  double** centeredVals = new double*[3];
9673  for (col = 0; col < 3; ++col)
9674  {
9675  totals[col] = 0.0;
9676  means [col] = 0.0;
9677  centeredVals[col] = new double[totPixels];
9678  }
9679 
9680  for (row = 0; row < totPixels; ++row)
9681  {
9682  if (maskArea[row] > maskTh)
9683  {
9684  totals[0] += (double)redArea [row];
9685  totals[1] += (double)greenArea [row];
9686  totals[2] += (double)blueArea [row];
9687  }
9688  }
9689 
9690  for (col = 0; col < 3; ++col)
9691  means[col] = totals[col] / (double)totalMaskPixels;
9692 
9693  for (row = 0; row < totPixels; ++row)
9694  {
9695  if (maskArea[row] > maskTh)
9696  {
9697  centeredVals[0][row] = (double)redArea [row] - means[0];
9698  centeredVals[1][row] = (double)greenArea [row] - means[1];
9699  centeredVals[2][row] = (double)blueArea [row] - means[2];
9700  }
9701  }
9702 
9703  for (kkint32 varIdxX = 0; varIdxX < 3; ++varIdxX)
9704  {
9705  double* varXs = centeredVals[varIdxX];
9706  for (kkint32 varIdxY = varIdxX; varIdxY < 3; ++varIdxY)
9707  {
9708  // Calculate the covariance between chanIdx0 and chanIdx1
9709 
9710  double* varYs = centeredVals[varIdxY];
9711  double total = 0.0f;
9712  for (row = 0; row < totPixels; ++row)
9713  {
9714  if (maskArea[row] > maskTh)
9715  total += varXs[row] * varYs[row];
9716  }
9717  (*cov)[varIdxX][varIdxY] = total / (double)(totalMaskPixels - 1);
9718  (*cov)[varIdxY][varIdxX] = (*cov)[varIdxX][varIdxY];
9719  }
9720  }
9721 
9722  for (col = 0; col < 3; col++)
9723  {
9724  delete centeredVals[col];
9725  centeredVals[col] = NULL;
9726  }
9727  delete[] centeredVals; centeredVals = NULL;
9728  delete[] means; means = NULL;
9729  delete[] totals; totals = NULL;
9730  }
9731 
9732  MatrixPtr eigenVectors = NULL;
9733  VectorDouble* eigenValues = NULL;
9734 
9735  cov->EigenVectors (eigenVectors, eigenValues);
9736  if (!eigenVectors)
9737  {
9738  cerr << std::endl << std::endl
9739  << "Raster::CreateGrayScaleKLT ***ERROR*** Could not derive Eigen Vectors of covariance matrix." << std::endl
9740  << std::endl;
9741  delete cov;
9742  cov = NULL;
9743  return NULL;
9744  }
9745 
9746  kkint32 eigenValueMaxIdx = 0;
9747  double eigenValueMax = (*eigenValues)[0];
9748  for (kkuint32 y = 1; y < eigenValues->size (); ++y)
9749  {
9750  if ((*eigenValues)[y] > eigenValueMax)
9751  {
9752  eigenValueMaxIdx = y;
9753  eigenValueMax = (*eigenValues)[y];
9754  }
9755  }
9756 
9757  VectorDouble eigenVector = eigenVectors->GetCol (eigenValueMaxIdx);
9758  // We are now going to do Matrix multiplication between the original image and the eigenVector
9759  // but since the eigen vector may have negative values the resultant numbers can be negative for
9760  // some pixels and a magnitude greater than 255. We will place temporarily into a floating
9761  // array, after which we will no the adjustment value and scaling factor.
9762 
9763  double redFact = eigenVector[0];
9764  double greenFact = eigenVector[1];
9765  double blueFact = eigenVector[2];
9766  double adjVal = 0.0;
9767 
9768  double valMin = DBL_MAX;
9769  double valMax = -9999999999.99;
9770  double* adjChannel = new double [totPixels];
9771  for (kkint32 y = 0; y < totPixels; ++y)
9772  {
9773  if (maskArea[y] > maskTh)
9774  {
9775  adjVal = (double)redArea [y] * redFact +
9776  (double)greenArea[y] * greenFact +
9777  (double)blueArea [y] * blueFact;
9778  if (adjVal < valMin) valMin = adjVal;
9779  if (adjVal > valMax) valMax = adjVal;
9780  adjChannel[y] = adjVal;
9781  }
9782  else
9783  {
9784  adjChannel[y] = 0.0;
9785  }
9786  }
9787 
9788  if (valMax <= valMin) valMax = valMin + 1.0; // This would only happen if the whole image had the same GrayScale value.
9789 
9790  //double adjScaleFact = 256.0 / (1 + valMax - valMin);
9791  double adjScaleFact = 255.0 / (valMax - valMin);
9792 
9794  {
9795  uchar* resultArea = result->GreenArea ();
9796  for (kkint32 y = 0; y < totPixels; ++y)
9797  {
9798  if (maskArea[y] > maskTh)
9799  resultArea[y] = (uchar)Min ((kkint32)((adjChannel[y] - valMin) * adjScaleFact + 0.5), (kkint32)255);
9800  else
9801  resultArea[y] = 0;
9802  }
9803  }
9804  delete[] adjChannel; adjChannel = NULL;
9805  delete cov; cov = NULL;
9806  delete eigenValues; eigenValues = NULL;
9807  delete eigenVectors; eigenVectors = NULL;
9808 
9809  return result;
9810 } /* CreateGrayScaleKLTOnMaskedArea */
9811 
9812 
9813 
9815 {
9816  for (kkint32 r = 0; r < height; ++r)
9817  {
9818  for (kkint32 c = 0; c < width; ++c)
9819  {
9820  if (BackgroundPixel (r, c))
9821  {
9822  green[r][c] = backgroundPixelValue;
9823  if (color)
9824  {
9825  red[r][c] = backgroundPixelValue;
9826  blue[r][c] = backgroundPixelValue;
9827  }
9828  }
9829  }
9830  }
9831 } /* WhiteOutBackground */
9832 
9833 
9834 
9835 
9836 
9838 {
9839  kkint32 x = 0;
9840 
9841  // Determine number of unique values in greenArea channel.
9842  kkint32 freqCount[256];
9843  for (x = 0; x < 256; ++x)
9844  freqCount[x] = 0;
9845  for (x = 0; x < totPixels; ++x)
9846  freqCount[greenArea[x]]++;
9847 
9848  multimap<kkint32,uchar> sortedFreqCounts;
9849  for (x = 0; x < 256; ++x)
9850  {
9851  if (freqCount[x] > 0)
9852  sortedFreqCounts.insert (pair<kkint32,uchar> (freqCount[x], (uchar)x));
9853  }
9854 
9855  PixelValue colorAssignments[256];
9856  colorAssignments[0] = PixelValue::Black;
9857  kkint32 numUniqueValues = (kkint32)sortedFreqCounts.size ();
9858  multimap<kkint32,uchar>::reverse_iterator idx;
9859  x = 0;
9860  for (idx = sortedFreqCounts.rbegin (); idx != sortedFreqCounts.rend (); ++idx)
9861  {
9862  kkint32 pixelValue = idx->second;
9863  colorAssignments[pixelValue] = PixelValue::FromHSI ((float)x / (float)numUniqueValues, 1.0f, 1.0f);
9864  x++;
9865  }
9866 
9868  uchar* destRed = colorImage->RedArea ();
9869  uchar* destGreen = colorImage->GreenArea ();
9870  uchar* destBlue = colorImage->BlueArea ();
9871  for (x = 0; x < totPixels; ++x)
9872  {
9873  PixelValue& pv = colorAssignments[greenArea[x]];
9874  destRed [x] = pv.r;
9875  destGreen[x] = pv.g;
9876  destBlue [x] = pv.b;
9877  }
9878 
9879  return colorImage;
9880 } /* CreateColorImageFromLabels */
9881 
9882 
9883 
9884 
9885 void Raster::FillBlob (RasterPtr origImage,
9886  BlobPtr blob,
9887  PixelValue color
9888  )
9889 {
9890  if (blob == NULL)
9891  return;
9892 
9893  if (origImage->blobIds == NULL)
9894  return;
9895 
9896  if ((origImage->Height () != height) || (origImage->Width () != width))
9897  return;
9898 
9899  kkint32 blobId = blob->Id ();
9900  kkint32 row = 0, col = 0;
9901 
9902  kkint32 rowStart = Min (blob->RowTop (), height - 1);
9903  kkint32 rowEnd = Min (blob->RowBot (), height - 1);
9904  kkint32 colStart = Min (blob->ColLeft (), width - 1);
9905  kkint32 colEnd = Min (blob->ColRight (), width - 1);
9906 
9907  for (row = rowStart; row <= rowEnd; ++row)
9908  {
9909  for (col = colStart; col <= colEnd; ++col)
9910  {
9911  if (origImage->blobIds[row][col] == blobId)
9912  {
9913  SetPixelValue (row, col, color);
9914  }
9915  }
9916  }
9917 } /* FillBlob */
9918 
9919 
9920 
9921 
9922 PointListPtr Raster::DeriveImageLength () const
9923 {
9924  PointListPtr results = NULL;
9925 
9926  float eigenRatio;
9927  float orientationAngle;
9928 
9930  workRaster->FillHole ();
9932  workRaster->ConnectedComponent (1);
9933  workRaster->CalcOrientationAndEigerRatio (eigenRatio,
9934  orientationAngle
9935  );
9936  if ((orientationAngle > TwoPie) || (orientationAngle < -TwoPie))
9937  {
9938  orientationAngle = 0.0;
9939  eigenRatio = 1.0;
9940  }
9941 
9942  RasterPtr rotatedImage = workRaster->Rotate (orientationAngle);
9943  kkint32 tlRow;
9944  kkint32 tlCol;
9945  kkint32 brRow;
9946  kkint32 brCol;
9947 
9948  rotatedImage->FindBoundingBox (tlRow, tlCol, brRow, brCol);
9949  if (tlRow >= 0)
9950  {
9951  uchar** imageData = rotatedImage->Green ();
9952 
9953  kkint32 boxWidth = brCol - tlCol;
9954  kkint32 boxHeight = brRow - tlRow;
9955 
9956  kkint32 mark1Col = (kkint32)((float)boxWidth * 0.05f + 0.5f) + tlCol;
9957  kkint32 mark2Col = (kkint32)((float)boxWidth * 0.95f + 0.5f) + tlCol;
9958 
9959  kkint32 a1RowTot = 0;
9960  kkint32 a1ColTot = 0;
9961  kkint32 a1PixCount = 0l;
9962 
9963  kkint32 a2RowTot = 0;
9964  kkint32 a2ColTot = 0;
9965  kkint32 a2PixCount = 0l;
9966 
9967  kkint32 a3RowTot = 0;
9968  kkint32 a3ColTot = 0;
9969  kkint32 a3PixCount = 0;
9970 
9971  for (kkint32 row = tlRow; row <= brRow; ++row)
9972  {
9973  kkint32 col = 0;
9974 
9975  uchar* rowData = imageData[row];
9976 
9977  for (col = tlCol; col <= mark1Col; ++col)
9978  {
9979  if (rowData[col] > 2)
9980  {
9981  ++a1PixCount;
9982  a1RowTot += row;
9983  a1ColTot += col;
9984  }
9985  }
9986 
9987  for (col = mark1Col + 1; col <= mark2Col; ++col)
9988  {
9989  if (rowData[col] > 2)
9990  {
9991  ++a2PixCount;
9992  a2RowTot += row;
9993  a2ColTot += col;
9994  }
9995  }
9996 
9997  for (col = mark2Col + 1; col <= brCol; ++col)
9998  {
9999  if (rowData[col] > 2)
10000  {
10001  ++a3PixCount;
10002  a3RowTot += row;
10003  a3ColTot += col;
10004  }
10005  }
10006  }
10007 
10008  a1PixCount = Max ((kkint32)1, a1PixCount);
10009  a2PixCount = Max ((kkint32)1, a2PixCount);
10010  a3PixCount = Max ((kkint32)1, a3PixCount);
10011 
10012  Point p1 ((kkint16)(0.5f + a1RowTot / a1PixCount), (kkint16)(0.5f + a1ColTot / a1PixCount));
10013  Point p2 ((kkint16)(0.5f + a2RowTot / a2PixCount), (kkint16)(0.5f + a2ColTot / a2PixCount));
10014  Point p3 ((kkint16)(0.5f + a3RowTot / a3PixCount), (kkint16)(0.5f + a3ColTot / a3PixCount));
10015 
10016 
10017  Point p1Orig = RotateDerivePreRotatedPoint (height, width, p1, orientationAngle);
10018  Point p2Orig = RotateDerivePreRotatedPoint (height, width, p2, orientationAngle);
10019  Point p3Orig = RotateDerivePreRotatedPoint (height, width, p3, orientationAngle);
10020 
10021  results = new PointList (true);
10022  results->PushOnBack (new Point (p1Orig));
10023  results->PushOnBack (new Point (p2Orig));
10024  results->PushOnBack (new Point (p3Orig));
10025  }
10026 
10027 
10028  delete rotatedImage; rotatedImage = NULL;
10029  delete workRaster; workRaster = NULL;
10030 
10031  return results;
10032 
10033 } /* DeriveImageLength */
Row & operator[](kkint32 rowIDX) const
Definition: Matrix.cpp:270
__int16 kkint16
16 bit signed integer.
Definition: KKBaseTypes.h:85
void Erosion(RasterPtr dest) const
Place into destination a eroded version of this instances image.
Definition: Raster.cpp:2411
KKStr(kkint32 size)
Creates a KKStr object that pre-allocates space for &#39;size&#39; characters.
Definition: KKStr.cpp:655
RasterPtr BandPass(float lowerFreqBound, float upperFreqBound, bool retainBackground)
Returns a image that is the result of a BandPass using Fourier Transforms.
Definition: Raster.cpp:8735
void ErosionChanged1(MaskTypes mask, kkint32 row, kkint32 col)
Definition: Raster.cpp:2671
static RasterPtr FromSimpleCompression(const uchar *compressedBuff, kkuint32 compressedBuffLen)
Creates a raster from a compressedBuff created by &#39;SimpleCompression&#39;.
Definition: Raster.cpp:9035
void CentralMoments(float features[9]) const
returns in &#39;features&#39; the 8 central moments as defined by Hu plus eccentricity in the eight bucket...
Definition: Raster.cpp:4100
Simple class that will compress and decompress specified buffers using the routines provided in zlib...
Definition: Compressor.h:17
RasterListPtr SplitImageIntoEqualParts(kkint32 numColSplits, kkint32 numRowSplits) const
Definition: Raster.cpp:8025
void Add16BitInt(kkuint32 i)
BlobPtr LocateMostComplete()
Locates the blob that covers the greatest part of the raster; that is the one who has the largest (He...
Definition: Blob.cpp:253
void Opening()
Definition: Raster.cpp:2944
float * fourierMagArea
Definition: Raster.h:1335
const MovDir movements[8]
Definition: Raster.cpp:5346
RasterPtr ExtractABlobTightly(const BlobPtr blob, kkint32 padding) const
Extracts a specified blob from this image into a tightly bounded image.
Definition: Raster.cpp:3722
#define PIE
Definition: KKBaseTypes.h:52
RasterPtr CreateFromOrginalImageWithSpecifidBlobsOnly(RasterPtr origImage, BlobListPtr blobs)
Returns a copy of &#39;origImage&#39; where only the blobs specified in &#39;blobs&#39; are copied over...
Definition: Raster.cpp:3382
void DrawLine(kkint32 bpRow, kkint32 bpCol, kkint32 epRow, kkint32 epCol, PixelValue pixelVal)
Definition: Raster.cpp:6771
uchar * blueArea
Definition: Raster.h:1345
static void RemoveRasterInstance(const RasterPtr r)
Definition: Raster.cpp:129
void ConnectedComponent(uchar connectedComponentDist)
Definition: Raster.cpp:3466
kkint32 MemoryConsumedEstimated() const
Definition: KKStr.cpp:766
Raster(const Raster &_raster, kkint32 _row, kkint32 _col, kkint32 _height, kkint32 _width)
Constructs a new Raster using a subset of the specified Raster as its source. The dimensions of the r...
Definition: Raster.cpp:514
void DrawConnectedPointList(Point offset, const PointList &borderPixs, const PixelValue &pixelValue, const PixelValue &linePixelValue)
Definition: Raster.cpp:6894
__int32 kkint32
Definition: KKBaseTypes.h:88
void FillBlob(RasterPtr origImage, BlobPtr blob, PixelValue color)
Will paint the specified blob with the specified color.
Definition: Raster.cpp:9885
float centroidRow
Definition: Raster.h:1328
Point RotateDerivePreRotatedPoint(kkint32 height, kkint32 width, Point &rotatedPoint, float turnAngle) const
Definition: Raster.cpp:5792
bool Color() const
Returns true if a Color image.
Definition: BMPImage.h:118
bool k_ThinningCheckTransitions(uchar m_Matrix22[][3])
Definition: Raster.cpp:8520
void BackgroundPixelTH(uchar _backgroundPixelTH)
Definition: Raster.h:341
void ForegroundCountTH(kkint32 _foregroundCountTH)
Definition: MorphOpStruct.h:40
void BackgroundCountTH(kkint32 _backgroundCountTH)
Definition: MorphOpStruct.h:39
void BackgroundPixelValue(uchar _backgroundPixelValue)
Definition: Raster.h:342
void Save(KKStr fileName) const
Definition: Histogram.cpp:529
kkint32 Width()
Number of columns that this blob occupies.
Definition: Blob.h:54
static void Initialize()
Definition: Raster.cpp:79
VectorDouble GetCol(kkint32 col) const
Definition: Matrix.cpp:891
uchar ** blue
Definition: Raster.h:1354
void CalcAreaAndIntensityFeatures(kkint32 &area, float &weightedSize, kkuint32 intensityHistBuckets[8], kkint32 &areaWithWhiteSpace, kkuint32 intensityHistBucketsWhiteSpace[8]) const
Calculates both Intensity Histograms, one not including internal background pixels and one with plus ...
Definition: Raster.cpp:3912
kkuint32 Height() const
Definition: BMPImage.h:125
RasterPtr CreateGrayScaleKLT() const
Creates a image using a KLT Transform with the goal of weighting in favor the color channels with gre...
Definition: Raster.cpp:9503
void Dilation()
Definition: Raster.cpp:1681
RasterPtr Rotate(float turnAngle)
Definition: Raster.cpp:5732
kkint32 NumOfBuckets() const
Definition: Histogram.h:96
RasterList(bool owner)
Definition: Raster.h:1390
RasterPtr ToColor() const
Definition: Raster.cpp:8696
void GetPixelValue(kkint32 row, kkint32 col, uchar &r, uchar &g, uchar &b) const
Definition: Raster.cpp:1308
static PixelValue Magenta
Definition: PixelValue.h:42
void Erosion(MorphOp::StructureType _structure, kkuint16 _structureSize, kkint32 _backgroundCountTH)
Definition: Raster.cpp:2388
kkint32 colLeft
Definition: Blob.h:61
kkint32 Col() const
Definition: Point.h:40
RasterPtr CreateDilatedRaster(MaskTypes mask) const
Definition: Raster.cpp:1702
RasterPtr FastFourier() const
Definition: Raster.cpp:5016
void osWaitForEnter()
Raster(const KKStr &fileName, bool &validFile)
Constructs a Raster image from by reading an existing image File such as a BMP file.
Definition: Raster.cpp:622
void CalcCentroid(kkint32 &size, kkint32 &weight, float &rowCenter, float &colCenter, float &rowCenterWeighted, float &colCenterWeighted) const
Definition: Raster.cpp:5977
KKStr ColorChannelToKKStr(ColorChannels c)
Definition: Raster.cpp:56
kkint32 rowBot
Definition: Blob.h:65
bool BackgroundPixel(kkint32 row, kkint32 col) const
Definition: Raster.cpp:1074
RasterPtr CreateErodedImage(MaskTypes mask) const
Definition: Raster.cpp:2906
void DrawLine(kkint32 bpRow, kkint32 bpCol, kkint32 epRow, kkint32 epCol, uchar pixelVal)
Definition: Raster.cpp:6253
uchar BackgroundPixelValue() const
Definition: Raster.h:336
Matrix(kkint32 _numOfRows, kkint32 _numOfCols)
Definition: Matrix.cpp:108
static uchar * Decompress(const uchar *compressedBuff, kkuint32 compressedBuffLen, kkuint32 &unCompressedSize)
Point operator+(const Point &r) const
Definition: Point.cpp:72
kkint32 width
Definition: Raster.h:1341
void MaxPixVal(uchar _maxPixVal)
Definition: Raster.h:347
void SetPixelValue(kkint32 row, kkint32 col, uchar pixVal)
Definition: Raster.cpp:1390
virtual RasterPtr AllocateARasterInstance(kkint32 height, kkint32 width, bool color) const
Definition: Raster.cpp:1014
void DrawPointList(const PointList &borderPixs, uchar redVal, uchar greenVal, uchar blueVal)
Definition: Raster.cpp:6841
kkint32 Row() const
Definition: Point.h:39
uchar foregroundPixelValue
Definition: Raster.h:1333
BlobListPtr ExtractBlobs(kkint32 dist)
Will extract a list of connected components from this instance.
Definition: Raster.cpp:3200
void DrawCircle(float centerRow, float centerCol, float radius, float startAngle, float endAngle, const PixelValue &pixelValue)
Definition: Raster.cpp:7030
RasterPtr HistogramEqualizedImage(HistogramPtr equalizedHistogram) const
Definition: Raster.cpp:6159
unsigned __int16 kkuint16
16 bit unsigned integer.
Definition: KKBaseTypes.h:86
uchar * ToCompressor(kkuint32 &compressedBuffLen) const
Compresses the image in Raster using zlib library and returns a pointer to compressed data...
Definition: Raster.cpp:9172
static void Destroy(volatile GoalKeeperPtr &_goalKeeperInstance)
Destroys an existing instance of GoalKeeper.
Definition: GoalKeeper.cpp:491
PixelValue & operator=(const PixelValue &right)
Definition: PixelValue.cpp:66
A class that is used by to represent a single image in memory.
Definition: Raster.h:108
uchar * redArea
Definition: Raster.h:1343
void ErodeSpurs()
removes spurs from image.
Definition: Raster.cpp:8089
MorphOpErosion(StructureType _structure, kkuint16 _structureSize)
static void AddRasterInstance(const RasterPtr r)
Definition: Raster.cpp:106
bool weOwnRasterData
Definition: Raster.h:1340
kkint32 CalcArea()
Definition: Raster.cpp:3789
Supports two dimensional matrices.
Definition: Matrix.h:46
RasterPtr HistogramImage(ColorChannels channel) const
Definition: Raster.cpp:6227
void DrawPointList(Point offset, const PointList &borderPixs, uchar redVal, uchar greenVal, uchar blueVal)
Definition: Raster.cpp:6853
float CalcWeightedArea() const
Definition: Raster.cpp:4060
static std::map< RasterPtr, RasterPtr > allocatedRasterInstances
Supports the tracking down of memory leaks in Raster; it will be called every time a new instance of ...
Definition: Raster.h:1358
void FourierExtractFeatures(float fourierFeatures[5]) const
Definition: Raster.cpp:5216
static StructureType MaskShapes(MaskTypes mt)
Definition: MorphOp.cpp:57
Histogram * HistogramPtr
Definition: Raster.h:83
void ReduceToMostCompleteBlob(uchar connectedComponentDist)
Locates most complete blob; that is the one with the largest (Height x Width); and removes all other ...
Definition: Raster.cpp:3522
kkint32 foregroundPixelCount
Definition: Raster.h:1332
static kkint32 Biases(MaskTypes mt)
Definition: MorphOp.cpp:44
void Initialize(kkint32 _height, kkint32 _width, uchar *_Data, uchar **_Rows, bool _takeOwnership)
Sets an existing instance to specific Raster Data of a image.
Definition: Raster.cpp:917
RasterPtr CreateGraph() const
Definition: Histogram.cpp:162
static void Create(const KKStr &_name, volatile GoalKeeperPtr &_newGoalKeeper)
Create a GoalKeeper object and avoid a race condition doing it.
Definition: GoalKeeper.cpp:346
Matrix * MatrixPtr
Definition: Raster.h:50
PointList(bool _owner)
Definition: Point.cpp:105
BlobPtr NewBlob(kkuint32 rowTop, kkuint32 colLeft)
Definition: Blob.cpp:93
kkint32 Max6(kkint32 x1, kkint32 x2, kkint32 x3, kkint32 x4, kkint32 x5, kkint32 x6)
Definition: Raster.cpp:240
bool k_ThinningStep1cdTests(uchar m_Matrix22[][3])
Definition: Raster.cpp:8507
void SetPixelValue(ColorChannels channel, kkint32 row, kkint32 col, uchar pixVal)
Definition: Raster.cpp:1479
Raster(const Raster &_raster, MaskTypes _mask, kkint32 _row, kkint32 _col)
Constructs a Raster that will be the same size as the specified &#39;_mask&#39; with the top left specified b...
Definition: Raster.cpp:566
const KKStr & FileName() const
Definition: BMPImage.h:121
bool Color() const
Definition: Raster.h:310
KKStr operator+(const char *right) const
Definition: KKStr.cpp:3986
uchar ** Red() const
Definition: Raster.h:326
void Erosion(MaskTypes mask)
Definition: Raster.cpp:2294
void WhiteOutBackground()
Sets all pixels that are in the Background Range ov values to BackgroundPixelValue.
Definition: Raster.cpp:9814
RasterPtr ExtractABlob(const BlobPtr blob) const
Extracts a specified blob from this image; useful to extract individual detected blobs.
Definition: Raster.cpp:3761
const uchar * RedRow(kkint32 row) const
Returns the specified Row from the Red Channel.
Definition: BMPImage.cpp:2690
unsigned int uint
Unsigned integer.
Definition: KKBaseTypes.h:78
void SetPixelValue(kkint32 row, kkint32 col, const PixelValue &pixVal)
Definition: Raster.cpp:1413
unsigned __int32 kkuint32
Definition: KKBaseTypes.h:89
RasterPtr ReadImage(const KKStr &imageFileName)
Definition: ImageIO.cpp:188
Raster(kkint32 _height, kkint32 _width)
Constructs a blank image with given dimensions; all pixels will be initialized to 0...
Definition: Raster.cpp:318
kkint32 col
Definition: Raster.h:1381
static void * Decompress(const void *compressedBuff, kkuint32 compressedBuffLen, kkuint32 &unCompressedLen)
Definition: Compressor.cpp:177
void ToHSI(float &hue, float &sat, float &intensity) const
Computes the equivalent HSI values; RGB -> HSI.
Definition: PixelValue.cpp:102
kkint32 Height()
Number of rows that the blob occupies.
Definition: Blob.h:49
const uchar * ImageRow(kkint32 row) const
Returns the specified Row from the Green Channel.
Definition: BMPImage.cpp:2672
virtual RasterPtr PerformOperation(RasterConstPtr _image)
kkint32 totPixels
Definition: Raster.h:1339
static MatrixPtr BuildGaussian2dKernel(float sigma)
Builds a 2d Gaussian kernel.
Definition: Raster.cpp:9331
uchar MergeAlpfaBeta(float alpha, uchar alphaPixel, float beta, uchar betaPixel)
Definition: Raster.cpp:6419
uchar ForegroundPixelValue() const
Definition: Raster.h:337
kkint32 NumOfCols() const
Definition: Matrix.h:126
uchar backgroundPixelValue
Definition: Raster.h:1324
uchar MaxPixVal() const
Definition: Raster.h:320
__int64 kkint64
Definition: KKBaseTypes.h:90
void GetPixelValue(kkint32 row, kkint32 col, PixelValue &p) const
Definition: Raster.cpp:1343
void ReSize(kkint32 _height, kkint32 _width, bool _color)
Lets you resize the raster dimensions; old image data will be lost.
Definition: Raster.cpp:898
double & operator[](kkint32 idx)
Definition: Matrix.cpp:76
static PixelValue Blue
Definition: PixelValue.h:36
static PixelValue Orange
Definition: PixelValue.h:43
void CalcAreaAndIntensityHistogram(kkint32 &area, kkuint32 intensityHistBuckets[8]) const
Calculates the occurrence of different intensity levels.
Definition: Raster.cpp:3872
RasterPtr Padded(kkint32 padding)
Definition: Raster.cpp:9308
ColorChannels
Definition: Raster.h:64
static void * CreateCompressedBuffer(void *source, kkuint32 sourceLen, kkuint32 &compressedBuffLen)
Definition: Compressor.cpp:22
RasterPtr ReduceByFactor(float factor) const
Definition: Raster.cpp:7473
KK_DFT2D< float > KK_DFT2D_Float
Definition: kku_fftw.h:224
void Edge(RasterPtr dest)
Definition: Raster.cpp:3052
RasterPtr CreateSmoothedFrame()
Definition: Raster.cpp:8950
Used by Raster class and MorphOp derived classes to denote a single pixel location in Raster image...
Definition: Point.h:20
kkint32 Height() const
Definition: Raster.h:319
RasterPtr ExtractChannel(ColorChannels channel)
Will return a gray-scale image consisting of the specified color channel only.
Definition: Raster.cpp:7717
void DrawDot(const Point &point, const PixelValue &color, kkint32 size)
Definition: Raster.cpp:6948
void EigenVectors(MatrixPtr &eigenVectors, VectorDouble *&eigenValues) const
Will derive the Eigen vectors and values of the matrix.
Definition: Matrix.cpp:768
float AverageOfMaxBucketInRange(kkint32 firstBucket, kkint32 lastBucket) const
Definition: Histogram.cpp:891
void FillHole(RasterPtr mask)
Fills holes in the image using the &#39;mask&#39; raster as a work area.
Definition: Raster.cpp:2107
KKTHread * KKTHreadPtr
void ForegroundPixelValue(uchar _foregroundPixelValue)
Definition: Raster.h:345
RasterList * RasterListPtr
Definition: Raster.h:75
RasterPtr CreateColorImageFromLabels()
Produces a color image using the &#39;greenArea&#39; channel, assuming that each unique value will be assigne...
Definition: Raster.cpp:9837
KK_DFT1D< float > KK_DFT1D_Float
Definition: kku_fftw.h:172
static PixelValue Teal
Definition: PixelValue.h:47
KKStr operator+(const char *left, const KKStr &right)
Definition: KKStr.cpp:3976
float CentroidCol() const
Definition: Raster.cpp:1100
Used to encode and decode BMP Images.
Definition: BMPImage.h:49
void DrawLine(kkint32 bpRow, kkint32 bpCol, kkint32 epRow, kkint32 epCol, uchar r, uchar g, uchar b)
Definition: Raster.cpp:6264
static PixelValue Black
Definition: PixelValue.h:35
virtual ~Raster()
Definition: Raster.cpp:826
HistogramPtr HistogramGrayscale() const
Definition: Raster.cpp:6091
RasterPtr CreateColor() const
Definition: Raster.cpp:6028
RasterPtr SobelEdgeDetector() const
Definition: Raster.cpp:7696
KKStr(const KKStr &str)
Copy Constructor.
Definition: KKStr.cpp:561
void StartBlock()
Initiates a Block as long as another thread has not already locked this object.
Definition: GoalKeeper.cpp:214
PixelValue(uchar _r, uchar _g, uchar _b)
Constructs a &#39;PixelValue&#39; instance using the provided values for the color components.
Definition: PixelValue.cpp:60
void CalcAreaAndIntensityFeatures(kkint32 &area, float &weightedSize, kkuint32 intensityHistBuckets[8]) const
Calculates both Intensity Histograms, one not including internal background pixels and one with plus ...
Definition: Raster.cpp:4018
void SaveImage(const Raster &image, const KKStr &imageFileName)
Definition: ImageIO.cpp:617
void Initialize(kkint32 _height, kkint32 _width, uchar *_redArea, uchar **_red, uchar *_greenArea, uchar **_green, uchar *_blueArea, uchar **_blue, bool _takeOwnership)
Sets an existing instance to specific Raster Data of a image.
Definition: Raster.cpp:944
void DrawLine(kkint32 bpRow, kkint32 bpCol, kkint32 epRow, kkint32 epCol)
Definition: Raster.cpp:6239
uchar GetPixelValue(ColorChannels channel, kkint32 row, kkint32 col) const
Definition: Raster.cpp:1356
T FindKthValue(T *values, kkint32 arraySize, kkint32 Kth)
Definition: Raster.cpp:7175
kkint32 Max9(kkint32 x1, kkint32 x2, kkint32 x3, kkint32 x4, kkint32 x5, kkint32 x6, kkint32 x7, kkint32 x8, kkint32 x9)
Definition: Raster.cpp:262
void Dilation(RasterPtr dest) const
Definition: Raster.cpp:1804
void Dilation(MaskTypes mask)
Definition: Raster.cpp:1755
RasterPtr SwapQuadrants() const
Definition: Raster.cpp:5165
const KKStr & FileName() const
Definition: Raster.h:315
SimpleCompressor(kkuint32 estimatedMaxBuffSize)
RasterPtr HalfSize()
Definition: Raster.cpp:7326
ColorChannels ColorChannelFromKKStr(const KKStr &s)
Definition: Raster.cpp:68
RasterPtr ReduceByEvenMultiple(kkint32 multiple) const
Definition: Raster.cpp:7361
kkint32 BlobId(kkint32 row, kkint32 col) const
Return the ID of the blob that the specified pixel location belongs to.
Definition: Raster.cpp:3116
MorphOpStretcher(float _rowFactor, float _colFactor)
float ** fourierMag
Definition: Raster.h:1334
RasterPtr TightlyBounded(kkuint32 borderPixels) const
Definition: Raster.cpp:8619
void EndBlock()
Ends the block and allows other threads to pass through StatBlock.
Definition: GoalKeeper.cpp:295
unsigned char uchar
Unsigned character.
Definition: KKBaseTypes.h:77
void SetPixelValue(kkint32 row, kkint32 col, uchar r, uchar g, uchar b)
Definition: Raster.cpp:1450
kkint32 ForegroundPixelCount() const
Definition: Raster.h:317
void DrawLine(kkint32 bpRow, kkint32 bpCol, kkint32 epRow, kkint32 epCol, PixelValue pixelVal, float alpha)
Definition: Raster.cpp:6782
Histogram * Smooth(kkint32 smoothWidth)
Definition: Histogram.cpp:585
bool k_ThinningStep2cdTests(uchar m_Matrix22[][3])
Definition: Raster.cpp:8493
kkint32 rowTop
Definition: Blob.h:66
void TakeOwnershipOfAnotherRastersData(Raster &otherRaster)
Will take ownership of &#39;otherRaster&#39; raster dynamically allocated data and copy its non dynamically a...
Definition: Raster.cpp:978
RasterPtr FindMagnitudeDifferences(const Raster &r)
Returns an image that reflects the differences between this image and the image supplied in the param...
Definition: Raster.cpp:5924
uchar BackgroundPixelTH() const
Definition: Raster.h:335
static KKStr Concat(const std::vector< std::string > &values)
Concatenates the list of &#39;std::string&#39; strings.
Definition: KKStr.cpp:1082
uchar ** red
Definition: Raster.h:1352
static void PrintOutListOfAllocatedrasterInstances()
Definition: Raster.cpp:153
void Edge()
reduces image to edge pixels only.
Definition: Raster.cpp:3043
static PixelValue White
Definition: PixelValue.h:49
void Dilation(RasterPtr dest, MaskTypes mask) const
Definition: Raster.cpp:1905
RasterPtr SegmentImage(bool save=false)
Definition: Raster.cpp:7824
RasterPtr HistogramGrayscaleImage() const
Definition: Raster.cpp:6203
uchar * RedArea() const
Definition: Raster.h:329
bool color
Definition: Raster.h:1329
static RasterPtr FromCompressor(const uchar *compressedBuff, kkuint32 compressedBuffLen)
Creates a new instance of Raster object from zLib compressed data.
Definition: Raster.cpp:9228
void ErosionChanged(MaskTypes mask, kkint32 row, kkint32 col)
Definition: Raster.cpp:2558
void DrawPointList(Point offset, const PointList &borderPixs, const PixelValue &pixelValue)
Definition: Raster.cpp:6830
void Erosion(RasterPtr dest, MaskTypes mask) const
Definition: Raster.cpp:2514
void MergeBlobIds(BlobPtr blob, kkint32 blobId, kkint32 **blobIds)
Used by the Connected component analysis to merge two blobs together.
Definition: Blob.cpp:122
Histogram(float _minValue, kkint32 _numOfBuckets, float _bucketSize, bool _wrapArround)
Definition: Histogram.cpp:24
static volatile GoalKeeperPtr goalKeeper
Definition: Raster.h:1359
void SetPixelValue(const Point &point, const PixelValue &pixVal)
Definition: Raster.cpp:1440
#define TwoPie
Definition: KKBaseTypes.h:53
kkint32 freqHist16BucketIdx[256]
Definition: Raster.cpp:215
kkint32 TotPixels() const
Definition: Raster.h:323
void Erosion()
Definition: Raster.cpp:2241
static PixelValue Yellow
Definition: PixelValue.h:50
kkint32 TotalBackgroundPixels() const
Definition: Raster.cpp:1086
void DrawCircle(const Point &point, kkint32 radius, const PixelValue &color)
Draw a circle who&#39;s center is at &#39;point&#39; and radius in pixels is &#39;radius&#39; using color &#39;color&#39;...
Definition: Raster.cpp:7081
RasterPtr CreateSmoothImage(kkint32 maskSize=3) const
Definition: Raster.cpp:7152
PointListPtr DeriveImageLength() const
Definition: Raster.cpp:9922
KKStr StrFormatInt(kkint32 val, const char *mask)
Definition: KKStr.cpp:5004
MorphOpDilation(StructureType _structure, kkuint16 _structureSize)
static PixelValue Purple
Definition: PixelValue.h:45
static RasterPtr CreatePaddedRaster(BmpImage &image, kkint32 padding)
Definition: Raster.cpp:1131
kkint32 * EqualizedMapTable()
Definition: Histogram.h:72
Raster(kkint32 _height, kkint32 _width, bool _color)
Constructs a blank image with given dimensions.
Definition: Raster.cpp:356
Raster(kkint32 _height, kkint32 _width, const uchar *_Data)
Construct a Raster object using provided raw data.
Definition: Raster.cpp:727
kkuint32 Width() const
Definition: BMPImage.h:140
KKStr operator+(const KKStr &right) const
Definition: KKStr.cpp:3998
const uchar * BlueRow(kkint32 row) const
Returns the specified Row from the Blue Channel.
Definition: BMPImage.cpp:2652
uchar * GreenArea() const
Definition: Raster.h:330
Raster * RasterPtr
Definition: Raster.h:111
uchar ** GetSubSet(uchar **_src, kkint32 _row, kkint32 _col, kkint32 _height, kkint32 _width) const
Returns back a two dimension array that is a copy of the specified region in the image.
Definition: Raster.cpp:4703
RasterPtr ExtractUsingMask(RasterPtr mask)
Extracts the pixel locations where the &#39;mask&#39; images pixel location is a foreground pixel...
Definition: Raster.cpp:7759
void DrawLine(const Point &beginPoint, const Point &endPoint, uchar pixelVal)
Definition: Raster.cpp:6794
Point(kkint32 _row, kkint32 _col)
Definition: Point.cpp:43
void FindBoundingBox(kkint32 &tlRow, kkint32 &tlCol, kkint32 &brRow, kkint32 &brCol) const
Definition: Raster.cpp:5823
void CalcAreaAndIntensityFeatures16(kkint32 &area, float &weighedSize, kkuint32 intensityHistBuckets[16])
Definition: Raster.cpp:3975
virtual RasterPtr AllocateARasterInstance(const Raster &_raster, kkint32 _row, kkint32 _col, kkint32 _height, kkint32 _width) const
Definition: Raster.cpp:1031
static PixelValue Red
Definition: PixelValue.h:46
static PixelValue FromHSI(float hue, float sat, float intensity)
Will create an instance of PixelValue from the HSI values provided (HSI -> RGB).
Definition: PixelValue.cpp:133
uchar * BlueArea() const
Definition: Raster.h:331
virtual RasterPtr PerformOperation(RasterConstPtr _image)
HistogramPtr Histogram(ColorChannels channel) const
Definition: Raster.cpp:6110
static volatile bool rasterInitialized
Definition: Raster.h:1360
bool AreThereEdgePixels(kkint32 edgeWidth)
returns true if there are any foreground pixels within &#39;edgeWidth&#39; pixels of the top, bottom, left, or right edges of the image.
Definition: Raster.cpp:1516
kkint32 Width() const
Definition: Raster.h:324
kkint32 height
Definition: Raster.h:1336
Histogram * Equalized()
Definition: Histogram.cpp:848
float centroidCol
Definition: Raster.h:1327
void CalcAreaAndIntensityHistogramWhite(kkint32 &area, kkuint32 intensityHistBuckets[8])
Calculates a Intensity Histogram including Background pixels in the image.
Definition: Raster.cpp:3825
Maintains a list of blobs.
Definition: Blob.h:77
RasterPtr ThresholdInHSI(float thresholdH, float thresholdS, float thresholdI, float distance, const PixelValue &flagValue)
Definition: Raster.cpp:9455
void SaveGraphImage(const KKStr &fileName) const
Definition: Histogram.cpp:510
void ComputeCentralMoments(kkint32 &foregroundPixelCount, float &weightedPixelCount, float centralMoments[9], float centralMomentsWeighted[9]) const
Computes central moments; one set where each pixel is treated as 1 or 0(Foreground/Background) and th...
Definition: Raster.cpp:4418
virtual RasterPtr PerformOperation(RasterConstPtr _image)
Raster(const BmpImage &_bmpImage)
Constructs a Raster from a BMP image loaded from disk.
Definition: Raster.cpp:405
void tqli(kkint32 n, double *d, double *e, double z[2][2])
void Closing()
Definition: Raster.cpp:2961
kkint32 ** blobIds
Definition: Raster.h:1326
void CentralMomentsWeighted(float features[9]) const
Similar to &#39;CentralMoments&#39; except each pixel position is weighted by its intensity value...
Definition: Raster.cpp:4243
KKException(const char *_exceptionStr)
Definition: KKException.cpp:38
Raster(kkint32 _height, kkint32 _width, uchar *_Data, uchar **_Rows)
Construct a raster object that will utilize a image already in memory.
Definition: Raster.cpp:689
static PixelValue Green
Definition: PixelValue.h:40
KKStr & operator=(const KKStr &src)
Definition: KKStr.cpp:1390
Base class for all Morphological operations.
Definition: MorphOp.h:44
MorphOpBinarize(kkuint16 _pixelValueMin, kkuint16 _pixelValueMax)
BlobPtr LocateLargestBlob()
Will return Blob with largest pixel count.
Definition: Blob.cpp:230
virtual RasterPtr AllocateARasterInstance(const Raster &r) const
Definition: Raster.cpp:1024
void Tred2(kkint32 n, double a[2][2], double *d, double *e)
Definition: EigenVector.cpp:31
void PaintFatPoint(kkint32 row, kkint32 col, const PixelValue pv, float alpha)
Definition: Raster.cpp:6453
Container object used to maintaining a list of pixel locations.
Definition: Point.h:75
void Increment(float val)
Definition: Histogram.cpp:137
kkint32 MemoryConsumedEstimated() const
Definition: Raster.cpp:864
void Dilation(MorphOp::StructureType _structure, kkuint16 _structureSize, kkint32 _foregroundCountTH)
Definition: Raster.cpp:1776
void DrawCircle(float centerRow, float centerCol, float radius, const PixelValue &pixelValue)
Definition: Raster.cpp:6991
KKStr fileName
Definition: Raster.h:1331
void DrawLine(const Point &beginPoint, const Point &endPoint, const PixelValue &pixelVal)
Definition: Raster.cpp:6807
void ReverseImage()
Definition: Raster.cpp:1198
Raster(const Raster &_raster)
Copy Constructor.
Definition: Raster.cpp:460
void DrawPointList(const PointList &borderPixs, const PixelValue &pixelValue)
Definition: Raster.cpp:6822
void Opening(MaskTypes mask)
Definition: Raster.cpp:2952
uchar ** Blue() const
Definition: Raster.h:328
RasterPtr HistogramEqualizedImage() const
Definition: Raster.cpp:6143
float CentroidRow() const
Definition: Raster.cpp:1116
kkint32 pixelCount
Definition: Blob.h:64
RasterPtr CreateGrayScaleKLTOnMaskedArea(const Raster &mask) const
Same as &#39;CreateKLT&#39; except it will only take into account pixels specified by the &#39;mask&#39; image...
Definition: Raster.cpp:9643
uchar * CreateCompressedBuffer(kkuint32 &compressedBuffserSize)
virtual RasterPtr PerformOperation(Raster const *_image)
kkint32 freqHistBucketIdx[256]
Definition: Raster.cpp:204
RasterPtr ReversedImage()
Definition: Raster.cpp:1177
void DrawFatLine(Point startPoint, Point endPoint, PixelValue pv, float alpha)
Definition: Raster.cpp:6636
KKException(const KKStr &_exceptionStr)
Definition: KKException.cpp:45
void FileName(const KKStr &_fileName)
Definition: Raster.h:346
bool ForegroundPixel(kkint32 row, kkint32 col) const
Definition: Raster.cpp:1054
RasterPtr CreateGrayScale() const
Definition: Raster.cpp:6060
void PaintPoint(kkint32 row, kkint32 col, const PixelValue &pv, float alpha)
Definition: Raster.cpp:6432
uchar * SimpleCompression(kkuint32 &buffLen) const
Compresses the image in Raster using a simple Run length algorithm and returns a pointer to compresse...
Definition: Raster.cpp:9016
RasterPtr ThinContour() const
Definition: Raster.cpp:8187
void DrawLine(kkint32 bpRow, kkint32 bpCol, kkint32 epRow, kkint32 epCol, uchar r, uchar g, uchar b, float alpha)
Definition: Raster.cpp:6479
bool osCreateDirectoryPath(KKStr _pathName)
Will create the whole Directory Path not just the final part of the path.
Definition: OSservices.cpp:825
RasterPtr Transpose() const
Definition: Raster.cpp:8669
RasterPtr CreateColorWithBlobsLabeldByColor(BlobListPtr blobs)
Returns image where each blob is labeled with a different color.
Definition: Raster.cpp:3331
uchar * greenArea
Definition: Raster.h:1344
Raster(kkint32 _height, kkint32 _width, const uchar *_redChannel, const uchar *_greenChannel, const uchar *_blueChannel)
Construct a Color Raster object using provided raw data,.
Definition: Raster.cpp:766
void DrawGrid(float pixelsPerMinor, kkuint32 minorsPerMajor, const PixelValue &hashColor, const PixelValue &gridColor)
Definition: Raster.cpp:1543
KKStr title
Definition: Raster.h:1338
RasterPtr CreateDilatedRaster() const
Definition: Raster.cpp:1623
void FollowContour(float countourFreq[5]) const
Definition: Raster.cpp:5357
Point(kkint16 _row, kkint16 _col)
Definition: Point.cpp:34
kkint32 row
Definition: Raster.h:1380
BlobPtr LookUpByBlobId(kkint32 blobId)
Will return pointer to blob with &#39;blobId&#39;; if not found will return NULL.
Definition: Blob.cpp:53
uchar ** Green() const
Definition: Raster.h:327
RasterPtr CreateGaussianSmoothedImage(float sigma) const
Definition: Raster.cpp:9433
Used to manage the construction of a Histogram.
Definition: Histogram.h:24
RasterPtr FastFourierKK() const
Definition: Raster.cpp:4939
kkint32 Id()
The unique ID assigned to this blob.
Definition: Blob.h:44
kkint32 colRight
Definition: Blob.h:62
void ErosionBoundary(MaskTypes mask, kkint32 blobrowstart, kkint32 blobrowend, kkint32 blobcolstart, kkint32 blobcolend)
Definition: Raster.cpp:2787
#define INT_MAX
Adapted by Kurt Kramer be a &#39;class&#39; definition so as to make it more usable in th ePices software wor...
Definition: UsfCasCor.h:186
BlobList(bool _owner)
Definition: Blob.cpp:64
double **const Data() const
Definition: Matrix.h:106
void ConnectedComponent8Conected()
Definition: Raster.cpp:3577
uchar ** green
Definition: Raster.h:1353
static void FinalCleanUp()
Definition: Raster.cpp:93
Used by the Raster Class to represent the contents of one pixel.
Definition: PixelValue.h:22
BlobPtr MergeIntoSingleBlob(BlobPtr blob1, kkint32 blob2Id, kkint32 **blobIds)
Definition: Blob.cpp:163
void CalcOrientationAndEigerRatio(float &eigenRatio, float &orientationAngle)
Definition: Raster.cpp:5610
uchar backgroundPixelTH
Definition: Raster.h:1325
uchar ** Rows() const
Definition: Raster.h:321
RasterPtr StreatchImage(float rowFactor, float colFactor) const
Definition: Raster.cpp:1187
std::vector< double > VectorDouble
Vector of doubles.
Definition: KKBaseTypes.h:148
void FillHole()
Definition: Raster.cpp:2047
kkint32 Min(kkint32 x1, kkint32 x2)
Definition: Raster.cpp:229
kkint32 id
Definition: Blob.h:63
kkint32 divisor
Definition: Raster.h:1330
virtual RasterPtr PerformOperation(RasterConstPtr _image)
void ForegroundPixelCount(kkint32 _foregroundPixelCount)
Definition: Raster.h:344
uchar maxPixVal
Definition: Raster.h:1337
KKStr osGetRootName(const KKStr &fullFileName)
float DeltaAngle(float ang1, float ang2)
Returns the difference between two angles in degrees.
Definition: Raster.cpp:5328
void FillRectangle(kkint32 tlRow, kkint32 tlCol, kkint32 brRow, kkint32 brCol, const PixelValue &fillColor)
Definition: Raster.cpp:1947
RasterPtr BinarizeByThreshold(uchar min, uchar max) const
Definition: Raster.cpp:7705
Point * PointPtr
Definition: Point.h:66
RasterPtr CreateSmoothedMediumImage(kkint32 maskSize) const
Definition: Raster.cpp:7229
void osDisplayWarning(KKStr _message)
void Closing(MaskTypes mask)
Definition: Raster.cpp:2971
void osAddLastSlash(KKStr &fileSpec)
Will add the appropriate Directory separator character to the end of fileSpec if one is not there alr...
uchar GetPixelValue(kkint32 row, kkint32 col) const
Definition: Raster.cpp:1289