ImageProcessor.cpp
Go to the documentation of this file.
1 // ****************************************************************************
2 // This file is part of the Integrating Vision Toolkit (IVT).
3 //
4 // The IVT is maintained by the Karlsruhe Institute of Technology (KIT)
5 // (www.kit.edu) in cooperation with the company Keyetech (www.keyetech.de).
6 //
7 // Copyright (C) 2014 Karlsruhe Institute of Technology (KIT).
8 // All rights reserved.
9 //
10 // Redistribution and use in source and binary forms, with or without
11 // modification, are permitted provided that the following conditions are met:
12 //
13 // 1. Redistributions of source code must retain the above copyright
14 // notice, this list of conditions and the following disclaimer.
15 //
16 // 2. Redistributions in binary form must reproduce the above copyright
17 // notice, this list of conditions and the following disclaimer in the
18 // documentation and/or other materials provided with the distribution.
19 //
20 // 3. Neither the name of the KIT nor the names of its contributors may be
21 // used to endorse or promote products derived from this software
22 // without specific prior written permission.
23 //
24 // THIS SOFTWARE IS PROVIDED BY THE KIT AND CONTRIBUTORS “AS IS” AND ANY
25 // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
26 // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
27 // DISCLAIMED. IN NO EVENT SHALL THE KIT OR CONTRIBUTORS BE LIABLE FOR ANY
28 // DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
29 // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
30 // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
31 // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
32 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
33 // THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34 // ****************************************************************************
35 // ****************************************************************************
36 // Filename: ImageProcessor.cpp
37 // Author: Pedram Azad
38 // Date: 2004
39 // ****************************************************************************
40 // Changes: 20.05.2008, Florian Hecht
41 // * Added Summed Area Table functions
42 //
43 // 07.01.2009, Moritz Hassert
44 // * Added new functions:
45 // Add, AddAndSaturate, Subtract, AbsoluteDifference,
46 // Average, Min, Max
47 // ****************************************************************************
48 
49 
50 // ****************************************************************************
51 // Includes
52 // ****************************************************************************
53 
54 #include <new> // for explicitly using correct new/delete operators on VC DSPs
55 
56 #include "ImageProcessor.h"
57 
58 #include "ByteImage.h"
59 #include "ShortImage.h"
60 #include "IntImage.h"
61 #include "FloatImage.h"
62 #include "PrimitivesDrawer.h"
63 #include "Color/RGBColorModel.h"
64 #include "Math/LinearAlgebra.h"
65 #include "Math/FloatMatrix.h"
66 #include "Math/DoubleMatrix.h"
67 #include "Math/Constants.h"
68 #include "Math/Math3d.h"
69 #include "Math/Matd.h"
70 #include "Math/Vecd.h"
71 #include "Helpers/helpers.h"
74 
75 #include <stdio.h>
76 #include <stdlib.h>
77 #include <string.h>
78 #include <math.h>
79 #include <stddef.h>
80 #include <algorithm>
81 #include <limits.h>
82 #include <float.h>
83 
84 
85 
86 // ****************************************************************************
87 // Static variables and functions
88 // ****************************************************************************
89 
90 // (1 << 20) / i
91 static const int division_table[] =
92 {
93  0, 1048576, 524288, 349525, 262144, 209715, 174762, 149796,
94  131072, 116508, 104857, 95325, 87381, 80659, 74898, 69905,
95  65536, 61680, 58254, 55188, 52428, 49932, 47662, 45590,
96  43690, 41943, 40329, 38836, 37449, 36157, 34952, 33825,
97  32768, 31775, 30840, 29959, 29127, 28339, 27594, 26886,
98  26214, 25575, 24966, 24385, 23831, 23301, 22795, 22310,
99  21845, 21399, 20971, 20560, 20164, 19784, 19418, 19065,
100  18724, 18396, 18078, 17772, 17476, 17189, 16912, 16644,
101  16384, 16131, 15887, 15650, 15420, 15196, 14979, 14768,
102  14563, 14364, 14169, 13981, 13797, 13617, 13443, 13273,
103  13107, 12945, 12787, 12633, 12483, 12336, 12192, 12052,
104  11915, 11781, 11650, 11522, 11397, 11275, 11155, 11037,
105  10922, 10810, 10699, 10591, 10485, 10381, 10280, 10180,
106  10082, 9986, 9892, 9799, 9709, 9619, 9532, 9446,
107  9362, 9279, 9198, 9118, 9039, 8962, 8886, 8811,
108  8738, 8665, 8594, 8525, 8456, 8388, 8322, 8256,
109  8192, 8128, 8065, 8004, 7943, 7884, 7825, 7767,
110  7710, 7653, 7598, 7543, 7489, 7436, 7384, 7332,
111  7281, 7231, 7182, 7133, 7084, 7037, 6990, 6944,
112  6898, 6853, 6808, 6765, 6721, 6678, 6636, 6594,
113  6553, 6512, 6472, 6432, 6393, 6355, 6316, 6278,
114  6241, 6204, 6168, 6132, 6096, 6061, 6026, 5991,
115  5957, 5924, 5890, 5857, 5825, 5793, 5761, 5729,
116  5698, 5667, 5637, 5607, 5577, 5548, 5518, 5489,
117  5461, 5433, 5405, 5377, 5349, 5322, 5295, 5269,
118  5242, 5216, 5190, 5165, 5140, 5115, 5090, 5065,
119  5041, 5017, 4993, 4969, 4946, 4922, 4899, 4877,
120  4854, 4832, 4809, 4788, 4766, 4744, 4723, 4702,
121  4681, 4660, 4639, 4619, 4599, 4578, 4559, 4539,
122  4519, 4500, 4481, 4462, 4443, 4424, 4405, 4387,
123  4369, 4350, 4332, 4315, 4297, 4279, 4262, 4245,
124  4228, 4211, 4194, 4177, 4161, 4144, 4128, 4112
125 };
126 
127 static const int MatrixGaussian5x5[25] =
128 {
129  1, 5, 7, 5, 1,
130  5, 20, 33, 20, 5,
131  7, 33, 55, 33, 7,
132  5, 20, 33, 20, 5,
133  1, 5, 7, 5, 1
134 };
135 
136 static float sin_table_[380];
137 static float cos_table_[380];
138 static float *sin_table = sin_table_ + 10;
139 static float *cos_table = cos_table_ + 10;
140 
141 static void InitSinCosTables()
142 {
143  static bool bSinCosTablesInitialized = false;
144 
145  if (bSinCosTablesInitialized)
146  return;
147 
148  for (int i = -10; i < 370; i++)
149  {
150  const float theta = i * FLOAT_DEG2RAD;
151  sin_table[i] = sinf(theta);
152  cos_table[i] = cosf(theta);
153  }
154 
155  bSinCosTablesInitialized = true;
156 }
157 
158 
159 
160 // ****************************************************************************
161 // Functions
162 // ****************************************************************************
163 
164 bool ImageProcessor::GeneralFilter(const CByteImage *pInputImage, CByteImage *pOutputImage, const int *pKernel, int nMaskSize, int nDivider, bool bAbsoluteValue)
165 {
166  if (pInputImage->width != pOutputImage->width || pInputImage->height != pOutputImage->height ||
167  pInputImage->type != CByteImage::eGrayScale || pOutputImage->type != CByteImage::eGrayScale)
168  {
169  printf("error: input and output image do not match for ImageProcessor::GeneralFilter\n");
170  return false;
171  }
172 
173  if (nMaskSize < 3 || (nMaskSize + 1) % 2 != 0)
174  {
175  printf("error: nMaskSize must be 2 * k + 1 with k >= 1 for ImageProcessor::GeneralFilter\n");
176  return false;
177  }
178 
179  CByteImage *pSaveOutputImage = 0;
180  if (pInputImage->pixels == pOutputImage->pixels)
181  {
182  pSaveOutputImage = pOutputImage;
183  pOutputImage = new CByteImage(pInputImage);
184  }
185 
186  ImageProcessor::Zero(pOutputImage);
187 
188  const int umax = pInputImage->width - nMaskSize + 1;
189  const int vmax = pInputImage->height - nMaskSize + 1;
190 
191  const unsigned char *input = pInputImage->pixels;
192  unsigned char *output = pOutputImage->pixels;
193 
194  const int diff = (nMaskSize - 1) * (pInputImage->width + 1) / 2;
195 
196  if (nDivider == 1)
197  {
198  if (bAbsoluteValue)
199  {
200  for (int v = 0, offset = diff; v < vmax; v++, offset += nMaskSize - 1)
201  {
202  for (int u = 0; u < umax; u++, offset++)
203  {
204  int sum = 0;
205 
206  for (int i = 0, offset2 = offset - diff, offset3 = 0; i < nMaskSize; i++, offset2 += umax - 1)
207  {
208  for (int j = 0; j < nMaskSize; j++, offset2++, offset3++)
209  sum += input[offset2] * pKernel[offset3];
210  }
211 
212  output[offset] = (unsigned char) abs(sum);
213  }
214  }
215  }
216  else
217  {
218  for (int v = 0, offset = diff; v < vmax; v++, offset += nMaskSize - 1)
219  {
220  for (int u = 0; u < umax; u++, offset++)
221  {
222  int sum = 0;
223 
224  for (int i = 0, offset2 = offset - diff, offset3 = 0; i < nMaskSize; i++, offset2 += umax - 1)
225  {
226  for (int j = 0; j < nMaskSize; j++, offset2++, offset3++)
227  sum += input[offset2] * pKernel[offset3];
228  }
229 
230  output[offset] = (unsigned char) sum;
231  }
232  }
233  }
234  }
235  else
236  {
237  if (bAbsoluteValue)
238  {
239  for (int v = 0, offset = diff; v < vmax; v++, offset += nMaskSize - 1)
240  {
241  for (int u = 0; u < umax; u++, offset++)
242  {
243  int sum = 0;
244 
245  for (int i = 0, offset2 = offset - diff, offset3 = 0; i < nMaskSize; i++, offset2 += umax - 1)
246  {
247  for (int j = 0; j < nMaskSize; j++, offset2++, offset3++)
248  sum += input[offset2] * pKernel[offset3];
249  }
250 
251  output[offset] = (unsigned char) (abs(sum) / nDivider);
252  }
253  }
254  }
255  else
256  {
257  for (int v = 0, offset = diff; v < vmax; v++, offset += nMaskSize - 1)
258  {
259  for (int u = 0; u < umax; u++, offset++)
260  {
261  int sum = 0;
262 
263  for (int i = 0, offset2 = offset - diff, offset3 = 0; i < nMaskSize; i++, offset2 += umax - 1)
264  {
265  for (int j = 0; j < nMaskSize; j++, offset2++, offset3++)
266  sum += input[offset2] * pKernel[offset3];
267  }
268 
269  output[offset] = (unsigned char) (sum / nDivider);
270  }
271  }
272  }
273  }
274 
275  if (pSaveOutputImage)
276  {
277  CopyImage(pOutputImage, pSaveOutputImage);
278  delete pOutputImage;
279  }
280 
281  return true;
282 }
283 
284 bool ImageProcessor::GeneralFilter(const CByteImage *pInputImage, CShortImage *pOutputImage, const int *pKernel, int nMaskSize, int nDivider, bool bAbsoluteValue)
285 {
286  if (pInputImage->width != pOutputImage->width || pInputImage->height != pOutputImage->height ||
287  pInputImage->type != CByteImage::eGrayScale)
288  {
289  printf("error: input and output image do not match for ImageProcessor::GeneralFilter\n");
290  return false;
291  }
292 
293  if (nMaskSize < 3 || (nMaskSize + 1) % 2 != 0)
294  {
295  printf("error: nMaskSize must be 2 * k + 1 with k >= 1 for ImageProcessor::GeneralFilter\n");
296  return false;
297  }
298 
299  ImageProcessor::Zero(pOutputImage);
300 
301  const int width = pInputImage->width;
302  const int height = pInputImage->height;
303  const int umax = width - nMaskSize + 1;
304  const int vmax = height - nMaskSize + 1;
305 
306  const unsigned char *input = pInputImage->pixels;
307  short *output = pOutputImage->pixels;
308 
309  const int diff = (nMaskSize - 1) * (width + 1) / 2;
310 
311  if (nDivider == 1)
312  {
313  if (bAbsoluteValue)
314  {
315  for (int v = 0, offset = diff; v < vmax; v++, offset += nMaskSize - 1)
316  {
317  for (int u = 0; u < umax; u++, offset++)
318  {
319  int sum = 0;
320 
321  for (int i = 0, offset2 = offset - diff, offset3 = 0; i < nMaskSize; i++, offset2 += umax - 1)
322  {
323  for (int j = 0; j < nMaskSize; j++, offset2++, offset3++)
324  sum += input[offset2] * pKernel[offset3];
325  }
326 
327  output[offset] = (short) abs(sum);
328  }
329  }
330  }
331  else
332  {
333  for (int v = 0, offset = diff; v < vmax; v++, offset += nMaskSize - 1)
334  {
335  for (int u = 0; u < umax; u++, offset++)
336  {
337  int sum = 0;
338 
339  for (int i = 0, offset2 = offset - diff, offset3 = 0; i < nMaskSize; i++, offset2 += umax - 1)
340  {
341  for (int j = 0; j < nMaskSize; j++, offset2++, offset3++)
342  sum += input[offset2] * pKernel[offset3];
343  }
344 
345  output[offset] = (short) sum;
346  }
347  }
348  }
349  }
350  else
351  {
352  if (bAbsoluteValue)
353  {
354  for (int v = 0, offset = diff; v < vmax; v++, offset += nMaskSize - 1)
355  {
356  for (int u = 0; u < umax; u++, offset++)
357  {
358  int sum = 0;
359 
360  for (int i = 0, offset2 = offset - diff, offset3 = 0; i < nMaskSize; i++, offset2 += umax - 1)
361  {
362  for (int j = 0; j < nMaskSize; j++, offset2++, offset3++)
363  sum += input[offset2] * pKernel[offset3];
364  }
365 
366  output[offset] = (short) (abs(sum) / nDivider);
367  }
368  }
369  }
370  else
371  {
372  for (int v = 0, offset = diff; v < vmax; v++, offset += nMaskSize - 1)
373  {
374  for (int u = 0; u < umax; u++, offset++)
375  {
376  int sum = 0;
377 
378  for (int i = 0, offset2 = offset - diff, offset3 = 0; i < nMaskSize; i++, offset2 += umax - 1)
379  {
380  for (int j = 0; j < nMaskSize; j++, offset2++, offset3++)
381  sum += input[offset2] * pKernel[offset3];
382  }
383 
384  output[offset] = (short) (sum / nDivider);
385  }
386  }
387  }
388  }
389 
390  return true;
391 }
392 
393 bool ImageProcessor::GeneralFilter(const CByteImage *pInputImage, CFloatMatrix *pOutputMatrix, const int *pKernel, int nMaskSize, int nDivider, bool bAbsoluteValue)
394 {
395  if (pInputImage->width != pOutputMatrix->columns || pInputImage->height != pOutputMatrix->rows ||
396  pInputImage->type != CByteImage::eGrayScale)
397  {
398  printf("error: input image and output matrix do not match for ImageProcessor::GeneralFilter\n");
399  return false;
400  }
401 
402  if (nMaskSize < 3 || (nMaskSize + 1) % 2 != 0)
403  {
404  printf("error: nMaskSize must be 2 * k + 1 with k >= 1 for ImageProcessor::GeneralFilter\n");
405  return false;
406  }
407 
408  ImageProcessor::Zero(pOutputMatrix);
409 
410  const int width = pInputImage->width;
411  const int height = pInputImage->height;
412  const int umax = width - nMaskSize + 1;
413  const int vmax = height - nMaskSize + 1;
414 
415  const unsigned char *input = pInputImage->pixels;
416  float *output = pOutputMatrix->data;
417 
418 #if 0
419 
420  const int k = (nMaskSize - 1) / 2;
421 
422  for (int v = 0; v < vmax; v++)
423  {
424  for (int u = 0; u < umax; u++)
425  {
426  int sum = 0;
427 
428  for (int i = 0; i < nMaskSize; i++)
429  {
430  for (int j = 0; j < nMaskSize; j++)
431  sum += input[(v + i) * width + (u + j)] * pKernel[i * nMaskSize + j];
432  }
433 
434  output[(v + k) * width + (u + k)] = float(abs(sum)) / nDivider;
435  }
436  }
437 
438 #else
439 
440  const int diff = (nMaskSize - 1) * (width + 1) / 2;
441 
442  if (nDivider == 1)
443  {
444  if (bAbsoluteValue)
445  {
446  for (int v = 0, offset = diff; v < vmax; v++, offset += nMaskSize - 1)
447  {
448  for (int u = 0; u < umax; u++, offset++)
449  {
450  int sum = 0;
451 
452  for (int i = 0, offset2 = offset - diff, offset3 = 0; i < nMaskSize; i++, offset2 += umax - 1)
453  {
454  for (int j = 0; j < nMaskSize; j++, offset2++, offset3++)
455  sum += input[offset2] * pKernel[offset3];
456  }
457 
458  output[offset] = (float) abs(sum);
459  }
460  }
461  }
462  else
463  {
464  for (int v = 0, offset = diff; v < vmax; v++, offset += nMaskSize - 1)
465  {
466  for (int u = 0; u < umax; u++, offset++)
467  {
468  int sum = 0;
469 
470  for (int i = 0, offset2 = offset - diff, offset3 = 0; i < nMaskSize; i++, offset2 += umax - 1)
471  {
472  for (int j = 0; j < nMaskSize; j++, offset2++, offset3++)
473  sum += input[offset2] * pKernel[offset3];
474  }
475 
476  output[offset] = (float) sum;
477  }
478  }
479  }
480  }
481  else
482  {
483  if (bAbsoluteValue)
484  {
485  for (int v = 0, offset = diff; v < vmax; v++, offset += nMaskSize - 1)
486  {
487  for (int u = 0; u < umax; u++, offset++)
488  {
489  int sum = 0;
490 
491  for (int i = 0, offset2 = offset - diff, offset3 = 0; i < nMaskSize; i++, offset2 += umax - 1)
492  {
493  for (int j = 0; j < nMaskSize; j++, offset2++, offset3++)
494  sum += input[offset2] * pKernel[offset3];
495  }
496 
497  output[offset] = float(abs(sum)) / nDivider;
498  }
499  }
500  }
501  else
502  {
503  for (int v = 0, offset = diff; v < vmax; v++, offset += nMaskSize - 1)
504  {
505  for (int u = 0; u < umax; u++, offset++)
506  {
507  int sum = 0;
508 
509  for (int i = 0, offset2 = offset - diff, offset3 = 0; i < nMaskSize; i++, offset2 += umax - 1)
510  {
511  for (int j = 0; j < nMaskSize; j++, offset2++, offset3++)
512  sum += input[offset2] * pKernel[offset3];
513  }
514 
515  output[offset] = float(sum) / nDivider;
516  }
517  }
518  }
519  }
520 #endif
521 
522  return true;
523 }
524 
525 
526 // Separation:
527 //
528 // ( 1 4 6 4 1 ) ( 1 )
529 // ( 4 16 24 16 4 ) ( 4 )
530 // ( 6 24 36 24 6 ) = ( 6 ) * ( 1 4 6 4 1 )
531 // ( 4 16 24 16 4 ) ( 4 )
532 // ( 1 4 6 4 1 ) ( 1 )
533 
534 bool ImageProcessor::GaussianSmooth5x5(const CByteImage *pInputImage, CByteImage *pOutputImage)
535 {
536  OPTIMIZED_FUNCTION_HEADER_2(GaussianSmooth5x5, pInputImage, pOutputImage)
537 
538  if (!pInputImage->IsCompatible(pOutputImage))
539  {
540  printf("error: input and output image do not match for ImageProcessor::GaussianSmooth5x5\n");
541  return false;
542  }
543 
544  if (pInputImage->width < 5 || pInputImage->height < 5)
545  {
546  printf("error: image must be at least of size 5x5 for ImageProcessor::GaussianSmooth5x5\n");
547  return false;
548  }
549 
550  const int width = pInputImage->width;
551  const int height = pInputImage->height;
552 
553  if (pInputImage->type == CByteImage::eRGB24)
554  {
555  // slow but better than nothing
556  CByteImage inputImageRGB24Split(width, height, CByteImage::eRGB24Split);
557  CByteImage outputImageRGB24Split(width, height, CByteImage::eRGB24Split);
558 
559  ImageProcessor::ConvertImage(pInputImage, &inputImageRGB24Split);
560 
561  GaussianSmooth5x5(&inputImageRGB24Split, &outputImageRGB24Split);
562 
563  ConvertImage(&outputImageRGB24Split, pOutputImage);
564 
565  return true;
566  }
567  else if (pInputImage->type == CByteImage::eRGB24Split)
568  {
569  const int nPixels = width * height;
570 
571  CByteImage imageHeaderInputGrayscale(width, height, CByteImage::eGrayScale, true);
572  CByteImage imageHeaderOutputGrayscale(width, height, CByteImage::eGrayScale, true);
573 
574  // red channel
575  imageHeaderInputGrayscale.pixels = pInputImage->pixels;
576  imageHeaderOutputGrayscale.pixels = pOutputImage->pixels;
577  GaussianSmooth5x5(&imageHeaderInputGrayscale, &imageHeaderOutputGrayscale);
578 
579  // green channel
580  imageHeaderInputGrayscale.pixels = pInputImage->pixels + nPixels;
581  imageHeaderOutputGrayscale.pixels = pOutputImage->pixels + nPixels;
582  GaussianSmooth5x5(&imageHeaderInputGrayscale, &imageHeaderOutputGrayscale);
583 
584  // blue channel
585  imageHeaderInputGrayscale.pixels = pInputImage->pixels + 2 * nPixels;
586  imageHeaderOutputGrayscale.pixels = pOutputImage->pixels + 2 * nPixels;
587  GaussianSmooth5x5(&imageHeaderInputGrayscale, &imageHeaderOutputGrayscale);
588 
589  return true;
590  }
591 
592  // create temp image
593  CByteImage *pTempImage = new CByteImage(pInputImage);
594 
595  const int width2 = width << 1;
596 
597  const unsigned char *input = pInputImage->pixels;
598  unsigned char *temp = pTempImage->pixels;
599  unsigned char *output = pOutputImage->pixels;
600 
601  int x, y, offset;
602 
603  // x direction
604  for (y = 0, offset = 0; y < height; y++)
605  {
606  temp[offset] = (11 * input[offset] + (input[offset + 1] << 2) + input[offset + 2] + 8) >> 4;
607  temp[offset + 1] = (5 * input[offset] + 6 * input[offset + 1] + (input[offset + 2] << 2) + input[offset + 3] + 8) >> 4;
608  offset += 2;
609 
610  // core loop
611  for (x = 4; x < width; x++, offset++)
612  temp[offset] = (input[offset - 2] + (input[offset - 1] << 2) + 6 * input[offset] + (input[offset + 1] << 2) + input[offset + 2] + 8) >> 4;
613 
614  temp[offset] = (input[offset - 2] + (input[offset - 1] << 2) + 6 * input[offset] + 5 * input[offset + 1] + 8) >> 4;
615  temp[offset + 1] = (input[offset - 1] + (input[offset] << 2) + 11 * input[offset + 1] + 8) >> 4;
616  offset += 2;
617  }
618 
619  // y direction
620  for (x = 0, offset = 0; x < width; x++, offset++)
621  {
622  output[offset] = (11 * temp[offset] + (temp[offset + width] << 2) + temp[offset + width2] + 8) >> 4;
623  output[offset + width] = (5 * temp[offset] + 6 * temp[offset + width] + (temp[offset + width2] << 2) + temp[offset + 3 * width] + 8) >> 4;
624  }
625 
626  // core loop
627  for (y = 4, offset = width << 1; y < height; y++)
628  for (x = 0; x < width; x++, offset++)
629  output[offset] = (temp[offset - width2] + (temp[offset - width] << 2) + 6 * temp[offset] + (temp[offset + width] << 2) + temp[offset + width2] + 8) >> 4;
630 
631  for (x = 0, offset = (height - 2) * width; x < width; x++, offset++)
632  {
633  output[offset] = (temp[offset - width2] + (temp[offset - width] << 2) + 6 * temp[offset] + 5 * temp[offset + width] + 8) >> 4;
634  output[offset + width] = (temp[offset - width] + (temp[offset] << 2) + 11 * temp[offset + width] + 8) >> 4;
635  }
636 
637  // free memory
638  delete pTempImage;
639 
641 
642  return true;
643 }
644 
645 
646 static bool AverageFilter3x3(const CByteImage *pInputImage, CByteImage *pOutputImage)
647 {
648  if (pInputImage->width != pOutputImage->width || pInputImage->height != pOutputImage->height ||
649  pInputImage->type != CByteImage::eGrayScale || pOutputImage->type != CByteImage::eGrayScale)
650  {
651  printf("error: input and output image do not match for ImageProcessor::AverageFilter\n");
652  return false;
653  }
654 
655  CByteImage *pSaveOutputImage = 0;
656  if (pInputImage->pixels == pOutputImage->pixels)
657  {
658  pSaveOutputImage = pOutputImage;
659  pOutputImage = new CByteImage(pInputImage);
660  }
661 
662  ImageProcessor::ZeroFrame(pOutputImage);
663 
664  const int maxj = pInputImage->width - 1, maxi = pInputImage->height - 1;
665  const int width = pInputImage->width;
666  const unsigned char *input = pInputImage->pixels;
667  unsigned char *output = pOutputImage->pixels;
668 
669  for (int i = 1, offset = width + 1; i < maxi; i++, offset += 2)
670  {
671  for (int j = 1; j < maxj; j++, offset++)
672  {
673  output[offset] = (
674  input[offset - width - 1] + input[offset - width] + input[offset - width + 1] +
675  input[offset - 1] + input[offset] + input[offset + 1] +
676  input[offset + width - 1] + input[offset + width] + input[offset + width + 1]
677  ) / 9;
678  }
679  }
680 
681  if (pSaveOutputImage)
682  {
683  ImageProcessor::CopyImage(pOutputImage, pSaveOutputImage);
684  delete pOutputImage;
685  }
686 
687  return true;
688 }
689 
690 bool ImageProcessor::AverageFilter(const CByteImage *pInputImage, CByteImage *pOutputImage, int nMaskSize)
691 {
692  if (nMaskSize == 3)
693  {
694  AverageFilter3x3(pInputImage, pOutputImage);
695  return false;
696  }
697 
698  if (pInputImage->width != pOutputImage->width || pInputImage->height != pOutputImage->height ||
699  pInputImage->type != CByteImage::eGrayScale || pOutputImage->type != CByteImage::eGrayScale)
700  {
701  printf("error: input and output image do not match for ImageProcessor::AverageFilter\n");
702  return false;
703  }
704 
705  if (nMaskSize < 3 || (nMaskSize + 1) % 2 != 0)
706  {
707  printf("error: nMaskSize must be 2 * k + 1 with k >= 1 for ImageProcessor::AverageFilter\n");
708  return false;
709  }
710 
711  const int width = pInputImage->width;
712  const int height = pInputImage->height;
713 
714  ImageProcessor::Zero(pOutputImage);
715 
716  CIntImage sat(width, height);
717 
718  ImageProcessor::CalculateSummedAreaTable(pInputImage, &sat);
719 
720  const int frame = (nMaskSize - 1) / 2;
721  const int area_size = nMaskSize*nMaskSize;
722 
723  const int maxx = width - 2*frame;
724  const int maxy = height - 2*frame;
725  const int offset = nMaskSize * width;
726 
727  const int *input = sat.pixels;
728  unsigned char *output = pOutputImage->pixels;
729 
730  for (int y = 1; y < maxy; y++)
731  {
732  const int line_offset = (y + frame)*width + frame;
733  for (int x = 1; x < maxx; x++)
734  {
735  int p1 = (y-1)*width + x - 1;
736  int p3 = p1 + offset;
737 
738  output[line_offset + x] = (input[p3 + nMaskSize] - input[p3] - input[p1 + nMaskSize] + input[p1]) / area_size;
739  }
740  }
741 
742  return true;
743 }
744 
745 
746 bool ImageProcessor::GaussianSmooth3x3(const CByteImage *pInputImage, CByteImage *pOutputImage)
747 {
748  OPTIMIZED_FUNCTION_HEADER_2(GaussianSmooth3x3, pInputImage, pOutputImage)
749 
750  if (pInputImage->width != pOutputImage->width || pInputImage->height != pOutputImage->height ||
751  pInputImage->type != pOutputImage->type)
752  {
753  printf("error: input and output image do not match for ImageProcessor::GaussianSmooth3x3\n");
754  return false;
755  }
756 
757  if (pInputImage->width < 3 || pInputImage->height < 3)
758  {
759  printf("error: image must be at least of size 3x3 for ImageProcessor::GaussianSmooth3x3\n");
760  return false;
761  }
762 
763  CByteImage *pSaveOutputImage = 0;
764  if (pInputImage->pixels == pOutputImage->pixels)
765  {
766  pSaveOutputImage = pOutputImage;
767  pOutputImage = new CByteImage(pInputImage);
768  }
769 
770  const int maxj = pInputImage->width - 1, maxi = pInputImage->height - 1;
771  const unsigned char *p = pInputImage->pixels;
772  unsigned char *output = pOutputImage->pixels;
773 
774  if (pInputImage->type == CByteImage::eGrayScale)
775  {
776  const int width = pInputImage->width;
777 
778  for (int i = 1, offset = width + 1; i < maxi; i++, offset += 2)
779  {
780  for (int j = 1; j < maxj; j++, offset++)
781  {
782  output[offset] = (
783  p[offset - width - 1] + (p[offset - width] << 1) + p[offset - width + 1] +
784  (p[offset - 1] << 1) + (p[offset] << 2) + (p[offset + 1] << 1) +
785  p[offset + width - 1] + (p[offset + width] << 1) + p[offset + width + 1] + 8
786  ) >> 4;
787  }
788  }
789  }
790  else if (pInputImage->type == CByteImage::eRGB24)
791  {
792  const int width = 3 * pInputImage->width;
793  int offset = width + 3;
794 
795  for (int i = 1; i < maxi; i++)
796  {
797  for (int j = 1; j < maxj; j++)
798  {
799  output[offset] = (
800  p[offset - width - 3] + (p[offset - width] << 1) + p[offset - width + 3] +
801  (p[offset - 3] << 1) + (p[offset] << 2) + (p[offset + 3] << 1) +
802  p[offset + width - 3] + (p[offset + width] << 1) + p[offset + width + 3] + 8
803  ) >> 4;
804 
805  offset++;
806 
807  output[offset] = (
808  p[offset - width - 3] + (p[offset - width] << 1) + p[offset - width + 3] +
809  (p[offset - 3] << 1) + (p[offset] << 2) + (p[offset + 3] << 1) +
810  p[offset + width - 3] + (p[offset + width] << 1) + p[offset + width + 3] + 8
811  ) >> 4;
812 
813  offset++;
814 
815  output[offset] = (
816  p[offset - width - 3] + (p[offset - width] << 1) + p[offset - width + 3] +
817  (p[offset - 3] << 1) + (p[offset] << 2) + (p[offset + 3] << 1) +
818  p[offset + width - 3] + (p[offset + width] << 1) + p[offset + width + 3] + 8
819  ) >> 4;
820 
821  offset++;
822  }
823 
824  offset += 6;
825  }
826  }
827 
828  // copy the border pixels from the original, since the border is not calculated
829  if (pSaveOutputImage)
830  CopyFrame(pSaveOutputImage, pOutputImage);
831  else
832  CopyFrame(pInputImage, pOutputImage);
833 
834  if (pSaveOutputImage)
835  {
836  CopyImage(pOutputImage, pSaveOutputImage);
837  delete pOutputImage;
838  }
839 
841 
842  return true;
843 }
844 
845 
846 bool ImageProcessor::SobelX(const CByteImage *pInputImage, CByteImage *pOutputImage, bool bAbsoluteValue)
847 {
848  CShortImage image(pInputImage->width, pInputImage->height);
849 
850  if (!SobelX(pInputImage, &image, bAbsoluteValue))
851  return false;
852 
853  return ConvertImage(&image, pOutputImage);
854 }
855 
856 bool ImageProcessor::SobelY(const CByteImage *pInputImage, CByteImage *pOutputImage, bool bAbsoluteValue)
857 {
858  CShortImage image(pInputImage->width, pInputImage->height);
859 
860  if (!SobelY(pInputImage, &image, bAbsoluteValue))
861  return false;
862 
863  return ConvertImage(&image, pOutputImage);
864 }
865 
866 bool ImageProcessor::SobelY(const CByteImage *pInputImage, CShortImage *pOutputImage, bool bAbsoluteValue)
867 {
868  OPTIMIZED_FUNCTION_HEADER_3(SobelY, pInputImage, pOutputImage, bAbsoluteValue)
869 
870  if (pInputImage->width != pOutputImage->width || pInputImage->height != pOutputImage->height ||
871  pInputImage->type != CByteImage::eGrayScale)
872  {
873  printf("error: input and output image do not match for ImageProcessor::SobelY\n");
874  return false;
875  }
876 
877  ZeroFrame(pOutputImage);
878 
879  const int maxj = pInputImage->width - 1, maxi = pInputImage->height - 1;
880  const int width = pInputImage->width;
881  const unsigned char *input = pInputImage->pixels;
882  short *output = pOutputImage->pixels;
883 
884  if (bAbsoluteValue)
885  {
886  for (int i = 1, offset = width + 1; i < maxi; i++, offset += 2)
887  {
888  for (int j = 1; j < maxj; j++, offset++)
889  {
890  output[offset] =
891  abs(input[offset + width - 1] + (input[offset + width] << 1) + input[offset + width + 1] -
892  input[offset - width - 1] - (input[offset - width] << 1) - input[offset - width + 1]);
893  }
894  }
895  }
896  else
897  {
898  for (int i = 1, offset = width + 1; i < maxi; i++, offset += 2)
899  {
900  for (int j = 1; j < maxj; j++, offset++)
901  {
902  output[offset] =
903  input[offset + width - 1] + (input[offset + width] << 1) + input[offset + width + 1] -
904  input[offset - width - 1] - (input[offset - width] << 1) - input[offset - width + 1];
905  }
906  }
907  }
908 
910 
911  return true;
912 }
913 
914 bool ImageProcessor::SobelX(const CByteImage *pInputImage, CShortImage *pOutputImage, bool bAbsoluteValue)
915 {
916  OPTIMIZED_FUNCTION_HEADER_3(SobelX, pInputImage, pOutputImage, bAbsoluteValue)
917 
918  if (pInputImage->width != pOutputImage->width || pInputImage->height != pOutputImage->height ||
919  pInputImage->type != CByteImage::eGrayScale)
920  {
921  printf("error: input and output image do not match for ImageProcessor::SobelX\n");
922  return false;
923  }
924 
925  ZeroFrame(pOutputImage);
926 
927  const int maxj = pInputImage->width - 1, maxi = pInputImage->height - 1;
928  const int width = pInputImage->width;
929  const unsigned char *input = pInputImage->pixels;
930  short *output = pOutputImage->pixels;
931 
932  if (bAbsoluteValue)
933  {
934  for (int i = 1, offset = width + 1; i < maxi; i++, offset += 2)
935  {
936  for (int j = 1; j < maxj; j++, offset++)
937  {
938  output[offset] =
939  abs(input[offset - width + 1] + (input[offset + 1] << 1) + input[offset + width + 1] -
940  input[offset - width - 1] - (input[offset - 1] << 1) - input[offset + width - 1]);
941  }
942  }
943  }
944  else
945  {
946  for (int i = 1, offset = width + 1; i < maxi; i++, offset += 2)
947  {
948  for (int j = 1; j < maxj; j++, offset++)
949  {
950  output[offset] =
951  input[offset - width + 1] + (input[offset + 1] << 1) + input[offset + width + 1] -
952  input[offset - width - 1] - (input[offset - 1] << 1) - input[offset + width - 1];
953  }
954  }
955  }
956 
958 
959  return true;
960 }
961 
962 
963 bool ImageProcessor::PrewittX(const CByteImage *pInputImage, CByteImage *pOutputImage, bool bAbsoluteValue)
964 {
965  CShortImage image(pInputImage->width, pInputImage->height);
966 
967  if (!PrewittX(pInputImage, &image, bAbsoluteValue))
968  return false;
969 
970  return ConvertImage(&image, pOutputImage);
971 }
972 
973 bool ImageProcessor::PrewittY(const CByteImage *pInputImage, CByteImage *pOutputImage, bool bAbsoluteValue)
974 {
975  CShortImage image(pInputImage->width, pInputImage->height);
976 
977  if (!PrewittY(pInputImage, &image, bAbsoluteValue))
978  return false;
979 
980  return ConvertImage(&image, pOutputImage);
981 }
982 
983 bool ImageProcessor::PrewittY(const CByteImage *pInputImage, CShortImage *pOutputImage, bool bAbsoluteValue)
984 {
985  OPTIMIZED_FUNCTION_HEADER_3(PrewittY, pInputImage, pOutputImage, bAbsoluteValue)
986 
987  if (pInputImage->width != pOutputImage->width || pInputImage->height != pOutputImage->height ||
988  pInputImage->type != CByteImage::eGrayScale)
989  {
990  printf("error: input and output image do not match for ImageProcessor::PrewittY\n");
991  return false;
992  }
993 
994  ZeroFrame(pOutputImage);
995 
996  const int maxj = pInputImage->width - 1, maxi = pInputImage->height - 1;
997  const int width = pInputImage->width;
998  const unsigned char *input = pInputImage->pixels;
999  short *output = pOutputImage->pixels;
1000 
1001  if (bAbsoluteValue)
1002  {
1003  for (int i = 1, offset = width + 1; i < maxi; i++, offset += 2)
1004  {
1005  for (int j = 1; j < maxj; j++, offset++)
1006  {
1007  output[offset] =
1008  abs(input[offset + width - 1] + input[offset + width] + input[offset + width + 1] -
1009  input[offset - width - 1] - input[offset - width] - input[offset - width + 1]);
1010  }
1011  }
1012  }
1013  else
1014  {
1015  for (int i = 1, offset = width + 1; i < maxi; i++, offset += 2)
1016  {
1017  for (int j = 1; j < maxj; j++, offset++)
1018  {
1019  output[offset] =
1020  input[offset + width - 1] + input[offset + width] + input[offset + width + 1] -
1021  input[offset - width - 1] - input[offset - width] - input[offset - width + 1];
1022  }
1023  }
1024  }
1025 
1027 
1028  return true;
1029 }
1030 
1031 bool ImageProcessor::PrewittX(const CByteImage *pInputImage, CShortImage *pOutputImage, bool bAbsoluteValue)
1032 {
1033  OPTIMIZED_FUNCTION_HEADER_3(PrewittX, pInputImage, pOutputImage, bAbsoluteValue)
1034 
1035  if (pInputImage->width != pOutputImage->width || pInputImage->height != pOutputImage->height ||
1036  pInputImage->type != CByteImage::eGrayScale)
1037  {
1038  printf("error: input and output image do not match for ImageProcessor::PrewittX\n");
1039  return false;
1040  }
1041 
1042  ZeroFrame(pOutputImage);
1043 
1044  const int maxj = pInputImage->width - 1, maxi = pInputImage->height - 1;
1045  const int width = pInputImage->width;
1046  const unsigned char *input = pInputImage->pixels;
1047  short *output = pOutputImage->pixels;
1048 
1049  if (bAbsoluteValue)
1050  {
1051  for (int i = 1; i < maxi; ++i)
1052  {
1053  int offset = width * i + 1;
1054  for (int j = 1; j < maxj; ++j, ++offset)
1055  {
1056  output[offset] =
1057  abs(input[offset - width + 1] + input[offset + 1] + input[offset + width + 1] -
1058  input[offset - width - 1] - input[offset - 1] - input[offset + width - 1]);
1059  }
1060  }
1061  }
1062  else
1063  {
1064  for (int i = 1; i < maxi; ++i)
1065  {
1066  int offset = width * i + 1;
1067  for (int j = 1; j < maxj; ++j, ++offset)
1068  {
1069  output[offset] =
1070  input[offset - width + 1] + input[offset + 1] + input[offset + width + 1] -
1071  input[offset - width - 1] - input[offset - 1] - input[offset + width - 1];
1072  }
1073  }
1074  }
1075 
1077 
1078  return true;
1079 }
1080 
1081 
1082 bool ImageProcessor::Laplace1(const CByteImage *pInputImage, CByteImage *pOutputImage, bool bAbsoluteValue)
1083 {
1084  CShortImage image(pInputImage->width, pInputImage->height);
1085 
1086  if (!Laplace1(pInputImage, &image, bAbsoluteValue))
1087  return false;
1088 
1089  ConvertImage(&image, pOutputImage);
1090 
1091  return true;
1092 }
1093 
1094 bool ImageProcessor::Laplace2(const CByteImage *pInputImage, CByteImage *pOutputImage, bool bAbsoluteValue)
1095 {
1096  CShortImage image(pInputImage->width, pInputImage->height);
1097 
1098  if (!Laplace2(pInputImage, &image, bAbsoluteValue))
1099  return false;
1100 
1101  ConvertImage(&image, pOutputImage);
1102 
1103  return true;
1104 }
1105 
1106 bool ImageProcessor::Laplace1(const CByteImage *pInputImage, CShortImage *pOutputImage, bool bAbsoluteValue)
1107 {
1108  OPTIMIZED_FUNCTION_HEADER_3(Laplace1, pInputImage, pOutputImage, bAbsoluteValue)
1109 
1110  if (pInputImage->width != pOutputImage->width || pInputImage->height != pOutputImage->height ||
1111  pInputImage->type != CByteImage::eGrayScale)
1112  {
1113  printf("error: input and output image do not match for ImageProcessor::Laplace1\n");
1114  return false;
1115  }
1116 
1117  ZeroFrame(pOutputImage);
1118 
1119  const int maxj = pInputImage->width - 1, maxi = pInputImage->height - 1;
1120  const int width = pInputImage->width;
1121  const unsigned char *input = pInputImage->pixels;
1122  short *output = pOutputImage->pixels;
1123 
1124  if (bAbsoluteValue)
1125  {
1126  for (int i = 1, offset = width + 1; i < maxi; i++, offset += 2)
1127  {
1128  for (int j = 1; j < maxj; j++, offset++)
1129  {
1130  output[offset] =
1131  abs(input[offset - width] +
1132  input[offset - 1] - (input[offset] << 2) + input[offset + 1] +
1133  input[offset + width]);
1134  }
1135  }
1136  }
1137  else
1138  {
1139  for (int i = 1, offset = width + 1; i < maxi; i++, offset += 2)
1140  {
1141  for (int j = 1; j < maxj; j++, offset++)
1142  {
1143  output[offset] =
1144  input[offset - width] +
1145  input[offset - 1] - (input[offset] << 2) + input[offset + 1] +
1146  input[offset + width];
1147  }
1148  }
1149  }
1150 
1152 
1153  return true;
1154 }
1155 
1156 bool ImageProcessor::Laplace2(const CByteImage *pInputImage, CShortImage *pOutputImage, bool bAbsoluteValue)
1157 {
1158  OPTIMIZED_FUNCTION_HEADER_3(Laplace2, pInputImage, pOutputImage, bAbsoluteValue)
1159 
1160  if (pInputImage->width != pOutputImage->width || pInputImage->height != pOutputImage->height ||
1161  pInputImage->type != CByteImage::eGrayScale)
1162  {
1163  printf("error: input and output image do not match for ImageProcessor::Laplace2\n");
1164  return false;
1165  }
1166 
1167  ZeroFrame(pOutputImage);
1168 
1169  const int maxj = pInputImage->width - 1, maxi = pInputImage->height - 1;
1170  const int width = pInputImage->width;
1171  const unsigned char *input = pInputImage->pixels;
1172  short *output = pOutputImage->pixels;
1173 
1174  if (bAbsoluteValue)
1175  {
1176  for (int i = 1, offset = width + 1; i < maxi; i++, offset += 2)
1177  {
1178  for (int j = 1; j < maxj; j++, offset++)
1179  {
1180  output[offset] =
1181  abs(input[offset - width - 1] + input[offset - width] + input[offset - width + 1] +
1182  input[offset - 1] - (input[offset] << 3) + input[offset + 1] +
1183  input[offset + width - 1] + input[offset + width] + input[offset + width + 1]);
1184  }
1185  }
1186  }
1187  else
1188  {
1189  for (int i = 1, offset = width + 1; i < maxi; i++, offset += 2)
1190  {
1191  for (int j = 1; j < maxj; j++, offset++)
1192  {
1193  output[offset] =
1194  input[offset - width - 1] + input[offset - width] + input[offset - width + 1] +
1195  input[offset - 1] - (input[offset] << 3) + input[offset + 1] +
1196  input[offset + width - 1] + input[offset + width] + input[offset + width + 1];
1197  }
1198  }
1199  }
1200 
1202 
1203  return true;
1204 }
1205 
1206 
1208 {
1210 
1211  if (pInputImage->width != pOutputImage->width || pInputImage->height != pOutputImage->height ||
1212  pInputImage->type != CByteImage::eGrayScale)
1213  {
1214  printf("error: input and output image do not match for ImageProcessor::CalculateGradientImagePrewitt\n");
1215  return false;
1216  }
1217 
1218  CByteImage *pSaveOutputImage = 0;
1219  if (pInputImage->pixels == pOutputImage->pixels)
1220  {
1221  pSaveOutputImage = pOutputImage;
1222  pOutputImage = new CByteImage(pInputImage);
1223  }
1224 
1225  ZeroFrame(pOutputImage);
1226 
1227  const int maxu = pInputImage->width - 1, maxv = pInputImage->height - 1;
1228  const int width = pInputImage->width;
1229  const unsigned char *input = pInputImage->pixels;
1230  unsigned char *output = pOutputImage->pixels;
1231 
1232  for (int v = 1, offset = width + 1; v < maxv; v++, offset += 2)
1233  {
1234  for (int u = 1; u < maxu; u++, offset++)
1235  {
1236  const int value_x =
1237  abs(input[offset + width - 1] + input[offset + width] + input[offset + width + 1] -
1238  input[offset - width - 1] - input[offset - width] - input[offset - width + 1]);
1239 
1240  const int value_y =
1241  abs(input[offset - width + 1] + input[offset + 1] + input[offset + width + 1] -
1242  input[offset - width - 1] - input[offset - 1] - input[offset + width - 1]);
1243 
1244  const int value = value_x > value_y ? value_x : value_y;
1245 
1246  output[offset] = value > 255 ? 255 : value;
1247  }
1248  }
1249 
1250  if (pSaveOutputImage)
1251  {
1252  CopyImage(pOutputImage, pSaveOutputImage);
1253  delete pOutputImage;
1254  }
1255 
1257 
1258  return true;
1259 }
1260 
1262 {
1263  OPTIMIZED_FUNCTION_HEADER_2(CalculateGradientImageSobel, pInputImage, pOutputImage)
1264 
1265  if (pInputImage->width != pOutputImage->width || pInputImage->height != pOutputImage->height ||
1266  pInputImage->type != CByteImage::eGrayScale)
1267  {
1268  printf("error: input and output image do not match for ImageProcessor::CalculateGradientImageSobel\n");
1269  return false;
1270  }
1271 
1272  CByteImage *pSaveOutputImage = 0;
1273  if (pInputImage->pixels == pOutputImage->pixels)
1274  {
1275  pSaveOutputImage = pOutputImage;
1276  pOutputImage = new CByteImage(pInputImage);
1277  }
1278 
1279  ZeroFrame(pOutputImage);
1280 
1281  const int maxu = pInputImage->width - 1, maxv = pInputImage->height - 1;
1282  const int width = pInputImage->width;
1283  const unsigned char *input = pInputImage->pixels;
1284  unsigned char *output = pOutputImage->pixels;
1285 
1286  for (int v = 1, offset = width + 1; v < maxv; v++, offset += 2)
1287  {
1288  for (int u = 1; u < maxu; u++, offset++)
1289  {
1290  const int value_x =
1291  abs(input[offset + width - 1] + (input[offset + width] << 1) + input[offset + width + 1] -
1292  input[offset - width - 1] - (input[offset - width] << 1) - input[offset - width + 1]);
1293 
1294  const int value_y =
1295  abs(input[offset - width + 1] + (input[offset + 1] << 1) + input[offset + width + 1] -
1296  input[offset - width - 1] - (input[offset - 1] << 1) - input[offset + width - 1]);
1297 
1298  const int value = value_x > value_y ? value_x : value_y;
1299 
1300  output[offset] = value > 255 ? 255 : value;
1301  }
1302  }
1303 
1304  if (pSaveOutputImage)
1305  {
1306  CopyImage(pOutputImage, pSaveOutputImage);
1307  delete pOutputImage;
1308  }
1309 
1311 
1312  return true;
1313 }
1314 
1315 bool ImageProcessor::CalculateGradientImage(const CByteImage *pInputImage, CByteImage *pOutputImage)
1316 {
1317  if (pInputImage->width != pOutputImage->width || pInputImage->height != pOutputImage->height)
1318  {
1319  printf("error: input and output image do not match for ImageProcessor::CalculateGradientImage\n");
1320  return false;
1321  }
1322 
1323  CByteImage *pSaveOutputImage = 0;
1324  if (pInputImage->pixels == pOutputImage->pixels)
1325  {
1326  pSaveOutputImage = pOutputImage;
1327  pOutputImage = new CByteImage(pInputImage);
1328  }
1329 
1330  ZeroFrame(pOutputImage);
1331 
1332  const int maxu = pInputImage->width - 1, maxv = pInputImage->height - 1;
1333  const int width = pInputImage->width;
1334  const unsigned char *input = pInputImage->pixels;
1335  unsigned char *output = pOutputImage->pixels;
1336 
1337  if (pInputImage->type == CByteImage::eGrayScale)
1338  {
1339  for (int v = 1, offset = width + 1; v < maxv; v++, offset += 2)
1340  {
1341  for (int u = 1; u < maxu; u++, offset++)
1342  {
1343  const int value_x = abs(input[offset + width] - input[offset - width]);
1344  const int value_y = abs(input[offset + 1] - input[offset - 1]);
1345  const int value = value_x > value_y ? value_x : value_y;
1346  output[offset] = value > 255 ? 255 : value;
1347  }
1348  }
1349  }
1350  else if (pInputImage->type == CByteImage::eRGB24)
1351  {
1352  const unsigned char *input_r = pInputImage->pixels;
1353  const unsigned char *input_g = pInputImage->pixels + 1;
1354  const unsigned char *input_b = pInputImage->pixels + 2;
1355  const int width3 = 3 * width;
1356 
1357  for (int v = 1, offset = width3 + 3, output_offset = 0; v < maxv; v++, offset += 6, output_offset += 2)
1358  {
1359  for (int u = 1; u < maxu; u++, offset += 3, output_offset++)
1360  {
1361  const int r1 = abs(input_r[offset + 3] - input_r[offset - 3]);
1362  const int r2 = abs(input_r[offset + width3] - input_r[offset - width3]);
1363  const int g1 = abs(input_g[offset + 3] - input_g[offset - 3]);
1364  const int g2 = abs(input_g[offset + width3] - input_g[offset - width3]);
1365  const int b1 = abs(input_b[offset + 3] - input_b[offset - 3]);
1366  const int b2 = abs(input_b[offset + width3] - input_b[offset - width3]);
1367  const int r = MY_MAX(r1, r2);
1368  const int g = MY_MAX(g1, g2);
1369  const int b = MY_MAX(b1, b2);
1370  const int value = r > g ? (r > b ? r : b) : (g > b ? g : b);
1371  output[output_offset] = value > 255 ? 255 : value;
1372  }
1373  }
1374  }
1375 
1376  if (pSaveOutputImage)
1377  {
1378  CopyImage(pOutputImage, pSaveOutputImage);
1379  delete pOutputImage;
1380  }
1381 
1382  return true;
1383 }
1384 
1386 {
1387  if (pInputImage->width != pOutputImage->width || pInputImage->height != pOutputImage->height ||
1388  pInputImage->type != CByteImage::eGrayScale || pOutputImage->type != CByteImage::eGrayScale)
1389  {
1390  printf("error: input and output image do not match for ImageProcessor::CalculateGradientImageBinary\n");
1391  return false;
1392  }
1393 
1394  CByteImage *pSaveOutputImage = 0;
1395  if (pInputImage->pixels == pOutputImage->pixels)
1396  {
1397  pSaveOutputImage = pOutputImage;
1398  pOutputImage = new CByteImage(pInputImage);
1399  }
1400 
1401  ZeroFrame(pOutputImage);
1402 
1403  const int maxj = pInputImage->width - 1, maxi = pInputImage->height - 1;
1404  const int width = pInputImage->width;
1405  const unsigned char *input = pInputImage->pixels;
1406  unsigned char *output = pOutputImage->pixels;
1407 
1408  for (int i = 0, offset = 0; i < maxi; i++, offset++)
1409  {
1410  for (int j = 0; j < maxj; j++, offset++)
1411  {
1412  output[offset] = (input[offset + 1] ^ input[offset]) | (input[offset] ^ input[offset + width]);
1413  }
1414  }
1415 
1416  if (pSaveOutputImage)
1417  {
1418  CopyImage(pOutputImage, pSaveOutputImage);
1419  delete pOutputImage;
1420  }
1421 
1422  return true;
1423 }
1424 
1425 
1426 static bool Dilate3x3(const CByteImage *pInputImage, CByteImage *pOutputImage, const MyRegion *pROI)
1427 {
1428  OPTIMIZED_FUNCTION_HEADER_2_ROI(Dilate3x3, pInputImage, pOutputImage, pROI)
1429 
1430  if (pInputImage->width != pOutputImage->width || pInputImage->height != pOutputImage->height ||
1431  pInputImage->type != pOutputImage->type || pInputImage->type != CByteImage::eGrayScale)
1432  {
1433  printf("error: input and output image do not match for Dilate3x3\n");
1434  return false;
1435  }
1436 
1437  CByteImage *pSaveOutputImage = 0;
1438  if (pInputImage->pixels == pOutputImage->pixels)
1439  {
1440  pSaveOutputImage = pOutputImage;
1441  pOutputImage = new CByteImage(pInputImage);
1442  }
1443 
1444  ImageProcessor::Zero(pOutputImage, pROI);
1445 
1446  const int width = pInputImage->width;
1447  const int height = pInputImage->height;
1448 
1449  const unsigned char *input = pInputImage->pixels;
1450  unsigned char *output = pOutputImage->pixels;
1451 
1452  int min_u, max_u, min_v, max_v;
1453 
1454  if (pROI)
1455  {
1456  min_u = pROI->min_x + 1;
1457  max_u = pROI->max_x - 1;
1458  min_v = pROI->min_y + 1;
1459  max_v = pROI->max_y - 1;
1460 
1461  if (min_u < 1) min_u = 1;
1462  if (min_u > width - 2) min_u = width - 2;
1463  if (max_u < 1) max_u = 1;
1464  if (max_u > width - 2) max_u = width - 2;
1465  if (min_v < 1) min_v = 1;
1466  if (min_v > height - 2) min_v = height - 2;
1467  if (max_v < 1) max_v = 1;
1468  if (max_v > height - 2) max_v = height - 2;
1469  }
1470  else
1471  {
1472  min_u = 1;
1473  max_u = width - 2;
1474  min_v = 1;
1475  max_v = height - 2;
1476  }
1477 
1478  const int diff = width - (max_u - min_u + 1);
1479 
1480  bool *bLastY = new bool[width];
1481  memset(bLastY, false, width * sizeof(bool));
1482 
1483  for (int v = min_v, offset = min_v * width + min_u; v <= max_v; v++, offset += diff)
1484  {
1485  bool bLastX = false;
1486 
1487  for (int u = min_u; u <= max_u; u++, offset++)
1488  {
1489  if (input[offset])
1490  {
1491  if (bLastX)
1492  {
1493  if (bLastY[u])
1494  {
1495  output[offset + width + 1] = 255;
1496  }
1497  else
1498  {
1499  output[offset - width + 1] = 255;
1500  output[offset + 1] = 255;
1501  output[offset + width + 1] = 255;
1502 
1503  bLastY[u] = true;
1504  }
1505  }
1506  else
1507  {
1508  if (bLastY[u])
1509  {
1510  output[offset + width - 1] = 255;
1511  output[offset + width] = 255;
1512  output[offset + width + 1] = 255;
1513  }
1514  else
1515  {
1516  output[offset - width - 1] = 255;
1517  output[offset - width] = 255;
1518  output[offset - width + 1] = 255;
1519  output[offset - 1] = 255;
1520  output[offset] = 255;
1521  output[offset + 1] = 255;
1522  output[offset + width - 1] = 255;
1523  output[offset + width] = 255;
1524  output[offset + width + 1] = 255;
1525 
1526  bLastY[u] = true;
1527  }
1528 
1529  bLastX = true;
1530  }
1531  }
1532  else
1533  {
1534  bLastX = false;
1535  bLastY[u] = false;
1536  }
1537  }
1538  }
1539 
1540  delete [] bLastY;
1541 
1542  if (pSaveOutputImage)
1543  {
1544  ImageProcessor::CopyImage(pOutputImage, pSaveOutputImage, pROI, true);
1545  delete pOutputImage;
1546  }
1547 
1549 
1550  return true;
1551 }
1552 
1553 static bool Erode3x3(const CByteImage *pInputImage, CByteImage *pOutputImage, const MyRegion *pROI)
1554 {
1555  OPTIMIZED_FUNCTION_HEADER_2_ROI(Erode3x3, pInputImage, pOutputImage, pROI)
1556 
1557  if (pInputImage->width != pOutputImage->width || pInputImage->height != pOutputImage->height ||
1558  pInputImage->type != pOutputImage->type || pInputImage->type != CByteImage::eGrayScale)
1559  {
1560  printf("error: input and output image do not match for Erode3x3\n");
1561  return false;
1562  }
1563 
1564  CByteImage *pSaveOutputImage = 0;
1565  if (pInputImage->pixels == pOutputImage->pixels)
1566  {
1567  pSaveOutputImage = pOutputImage;
1568  pOutputImage = new CByteImage(pInputImage);
1569  }
1570 
1571  ImageProcessor::Zero(pOutputImage, pROI);
1572 
1573  const int width = pInputImage->width;
1574  const int height = pInputImage->height;
1575 
1576  const unsigned char *input = pInputImage->pixels;
1577  unsigned char *output = pOutputImage->pixels;
1578 
1579  int min_u, max_u, min_v, max_v;
1580 
1581  if (pROI)
1582  {
1583  min_u = pROI->min_x + 1;
1584  max_u = pROI->max_x - 1;
1585  min_v = pROI->min_y + 1;
1586  max_v = pROI->max_y - 1;
1587 
1588  if (min_u < 1) min_u = 1;
1589  if (min_u > width - 2) min_u = width - 2;
1590  if (max_u < 1) max_u = 1;
1591  if (max_u > width - 2) max_u = width - 2;
1592  if (min_v < 1) min_v = 1;
1593  if (min_v > height - 2) min_v = height - 2;
1594  if (max_v < 1) max_v = 1;
1595  if (max_v > height - 2) max_v = height - 2;
1596  }
1597  else
1598  {
1599  min_u = 1;
1600  max_u = width - 2;
1601  min_v = 1;
1602  max_v = height - 2;
1603  }
1604 
1605  const int diff = width - (max_u - min_u + 1);
1606 
1607  bool *bLastY = new bool[width];
1608  memset(bLastY, false, width * sizeof(bool));
1609 
1610  for (int v = min_v, offset = min_v * width + min_u; v <= max_v; v++, offset += diff)
1611  {
1612  bool bLastX = false;
1613 
1614  for (int u = min_u; u <= max_u; u++, offset++)
1615  {
1616  if (bLastX)
1617  {
1618  if (bLastY[u])
1619  {
1620  if (!input[offset + width + 1])
1621  {
1622  bLastX = false;
1623  bLastY[u] = false;
1624  continue;
1625  }
1626  }
1627  else
1628  {
1629  if (!input[offset - width + 1] || !input[offset + 1] || !input[offset + width + 1])
1630  {
1631  bLastX = false;
1632  continue;
1633  }
1634  else
1635  {
1636  bLastY[u] = true;
1637  }
1638  }
1639  }
1640  else
1641  {
1642  if (bLastY[u])
1643  {
1644  if (!input[offset + width - 1] || !input[offset + width] || !input[offset + width + 1])
1645  {
1646  bLastY[u] = false;
1647  continue;
1648  }
1649  else
1650  {
1651  bLastX = true;
1652  }
1653  }
1654  else
1655  {
1656  if (!input[offset - width - 1] || !input[offset - width] || !input[offset - width + 1] ||
1657  !input[offset - 1] || !input[offset] || !input[offset + 1] ||
1658  !input[offset + width - 1] || !input[offset + width] || !input[offset + width + 1])
1659  {
1660  continue;
1661  }
1662  else
1663  {
1664  bLastX = true;
1665  bLastY[u] = true;
1666  }
1667  }
1668  }
1669 
1670  output[offset] = 255;
1671  }
1672  }
1673 
1674  delete [] bLastY;
1675 
1676  if (pSaveOutputImage)
1677  {
1678  ImageProcessor::CopyImage(pOutputImage, pSaveOutputImage, pROI, true);
1679  delete pOutputImage;
1680  }
1681 
1683 
1684  return true;
1685 }
1686 
1687 bool ImageProcessor::Dilate(const CByteImage *pInputImage, CByteImage *pOutputImage, int nMaskSize, const MyRegion *pROI)
1688 {
1689  if (nMaskSize == 3)
1690  {
1691  Dilate3x3(pInputImage, pOutputImage, pROI);
1692  return false;
1693  }
1694 
1695  if (nMaskSize < 2)
1696  {
1697  printf("error: mask size is too small for ImageProcessor::Dilate\n");
1698  return false;
1699  }
1700 
1701  if (pInputImage->width != pOutputImage->width || pInputImage->height != pOutputImage->height ||
1702  pInputImage->type != pOutputImage->type || pInputImage->type != CByteImage::eGrayScale)
1703  {
1704  printf("error: input and output image do not match for ImageProcessor::Dilate\n");
1705  return false;
1706  }
1707 
1708  const int k = (nMaskSize - 1) / 2;
1709 
1710  CByteImage *pSaveOutputImage = 0;
1711  if (pInputImage->pixels == pOutputImage->pixels)
1712  {
1713  pSaveOutputImage = pOutputImage;
1714  pOutputImage = new CByteImage(pInputImage);
1715  }
1716 
1717  ImageProcessor::Zero(pOutputImage, pROI);
1718 
1719  const int width = pInputImage->width;
1720  const int height = pInputImage->height;
1721 
1722  const unsigned char *input = pInputImage->pixels;
1723  unsigned char *output = pOutputImage->pixels;
1724 
1725  int min_u, max_u, min_v, max_v;
1726 
1727  if (pROI)
1728  {
1729  min_u = pROI->min_x + 1;
1730  max_u = pROI->max_x - 1;
1731  min_v = pROI->min_y + 1;
1732  max_v = pROI->max_y - 1;
1733 
1734  if (min_u < k) min_u = k;
1735  if (min_u > width - 1 - k) min_u = width - 1 - k;
1736  if (max_u < k) max_u = k;
1737  if (max_u > width - 1 - k) max_u = width - 1 - k;
1738  if (min_v < k) min_v = k;
1739  if (min_v > height - 1 - k) min_v = height - 1 - k;
1740  if (max_v < k) max_v = k;
1741  if (max_v > height - 1 - k) max_v = height - 1 - k;
1742  }
1743  else
1744  {
1745  min_u = k;
1746  max_u = width - 1 - k;
1747  min_v = k;
1748  max_v = height - 1 - k;
1749  }
1750 
1751  const int diff = width - (max_u - min_u + 1);
1752 
1753  bool *bLastY = new bool[width];
1754  memset(bLastY, false, width * sizeof(bool));
1755 
1756  for (int v = min_v, offset = min_v * width + min_u; v <= max_v; v++, offset += diff)
1757  {
1758  bool bLastX = false;
1759 
1760  for (int u = min_u; u <= max_u; u++, offset++)
1761  {
1762  if (input[offset])
1763  {
1764  if (bLastX)
1765  {
1766  if (bLastY[u])
1767  {
1768  output[offset + k * width + k] = 255;
1769  }
1770  else
1771  {
1772  for (int i = -k; i <= k; i++)
1773  output[offset + i * width + k] = 255;
1774 
1775  bLastY[u] = true;
1776  }
1777  }
1778  else
1779  {
1780  if (bLastY[u])
1781  {
1782  for (int i = -k; i <= k; i++)
1783  output[offset + k * width + i] = 255;
1784  }
1785  else
1786  {
1787  for (int i = -k; i <= k; i++)
1788  for (int j = -k; j <= k; j++)
1789  output[offset + i * width + j] = 255;
1790 
1791  bLastY[u] = true;
1792  }
1793 
1794  bLastX = true;
1795  }
1796  }
1797  else
1798  {
1799  bLastX = false;
1800  bLastY[u] = false;
1801  }
1802  }
1803  }
1804 
1805  delete [] bLastY;
1806 
1807  if (pSaveOutputImage)
1808  {
1809  CopyImage(pOutputImage, pSaveOutputImage, pROI, true);
1810  delete pOutputImage;
1811  }
1812 
1813  return true;
1814 }
1815 
1816 bool ImageProcessor::Erode(const CByteImage *pInputImage, CByteImage *pOutputImage, int nMaskSize, const MyRegion *pROI)
1817 {
1818  if (nMaskSize == 3)
1819  {
1820  Erode3x3(pInputImage, pOutputImage, pROI);
1821  return false;
1822  }
1823 
1824  if (nMaskSize < 2)
1825  {
1826  printf("error: mask size is too small for ImageProcessor::Erode\n");
1827  return false;
1828  }
1829 
1830  if (pInputImage->width != pOutputImage->width || pInputImage->height != pOutputImage->height ||
1831  pInputImage->type != pOutputImage->type || pInputImage->type != CByteImage::eGrayScale)
1832  {
1833  printf("error: input and output image do not match for ImageProcessor::Erode\n");
1834  return false;
1835  }
1836 
1837  const int k = (nMaskSize - 1) / 2;
1838 
1839  CByteImage *pSaveOutputImage = 0;
1840  if (pInputImage->pixels == pOutputImage->pixels)
1841  {
1842  pSaveOutputImage = pOutputImage;
1843  pOutputImage = new CByteImage(pInputImage);
1844  }
1845 
1846  ImageProcessor::Zero(pOutputImage, pROI);
1847 
1848  const int width = pInputImage->width;
1849  const int height = pInputImage->height;
1850 
1851  const unsigned char *input = pInputImage->pixels;
1852  unsigned char *output = pOutputImage->pixels;
1853 
1854  int min_u, max_u, min_v, max_v;
1855 
1856  if (pROI)
1857  {
1858  min_u = pROI->min_x + 1;
1859  max_u = pROI->max_x - 1;
1860  min_v = pROI->min_y + 1;
1861  max_v = pROI->max_y - 1;
1862 
1863  if (min_u < k) min_u = k;
1864  if (min_u > width - 1 - k) min_u = width - 1 - k;
1865  if (max_u < k) max_u = k;
1866  if (max_u > width - 1 - k) max_u = width - 1 - k;
1867  if (min_v < k) min_v = k;
1868  if (min_v > height - 1 - k) min_v = height - 1 - k;
1869  if (max_v < k) max_v = k;
1870  if (max_v > height - 1 - k) max_v = height - 1 - k;
1871  }
1872  else
1873  {
1874  min_u = k;
1875  max_u = width - 1 - k;
1876  min_v = k;
1877  max_v = height - 1 - k;
1878  }
1879 
1880  const int diff = width - (max_u - min_u + 1);
1881 
1882  bool *bLastY = new bool[width];
1883  memset(bLastY, false, width * sizeof(bool));
1884 
1885  for (int v = min_v, offset = min_v * width + min_u; v <= max_v; v++, offset += diff)
1886  {
1887  bool bLastX = false;
1888 
1889  for (int u = min_u; u <= max_u; u++)
1890  {
1891  if (bLastX)
1892  {
1893  if (bLastY[u])
1894  {
1895  if (!input[offset + k * width + k])
1896  {
1897  bLastX = false;
1898  bLastY[u] = false;
1899  goto next;
1900  }
1901  }
1902  else
1903  {
1904  for (int i = -k; i <= k; i++)
1905  if (!input[offset + i * width + k])
1906  {
1907  bLastX = false;
1908  goto next;
1909  }
1910 
1911  bLastY[u] = true;
1912  }
1913  }
1914  else
1915  {
1916  if (bLastY[u])
1917  {
1918  for (int i = -k; i <= k; i++)
1919  if (!input[offset + k * width + i])
1920  {
1921  bLastY[u] = false;
1922  goto next;
1923  }
1924  }
1925  else
1926  {
1927  for (int i = -k; i <= k; i++)
1928  for (int j = -k; j <= k; j++)
1929  if (!input[offset + i * width + j])
1930  goto next;
1931 
1932  bLastY[u] = true;
1933  }
1934 
1935  bLastX = true;
1936  }
1937 
1938  output[offset] = 255;
1939 
1940  next:
1941 
1942  offset++;
1943  }
1944  }
1945 
1946  delete [] bLastY;
1947 
1948  if (pSaveOutputImage)
1949  {
1950  CopyImage(pOutputImage, pSaveOutputImage, pROI, true);
1951  delete pOutputImage;
1952  }
1953 
1954  return true;
1955 }
1956 
1957 
1958 bool ImageProcessor::HistogramEqualization(const CByteImage *pInputImage, CByteImage *pOutputImage)
1959 {
1960  if (pInputImage->width != pOutputImage->width || pInputImage->height != pOutputImage->height ||
1961  pInputImage->type != CByteImage::eGrayScale || pOutputImage->type != CByteImage::eGrayScale)
1962  {
1963  printf("error: input and output image do not match for ImageProcessor::HistogramEqualization\n");
1964  return false;
1965  }
1966 
1967  const int nPixels = pInputImage->width * pInputImage->height;
1968  const unsigned char *input = pInputImage->pixels;
1969  unsigned char *output = pOutputImage->pixels;
1970  const float fNormalizeConstant = 255.0f / nPixels;
1971  int histogram[256] = { 0 };
1972  int i;
1973 
1974  // calculate histogram
1975  for (i = 0; i < nPixels; i++)
1976  histogram[input[i]]++;
1977 
1978  // calculate normalized accumulated histogram
1979  for (i = 1; i < 256; i++)
1980  histogram[i] += histogram[i - 1];
1981 
1982  for (i = 0; i < 256; i++)
1983  histogram[i] = int(histogram[i] * fNormalizeConstant + 0.5f);
1984 
1985  // apply normalization
1986  for (i = 0; i < nPixels; i++)
1987  output[i] = histogram[input[i]];
1988 
1989  return true;
1990 }
1991 
1992 
1993 bool ImageProcessor::ApplyAffinePointOperation(const CByteImage *pInputImage, CByteImage *pOutputImage, float a, float b)
1994 {
1995  OPTIMIZED_FUNCTION_HEADER_4(ApplyAffinePointOperation, pInputImage, pOutputImage, a, b)
1996 
1997  if (!pInputImage->IsCompatible(pOutputImage))
1998  {
1999  printf("error: input and output image do not match for ImageProcessor::ApplyAffinePointOperation\n");
2000  return false;
2001  }
2002 
2003  const int nBytes = pInputImage->width * pInputImage->height * pInputImage->bytesPerPixel;
2004  const unsigned char *input = pInputImage->pixels;
2005  unsigned char *output = pOutputImage->pixels;
2006 
2007  b += 0.5f;
2008 
2009  for (int i = 0; i < nBytes; i++)
2010  {
2011  const int v = int(a * input[i] + b);
2012  output[i] = v < 0 ? 0 : (v > 255 ? 255 : (unsigned char) v);
2013  }
2014 
2016 
2017  return true;
2018 }
2019 
2020 
2021 bool ImageProcessor::Spread(const CByteImage *pInputImage, CByteImage *pOutputImage)
2022 {
2023  if (pInputImage->width != pOutputImage->width || pInputImage->height != pOutputImage->height ||
2024  pInputImage->type != CByteImage::eGrayScale || pOutputImage->type != CByteImage::eGrayScale)
2025  {
2026  printf("error: input and output image do not match for ImageProcessor::Spread\n");
2027  return false;
2028  }
2029 
2030  const int nPixels = pInputImage->width * pInputImage->height;
2031  const unsigned char *input = pInputImage->pixels;
2032  unsigned char min = 255, max = 0;
2033 
2034  // calculate histogram
2035  for (int i = 0; i < nPixels; i++)
2036  {
2037  if (input[i] < min)
2038  min = input[i];
2039 
2040  if (input[i] > max)
2041  max = input[i];
2042  }
2043 
2044  if (min == max)
2045  {
2046  printf("error: input image is homogenous with gray value %i\n", min);
2047  return false;
2048  }
2049 
2050  const float a = 255.0f / (max - min);
2051  const float b = -(min * 255.0f) / (max - min);
2052 
2053  ApplyAffinePointOperation(pInputImage, pOutputImage, a, b);
2054 
2055  return true;
2056 }
2057 
2058 bool ImageProcessor::HistogramStretching(const CByteImage *pInputImage, CByteImage *pOutputImage, float p_min, float p_max)
2059 {
2060  if (pInputImage->width != pOutputImage->width || pInputImage->height != pOutputImage->height ||
2061  pInputImage->type != CByteImage::eGrayScale || pOutputImage->type != CByteImage::eGrayScale)
2062  {
2063  printf("error: input and output image do not match for ImageProcessor::HistogramStretching\n");
2064  return false;
2065  }
2066 
2067  const int nPixels = pInputImage->width * pInputImage->height;
2068  const unsigned char *input = pInputImage->pixels;
2069  int histogram[256] = { 0 };
2070  int i;
2071 
2072  // calculate histogram
2073  for (i = 0; i < nPixels; i++)
2074  histogram[input[i]]++;
2075 
2076  // calculate accumulated histogram
2077  for (i = 1; i < 256; i++)
2078  histogram[i] += histogram[i - 1];
2079 
2080  const float nMinValue = p_min * histogram[255];
2081  const float nMaxValue = p_max * histogram[255];
2082  int min = 0, max = 0;
2083 
2084  for (i = 0; i < 256; i++)
2085  {
2086  if (histogram[i] >= nMinValue)
2087  {
2088  min = i;
2089  break;
2090  }
2091  }
2092 
2093  for (i = 0; i < 256; i++)
2094  {
2095  if (histogram[i] >= nMaxValue)
2096  {
2097  max = i;
2098  break;
2099  }
2100  }
2101 
2102  if (min == max)
2103  {
2104  printf("error: input image is homogenous with gray value %i\n", min);
2105  return false;
2106  }
2107 
2108  const float a = 255.0f / (max - min);
2109  const float b = -(min * 255.0f) / (max - min);
2110 
2111  ApplyAffinePointOperation(pInputImage, pOutputImage, a, b);
2112 
2113  return true;
2114 }
2115 
2116 bool ImageProcessor::Invert(const CByteImage *pInputImage, CByteImage *pOutputImage)
2117 {
2118  OPTIMIZED_FUNCTION_HEADER_2(Invert, pInputImage, pOutputImage)
2119 
2120  if (!pInputImage->IsCompatible(pOutputImage))
2121  {
2122  printf("error: input and output image do not match for ImageProcessor::Invert\n");
2123  return false;
2124  }
2125 
2126  const int nBytes = pInputImage->width * pInputImage->height * pInputImage->bytesPerPixel;
2127  const unsigned char *input = pInputImage->pixels;
2128  unsigned char *output = pOutputImage->pixels;
2129 
2130  for (int i = 0; i < nBytes; i++)
2131  output[i] = 255 - input[i];
2132 
2134 
2135  return true;
2136 }
2137 
2138 
2139 bool ImageProcessor::ConvertImage(const CByteImage *pInputImage, CByteImage *pOutputImage, bool bFast, const MyRegion *pROI)
2140 {
2141  OPTIMIZED_FUNCTION_HEADER_3_ROI(ConvertImage, pInputImage, pOutputImage, bFast, pROI)
2142 
2143  if (pInputImage->width != pOutputImage->width || pInputImage->height != pOutputImage->height)
2144  {
2145  printf("error: input and output image do not match for ImageProcessor::ConvertImage\n");
2146  return false;
2147  }
2148 
2149  if (pInputImage->type == pOutputImage->type)
2150  {
2151  CopyImage(pInputImage, pOutputImage, pROI, true);
2152  return true;
2153  }
2154 
2155  const int nPixels = pInputImage->width * pInputImage->height;
2156 
2157  const unsigned char *input = pInputImage->pixels;
2158  unsigned char *output = pOutputImage->pixels;
2159 
2160  if (pROI)
2161  {
2162  const int width = pInputImage->width;
2163  const int height = pInputImage->height;
2164 
2165  int min_x = pROI->min_x;
2166  int max_x = pROI->max_x;
2167  int min_y = pROI->min_y;
2168  int max_y = pROI->max_y;
2169 
2170  if (min_x < 0) min_x = 0;
2171  if (min_x > width - 1) min_x = width - 1;
2172  if (max_x < 0) max_x = 0;
2173  if (max_x > width - 1) max_x = width - 1;
2174  if (min_y < 0) min_y = 0;
2175  if (min_y > height - 1) min_y = height - 1;
2176  if (max_y < 0) max_y = 0;
2177  if (max_y > height - 1) max_y = height - 1;
2178 
2179  const int diff = width - (max_x - min_x + 1);
2180  const int diff_rgb = 3 * diff;
2181 
2182  if (pInputImage->type == CByteImage::eRGB24)
2183  {
2184  if (pOutputImage->type == CByteImage::eGrayScale)
2185  {
2186  if (bFast)
2187  {
2188  for (int y = min_y, offset_output = width * min_y + min_x, offset_input = 3 * offset_output; y <= max_y; y++, offset_output += diff, offset_input += diff_rgb)
2189  for (int x = min_x; x <= max_x; x++, offset_output++, offset_input += 3)
2190  output[offset_output] = (input[offset_input] + (input[offset_input + 1] << 1) + input[offset_input + 2] + 2) >> 2;
2191  }
2192  else
2193  {
2194  for (int y = min_y, offset_output = width * min_y + min_x, offset_input = 3 * offset_output; y <= max_y; y++, offset_output += diff, offset_input += diff_rgb)
2195  for (int x = min_x; x <= max_x; x++, offset_output++, offset_input += 3)
2196  output[offset_output] = (9797 * input[offset_input] + 19235 * input[offset_input + 1] + 3736 * input[offset_input + 2] + 16384) >> 15;
2197  }
2198  }
2199  else if (pOutputImage->type == CByteImage::eRGB24Split)
2200  {
2201  unsigned char *pHelperR = output;
2202  unsigned char *pHelperG = pHelperR + nPixels;
2203  unsigned char *pHelperB = pHelperG + nPixels;
2204 
2205  for (int y = min_y, offset_output = width * min_y + min_x, offset_input = 3 * offset_output; y <= max_y; y++, offset_output += diff, offset_input += diff_rgb)
2206  for (int x = min_x; x <= max_x; x++, offset_output++, offset_input += 3)
2207  {
2208  pHelperR[offset_output] = input[offset_input];
2209  pHelperG[offset_output] = input[offset_input + 1];
2210  pHelperB[offset_output] = input[offset_input + 2];
2211  }
2212  }
2213  }
2214  if (pInputImage->type == CByteImage::eRGB24Split)
2215  {
2216  const unsigned char *pHelperR = input;
2217  const unsigned char *pHelperG = pHelperR + nPixels;
2218  const unsigned char *pHelperB = pHelperG + nPixels;
2219 
2220  if (pOutputImage->type == CByteImage::eGrayScale)
2221  {
2222  if (bFast)
2223  {
2224  for (int y = min_y, offset = width * min_y + min_x; y <= max_y; y++, offset += diff)
2225  for (int x = min_x; x <= max_x; x++, offset++)
2226  output[offset] = (pHelperR[offset] + (pHelperG[offset] << 1) + pHelperB[offset] + 2) >> 2;
2227  }
2228  else
2229  {
2230  for (int y = min_y, offset = width * min_y + min_x; y <= max_y; y++, offset += diff)
2231  for (int x = min_x; x <= max_x; x++, offset++)
2232  output[offset] = (9797 * pHelperR[offset] + 19235 * pHelperG[offset] + 3736 * pHelperB[offset] + 16384) >> 15;
2233  }
2234  }
2235  else if (pOutputImage->type == CByteImage::eRGB24)
2236  {
2237  for (int y = min_y, input_offset = width * min_y + min_x, output_offset = 3 * input_offset; y <= max_y; y++, input_offset += diff, output_offset += diff_rgb)
2238  for (int x = min_x; x <= max_x; x++, input_offset++, output_offset += 3)
2239  {
2240  output[output_offset] = pHelperR[input_offset];
2241  output[output_offset + 1] = pHelperG[input_offset];
2242  output[output_offset + 2] = pHelperB[input_offset];
2243  }
2244  }
2245  }
2246  else if (pInputImage->type == CByteImage::eGrayScale)
2247  {
2248  if (pOutputImage->type == CByteImage::eRGB24)
2249  {
2250  for (int y = min_y, offset_input = width * min_y + min_x, offset_output = 3 * offset_input; y <= max_y; y++, offset_output += diff_rgb, offset_input += diff)
2251  for (int x = min_x; x <= max_x; x++, offset_output += 3, offset_input++)
2252  {
2253  output[offset_output + 2] = input[offset_input];
2254  output[offset_output + 1] = input[offset_input];
2255  output[offset_output] = input[offset_input];
2256  }
2257  }
2258  else if (pOutputImage->type == CByteImage::eRGB24Split)
2259  {
2260  unsigned char *pHelperR = output;
2261  unsigned char *pHelperG = pHelperR + nPixels;
2262  unsigned char *pHelperB = pHelperG + nPixels;
2263 
2264  for (int y = min_y, offset = width * min_y + min_x; y <= max_y; y++, offset += diff)
2265  for (int x = min_x; x <= max_x; x++, offset++)
2266  pHelperR[offset] = pHelperG[offset] = pHelperB[offset] = input[offset];
2267  }
2268  }
2269  }
2270  else
2271  {
2272  if (pInputImage->type == CByteImage::eRGB24)
2273  {
2274  if (pOutputImage->type == CByteImage::eGrayScale)
2275  {
2276  if (bFast)
2277  {
2278  for (int offset = 0, i = 0; i < nPixels; i++, offset += 3)
2279  output[i] = (input[offset] + (input[offset + 1] << 1) + input[offset + 2] + 2) >> 2;
2280  }
2281  else
2282  {
2283  for (int offset = 0, i = 0; i < nPixels; i++, offset += 3)
2284  output[i] = (9797 * input[offset] + 19235 * input[offset + 1] + 3736 * input[offset + 2] + 16384) >> 15;
2285  }
2286  }
2287  else if (pOutputImage->type == CByteImage::eRGB24Split)
2288  {
2289  unsigned char *pHelperR = output;
2290  unsigned char *pHelperG = pHelperR + nPixels;
2291  unsigned char *pHelperB = pHelperG + nPixels;
2292 
2293  for (int offset = 0, i = 0; i < nPixels; i++, offset += 3)
2294  {
2295  pHelperR[i] = input[offset];
2296  pHelperG[i] = input[offset + 1];
2297  pHelperB[i] = input[offset + 2];
2298  }
2299  }
2300  }
2301  else if (pInputImage->type == CByteImage::eRGB24Split)
2302  {
2303  const unsigned char *pHelperR = input;
2304  const unsigned char *pHelperG = pHelperR + nPixels;
2305  const unsigned char *pHelperB = pHelperG + nPixels;
2306 
2307  if (pOutputImage->type == CByteImage::eGrayScale)
2308  {
2309  if (bFast)
2310  {
2311  for (int i = 0; i < nPixels; i++)
2312  output[i] = (pHelperR[i] + (pHelperG[i] << 1) + pHelperB[i] + 2) >> 2;
2313  }
2314  else
2315  {
2316  for (int i = 0; i < nPixels; i++)
2317  output[i] = (9797 * pHelperR[i] + 19235 * pHelperG[i] + 3736 * pHelperB[i] + 16384) >> 15;
2318  }
2319  }
2320  else if (pOutputImage->type == CByteImage::eRGB24)
2321  {
2322  for (int offset = 0, i = 0; i < nPixels; i++, offset += 3)
2323  {
2324  output[offset] = pHelperR[i];
2325  output[offset + 1] = pHelperG[i];
2326  output[offset + 2] = pHelperB[i];
2327  }
2328  }
2329  }
2330  else if (pInputImage->type == CByteImage::eGrayScale)
2331  {
2332  if (pOutputImage->type == CByteImage::eRGB24)
2333  {
2334  for (int offset = 0, i = 0; i < nPixels; i++, offset += 3)
2335  {
2336  output[offset + 2] = input[i];
2337  output[offset + 1] = input[i];
2338  output[offset] = input[i];
2339  }
2340  }
2341  else if (pOutputImage->type == CByteImage::eRGB24Split)
2342  {
2343  unsigned char *pHelperR = output;
2344  unsigned char *pHelperG = pHelperR + nPixels;
2345  unsigned char *pHelperB = pHelperG + nPixels;
2346 
2347  for (int i = 0; i < nPixels; i++)
2348  pHelperR[i] = pHelperG[i] = pHelperB[i] = input[i];
2349  }
2350  }
2351  }
2352 
2354 
2355  return true;
2356 }
2357 
2358 
2359 bool ImageProcessor::ConvertImage(const CFloatImage *pInputImage, CByteImage *pOutputImage, bool equalize)
2360 {
2361  if(pInputImage->numberOfChannels == 1 && pOutputImage->type != CByteImage::eGrayScale)
2362  {
2363  printf("error: ImageProcessor::ConvertImage cannot convert a single channel float image into mulitple channel byte image\n");
2364  return false;
2365  }
2366 
2367  if(pInputImage->numberOfChannels == 3 && pOutputImage->type == CByteImage::eGrayScale)
2368  {
2369  printf("error: ImageProcessor::ConvertImage cannot convert a 3 channel float image into single channel byte image\n");
2370  return false;
2371  }
2372 
2373  if (pInputImage->width != pOutputImage->width || pInputImage->height != pOutputImage->height)
2374  {
2375  printf("error: input and output image dimensions do not match for ImageProcessor::ConvertImage\n");
2376  return false;
2377  }
2378 
2379  const int nPixels = pInputImage->width * pInputImage->height;
2380  const float* input = pInputImage->pixels;
2381  unsigned char* output = pOutputImage->pixels;
2382  float* min = new float[pInputImage->numberOfChannels];
2383  float* max = new float[pInputImage->numberOfChannels];
2384  float* factor = new float[pInputImage->numberOfChannels];
2385  int i, j;
2386  int pixelChannelIndex;
2387  for (i = 0; i < pInputImage->numberOfChannels; i++)
2388  {
2389  min[i] = FLT_MAX;
2390  max[i] = -FLT_MAX;
2391  }
2392 
2393  for (i = 0; i < nPixels; i++)
2394  {
2395  for (j = 0; j < pInputImage->numberOfChannels; j++)
2396  {
2397  pixelChannelIndex = i * pInputImage->numberOfChannels + j;
2398 
2399  if (input[pixelChannelIndex] > max[j])
2400  {
2401  max[j] = input[pixelChannelIndex];
2402  }
2403 
2404  if (input[pixelChannelIndex] < min[j])
2405  {
2406  min[j] = input[pixelChannelIndex];
2407  }
2408  }
2409  }
2410 
2411  if (equalize)
2412  {
2413 
2414  for (i = 0; i < pInputImage->numberOfChannels; i++)
2415  {
2416  if((max[i] - min[i]) != 0.0f)
2417  {
2418  factor[i] = 255.0f / max[i] - min[i];
2419  }
2420  else
2421  {
2422  factor[i] = 0.0f;
2423  }
2424  }
2425 
2426  for (i = 0; i < nPixels; i++)
2427  {
2428  for (j = 0; j < pInputImage->numberOfChannels; j++)
2429  {
2430  pixelChannelIndex = i * pInputImage->numberOfChannels + j;
2431 
2432  output[pixelChannelIndex] = (unsigned char) ((input[pixelChannelIndex] - min[j]) * factor[j]);
2433  }
2434  }
2435  }
2436  else
2437  {
2438  // verify input value ranges
2439  for (i = 0; i < pInputImage->numberOfChannels; i++)
2440  {
2441  if(min[i] < 0.0f || max[i] > 255.0f)
2442  {
2443  printf("error: float input image values exceed value range of output byte image in ImageProcessor::ConvertImage. Equalization required!\n");
2444  return false;
2445  }
2446  }
2447 
2448  for (i = 0; i < nPixels; i++)
2449  {
2450  for (j = 0; j < pInputImage->numberOfChannels; j++)
2451  {
2452  pixelChannelIndex = i * pInputImage->numberOfChannels + j;
2453 
2454  output[pixelChannelIndex] = (unsigned char) input[pixelChannelIndex];
2455  }
2456  }
2457  }
2458 
2459  return true;
2460 }
2461 
2462 
2463 bool ImageProcessor::ConvertImage(const CByteImage *pInputImage, CFloatImage *pOutputImage)
2464 {
2465  if(pOutputImage->numberOfChannels == 1 && pInputImage->type != CByteImage::eGrayScale)
2466  {
2467  printf("error: ImageProcessor::ConvertImage cannot convert a single channel byte image into single channel byte image\n");
2468  return false;
2469  }
2470 
2471  if(pOutputImage->numberOfChannels == 3 && pInputImage->type == CByteImage::eGrayScale)
2472  {
2473  printf("error: ImageProcessor::ConvertImage cannot convert a single channel byte image into 3-channel float image\n");
2474  return false;
2475  }
2476 
2477  if (pInputImage->width != pOutputImage->width || pInputImage->height != pOutputImage->height)
2478  {
2479  printf("error: input and output image dimensions do not match for ImageProcessor::ConvertImage\n");
2480  return false;
2481  }
2482 
2483  const int nPixels = pInputImage->width * pInputImage->height;
2484  const unsigned char *input = pInputImage->pixels;
2485  float *output = pOutputImage->pixels;
2486  int i, j;
2487  int pixelChannelIndex;
2488 
2489  for (i = 0; i < nPixels; i++)
2490  {
2491  for (j = 0; j < pInputImage->bytesPerPixel; j++)
2492  {
2493  pixelChannelIndex = i * pInputImage->bytesPerPixel + j;
2494 
2495  output[pixelChannelIndex] = (float) input[pixelChannelIndex];
2496  }
2497  }
2498 
2499  return true;
2500 }
2501 
2502 
2503 bool ImageProcessor::ConvertImage(const CFloatMatrix *pInputMatrix, CByteImage *pOutputImage)
2504 {
2505  if (pOutputImage->type != CByteImage::eGrayScale || pInputMatrix->columns != pOutputImage->width || pInputMatrix->rows != pOutputImage->height)
2506  {
2507  printf("error: input matrix and output image do not match for ImageProcessor::ConvertImage\n");
2508  return false;
2509  }
2510 
2511  const int nPixels = pInputMatrix->columns * pInputMatrix->rows;
2512  const float *input = pInputMatrix->data;
2513  unsigned char *output = pOutputImage->pixels;
2514  float min = FLT_MAX, max = -FLT_MAX;
2515  int i;
2516 
2517  for (i = 0; i < nPixels; i++)
2518  {
2519  if (input[i] > max)
2520  max = input[i];
2521 
2522  if (input[i] < min)
2523  min = input[i];
2524  }
2525 
2526  const float divider = max - min;
2527 
2528  if (divider == 0.0f)
2529  {
2530  Zero(pOutputImage);
2531  }
2532  else
2533  {
2534  const float factor = 255.0f / divider;
2535 
2536  for (i = 0; i < nPixels; i++)
2537  output[i] = (unsigned char) ((input[i] - min) * factor);
2538  }
2539 
2540  return true;
2541 }
2542 
2543 bool ImageProcessor::ConvertImage(const CByteImage *pInputImage, CFloatMatrix *pOutputMatrix)
2544 {
2545  if (pInputImage->type != CByteImage::eGrayScale || pOutputMatrix->columns != pInputImage->width || pOutputMatrix->rows != pInputImage->height)
2546  {
2547  printf("error: input image and output matrix do not match for ImageProcessor::ConvertImage\n");
2548  return false;
2549  }
2550 
2551  const int nPixels = pOutputMatrix->columns * pOutputMatrix->rows;
2552  const unsigned char *input = pInputImage->pixels;
2553  float *output = pOutputMatrix->data;
2554 
2555  for (int i = 0; i < nPixels; i++)
2556  output[i] = input[i];
2557 
2558  return true;
2559 }
2560 
2561 bool ImageProcessor::ConvertImage(const CShortImage *pInputImage, CByteImage *pOutputImage)
2562 {
2563  if (pOutputImage->type != CByteImage::eGrayScale || pInputImage->width != pOutputImage->width || pInputImage->height != pOutputImage->height)
2564  {
2565  printf("error: input matrix and output image do not match for ImageProcessor::ConvertImage\n");
2566  return false;
2567  }
2568 
2569  const int nPixels = pInputImage->width * pInputImage->height;
2570  const short *input = pInputImage->pixels;
2571  unsigned char *output = pOutputImage->pixels;
2572  short min = SHRT_MAX, max = SHRT_MIN;
2573  int i;
2574 
2575  for (i = 0; i < nPixels; i++)
2576  {
2577  if (input[i] > max)
2578  max = input[i];
2579 
2580  if (input[i] < min)
2581  min = input[i];
2582  }
2583 
2584  const short divider = max - min;
2585 
2586  if (divider == 0)
2587  {
2588  Zero(pOutputImage);
2589  }
2590  else
2591  {
2592  for (i = 0; i < nPixels; i++)
2593  output[i] = (unsigned char) ((255 * (input[i] - min)) / divider);
2594  }
2595 
2596  return true;
2597 }
2598 
2599 bool ImageProcessor::ConvertImage(const CByteImage *pInputImage, CShortImage *pOutputImage)
2600 {
2601  if (pInputImage->type != CByteImage::eGrayScale || pOutputImage->width != pInputImage->width || pOutputImage->height != pInputImage->height)
2602  {
2603  printf("error: input image and output matrix do not match for ImageProcessor::ConvertImage\n");
2604  return false;
2605  }
2606 
2607  const int nPixels = pOutputImage->width * pOutputImage->height;
2608  const unsigned char *input = pInputImage->pixels;
2609  short *output = pOutputImage->pixels;
2610 
2611  for (int i = 0; i < nPixels; i++)
2612  output[i] = (short) input[i];
2613 
2614  return true;
2615 }
2616 
2617 bool ImageProcessor::ConvertImage(const CByteImage *pInputImage, CIntImage *pOutputImage)
2618 {
2619  if (pInputImage->type != CByteImage::eGrayScale || pOutputImage->width != pInputImage->width || pOutputImage->height != pInputImage->height)
2620  {
2621  printf("error: input image and output matrix do not match for ImageProcessor::ConvertImage\n");
2622  return false;
2623  }
2624 
2625  const int nPixels = pOutputImage->width * pOutputImage->height;
2626  const unsigned char *input = pInputImage->pixels;
2627  int *output = pOutputImage->pixels;
2628 
2629  for (int i = 0; i < nPixels; i++)
2630  output[i] = (int) input[i];
2631 
2632  return true;
2633 }
2634 
2635 bool ImageProcessor::ConvertImage(const CIntImage *pInputImage, CByteImage *pOutputImage)
2636 {
2637  if (pOutputImage->type != CByteImage::eGrayScale || pInputImage->width != pOutputImage->width || pInputImage->height != pOutputImage->height)
2638  {
2639  printf("error: input matrix and output image do not match for ImageProcessor::ConvertImage\n");
2640  return false;
2641  }
2642 
2643  const int nPixels = pInputImage->width * pInputImage->height;
2644  const int *input = pInputImage->pixels;
2645  unsigned char *output = pOutputImage->pixels;
2646  int min = INT_MAX, max = INT_MIN;
2647  int i;
2648 
2649  for (i = 0; i < nPixels; i++)
2650  {
2651  if (input[i] > max)
2652  max = input[i];
2653 
2654  if (input[i] < min)
2655  min = input[i];
2656  }
2657 
2658  const int divider = max - min;
2659 
2660  if (divider == 0)
2661  {
2662  Zero(pOutputImage);
2663  }
2664  else
2665  {
2666  for (i = 0; i < nPixels; i++)
2667  output[i] = (unsigned char) ((255 * (input[i] - min)) / divider);
2668  }
2669 
2670  return true;
2671 }
2672 
2673 
2674 bool ImageProcessor::ConvertMatrix(const CFloatMatrix *pInputMatrix, CDoubleMatrix *pOutputMatrix)
2675 {
2676  if (pInputMatrix->rows != pOutputMatrix->rows || pInputMatrix->columns != pOutputMatrix->columns)
2677  {
2678  printf("error: input image and output matrix do not match for ImageProcessor::ConvertMatrix\n");
2679  return false;
2680  }
2681 
2682  const int nElements = pOutputMatrix->rows * pOutputMatrix->columns;
2683  const float *input = pInputMatrix->data;
2684  double *output = pOutputMatrix->data;
2685 
2686  for (int i = 0; i < nElements; i++)
2687  output[i] = (double) input[i];
2688 
2689  return true;
2690 }
2691 
2692 bool ImageProcessor::ConvertMatrix(const CDoubleMatrix *pInputMatrix, CFloatMatrix *pOutputMatrix)
2693 {
2694  if (pInputMatrix->rows != pOutputMatrix->rows || pInputMatrix->columns != pOutputMatrix->columns)
2695  {
2696  printf("error: input image and output matrix do not match for ImageProcessor::ConvertMatrix\n");
2697  return false;
2698  }
2699 
2700  const int nElements = pOutputMatrix->rows * pOutputMatrix->columns;
2701  const double *input = pInputMatrix->data;
2702  float *output = pOutputMatrix->data;
2703 
2704  for (int i = 0; i < nElements; i++)
2705  output[i] = (float) input[i];
2706 
2707  return true;
2708 }
2709 
2710 
2711 bool ImageProcessor::CopyImage(const CByteImage *pInputImage, CByteImage *pOutputImage, const MyRegion *pROI, bool bUseSameSize)
2712 {
2713  if (!pROI || bUseSameSize)
2714  {
2715  if (pInputImage->width != pOutputImage->width || pInputImage->height != pOutputImage->height || pInputImage->type != pOutputImage->type)
2716  {
2717  printf("error: input and output image do not match for ImageProcessor::CopyImage\n");
2718  return false;
2719  }
2720  }
2721  else if (pROI && !bUseSameSize)
2722  {
2723  const int w = pROI->max_x - pROI->min_x + 1;
2724  const int h = pROI->max_y - pROI->min_y + 1;
2725 
2726  if (w != pOutputImage->width || pOutputImage->height != h || pInputImage->type != pOutputImage->type)
2727  {
2728  printf("error: ROI and output image do not match for ImageProcessor::CopyImage\n");
2729  return false;
2730  }
2731  }
2732 
2733  if (pROI)
2734  {
2735  const int width = pInputImage->width;
2736  const int height = pInputImage->height;
2737 
2738  unsigned char *input = pInputImage->pixels;
2739  unsigned char *output = pOutputImage->pixels;
2740 
2741  int min_x = pROI->min_x;
2742  int max_x = pROI->max_x;
2743  int min_y = pROI->min_y;
2744  int max_y = pROI->max_y;
2745 
2746  if (!bUseSameSize)
2747  {
2748  if (min_x < 0 || min_x > width - 1 || max_x < 0 || max_x > width - 1 ||
2749  min_y < 0 || min_y > height - 1 || max_y < 0 || max_y > height - 1)
2750  {
2751  printf("error: ROI is out of image in ImageProcessor::CopyImage\n");
2752  return false;
2753  }
2754  }
2755 
2756  if (min_x < 0) min_x = 0;
2757  if (min_x > width - 1) min_x = width - 1;
2758  if (max_x < 0) max_x = 0;
2759  if (max_x > width - 1) max_x = width - 1;
2760  if (min_y < 0) min_y = 0;
2761  if (min_y > height - 1) min_y = height - 1;
2762  if (max_y < 0) max_y = 0;
2763  if (max_y > height - 1) max_y = height - 1;
2764 
2765  if (pInputImage->type == CByteImage::eGrayScale)
2766  {
2767  const int size = max_x - min_x + 1;
2768 
2769  if (bUseSameSize)
2770  {
2771  for (int y = min_y, offset = width * min_y + min_x; y <= max_y; y++, offset += width)
2772  memcpy(output + offset, input + offset, size);
2773  }
2774  else
2775  {
2776  for (int y = min_y, offset = width * min_y + min_x, output_offset = 0; y <= max_y; y++, offset += width, output_offset += size)
2777  memcpy(output + output_offset, input + offset, size);
2778  }
2779  }
2780  else if (pInputImage->type == CByteImage::eRGB24)
2781  {
2782  const int size = 3 * (max_x - min_x + 1);
2783  const int width3 = 3 * width;
2784 
2785  if (bUseSameSize)
2786  {
2787  for (int y = min_y, offset = 3 * (width * min_y + min_x); y <= max_y; y++, offset += width3)
2788  memcpy(output + offset, input + offset, size);
2789  }
2790  else
2791  {
2792  for (int y = min_y, offset = 3 * (width * min_y + min_x), output_offset = 0; y <= max_y; y++, offset += width3, output_offset += size)
2793  memcpy(output + output_offset, input + offset, size);
2794  }
2795  }
2796  else if (pInputImage->type == CByteImage::eRGB24Split)
2797  {
2798  const int size = max_x - min_x + 1;
2799 
2800  unsigned char *pHelperR = output;
2801  unsigned char *pHelperG = pHelperR + width * height;
2802  unsigned char *pHelperB = pHelperG + width * height;
2803 
2804  if (bUseSameSize)
2805  {
2806  for (int y = min_y, offset = width * min_y + min_x; y <= max_y; y++, offset += width)
2807  {
2808  memcpy(pHelperR + offset, input + offset, size);
2809  memcpy(pHelperG + offset, input + offset, size);
2810  memcpy(pHelperB + offset, input + offset, size);
2811  }
2812  }
2813  else
2814  {
2815  for (int y = min_y, offset = 3 * (width * min_y + min_x), output_offset = 0; y <= max_y; y++, offset += width, output_offset += size)
2816  {
2817  memcpy(pHelperR + output_offset, input + offset, size);
2818  memcpy(pHelperG + output_offset, input + offset, size);
2819  memcpy(pHelperB + output_offset, input + offset, size);
2820  }
2821  }
2822  }
2823  }
2824  else
2825  {
2826  memcpy(pOutputImage->pixels, pInputImage->pixels, pInputImage->width * pInputImage->height * pInputImage->bytesPerPixel);
2827  }
2828 
2829  return true;
2830 }
2831 
2832 bool ImageProcessor::CopyImage(const CShortImage *pInputImage, CShortImage *pOutputImage, const MyRegion *pROI, bool bUseSameSize)
2833 {
2834  if (!pROI || bUseSameSize)
2835  {
2836  if (pInputImage->width != pOutputImage->width || pInputImage->height != pOutputImage->height)
2837  {
2838  printf("error: input and output image do not match for ImageProcessor::CopyImage\n");
2839  return false;
2840  }
2841  }
2842  else if (pROI && !bUseSameSize)
2843  {
2844  const int w = pROI->max_x - pROI->min_x + 1;
2845  const int h = pROI->max_y - pROI->min_y + 1;
2846 
2847  if (w != pOutputImage->width || pOutputImage->height != h)
2848  {
2849  printf("error: ROI and output image do not match for ImageProcessor::CopyImage\n");
2850  return false;
2851  }
2852  }
2853 
2854  if (pROI)
2855  {
2856  const int width = pInputImage->width;
2857  const int height = pInputImage->height;
2858 
2859  short *input = pInputImage->pixels;
2860  short *output = pOutputImage->pixels;
2861 
2862  int min_x = pROI->min_x;
2863  int max_x = pROI->max_x;
2864  int min_y = pROI->min_y;
2865  int max_y = pROI->max_y;
2866 
2867  if (!bUseSameSize)
2868  {
2869  if (min_x < 0 || min_x > width - 1 || max_x < 0 || max_x > width - 1 ||
2870  min_y < 0 || min_y > height - 1 || max_y < 0 || max_y > height - 1)
2871  {
2872  printf("error: ROI is out of image in ImageProcessor::CopyImage\n");
2873  return false;
2874  }
2875  }
2876 
2877  if (min_x < 0) min_x = 0;
2878  if (min_x > width - 1) min_x = width - 1;
2879  if (max_x < 0) max_x = 0;
2880  if (max_x > width - 1) max_x = width - 1;
2881  if (min_y < 0) min_y = 0;
2882  if (min_y > height - 1) min_y = height - 1;
2883  if (max_y < 0) max_y = 0;
2884  if (max_y > height - 1) max_y = height - 1;
2885 
2886  if (bUseSameSize)
2887  {
2888  const int diff = width - (max_x - min_x + 1);
2889 
2890  for (int y = min_y, offset = width * min_y + min_x; y <= max_y; y++, offset += diff)
2891  for (int x = min_x; x <= max_x; x++, offset++)
2892  output[offset] = input[offset];
2893  }
2894  else
2895  {
2896  const int diff = width - (max_x - min_x + 1);
2897 
2898  for (int y = min_y, offset = width * min_y + min_x, output_offset = 0; y <= max_y; y++, offset += diff)
2899  for (int x = min_x; x <= max_x; x++, offset++, output_offset++)
2900  output[output_offset] = input[offset];
2901  }
2902  }
2903  else
2904  {
2905  memcpy(pOutputImage->pixels, pInputImage->pixels, pInputImage->width * pInputImage->height * sizeof(short));
2906  }
2907 
2908  return true;
2909 }
2910 
2911 
2912 bool ImageProcessor::CopyMatrix(const CFloatMatrix *pInputMatrix, CFloatMatrix *pOutputMatrix)
2913 {
2914  if (pInputMatrix->rows != pOutputMatrix->rows || pInputMatrix->columns != pOutputMatrix->columns)
2915  {
2916  printf("error: input and output matrix do not match for ImageProcessor::CopyMatrix\n");
2917  return false;
2918  }
2919 
2920  memcpy(pOutputMatrix->data, pInputMatrix->data, pInputMatrix->rows * pInputMatrix->columns * sizeof(float));
2921 
2922  return true;
2923 }
2924 
2925 bool ImageProcessor::CopyMatrix(const CDoubleMatrix *pInputMatrix, CDoubleMatrix *pOutputMatrix)
2926 {
2927  if (pInputMatrix->rows != pOutputMatrix->rows || pInputMatrix->columns != pOutputMatrix->columns)
2928  {
2929  printf("error: input and output matrix do not match for ImageProcessor::CopyMatrix\n");
2930  return false;
2931  }
2932 
2933  memcpy(pOutputMatrix->data, pInputMatrix->data, pInputMatrix->rows * pInputMatrix->columns * sizeof(double));
2934 
2935  return true;
2936 }
2937 
2938 
2939 void ImageProcessor::Zero(CByteImage *pImage, const MyRegion *pROI)
2940 {
2941  if (pROI)
2942  {
2943  const int width = pImage->width;
2944  const int height = pImage->height;
2945 
2946  unsigned char *pixels = pImage->pixels;
2947 
2948  int min_x = pROI->min_x;
2949  int max_x = pROI->max_x;
2950  int min_y = pROI->min_y;
2951  int max_y = pROI->max_y;
2952 
2953  if (min_x < 0) min_x = 0;
2954  if (min_x > width - 1) min_x = width - 1;
2955  if (max_x < 0) max_x = 0;
2956  if (max_x > width - 1) max_x = width - 1;
2957  if (min_y < 0) min_y = 0;
2958  if (min_y > height - 1) min_y = height - 1;
2959  if (max_y < 0) max_y = 0;
2960  if (max_y > height - 1) max_y = height - 1;
2961 
2962  if (pImage->type == CByteImage::eGrayScale)
2963  {
2964  const int size = max_x - min_x + 1;
2965 
2966  for (int y = min_y, offset = width * min_y + min_x; y <= max_y; y++, offset += width)
2967  memset(pixels + offset, 0, size);
2968  }
2969  else if (pImage->type == CByteImage::eRGB24)
2970  {
2971  const int size = 3 * (max_x - min_x + 1);
2972  const int width3 = 3 * width;
2973 
2974  for (int y = min_y, offset = 3 * (width * min_y + min_x); y <= max_y; y++, offset += width3)
2975  memset(pixels, 0, size);
2976  }
2977  else if (pImage->type == CByteImage::eRGB24Split)
2978  {
2979  const int size = max_x - min_x + 1;
2980 
2981  unsigned char *pHelperR = pixels;
2982  unsigned char *pHelperG = pHelperR + width * height;
2983  unsigned char *pHelperB = pHelperG + width * height;
2984 
2985  for (int y = min_y, offset = width * min_y + min_x; y <= max_y; y++, offset += width)
2986  {
2987  memset(pHelperR + offset, 0, size);
2988  memset(pHelperG + offset, 0, size);
2989  memset(pHelperB + offset, 0, size);
2990  }
2991  }
2992  }
2993  else
2994  {
2995  memset(pImage->pixels, 0, pImage->width * pImage->height * pImage->bytesPerPixel);
2996  }
2997 }
2998 
3000 {
3001  memset(pImage->pixels, 0, pImage->width * pImage->height * sizeof(*pImage->pixels));
3002 }
3003 
3005 {
3006  memset(pImage->pixels, 0, pImage->width * pImage->height * sizeof(*pImage->pixels));
3007 }
3008 
3010 {
3011  memset(pMatrix->data, 0, pMatrix->columns * pMatrix->rows * sizeof(*pMatrix->data));
3012 }
3013 
3015 {
3016  memset(pMatrix->data, 0, pMatrix->columns * pMatrix->rows * sizeof(*pMatrix->data));
3017 }
3018 
3019 
3021 {
3022  const int width = pImage->width;
3023  const int height = pImage->height;
3024  unsigned char *pixels = pImage->pixels;
3025 
3026  if (pImage->type == CByteImage::eGrayScale)
3027  {
3028  // zero top and bottom row
3029  memset(pixels, 0, width);
3030  memset(pixels + width * (height - 1), 0, width);
3031 
3032  // zero left and right column
3033  for (int i = 0, offset = 0; i < height; i++, offset += width)
3034  {
3035  pixels[offset] = 0;
3036  pixels[offset + width - 1] = 0;
3037  }
3038  }
3039  else
3040  {
3041  const int width3 = 3 * width;
3042 
3043  // zero top and bottom row
3044  memset(pixels, 0, width3);
3045  memset(pixels + width3 * (height - 1), 0, width3);
3046 
3047  // zero left and right column
3048  for (int i = 0, offset = 0; i < height; i++, offset += width3)
3049  {
3050  pixels[offset] = pixels[offset + 1] = pixels[offset + 2] = 0;
3051  pixels[offset + width3 - 3] = pixels[offset + width3 - 2] = pixels[offset + width3 - 1] = 0;
3052  }
3053  }
3054 }
3055 
3057 {
3058  const int width = pImage->width;
3059  const int height = pImage->height;
3060  short *pixels = pImage->pixels;
3061 
3062  // zero top and bottom row
3063  memset(pixels, 0, width * sizeof(short));
3064  memset(pixels + width * (height - 1), 0, width * sizeof(short));
3065 
3066  // zero left and right column
3067  for (int i = 0, offset = 0; i < height; i++, offset += width)
3068  {
3069  pixels[offset] = 0;
3070  pixels[offset + width - 1] = 0;
3071  }
3072 }
3073 
3075 {
3076  const int width = pImage->width;
3077  const int height = pImage->height;
3078  int *pixels = pImage->pixels;
3079 
3080  // zero top and bottom row
3081  memset(pixels, 0, width * sizeof(int));
3082  memset(pixels + width * (height - 1), 0, width * sizeof(int));
3083 
3084  // zero left and right column
3085  for (int i = 0, offset = 0; i < height; i++, offset += width)
3086  {
3087  pixels[offset] = 0;
3088  pixels[offset + width - 1] = 0;
3089  }
3090 }
3091 
3092 bool ImageProcessor::CopyFrame(const CByteImage *pInputImage, CByteImage *pOutputImage)
3093 {
3094  if (pInputImage->width != pOutputImage->width || pInputImage->height != pOutputImage->height || pInputImage->type != pOutputImage->type || pInputImage->type == CByteImage::eRGB24Split)
3095  {
3096  printf("error: input and output images do not match for ImageProcessor::CopyFrame\n");
3097  return false;
3098  }
3099 
3100  // copy is not necessary in this case
3101  if (pInputImage->pixels == pOutputImage->pixels)
3102  return true;
3103 
3104  const unsigned char *input = pInputImage->pixels;
3105  unsigned char *output = pOutputImage->pixels;
3106 
3107  const int width = pInputImage->width;
3108  const int height = pInputImage->height;
3109 
3110  if (pInputImage->type == CByteImage::eGrayScale)
3111  {
3112  memcpy(output, input, width);
3113  memcpy(output + width * (height - 1), input + width * (height - 1), width);
3114 
3115  unsigned int offset = width;
3116  const unsigned int offset2 = width - 1;
3117  for (int y = 1; y < height-1; y++, offset += width)
3118  {
3119  output[offset] = input[offset];
3120  output[offset + offset2] = input[offset + offset2];
3121  }
3122  }
3123  else if (pInputImage->type == CByteImage::eRGB24)
3124  {
3125  memcpy(output, input, 3*width);
3126  memcpy(output + 3 * width * (height - 1), input + 3 * width * (height - 1), 3 * width);
3127 
3128  unsigned int offset = 3 * width;
3129  const unsigned int offset2 = 3 * (width - 1);
3130  for (int y = 1; y < height - 1; y++, offset += 3 * width)
3131  {
3132  output[offset] = input[offset];
3133  output[offset + 1] = input[offset + 1];
3134  output[offset + 2] = input[offset + 2];
3135  output[offset + offset2] = input[offset + offset2];
3136  output[offset + offset2 + 1] = input[offset + offset2 + 1];
3137  output[offset + offset2 + 2] = input[offset + offset2 + 2];
3138  }
3139  }
3140 
3141  return true;
3142 }
3143 
3144 bool ImageProcessor::AdaptFrame(const CByteImage *pInputImage, CByteImage *pOutputImage)
3145 {
3146  if (pInputImage->width != pOutputImage->width || pInputImage->height != pOutputImage->height || pInputImage->type != pOutputImage->type || pInputImage->type == CByteImage::eRGB24Split)
3147  {
3148  printf("error: input and output images do not match for ImageProcessor::CopyFrame\n");
3149  return false;
3150  }
3151 
3152  const unsigned char *input = pInputImage->pixels;
3153  unsigned char *output = pOutputImage->pixels;
3154 
3155  const int width = pInputImage->width;
3156  const int height = pInputImage->height;
3157 
3158  if (pInputImage->type == CByteImage::eGrayScale)
3159  {
3160  // adapt the top and bottom row
3161  memcpy(&output[1], &input[width + 1], width-2);
3162  memcpy(&output[width*(height-1) + 1], &input[width*(height-2) + 1], width-2);
3163 
3164  // adapt the corners
3165  output[0] = input[width + 1];
3166  output[width - 1] = input[2*width - 2];
3167  output[width*(height-1)] = input[width*(height-2) + 1];
3168  output[width*height - 1] = input[width*height - 2];
3169 
3170  // adapt the left and right borders
3171  unsigned int offset = width;
3172  const unsigned int offset2 = width-1;
3173  for (int y = 1; y < height-1; y++, offset += width)
3174  {
3175  output[offset] = input[offset+1];
3176  output[offset + offset2] = input[offset + offset2 - 1];
3177  }
3178  }
3179  else if (pInputImage->type == CByteImage::eRGB24)
3180  {
3181  // adapt the top and bottom row
3182  memcpy(&output[3], &input[3*(width + 1)], 3*(width-2));
3183  memcpy(&output[3*(width*(height-1) + 1)], &input[3*(width*(height-2) + 1)], 3*(width-2));
3184 
3185  // adapt the corners
3186  output[0] = input[3*(width + 1)];
3187  output[1] = input[3*(width + 1) + 1];
3188  output[2] = input[3*(width + 1) + 2];
3189  output[3*(width - 1)] = input[3*(2*width - 2)];
3190  output[3*(width - 1) + 1] = input[3*(2*width - 2) + 1];
3191  output[3*(width - 1) + 2] = input[3*(2*width - 2) + 2];
3192  output[3*(width*(height-1))] = input[3*(width*(height-2) + 1)];
3193  output[3*(width*(height-1)) + 1] = input[3*(width*(height-2) + 1) + 1];
3194  output[3*(width*(height-1)) + 2] = input[3*(width*(height-2) + 1) + 2];
3195  output[3*(width*height - 1)] = input[3*(width*(height-1) - 2)];
3196  output[3*(width*height - 1) + 1] = input[3*(width*(height-1) - 2) + 1];
3197  output[3*(width*height - 1) + 2] = input[3*(width*(height-1) - 2) + 2];
3198 
3199  // adapt the left and right borders
3200  unsigned int offset = 3*width;
3201  const unsigned int offset2 = 3*(width-1);
3202  for (int y = 1; y < height-1; y++, offset += 3*width)
3203  {
3204  output[offset] = input[offset + 3];
3205  output[offset + 1] = input[offset + 3 + 1];
3206  output[offset + 2] = input[offset + 3 + 2];
3207  output[offset + offset2] = input[offset + offset2 - 3];
3208  output[offset + offset2 + 1] = input[offset + offset2 - 3 + 1];
3209  output[offset + offset2 + 2] = input[offset + offset2 - 3 + 2];
3210  }
3211  }
3212 
3213  return true;
3214 }
3215 
3216 
3217 bool ImageProcessor::ApplyHomography(const CByteImage *pInputImage, CByteImage *pOutputImage, float a1, float a2, float a3, float a4, float a5, float a6, float a7, float a8, bool bInterpolation)
3218 {
3219  const Mat3d A = { a1, a2, a3, a4, a5, a6, a7, a8, 1.0f };
3220  return ApplyHomography(pInputImage, pOutputImage, A, bInterpolation);
3221 }
3222 
3223 bool ImageProcessor::ApplyHomography(const CByteImage *pInputImage, CByteImage *pOutputImage, const Mat3d &A, bool bInterpolation)
3224 {
3225  if (pInputImage->type != pOutputImage->type)
3226  {
3227  printf("error: input and output image do not match in ImageProcessor::ApplyHomography\n");
3228  return false;
3229  }
3230 
3231  const float a1 = A.r1;
3232  const float a2 = A.r2;
3233  const float a3 = A.r3;
3234  const float a4 = A.r4;
3235  const float a5 = A.r5;
3236  const float a6 = A.r6;
3237  const float a7 = A.r7;
3238  const float a8 = A.r8;
3239  const float a9 = A.r9;
3240 
3241  CByteImage *pSaveOutputImage = 0;
3242  if (pInputImage->pixels == pOutputImage->pixels)
3243  {
3244  pSaveOutputImage = pOutputImage;
3245  pOutputImage = new CByteImage(pInputImage);
3246  }
3247 
3248  const int width = pInputImage->width;
3249  const int height = pInputImage->height;
3250  const int output_width = pOutputImage->width;
3251  const int output_height = pOutputImage->height;
3252  const unsigned char *input = pInputImage->pixels;
3253  unsigned char *output = pOutputImage->pixels;
3254  const CByteImage::ImageType type = pInputImage->type;
3255 
3256  if (bInterpolation)
3257  {
3258  if (type == CByteImage::eGrayScale)
3259  {
3260  for (int v = 0, offset = 0; v < output_height; v++)
3261  {
3262  for (int u = 0; u < output_width; u++, offset++)
3263  {
3264  const float u_ = (a1 * u + a2 * v + a3) / (a7 * u + a8 * v + a9);
3265  const float v_ = (a4 * u + a5 * v + a6) / (a7 * u + a8 * v + a9);
3266 
3267  const int u1 = int(floor(u_));
3268  const int v1 = int(floor(v_));
3269  const int u2 = u1 + 1;
3270  const int v2 = v1 + 1;
3271 
3272  unsigned char f00 = 0, f10 = 0, f01 = 0, f11 = 0;
3273 
3274  const bool v1_ok = v1 >= 0 && v1 < height;
3275  const bool v2_ok = v2 >= 0 && v2 < height;
3276 
3277  if (u1 >= 0 && u1 < width)
3278  {
3279  if (v1_ok)
3280  f00 = input[v1 * width + u1];
3281 
3282  if (v2_ok)
3283  f01 = input[v2 * width + u1];
3284  }
3285 
3286  if (u2 >= 0 && u2 < width)
3287  {
3288  if (v1_ok)
3289  f10 = input[v1 * width + u2];
3290 
3291  if (v2_ok)
3292  f11 = input[v2 * width + u2];
3293  }
3294 
3295  const float x = u_ - u1;
3296  const float y = v_ - v1;
3297 
3298  output[offset] = (unsigned char) (f00 * (1 - x) * (1 - y) + f10 * x * (1 - y) + f01 * (1 - x) * y + f11 * x * y + 0.5f);
3299  }
3300  }
3301  }
3302  else if (type == CByteImage::eRGB24)
3303  {
3304  for (int v = 0, offset = 0; v < height; v++)
3305  {
3306  for (int u = 0; u < width; u++, offset += 3)
3307  {
3308  const float u_ = (a1 * u + a2 * v + a3) / (a7 * u + a8 * v + a9);
3309  const float v_ = (a4 * u + a5 * v + a6) / (a7 * u + a8 * v + a9);
3310 
3311  const int u1 = int(floor(u_));
3312  const int v1 = int(floor(v_));
3313  const int u2 = u1 + 1;
3314  const int v2 = v1 + 1;
3315 
3316  unsigned char f00_r = 0, f00_g = 0, f00_b = 0;
3317  unsigned char f10_r = 0, f10_g = 0, f10_b = 0;
3318  unsigned char f01_r = 0, f01_g = 0, f01_b = 0;
3319  unsigned char f11_r = 0, f11_g = 0, f11_b = 0;
3320 
3321  const bool v1_ok = v1 >= 0 && v1 < height;
3322  const bool v2_ok = v2 >= 0 && v2 < height;
3323 
3324  if (u1 >= 0 && u1 < width)
3325  {
3326  if (v1_ok)
3327  {
3328  const int x = 3 * (v1 * width + u1);
3329  f00_r = input[x];
3330  f00_g = input[x + 1];
3331  f00_b = input[x + 2];
3332  }
3333 
3334  if (v2_ok)
3335  {
3336  const int x = 3 * (v2 * width + u1);
3337  f01_r = input[x];
3338  f01_g = input[x + 1];
3339  f01_b = input[x + 2];
3340  }
3341  }
3342 
3343  if (u2 >= 0 && u2 < width)
3344  {
3345  if (v1_ok)
3346  {
3347  const int x = 3 * (v1 * width + u2);
3348  f10_r = input[x];
3349  f10_g = input[x + 1];
3350  f10_b = input[x + 2];
3351  }
3352 
3353  if (v2_ok)
3354  {
3355  const int x = 3 * (v2 * width + u2);
3356  f11_r = input[x];
3357  f11_g = input[x + 1];
3358  f11_b = input[x + 2];
3359  }
3360  }
3361 
3362  const float x = u_ - u1;
3363  const float y = v_ - v1;
3364 
3365  output[offset ] = (unsigned char) (f00_r * (1 - x) * (1 - y) + f10_r * x * (1 - y) + f01_r * (1 - x) * y + f11_r * x * y + 0.5f);
3366  output[offset + 1] = (unsigned char) (f00_g * (1 - x) * (1 - y) + f10_g * x * (1 - y) + f01_g * (1 - x) * y + f11_g * x * y + 0.5f);
3367  output[offset + 2] = (unsigned char) (f00_b * (1 - x) * (1 - y) + f10_b * x * (1 - y) + f01_b * (1 - x) * y + f11_b * x * y + 0.5f);
3368  }
3369  }
3370  }
3371  }
3372  else
3373  {
3374  if (type == CByteImage::eGrayScale)
3375  {
3376  for (int v = 0, offset = 0; v < output_height; v++)
3377  {
3378  for (int u = 0; u < output_width; u++, offset++)
3379  {
3380  const int u_ = (int) ((a1 * u + a2 * v + a3) / (a7 * u + a8 * v + 1.0f) + 0.5f);
3381  const int v_ = (int) ((a4 * u + a5 * v + a6) / (a7 * u + a8 * v + 1.0f) + 0.5f);
3382 
3383  if (u_ < 0 || u_ >= width || v_ < 0 || v_ >= height)
3384  output[offset] = 0;
3385  else
3386  output[offset] = input[v_ * width + u_];
3387  }
3388  }
3389  }
3390  else if (type == CByteImage::eRGB24)
3391  {
3392  for (int v = 0, offset = 0; v < output_height; v++)
3393  {
3394  for (int u = 0; u < output_width; u++, offset += 3)
3395  {
3396  const int u_ = (int) ((a1 * u + a2 * v + a3) / (a7 * u + a8 * v + 1.0f) + 0.5f);
3397  const int v_ = (int) ((a4 * u + a5 * v + a6) / (a7 * u + a8 * v + 1.0f) + 0.5f);
3398 
3399  if (u_ < 0 || u_ >= width || v_ < 0 || v_ >= height)
3400  output[offset] = output[offset + 1] = output[offset + 2] = 0;
3401  else
3402  {
3403  const int offset2 = 3 * (v_ * width + u_);
3404  output[offset] = input[offset2];
3405  output[offset + 1] = input[offset2 + 1];
3406  output[offset + 2] = input[offset2 + 2];
3407  }
3408  }
3409  }
3410  }
3411  }
3412 
3413  if (pSaveOutputImage)
3414  {
3415  CopyImage(pOutputImage, pSaveOutputImage);
3416  delete pOutputImage;
3417  }
3418 
3419  return true;
3420 }
3421 
3422 bool ImageProcessor::Resize(const CByteImage *pInputImage, CByteImage *pOutputImage, const MyRegion *pROI, bool bInterpolation)
3423 {
3424  if (pInputImage->type != pOutputImage->type || pInputImage->type == CByteImage::eRGB24Split)
3425  {
3426  printf("error: input and output image do not match in ImageProcessor::Resize\n");
3427  return false;
3428  }
3429 
3430  if (pInputImage->width == pOutputImage->width && pInputImage->height == pOutputImage->height)
3431  {
3432  CopyImage(pInputImage, pOutputImage);
3433  return false;
3434  }
3435 
3436  const CByteImage::ImageType type = pInputImage->type;
3437 
3438  const int output_width = pOutputImage->width;
3439  const int output_height = pOutputImage->height;
3440  unsigned char *output = pOutputImage->pixels;
3441 
3442  const int input_width = pInputImage->width;
3443  const int input_height = pInputImage->height;
3444  const unsigned char *input = pInputImage->pixels;
3445 
3446  const int start_x = pROI ? pROI->min_x : 0;
3447  const int start_y = pROI ? pROI->min_y : 0;
3448 
3449  const int width = pROI ? pROI->max_x - pROI->min_x + 1 : input_width;
3450  const int height = pROI ? pROI->max_y - pROI->min_y + 1 : input_height;
3451 
3452  if (pROI)
3453  {
3454  if (pROI->min_x < 0 || pROI->min_y < 0 || pROI->max_x >= input_width || pROI->max_y >= input_height)
3455  {
3456  printf("error: provided ROI in ImageProcessor::Resize exceeds input image boundaries\n");
3457  return false;
3458  }
3459  }
3460 
3461  if (width > output_width && width % output_width == 0 &&
3462  height > output_height && height % output_height == 0)
3463  {
3464  if (type == CByteImage::eGrayScale)
3465  {
3466  const int a1 = width / output_width;
3467  const int a4 = height / output_height;
3468  const int delta = a4 * input_width - width;
3469 
3470  for (int v = 0, offset = 0, offset_ = start_y * input_width + start_x; v < output_height; v++, offset_ += delta)
3471  {
3472  for (int u = 0; u < output_width; u++, offset++, offset_ += a1)
3473  output[offset] = input[offset_];
3474  }
3475  }
3476  else if (type == CByteImage::eRGB24)
3477  {
3478  const int a1 = 3 * (width / output_width);
3479  const int a4 = height / output_height;
3480  const int delta = 3 * (a4 * input_width - width);
3481 
3482  for (int v = 0, offset = 0, offset_ = 3 * (start_y * input_width + start_x); v < output_height; v++, offset_ += delta)
3483  {
3484  for (int u = 0; u < output_width; u++, offset += 3, offset_ += a1)
3485  {
3486  output[offset] = input[offset_];
3487  output[offset + 1] = input[offset_ + 1];
3488  output[offset + 2] = input[offset_ + 2];
3489  }
3490  }
3491  }
3492 
3493  return true;
3494  }
3495 
3496  const float a1 = float(width) / output_width;
3497  const float a4 = float(height) / output_height;
3498 
3499  int *pXOffsets = 0, *pYOffsets = 0;
3500  int *pXCoordinates = 0, *pYCoordinates = 0;
3501 
3502  const int min_width = MY_MIN(width, output_width);
3503  const int min_height = MY_MIN(height, output_height);
3504  int i;
3505 
3506  if (type == CByteImage::eGrayScale)
3507  {
3508  pXOffsets = new int[output_width];
3509  pYOffsets = new int[output_height];
3510 
3511  if (bInterpolation)
3512  {
3513  pXCoordinates = new int[output_width];
3514  pYCoordinates = new int[output_height];
3515 
3516  for (i = 0; i < output_width; i++)
3517  {
3518  register int x = (i * width) / output_width;
3519 
3520  if (start_x + x < input_width - 1)
3521  {
3522  pXOffsets[i] = start_x + x;
3523  pXCoordinates[i] = int((i * a1 - x) * 1024);
3524  }
3525  else
3526  {
3527  pXOffsets[i] = input_width - 2;
3528  pXCoordinates[i] = 1024;
3529  }
3530  }
3531 
3532  for (i = 0; i < output_height; i++)
3533  {
3534  register int y = (i * height) / output_height;
3535 
3536  if (start_y + y < input_height - 1)
3537  {
3538  pYOffsets[i] = input_width * (start_y + y);
3539  pYCoordinates[i] = int((i * a4 - y) * 1024);
3540  }
3541  else
3542  {
3543  pYOffsets[i] = input_width * (input_height - 2);
3544  pYCoordinates[i] = 1024;
3545  }
3546  }
3547  }
3548  else
3549  {
3550  for (i = 0; i < output_width; i++)
3551  pXOffsets[i] = start_x + (((i * width) << 1) + min_width - 1) / (output_width << 1);
3552 
3553  for (i = 0; i < output_height; i++)
3554  pYOffsets[i] = input_width * (start_y + (((i * height) << 1) + min_height - 1) / (output_height << 1));
3555  }
3556  }
3557  else
3558  {
3559  pXOffsets = new int[3 * output_width];
3560  pYOffsets = new int[output_height];
3561 
3562  int offset = 0;
3563 
3564  if (bInterpolation)
3565  {
3566  pXCoordinates = new int[3 * output_width];
3567  pYCoordinates = new int[output_height];
3568 
3569  for (i = 0; i < output_width; i++, offset += 3)
3570  {
3571  register int x = (i * width) / output_width;
3572 
3573  if (start_x + x < input_width - 1)
3574  {
3575  pXOffsets[offset] = 3 * (start_x + x);
3576  pXCoordinates[offset] = int((i * a1 - x) * 1024);
3577  }
3578  else
3579  {
3580  pXOffsets[offset] = 3 * (input_width - 2);
3581  pXCoordinates[offset] = 1024;
3582  }
3583  }
3584 
3585  for (i = 0; i < output_height; i++)
3586  {
3587  register int y = (i * height) / output_height;
3588 
3589  if (start_y + y < input_height - 1)
3590  {
3591  pYOffsets[i] = 3 * input_width * (start_y + y);
3592  pYCoordinates[i] = int((i * a4 - y) * 1024);
3593  }
3594  else
3595  {
3596  pYOffsets[i] = 3 * input_width * (input_height - 2);
3597  pYCoordinates[i] = 1024;
3598  }
3599  }
3600  }
3601  else
3602  {
3603  for (i = 0; i < output_width; i++, offset += 3)
3604  pXOffsets[offset] = 3 * (start_x + (((i * width) << 1) + min_width - 1) / (output_width << 1));
3605 
3606  for (i = 0; i < output_height; i++)
3607  pYOffsets[i] = 3 * input_width * (start_y + (((i * height) << 1) + min_height - 1) / (output_height << 1));
3608  }
3609  }
3610 
3611  if (bInterpolation)
3612  {
3613  if (type == CByteImage::eGrayScale)
3614  {
3615  const int last_u = MY_MAX(0, output_width - output_width % 4);
3616 
3617  for (int v = 0; v < output_height; v++)
3618  {
3619  const unsigned char *input_helper = input + pYOffsets[v];
3620  const int y = pYCoordinates[v];
3621  int u;
3622 
3623  for (u = 0; u < last_u; u += 4)
3624  {
3625  int offset;
3626  int x;
3627 
3628  offset = pXOffsets[u];
3629  x = pXCoordinates[u];
3630  output[u] = (unsigned char) (
3631  ((input_helper[offset] * (1024 - x) * (1024 - y)) +
3632  (input_helper[offset + 1] * x * (1024 - y)) +
3633  (input_helper[offset + input_width] * (1024 - x) * y) +
3634  (input_helper[offset + input_width + 1] * x * y)) >> 20
3635  );
3636 
3637  offset = pXOffsets[u + 1];
3638  x = pXCoordinates[u + 1];
3639  output[u + 1] = (unsigned char) (
3640  ((input_helper[offset] * (1024 - x) * (1024 - y)) +
3641  (input_helper[offset + 1] * x * (1024 - y)) +
3642  (input_helper[offset + input_width] * (1024 - x) * y) +
3643  (input_helper[offset + input_width + 1] * x * y)) >> 20
3644  );
3645 
3646  offset = pXOffsets[u + 2];
3647  x = pXCoordinates[u + 2];
3648  output[u + 2] = (unsigned char) (
3649  ((input_helper[offset] * (1024 - x) * (1024 - y)) +
3650  (input_helper[offset + 1] * x * (1024 - y)) +
3651  (input_helper[offset + input_width] * (1024 - x) * y) +
3652  (input_helper[offset + input_width + 1] * x * y)) >> 20
3653  );
3654 
3655  offset = pXOffsets[u + 3];
3656  x = pXCoordinates[u + 3];
3657  output[u + 3] = (unsigned char) (
3658  ((input_helper[offset] * (1024 - x) * (1024 - y)) +
3659  (input_helper[offset + 1] * x * (1024 - y)) +
3660  (input_helper[offset + input_width] * (1024 - x) * y) +
3661  (input_helper[offset + input_width + 1] * x * y)) >> 20
3662  );
3663  }
3664 
3665  for (u = last_u; u < output_width; u++)
3666  {
3667  const int offset = pXOffsets[u];
3668  const int x = pXCoordinates[u];
3669  output[u] = (unsigned char) (
3670  ((input_helper[offset] * (1024 - x) * (1024 - y)) +
3671  (input_helper[offset + 1] * x * (1024 - y)) +
3672  (input_helper[offset + input_width] * (1024 - x) * y) +
3673  (input_helper[offset + input_width + 1] * x * y)) >> 20
3674  );
3675  }
3676 
3677  output += output_width;
3678  }
3679  }
3680  else if (type == CByteImage::eRGB24)
3681  {
3682  const int output_width3 = 3 * output_width;
3683  const int input_width3 = 3 * input_width;
3684 
3685  for (int v = 0; v < output_height; v++)
3686  {
3687  const unsigned char *input_helper = input + pYOffsets[v];
3688  const int y = pYCoordinates[v];
3689 
3690  for (int u = 0; u < output_width3; u += 3)
3691  {
3692  const int x = pXCoordinates[u];
3693  const int f00 = (1024 - x) * (1024 - y);
3694  const int f10 = x * (1024 - y);
3695  const int f01 = (1024 - x) * y;
3696  const int f11 = x * y;
3697 
3698  register int offset;
3699 
3700  offset = pXOffsets[u];
3701  output[u] = (unsigned char) (
3702  ((input_helper[offset] * f00) +
3703  (input_helper[offset + 3] * f10) +
3704  (input_helper[offset + input_width3] * f01) +
3705  (input_helper[offset + input_width3 + 3] * f11)) >> 20
3706  );
3707 
3708  offset++;
3709  output[u + 1] = (unsigned char) (
3710  ((input_helper[offset] * f00) +
3711  (input_helper[offset + 3] * f10) +
3712  (input_helper[offset + input_width3] * f01) +
3713  (input_helper[offset + input_width3 + 3] * f11)) >> 20
3714  );
3715 
3716  offset++;
3717  output[u + 2] = (unsigned char) (
3718  ((input_helper[offset] * f00) +
3719  (input_helper[offset + 3] * f10) +
3720  (input_helper[offset + input_width3] * f01) +
3721  (input_helper[offset + input_width3 + 3] * f11)) >> 20
3722  );
3723  }
3724 
3725  output += output_width3;
3726  }
3727  }
3728  }
3729  else
3730  {
3731  if (type == CByteImage::eGrayScale)
3732  {
3733  const int last_u = MY_MAX(0, output_width - output_width % 4);
3734 
3735  for (int v = 0; v < output_height; v++)
3736  {
3737  const unsigned char *input_helper = input + pYOffsets[v];
3738  int u;
3739 
3740  for (u = 0; u < last_u; u += 4)
3741  {
3742  output[u] = input_helper[pXOffsets[u]];
3743  output[u + 1] = input_helper[pXOffsets[u + 1]];
3744  output[u + 2] = input_helper[pXOffsets[u + 2]];
3745  output[u + 3] = input_helper[pXOffsets[u + 3]];
3746  }
3747 
3748  for (u = last_u; u < output_width; u++)
3749  output[u] = input_helper[pXOffsets[u]];
3750 
3751  output += output_width;
3752  }
3753  }
3754  else if (type == CByteImage::eRGB24)
3755  {
3756  const int output_width3 = 3 * output_width;
3757  const int last_u = 3 * MY_MAX(0, output_width - output_width % 4);
3758 
3759  for (int v = 0; v < output_height; v++)
3760  {
3761  const unsigned char *input_helper = input + pYOffsets[v];
3762  int u;
3763 
3764  for (u = 0; u < last_u; u += 12)
3765  {
3766  register int input_offset;
3767 
3768  input_offset = pXOffsets[u];
3769  output[u] = input_helper[input_offset];
3770  output[u + 1] = input_helper[input_offset + 1];
3771  output[u + 2] = input_helper[input_offset + 2];
3772 
3773  input_offset = pXOffsets[u + 3];
3774  output[u + 3] = input_helper[input_offset];
3775  output[u + 4] = input_helper[input_offset + 1];
3776  output[u + 5] = input_helper[input_offset + 2];
3777 
3778  input_offset = pXOffsets[u + 6];
3779  output[u + 6] = input_helper[input_offset];
3780  output[u + 7] = input_helper[input_offset + 1];
3781  output[u + 8] = input_helper[input_offset + 2];
3782 
3783  input_offset = pXOffsets[u + 9];
3784  output[u + 9] = input_helper[input_offset];
3785  output[u + 10] = input_helper[input_offset + 1];
3786  output[u + 11] = input_helper[input_offset + 2];
3787  }
3788 
3789  for (u = last_u; u < output_width3; u += 3)
3790  {
3791  register int input_offset = pXOffsets[u];
3792  output[u] = input_helper[input_offset];
3793  output[u + 1] = input_helper[input_offset + 1];
3794  output[u + 2] = input_helper[input_offset + 2];
3795  }
3796 
3797  output += output_width3;
3798  }
3799  }
3800  }
3801 
3802  delete [] pXOffsets;
3803  delete [] pYOffsets;
3804 
3805  if (pXCoordinates)
3806  {
3807  delete [] pXCoordinates;
3808  delete [] pYCoordinates;
3809  }
3810 
3811  return true;
3812 }
3813 
3814 
3815 bool ImageProcessor::Rotate(const CByteImage *pInputImage, CByteImage *pOutputImage, float mx, float my, float theta, bool bInterpolation)
3816 {
3817  const float cos_theta = cosf(theta);
3818  const float sin_theta = sinf(theta);
3819 
3820  return ApplyHomography(pInputImage, pOutputImage,
3821  cos_theta, -sin_theta, mx * (1 - cos_theta) + my * sin_theta,
3822  sin_theta, cos_theta, my * (1 - cos_theta) - mx * sin_theta,
3823  0, 0,
3824  bInterpolation);
3825 }
3826 
3827 bool ImageProcessor::Amplify(const CByteImage *pInputImage, CByteImage *pOutputImage, float fFactor)
3828 {
3829  OPTIMIZED_FUNCTION_HEADER_3(Amplify, pInputImage, pOutputImage, fFactor)
3830 
3831  if (!pInputImage->IsCompatible(pOutputImage))
3832  {
3833  printf("error: input and output image do not match for ImageProcessor::Amplify\n");
3834  return false;
3835  }
3836 
3837  const int nBytes = pInputImage->width * pInputImage->height * pInputImage->bytesPerPixel;
3838  const unsigned char *input = pInputImage->pixels;
3839  unsigned char *output = pOutputImage->pixels;
3840 
3841  for (int i = 0; i < nBytes; i++)
3842  {
3843  const int v = int(fFactor * input[i] + 0.5f);
3844  output[i] = v < 0 ? 0 : (v > 255 ? 255 : (unsigned char) v);
3845  }
3846 
3848 
3849  return true;
3850 }
3851 
3852 
3853 bool ImageProcessor::CalculateSaturationImage(const CByteImage *pInputImage, CByteImage *pOutputImage)
3854 {
3855  if (pInputImage->width != pOutputImage->width || pInputImage->height != pOutputImage->height ||
3856  (pInputImage->type != CByteImage::eRGB24 && pInputImage->type != CByteImage::eRGB24Split) || pOutputImage->type != CByteImage::eGrayScale)
3857  {
3858  printf("error: input and output image do not match for ImageProcessor::CalculateSaturationImage\n");
3859  return false;
3860  }
3861 
3862  const int nPixels = pInputImage->width * pInputImage->height;
3863  unsigned char *output = pOutputImage->pixels;
3864 
3865  if (pInputImage->type == CByteImage::eRGB24)
3866  {
3867  const unsigned char *input = pInputImage->pixels;
3868 
3869  for (int i = 0, offset = 0; i < nPixels; i++)
3870  {
3871  const int r = input[offset];
3872  const int g = input[offset + 1];
3873  const int b = input[offset + 2];
3874  const int min = MY_MIN(r, MY_MIN(g, b));
3875  const int max = MY_MAX(r, MY_MAX(g, b));
3876  output[i] = (255 * (max - min) * division_table[max]) >> 20;
3877  offset += 3;
3878  }
3879  }
3880  else
3881  {
3882  const unsigned char *input_r = pInputImage->pixels;
3883  const unsigned char *input_g = input_r + nPixels;
3884  const unsigned char *input_b = input_g + nPixels;
3885 
3886  for (int i = 0; i < nPixels; i++)
3887  {
3888  const int r = input_r[i];
3889  const int g = input_g[i];
3890  const int b = input_b[i];
3891  const int min = MY_MIN(r, MY_MIN(g, b));
3892  const int max = MY_MAX(r, MY_MAX(g, b));
3893  output[i] = (255 * (max - min) * division_table[max]) >> 20;
3894  }
3895  }
3896 
3897  return true;
3898 }
3899 
3900 
3901 bool ImageProcessor::ThresholdBinarize(const CByteImage *pInputImage, CByteImage *pOutputImage, unsigned char nThreshold)
3902 {
3903  OPTIMIZED_FUNCTION_HEADER_3(ThresholdBinarize, pInputImage, pOutputImage, nThreshold)
3904 
3905  if (pInputImage->width != pOutputImage->width || pInputImage->height != pOutputImage->height ||
3906  pInputImage->type != pOutputImage->type || pInputImage->type != CByteImage::eGrayScale)
3907  {
3908  printf("error: input and output image do not match for ImageProcessor::ThresholdBinarize\n");
3909  return false;
3910  }
3911 
3912  const int nPixels = pInputImage->width * pInputImage->height;
3913  const unsigned char *input = pInputImage->pixels;
3914  unsigned char *output = pOutputImage->pixels;
3915 
3916  for (int i = 0; i < nPixels; i++)
3917  output[i] = input[i] >= nThreshold ? 255 : 0;
3918 
3920 
3921  return true;
3922 }
3923 
3924 bool ImageProcessor::ThresholdBinarize(const CByteImage *pInputImage, CByteImage *pOutputImage, unsigned char nMinThreshold, unsigned char nMaxThreshold)
3925 {
3926  //OPTIMIZED_FUNCTION_HEADER_4(ThresholdBinarize, pInputImage, pOutputImage, nMinThreshold, nMaxThreshold)
3927 
3928  if (pInputImage->width != pOutputImage->width || pInputImage->height != pOutputImage->height ||
3929  pInputImage->type != pOutputImage->type || pInputImage->type != CByteImage::eGrayScale)
3930  {
3931  printf("error: input and output image do not match for ImageProcessor::ThresholdBinarize\n");
3932  return false;
3933  }
3934 
3935  const int nPixels = pInputImage->width * pInputImage->height;
3936  const unsigned char *input = pInputImage->pixels;
3937  unsigned char *output = pOutputImage->pixels;
3938 
3939  for (int i = 0; i < nPixels; i++)
3940  output[i] = input[i] >= nMinThreshold && input[i] <= nMaxThreshold ? 255 : 0;
3941 
3942  //OPTIMIZED_FUNCTION_FOOTER
3943 
3944  return true;
3945 }
3946 
3947 bool ImageProcessor::ThresholdBinarize(const CFloatMatrix *pInputMatrix, CFloatMatrix *pOutputMatrix, float fThreshold)
3948 {
3949  if (pInputMatrix->columns != pOutputMatrix->columns || pInputMatrix->rows != pOutputMatrix->rows)
3950  {
3951  printf("error: input and output matrix do not match for ImageProcessor::ThresholdBinarize\n");
3952  return false;
3953  }
3954 
3955  const int n = pInputMatrix->columns * pInputMatrix->rows;
3956  const float *input = pInputMatrix->data;
3957  float *output = pOutputMatrix->data;
3958 
3959  for (int i = 0; i < n; i++)
3960  output[i] = input[i] >= fThreshold ? 255.0f : 0;
3961 
3962  return true;
3963 }
3964 
3965 bool ImageProcessor::ThresholdBinarizeInverse(const CByteImage *pInputImage, CByteImage *pOutputImage, unsigned char nThreshold)
3966 {
3967  OPTIMIZED_FUNCTION_HEADER_3(ThresholdBinarizeInverse, pInputImage, pOutputImage, nThreshold)
3968 
3969  if (pInputImage->width != pOutputImage->width || pInputImage->height != pOutputImage->height ||
3970  pInputImage->type != pOutputImage->type || pInputImage->type != CByteImage::eGrayScale)
3971  {
3972  printf("error: input and output image do not match for ImageProcessor::ThresholdBinarizeInverse\n");
3973  return false;
3974  }
3975 
3976  unsigned char *input = pInputImage->pixels;
3977  unsigned char *output = pOutputImage->pixels;
3978  const int nPixels = pInputImage->width * pInputImage->height;
3979 
3980  for (int i = 0; i < nPixels; i++)
3981  output[i] = input[i] <= nThreshold ? 255 : 0;
3982 
3984 
3985  return true;
3986 }
3987 
3988 bool ImageProcessor::ThresholdFilter(const CByteImage *pInputImage, CByteImage *pOutputImage, unsigned char nThreshold)
3989 {
3990  OPTIMIZED_FUNCTION_HEADER_3(ThresholdFilter, pInputImage, pOutputImage, nThreshold)
3991 
3992  if (pInputImage->width != pOutputImage->width || pInputImage->height != pOutputImage->height ||
3993  pInputImage->type != pOutputImage->type || pInputImage->type != CByteImage::eGrayScale)
3994  {
3995  printf("error: input and output image do not match for ImageProcessor::ThresholdFilter\n");
3996  return false;
3997  }
3998 
3999  const int nPixels = pInputImage->width * pInputImage->height;
4000  const unsigned char *input = pInputImage->pixels;
4001  unsigned char *output = pOutputImage->pixels;
4002 
4003  for (int i = 0; i < nPixels; i++)
4004  output[i] = input[i] >= nThreshold ? input[i] : 0;
4005 
4007 
4008  return true;
4009 }
4010 
4011 bool ImageProcessor::ThresholdFilterInverse(const CByteImage *pInputImage, CByteImage *pOutputImage, unsigned char nThreshold)
4012 {
4013  OPTIMIZED_FUNCTION_HEADER_3(ThresholdFilterInverse, pInputImage, pOutputImage, nThreshold)
4014 
4015  if (pInputImage->width != pOutputImage->width || pInputImage->height != pOutputImage->height ||
4016  pInputImage->type != pOutputImage->type || pInputImage->type != CByteImage::eGrayScale)
4017  {
4018  printf("error: input and output image do not match for ImageProcessor::ThresholdFilterInverse\n");
4019  return false;
4020  }
4021 
4022  unsigned char *input = pInputImage->pixels;
4023  unsigned char *output = pOutputImage->pixels;
4024  const int nPixels = pInputImage->width * pInputImage->height;
4025 
4026  for (int i = 0; i < nPixels; i++)
4027  output[i] = input[i] <= nThreshold ? input[i] : 0;
4028 
4030 
4031  return true;
4032 }
4033 
4034 
4035 bool ImageProcessor::FilterRGB(const CByteImage *pInputImage, CByteImage *pOutputImage, CRGBColorModel *pColorModel, float fThreshold)
4036 {
4037  if (pInputImage->width != pOutputImage->width || pInputImage->height != pOutputImage->height ||
4038  pInputImage->type != CByteImage::eRGB24 || pOutputImage->type != CByteImage::eGrayScale)
4039  {
4040  printf("error: input and output image do not match for ImageProcessor::FilterRGB\n");
4041  return false;
4042  }
4043 
4044  const unsigned char *input = pInputImage->pixels;
4045  unsigned char *output = pOutputImage->pixels;
4046  const int nPixels = pInputImage->width * pInputImage->height;
4047  int offset = 0;
4048 
4049  for (int i = 0; i < nPixels; i++, offset += 3)
4050  {
4051  Vec3d rgb = { input[offset], input[offset + 1], input[offset + 2] };
4052  output[i] = pColorModel->CalculateColorProbability(rgb) > fThreshold ? 255 : 0;
4053  }
4054 
4055  return true;
4056 }
4057 
4058 bool ImageProcessor::FilterHSV(const CByteImage *pInputImage, CByteImage *pOutputImage, unsigned char hue, unsigned char tol_hue, unsigned char min_sat, unsigned char max_sat, unsigned char min_v, unsigned char max_v, const MyRegion *pROI)
4059 {
4060  if (pInputImage->width != pOutputImage->width || pInputImage->height != pOutputImage->height ||
4061  (pInputImage->type != CByteImage::eRGB24 && pInputImage->type != CByteImage::eRGB24Split) || pOutputImage->type != CByteImage::eGrayScale)
4062  {
4063  printf("error: input and output image do not match for ImageProcessor::FilterHSV\n");
4064  return false;
4065  }
4066 
4067  int min_hue = (int) hue - (int) tol_hue;
4068  int max_hue = (int) hue + (int) tol_hue;
4069 
4070  if (min_hue < 0)
4071  min_hue += 180;
4072 
4073  if (max_hue >= 180)
4074  max_hue -= 180;
4075 
4076  if(tol_hue > 89)
4077  {
4078  min_hue = 0;
4079  max_hue = 179;
4080  }
4081 
4082  return FilterHSV2(pInputImage, pOutputImage, (unsigned char) min_hue, (unsigned char) max_hue, min_sat, max_sat, min_v, max_v, pROI);
4083 }
4084 
4085 bool ImageProcessor::FilterHSV2(const CByteImage *pInputImage, CByteImage *pOutputImage, unsigned char min_hue, unsigned char max_hue, unsigned char min_sat, unsigned char max_sat, unsigned char min_v, unsigned char max_v, const MyRegion *pROI)
4086 {
4087  OPTIMIZED_FUNCTION_HEADER_8_ROI(FilterHSV2, pInputImage, pOutputImage, min_hue, max_hue, min_sat, max_sat, min_v, max_v, pROI)
4088 
4089  if (pInputImage->width != pOutputImage->width || pInputImage->height != pOutputImage->height ||
4090  (pInputImage->type != CByteImage::eRGB24 && pInputImage->type != CByteImage::eRGB24Split) || pOutputImage->type != CByteImage::eGrayScale)
4091  {
4092  printf("error: input and output image do not match for ImageProcessor::FilterHSV2\n");
4093  return false;
4094  }
4095 
4096  if (pInputImage->type == CByteImage::eRGB24)
4097  {
4098  const unsigned char *input_h = pInputImage->pixels;
4099  const unsigned char *input_s = pInputImage->pixels + 1;
4100  const unsigned char *input_v = pInputImage->pixels + 2;
4101  unsigned char *output = pOutputImage->pixels;
4102 
4103  if (pROI)
4104  {
4105  const int width = pInputImage->width;
4106  const int height = pInputImage->height;
4107 
4108  int min_x = pROI->min_x;
4109  int max_x = pROI->max_x;
4110  int min_y = pROI->min_y;
4111  int max_y = pROI->max_y;
4112 
4113  if (min_x < 0) min_x = 0;
4114  if (min_x > width - 1) min_x = width - 1;
4115  if (max_x < 0) max_x = 0;
4116  if (max_x > width - 1) max_x = width - 1;
4117  if (min_y < 0) min_y = 0;
4118  if (min_y > height - 1) min_y = height - 1;
4119  if (max_y < 0) max_y = 0;
4120  if (max_y > height - 1) max_y = height - 1;
4121 
4122  const int diff = width - (max_x - min_x + 1);
4123  const int diff_rgb = 3 * diff;
4124 
4125  if (max_hue >= min_hue)
4126  {
4127  for (int y = min_y, offset = min_y * width + min_x, offset_rgb = 3 * (min_y * width + min_x); y <= max_y; y++, offset += diff, offset_rgb += diff_rgb)
4128  for (int x = min_x; x <= max_x; x++, offset++, offset_rgb += 3)
4129  output[offset] = (input_s[offset_rgb] <= max_sat && input_s[offset_rgb] >= min_sat && input_h[offset_rgb] >= min_hue && input_h[offset_rgb] <= max_hue && input_v[offset_rgb] >= min_v && input_v[offset_rgb] <= max_v) * 255;
4130  }
4131  else
4132  {
4133  for (int y = min_y, offset = min_y * width + min_x, offset_rgb = 3 * (min_y * width + min_x); y <= max_y; y++, offset += diff, offset_rgb += diff_rgb)
4134  for (int x = min_x; x <= max_x; x++, offset++, offset_rgb += 3)
4135  output[offset] = (input_s[offset_rgb] <= max_sat && input_s[offset_rgb] >= min_sat && (input_h[offset_rgb] >= min_hue || input_h[offset_rgb] <= max_hue) && input_v[offset_rgb] >= min_v && input_v[offset_rgb] <= max_v) * 255;
4136  }
4137  }
4138  else
4139  {
4140  const int nPixels = pInputImage->width * pInputImage->height;
4141 
4142  if (max_hue >= min_hue)
4143  {
4144  for (int i = 0, offset = 0; i < nPixels; i++, offset += 3)
4145  output[i] = (input_s[offset] <= max_sat && input_s[offset] >= min_sat && input_h[offset] >= min_hue && input_h[offset] <= max_hue && input_v[offset] >= min_v && input_v[offset] <= max_v) * 255;
4146  }
4147  else
4148  {
4149  for (int i = 0, offset = 0; i < nPixels; i++, offset += 3)
4150  output[i] = (input_s[offset] <= max_sat && input_s[offset] >= min_sat && (input_h[offset] >= min_hue || input_h[offset] <= max_hue) && input_v[offset] >= min_v && input_v[offset] <= max_v) * 255;
4151  }
4152  }
4153  }
4154  else
4155  {
4156  const int width = pInputImage->width;
4157  const int height = pInputImage->height;
4158  const int nPixels = width * height;
4159 
4160  const unsigned char *input_h = pInputImage->pixels;
4161  const unsigned char *input_s = input_h + nPixels;
4162  const unsigned char *input_v = input_s + nPixels;
4163  unsigned char *output = pOutputImage->pixels;
4164 
4165  if (pROI)
4166  {
4167  int min_x = pROI->min_x;
4168  int max_x = pROI->max_x;
4169  int min_y = pROI->min_y;
4170  int max_y = pROI->max_y;
4171 
4172  if (min_x < 0) min_x = 0;
4173  if (min_x > width - 1) min_x = width - 1;
4174  if (max_x < 0) max_x = 0;
4175  if (max_x > width - 1) max_x = width - 1;
4176  if (min_y < 0) min_y = 0;
4177  if (min_y > height - 1) min_y = height - 1;
4178  if (max_y < 0) max_y = 0;
4179  if (max_y > height - 1) max_y = height - 1;
4180 
4181  const int diff = width - (max_x - min_x + 1);
4182 
4183  if (max_hue >= min_hue)
4184  {
4185  for (int y = min_y, offset = min_y * width + min_x; y <= max_y; y++, offset += diff)
4186  for (int x = min_x; x <= max_x; x++, offset++)
4187  output[offset] = (input_s[offset] <= max_sat && input_s[offset] >= min_sat && input_h[offset] >= min_hue && input_h[offset] <= max_hue && input_v[offset] >= min_v && input_v[offset] <= max_v) * 255;
4188  }
4189  else
4190  {
4191  for (int y = min_y, offset = min_y * width + min_x; y <= max_y; y++, offset += diff)
4192  for (int x = min_x; x <= max_x; x++, offset++)
4193  output[offset] = (input_s[offset] <= max_sat && input_s[offset] >= min_sat && (input_h[offset] >= min_hue || input_h[offset] <= max_hue) && input_v[offset] >= min_v && input_v[offset] <= max_v) * 255;
4194  }
4195  }
4196  else
4197  {
4198  if (max_hue >= min_hue)
4199  {
4200  for (int i = 0; i < nPixels; i++)
4201  output[i] = (input_s[i] <= max_sat && input_s[i] >= min_sat && input_h[i] >= min_hue && input_h[i] <= max_hue && input_v[i] >= min_v && input_v[i] <= max_v) * 255;
4202  }
4203  else
4204  {
4205  for (int i = 0; i < nPixels; i++)
4206  output[i] = (input_s[i] <= max_sat && input_s[i] >= min_sat && (input_h[i] >= min_hue || input_h[i] <= max_hue) && input_v[i] >= min_v && input_v[i] <= max_v) * 255;
4207  }
4208  }
4209  }
4210 
4212 
4213  return true;
4214 }
4215 
4216 
4217 
4218 bool ImageProcessor::FilterColor(const CByteImage *pInputImage, CByteImage *pOutputImage, ObjectColor cColor, CColorParameterSet* pColorParameterSet, bool bImageIsHSV)
4219 {
4220  const int* pParams = pColorParameterSet->GetColorParameters(cColor);
4221 
4222  bool bRet;
4223  if (bImageIsHSV)
4224  {
4225  bRet = FilterHSV(pInputImage, pOutputImage, pParams[0], pParams[1], pParams[2], pParams[3], pParams[4], pParams[5]);
4226  }
4227  else
4228  {
4229  CByteImage* pImage = new CByteImage(pInputImage);
4230  CalculateHSVImage(pInputImage, pImage);
4231  bRet = FilterHSV(pImage, pOutputImage, pParams[0], pParams[1], pParams[2], pParams[3], pParams[4], pParams[5]);
4232  delete pImage;
4233  }
4234  return bRet;
4235 }
4236 
4237 
4238 
4239 // Original version of this function by Olaf Fischer
4240 bool ImageProcessor::Rotate180Degrees(const CByteImage *pInputImage, CByteImage *pOutputImage)
4241 {
4242  if (pInputImage->width != pOutputImage->width || pInputImage->height != pOutputImage->height || pInputImage->type != pOutputImage->type || pInputImage->type == CByteImage::eRGB24Split)
4243  {
4244  printf("error: input and output image do not match for ImageProcessor::Rotate180Degrees\n");
4245  return false;
4246  }
4247 
4248  CByteImage *pSaveOutputImage = 0;
4249  if (pInputImage->pixels == pOutputImage->pixels)
4250  {
4251  pSaveOutputImage = pOutputImage;
4252  pOutputImage = new CByteImage(pInputImage);
4253  }
4254 
4255  const int nBytes = pInputImage->width * pInputImage->height * pInputImage->bytesPerPixel;
4256  const int nLastPixel = nBytes - pInputImage->bytesPerPixel;
4257  const unsigned char *input = pInputImage->pixels;
4258  unsigned char *output = pOutputImage->pixels;
4259 
4260  if (pInputImage->type == CByteImage::eGrayScale)
4261  {
4262  for (int i = 0; i < nBytes; i++)
4263  output[i] = input[nLastPixel - i];
4264  }
4265  else if (pInputImage->type == CByteImage::eRGB24)
4266  {
4267  for (int i = 0; i < nBytes; i += 3)
4268  {
4269  output[i + 2] = input[nLastPixel - i + 2];
4270  output[i + 1] = input[nLastPixel - i + 1];
4271  output[i] = input[nLastPixel - i];
4272  }
4273  }
4274 
4275  if (pSaveOutputImage)
4276  {
4277  CopyImage(pOutputImage, pSaveOutputImage);
4278  delete pOutputImage;
4279  }
4280 
4281  return true;
4282 }
4283 
4284 
4285 static int _RegionGrowing(unsigned char *pixels, int width, int offset, int *stack, int *region, MyRegion &resultRegion, int nMinimumPointsPerRegion, int nMaximumPointsPerRegion, bool bCalculateBoundingBox)
4286 {
4287  resultRegion.nSeedOffset = offset;
4288 
4289  int sp = 0, nPixels = 0;
4290 
4291  stack[sp++] = offset;
4292  pixels[offset] = 254;
4293 
4294  while (sp--)
4295  {
4296  const int offset = stack[sp];
4297 
4298  if (pixels[offset - width] == 255)
4299  {
4300  pixels[offset - width] = 254;
4301  stack[sp++] = offset - width;
4302  }
4303 
4304  if (pixels[offset - 1] == 255)
4305  {
4306  pixels[offset - 1] = 254;
4307  stack[sp++] = offset - 1;
4308  }
4309 
4310  if (pixels[offset + 1] == 255)
4311  {
4312  pixels[offset + 1] = 254;
4313  stack[sp++] = offset + 1;
4314  }
4315 
4316  if (pixels[offset + width] == 255)
4317  {
4318  pixels[offset + width] = 254;
4319  stack[sp++] = offset + width;
4320  }
4321 
4322  region[nPixels++] = offset;
4323  }
4324 
4325  if ((nMinimumPointsPerRegion > 0 && nPixels < nMinimumPointsPerRegion) || (nMaximumPointsPerRegion > 0 && nPixels > nMaximumPointsPerRegion))
4326  return 0;
4327 
4328  int cx = 0, cy = 0;
4329 
4330  if (bCalculateBoundingBox)
4331  {
4332  const int x = offset % width;
4333  const int y = offset / width;
4334  int min_x = x, max_x = x, min_y = y, max_y = y;
4335 
4336  for (int i = 0; i < nPixels; i++)
4337  {
4338  const int offset = region[i];
4339  const int x = offset % width;
4340  const int y = offset / width;
4341 
4342  cx += x;
4343  cy += y;
4344 
4345  if (x < min_x)
4346  min_x = x;
4347 
4348  if (x > max_x)
4349  max_x = x;
4350 
4351  if (y < min_y)
4352  min_y = y;
4353 
4354  if (y > max_y)
4355  max_y = y;
4356  }
4357 
4358  resultRegion.min_x = min_x;
4359  resultRegion.min_y = min_y;
4360  resultRegion.max_x = max_x;
4361  resultRegion.max_y = max_y;
4362  resultRegion.ratio = float(max_x - min_x + 1) / float(max_y - min_y + 1);
4363  }
4364  else
4365  {
4366  for (int i = 0; i < nPixels; i++)
4367  {
4368  const int offset = region[i];
4369 
4370  cx += offset % width;
4371  cy += offset / width;
4372  }
4373 
4374  resultRegion.min_x = -1;
4375  resultRegion.min_y = -1;
4376  resultRegion.max_x = -1;
4377  resultRegion.max_y = -1;
4378  resultRegion.ratio = 0.0f;
4379  }
4380 
4381  // fill rest of region struct
4382  resultRegion.nPixels = nPixels;
4383  resultRegion.centroid.x = float(cx) / nPixels;
4384  resultRegion.centroid.y = float(cy) / nPixels;
4385 
4386  return nPixels;
4387 }
4388 
4389 int ImageProcessor::RegionGrowing(const CByteImage *pImage, MyRegion &resultRegion, int x, int y, int nMinimumPointsPerRegion, int nMaximumPointsPerRegion, bool bCalculateBoundingBox, bool bStorePixels)
4390 {
4391  if (pImage->type != CByteImage::eGrayScale)
4392  {
4393  printf("error: input image should be grayscale for ImageProcessor::RegionGrowing\n");
4394  return -1;
4395  }
4396 
4397  const int width = pImage->width;
4398  const int height = pImage->height;
4399 
4400  if (x < 0 || x >= width || y < 0 || y >= height)
4401  {
4402  printf("error: x/y is not within bounds of image in ImageProcessor::RegionGrowing\n");
4403  return -1;
4404  }
4405 
4406  // create image with additional 1 pixel border
4407  CByteImage *pTempImage = new CByteImage(width + 2, height + 2, CByteImage::eGrayScale);
4408 
4409  const int temp_width = pTempImage->width;
4410  const int temp_height = pTempImage->height;
4411 
4412  unsigned char *temp = pTempImage->pixels;
4413 
4414  // copy contents
4415  unsigned char *temp_helper = temp + temp_width + 1;
4416 
4417  for (int i = 0; i < pImage->height; i++)
4418  memcpy(temp_helper + i * temp_width, pImage->pixels + i * width, width);
4419 
4420  // zero frame
4421  ImageProcessor::ZeroFrame(pTempImage);
4422 
4423  // allocate memory
4424  const int nPixels = temp_width * temp_height;
4425 
4426  int *pStack = new int[nPixels];
4427  int *pRegionPixels = new int[nPixels];
4428 
4429  // perform region growing
4430  const int nRegionPixels = _RegionGrowing(temp, temp_width, (y + 1) * temp_width + (x + 1), pStack, pRegionPixels, resultRegion, nMinimumPointsPerRegion, nMaximumPointsPerRegion, bCalculateBoundingBox);
4431 
4432  if (resultRegion.pPixels)
4433  {
4434  delete [] resultRegion.pPixels;
4435  resultRegion.pPixels = 0;
4436  }
4437 
4438  if (nRegionPixels > 0)
4439  {
4440  if (bStorePixels)
4441  {
4442  resultRegion.pPixels = new int[nRegionPixels];
4443 
4444  for (int j = 0; j < nRegionPixels; j++)
4445  {
4446  const int x = pRegionPixels[j] % temp_width;
4447  const int y = pRegionPixels[j] / temp_width;
4448 
4449  resultRegion.pPixels[j] = (y - 1) * width + x - 1;
4450  }
4451  }
4452 
4453  // correct coordinates
4454  resultRegion.centroid.x -= 1.0f;
4455  resultRegion.centroid.y -= 1.0f;
4456 
4457  resultRegion.min_x -= 1;
4458  resultRegion.min_y -= 1;
4459  resultRegion.max_x -= 1;
4460  resultRegion.max_y -= 1;
4461 
4462  resultRegion.nSeedOffset = (resultRegion.nSeedOffset / temp_width - 1) * width + (resultRegion.nSeedOffset % temp_width - 1);
4463  }
4464 
4465  // free memory
4466  delete pTempImage;
4467  delete [] pStack;
4468  delete [] pRegionPixels;
4469 
4470  return nRegionPixels;
4471 }
4472 
4473 bool ImageProcessor::FindRegions(const CByteImage *pImage, RegionList &regionList, int nMinimumPointsPerRegion, int nMaximumPointsPerRegion, bool bCalculateBoundingBox, bool bStorePixels)
4474 {
4475  // clear result list
4476  regionList.clear();
4477 
4478  if (pImage->type != CByteImage::eGrayScale)
4479  {
4480  printf("error: input image should be grayscale for ImageProcessor::FindRegions\n");
4481  return false;
4482  }
4483 
4484  const int width = pImage->width;
4485  const int height = pImage->height;
4486 
4487  // create image with additional 1 pixel border
4488  CByteImage *pTempImage = new CByteImage(width + 2, height + 2, CByteImage::eGrayScale);
4489 
4490  const int temp_width = pTempImage->width;
4491  const int temp_height = pTempImage->height;
4492 
4493  unsigned char *temp = pTempImage->pixels;
4494 
4495  // copy contents
4496  unsigned char *temp_helper = temp + temp_width + 1;
4497 
4498  for (int y = 0; y < pImage->height; y++)
4499  memcpy(temp_helper + y * temp_width, pImage->pixels + y * width, width);
4500 
4501  // zero frame
4502  ImageProcessor::ZeroFrame(pTempImage);
4503 
4504  // allocate memory
4505  const int nPixels = temp_width * temp_height;
4506 
4507  int *pStack = new int[nPixels];
4508  int *pRegionPixels = new int[nPixels];
4509 
4510  // go through image
4511  for (int i = 0; i < nPixels; i++)
4512  {
4513  if (temp[i] == 255)
4514  {
4515  MyRegion region;
4516 
4517  // do region growing
4518  const int nRegionPixels = _RegionGrowing(temp, temp_width, i, pStack, pRegionPixels, region, nMinimumPointsPerRegion, nMaximumPointsPerRegion, bCalculateBoundingBox);
4519 
4520  if (nRegionPixels > 0)
4521  {
4522  // first add
4523  regionList.push_back(region);
4524 
4525  // then copy (this way a double copy through copy constructor is avoided)
4526  // and correct coordinates
4527  MyRegion &addedEntry = regionList.back();
4528 
4529  // correct coordinates
4530  addedEntry.centroid.x -= 1.0f;
4531  addedEntry.centroid.y -= 1.0f;
4532 
4533  addedEntry.min_x -= 1;
4534  addedEntry.min_y -= 1;
4535  addedEntry.max_x -= 1;
4536  addedEntry.max_y -= 1;
4537 
4538  if (bStorePixels)
4539  {
4540  addedEntry.pPixels = new int[nRegionPixels];
4541 
4542  for (int j = 0; j < nRegionPixels; j++)
4543  {
4544  const int x = pRegionPixels[j] % temp_width;
4545  const int y = pRegionPixels[j] / temp_width;
4546 
4547  addedEntry.pPixels[j] = (y - 1) * width + x - 1;
4548  }
4549 
4550  addedEntry.nSeedOffset = (addedEntry.nSeedOffset / temp_width - 1) * width + (addedEntry.nSeedOffset % temp_width - 1);
4551  }
4552  }
4553  }
4554  }
4555 
4556  // free memory
4557  delete pTempImage;
4558  delete [] pStack;
4559  delete [] pRegionPixels;
4560 
4561  return true;
4562 }
4563 
4564 bool ImageProcessor::FindRegions(const CByteImage *pImage, CRegionArray &regionList, int nMinimumPointsPerRegion, int nMaximumPointsPerRegion, bool bCalculateBoundingBox, bool bStorePixels)
4565 {
4566  // clear result list
4567  regionList.Clear();
4568 
4569  if (pImage->type != CByteImage::eGrayScale)
4570  {
4571  printf("error: input image should be grayscale for ImageProcessor::FindRegions\n");
4572  return false;
4573  }
4574 
4575  const int width = pImage->width;
4576  const int height = pImage->height;
4577 
4578  // create image with additional 1 pixel border
4579  CByteImage *pTempImage = new CByteImage(width + 2, height + 2, CByteImage::eGrayScale);
4580 
4581  const int temp_width = pTempImage->width;
4582  const int temp_height = pTempImage->height;
4583 
4584  unsigned char *temp = pTempImage->pixels;
4585 
4586  // copy contents
4587  unsigned char *temp_helper = temp + temp_width + 1;
4588 
4589  for (int y = 0; y < pImage->height; y++)
4590  memcpy(temp_helper + y * temp_width, pImage->pixels + y * width, width);
4591 
4592  // zero frame
4593  ImageProcessor::ZeroFrame(pTempImage);
4594 
4595  // allocate memory
4596  const int nPixels = temp_width * temp_height;
4597 
4598  int *pStack = new int[nPixels];
4599  int *pRegionPixels = new int[nPixels];
4600 
4601  // go through image
4602  for (int i = 0; i < nPixels; i++)
4603  {
4604  if (temp[i] == 255)
4605  {
4606  MyRegion region;
4607 
4608  // do region growing
4609  const int nRegionPixels = _RegionGrowing(temp, temp_width, i, pStack, pRegionPixels, region, nMinimumPointsPerRegion, nMaximumPointsPerRegion, bCalculateBoundingBox);
4610 
4611  if (nRegionPixels > 0)
4612  {
4613  // first add
4614  regionList.AddElement(region);
4615 
4616  // then copy (this way a double copy through copy constructor is avoided)
4617  // and correct coordinates
4618  MyRegion &addedEntry = regionList[regionList.GetSize() - 1];
4619 
4620  // correct coordinates
4621  addedEntry.centroid.x -= 1.0f;
4622  addedEntry.centroid.y -= 1.0f;
4623 
4624  addedEntry.min_x -= 1;
4625  addedEntry.min_y -= 1;
4626  addedEntry.max_x -= 1;
4627  addedEntry.max_y -= 1;
4628 
4629  if (bStorePixels)
4630  {
4631  addedEntry.pPixels = new int[nRegionPixels];
4632 
4633  for (int j = 0; j < nRegionPixels; j++)
4634  {
4635  const int x = pRegionPixels[j] % temp_width;
4636  const int y = pRegionPixels[j] / temp_width;
4637 
4638  addedEntry.pPixels[j] = (y - 1) * width + x - 1;
4639  }
4640 
4641  addedEntry.nSeedOffset = (addedEntry.nSeedOffset / temp_width - 1) * width + (addedEntry.nSeedOffset % temp_width - 1);
4642  }
4643  }
4644  }
4645  }
4646 
4647  // free memory
4648  delete pTempImage;
4649  delete [] pStack;
4650  delete [] pRegionPixels;
4651 
4652  return true;
4653 }
4654 
4655 
4656 bool ImageProcessor::CalculateHSVImage(const CByteImage *pInputImage, CByteImage *pOutputImage, const MyRegion *pROI)
4657 {
4658  OPTIMIZED_FUNCTION_HEADER_2_ROI(CalculateHSVImage, pInputImage, pOutputImage, pROI)
4659 
4660  if (pInputImage->width != pOutputImage->width || pInputImage->height != pOutputImage->height ||
4661  pInputImage->type != pOutputImage->type || (pInputImage->type != CByteImage::eRGB24 && pInputImage->type != CByteImage::eRGB24Split))
4662  {
4663  printf("error: input and output image do not match for ImageProcessor::CalculateHSVImage\n");
4664  return false;
4665  }
4666 
4667  const unsigned char *input = pInputImage->pixels;
4668  unsigned char *output = pOutputImage->pixels;
4669 
4670  if (pROI)
4671  {
4672  if (pInputImage->type == CByteImage::eRGB24)
4673  {
4674  const int width = pInputImage->width;
4675  const int height = pInputImage->height;
4676 
4677  int min_x = pROI->min_x;
4678  int max_x = pROI->max_x;
4679  int min_y = pROI->min_y;
4680  int max_y = pROI->max_y;
4681 
4682  if (min_x < 0) min_x = 0;
4683  if (min_x > width - 1) min_x = width - 1;
4684  if (max_x < 0) max_x = 0;
4685  if (max_x > width - 1) max_x = width - 1;
4686  if (min_y < 0) min_y = 0;
4687  if (min_y > height - 1) min_y = height - 1;
4688  if (max_y < 0) max_y = 0;
4689  if (max_y > height - 1) max_y = height - 1;
4690 
4691  const int diff = 3 * (width - (max_x - min_x + 1));
4692 
4693  for (int y = min_y, offset = 3 * (min_y * width + min_x); y <= max_y; y++, offset += diff)
4694  {
4695  for (int x = min_x; x <= max_x; x++, offset += 3)
4696  {
4697  const int r = input[offset];
4698  const int g = input[offset + 1];
4699  const int b = input[offset + 2];
4700 
4701  const int max = MY_MAX(MY_MAX(r, g), b);
4702  const int min = MY_MIN(MY_MIN(r, g), b);
4703  const int delta = max - min;
4704 
4705  // unoptimized: delta * 255 / max;
4706  const int s = (255 * delta * division_table[max]) >> 20;
4707  int h;
4708 
4709  // unoptimized: 30 * (g - b) / delta (etc.)
4710  if (r == max)
4711  h = g > b ? 180 + ((30 * (g - b) * division_table[delta]) >> 20) : 180 - ((30 * (b - g) * division_table[delta]) >> 20);
4712  else if (g == max)
4713  h = b > r ? 60 + ((30 * (b - r) * division_table[delta]) >> 20) : 60 - ((30 * (r - b) * division_table[delta]) >> 20);
4714  else
4715  h = r > g ? 120 + ((30 * (r - g) * division_table[delta]) >> 20) : 120 - ((30 * (g - r) * division_table[delta]) >> 20);
4716 
4717  if (h >= 180) h -= 180;
4718 
4719  output[offset] = h;
4720  output[offset + 1] = s;
4721  output[offset + 2] = max;
4722  }
4723  }
4724  }
4725  else
4726  {
4727  const int width = pInputImage->width;
4728  const int height = pInputImage->height;
4729 
4730  const int nPixels = width * height;
4731 
4732  const unsigned char *input_r = input;
4733  const unsigned char *input_g = input_r + nPixels;
4734  const unsigned char *input_b = input_g + nPixels;
4735  unsigned char *output_r = output;
4736  unsigned char *output_g = output_r + nPixels;
4737  unsigned char *output_b = output_g + nPixels;
4738 
4739  int min_x = pROI->min_x;
4740  int max_x = pROI->max_x;
4741  int min_y = pROI->min_y;
4742  int max_y = pROI->max_y;
4743 
4744  if (min_x < 0) min_x = 0;
4745  if (min_x > width - 1) min_x = width - 1;
4746  if (max_x < 0) max_x = 0;
4747  if (max_x > width - 1) max_x = width - 1;
4748  if (min_y < 0) min_y = 0;
4749  if (min_y > height - 1) min_y = height - 1;
4750  if (max_y < 0) max_y = 0;
4751  if (max_y > height - 1) max_y = height - 1;
4752 
4753  const int diff = width - (max_x - min_x + 1);
4754 
4755  for (int y = min_y, offset = min_y * width + min_x; y <= max_y; y++, offset += diff)
4756  {
4757  for (int x = min_x; x <= max_x; x++, offset++)
4758  {
4759  const int r = input_r[offset];
4760  const int g = input_g[offset];
4761  const int b = input_b[offset];
4762 
4763  const int max = MY_MAX(MY_MAX(r, g), b);
4764  const int min = MY_MIN(MY_MIN(r, g), b);
4765  const int delta = max - min;
4766 
4767  // unoptimized: delta * 255 / max;
4768  const int s = (255 * delta * division_table[max]) >> 20;
4769  int h;
4770 
4771  // unoptimized: 30 * (g - b) / delta (etc.)
4772  if (r == max)
4773  h = g > b ? 180 + ((30 * (g - b) * division_table[delta]) >> 20) : 180 - ((30 * (b - g) * division_table[delta]) >> 20);
4774  else if (g == max)
4775  h = b > r ? 60 + ((30 * (b - r) * division_table[delta]) >> 20) : 60 - ((30 * (r - b) * division_table[delta]) >> 20);
4776  else
4777  h = r > g ? 120 + ((30 * (r - g) * division_table[delta]) >> 20) : 120 - ((30 * (g - r) * division_table[delta]) >> 20);
4778 
4779  if (h >= 180) h -= 180;
4780 
4781  output_r[offset] = h;
4782  output_g[offset] = s;
4783  output_b[offset] = max;
4784  }
4785  }
4786  }
4787  }
4788  else
4789  {
4790  if (pInputImage->type == CByteImage::eRGB24)
4791  {
4792  const int maxi = pInputImage->width * pInputImage->height * 3;
4793 
4794  for (int i = 0; i < maxi; i += 3)
4795  {
4796  const int r = input[i];
4797  const int g = input[i + 1];
4798  const int b = input[i + 2];
4799 
4800  const int max = MY_MAX(MY_MAX(r, g), b);
4801  const int min = MY_MIN(MY_MIN(r, g), b);
4802  const int delta = max - min;
4803 
4804  // unoptimized: delta * 255 / max;
4805  const int s = (255 * delta * division_table[max]) >> 20;
4806  int h;
4807 
4808  // unoptimized: 30 * (g - b) / delta (etc.)
4809  if (r == max)
4810  h = g > b ? 180 + ((30 * (g - b) * division_table[delta]) >> 20) : 180 - ((30 * (b - g) * division_table[delta]) >> 20);
4811  else if (g == max)
4812  h = b > r ? 60 + ((30 * (b - r) * division_table[delta]) >> 20) : 60 - ((30 * (r - b) * division_table[delta]) >> 20);
4813  else
4814  h = r > g ? 120 + ((30 * (r - g) * division_table[delta]) >> 20) : 120 - ((30 * (g - r) * division_table[delta]) >> 20);
4815 
4816  if (h >= 180) h -= 180;
4817 
4818  output[i] = h;
4819  output[i + 1] = s;
4820  output[i + 2] = max;
4821  }
4822  }
4823  else
4824  {
4825  const int nPixels = pInputImage->width * pInputImage->height;
4826 
4827  const unsigned char *input_r = input;
4828  const unsigned char *input_g = input_r + nPixels;
4829  const unsigned char *input_b = input_g + nPixels;
4830  unsigned char *output_r = output;
4831  unsigned char *output_g = output_r + nPixels;
4832  unsigned char *output_b = output_g + nPixels;
4833 
4834  for (int i = 0; i < nPixels; i++)
4835  {
4836  const int r = input_r[i];
4837  const int g = input_g[i];
4838  const int b = input_b[i];
4839 
4840  const int max = MY_MAX(MY_MAX(r, g), b);
4841  const int min = MY_MIN(MY_MIN(r, g), b);
4842  const int delta = max - min;
4843 
4844  // unoptimized: delta * 255 / max;
4845  const int s = (255 * delta * division_table[max]) >> 20;
4846  int h;
4847 
4848  // unoptimized: 30 * (g - b) / delta (etc.)
4849  if (r == max)
4850  h = g > b ? 180 + ((30 * (g - b) * division_table[delta]) >> 20) : 180 - ((30 * (b - g) * division_table[delta]) >> 20);
4851  else if (g == max)
4852  h = b > r ? 60 + ((30 * (b - r) * division_table[delta]) >> 20) : 60 - ((30 * (r - b) * division_table[delta]) >> 20);
4853  else
4854  h = r > g ? 120 + ((30 * (r - g) * division_table[delta]) >> 20) : 120 - ((30 * (g - r) * division_table[delta]) >> 20);
4855 
4856  if (h >= 180) h -= 180;
4857 
4858  output_r[i] = h;
4859  output_g[i] = s;
4860  output_b[i] = max;
4861  }
4862  }
4863  }
4864 
4866 
4867  return true;
4868 }
4869 
4870 
4871 bool ImageProcessor::HoughTransformLines(const CByteImage *pImage, CByteImage *pVisualizationImage, Vec2dList &resultLines, int nLinesToExtract, int nMinHits)
4872 {
4873  if (pImage->type == CByteImage::eGrayScale)
4874  {
4875  printf("error: input image must be of type CByteImage::eGrayScale\n");
4876  return false;
4877  }
4878 
4879  const int width = pImage->width;
4880  const int height = pImage->height;
4881  const unsigned char *pixels = pImage->pixels;
4882 
4883  const int m = 1 + 2 * (int(sqrtf(float(width * width + height * height))) + 1);
4884  const int m2 = m / 2;
4885  const float m2f = float(m2) + 0.5f;
4886  const int n = 180;
4887  const int nHoughPixels = n * m;
4888 
4889  CShortImage houghSpace(m, n);
4890 
4891  // reset bins
4892  ImageProcessor::Zero(&houghSpace);
4893  short *houghspace = houghSpace.pixels;
4894 
4895  // initialize lookup tables for sin and cos
4896  // function does initialization only for the first call
4897  InitSinCosTables();
4898 
4899  // perform hough transform
4900  for (int y = 0, offset = 0; y < height; y++)
4901  {
4902  for (int x = 0; x < width; x++, offset++)
4903  {
4904  if (pixels[offset])
4905  {
4906  for (int t = 0; t < n; t++)
4907  {
4908  const float r = x * cos_table[t] + y * sin_table[t];
4909  const int r_ = int(r + m2f);
4910 
4911  houghspace[t * m + r_]++;
4912  }
4913  }
4914  }
4915  }
4916 
4917  resultLines.clear();
4918 
4919  // find maxima
4920  for (int nn = 0; nn < nLinesToExtract; nn++)
4921  {
4922  int max = nMinHits - 1, best_i = -1;
4923 
4924  for (int i = 0; i < nHoughPixels; i++)
4925  {
4926  if (houghspace[i] > max)
4927  {
4928  max = houghspace[i];
4929  best_i = i;
4930  }
4931  }
4932 
4933  if (best_i != -1)
4934  {
4935  const int t = best_i / m;
4936  const int r = best_i % m;
4937 
4938  const int w = 10;
4939 
4940  for (int j = -w; j <= w; j++)
4941  {
4942  for (int k = -w; k <= w; k++)
4943  {
4944  const int r_ = r + j;
4945  int t_ = t + k;
4946 
4947  if (t_ >= n)
4948  t_ -= n;
4949 
4950  if (t_ < 0)
4951  t_ += n;
4952 
4953  if (r_ >= 0 && r_ < m)
4954  houghspace[t_ * m + r_] = 0;
4955  }
4956  }
4957 
4958  const float theta = t * FLOAT_DEG2RAD;
4959  const int r_value = r - m2;
4960 
4961  const Vec2d g = { theta, float(r_value) };
4962  resultLines.push_back(g);
4963 
4964  if (pVisualizationImage)
4965  {
4966  //printf("%i hits: (theta, r) = (%i, %i)\n", max, t, r_value);
4967  PrimitivesDrawer::DrawLinePolar(pVisualizationImage, theta, float(r_value), 255, 0, 0);
4968  }
4969  }
4970  else
4971  break;
4972  }
4973 
4974  return true;
4975 }
4976 
4977 bool ImageProcessor::HoughTransformCircles(const CByteImage *pImage, CByteImage *pVisualizationImage, Vec3dList &resultCircles, int rmin, int rmax, int nCirclesToExtract, int nMinHits)
4978 {
4979  if (rmin > rmax)
4980  {
4981  printf("error: rmin (%i) may not be greater than rmax (%i) for ImageProcessor::HoughTransformCircles\n", rmin, rmax);
4982  return false;
4983  }
4984 
4985  const int width = pImage->width;
4986  const int height = pImage->height;
4987  const unsigned char *pixels = pImage->pixels;
4988 
4989  const int n = width + 2 * rmax;
4990  const int m = height + 2 * rmax;
4991  const int nHoughPixels = n * m * (rmax - rmin + 1);
4992 
4993  short *houghspace = new short[nHoughPixels];
4994 
4995  // reset bins
4996  memset(houghspace, 0, nHoughPixels * sizeof(short));
4997 
4998  // initialize lookup tables for sin and cos
4999  // function does initialization only for the first call
5000  InitSinCosTables();
5001 
5002  const int mn = m * n;
5003  short *helper = houghspace - rmin * mn + rmax * m + rmax;
5004 
5005  // perform hough transform
5006  for (int v = 0, offset = 0; v < height; v++)
5007  {
5008  for (int u = 0; u < width; u++, offset++)
5009  {
5010  if (pixels[offset] == 255)
5011  {
5012  for (int t = 0; t < 180; t++)
5013  {
5014  for (int r = rmin; r <= rmax; r++)
5015  {
5016  const int um = int(u - r * cos_table[t] + 0.5f);
5017  const int vm1 = int(v - r * sin_table[t] + 0.5f);
5018  const int vm2 = int(v + r * sin_table[t] + 0.5f);
5019 
5020  //const int base = (r - rmin) * mn + (rmax + um) * m + rmax;
5021  //houghspace[base + vm1]++;
5022  //houghspace[base + vm2]++;
5023 
5024  const int base = r * mn + um * m;
5025  helper[base + vm1]++;
5026  helper[base + vm2]++;
5027  }
5028  }
5029  }
5030  }
5031  }
5032 
5033  resultCircles.clear();
5034 
5035  // find maxima
5036  for (int nn = 0; nn < nCirclesToExtract; nn++)
5037  {
5038  int max = nMinHits - 1, best_i = -1;
5039 
5040  for (int i = 0; i < nHoughPixels; i++)
5041  {
5042  if (houghspace[i] > max)
5043  {
5044  max = houghspace[i];
5045  best_i = i;
5046  }
5047  }
5048 
5049  if (best_i != -1)
5050  {
5051  int um = (best_i % mn) / m;
5052  int vm = (best_i % mn) % m;
5053  int r = best_i / mn;
5054 
5055  const int w = 5;
5056 
5057  for (int j = -w; j <= w; j++)
5058  {
5059  for (int k = -w; k <= w; k++)
5060  {
5061  for (int l = -w; l <= w; l++)
5062  {
5063  const int um_ = um + j;
5064  const int vm_ = vm + k;
5065  const int r_ = r + l;
5066 
5067  if (um_ >= 0 && um_ < n && vm >= 0 && vm < m && r_ >= 0 && r_ <= rmax - rmin)
5068  houghspace[r_ * mn + um_ * m + vm_] = 0;
5069  }
5070  }
5071  }
5072 
5073  um -= rmax;
5074  vm -= rmax;
5075  r += rmin;
5076 
5077  //printf("%i hits: (um vm) = (%i %i) -- r = = %i\n", max, um, vm, r);
5078 
5079  const Vec3d circle = { float(um), float(vm), float(r) };
5080  resultCircles.push_back(circle);
5081 
5082  if (pVisualizationImage)
5083  {
5084  Vec2d center = { float(um), float(vm) };
5085  PrimitivesDrawer::DrawCircle(pVisualizationImage, center, float(r), 255, 0, 0, 1);
5086  }
5087  }
5088  else
5089  break;
5090  }
5091 
5092  delete [] houghspace;
5093 
5094  return true;
5095 }
5096 
5097 void ImageProcessor::HoughTransformLines(const CVec2dArray &edgePoints, const CVec2dArray &edgeDirections, int width, int height, int nLinesToExtract, int nMinHits, CVec2dArray &resultLines, CIntArray &resultHits, CByteImage *pVisualizationImage)
5098 {
5099  // clear result list
5100  resultLines.Clear();
5101 
5102  // perform detection
5103  CStraightLine2dArray resultLines_;
5104 
5105  HoughTransformLines(edgePoints, edgeDirections, width, height, nLinesToExtract, nMinHits, resultLines_, resultHits, pVisualizationImage);
5106 
5107  // fill result list
5108  const int nResultLines = resultLines_.GetSize();
5109 
5110  for (int i = 0; i < nResultLines; i++)
5111  {
5112  const StraightLine2d &line = resultLines_[i];
5113 
5114  Vec2d x = { atan2f(line.normalVector.y, line.normalVector.x), -line.c };
5115 
5116  resultLines.AddElement(x);
5117  }
5118 }
5119 
5120 void ImageProcessor::HoughTransformLines(const CVec2dArray &edgePoints, const CVec2dArray &edgeDirections, int width, int height, int nLinesToExtract, int nMinHits, CStraightLine2dArray &resultLines, CIntArray &resultHits, CByteImage *pVisualizationImage)
5121 {
5122  // clear result list
5123  resultLines.Clear();
5124 
5125  const int m = 1 + 2 * (int(sqrtf(float(width * width + height * height))) + 1);
5126  const int m2 = m / 2;
5127  const float m2f = float(m2) + 0.5f;
5128  const int n = 360;
5129  const int nHoughPixels = n * m;
5130 
5131  CShortImage houghSpace(m, n);
5132 
5133  // reset bins
5134  ImageProcessor::Zero(&houghSpace);
5135  short *houghspace = houghSpace.pixels;
5136 
5137  // initialize lookup tables for sin and cos
5138  // function does initialization only for the first call
5139  InitSinCosTables();
5140 
5141  // perform hough transform
5142  const int nEdgePoints = edgePoints.GetSize();
5143  for (int i = 0; i < nEdgePoints; i++)
5144  {
5145  const Vec2d &point = edgePoints[i];
5146  const Vec2d &direction = edgeDirections[i];
5147 
5148  const float angle = atan2f(direction.y, direction.x) + FLOAT_PI;
5149  const int t0 = int(angle * FLOAT_RAD2DEG + 0.5f);
5150 
5151  const int t1 = t0 - 5;
5152  const int t2 = t0 + 5;
5153 
5154  for (int t = t1; t <= t2; t++)
5155  {
5156  const float r = point.x * cos_table[t] + point.y * sin_table[t];
5157  const int r_ = int(r + m2f);
5158 
5159  houghspace[((t + 360) % 360) * m + r_]++;
5160  }
5161  }
5162 
5163  resultLines.Clear();
5164  resultHits.Clear();
5165 
5166  // find maxima
5167  for (int nn = 0; nn < nLinesToExtract; nn++)
5168  {
5169  short max = nMinHits - 1;
5170  int best_i = -1;
5171 
5172  for (int i = 0; i < nHoughPixels; i++)
5173  {
5174  if (houghspace[i] > max)
5175  {
5176  max = houghspace[i];
5177  best_i = i;
5178  }
5179  }
5180 
5181  if (best_i != -1)
5182  {
5183  const int t = best_i / m;
5184  const int r = best_i % m;
5185 
5186  const int w = 10;
5187 
5188  for (int j = -w; j <= w; j++)
5189  {
5190  for (int k = -w; k <= w; k++)
5191  {
5192  const int r_ = r + j;
5193  int t_ = t + k;
5194 
5195  if (t_ >= n)
5196  t_ -= n;
5197 
5198  if (t_ < 0)
5199  t_ += n;
5200 
5201  if (r_ >= 0 && r_ < m)
5202  houghspace[t_ * m + r_] = 0;
5203  }
5204  }
5205 
5206  const float theta = t * FLOAT_DEG2RAD;
5207  const int r_value = r - m2;
5208 
5209  StraightLine2d line(theta, -float(r_value));
5210  resultLines.AddElement(line);
5211 
5212  if (pVisualizationImage)
5213  {
5214  //printf("%i hits: (theta, r) = (%i, %i)\n", max, t, r_value);
5215  PrimitivesDrawer::DrawLine(pVisualizationImage, line, 255, 0, 0);
5216  }
5217  }
5218  else
5219  break;
5220  }
5221 }
5222 
5223 bool ImageProcessor::HoughTransformCircles(const CVec2dArray &edgePoints, const CVec2dArray &edgeDirections, int width, int height, int rmin, int rmax, int nCirclesToExtract, int nMinHits, CVec3dArray &resultCircles, CIntArray &resultHits, CByteImage *pVisualizationImage)
5224 {
5225  // clear result list
5226  resultCircles.Clear();
5227 
5228  // perform detection
5229  CCircle2dArray resultCircles_;
5230 
5231  if (!HoughTransformCircles(edgePoints, edgeDirections, width, height, rmin, rmax, nCirclesToExtract, nMinHits, resultCircles_, resultHits, pVisualizationImage))
5232  return false;
5233 
5234  // fill result list
5235  const int nResultCircles = resultCircles_.GetSize();
5236 
5237  for (int i = 0; i < nResultCircles; i++)
5238  {
5239  const Circle2d &circle = resultCircles_[i];
5240 
5241  Vec3d x = { circle.center.x, circle.center.y, circle.radius };
5242 
5243  resultCircles.AddElement(x);
5244  }
5245 
5246  return true;
5247 }
5248 
5249 bool ImageProcessor::HoughTransformCircles(const CVec2dArray &edgePoints, const CVec2dArray &edgeDirections, int width, int height, int rmin, int rmax, int nCirclesToExtract, int nMinHits, CCircle2dArray &resultCircles, CIntArray &resultHits, CByteImage *pVisualizationImage)
5250 {
5251  // clear result list
5252  resultCircles.Clear();
5253 
5254  if (rmin > rmax)
5255  {
5256  printf("error: rmin (%i) may not be greater than rmax (%i) for ImageProcessor::HoughTransformCircles\n", rmin, rmax);
5257  return false;
5258  }
5259 
5260  const int n = width + 2 * rmax;
5261  const int m = height + 2 * rmax;
5262  const int nHoughPixels = n * m * (rmax - rmin + 1);
5263 
5264  short *houghspace = new short[nHoughPixels];
5265 
5266  // reset bins
5267  memset(houghspace, 0, nHoughPixels * sizeof(short));
5268 
5269  // initialize lookup tables for sin and cos
5270  // function does initialization only for the first call
5271  InitSinCosTables();
5272 
5273  const int mn = m * n;
5274  short *helper = houghspace - rmin * mn + rmax * m + rmax;
5275 
5276  // perform hough transform
5277  const int nEdgePoints = edgePoints.GetSize();
5278 
5279  for (int i = 0; i < nEdgePoints; i++)
5280  {
5281  const Vec2d &point = edgePoints[i];
5282  const Vec2d &direction = edgeDirections[i];
5283 
5284  const float u = point.x + 0.5f;
5285  const float v = point.y + 0.5f;
5286 
5287  const float angle = atan2f(direction.y, direction.x) + FLOAT_PI;
5288  const int t0 = int(angle * FLOAT_RAD2DEG + 0.5f);
5289 
5290  const int t1 = t0 - 3;
5291  const int t2 = t0 + 3;
5292 
5293  for (int t = t1; t <= t2; t++)
5294  {
5295  for (int r = rmin; r <= rmax; r++)
5296  {
5297  int um, vm;
5298 
5299  um = int(u + r * cos_table[t]);
5300  vm = int(v + r * sin_table[t]);
5301  helper[r * mn + um * m + vm]++;
5302 
5303  um = int(u - r * cos_table[t]);
5304  vm = int(v - r * sin_table[t]);
5305  helper[r * mn + um * m + vm]++;
5306 
5307  //const int offset = (r - rmin) * mn + (rmax + um) * m + rmax + vm;
5308  }
5309  }
5310  }
5311 
5312  resultCircles.Clear();
5313 
5314  // find maxima
5315  for (int nn = 0; nn < nCirclesToExtract; nn++)
5316  {
5317  int max = nMinHits - 1, best_i = -1;
5318 
5319  for (int i = 0; i < nHoughPixels; i++)
5320  {
5321  if (houghspace[i] > max)
5322  {
5323  max = houghspace[i];
5324  best_i = i;
5325  }
5326  }
5327 
5328  if (best_i != -1)
5329  {
5330  int um = (best_i % mn) / m;
5331  int vm = (best_i % mn) % m;
5332  int r = best_i / mn;
5333 
5334  const int w = 5;
5335 
5336  for (int j = -w; j <= w; j++)
5337  {
5338  for (int k = -w; k <= w; k++)
5339  {
5340  for (int l = -w; l <= w; l++)
5341  {
5342  int um_ = um + j;
5343  int vm_ = vm + k;
5344  int r_ = r + l;
5345 
5346  if (um_ >= 0 && um_ < n && vm >= 0 && vm < m && r_ >= 0 && r_ <= rmax - rmin)
5347  houghspace[r_ * mn + um_ * m + vm_] = 0;
5348  }
5349  }
5350  }
5351 
5352  um -= rmax;
5353  vm -= rmax;
5354  r += rmin;
5355 
5356  //printf("%i hits: (um vm) = (%i %i) -- r = = %i\n", max, um, vm, r);
5357 
5358  Circle2d circle;
5359  Math2d::SetVec(circle.center, float(um), float(vm));
5360  circle.radius = float(r);
5361 
5362  resultCircles.AddElement(circle);
5363  resultHits.AddElement(max);
5364 
5365  if (pVisualizationImage)
5366  PrimitivesDrawer::DrawCircle(pVisualizationImage, circle, 255, 0, 0, 1);
5367  }
5368  else
5369  break;
5370  }
5371 
5372  delete [] houghspace;
5373 
5374  return true;
5375 }
5376 
5377 
5378 
5379 bool ImageProcessor::DetermineHomography(const Vec2d *pSourcePoints, const Vec2d *pTargetPoints, int nPoints,
5380  float &a1, float &a2, float &a3, float &a4, float &a5, float &a6, float &a7, float &a8)
5381 {
5382  Mat3d A;
5383 
5384  if (!LinearAlgebra::DetermineHomography(pSourcePoints, pTargetPoints, nPoints, A, false))
5385  return false;
5386 
5387  a1 = A.r1;
5388  a2 = A.r2;
5389  a3 = A.r3;
5390  a4 = A.r4;
5391  a5 = A.r5;
5392  a6 = A.r6;
5393  a7 = A.r7;
5394  a8 = A.r8;
5395 
5396  return true;
5397 }
5398 
5399 bool ImageProcessor::DetermineAffineTransformation(const Vec2d *pSourcePoints, const Vec2d *pTargetPoints, int nPoints,
5400  float &a1, float &a2, float &a3, float &a4, float &a5, float &a6)
5401 {
5402  Mat3d A;
5403 
5404  if (!LinearAlgebra::DetermineAffineTransformation(pSourcePoints, pTargetPoints, nPoints, A, false))
5405  return false;
5406 
5407  a1 = A.r1;
5408  a2 = A.r2;
5409  a3 = A.r3;
5410  a4 = A.r4;
5411  a5 = A.r5;
5412  a6 = A.r6;
5413 
5414  return true;
5415 }
5416 
5417 
5418 bool ImageProcessor::NormalizeColor(const CByteImage *pInputImage, CByteImage *pOutputImage)
5419 {
5420  if (pInputImage->type == CByteImage::eGrayScale)
5421  {
5422  printf("error: input image must be of type CByteImage::eRGB24 or CByteImage::eRGB24Split for ImageProcessor::NormalizeColor\n");
5423  return false;
5424  }
5425 
5426  if (!pInputImage->IsCompatible(pOutputImage))
5427  {
5428  printf("error: input and output image must be of same size and type for ImageProcessor::NormalizeColor\n");
5429  return false;
5430  }
5431 
5432  const int nPixels = pInputImage->width * pInputImage->height;
5433  const unsigned char *input = pInputImage->pixels;
5434 
5435  int redHistogram[256], greenHistogram[256], blueHistogram[256];
5436  float fNormalizeConstant = 255.0f / nPixels;
5437  int i;
5438 
5439  // reset bins
5440  memset(redHistogram, 0, sizeof(redHistogram));
5441  memset(greenHistogram, 0, sizeof(greenHistogram));
5442  memset(blueHistogram, 0, sizeof(blueHistogram));
5443 
5444  // calculate histograms
5445  int offset = 0;
5446  for (i = 0; i < nPixels; i++)
5447  {
5448  redHistogram[input[offset]]++;
5449  greenHistogram[input[offset + 1]]++;
5450  blueHistogram[input[offset + 2]]++;
5451  offset += 3;
5452  }
5453 
5454  // normalize histograms
5455  for (i = 1; i < 256; i++)
5456  {
5457  redHistogram[i] += redHistogram[i - 1];
5458  greenHistogram[i] += greenHistogram[i - 1];
5459  blueHistogram[i] += blueHistogram[i - 1];
5460  }
5461 
5462  for (i = 0; i < 256; i++)
5463  {
5464  redHistogram[i] = int(redHistogram[i] * fNormalizeConstant + 0.5f);
5465  greenHistogram[i] = int(greenHistogram[i] * fNormalizeConstant + 0.5f);
5466  blueHistogram[i] = int(blueHistogram[i] * fNormalizeConstant + 0.5f);
5467  }
5468 
5469  // apply normalization
5470  if (pInputImage->type == CByteImage::eRGB24)
5471  {
5472  const unsigned char *input_r = input;
5473  const unsigned char *input_g = input_r + nPixels;
5474  const unsigned char *input_b = input_g + nPixels;
5475  unsigned char *output_r = pOutputImage->pixels;
5476  unsigned char *output_g = output_r + nPixels;
5477  unsigned char *output_b = output_g + nPixels;
5478 
5479  for (int i = 0; i < nPixels; i++)
5480  {
5481  output_r[i] = redHistogram[input_r[i]];
5482  output_g[i] = greenHistogram[input_g[i]];
5483  output_b[i] = blueHistogram[input_b[i]];
5484  }
5485  }
5486  else if (pInputImage->type == CByteImage::eRGB24Split)
5487  {
5488  unsigned char *output = pOutputImage->pixels;
5489 
5490  for (int i = 0, offset = 0; i < nPixels; i++, offset += 3)
5491  {
5492  output[offset] = redHistogram[input[offset]];
5493  output[offset + 1] = greenHistogram[input[offset + 1]];
5494  output[offset + 2] = blueHistogram[input[offset + 2]];
5495  }
5496  }
5497 
5498  return true;
5499 }
5500 
5501 
5502 bool ImageProcessor::GaussianSmooth5x5(const CFloatMatrix *pInputImage, CFloatMatrix *pOutputImage, float fVariance)
5503 {
5504  if (pInputImage->columns != pOutputImage->columns || pInputImage->rows != pOutputImage->rows)
5505  {
5506  printf("error: input and output matrix do not match for ImageProcessor::GaussianSmooth5x5\n");
5507  return false;
5508  }
5509 
5510  if (pInputImage->columns < 5 || pInputImage->rows < 5)
5511  {
5512  printf("error: matrices must be at least of size 5x5 for ImageProcessor::GaussianSmooth5x5\n");
5513  return false;
5514  }
5515 
5516  const int nKernelSize = 5;
5517  const int k = 2;//(nKernelSize - 1) / 2;
5518 
5519  float pFilter[nKernelSize];
5520  float sum = 0.0f;
5521  int i;
5522 
5523  // construct Gaussian kernel
5524  for (i = 0; i < nKernelSize; i++)
5525  {
5526  pFilter[i] = expf(-(i - k) * (i - k) / (2.0f * fVariance));
5527  sum += pFilter[i];
5528  }
5529 
5530  for (i = 0; i < nKernelSize; i++)
5531  pFilter[i] /= sum;
5532 
5533  // create temp image if necessary
5534  CFloatMatrix *pTempImage = new CFloatMatrix(pInputImage);
5535 
5536  const int width = pInputImage->columns;
5537  const int height = pInputImage->rows;
5538 
5539  const float *input = pInputImage->data;
5540  float *temp = pTempImage->data;
5541  float *output = pOutputImage->data;
5542 
5543  int x, y, d, offset;
5544 
5545 
5546  // x direction
5547  for (y = 0, offset = 0; y < height; y++)
5548  {
5549  for (x = 0; x < k; x++, offset++)
5550  {
5551  float sum = 0.0f;
5552 
5553  for (d = -k; d < -x; d++)
5554  sum += input[y * width] * pFilter[k + d];
5555 
5556  for (d = -x; d <= k; d++)
5557  sum += input[offset + d] * pFilter[k + d];
5558 
5559  temp[offset] = sum;
5560  }
5561 
5562  // core loop (optimized)
5563  for (x = 2 * k; x < width; x++, offset++)
5564  {
5565  temp[offset] =
5566  input[offset - 2] * pFilter[0] +
5567  input[offset - 1] * pFilter[1] +
5568  input[offset] * pFilter[2] +
5569  input[offset + 1] * pFilter[3] +
5570  input[offset + 2] * pFilter[4];
5571  }
5572 
5573  for (x = width - k; x < width; x++, offset++)
5574  {
5575  float sum = 0.0f;
5576 
5577  for (d = -k; d < width - x; d++)
5578  sum += input[offset + d] * pFilter[k + d];
5579 
5580  for (d = width - x; d <= k; d++)
5581  sum += input[y * width + width - 1] * pFilter[k + d];
5582 
5583  temp[offset] = sum;
5584  }
5585  }
5586 
5587 
5588  // y direction
5589  for (y = 0; y < k; y++)
5590  {
5591  for (x = 0; x < width; x++)
5592  {
5593  float sum = 0.0f;
5594 
5595  for (d = -k; d < -y; d++)
5596  sum += temp[x] * pFilter[k + d];
5597 
5598  for (d = -y; d <= k; d++)
5599  sum += temp[(y + d) * width + x] * pFilter[k + d];
5600 
5601  output[y * width + x] = sum;
5602  }
5603  }
5604 
5605  // core loop (optimized)
5606  for (y = 2 * k, offset = k * width; y < height; y++)
5607  {
5608  for (x = 0; x < width; x++, offset++)
5609  {
5610  output[offset] =
5611  temp[offset - (width << 1)] * pFilter[0] +
5612  temp[offset - width] * pFilter[1] +
5613  temp[offset] * pFilter[2] +
5614  temp[offset + width] * pFilter[3] +
5615  temp[offset + (width << 1)] * pFilter[4];
5616  }
5617  }
5618 
5619  for (y = height - k; y < height; y++)
5620  {
5621  for (x = 0; x < width; x++)
5622  {
5623  float sum = 0.0f;
5624 
5625  for (d = -k; d < height - y; d++)
5626  sum += temp[(y + d) * width + x] * pFilter[k + d];
5627 
5628  for (d = height - y; d < k; d++)
5629  sum += temp[(height - 1) * width + x] * pFilter[k + d];
5630 
5631  output[y * width + x] = sum;
5632  }
5633  }
5634 
5635 
5636  delete pTempImage;
5637 
5638  return true;
5639 }
5640 
5641 bool ImageProcessor::GaussianSmooth(const CByteImage *pInputImage, CByteImage *pOutputImage, float fVariance, int nKernelSize)
5642 {
5643  if (pInputImage->width != pOutputImage->width || pInputImage->height != pOutputImage->height || pInputImage->type != pOutputImage->type || pInputImage->type != CByteImage::eGrayScale)
5644  {
5645  printf("error: input and output image do not match for ImageProcessor::GaussianSmooth\n");
5646  return false;
5647  }
5648 
5649  if (pInputImage->width < nKernelSize || pInputImage->height < nKernelSize)
5650  {
5651  printf("error: image must be at least of size nKernelSize x nKernelSize for ImageProcessor::GaussianSmooth\n");
5652  return false;
5653  }
5654 
5655  const int k = (nKernelSize - 1) / 2;
5656 
5657  float *pFilter = new float[nKernelSize];
5658  float sum = 0.0f;
5659  int i;
5660 
5661  // construct Gaussian kernel
5662  for (i = 0; i < nKernelSize; i++)
5663  {
5664  pFilter[i] = expf(-(i - k) * (i - k) / (2.0f * fVariance));
5665  sum += pFilter[i];
5666  }
5667 
5668  for (i = 0; i < nKernelSize; i++)
5669  pFilter[i] /= sum;
5670 
5671  // create temp image
5672  CByteImage *pTempImage = new CByteImage(pInputImage);
5673 
5674  const int width = pInputImage->width;
5675  const int height = pInputImage->height;
5676 
5677  const unsigned char *input = pInputImage->pixels;
5678  unsigned char *temp = pTempImage->pixels;
5679  unsigned char *output = pOutputImage->pixels;
5680 
5681  int x, y, d, offset;
5682 
5683 
5684  // x direction
5685  for (y = 0, offset = 0; y < height; y++)
5686  {
5687  for (x = 0; x < k; x++, offset++)
5688  {
5689  float sum = 0.0f;
5690 
5691  for (d = -k; d < -x; d++)
5692  sum += input[y * width] * pFilter[k + d];
5693 
5694  for (d = -x; d <= k; d++)
5695  sum += input[offset + d] * pFilter[k + d];
5696 
5697  temp[offset] = (unsigned char) (sum + 0.5f);
5698  }
5699 
5700  // core loop
5701  for (x = 2 * k; x < width; x++, offset++)
5702  {
5703  float sum = 0.0f;
5704 
5705  for (d = -k; d <= k; d++)
5706  sum += input[offset + d] * pFilter[d + k];
5707 
5708  temp[offset] = (unsigned char) (sum + 0.5f);
5709  }
5710 
5711  for (x = width - k; x < width; x++, offset++)
5712  {
5713  float sum = 0.0f;
5714 
5715  for (d = -k; d < width - x; d++)
5716  sum += input[offset + d] * pFilter[k + d];
5717 
5718  for (d = width - x; d <= k; d++)
5719  sum += input[y * width + width - 1] * pFilter[k + d];
5720 
5721  temp[offset] = (unsigned char) (sum + 0.5f);
5722  }
5723  }
5724 
5725 
5726  // y direction
5727  for (y = 0; y < k; y++)
5728  {
5729  for (x = 0; x < width; x++)
5730  {
5731  float sum = 0.0f;
5732 
5733  for (d = -k; d < -y; d++)
5734  sum += temp[x] * pFilter[k + d];
5735 
5736  for (d = -y; d <= k; d++)
5737  sum += temp[(y + d) * width + x] * pFilter[k + d];
5738 
5739  output[y * width + x] = (unsigned char) (sum + 0.5f);
5740  }
5741  }
5742 
5743  // core loop
5744  for (y = 2 * k, offset = k * width; y < height; y++)
5745  {
5746  for (x = 0; x < width; x++, offset++)
5747  {
5748  float sum = 0.0f;
5749 
5750  for (d = -k; d <= k; d++)
5751  sum += temp[offset + d * width] * pFilter[d + k];
5752 
5753  output[offset] = (unsigned char) (sum + 0.5f);
5754  }
5755  }
5756 
5757  for (y = height - k; y < height; y++)
5758  {
5759  for (x = 0; x < width; x++)
5760  {
5761  float sum = 0.0f;
5762 
5763  for (d = -k; d < height - y; d++)
5764  sum += temp[(y + d) * width + x] * pFilter[k + d];
5765 
5766  for (d = height - y; d < k; d++)
5767  sum += temp[(height - 1) * width + x] * pFilter[k + d];
5768 
5769  output[y * width + x] = (unsigned char) (sum + 0.5f);
5770  }
5771  }
5772 
5773 
5774  delete pTempImage;
5775  delete [] pFilter;
5776 
5777  return true;
5778 }
5779 
5780 bool ImageProcessor::GaussianSmooth(const CByteImage *pInputImage, CFloatMatrix *pOutputImage, float fVariance, int nKernelSize)
5781 {
5782  if (pInputImage->width != pOutputImage->columns || pInputImage->height != pOutputImage->rows || pInputImage->type != CByteImage::eGrayScale)
5783  {
5784  printf("error: input image and output matrix do not match for ImageProcessor::GaussianSmooth\n");
5785  return false;
5786  }
5787 
5788  if (pInputImage->width < nKernelSize || pInputImage->height < nKernelSize)
5789  {
5790  printf("error: image must be at least of size nKernelSize x nKernelSize for ImageProcessor::GaussianSmooth\n");
5791  return false;
5792  }
5793 
5794  const int k = (nKernelSize - 1) / 2;
5795 
5796  float *pFilter = new float[nKernelSize];
5797  float sum = 0.0f;
5798  int i;
5799 
5800  // construct Gaussian kernel
5801  for (i = 0; i < nKernelSize; i++)
5802  {
5803  pFilter[i] = expf(-(i - k) * (i - k) / (2.0f * fVariance));
5804  sum += pFilter[i];
5805  }
5806 
5807  for (i = 0; i < nKernelSize; i++)
5808  pFilter[i] /= sum;
5809 
5810  // create temp image
5811  CFloatMatrix *pTempImage = new CFloatMatrix(pInputImage->width, pInputImage->height);
5812 
5813  const int width = pInputImage->width;
5814  const int height = pInputImage->height;
5815 
5816  const unsigned char *input = pInputImage->pixels;
5817  float *temp = pTempImage->data;
5818  float *output = pOutputImage->data;
5819 
5820  int x, y, d, offset;
5821 
5822 
5823  // x direction
5824  for (y = 0, offset = 0; y < height; y++)
5825  {
5826  for (x = 0; x < k; x++, offset++)
5827  {
5828  float sum = 0.0f;
5829 
5830  for (d = -k; d < -x; d++)
5831  sum += input[y * width] * pFilter[k + d];
5832 
5833  for (d = -x; d <= k; d++)
5834  sum += input[offset + d] * pFilter[k + d];
5835 
5836  temp[offset] = sum;
5837  }
5838 
5839  // core loop
5840  for (x = 2 * k; x < width; x++, offset++)
5841  {
5842  float sum = 0.0f;
5843 
5844  for (d = -k; d <= k; d++)
5845  sum += input[offset + d] * pFilter[d + k];
5846 
5847  temp[offset] = sum;
5848  }
5849 
5850  for (x = width - k; x < width; x++, offset++)
5851  {
5852  float sum = 0.0f;
5853 
5854  for (d = -k; d < width - x; d++)
5855  sum += input[offset + d] * pFilter[k + d];
5856 
5857  for (d = width - x; d <= k; d++)
5858  sum += input[y * width + width - 1] * pFilter[k + d];
5859 
5860  temp[offset] = sum;
5861  }
5862  }
5863 
5864 
5865  // y direction
5866  for (y = 0; y < k; y++)
5867  {
5868  for (x = 0; x < width; x++)
5869  {
5870  float sum = 0.0f;
5871 
5872  for (d = -k; d < -y; d++)
5873  sum += temp[x] * pFilter[k + d];
5874 
5875  for (d = -y; d <= k; d++)
5876  sum += temp[(y + d) * width + x] * pFilter[k + d];
5877 
5878  output[y * width + x] = sum;
5879  }
5880  }
5881 
5882  // core loop
5883  for (y = 2 * k, offset = k * width; y < height; y++)
5884  {
5885  for (x = 0; x < width; x++, offset++)
5886  {
5887  float sum = 0.0f;
5888 
5889  for (d = -k; d <= k; d++)
5890  sum += temp[offset + d * width] * pFilter[d + k];
5891 
5892  output[offset] = sum;
5893  }
5894  }
5895 
5896  for (y = height - k; y < height; y++)
5897  {
5898  for (x = 0; x < width; x++)
5899  {
5900  float sum = 0.0f;
5901 
5902  for (d = -k; d < height - y; d++)
5903  sum += temp[(y + d) * width + x] * pFilter[k + d];
5904 
5905  for (d = height - y; d < k; d++)
5906  sum += temp[(height - 1) * width + x] * pFilter[k + d];
5907 
5908  output[y * width + x] = sum;
5909  }
5910  }
5911 
5912 
5913  delete pTempImage;
5914  delete [] pFilter;
5915 
5916  return true;
5917 }
5918 
5919 bool ImageProcessor::GaussianSmooth(const CFloatMatrix *pInputImage, CFloatMatrix *pOutputImage, float fVariance, int nKernelSize)
5920 {
5921  if (pInputImage->columns != pOutputImage->columns || pInputImage->rows != pOutputImage->rows)
5922  {
5923  printf("error: input and output matrix do not match for ImageProcessor::GaussianSmooth\n");
5924  return false;
5925  }
5926 
5927  if (pInputImage->columns < nKernelSize || pInputImage->rows < nKernelSize)
5928  {
5929  printf("error: matrix must be at least of size nKernelSize x nKernelSize for ImageProcessor::GaussianSmooth\n");
5930  return false;
5931  }
5932 
5933  const int k = (nKernelSize - 1) / 2;
5934 
5935  float *pFilter = new float[nKernelSize];
5936  float sum = 0.0f;
5937  int i;
5938 
5939  // construct Gaussian kernel
5940  for (i = 0; i < nKernelSize; i++)
5941  {
5942  pFilter[i] = expf(-(i - k) * (i - k) / (2.0f * fVariance));
5943  sum += pFilter[i];
5944  }
5945 
5946  for (i = 0; i < nKernelSize; i++)
5947  pFilter[i] /= sum;
5948 
5949  // create temp image
5950  CFloatMatrix *pTempImage = new CFloatMatrix(pInputImage);
5951 
5952  const int width = pInputImage->columns;
5953  const int height = pInputImage->rows;
5954 
5955  const float *input = pInputImage->data;
5956  float *temp = pTempImage->data;
5957  float *output = pOutputImage->data;
5958 
5959  int x, y, d, offset;
5960 
5961 
5962  // x direction
5963  for (y = 0, offset = 0; y < height; y++)
5964  {
5965  for (x = 0; x < k; x++, offset++)
5966  {
5967  float sum = 0.0f;
5968 
5969  for (d = -k; d < -x; d++)
5970  sum += input[y * width] * pFilter[k + d];
5971 
5972  for (d = -x; d <= k; d++)
5973  sum += input[offset + d] * pFilter[k + d];
5974 
5975  temp[offset] = sum;
5976  }
5977 
5978  // core loop
5979  for (x = 2 * k; x < width; x++, offset++)
5980  {
5981  float sum = 0.0f;
5982 
5983  for (d = -k; d <= k; d++)
5984  sum += input[offset + d] * pFilter[d + k];
5985 
5986  temp[offset] = sum;
5987  }
5988 
5989  for (x = width - k; x < width; x++, offset++)
5990  {
5991  float sum = 0.0f;
5992 
5993  for (d = -k; d < width - x; d++)
5994  sum += input[offset + d] * pFilter[k + d];
5995 
5996  for (d = width - x; d <= k; d++)
5997  sum += input[y * width + width - 1] * pFilter[k + d];
5998 
5999  temp[offset] = sum;
6000  }
6001  }
6002 
6003 
6004  // y direction
6005  for (y = 0; y < k; y++)
6006  {
6007  for (x = 0; x < width; x++)
6008  {
6009  float sum = 0.0f;
6010 
6011  for (d = -k; d < -y; d++)
6012  sum += temp[x] * pFilter[k + d];
6013 
6014  for (d = -y; d <= k; d++)
6015  sum += temp[(y + d) * width + x] * pFilter[k + d];
6016 
6017  output[y * width + x] = sum;
6018  }
6019  }
6020 
6021  // core loop
6022  for (y = 2 * k, offset = k * width; y < height; y++)
6023  {
6024  for (x = 0; x < width; x++, offset++)
6025  {
6026  float sum = 0.0f;
6027 
6028  for (d = -k; d <= k; d++)
6029  sum += temp[offset + d * width] * pFilter[d + k];
6030 
6031  output[offset] = sum;
6032  }
6033  }
6034 
6035  for (y = height - k; y < height; y++)
6036  {
6037  for (x = 0; x < width; x++)
6038  {
6039  float sum = 0.0f;
6040 
6041  for (d = -k; d < height - y; d++)
6042  sum += temp[(y + d) * width + x] * pFilter[k + d];
6043 
6044  for (d = height - y; d < k; d++)
6045  sum += temp[(height - 1) * width + x] * pFilter[k + d];
6046 
6047  output[y * width + x] = sum;
6048  }
6049  }
6050 
6051 
6052  delete pTempImage;
6053  delete [] pFilter;
6054 
6055  return true;
6056 }
6057 
6058 bool ImageProcessor::HighPassX3(const CFloatMatrix *pInputImage, CFloatMatrix *pOutputImage)
6059 {
6060  if (pInputImage->columns != pOutputImage->columns || pInputImage->rows != pOutputImage->rows)
6061  {
6062  printf("error: input and output image do not match for ImageProcessor::HighPassX3\n");
6063  return false;
6064  }
6065 
6066  CFloatMatrix *pSaveOutputImage = 0;
6067  if (pInputImage->data == pOutputImage->data)
6068  {
6069  pSaveOutputImage = pOutputImage;
6070  pOutputImage = new CFloatMatrix(pInputImage);
6071  }
6072 
6073  const float *input = pInputImage->data;
6074  float *output = pOutputImage->data;
6075 
6076  const int width = pInputImage->columns;
6077  const int height = pInputImage->rows;
6078 
6079  for (int y = 0, offset = 0; y < height; y++, offset += width)
6080  {
6081  output[offset] = input[offset + 1] - input[offset];
6082 
6083  const int max = offset + width - 1;
6084 
6085 
6086  for (int x = offset + 1; x < max; x++)
6087  output[x] = (input[x + 1] - input[x - 1]) * 0.5f;
6088 
6089  output[offset + width - 1] = input[offset + width - 1] - input[offset + width - 2];
6090  }
6091 
6092  if (pSaveOutputImage)
6093  {
6094  CopyMatrix(pOutputImage, pSaveOutputImage);
6095  delete pOutputImage;
6096  }
6097 
6098  return true;
6099 }
6100 
6101 bool ImageProcessor::HighPassY3(const CFloatMatrix *pInputImage, CFloatMatrix *pOutputImage)
6102 {
6103  if (pInputImage->columns != pOutputImage->columns || pInputImage->rows != pOutputImage->rows)
6104  {
6105  printf("error: input and output image do not match for ImageProcessor::HighPassY3\n");
6106  return false;
6107  }
6108 
6109  CFloatMatrix *pSaveOutputImage = 0;
6110  if (pInputImage->data == pOutputImage->data)
6111  {
6112  pSaveOutputImage = pOutputImage;
6113  pOutputImage = new CFloatMatrix(pInputImage);
6114  }
6115 
6116  const float *input = pInputImage->data;
6117  float *output = pOutputImage->data;
6118 
6119  const int width = pInputImage->columns;
6120  const int height = pInputImage->rows;
6121 
6122  int x;
6123 
6124  for (x = 0; x < width; x++)
6125  output[x] = input[x + width] - input[x];
6126 
6127  for (int y = 2, offset = width; y < height; y++)
6128  for (x = 0; x < width; x++, offset++)
6129  output[offset] = (input[offset + width] - input[offset - width]) * 0.5f;
6130 
6131  for (x = (height - 1) * width; x < width; x++)
6132  output[x] = input[x] - input[x - width];
6133 
6134  if (pSaveOutputImage)
6135  {
6136  CopyMatrix(pOutputImage, pSaveOutputImage);
6137  delete pOutputImage;
6138  }
6139 
6140  return true;
6141 }
6142 
6143 bool ImageProcessor::FlipY(const CByteImage *pInputImage, CByteImage *pOutputImage)
6144 {
6145  if (pInputImage->width != pOutputImage->width || pInputImage->height != pOutputImage->height ||
6146  pInputImage->type != pOutputImage->type)
6147  {
6148  printf("error: input and output image do not match for ImageProcessor::FlipY\n");
6149  return false;
6150  }
6151 
6152  const int width = pInputImage->width;
6153  const int height = pInputImage->height;
6154  const int nPixels = width * height;
6155 
6156  unsigned char *input = pInputImage->pixels;
6157 
6158  if (pInputImage->pixels == pOutputImage->pixels)
6159  {
6160  const int h = height / 2;
6161 
6162  if (pInputImage->type == CByteImage::eGrayScale)
6163  {
6164  unsigned char *temp = new unsigned char[width];
6165  unsigned char *output = pOutputImage->pixels + nPixels - width;
6166 
6167  for (int y = 0; y < h; y++)
6168  {
6169  memcpy(temp, output, width);
6170  memcpy(output, input, width);
6171  memcpy(input, temp, width);
6172 
6173  input += width;
6174  output -= width;
6175  }
6176 
6177  delete [] temp;
6178  }
6179  else if (pInputImage->type == CByteImage::eRGB24)
6180  {
6181  const int nWidthBytes = 3 * width;
6182 
6183  unsigned char *temp = new unsigned char[nWidthBytes];
6184  unsigned char *output = pOutputImage->pixels + 3 * nPixels - nWidthBytes;
6185 
6186  for (int y = 0; y < h; y++)
6187  {
6188  memcpy(temp, output, nWidthBytes);
6189  memcpy(output, input, nWidthBytes);
6190  memcpy(input, temp, nWidthBytes);
6191 
6192  input += nWidthBytes;
6193  output -= nWidthBytes;
6194  }
6195 
6196  delete [] temp;
6197  }
6198  }
6199  else
6200  {
6201  if (pInputImage->type == CByteImage::eGrayScale)
6202  {
6203  unsigned char *output = pOutputImage->pixels + nPixels - width;
6204 
6205  for (int y = 0; y < height; y++)
6206  {
6207  memcpy(output, input, width);
6208 
6209  input += width;
6210  output -= width;
6211  }
6212  }
6213  else if (pInputImage->type == CByteImage::eRGB24)
6214  {
6215  const int nWidthBytes = 3 * width;
6216  unsigned char *output = pOutputImage->pixels + 3 * nPixels - nWidthBytes;
6217 
6218  for (int y = 0; y < height; y++)
6219  {
6220  memcpy(output, input, nWidthBytes);
6221 
6222  input += nWidthBytes;
6223  output -= nWidthBytes;
6224  }
6225  }
6226  }
6227 
6228  return true;
6229 }
6230 
6231 bool ImageProcessor::CalculateIntegralImage(const CByteImage *pInputImage, CIntImage *pIntegralImage)
6232 {
6233  if (pInputImage->width != pIntegralImage->width || pInputImage->height != pIntegralImage->height || pInputImage->type != CByteImage::eGrayScale)
6234  {
6235  printf("error: input and output image do not match for ImageProcessor::CalculateIntegralImage\n");
6236  return false;
6237  }
6238 
6239  const int width = pInputImage->width;
6240  const int height = pInputImage->height;
6241 
6242  const unsigned char *input = pInputImage->pixels;
6243  int *output = pIntegralImage->pixels;
6244 
6245  // top left pixel
6246  *output = *input++;
6247  output++;
6248 
6249  // top row
6250  for (int x = 1; x < width; x++)
6251  {
6252  *output = *input++ + *(output - 1);
6253  output++;
6254  }
6255 
6256  // the other rows
6257  for (int y = 1; y < height; y++)
6258  {
6259  // first entry in a row
6260  *output = *input++ + *(output - width);
6261  output++;
6262 
6263  // rest of the row
6264  for (int x = 1; x < width; x++)
6265  {
6266  *output = *input++ + *(output - 1) + *(output - width) - *(output - width - 1);
6267  output++;
6268  }
6269  }
6270 
6271  return true;
6272 }
6273 
6274 bool ImageProcessor::CalculateSummedAreaTable(const CByteImage *pInputImage, CIntImage *pSummedAreaTable)
6275 {
6276  if (pInputImage->width != pSummedAreaTable->width || pInputImage->height != pSummedAreaTable->height || pInputImage->type != CByteImage::eGrayScale)
6277  {
6278  printf("error: input and output image do not match for ImageProcessor::CalculateSummedAreaTable\n");
6279  return false;
6280  }
6281 
6282  return CalculateIntegralImage(pInputImage, pSummedAreaTable);
6283 }
6284 
6285 // counts every pixel != 0 as 1
6287 {
6288  if (pInputImage->width != pSummedAreaTable->width || pInputImage->height != pSummedAreaTable->height || pInputImage->type != CByteImage::eGrayScale)
6289  {
6290  printf("error: input and output image do not match for ImageProcessor::CalculateBinarizedSummedAreaTable\n");
6291  return false;
6292  }
6293 
6294  const int width = pInputImage->width;
6295  const int height = pInputImage->height;
6296 
6297  unsigned char *input = pInputImage->pixels;
6298  int *output = pSummedAreaTable->pixels;
6299 
6300  // top left pixel
6301  int c = *input++;
6302  c = (c != 0 ? 1 : 0);
6303 
6304  *output++ = c;
6305 
6306  // top row
6307  for (int x = 1; x < width; x++)
6308  {
6309  c = *input++;
6310  c = (c != 0 ? 1 : 0);
6311 
6312  *output = c + *(output-1);
6313  output++;
6314  }
6315 
6316  // the other rows
6317  for (int y = 1; y < height; y++)
6318  {
6319  // first entry in a row
6320  c = *input++;
6321  c = (c != 0 ? 1 : 0);
6322 
6323  *output = c + *(output - width);
6324  output++;
6325 
6326  // rest of the row
6327  for (int x = 1; x < width; x++)
6328  {
6329  c = *input++;
6330  c = (c != 0 ? 1 : 0);
6331 
6332  *output = c + *(output-1) + *(output - width) - *(output - width - 1);
6333  output++;
6334  }
6335  }
6336 
6337  return true;
6338 }
6339 
6340 bool ImageProcessor::CalculateReverseSummedAreaTable(const CIntImage *pSummedAreaTable, CByteImage *pOutputImage)
6341 {
6342  if (pOutputImage->width != pSummedAreaTable->width || pOutputImage->height != pSummedAreaTable->height || pOutputImage->type != CByteImage::eGrayScale)
6343  {
6344  printf("error: input and output image do not match for ImageProcessor::CalculateReverseSummedAreaTable\n");
6345  return false;
6346  }
6347 
6348  const int width = pSummedAreaTable->width;
6349  const int height = pSummedAreaTable->height;
6350 
6351  int *input = pSummedAreaTable->pixels;
6352  unsigned char *output = pOutputImage->pixels;
6353 
6354  // top left pixel
6355  int c = *input++;
6356  *output++ = c;
6357 
6358  // top row
6359  for (int x = 1; x < width; x++)
6360  {
6361  c = *input++;
6362  *output++ = c - *(input - 2);
6363  }
6364 
6365  // the other rows
6366  for (int y = 1; y < height; y++)
6367  {
6368  // first entry in a row
6369  c = *input++;
6370  *output++ = c - *(input - width - 1);
6371 
6372  // rest of the row
6373  for (int x = 1; x < width; x++)
6374  {
6375  c = *input++;
6376  *output++ = c - *(input - 2) - *(input - width - 1) + *(input - width - 2);
6377  }
6378  }
6379 
6380  return true;
6381 }
6382 
6383 int ImageProcessor::GetAreaSum(const CIntImage *pIntegralImage, int min_x, int min_y, int max_x, int max_y)
6384 {
6385  const int width = pIntegralImage->width;
6386  const int height = pIntegralImage->height;
6387 
6388  // to include the min_x column and the min_y row
6389  min_x--;
6390  min_y--;
6391 
6392  if (min_x >= width) min_x = width - 1;
6393  if (max_x < 0) max_x = 0;
6394  if (max_x >= width) max_x = width - 1;
6395  if (min_y >= height) min_y = height - 1;
6396  if (max_y < 0) max_y = 0;
6397  if (max_y >= height) max_y = height - 1;
6398 
6399  const int *pixels = pIntegralImage->pixels;
6400  const int c1 = min_x < 0 || min_y < 0 ? 0 : pixels[min_y * width + min_x];
6401  const int c2 = min_y < 0 ? 0 : pixels[min_y * width + max_x];
6402  const int c3 = min_x < 0 ? 0 : pixels[max_y * width + min_x];
6403  const int c4 = pixels[max_y * width + max_x];
6404 
6405  return c4 - c3 - c2 + c1;
6406 }
6407 
6408 inline int ImageProcessor::GetAreaSumNoChecks(const CIntImage *pIntegralImage, int min_x, int min_y, int max_x, int max_y)
6409 {
6410  // to include the min_x column and the min_y row
6411  min_x--;
6412  min_y--;
6413 
6414  const int width = pIntegralImage->width;
6415  const int *pixels = pIntegralImage->pixels;
6416 
6417  return pixels[max_y * width + max_x] - pixels[max_y * width + min_x] - pixels[min_y * width + max_x] + pixels[min_y * width + min_x];
6418 }
6419 
6420 int ImageProcessor::GetAreaSum(const CIntImage *pIntegralImage, const MyRegion *region)
6421 {
6422  return GetAreaSum(pIntegralImage, region->min_x, region->min_y, region->max_x, region->max_y);
6423 }
6424 
6425 
6426 static void track(unsigned char *magnitudes, int *stack, int offset, int width)
6427 {
6428  int sp = 0;
6429 
6430  stack[sp++] = offset;
6431 
6432  while (sp--)
6433  {
6434  const int offset = stack[sp];
6435 
6436  if (magnitudes[offset - width - 1] == 1)
6437  {
6438  stack[sp++] = offset - width - 1;
6439  magnitudes[offset - width - 1] = 255;
6440  }
6441 
6442  if (magnitudes[offset + width + 1] == 1)
6443  {
6444  stack[sp++] = offset + width + 1;
6445  magnitudes[offset + width + 1] = 255;
6446  }
6447 
6448  if (magnitudes[offset - width + 1] == 1)
6449  {
6450  stack[sp++] = offset - width + 1;
6451  magnitudes[offset - width + 1] = 255;
6452  }
6453 
6454  if (magnitudes[offset + width - 1] == 1)
6455  {
6456  stack[sp++] = offset + width - 1;
6457  magnitudes[offset + width - 1] = 255;
6458  }
6459 
6460  if (magnitudes[offset - width] == 1)
6461  {
6462  stack[sp++] = offset - width;
6463  magnitudes[offset - width] = 255;
6464  }
6465 
6466  if (magnitudes[offset + width] == 1)
6467  {
6468  stack[sp++] = offset + width;
6469  magnitudes[offset + width] = 255;
6470  }
6471 
6472  if (magnitudes[offset - 1] == 1)
6473  {
6474  stack[sp++] = offset - 1;
6475  magnitudes[offset - 1] = 255;
6476  }
6477 
6478  if (magnitudes[offset + 1] == 1)
6479  {
6480  stack[sp++] = offset + 1;
6481  magnitudes[offset + 1] = 255;
6482  }
6483  }
6484 }
6485 
6486 bool ImageProcessor::Canny(const CByteImage *pInputImage, CByteImage *pOutputImage, int nLowThreshold, int nHighThreshold)
6487 {
6488  OPTIMIZED_FUNCTION_HEADER_4(Canny, pInputImage, pOutputImage, nLowThreshold, nHighThreshold)
6489 
6490  if (pInputImage->width != pOutputImage->width || pInputImage->height != pOutputImage->height ||
6491  pInputImage->type != pOutputImage->type || pInputImage->type != CByteImage::eGrayScale)
6492  {
6493  printf("error: input and output image do not match for ImageProcessor::Canny\n");
6494  return false;
6495  }
6496 
6497  if (nLowThreshold == 0) nLowThreshold = 1;
6498  if (nHighThreshold == 0) nHighThreshold = 1;
6499 
6500  const int width = pInputImage->width;
6501  const int height = pInputImage->height;
6502  const int nPixels = width * height;
6503 
6504  CShortImage gradientsX(width, height), gradientsY(width, height);
6505  SobelX(pInputImage, &gradientsX, false);
6506  SobelY(pInputImage, &gradientsY, false);
6507 
6508  Zero(pOutputImage);
6509 
6510  unsigned char *output = pOutputImage->pixels;
6511  short *magnitudes = gradientsX.pixels; // alias for the gradientX image
6512 
6513  int i;
6514 
6515  // calculate gradients and sectors
6516  for (i = 0; i < nPixels; i++)
6517  {
6518  const int gx = gradientsX.pixels[i];
6519  const int gy = gradientsY.pixels[i];
6520  const int agx = abs(gx);
6521  const int agy = abs(gy);
6522  const int g = agx + agy;
6523  //const int g = short(sqrtf(float(gx * gx + gy * gy)));
6524 
6525  magnitudes[i] = g;
6526 
6527  if (g >= nLowThreshold)
6528  {
6529  if (agx > (agy << 1))
6530  {
6531  output[i] = 10;
6532  }
6533  else if ((agx << 1) > agy)
6534  {
6535  output[i] = gx * gy >= 0 ? 12 : 13;
6536  }
6537  else
6538  {
6539  output[i] = 11;
6540  }
6541  }
6542  }
6543 
6544  // apply non maximal supression
6545  for (i = 0; i < nPixels; i++)
6546  {
6547  const int g = (int) magnitudes[i];
6548 
6549  if (g >= nLowThreshold)
6550  {
6551  switch (output[i])
6552  {
6553  case 10:
6554  if (magnitudes[i + 1] <= g && magnitudes[i - 1] < g)
6555  output[i] = g >= nHighThreshold ? 254 : 1;
6556  break;
6557 
6558  case 11:
6559  if (magnitudes[i + width] <= g && magnitudes[i - width] < g)
6560  output[i] = g >= nHighThreshold ? 254 : 1;
6561  break;
6562 
6563  case 12:
6564  if (magnitudes[i + width + 1] <= g && magnitudes[i - width - 1] < g)
6565  output[i] = g >= nHighThreshold ? 254 : 1;
6566  break;
6567 
6568  case 13:
6569  if (magnitudes[i + width - 1] <= g && magnitudes[i - width + 1] < g)
6570  output[i] = g >= nHighThreshold ? 254 : 1;
6571  break;
6572  }
6573  }
6574  }
6575 
6576  // track
6577  int *stack = new int[nPixels];
6578 
6579  for (i = 0; i < nPixels; i++)
6580  if (output[i] == 254)
6581  {
6582  track(output, stack, i, width);
6583  output[i] = 255;
6584  }
6585 
6586  for (i = 0; i < nPixels; i++)
6587  {
6588  if (output[i] != 255)
6589  output[i] = 0;
6590  }
6591 
6592  delete [] stack;
6593 
6595 
6596  return true;
6597 }
6598 
6599 
6600 static inline void CalculateSubpixel(const unsigned char *input, int width, int sector, Vec2d &point, Vec2d &direction)
6601 {
6602  int a, b, c, n;
6603 
6604  if (sector == 0)
6605  {
6606  a = *input - *(input - 2);
6607  b = *(input + 1) - *(input - 1);
6608  c = *(input + 2) - *input;
6609  n = a - 2 * b + c;
6610 
6611  if (n != 0)
6612  {
6613  const float x = 0.5f * (a - c) / n;
6614 
6615  if (fabsf(x) < 1.0f)
6616  point.x += x;
6617  }
6618  }
6619  else if (sector == 1)
6620  {
6621  a = *input - *(input - (width << 1));
6622  b = *(input + width) - *(input - width);
6623  c = *(input + (width << 1)) - *input;
6624  n = a - 2 * b + c;
6625 
6626  if (n != 0)
6627  {
6628  const float y = 0.5f * (a - c) / n;
6629 
6630  if (fabsf(y) < 1.0f)
6631  point.y += y;
6632  }
6633  }
6634  else if (sector == 2)
6635  {
6636  a = *input - *(input - (width << 1) - 2);
6637  b = *(input + width + 1) - *(input - width - 1);
6638  c = *(input + (width << 1) + 2) - *input;
6639  n = a - 2 * b + c;
6640 
6641  if (n != 0)
6642  {
6643  const float xy = 0.35355339059327378637f * (a - c) / n;
6644 
6645  if (fabsf(xy) < 1.0f)
6646  {
6647  point.y += xy;
6648  point.x += xy;
6649  }
6650  }
6651  }
6652  else if (sector == 3)
6653  {
6654  a = *input - *(input - (width << 1) + 2);
6655  b = *(input + width - 1) - *(input - width + 1);
6656  c = *(input + (width << 1) - 2) - *input;
6657  n = a - 2 * b + c;
6658 
6659  if (n != 0)
6660  {
6661  const float xy = 0.35355339059327378637f * (a - c) / n;
6662 
6663  if (fabsf(xy) < 1.0f)
6664  {
6665  point.y += xy;
6666  point.x -= xy;
6667  }
6668  }
6669  }
6670 
6671  Math2d::SetVec(direction,
6672  (float) ((input[1] << 1) + input[1 - width] + input[1 + width] - (input[-1] << 1) - input[-1 - width] - input[-1 + width]),
6673  (float) ((input[width] << 1) + input[width - 1] + input[width + 1] - (input[-width] << 1) - input[-width - 1] - input[-width + 1]));
6674  Math2d::NormalizeVec(direction);
6675 }
6676 
6677 bool ImageProcessor::Canny(const CByteImage *pInputImage, CVec2dArray &resultPoints, CVec2dArray &resultDirections, int nLowThreshold, int nHighThreshold)
6678 {
6679  OPTIMIZED_FUNCTION_HEADER_5(CannyList, pInputImage, resultPoints, resultDirections, nLowThreshold, nHighThreshold)
6680 
6681  if (pInputImage->type != CByteImage::eGrayScale)
6682  {
6683  printf("error: input image must be of type eGrayScale for ImageProcessor::Canny (list)\n");
6684  return false;
6685  }
6686 
6687  if (nLowThreshold == 0) nLowThreshold = 1;
6688  if (nHighThreshold == 0) nHighThreshold = 1;
6689 
6690  const int width = pInputImage->width;
6691  const int height = pInputImage->height;
6692  const int nPixels = width * height;
6693 
6694  CShortImage gradientsX(width, height), gradientsY(width, height);
6695  SobelX(pInputImage, &gradientsX, false);
6696  SobelY(pInputImage, &gradientsY, false);
6697 
6698  CByteImage tempImage(width, height, CByteImage::eGrayScale);
6699  CByteImage sectorImage(width, height, CByteImage::eGrayScale);
6700  Zero(&tempImage);
6701  Zero(&sectorImage);
6702 
6703  unsigned char *temp = tempImage.pixels;
6704  unsigned char *sectors = sectorImage.pixels;
6705  short *magnitudes = gradientsX.pixels; // alias for the gradientX image
6706 
6707  int i;
6708 
6709  // calculate gradients and sectors
6710  for (i = 0; i < nPixels; i++)
6711  {
6712  const int gx = gradientsX.pixels[i];
6713  const int gy = gradientsY.pixels[i];
6714  const int agx = abs(gx);
6715  const int agy = abs(gy);
6716  const int g = agx + agy;
6717  //const int g = short(sqrtf(float(gx * gx + gy * gy)));
6718 
6719  magnitudes[i] = g;
6720 
6721  if (g >= nLowThreshold)
6722  {
6723  if (agx > (agy << 1))
6724  {
6725  sectors[i] = 0;
6726  }
6727  else if ((agx << 1) > agy)
6728  {
6729  sectors[i] = gx * gy >= 0 ? 2 : 3;
6730  }
6731  else
6732  {
6733  sectors[i] = 1;
6734  }
6735  }
6736  }
6737 
6738  // apply non maximal supression
6739  for (i = 0; i < nPixels; i++)
6740  {
6741  const int g = (int) magnitudes[i];
6742 
6743  if (g >= nLowThreshold)
6744  {
6745  switch (sectors[i])
6746  {
6747  case 0:
6748  if (magnitudes[i + 1] <= g && magnitudes[i - 1] < g)
6749  temp[i] = g >= nHighThreshold ? 254 : 1;
6750  break;
6751 
6752  case 1:
6753  if (magnitudes[i + width] <= g && magnitudes[i - width] < g)
6754  temp[i] = g >= nHighThreshold ? 254 : 1;
6755  break;
6756 
6757  case 2:
6758  if (magnitudes[i + width + 1] <= g && magnitudes[i - width - 1] < g)
6759  temp[i] = g >= nHighThreshold ? 254 : 1;
6760  break;
6761 
6762  case 3:
6763  if (magnitudes[i + width - 1] <= g && magnitudes[i - width + 1] < g)
6764  temp[i] = g >= nHighThreshold ? 254 : 1;
6765  break;
6766  }
6767  }
6768  }
6769 
6770  // track
6771  int *stack = new int[nPixels];
6772 
6773  for (i = 0; i < nPixels; i++)
6774  if (temp[i] == 254)
6775  {
6776  track(temp, stack, i, width);
6777  temp[i] = 255;
6778  }
6779 
6780  resultPoints.Clear();
6781  resultDirections.Clear();
6782 
6783  int offset;
6784  for (i = height - 4, offset = 2 * width + 2; i; i--, offset += 4)
6785  for (int j = width - 4; j; j--, offset++)
6786  if (temp[offset] == 255)
6787  {
6788  Vec2d point;
6789  Math2d::SetVec(point, (float) (offset % width), (float) (offset / width));
6790 
6791  Vec2d direction;
6792  CalculateSubpixel(pInputImage->pixels + offset, width, sectors[offset], point, direction);
6793 
6794  resultPoints.AddElement(point);
6795  resultDirections.AddElement(direction);
6796  }
6797 
6798  delete [] stack;
6799 
6801 
6802  return true;
6803 }
6804 
6805 
6806 
6807 #define HARRIS_WINDOW_SIZE 3 // don't change this define
6808 
6809 bool ImageProcessor::CalculateHarrisMap(const CByteImage *pInputImage, CIntImage *pOutputImage)
6810 {
6811  if (pInputImage->type != CByteImage::eGrayScale || pInputImage->width != pOutputImage->width || pInputImage->height != pOutputImage->height)
6812  {
6813  printf("error: input image and output matrix do not match for ImageProcessor::CalculateHarrisMap\n");
6814  return false;
6815  }
6816 
6817  const int width = pInputImage->width;
6818  const int height = pInputImage->height;
6819  const int nPixels = width * height;
6820 
6821  const unsigned char *input = pInputImage->pixels;
6822 
6823  int i, j, offset;
6824 
6825  int *cov = new int[3 * nPixels];
6826 
6827  // calculate gradients
6828  const int stop = nPixels - width - 1;
6829  for (offset = width + 1; offset < stop; offset++)
6830  {
6831  const int p = int(input[offset + 1]) - int(input[offset - 1]);
6832  const int q = int(input[offset + width]) - int(input[offset - width]);
6833  const int offset_ = 3 * offset;
6834 
6835  cov[offset_ ] = p * p;
6836  cov[offset_ + 1] = q * q;
6837  cov[offset_ + 2] = p * q;
6838  }
6839 
6840  // zero R image
6841  Zero(pOutputImage);
6842 
6843  // calculate harris response function
6844  const int diff = HARRIS_WINDOW_SIZE + 1;
6845  const int width3 = 3 * width;
6846  int *R = pOutputImage->pixels + (HARRIS_WINDOW_SIZE / 2) * (width + 1);
6847 
6848  // do not use one-pixel-thick border of cov (gradients are not valid there)
6849  for (i = diff, offset = width + 1; i < height; i++, offset += diff)
6850  {
6851  for (j = diff; j < width; j++, offset++)
6852  {
6853  int ppsum = 0;
6854  int qqsum = 0;
6855  int pqsum = 0;
6856 
6857  for (int k = 0, offset2 = 3 * offset; k < HARRIS_WINDOW_SIZE; k++, offset2 += width3)
6858  {
6859  ppsum += cov[offset2];
6860  qqsum += cov[offset2 + 1];
6861  pqsum += cov[offset2 + 2];
6862  ppsum += cov[offset2 + 3];
6863  qqsum += cov[offset2 + 4];
6864  pqsum += cov[offset2 + 5];
6865  ppsum += cov[offset2 + 6];
6866  qqsum += cov[offset2 + 7];
6867  pqsum += cov[offset2 + 8];
6868  }
6869 
6870  // NOTE:
6871  // while abs() should not be necessary for most targets (the squared result fits into 32bit),
6872  // some targets (known: ti 64x) produce faulty code here.
6873  pqsum = abs(pqsum);
6874 
6875  ppsum >>= 4;
6876  qqsum >>= 4;
6877  pqsum >>= 4;
6878 
6879  //R[offset] = (ppsum * qqsum - pqsum * pqsum) - 0.04f * ((ppsum + qqsum) * (ppsum + qqsum));
6880  // approximation: 0.04f = 1 / 25. instead: 1 / 16
6881  R[offset] = (ppsum * qqsum - pqsum * pqsum) - (((ppsum + qqsum) >> 2) * ((ppsum + qqsum) >> 2));
6882  }
6883  }
6884 
6885  delete [] cov;
6886 
6887  return true;
6888 }
6889 
6890 
6891 static void QuicksortInverse(int *pOffsets, const int *pValues, int nLow, int nHigh)
6892 {
6893  int i = nLow;
6894  int j = nHigh;
6895 
6896  const int x = pValues[pOffsets[(nLow + nHigh) >> 1]];
6897 
6898  while (i <= j)
6899  {
6900  while (pValues[pOffsets[i]] > x) i++;
6901  while (pValues[pOffsets[j]] < x) j--;
6902 
6903  if (i <= j)
6904  {
6905  const int temp = pOffsets[i];
6906  pOffsets[i] = pOffsets[j];
6907  pOffsets[j] = temp;
6908 
6909  i++;
6910  j--;
6911  }
6912  }
6913 
6914  if (nLow < j) QuicksortInverse(pOffsets, pValues, nLow, j);
6915  if (i < nHigh) QuicksortInverse(pOffsets, pValues, i, nHigh);
6916 }
6917 
6918 int ImageProcessor::CalculateHarrisInterestPoints(const CByteImage *pInputImage, Vec2d *pInterestPoints, int nMaxPoints, float fQualityLevel, float fMinDistance)
6919 {
6920  OPTIMIZED_FUNCTION_HEADER_5_RET(CalculateHarrisInterestPoints, pInputImage, pInterestPoints, nMaxPoints, fQualityLevel, fMinDistance)
6921 
6922  if (pInputImage->type != CByteImage::eGrayScale)
6923  {
6924  printf("error: input image should be grayscale ImageProcessor::CalculateHarrisInterestPoints\n");
6925  return -1;
6926  }
6927 
6928  const int width = pInputImage->width;
6929  const int height = pInputImage->height;
6930  const int nPixels = width * height;
6931 
6932  // calculate harris map
6933  CIntImage R(pInputImage->width, pInputImage->height);
6934  CalculateHarrisMap(pInputImage, &R);
6935 
6936  int *data = R.pixels;
6937  int i;
6938 
6939  // determine maximum value
6940  int max = 0;
6941  for (i = 0; i < nPixels; ++i)
6942  {
6943  if (data[i] > max)
6944  max = data[i];
6945  }
6946 
6947  int *pCandidateOffsets = new int[nPixels];
6948  int nCandidates = 0;
6949 
6950  // only accept good pixels
6951  max = int(max * fQualityLevel + 0.5f);
6952  for (i = 0; i < nPixels; i++)
6953  {
6954  if (data[i] >= max)
6955  pCandidateOffsets[nCandidates++] = i;
6956  }
6957 
6958  // sort by quality
6959  QuicksortInverse(pCandidateOffsets, data, 0, nCandidates - 1);
6960 
6961  // enforce distance constraint
6962  const int nMinDistance = int(fMinDistance + 0.5f);
6963  CByteImage image(width, height, CByteImage::eGrayScale);
6964  Zero(&image);
6965  int nInterestPoints = 0;
6966  for (i = 0; i < nCandidates && nInterestPoints < nMaxPoints; i++)
6967  {
6968  const int offset = pCandidateOffsets[i];
6969 
6970  const int x = offset % width;
6971  const int y = offset / width;
6972 
6973  bool bTake = true;
6974 
6975  const int minx = x - nMinDistance < 0 ? 0 : x - nMinDistance;
6976  const int miny = y - nMinDistance < 0 ? 0 : y - nMinDistance;
6977  const int maxx = x + nMinDistance >= width ? width - 1 : x + nMinDistance;
6978  const int maxy = y + nMinDistance >= height ? height - 1 : y + nMinDistance;
6979  const int diff = width - (maxx - minx + 1);
6980 
6981  for (int l = miny, offset2 = miny * width + minx; l <= maxy; l++, offset2 += diff)
6982  for (int k = minx; k <= maxx; k++, offset2++)
6983  if (image.pixels[l * width + k])
6984  {
6985  bTake = false;
6986  break;
6987  }
6988 
6989  if (bTake)
6990  {
6991  // store point
6992  pInterestPoints[nInterestPoints].x = float(x);
6993  pInterestPoints[nInterestPoints].y = float(y);
6994  nInterestPoints++;
6995 
6996  // mark location in grid for distance constraint check
6997  image.pixels[offset] = 1;
6998  }
6999  }
7000 
7001  delete [] pCandidateOffsets;
7002 
7003  return nInterestPoints;
7004 }
7005 
7006 
7007 bool ImageProcessor::And(const CByteImage *pInputImage1, const CByteImage *pInputImage2, CByteImage *pOutputImage)
7008 {
7009  OPTIMIZED_FUNCTION_HEADER_3(And, pInputImage1, pInputImage2, pOutputImage)
7010 
7011  if (!pInputImage1->IsCompatible(pInputImage2) || !pInputImage1->IsCompatible(pOutputImage))
7012  {
7013  printf("error: input images and output image do not match for ImageProcessor::And\n");
7014  return false;
7015  }
7016 
7017  const int nBytes = pInputImage1->width * pInputImage1->height * pInputImage1->bytesPerPixel;
7018 
7019  const unsigned char *input1 = pInputImage1->pixels;
7020  const unsigned char *input2 = pInputImage2->pixels;
7021  unsigned char *output = pOutputImage->pixels;
7022  for (int i = 0; i < nBytes; i++)
7023  output[i] = input1[i] & input2[i];
7024 
7026 
7027  return true;
7028 }
7029 
7030 bool ImageProcessor::Xor(const CByteImage *pInputImage1, const CByteImage *pInputImage2, CByteImage *pOutputImage)
7031 {
7032  OPTIMIZED_FUNCTION_HEADER_3(Xor, pInputImage1, pInputImage2, pOutputImage)
7033 
7034  if (!pInputImage1->IsCompatible(pInputImage2) || !pInputImage1->IsCompatible(pOutputImage))
7035  {
7036  printf("error: input images and output image do not match for ImageProcessor::Xor\n");
7037  return false;
7038  }
7039 
7040  const int nBytes = pInputImage1->width * pInputImage1->height * pInputImage1->bytesPerPixel;
7041 
7042  const unsigned char *input1 = pInputImage1->pixels;
7043  const unsigned char *input2 = pInputImage2->pixels;
7044  unsigned char *output = pOutputImage->pixels;
7045  for (int i = 0; i < nBytes; i++)
7046  output[i] = input1[i] ^ input2[i];
7047 
7049 
7050  return true;
7051 }
7052 
7053 bool ImageProcessor::Or(const CByteImage *pInputImage1, const CByteImage *pInputImage2, CByteImage *pOutputImage)
7054 {
7055  OPTIMIZED_FUNCTION_HEADER_3(Or, pInputImage1, pInputImage2, pOutputImage)
7056 
7057  if (!pInputImage1->IsCompatible(pInputImage2) || !pInputImage1->IsCompatible(pOutputImage))
7058  {
7059  printf("error: input images and output image do not match for ImageProcessor::Or\n");
7060  return false;
7061  }
7062 
7063  const int nBytes = pInputImage1->width * pInputImage1->height * pInputImage1->bytesPerPixel;
7064 
7065  const unsigned char *input1 = pInputImage1->pixels;
7066  const unsigned char *input2 = pInputImage2->pixels;
7067  unsigned char *output = pOutputImage->pixels;
7068  for (int i = 0; i < nBytes; i++)
7069  output[i] = input1[i] | input2[i];
7070 
7072 
7073  return true;
7074 }
7075 
7076 
7077 bool ImageProcessor::Add(const CByteImage *pInputImage1, const CByteImage *pInputImage2, CByteImage *pOutputImage)
7078 {
7079  OPTIMIZED_FUNCTION_HEADER_3(Add, pInputImage1, pInputImage2, pOutputImage)
7080 
7081  if (!pInputImage1->IsCompatible(pInputImage2) || !pInputImage1->IsCompatible(pOutputImage))
7082  {
7083  printf("error: input images and output image do not match for ImageProcessor::Add\n");
7084  return false;
7085  }
7086 
7087  const int nBytes = pInputImage1->width * pInputImage1->height * pInputImage1->bytesPerPixel;
7088 
7089  const unsigned char *input1 = pInputImage1->pixels;
7090  const unsigned char *input2 = pInputImage2->pixels;
7091  unsigned char *output = pOutputImage->pixels;
7092 
7093  for (int i = 0; i < nBytes; i++)
7094  output[i] = input1[i] + input2[i];
7095 
7097 
7098  return true;
7099 }
7100 
7101 bool ImageProcessor::AddWithSaturation(const CByteImage *pInputImage1, const CByteImage *pInputImage2, CByteImage *pOutputImage)
7102 {
7103  OPTIMIZED_FUNCTION_HEADER_3(AddWithSaturation, pInputImage1, pInputImage2, pOutputImage)
7104 
7105  if (!pInputImage1->IsCompatible(pInputImage2) || !pInputImage1->IsCompatible(pOutputImage))
7106  {
7107  printf("error: input images and output image do not match for ImageProcessor::AddAndSaturate\n");
7108  return false;
7109  }
7110 
7111  const int nBytes = pInputImage1->width * pInputImage1->height * pInputImage1->bytesPerPixel;
7112 
7113  const unsigned char *input1 = pInputImage1->pixels;
7114  const unsigned char *input2 = pInputImage2->pixels;
7115  unsigned char *output = pOutputImage->pixels;
7116 
7117  for (int i = 0; i < nBytes; i++)
7118  output[i] = MY_MIN((unsigned int) input1[i] + (unsigned int) input2[i], 255);
7119 
7121 
7122  return true;
7123 }
7124 
7125 bool ImageProcessor::Subtract(const CByteImage *pInputImage1, const CByteImage *pInputImage2, CByteImage *pOutputImage)
7126 {
7127  OPTIMIZED_FUNCTION_HEADER_3(Subtract, pInputImage1, pInputImage2, pOutputImage)
7128 
7129  if (!pInputImage1->IsCompatible(pInputImage2) || !pInputImage1->IsCompatible(pOutputImage))
7130  {
7131  printf("error: input images and output image do not match for ImageProcessor::Subtract\n");
7132  return false;
7133  }
7134 
7135  const int nBytes = pInputImage1->width * pInputImage1->height * pInputImage1->bytesPerPixel;
7136 
7137  const unsigned char *input1 = pInputImage1->pixels;
7138  const unsigned char *input2 = pInputImage2->pixels;
7139  unsigned char *output = pOutputImage->pixels;
7140 
7141  for (int i = 0; i < nBytes; i++)
7142  output[i] = input1[i] - input2[i];
7143 
7145 
7146  return true;
7147 }
7148 
7149 bool ImageProcessor::SubtractWithSaturation(const CByteImage *pInputImage1, const CByteImage *pInputImage2, CByteImage *pOutputImage)
7150 {
7151  OPTIMIZED_FUNCTION_HEADER_3(SubtractWithSaturation, pInputImage1, pInputImage2, pOutputImage)
7152 
7153  if (!pInputImage1->IsCompatible(pInputImage2) || !pInputImage1->IsCompatible(pOutputImage))
7154  {
7155  printf("error: input images and output image do not match for ImageProcessor::SubtractAndSaturate\n");
7156  return false;
7157  }
7158 
7159  const int nBytes = pInputImage1->width * pInputImage1->height * pInputImage1->bytesPerPixel;
7160 
7161  const unsigned char *input1 = pInputImage1->pixels;
7162  const unsigned char *input2 = pInputImage2->pixels;
7163  unsigned char *output = pOutputImage->pixels;
7164 
7165  for (int i = 0; i < nBytes; i++)
7166  output[i] = MY_MAX((int) input1[i] - (int) input2[i], 0);
7167 
7169 
7170  return true;
7171 }
7172 
7173 bool ImageProcessor::AbsoluteDifference(const CByteImage *pInputImage1, const CByteImage *pInputImage2, CByteImage *pOutputImage)
7174 {
7175  OPTIMIZED_FUNCTION_HEADER_3(AbsoluteDifference, pInputImage1, pInputImage2, pOutputImage)
7176 
7177  if (!pInputImage1->IsCompatible(pInputImage2) || !pInputImage1->IsCompatible(pOutputImage))
7178  {
7179  printf("error: input images and output image do not match for ImageProcessor::AbsoluteDifference\n");
7180  return false;
7181  }
7182 
7183  const int nBytes = pInputImage1->width * pInputImage1->height * pInputImage1->bytesPerPixel;
7184 
7185  const unsigned char *input1 = pInputImage1->pixels;
7186  const unsigned char *input2 = pInputImage2->pixels;
7187  unsigned char *output = pOutputImage->pixels;
7188 
7189  for (int i = 0; i < nBytes; i++)
7190  output[i] = abs((int) input1[i] - (int) input2[i]);
7191 
7193 
7194  return true;
7195 }
7196 
7197 bool ImageProcessor::Average(const CByteImage *pInputImage1, const CByteImage *pInputImage2, CByteImage *pOutputImage)
7198 {
7199  OPTIMIZED_FUNCTION_HEADER_3(Average, pInputImage1, pInputImage2, pOutputImage)
7200 
7201  if (!pInputImage1->IsCompatible(pInputImage2) || !pInputImage1->IsCompatible(pOutputImage))
7202  {
7203  printf("error: input images and output image do not match for ImageProcessor::Average\n");
7204  return false;
7205  }
7206 
7207  const int nBytes = pInputImage1->width * pInputImage1->height * pInputImage1->bytesPerPixel;
7208 
7209  const unsigned char *input1 = pInputImage1->pixels;
7210  const unsigned char *input2 = pInputImage2->pixels;
7211  unsigned char *output = pOutputImage->pixels;
7212 
7213  for (int i = 0; i < nBytes; i++)
7214  output[i] = ((unsigned int) input1[i] + (unsigned int) input2[i] + 1) >> 1;
7215 
7217 
7218  return true;
7219 }
7220 
7221 bool ImageProcessor::Min(const CByteImage *pInputImage1, const CByteImage *pInputImage2, CByteImage *pOutputImage)
7222 {
7223  OPTIMIZED_FUNCTION_HEADER_3(Min, pInputImage1, pInputImage2, pOutputImage)
7224 
7225  if (!pInputImage1->IsCompatible(pInputImage2) || !pInputImage1->IsCompatible(pOutputImage))
7226  {
7227  printf("error: input images and output image do not match for ImageProcessor::Min\n");
7228  return false;
7229  }
7230 
7231  const int nBytes = pInputImage1->width * pInputImage1->height * pInputImage1->bytesPerPixel;
7232 
7233  const unsigned char *input1 = pInputImage1->pixels;
7234  const unsigned char *input2 = pInputImage2->pixels;
7235  unsigned char *output = pOutputImage->pixels;
7236 
7237  for (int i = 0; i < nBytes; i++)
7238  output[i] = MY_MIN(input1[i], input2[i]);
7239 
7241 
7242  return true;
7243 }
7244 
7245 bool ImageProcessor::Max(const CByteImage *pInputImage1, const CByteImage *pInputImage2, CByteImage *pOutputImage)
7246 {
7247  OPTIMIZED_FUNCTION_HEADER_3(Max, pInputImage1, pInputImage2, pOutputImage)
7248 
7249  if (!pInputImage1->IsCompatible(pInputImage2) || !pInputImage1->IsCompatible(pOutputImage))
7250  {
7251  printf("error: input images and output image do not match for ImageProcessor::Max\n");
7252  return false;
7253  }
7254 
7255  const int nBytes = pInputImage1->width * pInputImage1->height * pInputImage1->bytesPerPixel;
7256 
7257  const unsigned char *input1 = pInputImage1->pixels;
7258  const unsigned char *input2 = pInputImage2->pixels;
7259  unsigned char *output = pOutputImage->pixels;
7260 
7261  for (int i = 0; i < nBytes; i++)
7262  output[i] = MY_MAX(input1[i], input2[i]);
7263 
7265 
7266  return true;
7267 }
7268 
7269 
7270 unsigned char ImageProcessor::MaxValue(const CByteImage *pInputImage)
7271 {
7272  unsigned char max;
7273 
7274  OPTIMIZED_FUNCTION_HEADER_2(MaxValue, pInputImage, max)
7275 
7276  if (pInputImage->type != CByteImage::eGrayScale)
7277  {
7278  printf("error: input image must be of type eGrayScale for ImageProcessor::MaxValue\n");
7279  return 0;
7280  }
7281 
7282  const int nPixels = pInputImage->width * pInputImage->height;
7283  const unsigned char *input = pInputImage->pixels;
7284  max = 0;
7285 
7286  for (int i = 0; i < nPixels; i++)
7287  {
7288  if (input[i] > max)
7289  max = input[i];
7290  }
7291 
7293 
7294  return max;
7295 }
7296 
7297 short ImageProcessor::MaxValue(const CShortImage *pInputImage)
7298 {
7299  short max;
7300 
7301  OPTIMIZED_FUNCTION_HEADER_2(MaxValue_Short, pInputImage, max)
7302 
7303  const int nPixels = pInputImage->width * pInputImage->height;
7304  const short *input = pInputImage->pixels;
7305  max = SHRT_MIN;
7306 
7307  for (int i = 0; i < nPixels; i++)
7308  {
7309  if (input[i] > max)
7310  max = input[i];
7311  }
7312 
7314 
7315  return max;
7316 }
7317 
7318 int ImageProcessor::MaxValue(const CIntImage *pInputImage)
7319 {
7320  int max;
7321 
7322  OPTIMIZED_FUNCTION_HEADER_2(MaxValue_Int, pInputImage, max)
7323 
7324  const int nPixels = pInputImage->width * pInputImage->height;
7325  const int *input = pInputImage->pixels;
7326  max = INT_MIN;
7327 
7328  for (int i = 0; i < nPixels; i++)
7329  {
7330  if (input[i] > max)
7331  max = input[i];
7332  }
7333 
7335 
7336  return max;
7337 }
7338 
7339 unsigned char ImageProcessor::MinValue(const CByteImage *pInputImage)
7340 {
7341  unsigned char min;
7342 
7343  OPTIMIZED_FUNCTION_HEADER_2(MinValue, pInputImage, min)
7344 
7345  if (pInputImage->type != CByteImage::eGrayScale)
7346  {
7347  printf("error: input image must be of type eGrayScale for ImageProcessor::MinValue\n");
7348  return 0;
7349  }
7350 
7351  const int nPixels = pInputImage->width * pInputImage->height;
7352  const unsigned char *input = pInputImage->pixels;
7353  min = 255;
7354 
7355  for (int i = 0; i < nPixels; i++)
7356  {
7357  if (input[i] < min)
7358  min = input[i];
7359  }
7360 
7362 
7363  return min;
7364 }
7365 
7366 short ImageProcessor::MinValue(const CShortImage *pInputImage)
7367 {
7368  short min;
7369 
7370  OPTIMIZED_FUNCTION_HEADER_2(MinValue_Short, pInputImage, min)
7371 
7372  const int nPixels = pInputImage->width * pInputImage->height;
7373  const short *input = pInputImage->pixels;
7374  min = SHRT_MAX;
7375 
7376  for (int i = 0; i < nPixels; i++)
7377  {
7378  if (input[i] < min)
7379  min = input[i];
7380  }
7381 
7383 
7384  return min;
7385 }
7386 
7387 int ImageProcessor::MinValue(const CIntImage *pInputImage)
7388 {
7389  int min;
7390 
7391  OPTIMIZED_FUNCTION_HEADER_2(MinValue_Int, pInputImage, min)
7392 
7393  const int nPixels = pInputImage->width * pInputImage->height;
7394  const int *input = pInputImage->pixels;
7395  min = INT_MAX;
7396 
7397  for (int i = 0; i < nPixels; i++)
7398  {
7399  if (input[i] < min)
7400  min = input[i];
7401  }
7402 
7404 
7405  return min;
7406 }
7407 
7408 bool ImageProcessor::MinMaxValue(const CByteImage *pInputImage, unsigned char &min, unsigned char &max)
7409 {
7410  OPTIMIZED_FUNCTION_HEADER_3(MinMaxValue, pInputImage, min, max)
7411 
7412  if (pInputImage->type != CByteImage::eGrayScale)
7413  {
7414  printf("error: input image must be of type eGrayScale for ImageProcessor::MinMaxValue\n");
7415  return false;
7416  }
7417 
7418  const int nPixels = pInputImage->width * pInputImage->height;
7419  const unsigned char *input = pInputImage->pixels;
7420  min = 255;
7421  max = 0;
7422 
7423  for (int i = 0; i < nPixels; i++)
7424  {
7425  if (input[i] < min)
7426  min = input[i];
7427 
7428  if (input[i] > max)
7429  max = input[i];
7430  }
7431 
7433 
7434  return true;
7435 }
7436 
7437 void ImageProcessor::MinMaxValue(const CShortImage *pInputImage, short &min, short &max)
7438 {
7439  OPTIMIZED_FUNCTION_HEADER_3(MinMaxValue_Short, pInputImage, min, max)
7440 
7441  const int nPixels = pInputImage->width * pInputImage->height;
7442  const short *input = pInputImage->pixels;
7443  min = SHRT_MAX;
7444  max = SHRT_MIN;
7445 
7446  for (int i = 0; i < nPixels; i++)
7447  {
7448  if (input[i] < min)
7449  min = input[i];
7450 
7451  if (input[i] > max)
7452  max = input[i];
7453  }
7454 
7456 }
7457 
7458 void ImageProcessor::MinMaxValue(const CIntImage *pInputImage, int &min, int &max)
7459 {
7460  OPTIMIZED_FUNCTION_HEADER_3(MinMaxValue_Int, pInputImage, min, max)
7461 
7462  const int nPixels = pInputImage->width * pInputImage->height;
7463  const int *input = pInputImage->pixels;
7464  min = INT_MAX;
7465  max = INT_MIN;
7466 
7467  for (int i = 0; i < nPixels; i++)
7468  {
7469  if (input[i] < min)
7470  min = input[i];
7471 
7472  if (input[i] > max)
7473  max = input[i];
7474  }
7475 
7477 }
7478 
7479 
7480 unsigned int ImageProcessor::PixelSum(const CByteImage *pImage)
7481 {
7482  unsigned int sum = 0;
7483 
7485 
7486  if (pImage->type != CByteImage::eGrayScale)
7487  {
7488  printf("error: input image must be of type eGrayScale for ImageProcessor::PixelSum\n");
7489  return -1;
7490  }
7491 
7492  const int nPixels = pImage->width * pImage->height;
7493  const unsigned char *pixels = pImage->pixels;
7494 
7495  for (int i = 0; i < nPixels; i++)
7496  sum += pixels[i];
7497 
7499 
7500  return sum;
7501 }
7502 
7503 
7504 
7505 
7507 // The Bayer pattern conversion source code is originally from the OpenCV.
7508 // Below is the copyright notice:
7510 //
7511 // IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
7512 //
7513 // By downloading, copying, installing or using the software you agree to this license.
7514 // If you do not agree to this license, do not download, install,
7515 // copy or use the software.
7516 //
7517 // Intel License Agreement
7518 // For Open Source Computer Vision Library
7519 //
7520 // Copyright (C) 2000, Intel Corporation, all rights reserved.
7521 // Third party copyrights are property of their respective owners.
7522 //
7523 // Redistribution and use in source and binary forms, with or without modification,
7524 // are permitted provided that the following conditions are met:
7525 //
7526 // * Redistribution's of source code must retain the above copyright notice,
7527 // this list of conditions and the following disclaimer.
7528 //
7529 // * Redistribution's in binary form must reproduce the above copyright notice,
7530 // this list of conditions and the following disclaimer in the documentation
7531 // and/or other materials provided with the distribution.
7532 //
7533 // * The name of Intel Corporation may not be used to endorse or promote products
7534 // derived from this software without specific prior written permission.
7535 //
7536 // This software is provided by the copyright holders and contributors "as is" and
7537 // any express or implied warranties, including, but not limited to, the implied
7538 // warranties of merchantability and fitness for a particular purpose are disclaimed.
7539 // In no event shall the Intel Corporation or contributors be liable for any direct,
7540 // indirect, incidental, special, exemplary, or consequential damages
7541 // (including, but not limited to, procurement of substitute goods or services;
7542 // loss of use, data, or profits; or business interruption) however caused
7543 // and on any theory of liability, whether in contract, strict liability,
7544 // or tort (including negligence or otherwise) arising in any way out of
7545 // the use of this software, even if advised of the possibility of such damage.
7547 
7549 {
7550  if (pBayerImage->type != CByteImage::eGrayScale || pOutputImage->type != CByteImage::eRGB24)
7551  {
7552  printf("error: input image must be of type eGrayScale and output image of type eRGB24 for ImageProcessor::ConvertBayerPattern\n");
7553  return false;
7554  }
7555 
7556  const unsigned char *input = pBayerImage->pixels;
7557  unsigned char *output = pOutputImage->pixels;
7558 
7559  const int width = pBayerImage->width;
7560  const int height = pBayerImage->height;
7561  const int width3 = 3 * width;
7562 
7563  int blue = type == eBayerGB || type == eBayerBG ? 1 : -1;
7564  bool bGreenFirst = type == eBayerGR || type == eBayerGB;
7565 
7566  memset(output, 0, width);
7567  memset(output + (height - 1) * width, 0, width);
7568 
7569  for (int i = 2, input_offset = 0, output_offset = width3 + 4; i < height; i++, input_offset += width, output_offset += width3)
7570  {
7571  const unsigned char *bayer = input + input_offset;
7572  const unsigned char *bayer_end = bayer + width - 4;
7573  unsigned char *dst = output + output_offset;
7574 
7575  dst[-4] = dst[-3] = dst[-2] = 0;
7576 
7577  if (bGreenFirst)
7578  {
7579  dst[blue] = (unsigned char) ((bayer[1] + bayer[2 * width + 1] + 1) >> 1);
7580  dst[0] = bayer[width + 1];
7581  dst[-blue] = (unsigned char) ((bayer[width] + bayer[width + 2] + 1) >> 1);
7582 
7583  bayer++;
7584  dst += 3;
7585  }
7586 
7587  if (blue > 0)
7588  {
7589  for (; bayer <= bayer_end; bayer += 2, dst += 6)
7590  {
7591  register int v = bayer[2] + bayer[2 * width + 2] + 1;
7592 
7593  dst[4] = (unsigned char) (v >> 1);
7594  dst[3] = bayer[width + 2];
7595  dst[2] = (unsigned char) ((bayer[width + 1] + bayer[width + 3] + 1) >> 1);
7596 
7597  dst[1] = (unsigned char) ((bayer[0] + bayer[2 * width] + v + 1) >> 2);
7598  dst[0] = (unsigned char) ((bayer[1] + bayer[width] + bayer[width + 2] + bayer[2 * width + 1] + 2) >> 2);
7599  dst[-1] = bayer[width + 1];
7600  }
7601  }
7602  else
7603  {
7604  for (; bayer <= bayer_end; bayer += 2, dst += 6)
7605  {
7606  register int v = bayer[2] + bayer[2 * width + 2] + 1;
7607 
7608  dst[2] = (unsigned char) (v >> 1);
7609  dst[3] = bayer[width + 2];
7610  dst[4] = (unsigned char) ((bayer[width + 1] + bayer[width + 3] + 1) >> 1);
7611 
7612  dst[-1] = (unsigned char) ((bayer[0] + bayer[2 * width] + v + 1) >> 2);
7613  dst[0] = (unsigned char) ((bayer[1] + bayer[width] + bayer[width + 2] + bayer[2 * width + 1] + 2) >> 2);
7614  dst[1] = bayer[width + 1];
7615  }
7616  }
7617 
7618  if (bayer < bayer_end + 2)
7619  {
7620  dst[blue] = (unsigned char) ((bayer[0] + bayer[2] + bayer[2 * width] + bayer[2 * width + 2] + 2) >> 2);
7621  dst[0] = (unsigned char) ((bayer[1] + bayer[width] + bayer[width + 2] + bayer[2 * width + 1] + 2) >> 2);
7622  dst[-blue] = bayer[width + 1];
7623 
7624  bayer++;
7625  dst += 3;
7626  }
7627 
7628  dst[-1] = dst[0] = dst[1] = 0;
7629 
7630  blue = -blue;
7631  bGreenFirst = !bGreenFirst;
7632  }
7633 
7634  // this removes the black frame of the image by copying the pixels from the inner frame (2 pixels from the border)
7635  // to the frame pixels
7636  AdaptFrame(pOutputImage, pOutputImage);
7637 
7638  return true;
7639 }
float r4
Definition: Math3d.h:95
bool HighPassX3(const CFloatMatrix *pInputImage, CFloatMatrix *pOutputImage)
Applies a 1x3 highpass filter to a CFloatMatrix and write the result to a CFloatMatrix.
GLdouble GLdouble u2
Definition: glext.h:4584
GLubyte g
Definition: glext.h:5166
unsigned int PixelSum(const CByteImage *pImage)
Returns the sum of all pixel values of a grayscale CByteImage.
unsigned char MaxValue(const CByteImage *pImage)
Returns the maximum value within a grayscale CByteImage.
bool AddWithSaturation(const CByteImage *pInputImage1, const CByteImage *pInputImage2, CByteImage *pOutputImage)
Sets each pixel in a CByteImage to the sum of the corresponding pixels in two instances of CByteImage...
const int * GetColorParameters(ObjectColor color) const
bool DetermineAffineTransformation(const Vec2d *pSourcePoints, const Vec2d *pTargetPoints, int nPoints, float &a1, float &a2, float &a3, float &a4, float &a5, float &a6)
Deprecated.
BayerPatternType
The four possible variants for Bayer pattern conversion.
GLfloat GLfloat GLfloat v2
Definition: glext.h:3532
bool MinMaxValue(const CByteImage *pImage, unsigned char &min, unsigned char &max)
Computes the minimum and maximum value within a grayscale CByteImage.
Vec2d centroid
Definition: Structs.h:331
bool IsCompatible(const CByteImage *pImage) const
Checks whether two images are compatible or not.
Definition: ByteImage.cpp:212
GLdouble GLdouble t
Definition: glext.h:3219
#define OPTIMIZED_FUNCTION_HEADER_3(name, p1, p2, p3)
float * pixels
The pointer to the the pixels.
Definition: FloatImage.h:203
#define OPTIMIZED_FUNCTION_HEADER_4(name, p1, p2, p3, p4)
int min_x
Definition: Structs.h:333
bool ApplyAffinePointOperation(const CByteImage *pInputImage, CByteImage *pOutputImage, float a, float b)
Applies an affine point operation to a CByteImage and writes the result to a CByteImage.
bool ApplyHomography(const CByteImage *pInputImage, CByteImage *pOutputImage, const Mat3d &A, bool bInterpolation=true)
Applies a homography to a CByteImage and writes the result to a CByteImage.
double * data
Definition: DoubleMatrix.h:85
#define HARRIS_WINDOW_SIZE
bool CopyFrame(const CByteImage *pInputImage, CByteImage *pOutputImage)
Copies all pixels on a one pixel wide frame from one CByteImage to CByteImage.
bool DetermineHomography(const Vec2d *pSourcePoints, const Vec2d *pTargetPoints, int nPoints, Mat3d &A, bool bUseSVD=false)
Determines a homography based on a set of 2d-2d point correspondences.
static void CalculateSubpixel(const unsigned char *input, int width, int sector, Vec2d &point, Vec2d &direction)
bool HoughTransformLines(const CByteImage *pImage, CByteImage *pVisualizationImage, Vec2dList &resultLines, int nLinesToExtract, int nMinHits=1)
Performs the Hough transform for straight lines on a CByteImage.
float r7
Definition: Math3d.h:95
bool CalculateGradientImageSobel(const CByteImage *pInputImage, CByteImage *pOutputImage)
Applies a combined Sobel filter for both x- and y-direction to a CByteImage and stores the result in ...
Data structure for the representation of a 2D circle.
Definition: Structs.h:118
GLdouble u1
Definition: glext.h:4584
bool Laplace2(const CByteImage *pInputImage, CShortImage *pOutputImage, bool bAbsoluteValue=true)
Filters a CByteImage with the Laplace2 operator and writes the result to a CShortImage.
bool FilterColor(const CByteImage *pInputImage, CByteImage *pOutputImage, ObjectColor cColor, CColorParameterSet *pColorParameterSet, bool bImageIsHSV=true)
Performs color filtering with binarization for a CByteImage and writes the result to a grayscale CByt...
bool FindRegions(const CByteImage *pImage, RegionList &regionList, int nMinimumPointsPerRegion=0, int nMaximumPointsPerRegion=0, bool bCalculateBoundingBox=true, bool bStorePixels=false)
Performs region growing on a binary CByteImage, segmenting all regions in the image.
bool Max(const CByteImage *pInputImage1, const CByteImage *pInputImage2, CByteImage *pOutputImage)
Sets each pixel in a CByteImage to the maximum of the corresponding pixels in two instances of CByteI...
float y
Definition: Math2d.h:84
bool CalculateSaturationImage(const CByteImage *pInputImage, CByteImage *pOutputImage)
Calculates the saturation image for an RGB CByteImage and writes the result to a CByteImage.
bool NormalizeColor(const CByteImage *pInputImage, CByteImage *pOutputImage)
Applies histogram equalization to all channels of a color CByteImage.
float r1
Definition: Math3d.h:95
bool ThresholdFilterInverse(const CByteImage *pInputImage, CByteImage *pOutputImage, unsigned char nThreshold)
Performs inverse threhold filtering to a CByteImage and writes the result to a CByteImage.
bool Dilate(const CByteImage *pInputImage, CByteImage *pOutputImage, int nMaskSize=3, const MyRegion *pROI=0)
Applies a morphological dilate operation to a binary CByteImage and writes the result to a binary CBy...
GLdouble GLdouble GLdouble GLdouble q
Definition: glext.h:3235
bool ThresholdFilter(const CByteImage *pInputImage, CByteImage *pOutputImage, unsigned char nThreshold)
Performs threhold filtering to a CByteImage and writes the result to a CByteImage.
std::vector< Vec2d > Vec2dList
Definition: Math2d.h:106
int width
The width of the image in pixels.
Definition: ByteImage.h:257
bool DetermineHomography(const Vec2d *pSourcePoints, const Vec2d *pTargetPoints, int nPoints, float &a1, float &a2, float &a3, float &a4, float &a5, float &a6, float &a7, float &a8)
Deprecated.
GLenum GLsizei n
Definition: glext.h:4209
static void QuicksortInverse(int *pOffsets, const int *pValues, int nLow, int nHigh)
bool SobelX(const CByteImage *pInputImage, CShortImage *pOutputImage, bool bAbsoluteValue=true)
Filters a CByteImage with the SobelX operator and writes the result to a CShortImage.
int width
Definition: IntImage.h:71
bool FilterRGB(const CByteImage *pInputImage, CByteImage *pOutputImage, CRGBColorModel *pColorModel, float fThreshold)
Performs color filtering with binarization for an RGB CByteImage, given a CRGBColorModel, and writes the result to a grayscale CByteImage.
bool PrewittX(const CByteImage *pInputImage, CShortImage *pOutputImage, bool bAbsoluteValue=true)
Filters a CByteImage with the PrewittX operator and writes the result to a CShortImage.
float r2
Definition: Math3d.h:95
unsigned char MinValue(const CByteImage *pImage)
Returns the minimum value within a grayscale CByteImage.
bool CalculateBinarizedSummedAreaTable(const CByteImage *pInputImage, CIntImage *pSummedAreaTable)
Calculates the binarized summed area table of a grayscale CByteImage and writes the result to a CIntI...
bool Invert(const CByteImage *pInputImage, CByteImage *pOutputImage)
Calculates the inverted image of a CByteImage and writes the result to a CByteImage.
GLenum GLsizei GLenum GLenum const GLvoid * image
Definition: glext.h:3131
bool ConvertBayerPattern(const CByteImage *pInputImage, CByteImage *pOutputImage, BayerPatternType type)
Converts an 8 bit Bayer pattern CByteImage to an RGB24 color CByteImage.
bool SobelY(const CByteImage *pInputImage, CShortImage *pOutputImage, bool bAbsoluteValue=true)
Filters a CByteImage with the SobelY operator and writes the result to a CShortImage.
float r3
Definition: Math3d.h:95
Data structure for the representation of a 3D vector.
Definition: Math3d.h:73
Data structure for the representation of 8-bit grayscale images and 24-bit RGB (or HSV) color images ...
Definition: ByteImage.h:80
int numberOfChannels
Number of channels per pixel.
Definition: FloatImage.h:212
bool GeneralFilter(const CByteImage *pInputImage, CByteImage *pOutputImage, const int *pKernel, int nMaskSize, int nDivider=1, bool bAbsoluteValue=false)
Applies a user defined filter to a CByteImage and writes the result to a CByteImage.
bool CalculateHSVImage(const CByteImage *pInputImage, CByteImage *pOutputImage, const MyRegion *pROI=0)
Computes the HSV image for a RGB CByteImage and writes the result to a CByteImage.
int GetAreaSumNoChecks(const CIntImage *pIntegralImage, int min_x, int min_y, int max_x, int max_y)
Efficiently computes the sum of all pixel values in a rectangular area using integral image lookups...
GLdouble s
Definition: glext.h:3211
bool HighPassY3(const CFloatMatrix *pInputImage, CFloatMatrix *pOutputImage)
Applies a 3x1 highpass filter to a CFloatMatrix and writes the result to a CFloatMatrix.
bool CalculateGradientImage(const CByteImage *pInputImage, CByteImage *pOutputImage)
Applies a combined simple gradient filter for both x- and y-direction to a CByteImage and stores the ...
bool Xor(const CByteImage *pInputImage1, const CByteImage *pInputImage2, CByteImage *pOutputImage)
Applies the bitwise operator XOR to two instance of CByteImage and writes the result to a CByteImage...
#define OPTIMIZED_FUNCTION_HEADER_2(name, p1, p2)
bool CalculateHarrisMap(const CByteImage *pInputImage, CIntImage *pOutputImage)
Calculates the Harris cornerness measure for every pixel in a CByteImage and writes the results to a ...
GLintptr offset
Definition: glext.h:3389
#define MY_MAX(a, b)
Definition: helpers.h:63
GLuint GLuint GLsizei GLenum type
Definition: glext.h:3121
unsigned char * pixels
The pointer to the the pixels.
Definition: ByteImage.h:283
bool CalculateReverseSummedAreaTable(const CIntImage *pSummedAreaTable, CByteImage *pOutputImage)
Reconstructs the original image, given a summed area table, and writes the result to a grayscale CByt...
bool ConvertImage(const CByteImage *pInputImage, CByteImage *pOutputImage, bool bFast=false, const MyRegion *pROI=0)
Converts a grayscale CByteImage to an RGB CByteImage image and vice versa.
bool ThresholdBinarizeInverse(const CByteImage *pInputImage, CByteImage *pOutputImage, unsigned char nThreshold)
Performs inverse threshold binarization to a CByteImage and writes the result to a CByteImage...
int width
The width of the image in pixels.
Definition: FloatImage.h:177
std::vector< Vec3d > Vec3dList
Definition: Math3d.h:126
float radius
The radius of the circle.
Definition: Structs.h:128
void DrawLinePolar(CByteImage *pImage, float theta, float r, int color_r, int color_g, int color_b, int thickness=1)
Draws a straight line into a CByteImage, given its parameters in polar form.
Vec2d normalVector
The normalized normal vector of the straight line.
Definition: Structs.h:247
bool FlipY(const CByteImage *pInputImage, CByteImage *pOutputImage)
Flips the rows in a CByteImage vertically and writes the result to a CByteImage.
static float * sin_table
bool SubtractWithSaturation(const CByteImage *pInputImage1, const CByteImage *pInputImage2, CByteImage *pOutputImage)
Sets each pixel in a CByteImage to the difference between the corresponding pixels in two instances o...
int RegionGrowing(const CByteImage *pInputImage, MyRegion &resultRegion, int x, int y, int nMinimumPointsPerRegion=0, int nMaximumPointsPerRegion=0, bool bCalculateBoundingBox=true, bool bStorePixels=false)
Performs a region growing on a binary CByteImage on the basis of one seed point and stores the comput...
GLuint dst
Definition: glext.h:5789
GLenum GLint x
Definition: glext.h:3125
bool GaussianSmooth(const CByteImage *pInputImage, CFloatMatrix *pOutputImage, float fVariance, int nKernelSize)
Applies a Gaussian filter to a CByteImage and writes the result to a CFloatMatrix.
bool Average(const CByteImage *pInputImage1, const CByteImage *pInputImage2, CByteImage *pOutputImage)
Sets each pixel in a CByteImage to the average of the corresponding pixels in two instances of CByteI...
int height
The height of the image in pixels.
Definition: FloatImage.h:184
static float * cos_table
float x
Definition: Math2d.h:84
std::vector< MyRegion > RegionList
Definition: Structs.h:346
bool DetermineAffineTransformation(const Vec2d *pSourcePoints, const Vec2d *pTargetPoints, int nPoints, Mat3d &A, bool bUseSVD=false)
Determines an affine transformation based on a set of 2d-2d point correspondences.
#define OPTIMIZED_FUNCTION_HEADER_5_RET(name, p1, p2, p3, p4, p5)
const GLubyte * c
Definition: glext.h:5181
bool AverageFilter(const CByteImage *pInputImage, CByteImage *pOutputImage, int nMaskSize=3)
Applies an average filter to a CByteImage and writes the result to a CByteImage.
static const int MatrixGaussian5x5[25]
void DrawCircle(CByteImage *pImage, float mx, float my, float radius, int r=255, int g=255, int b=255, int thickness=1, bool bAntiAlias=false)
Draws a circle into a CByteImage.
float r6
Definition: Math3d.h:95
GLsizei const GLfloat * value
Definition: glext.h:3538
bool CopyMatrix(const CFloatMatrix *pInputImage, CFloatMatrix *pOutputImage)
Copies one CFloatMatrix to another.
Data structure for the representation of a matrix of values of the data type float.
Definition: FloatMatrix.h:56
GLsizei GLsizei GLenum GLenum const GLvoid * data
Definition: glext.h:3129
bool AbsoluteDifference(const CByteImage *pInputImage1, const CByteImage *pInputImage2, CByteImage *pOutputImage)
Sets each pixel in a CByteImage to the absolute value of the difference between the corresponding pix...
int * pPixels
Definition: Structs.h:326
bool Canny(const CByteImage *pInputImage, CByteImage *pOutputImage, int nLowThreshold, int nHighThreshold)
Applies the Canny edge detector to a CByteImage and writes the result to a CByteImage.
int min_y
Definition: Structs.h:334
bool CopyImage(const CByteImage *pInputImage, CByteImage *pOutputImage, const MyRegion *pROI=0, bool bUseSameSize=false)
Copies one CByteImage to another.
#define FLOAT_RAD2DEG
Definition: Constants.h:51
void NormalizeVec(Vec2d &vec)
Definition: Math2d.cpp:160
GLint GLint GLsizei GLsizei GLsizei GLint GLenum GLenum const GLvoid * pixels
Definition: glext.h:3154
void ZeroFrame(CByteImage *pImage)
Sets all pixels on a one pixel wide frame of a CByteImage to zero.
bool Min(const CByteImage *pInputImage1, const CByteImage *pInputImage2, CByteImage *pOutputImage)
Sets each pixel in a CByteImage to the minimum of the corresponding pixels in two instances of CByteI...
float r8
Definition: Math3d.h:95
Data structure for the representation of single channel images of the data type signed short...
Definition: ShortImage.h:54
float r9
Definition: Math3d.h:95
float * data
Definition: FloatMatrix.h:91
#define OPTIMIZED_FUNCTION_FOOTER
GLubyte GLubyte GLubyte a
Definition: glext.h:5166
int height
The height of the image in pixels.
Definition: ByteImage.h:264
bool Subtract(const CByteImage *pInputImage1, const CByteImage *pInputImage2, CByteImage *pOutputImage)
Sets each pixel in a CByteImage to the difference between the corresponding pixels in two instances o...
int height
Definition: IntImage.h:72
float CalculateColorProbability(const Vec3d &rgb)
int nPixels
Definition: Structs.h:327
bool Amplify(const CByteImage *pInputImage, CByteImage *pOutputImage, float fFactor)
Multiplies each byte value of a CByteImage with a floating point factor and writes the result to a CB...
#define FLOAT_DEG2RAD
Definition: Constants.h:52
void DrawLine(CByteImage *pImage, const PointPair2d &line, int r=255, int g=255, int b=255, int thickness=1)
Draws a line segment into a CByteImage, given its two end points.
bool PrewittY(const CByteImage *pInputImage, CShortImage *pOutputImage, bool bAbsoluteValue=true)
Filters a CByteImage with the PrewittY operator and writes the result to a CShortImage.
bool ThresholdBinarize(const CByteImage *pInputImage, CByteImage *pOutputImage, unsigned char nThreshold)
Performs threshold binarization to a CByteImage and writes the result to a CByteImage.
GLubyte GLubyte b
Definition: glext.h:5166
static bool Dilate3x3(const CByteImage *pInputImage, CByteImage *pOutputImage, const MyRegion *pROI)
#define OPTIMIZED_FUNCTION_HEADER_8_ROI(name, p1, p2, p3, p4, p5, p6, p7, p8, p9)
int bytesPerPixel
The number of bytes used for encoding one pixel.
Definition: ByteImage.h:273
static const int division_table[]
#define OPTIMIZED_FUNCTION_HEADER_2_ROI(name, p1, p2, p3)
GLclampf GLclampf blue
Definition: glext.h:3119
#define MY_MIN(a, b)
Definition: helpers.h:64
GLenum GLsizei width
Definition: glext.h:3122
GLenum GLsizei GLsizei height
Definition: glext.h:3132
ImageType
Enum specifying the supported image types.
Definition: ByteImage.h:86
bool CalculateGradientImageBinary(const CByteImage *pInputImage, CByteImage *pOutputImage)
Calculates a gradient image for a CByteImage and writes the result to a CByteImage, for the special case of binary images.
bool Rotate(const CByteImage *pInputImage, CByteImage *pOutputImage, float mx, float my, float theta, bool bInterpolation=true)
Rotates pInputImage to the dimensions specified by pOutputImage and stores the result in pOutputImage...
int max_x
Definition: Structs.h:335
bool FilterHSV2(const CByteImage *pInputImage, CByteImage *pOutputImage, unsigned char min_hue, unsigned char max_hue, unsigned char min_sat, unsigned char max_sat, unsigned char min_v, unsigned char max_v, const MyRegion *pROI=0)
Performs color filtering with binarization for an HSV CByteImage and writes the result to a grayscale...
bool Spread(const CByteImage *pInputImage, CByteImage *pOutputImage)
Performs a spread operation on pInputImage and stores the result in pOutputImage. ...
#define FLOAT_PI
Definition: Constants.h:50
bool Rotate180Degrees(const CByteImage *pInputImage, CByteImage *pOutputImage)
Rotates a CByteImage by 180 degrees and writes the result to a CByteImage.
bool Add(const CByteImage *pInputImage1, const CByteImage *pInputImage2, CByteImage *pOutputImage)
Sets each pixel in a CByteImage to the sum of the corresponding pixels in two instances of CByteImage...
Data structure for the representation of a 2D straight line.
Definition: Structs.h:179
static void track(unsigned char *magnitudes, int *stack, int offset, int width)
GLenum GLenum GLenum input
Definition: glext.h:5307
ImageType type
The type of the image.
Definition: ByteImage.h:292
bool Laplace1(const CByteImage *pInputImage, CShortImage *pOutputImage, bool bAbsoluteValue=true)
Filters a CByteImage with the Laplace1 operator and writes the result to a CShortImage.
bool GaussianSmooth5x5(const CFloatMatrix *pInputImage, CFloatMatrix *pOutputImage, float fVariance)
Applies a 5x5 Gaussian filter to a CFloatMatrix and writes the result to a CFloatMatrix.
GLdouble GLdouble GLdouble r
Definition: glext.h:3227
Vec2d center
The center of the circle.
Definition: Structs.h:123
int nSeedOffset
Definition: Structs.h:329
GLsizeiptr size
Definition: glext.h:3388
bool AdaptFrame(const CByteImage *pInputImage, CByteImage *pOutputImage)
Sets all pixels on a one pixel wide outer frame in a CByteImage to the pixel values of the inner fram...
float r5
Definition: Math3d.h:95
int CalculateHarrisInterestPoints(const CByteImage *pInputImage, Vec2d *pInterestPoints, int nMaxPoints, float fQualityLevel=0.01f, float fMinDistance=5.0f)
Computes interest points within a CByteImage by applying the Harris corner detector.
float c
The negative scalar product of normalVector and point.
Definition: Structs.h:252
float ratio
Definition: Structs.h:338
void AddElement(const T &element)
GLenum GLint GLint y
Definition: glext.h:3125
const GLdouble * v
Definition: glext.h:3212
int GetAreaSum(const CIntImage *pIntegralImage, int min_x, int min_y, int max_x, int max_y)
Efficiently computes the sum of all pixel values in a rectangular area using integral image lookups...
Data structure for the representation of a 2D vector.
Definition: Math2d.h:82
bool Erode(const CByteImage *pInputImage, CByteImage *pOutputImage, int nMaskSize=3, const MyRegion *pROI=0)
Applies a morphological erode operation to a binary CByteImage and writes the result to a binary CByt...
bool HoughTransformCircles(const CByteImage *pImage, CByteImage *pVisualizationImage, Vec3dList &resultCircles, int rmin, int rmax, int nCirclesToExtract, int nMinHits=1)
Performs the Hough transform for circles on a CByteImage.
bool Or(const CByteImage *pInputImage1, const CByteImage *pInputImage2, CByteImage *pOutputImage)
Applies the bitwise operator OR to two instance of CByteImage and writes the result to a CByteImage...
bool HistogramStretching(const CByteImage *pInputImage, CByteImage *pOutputImage, float p1=0.1f, float p2=0.9f)
Performs histogram stretching on pInputImage and stores the result in pOutputImage.
GLfloat GLfloat v1
Definition: glext.h:3531
Data structure for the representation of single channel images of the data type signed int...
Definition: IntImage.h:55
short * pixels
Definition: ShortImage.h:72
Data structure for the representation of a matrix of values of the data type double.
Definition: DoubleMatrix.h:54
static bool Erode3x3(const CByteImage *pInputImage, CByteImage *pOutputImage, const MyRegion *pROI)
bool HistogramEqualization(const CByteImage *pInputImage, CByteImage *pOutputImage)
Performs histogram equalization for a CByteImage and writes the result to a CByteImage.
void SetVec(Vec2d &vec, float x, float y)
Definition: Math2d.cpp:68
bool And(const CByteImage *pInputImage1, const CByteImage *pInputImage2, CByteImage *pOutputImage)
Applies the bitwise operator AND to two instance of CByteImage and writes the result to a CByteImage...
#define OPTIMIZED_FUNCTION_HEADER_3_ROI(name, p1, p2, p3, p4)
bool CalculateSummedAreaTable(const CByteImage *pInputImage, CIntImage *pSummedAreaTable)
Calculates the summed area table of a grayscale CByteImage and writes the result to a CIntImage...
bool GaussianSmooth3x3(const CByteImage *pInputImage, CByteImage *pOutputImage)
Applies a 3x3 Gaussian filter to a CByteImage and writes the result to a CByteImage.
void Zero(CByteImage *pImage, const MyRegion *pROI=0)
Sets all values in a CByteImage to zero.
GLfloat GLfloat p
Definition: glext.h:5178
bool ConvertMatrix(const CFloatMatrix *pInputImage, CDoubleMatrix *pOutputImage)
Converts a CFloatMatrix to a CDoubleMatrix.
bool CalculateGradientImagePrewitt(const CByteImage *pInputImage, CByteImage *pOutputImage)
Applies a combined Prewitt filter for both x- and y-direction to a CByteImage and stores the result i...
int * pixels
Definition: IntImage.h:73
static float sin_table_[380]
Data structure for the representation of a 3x3 matrix.
Definition: Math3d.h:93
int max_y
Definition: Structs.h:336
static float cos_table_[380]
GLubyte GLubyte GLubyte GLubyte w
Definition: glext.h:3571
Data structure for the representation of any image type (arbitrary number of channels) using the data...
Definition: FloatImage.h:62
Training and application of an RGB color model on the basis of the Mahalanobis distance.
Definition: RGBColorModel.h:63
#define OPTIMIZED_FUNCTION_HEADER_5(name, p1, p2, p3, p4, p5)
static int _RegionGrowing(unsigned char *pixels, int width, int offset, int *stack, int *region, MyRegion &resultRegion, int nMinimumPointsPerRegion, int nMaximumPointsPerRegion, bool bCalculateBoundingBox)
ObjectColor
bool Resize(const CByteImage *pInputImage, CByteImage *pOutputImage, const MyRegion *pROI=0, bool bInterpolation=true)
Resizes a CByteImage and writes the result to a CByteImage.
static bool AverageFilter3x3(const CByteImage *pInputImage, CByteImage *pOutputImage)
bool FilterHSV(const CByteImage *pInputImage, CByteImage *pOutputImage, unsigned char hue, unsigned char tol_hue, unsigned char min_sat, unsigned char max_sat, unsigned char min_v, unsigned char max_v, const MyRegion *pROI=0)
Performs color filtering with binarization for an HSV CByteImage and writes the result to a grayscale...
static void InitSinCosTables()
bool CalculateIntegralImage(const CByteImage *pInputImage, CIntImage *pIntegralImage)
Calculates the integral image of a grayscale CByteImage and writes the result to a CIntImage...


asr_ivt
Author(s): Allgeyer Tobias, Hutmacher Robin, Kleinert Daniel, Meißner Pascal, Scholz Jonas, Stöckle Patrick
autogenerated on Mon Dec 2 2019 03:47:28