ImageProcessor.cpp
Go to the documentation of this file.
00001 // ****************************************************************************
00002 // This file is part of the Integrating Vision Toolkit (IVT).
00003 //
00004 // The IVT is maintained by the Karlsruhe Institute of Technology (KIT)
00005 // (www.kit.edu) in cooperation with the company Keyetech (www.keyetech.de).
00006 //
00007 // Copyright (C) 2014 Karlsruhe Institute of Technology (KIT).
00008 // All rights reserved.
00009 //
00010 // Redistribution and use in source and binary forms, with or without
00011 // modification, are permitted provided that the following conditions are met:
00012 //
00013 // 1. Redistributions of source code must retain the above copyright
00014 //    notice, this list of conditions and the following disclaimer.
00015 //
00016 // 2. Redistributions in binary form must reproduce the above copyright
00017 //    notice, this list of conditions and the following disclaimer in the
00018 //    documentation and/or other materials provided with the distribution.
00019 //
00020 // 3. Neither the name of the KIT nor the names of its contributors may be
00021 //    used to endorse or promote products derived from this software
00022 //    without specific prior written permission.
00023 //
00024 // THIS SOFTWARE IS PROVIDED BY THE KIT AND CONTRIBUTORS “AS IS” AND ANY
00025 // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
00026 // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
00027 // DISCLAIMED. IN NO EVENT SHALL THE KIT OR CONTRIBUTORS BE LIABLE FOR ANY
00028 // DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
00029 // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00030 // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
00031 // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00032 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
00033 // THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00034 // ****************************************************************************
00035 // ****************************************************************************
00036 // Filename:  ImageProcessor.cpp
00037 // Author:    Pedram Azad
00038 // Date:      2004
00039 // ****************************************************************************
00040 // Changes:   20.05.2008, Florian Hecht
00041 //            * Added Summed Area Table functions 
00042 //
00043 //            07.01.2009, Moritz Hassert
00044 //            * Added new functions:
00045 //              Add, AddAndSaturate, Subtract, AbsoluteDifference,
00046 //              Average, Min, Max
00047 // ****************************************************************************
00048 
00049 
00050 // ****************************************************************************
00051 // Includes
00052 // ****************************************************************************
00053 
00054 #include <new> // for explicitly using correct new/delete operators on VC DSPs
00055 
00056 #include "ImageProcessor.h"
00057 
00058 #include "ByteImage.h"
00059 #include "ShortImage.h"
00060 #include "IntImage.h"
00061 #include "FloatImage.h"
00062 #include "PrimitivesDrawer.h"
00063 #include "Color/RGBColorModel.h"
00064 #include "Math/LinearAlgebra.h"
00065 #include "Math/FloatMatrix.h"
00066 #include "Math/DoubleMatrix.h"
00067 #include "Math/Constants.h"
00068 #include "Math/Math3d.h"
00069 #include "Math/Matd.h"
00070 #include "Math/Vecd.h"
00071 #include "Helpers/helpers.h"
00072 #include "Helpers/OptimizedFunctions.h"
00073 #include "Color/ColorParameterSet.h"
00074 
00075 #include <stdio.h>
00076 #include <stdlib.h>
00077 #include <string.h>
00078 #include <math.h>
00079 #include <stddef.h>
00080 #include <algorithm>
00081 #include <limits.h>
00082 #include <float.h>
00083 
00084 
00085 
00086 // ****************************************************************************
00087 // Static variables and functions
00088 // ****************************************************************************
00089 
00090 // (1 << 20) / i
00091 static const int division_table[] =
00092 {
00093         0, 1048576, 524288, 349525, 262144, 209715, 174762, 149796, 
00094         131072, 116508, 104857, 95325, 87381, 80659, 74898, 69905, 
00095         65536, 61680, 58254, 55188, 52428, 49932, 47662, 45590, 
00096         43690, 41943, 40329, 38836, 37449, 36157, 34952, 33825, 
00097         32768, 31775, 30840, 29959, 29127, 28339, 27594, 26886, 
00098         26214, 25575, 24966, 24385, 23831, 23301, 22795, 22310, 
00099         21845, 21399, 20971, 20560, 20164, 19784, 19418, 19065, 
00100         18724, 18396, 18078, 17772, 17476, 17189, 16912, 16644, 
00101         16384, 16131, 15887, 15650, 15420, 15196, 14979, 14768, 
00102         14563, 14364, 14169, 13981, 13797, 13617, 13443, 13273, 
00103         13107, 12945, 12787, 12633, 12483, 12336, 12192, 12052, 
00104         11915, 11781, 11650, 11522, 11397, 11275, 11155, 11037, 
00105         10922, 10810, 10699, 10591, 10485, 10381, 10280, 10180, 
00106         10082, 9986, 9892, 9799, 9709, 9619, 9532, 9446, 
00107         9362, 9279, 9198, 9118, 9039, 8962, 8886, 8811, 
00108         8738, 8665, 8594, 8525, 8456, 8388, 8322, 8256, 
00109         8192, 8128, 8065, 8004, 7943, 7884, 7825, 7767, 
00110         7710, 7653, 7598, 7543, 7489, 7436, 7384, 7332, 
00111         7281, 7231, 7182, 7133, 7084, 7037, 6990, 6944, 
00112         6898, 6853, 6808, 6765, 6721, 6678, 6636, 6594, 
00113         6553, 6512, 6472, 6432, 6393, 6355, 6316, 6278, 
00114         6241, 6204, 6168, 6132, 6096, 6061, 6026, 5991, 
00115         5957, 5924, 5890, 5857, 5825, 5793, 5761, 5729, 
00116         5698, 5667, 5637, 5607, 5577, 5548, 5518, 5489, 
00117         5461, 5433, 5405, 5377, 5349, 5322, 5295, 5269, 
00118         5242, 5216, 5190, 5165, 5140, 5115, 5090, 5065, 
00119         5041, 5017, 4993, 4969, 4946, 4922, 4899, 4877, 
00120         4854, 4832, 4809, 4788, 4766, 4744, 4723, 4702, 
00121         4681, 4660, 4639, 4619, 4599, 4578, 4559, 4539, 
00122         4519, 4500, 4481, 4462, 4443, 4424, 4405, 4387, 
00123         4369, 4350, 4332, 4315, 4297, 4279, 4262, 4245, 
00124         4228, 4211, 4194, 4177, 4161, 4144, 4128, 4112
00125 };
00126 
00127 static const int MatrixGaussian5x5[25] =
00128 {
00129         1,  5,  7,  5, 1,
00130         5, 20, 33, 20, 5,
00131         7, 33, 55, 33, 7,
00132         5, 20, 33, 20, 5,
00133         1,  5,  7,  5, 1
00134 };
00135 
00136 static float sin_table_[380];
00137 static float cos_table_[380];
00138 static float *sin_table = sin_table_ + 10;
00139 static float *cos_table = cos_table_ + 10;
00140 
00141 static void InitSinCosTables()
00142 {
00143         static bool bSinCosTablesInitialized = false;
00144         
00145         if (bSinCosTablesInitialized)
00146                 return;
00147         
00148         for (int i = -10; i < 370; i++)
00149         {
00150                 const float theta = i * FLOAT_DEG2RAD;
00151                 sin_table[i] = sinf(theta);
00152                 cos_table[i] = cosf(theta);
00153         }
00154         
00155         bSinCosTablesInitialized = true;
00156 }
00157 
00158 
00159 
00160 // ****************************************************************************
00161 // Functions
00162 // ****************************************************************************
00163 
00164 bool ImageProcessor::GeneralFilter(const CByteImage *pInputImage, CByteImage *pOutputImage, const int *pKernel, int nMaskSize, int nDivider, bool bAbsoluteValue)
00165 {
00166         if (pInputImage->width != pOutputImage->width || pInputImage->height != pOutputImage->height ||
00167                 pInputImage->type != CByteImage::eGrayScale || pOutputImage->type != CByteImage::eGrayScale)
00168         {
00169                 printf("error: input and output image do not match for ImageProcessor::GeneralFilter\n");
00170                 return false;
00171         }
00172 
00173         if (nMaskSize < 3 || (nMaskSize + 1) % 2 != 0)
00174         {
00175                 printf("error: nMaskSize must be 2 * k + 1 with k >= 1 for ImageProcessor::GeneralFilter\n");
00176                 return false;
00177         }
00178 
00179         CByteImage *pSaveOutputImage = 0;
00180         if (pInputImage->pixels == pOutputImage->pixels)
00181         {
00182                 pSaveOutputImage = pOutputImage;
00183                 pOutputImage = new CByteImage(pInputImage);
00184         }
00185 
00186         ImageProcessor::Zero(pOutputImage);
00187         
00188         const int umax = pInputImage->width - nMaskSize + 1;
00189         const int vmax = pInputImage->height - nMaskSize + 1;
00190 
00191         const unsigned char *input = pInputImage->pixels;
00192         unsigned char *output = pOutputImage->pixels;
00193 
00194         const int diff = (nMaskSize - 1) * (pInputImage->width + 1) / 2;
00195 
00196         if (nDivider == 1)
00197         {
00198                 if (bAbsoluteValue)
00199                 {
00200                         for (int v = 0, offset = diff; v < vmax; v++, offset += nMaskSize - 1)
00201                         {
00202                                 for (int u = 0; u < umax; u++, offset++)
00203                                 {
00204                                         int sum = 0;
00205                 
00206                                         for (int i = 0, offset2 = offset - diff, offset3 = 0; i < nMaskSize; i++, offset2 += umax - 1)
00207                                         {
00208                                                 for (int j = 0;  j < nMaskSize; j++, offset2++, offset3++)
00209                                                         sum += input[offset2] * pKernel[offset3];
00210                                         }
00211                                         
00212                                         output[offset] = (unsigned char) abs(sum);
00213                                 }
00214                         }
00215                 }
00216                 else
00217                 {
00218                         for (int v = 0, offset = diff; v < vmax; v++, offset += nMaskSize - 1)
00219                         {
00220                                 for (int u = 0; u < umax; u++, offset++)
00221                                 {
00222                                         int sum = 0;
00223                 
00224                                         for (int i = 0, offset2 = offset - diff, offset3 = 0; i < nMaskSize; i++, offset2 += umax - 1)
00225                                         {
00226                                                 for (int j = 0;  j < nMaskSize; j++, offset2++, offset3++)
00227                                                         sum += input[offset2] * pKernel[offset3];
00228                                         }
00229                                         
00230                                         output[offset] = (unsigned char) sum;
00231                                 }
00232                         }
00233                 }
00234         }
00235         else
00236         {
00237                 if (bAbsoluteValue)
00238                 {
00239                         for (int v = 0, offset = diff; v < vmax; v++, offset += nMaskSize - 1)
00240                         {
00241                                 for (int u = 0; u < umax; u++, offset++)
00242                                 {
00243                                         int sum = 0;
00244                 
00245                                         for (int i = 0, offset2 = offset - diff, offset3 = 0; i < nMaskSize; i++, offset2 += umax - 1)
00246                                         {
00247                                                 for (int j = 0;  j < nMaskSize; j++, offset2++, offset3++)
00248                                                         sum += input[offset2] * pKernel[offset3];
00249                                         }
00250                                         
00251                                         output[offset] = (unsigned char) (abs(sum) / nDivider);
00252                                 }
00253                         }
00254                 }
00255                 else
00256                 {
00257                         for (int v = 0, offset = diff; v < vmax; v++, offset += nMaskSize - 1)
00258                         {
00259                                 for (int u = 0; u < umax; u++, offset++)
00260                                 {
00261                                         int sum = 0;
00262                 
00263                                         for (int i = 0, offset2 = offset - diff, offset3 = 0; i < nMaskSize; i++, offset2 += umax - 1)
00264                                         {
00265                                                 for (int j = 0;  j < nMaskSize; j++, offset2++, offset3++)
00266                                                         sum += input[offset2] * pKernel[offset3];
00267                                         }
00268                                         
00269                                         output[offset] = (unsigned char) (sum / nDivider);
00270                                 }
00271                         }
00272                 }
00273         }
00274 
00275         if (pSaveOutputImage)
00276         {
00277                 CopyImage(pOutputImage, pSaveOutputImage);
00278                 delete pOutputImage;
00279         }
00280 
00281         return true;
00282 }
00283 
00284 bool ImageProcessor::GeneralFilter(const CByteImage *pInputImage, CShortImage *pOutputImage, const int *pKernel, int nMaskSize, int nDivider, bool bAbsoluteValue)
00285 {
00286         if (pInputImage->width != pOutputImage->width || pInputImage->height != pOutputImage->height ||
00287                 pInputImage->type != CByteImage::eGrayScale)
00288         {
00289                 printf("error: input and output image do not match for ImageProcessor::GeneralFilter\n");
00290                 return false;
00291         }
00292 
00293         if (nMaskSize < 3 || (nMaskSize + 1) % 2 != 0)
00294         {
00295                 printf("error: nMaskSize must be 2 * k + 1 with k >= 1 for ImageProcessor::GeneralFilter\n");
00296                 return false;
00297         }
00298 
00299         ImageProcessor::Zero(pOutputImage);
00300         
00301         const int width = pInputImage->width;
00302         const int height = pInputImage->height;
00303         const int umax = width - nMaskSize + 1;
00304         const int vmax = height - nMaskSize + 1;
00305 
00306         const unsigned char *input = pInputImage->pixels;
00307         short *output = pOutputImage->pixels;
00308 
00309         const int diff = (nMaskSize - 1) * (width + 1) / 2;
00310 
00311         if (nDivider == 1)
00312         {
00313                 if (bAbsoluteValue)
00314                 {
00315                         for (int v = 0, offset = diff; v < vmax; v++, offset += nMaskSize - 1)
00316                         {
00317                                 for (int u = 0; u < umax; u++, offset++)
00318                                 {
00319                                         int sum = 0;
00320                 
00321                                         for (int i = 0, offset2 = offset - diff, offset3 = 0; i < nMaskSize; i++, offset2 += umax - 1)
00322                                         {
00323                                                 for (int j = 0;  j < nMaskSize; j++, offset2++, offset3++)
00324                                                         sum += input[offset2] * pKernel[offset3];
00325                                         }
00326                                         
00327                                         output[offset] = (short) abs(sum);
00328                                 }
00329                         }
00330                 }
00331                 else
00332                 {
00333                         for (int v = 0, offset = diff; v < vmax; v++, offset += nMaskSize - 1)
00334                         {
00335                                 for (int u = 0; u < umax; u++, offset++)
00336                                 {
00337                                         int sum = 0;
00338                 
00339                                         for (int i = 0, offset2 = offset - diff, offset3 = 0; i < nMaskSize; i++, offset2 += umax - 1)
00340                                         {
00341                                                 for (int j = 0;  j < nMaskSize; j++, offset2++, offset3++)
00342                                                         sum += input[offset2] * pKernel[offset3];
00343                                         }
00344                                         
00345                                         output[offset] = (short) sum;
00346                                 }
00347                         }
00348                 }
00349         }
00350         else
00351         {
00352                 if (bAbsoluteValue)
00353                 {
00354                         for (int v = 0, offset = diff; v < vmax; v++, offset += nMaskSize - 1)
00355                         {
00356                                 for (int u = 0; u < umax; u++, offset++)
00357                                 {
00358                                         int sum = 0;
00359                 
00360                                         for (int i = 0, offset2 = offset - diff, offset3 = 0; i < nMaskSize; i++, offset2 += umax - 1)
00361                                         {
00362                                                 for (int j = 0;  j < nMaskSize; j++, offset2++, offset3++)
00363                                                         sum += input[offset2] * pKernel[offset3];
00364                                         }
00365                                         
00366                                         output[offset] = (short) (abs(sum) / nDivider);
00367                                 }
00368                         }
00369                 }
00370                 else
00371                 {
00372                         for (int v = 0, offset = diff; v < vmax; v++, offset += nMaskSize - 1)
00373                         {
00374                                 for (int u = 0; u < umax; u++, offset++)
00375                                 {
00376                                         int sum = 0;
00377                 
00378                                         for (int i = 0, offset2 = offset - diff, offset3 = 0; i < nMaskSize; i++, offset2 += umax - 1)
00379                                         {
00380                                                 for (int j = 0;  j < nMaskSize; j++, offset2++, offset3++)
00381                                                         sum += input[offset2] * pKernel[offset3];
00382                                         }
00383                                         
00384                                         output[offset] = (short) (sum / nDivider);
00385                                 }
00386                         }
00387                 }
00388         }
00389 
00390         return true;
00391 }
00392 
00393 bool ImageProcessor::GeneralFilter(const CByteImage *pInputImage, CFloatMatrix *pOutputMatrix, const int *pKernel, int nMaskSize, int nDivider, bool bAbsoluteValue)
00394 {
00395         if (pInputImage->width != pOutputMatrix->columns || pInputImage->height != pOutputMatrix->rows ||
00396                 pInputImage->type != CByteImage::eGrayScale)
00397         {
00398                 printf("error: input image and output matrix do not match for ImageProcessor::GeneralFilter\n");
00399                 return false;
00400         }
00401 
00402         if (nMaskSize < 3 || (nMaskSize + 1) % 2 != 0)
00403         {
00404                 printf("error: nMaskSize must be 2 * k + 1 with k >= 1 for ImageProcessor::GeneralFilter\n");
00405                 return false;
00406         }
00407 
00408         ImageProcessor::Zero(pOutputMatrix);
00409         
00410         const int width = pInputImage->width;
00411         const int height = pInputImage->height;
00412         const int umax = width - nMaskSize + 1;
00413         const int vmax = height - nMaskSize + 1;
00414 
00415         const unsigned char *input = pInputImage->pixels;
00416         float *output = pOutputMatrix->data;
00417 
00418 #if 0
00419         
00420         const int k = (nMaskSize - 1) / 2;
00421 
00422         for (int v = 0; v < vmax; v++)
00423         {
00424                 for (int u = 0; u < umax; u++)
00425                 {
00426                         int sum = 0;
00427 
00428                         for (int i = 0; i < nMaskSize; i++)
00429                         {
00430                                 for (int j = 0;  j < nMaskSize; j++)
00431                                         sum += input[(v + i) * width + (u + j)] * pKernel[i * nMaskSize + j];
00432                         }
00433 
00434                         output[(v + k) * width + (u + k)] = float(abs(sum)) / nDivider;
00435                 }
00436         }
00437 
00438 #else
00439 
00440         const int diff = (nMaskSize - 1) * (width + 1) / 2;
00441 
00442         if (nDivider == 1)
00443         {
00444                 if (bAbsoluteValue)
00445                 {
00446                         for (int v = 0, offset = diff; v < vmax; v++, offset += nMaskSize - 1)
00447                         {
00448                                 for (int u = 0; u < umax; u++, offset++)
00449                                 {
00450                                         int sum = 0;
00451                 
00452                                         for (int i = 0, offset2 = offset - diff, offset3 = 0; i < nMaskSize; i++, offset2 += umax - 1)
00453                                         {
00454                                                 for (int j = 0;  j < nMaskSize; j++, offset2++, offset3++)
00455                                                         sum += input[offset2] * pKernel[offset3];
00456                                         }
00457                                         
00458                                         output[offset] = (float) abs(sum);
00459                                 }
00460                         }
00461                 }
00462                 else
00463                 {
00464                         for (int v = 0, offset = diff; v < vmax; v++, offset += nMaskSize - 1)
00465                         {
00466                                 for (int u = 0; u < umax; u++, offset++)
00467                                 {
00468                                         int sum = 0;
00469                 
00470                                         for (int i = 0, offset2 = offset - diff, offset3 = 0; i < nMaskSize; i++, offset2 += umax - 1)
00471                                         {
00472                                                 for (int j = 0;  j < nMaskSize; j++, offset2++, offset3++)
00473                                                         sum += input[offset2] * pKernel[offset3];
00474                                         }
00475                                         
00476                                         output[offset] = (float) sum;
00477                                 }
00478                         }
00479                 }
00480         }
00481         else
00482         {
00483                 if (bAbsoluteValue)
00484                 {
00485                         for (int v = 0, offset = diff; v < vmax; v++, offset += nMaskSize - 1)
00486                         {
00487                                 for (int u = 0; u < umax; u++, offset++)
00488                                 {
00489                                         int sum = 0;
00490                 
00491                                         for (int i = 0, offset2 = offset - diff, offset3 = 0; i < nMaskSize; i++, offset2 += umax - 1)
00492                                         {
00493                                                 for (int j = 0;  j < nMaskSize; j++, offset2++, offset3++)
00494                                                         sum += input[offset2] * pKernel[offset3];
00495                                         }
00496                                         
00497                                         output[offset] = float(abs(sum)) / nDivider;
00498                                 }
00499                         }
00500                 }
00501                 else
00502                 {
00503                         for (int v = 0, offset = diff; v < vmax; v++, offset += nMaskSize - 1)
00504                         {
00505                                 for (int u = 0; u < umax; u++, offset++)
00506                                 {
00507                                         int sum = 0;
00508                 
00509                                         for (int i = 0, offset2 = offset - diff, offset3 = 0; i < nMaskSize; i++, offset2 += umax - 1)
00510                                         {
00511                                                 for (int j = 0;  j < nMaskSize; j++, offset2++, offset3++)
00512                                                         sum += input[offset2] * pKernel[offset3];
00513                                         }
00514                                         
00515                                         output[offset] = float(sum) / nDivider;
00516                                 }
00517                         }
00518                 }
00519         }
00520 #endif
00521 
00522         return true;
00523 }
00524 
00525 
00526 // Separation:
00527 //
00528 // ( 1  4  6  4  1 )     ( 1 )
00529 // ( 4 16 24 16  4 )     ( 4 )
00530 // ( 6 24 36 24  6 )  =  ( 6 ) * ( 1  4  6  4  1 )
00531 // ( 4 16 24 16  4 )     ( 4 )
00532 // ( 1  4  6  4  1 )     ( 1 )
00533 
00534 bool ImageProcessor::GaussianSmooth5x5(const CByteImage *pInputImage, CByteImage *pOutputImage)
00535 {
00536         OPTIMIZED_FUNCTION_HEADER_2(GaussianSmooth5x5, pInputImage, pOutputImage)
00537         
00538         if (!pInputImage->IsCompatible(pOutputImage))
00539         {
00540                 printf("error: input and output image do not match for ImageProcessor::GaussianSmooth5x5\n");
00541                 return false;
00542         }
00543 
00544         if (pInputImage->width < 5 || pInputImage->height < 5)
00545         {
00546                 printf("error: image must be at least of size 5x5 for ImageProcessor::GaussianSmooth5x5\n");
00547                 return false;
00548         }
00549 
00550         const int width = pInputImage->width;
00551         const int height = pInputImage->height;
00552 
00553         if (pInputImage->type == CByteImage::eRGB24)
00554         {
00555                 // slow but better than nothing
00556                 CByteImage inputImageRGB24Split(width, height, CByteImage::eRGB24Split);
00557                 CByteImage outputImageRGB24Split(width, height, CByteImage::eRGB24Split);
00558 
00559                 ImageProcessor::ConvertImage(pInputImage, &inputImageRGB24Split);
00560 
00561                 GaussianSmooth5x5(&inputImageRGB24Split, &outputImageRGB24Split);
00562 
00563                 ConvertImage(&outputImageRGB24Split, pOutputImage);
00564 
00565                 return true;
00566         }
00567         else if (pInputImage->type == CByteImage::eRGB24Split)
00568         {
00569                 const int nPixels = width * height;
00570 
00571                 CByteImage imageHeaderInputGrayscale(width, height, CByteImage::eGrayScale, true);
00572                 CByteImage imageHeaderOutputGrayscale(width, height, CByteImage::eGrayScale, true);
00573 
00574                 // red channel
00575                 imageHeaderInputGrayscale.pixels = pInputImage->pixels;
00576                 imageHeaderOutputGrayscale.pixels = pOutputImage->pixels;
00577                 GaussianSmooth5x5(&imageHeaderInputGrayscale, &imageHeaderOutputGrayscale);
00578 
00579                 // green channel
00580                 imageHeaderInputGrayscale.pixels = pInputImage->pixels + nPixels;
00581                 imageHeaderOutputGrayscale.pixels = pOutputImage->pixels + nPixels;
00582                 GaussianSmooth5x5(&imageHeaderInputGrayscale, &imageHeaderOutputGrayscale);
00583 
00584                 // blue channel
00585                 imageHeaderInputGrayscale.pixels = pInputImage->pixels + 2 * nPixels;
00586                 imageHeaderOutputGrayscale.pixels = pOutputImage->pixels + 2 * nPixels;
00587                 GaussianSmooth5x5(&imageHeaderInputGrayscale, &imageHeaderOutputGrayscale);
00588 
00589                 return true;
00590         }
00591                 
00592         // create temp image
00593         CByteImage *pTempImage = new CByteImage(pInputImage);
00594         
00595         const int width2 = width << 1;
00596         
00597         const unsigned char *input = pInputImage->pixels;
00598         unsigned char *temp = pTempImage->pixels;
00599         unsigned char *output = pOutputImage->pixels;
00600         
00601         int x, y, offset;
00602         
00603         // x direction
00604         for (y = 0, offset = 0; y < height; y++)
00605         {
00606                 temp[offset] = (11 * input[offset] + (input[offset + 1] << 2) + input[offset + 2] + 8) >> 4;
00607                 temp[offset + 1] = (5 * input[offset] + 6 * input[offset + 1] + (input[offset + 2] << 2) + input[offset + 3] + 8) >> 4;
00608                 offset += 2;
00609                 
00610                 // core loop
00611                 for (x = 4; x < width; x++, offset++)
00612                         temp[offset] = (input[offset - 2] + (input[offset - 1] << 2) + 6 * input[offset] + (input[offset + 1] << 2) + input[offset + 2] + 8) >> 4;
00613                 
00614                 temp[offset] = (input[offset - 2] + (input[offset - 1] << 2) + 6 * input[offset] + 5 * input[offset + 1] + 8) >> 4;
00615                 temp[offset + 1] = (input[offset - 1] + (input[offset] << 2) + 11 * input[offset + 1] + 8) >> 4;
00616                 offset += 2;
00617         }
00618         
00619         // y direction
00620         for (x = 0, offset = 0; x < width; x++, offset++)
00621         {
00622                 output[offset] = (11 * temp[offset] + (temp[offset + width] << 2) + temp[offset + width2] + 8) >> 4;
00623                 output[offset + width] = (5 * temp[offset] + 6 * temp[offset + width] + (temp[offset + width2] << 2) + temp[offset + 3 * width] + 8) >> 4;
00624         }
00625         
00626         // core loop
00627         for (y = 4, offset = width << 1; y < height; y++)
00628                 for (x = 0; x < width; x++, offset++)
00629                         output[offset] = (temp[offset - width2] + (temp[offset - width] << 2) + 6 * temp[offset] + (temp[offset + width] << 2) + temp[offset + width2] + 8) >> 4;
00630                 
00631         for (x = 0, offset = (height - 2) * width; x < width; x++, offset++)
00632         {
00633                 output[offset] = (temp[offset - width2] + (temp[offset - width] << 2) + 6 * temp[offset] + 5 * temp[offset + width] + 8) >> 4;
00634                 output[offset + width] = (temp[offset - width] + (temp[offset] << 2) + 11 * temp[offset + width] + 8) >> 4;
00635         }
00636         
00637         // free memory
00638         delete pTempImage;
00639         
00640         OPTIMIZED_FUNCTION_FOOTER
00641 
00642         return true;
00643 }
00644 
00645 
00646 static bool AverageFilter3x3(const CByteImage *pInputImage, CByteImage *pOutputImage)
00647 {
00648         if (pInputImage->width != pOutputImage->width || pInputImage->height != pOutputImage->height ||
00649                 pInputImage->type != CByteImage::eGrayScale || pOutputImage->type != CByteImage::eGrayScale)
00650         {
00651                 printf("error: input and output image do not match for ImageProcessor::AverageFilter\n");
00652                 return false;
00653         }
00654         
00655         CByteImage *pSaveOutputImage = 0;
00656         if (pInputImage->pixels == pOutputImage->pixels)
00657         {
00658                 pSaveOutputImage = pOutputImage;
00659                 pOutputImage = new CByteImage(pInputImage);
00660         }
00661         
00662         ImageProcessor::ZeroFrame(pOutputImage);
00663 
00664         const int maxj = pInputImage->width - 1, maxi = pInputImage->height - 1;
00665         const int width = pInputImage->width;
00666         const unsigned char *input = pInputImage->pixels;
00667         unsigned char *output = pOutputImage->pixels;
00668         
00669         for (int i = 1, offset = width + 1; i < maxi; i++, offset += 2)
00670         {
00671                 for (int j = 1; j < maxj; j++, offset++)
00672                 {
00673                         output[offset] = (
00674                                 input[offset - width - 1] + input[offset - width] + input[offset - width + 1] +
00675                                 input[offset - 1] + input[offset] + input[offset + 1] + 
00676                                 input[offset + width - 1] + input[offset + width] + input[offset + width + 1]
00677                         ) / 9;
00678                 }
00679         }
00680 
00681         if (pSaveOutputImage)
00682         {
00683                 ImageProcessor::CopyImage(pOutputImage, pSaveOutputImage);
00684                 delete pOutputImage;
00685         }
00686 
00687         return true;
00688 }
00689 
00690 bool ImageProcessor::AverageFilter(const CByteImage *pInputImage, CByteImage *pOutputImage, int nMaskSize)
00691 {
00692         if (nMaskSize == 3)
00693         {
00694                 AverageFilter3x3(pInputImage, pOutputImage);
00695                 return false;
00696         }
00697         
00698         if (pInputImage->width != pOutputImage->width || pInputImage->height != pOutputImage->height ||
00699                 pInputImage->type != CByteImage::eGrayScale || pOutputImage->type != CByteImage::eGrayScale)
00700         {
00701                 printf("error: input and output image do not match for ImageProcessor::AverageFilter\n");
00702                 return false;
00703         }
00704 
00705         if (nMaskSize < 3 || (nMaskSize + 1) % 2 != 0)
00706         {
00707                 printf("error: nMaskSize must be 2 * k + 1 with k >= 1 for ImageProcessor::AverageFilter\n");
00708                 return false;
00709         }
00710         
00711         const int width = pInputImage->width;
00712         const int height = pInputImage->height;
00713         
00714         ImageProcessor::Zero(pOutputImage);
00715         
00716         CIntImage sat(width, height);
00717         
00718         ImageProcessor::CalculateSummedAreaTable(pInputImage, &sat);
00719         
00720         const int frame = (nMaskSize - 1) / 2;
00721         const int area_size = nMaskSize*nMaskSize;
00722         
00723         const int maxx = width - 2*frame;
00724         const int maxy = height - 2*frame;
00725         const int offset = nMaskSize * width;
00726         
00727         const int *input = sat.pixels;
00728         unsigned char *output = pOutputImage->pixels;
00729         
00730         for (int y = 1; y < maxy; y++)
00731         {
00732                 const int line_offset = (y + frame)*width + frame;
00733                 for (int x = 1; x < maxx; x++)
00734                 {
00735                         int p1 = (y-1)*width + x - 1;
00736                         int p3 = p1 + offset;
00737                 
00738                         output[line_offset + x] = (input[p3 + nMaskSize] - input[p3] - input[p1 + nMaskSize] + input[p1]) / area_size;
00739                 }
00740         }
00741 
00742         return true;
00743 }
00744 
00745 
00746 bool ImageProcessor::GaussianSmooth3x3(const CByteImage *pInputImage, CByteImage *pOutputImage)
00747 {
00748         OPTIMIZED_FUNCTION_HEADER_2(GaussianSmooth3x3, pInputImage, pOutputImage)
00749         
00750         if (pInputImage->width != pOutputImage->width || pInputImage->height != pOutputImage->height ||
00751                 pInputImage->type != pOutputImage->type)
00752         {
00753                 printf("error: input and output image do not match for ImageProcessor::GaussianSmooth3x3\n");
00754                 return false;
00755         }
00756 
00757         if (pInputImage->width < 3 || pInputImage->height < 3)
00758         {
00759                 printf("error: image must be at least of size 3x3 for ImageProcessor::GaussianSmooth3x3\n");
00760                 return false;
00761         }
00762         
00763         CByteImage *pSaveOutputImage = 0;
00764         if (pInputImage->pixels == pOutputImage->pixels)
00765         {
00766                 pSaveOutputImage = pOutputImage;
00767                 pOutputImage = new CByteImage(pInputImage);
00768         }
00769 
00770         const int maxj = pInputImage->width - 1, maxi = pInputImage->height - 1;
00771         const unsigned char *p = pInputImage->pixels;
00772         unsigned char *output = pOutputImage->pixels;
00773         
00774         if (pInputImage->type == CByteImage::eGrayScale)
00775         {
00776                 const int width = pInputImage->width;
00777 
00778                 for (int i = 1, offset = width + 1; i < maxi; i++, offset += 2)
00779                 {
00780                         for (int j = 1; j < maxj; j++, offset++)
00781                         {
00782                                 output[offset] = (
00783                                         p[offset - width - 1] + (p[offset - width] << 1) + p[offset - width + 1] +
00784                                         (p[offset - 1] << 1) + (p[offset] << 2) + (p[offset + 1] << 1) + 
00785                                         p[offset + width - 1] + (p[offset + width] << 1) + p[offset + width + 1] + 8
00786                                 ) >> 4;
00787                         }
00788                 }
00789         }
00790         else if (pInputImage->type == CByteImage::eRGB24)
00791         {
00792                 const int width = 3 * pInputImage->width;
00793                 int offset = width + 3;
00794 
00795                 for (int i = 1; i < maxi; i++)
00796                 {
00797                         for (int j = 1; j < maxj; j++)
00798                         {
00799                                 output[offset] = (
00800                                         p[offset - width - 3] + (p[offset - width] << 1) + p[offset - width + 3] +
00801                                         (p[offset - 3] << 1) + (p[offset] << 2) + (p[offset + 3] << 1) + 
00802                                         p[offset + width - 3] + (p[offset + width] << 1) + p[offset + width + 3] + 8
00803                                 ) >> 4;
00804 
00805                                 offset++;
00806 
00807                                 output[offset] = (
00808                                         p[offset - width - 3] + (p[offset - width] << 1) + p[offset - width + 3] +
00809                                         (p[offset - 3] << 1) + (p[offset] << 2) + (p[offset + 3] << 1) + 
00810                                         p[offset + width - 3] + (p[offset + width] << 1) + p[offset + width + 3] + 8
00811                                 ) >> 4;
00812 
00813                                 offset++;
00814 
00815                                 output[offset] = (
00816                                         p[offset - width - 3] + (p[offset - width] << 1) + p[offset - width + 3] +
00817                                         (p[offset - 3] << 1) + (p[offset] << 2) + (p[offset + 3] << 1) + 
00818                                         p[offset + width - 3] + (p[offset + width] << 1) + p[offset + width + 3] + 8
00819                                 ) >> 4;
00820 
00821                                 offset++;
00822                         }
00823 
00824                         offset += 6;
00825                 }
00826         }
00827         
00828         // copy the border pixels from the original, since the border is not calculated
00829         if (pSaveOutputImage)
00830                 CopyFrame(pSaveOutputImage, pOutputImage);
00831         else
00832                 CopyFrame(pInputImage, pOutputImage);
00833 
00834         if (pSaveOutputImage)
00835         {
00836                 CopyImage(pOutputImage, pSaveOutputImage);
00837                 delete pOutputImage;
00838         }
00839         
00840         OPTIMIZED_FUNCTION_FOOTER
00841 
00842         return true;
00843 }
00844 
00845 
00846 bool ImageProcessor::SobelX(const CByteImage *pInputImage, CByteImage *pOutputImage, bool bAbsoluteValue)
00847 {
00848         CShortImage image(pInputImage->width, pInputImage->height);
00849         
00850         if (!SobelX(pInputImage, &image, bAbsoluteValue))
00851                 return false;
00852 
00853         return ConvertImage(&image, pOutputImage);
00854 }
00855 
00856 bool ImageProcessor::SobelY(const CByteImage *pInputImage, CByteImage *pOutputImage, bool bAbsoluteValue)
00857 {
00858         CShortImage image(pInputImage->width, pInputImage->height);
00859         
00860         if (!SobelY(pInputImage, &image, bAbsoluteValue))
00861                 return false;
00862 
00863         return ConvertImage(&image, pOutputImage);
00864 }
00865 
00866 bool ImageProcessor::SobelY(const CByteImage *pInputImage, CShortImage *pOutputImage, bool bAbsoluteValue)
00867 {
00868         OPTIMIZED_FUNCTION_HEADER_3(SobelY, pInputImage, pOutputImage, bAbsoluteValue)
00869 
00870         if (pInputImage->width != pOutputImage->width || pInputImage->height != pOutputImage->height ||
00871                 pInputImage->type != CByteImage::eGrayScale)
00872         {
00873                 printf("error: input and output image do not match for ImageProcessor::SobelY\n");
00874                 return false;
00875         }
00876         
00877         ZeroFrame(pOutputImage);
00878 
00879         const int maxj = pInputImage->width - 1, maxi = pInputImage->height - 1;
00880         const int width = pInputImage->width;
00881         const unsigned char *input = pInputImage->pixels;
00882         short *output = pOutputImage->pixels;
00883 
00884         if (bAbsoluteValue)
00885         {
00886                 for (int i = 1, offset = width + 1; i < maxi; i++, offset += 2)
00887                 {
00888                         for (int j = 1; j < maxj; j++, offset++)
00889                         {
00890                                 output[offset] =
00891                                         abs(input[offset + width - 1] + (input[offset + width] << 1) + input[offset + width + 1] -
00892                                         input[offset - width - 1] - (input[offset - width] << 1) - input[offset - width + 1]);
00893                         }
00894                 }
00895         }
00896         else
00897         {
00898                 for (int i = 1, offset = width + 1; i < maxi; i++, offset += 2)
00899                 {
00900                         for (int j = 1; j < maxj; j++, offset++)
00901                         {
00902                                 output[offset] =
00903                                         input[offset + width - 1] + (input[offset + width] << 1) + input[offset + width + 1] -
00904                                         input[offset - width - 1] - (input[offset - width] << 1) - input[offset - width + 1];
00905                         }
00906                 }
00907         }
00908 
00909         OPTIMIZED_FUNCTION_FOOTER
00910 
00911         return true;
00912 }
00913 
00914 bool ImageProcessor::SobelX(const CByteImage *pInputImage, CShortImage *pOutputImage, bool bAbsoluteValue)
00915 {
00916         OPTIMIZED_FUNCTION_HEADER_3(SobelX, pInputImage, pOutputImage, bAbsoluteValue)
00917 
00918         if (pInputImage->width != pOutputImage->width || pInputImage->height != pOutputImage->height ||
00919                 pInputImage->type != CByteImage::eGrayScale)
00920         {
00921                 printf("error: input and output image do not match for ImageProcessor::SobelX\n");
00922                 return false;
00923         }
00924         
00925         ZeroFrame(pOutputImage);
00926 
00927         const int maxj = pInputImage->width - 1, maxi = pInputImage->height - 1;
00928         const int width = pInputImage->width;
00929         const unsigned char *input = pInputImage->pixels;
00930         short *output = pOutputImage->pixels;
00931 
00932         if (bAbsoluteValue)
00933         {
00934                 for (int i = 1, offset = width + 1; i < maxi; i++, offset += 2)
00935                 {
00936                         for (int j = 1; j < maxj; j++, offset++)
00937                         {
00938                                 output[offset] =
00939                                         abs(input[offset - width + 1] + (input[offset + 1] << 1) + input[offset + width + 1] -
00940                                         input[offset - width - 1] - (input[offset - 1] << 1) - input[offset + width - 1]);
00941                         }
00942                 }
00943         }
00944         else
00945         {
00946                 for (int i = 1, offset = width + 1; i < maxi; i++, offset += 2)
00947                 {
00948                         for (int j = 1; j < maxj; j++, offset++)
00949                         {
00950                                 output[offset] =
00951                                         input[offset - width + 1] + (input[offset + 1] << 1) + input[offset + width + 1] -
00952                                         input[offset - width - 1] - (input[offset - 1] << 1) - input[offset + width - 1];
00953                         }
00954                 }
00955         }
00956 
00957         OPTIMIZED_FUNCTION_FOOTER
00958 
00959         return true;
00960 }
00961 
00962 
00963 bool ImageProcessor::PrewittX(const CByteImage *pInputImage, CByteImage *pOutputImage, bool bAbsoluteValue)
00964 {
00965         CShortImage image(pInputImage->width, pInputImage->height);
00966         
00967         if (!PrewittX(pInputImage, &image, bAbsoluteValue))
00968                 return false;
00969 
00970         return ConvertImage(&image, pOutputImage);
00971 }
00972 
00973 bool ImageProcessor::PrewittY(const CByteImage *pInputImage, CByteImage *pOutputImage, bool bAbsoluteValue)
00974 {
00975         CShortImage image(pInputImage->width, pInputImage->height);
00976         
00977         if (!PrewittY(pInputImage, &image, bAbsoluteValue))
00978                 return false;
00979 
00980         return ConvertImage(&image, pOutputImage);
00981 }
00982 
00983 bool ImageProcessor::PrewittY(const CByteImage *pInputImage, CShortImage *pOutputImage, bool bAbsoluteValue)
00984 {
00985         OPTIMIZED_FUNCTION_HEADER_3(PrewittY, pInputImage, pOutputImage, bAbsoluteValue)
00986 
00987         if (pInputImage->width != pOutputImage->width || pInputImage->height != pOutputImage->height ||
00988                 pInputImage->type != CByteImage::eGrayScale)
00989         {
00990                 printf("error: input and output image do not match for ImageProcessor::PrewittY\n");
00991                 return false;
00992         }
00993         
00994         ZeroFrame(pOutputImage);
00995 
00996         const int maxj = pInputImage->width - 1, maxi = pInputImage->height - 1;
00997         const int width = pInputImage->width;
00998         const unsigned char *input = pInputImage->pixels;
00999         short *output = pOutputImage->pixels;
01000 
01001         if (bAbsoluteValue)
01002         {
01003                 for (int i = 1, offset = width + 1; i < maxi; i++, offset += 2)
01004                 {
01005                         for (int j = 1; j < maxj; j++, offset++)
01006                         {
01007                                 output[offset] =
01008                                         abs(input[offset + width - 1] + input[offset + width] + input[offset + width + 1] -
01009                                         input[offset - width - 1] - input[offset - width] - input[offset - width + 1]);
01010                         }
01011                 }
01012         }
01013         else
01014         {
01015                 for (int i = 1, offset = width + 1; i < maxi; i++, offset += 2)
01016                 {
01017                         for (int j = 1; j < maxj; j++, offset++)
01018                         {
01019                                 output[offset] =
01020                                         input[offset + width - 1] + input[offset + width] + input[offset + width + 1] -
01021                                         input[offset - width - 1] - input[offset - width] - input[offset - width + 1];
01022                         }
01023                 }
01024         }
01025 
01026         OPTIMIZED_FUNCTION_FOOTER
01027 
01028         return true;
01029 }
01030 
01031 bool ImageProcessor::PrewittX(const CByteImage *pInputImage, CShortImage *pOutputImage, bool bAbsoluteValue)
01032 {
01033         OPTIMIZED_FUNCTION_HEADER_3(PrewittX, pInputImage, pOutputImage, bAbsoluteValue)
01034 
01035         if (pInputImage->width != pOutputImage->width || pInputImage->height != pOutputImage->height ||
01036                 pInputImage->type != CByteImage::eGrayScale)
01037         {
01038                 printf("error: input and output image do not match for ImageProcessor::PrewittX\n");
01039                 return false;
01040         }
01041         
01042         ZeroFrame(pOutputImage);
01043 
01044         const int maxj = pInputImage->width - 1, maxi = pInputImage->height - 1;
01045         const int width = pInputImage->width;
01046         const unsigned char *input = pInputImage->pixels;
01047         short *output = pOutputImage->pixels;
01048 
01049         if (bAbsoluteValue)
01050         {
01051                 for (int i = 1; i < maxi; ++i)
01052                 {
01053                         int offset = width * i + 1;
01054                         for (int j = 1; j < maxj; ++j, ++offset)
01055                         {
01056                                 output[offset] =
01057                                         abs(input[offset - width + 1] + input[offset + 1] + input[offset + width + 1] -
01058                                         input[offset - width - 1] - input[offset - 1] - input[offset + width - 1]);
01059                         }
01060                 }
01061         }
01062         else
01063         {
01064                 for (int i = 1; i < maxi; ++i)
01065                 {
01066                         int offset = width * i + 1;
01067                         for (int j = 1; j < maxj; ++j, ++offset)
01068                         {
01069                                 output[offset] =
01070                                         input[offset - width + 1] + input[offset + 1] + input[offset + width + 1] -
01071                                         input[offset - width - 1] - input[offset - 1] - input[offset + width - 1];
01072                         }
01073                 }
01074         }
01075 
01076         OPTIMIZED_FUNCTION_FOOTER
01077 
01078         return true;
01079 }
01080 
01081 
01082 bool ImageProcessor::Laplace1(const CByteImage *pInputImage, CByteImage *pOutputImage, bool bAbsoluteValue)
01083 {
01084         CShortImage image(pInputImage->width, pInputImage->height);
01085         
01086         if (!Laplace1(pInputImage, &image, bAbsoluteValue))
01087                 return false;
01088 
01089         ConvertImage(&image, pOutputImage);
01090 
01091         return true;
01092 }
01093 
01094 bool ImageProcessor::Laplace2(const CByteImage *pInputImage, CByteImage *pOutputImage, bool bAbsoluteValue)
01095 {
01096         CShortImage image(pInputImage->width, pInputImage->height);
01097         
01098         if (!Laplace2(pInputImage, &image, bAbsoluteValue))
01099                 return false;
01100 
01101         ConvertImage(&image, pOutputImage);
01102 
01103         return true;
01104 }
01105 
01106 bool ImageProcessor::Laplace1(const CByteImage *pInputImage, CShortImage *pOutputImage, bool bAbsoluteValue)
01107 {
01108         OPTIMIZED_FUNCTION_HEADER_3(Laplace1, pInputImage, pOutputImage, bAbsoluteValue)
01109                 
01110         if (pInputImage->width != pOutputImage->width || pInputImage->height != pOutputImage->height ||
01111                 pInputImage->type != CByteImage::eGrayScale)
01112         {
01113                 printf("error: input and output image do not match for ImageProcessor::Laplace1\n");
01114                 return false;
01115         }
01116         
01117         ZeroFrame(pOutputImage);
01118 
01119         const int maxj = pInputImage->width - 1, maxi = pInputImage->height - 1;
01120         const int width = pInputImage->width;
01121         const unsigned char *input = pInputImage->pixels;
01122         short *output = pOutputImage->pixels;
01123 
01124         if (bAbsoluteValue)
01125         {
01126                 for (int i = 1, offset = width + 1; i < maxi; i++, offset += 2)
01127                 {
01128                         for (int j = 1; j < maxj; j++, offset++)
01129                         {
01130                                 output[offset] =
01131                                         abs(input[offset - width] +
01132                                         input[offset - 1] - (input[offset] << 2) + input[offset + 1] + 
01133                                         input[offset + width]);
01134                         }
01135                 }
01136         }
01137         else
01138         {
01139                 for (int i = 1, offset = width + 1; i < maxi; i++, offset += 2)
01140                 {
01141                         for (int j = 1; j < maxj; j++, offset++)
01142                         {
01143                                 output[offset] =
01144                                         input[offset - width] +
01145                                         input[offset - 1] - (input[offset] << 2) + input[offset + 1] + 
01146                                         input[offset + width];
01147                         }
01148                 }
01149         }
01150         
01151         OPTIMIZED_FUNCTION_FOOTER
01152 
01153         return true;
01154 }
01155 
01156 bool ImageProcessor::Laplace2(const CByteImage *pInputImage, CShortImage *pOutputImage, bool bAbsoluteValue)
01157 {
01158         OPTIMIZED_FUNCTION_HEADER_3(Laplace2, pInputImage, pOutputImage, bAbsoluteValue)
01159 
01160         if (pInputImage->width != pOutputImage->width || pInputImage->height != pOutputImage->height ||
01161                 pInputImage->type != CByteImage::eGrayScale)
01162         {
01163                 printf("error: input and output image do not match for ImageProcessor::Laplace2\n");
01164                 return false;
01165         }
01166         
01167         ZeroFrame(pOutputImage);
01168 
01169         const int maxj = pInputImage->width - 1, maxi = pInputImage->height - 1;
01170         const int width = pInputImage->width;
01171         const unsigned char *input = pInputImage->pixels;
01172         short *output = pOutputImage->pixels;
01173 
01174         if (bAbsoluteValue)
01175         {
01176                 for (int i = 1, offset = width + 1; i < maxi; i++, offset += 2)
01177                 {
01178                         for (int j = 1; j < maxj; j++, offset++)
01179                         {
01180                                 output[offset] =
01181                                         abs(input[offset - width - 1] + input[offset - width] + input[offset - width + 1] +
01182                                         input[offset - 1] - (input[offset] << 3) + input[offset + 1] + 
01183                                         input[offset + width - 1] + input[offset + width] + input[offset + width + 1]);
01184                         }
01185                 }
01186         }
01187         else
01188         {
01189                 for (int i = 1, offset = width + 1; i < maxi; i++, offset += 2)
01190                 {
01191                         for (int j = 1; j < maxj; j++, offset++)
01192                         {
01193                                 output[offset] =
01194                                         input[offset - width - 1] + input[offset - width] + input[offset - width + 1] +
01195                                         input[offset - 1] - (input[offset] << 3) + input[offset + 1] + 
01196                                         input[offset + width - 1] + input[offset + width] + input[offset + width + 1];
01197                         }
01198                 }
01199         }
01200 
01201         OPTIMIZED_FUNCTION_FOOTER
01202 
01203         return true;
01204 }
01205 
01206 
01207 bool ImageProcessor::CalculateGradientImagePrewitt(const CByteImage *pInputImage, CByteImage *pOutputImage)
01208 {
01209         OPTIMIZED_FUNCTION_HEADER_2(CalculateGradientImagePrewitt, pInputImage, pOutputImage)
01210         
01211         if (pInputImage->width != pOutputImage->width || pInputImage->height != pOutputImage->height ||
01212                 pInputImage->type != CByteImage::eGrayScale)
01213         {
01214                 printf("error: input and output image do not match for ImageProcessor::CalculateGradientImagePrewitt\n");
01215                 return false;
01216         }
01217         
01218         CByteImage *pSaveOutputImage = 0;
01219         if (pInputImage->pixels == pOutputImage->pixels)
01220         {
01221                 pSaveOutputImage = pOutputImage;
01222                 pOutputImage = new CByteImage(pInputImage);
01223         }
01224         
01225         ZeroFrame(pOutputImage);
01226 
01227         const int maxu = pInputImage->width - 1, maxv = pInputImage->height - 1;
01228         const int width = pInputImage->width;
01229         const unsigned char *input = pInputImage->pixels;
01230         unsigned char *output = pOutputImage->pixels;
01231 
01232         for (int v = 1, offset = width + 1; v < maxv; v++, offset += 2)
01233         {
01234                 for (int u = 1; u < maxu; u++, offset++)
01235                 {
01236                         const int value_x = 
01237                                 abs(input[offset + width - 1] + input[offset + width] + input[offset + width + 1] -
01238                                 input[offset - width - 1] - input[offset - width] - input[offset - width + 1]);
01239                                 
01240                         const int value_y = 
01241                                 abs(input[offset - width + 1] + input[offset + 1] + input[offset + width + 1] -
01242                                 input[offset - width - 1] - input[offset - 1] - input[offset + width - 1]);
01243                         
01244                         const int value = value_x > value_y ? value_x : value_y;
01245 
01246                         output[offset] = value > 255 ? 255 : value;
01247                 }
01248         }
01249         
01250         if (pSaveOutputImage)
01251         {
01252                 CopyImage(pOutputImage, pSaveOutputImage);
01253                 delete pOutputImage;
01254         }
01255         
01256         OPTIMIZED_FUNCTION_FOOTER
01257 
01258         return true;
01259 }
01260 
01261 bool ImageProcessor::CalculateGradientImageSobel(const CByteImage *pInputImage, CByteImage *pOutputImage)
01262 {
01263         OPTIMIZED_FUNCTION_HEADER_2(CalculateGradientImageSobel, pInputImage, pOutputImage)
01264         
01265         if (pInputImage->width != pOutputImage->width || pInputImage->height != pOutputImage->height ||
01266                 pInputImage->type != CByteImage::eGrayScale)
01267         {
01268                 printf("error: input and output image do not match for ImageProcessor::CalculateGradientImageSobel\n");
01269                 return false;
01270         }
01271         
01272         CByteImage *pSaveOutputImage = 0;
01273         if (pInputImage->pixels == pOutputImage->pixels)
01274         {
01275                 pSaveOutputImage = pOutputImage;
01276                 pOutputImage = new CByteImage(pInputImage);
01277         }
01278         
01279         ZeroFrame(pOutputImage);
01280 
01281         const int maxu = pInputImage->width - 1, maxv = pInputImage->height - 1;
01282         const int width = pInputImage->width;
01283         const unsigned char *input = pInputImage->pixels;
01284         unsigned char *output = pOutputImage->pixels;
01285 
01286         for (int v = 1, offset = width + 1; v < maxv; v++, offset += 2)
01287         {
01288                 for (int u = 1; u < maxu; u++, offset++)
01289                 {
01290                         const int value_x = 
01291                                 abs(input[offset + width - 1] + (input[offset + width] << 1) + input[offset + width + 1] -
01292                                 input[offset - width - 1] - (input[offset - width] << 1) - input[offset - width + 1]);
01293                                 
01294                         const int value_y = 
01295                                 abs(input[offset - width + 1] + (input[offset + 1] << 1) + input[offset + width + 1] -
01296                                 input[offset - width - 1] - (input[offset - 1] << 1) - input[offset + width - 1]);
01297                         
01298                         const int value = value_x > value_y ? value_x : value_y;
01299                         
01300                         output[offset] = value > 255 ? 255 : value;
01301                 }
01302         }
01303         
01304         if (pSaveOutputImage)
01305         {
01306                 CopyImage(pOutputImage, pSaveOutputImage);
01307                 delete pOutputImage;
01308         }
01309         
01310         OPTIMIZED_FUNCTION_FOOTER
01311 
01312         return true;
01313 }
01314 
01315 bool ImageProcessor::CalculateGradientImage(const CByteImage *pInputImage, CByteImage *pOutputImage)
01316 {
01317         if (pInputImage->width != pOutputImage->width || pInputImage->height != pOutputImage->height)
01318         {
01319                 printf("error: input and output image do not match for ImageProcessor::CalculateGradientImage\n");
01320                 return false;
01321         }
01322         
01323         CByteImage *pSaveOutputImage = 0;
01324         if (pInputImage->pixels == pOutputImage->pixels)
01325         {
01326                 pSaveOutputImage = pOutputImage;
01327                 pOutputImage = new CByteImage(pInputImage);
01328         }
01329         
01330         ZeroFrame(pOutputImage);
01331 
01332         const int maxu = pInputImage->width - 1, maxv = pInputImage->height - 1;
01333         const int width = pInputImage->width;
01334         const unsigned char *input = pInputImage->pixels;
01335         unsigned char *output = pOutputImage->pixels;
01336 
01337         if (pInputImage->type == CByteImage::eGrayScale)
01338         {
01339                 for (int v = 1, offset = width + 1; v < maxv; v++, offset += 2)
01340                 {
01341                         for (int u = 1; u < maxu; u++, offset++)
01342                         {
01343                                 const int value_x = abs(input[offset + width] - input[offset - width]);
01344                                 const int value_y = abs(input[offset + 1] - input[offset - 1]);
01345                                 const int value = value_x > value_y ? value_x : value_y;
01346                                 output[offset] = value > 255 ? 255 : value;
01347                         }
01348                 }
01349         }
01350         else if (pInputImage->type == CByteImage::eRGB24)
01351         {
01352                 const unsigned char *input_r = pInputImage->pixels;
01353                 const unsigned char *input_g = pInputImage->pixels + 1;
01354                 const unsigned char *input_b = pInputImage->pixels + 2;
01355                 const int width3 = 3 * width;
01356         
01357                 for (int v = 1, offset = width3 + 3, output_offset = 0; v < maxv; v++, offset += 6, output_offset += 2)
01358                 {
01359                         for (int u = 1; u < maxu; u++, offset += 3, output_offset++)
01360                         {
01361                                 const int r1 = abs(input_r[offset + 3] - input_r[offset - 3]);
01362                                 const int r2 = abs(input_r[offset + width3] - input_r[offset - width3]);
01363                                 const int g1 = abs(input_g[offset + 3] - input_g[offset - 3]);
01364                                 const int g2 = abs(input_g[offset + width3] - input_g[offset - width3]);
01365                                 const int b1 = abs(input_b[offset + 3] - input_b[offset - 3]);
01366                                 const int b2 = abs(input_b[offset + width3] - input_b[offset - width3]);
01367                                 const int r = MY_MAX(r1, r2);
01368                                 const int g = MY_MAX(g1, g2);
01369                                 const int b = MY_MAX(b1, b2);
01370                                 const int value = r > g ? (r > b ? r : b) : (g > b ? g : b);
01371                                 output[output_offset] = value > 255 ? 255 : value;
01372                         }
01373                 }
01374         }
01375         
01376         if (pSaveOutputImage)
01377         {
01378                 CopyImage(pOutputImage, pSaveOutputImage);
01379                 delete pOutputImage;
01380         }
01381 
01382         return true;
01383 }
01384 
01385 bool ImageProcessor::CalculateGradientImageBinary(const CByteImage *pInputImage, CByteImage *pOutputImage)
01386 {
01387         if (pInputImage->width != pOutputImage->width || pInputImage->height != pOutputImage->height ||
01388                 pInputImage->type != CByteImage::eGrayScale || pOutputImage->type != CByteImage::eGrayScale)
01389         {
01390                 printf("error: input and output image do not match for ImageProcessor::CalculateGradientImageBinary\n");
01391                 return false;
01392         }
01393                 
01394         CByteImage *pSaveOutputImage = 0;
01395         if (pInputImage->pixels == pOutputImage->pixels)
01396         {
01397                 pSaveOutputImage = pOutputImage;
01398                 pOutputImage = new CByteImage(pInputImage);
01399         }
01400         
01401         ZeroFrame(pOutputImage);
01402 
01403         const int maxj = pInputImage->width - 1, maxi = pInputImage->height - 1;
01404         const int width = pInputImage->width;
01405         const unsigned char *input = pInputImage->pixels;
01406         unsigned char *output = pOutputImage->pixels;
01407         
01408         for (int i = 0, offset = 0; i < maxi; i++, offset++)
01409         {
01410                 for (int j = 0; j < maxj; j++, offset++)
01411                 {
01412                         output[offset] = (input[offset + 1] ^ input[offset]) | (input[offset] ^ input[offset + width]);
01413                 }
01414         }
01415         
01416         if (pSaveOutputImage)
01417         {
01418                 CopyImage(pOutputImage, pSaveOutputImage);
01419                 delete pOutputImage;
01420         }
01421 
01422         return true;
01423 }
01424 
01425 
01426 static bool Dilate3x3(const CByteImage *pInputImage, CByteImage *pOutputImage, const MyRegion *pROI)
01427 {
01428         OPTIMIZED_FUNCTION_HEADER_2_ROI(Dilate3x3, pInputImage, pOutputImage, pROI)
01429         
01430         if (pInputImage->width != pOutputImage->width || pInputImage->height != pOutputImage->height ||
01431                 pInputImage->type != pOutputImage->type || pInputImage->type != CByteImage::eGrayScale)
01432         {
01433                 printf("error: input and output image do not match for Dilate3x3\n");
01434                 return false;
01435         }
01436                 
01437         CByteImage *pSaveOutputImage = 0;
01438         if (pInputImage->pixels == pOutputImage->pixels)
01439         {
01440                 pSaveOutputImage = pOutputImage;
01441                 pOutputImage = new CByteImage(pInputImage);
01442         }
01443 
01444         ImageProcessor::Zero(pOutputImage, pROI);
01445 
01446         const int width = pInputImage->width;
01447         const int height = pInputImage->height;
01448         
01449         const unsigned char *input = pInputImage->pixels;
01450         unsigned char *output = pOutputImage->pixels;
01451 
01452         int min_u, max_u, min_v, max_v;
01453 
01454         if (pROI)
01455         {
01456                 min_u = pROI->min_x + 1;
01457                 max_u = pROI->max_x - 1;
01458                 min_v = pROI->min_y + 1;
01459                 max_v = pROI->max_y - 1;
01460 
01461                 if (min_u < 1) min_u = 1;
01462                 if (min_u > width - 2) min_u = width - 2;
01463                 if (max_u < 1) max_u = 1;
01464                 if (max_u > width - 2) max_u = width - 2;
01465                 if (min_v < 1) min_v = 1;
01466                 if (min_v > height - 2) min_v = height - 2;
01467                 if (max_v < 1) max_v = 1;
01468                 if (max_v > height - 2) max_v = height - 2;
01469         }
01470         else
01471         {
01472                 min_u = 1;
01473                 max_u = width - 2;
01474                 min_v = 1;
01475                 max_v = height - 2;
01476         }
01477 
01478         const int diff = width - (max_u - min_u + 1);
01479         
01480         bool *bLastY = new bool[width];
01481         memset(bLastY, false, width * sizeof(bool));
01482 
01483         for (int v = min_v, offset = min_v * width + min_u; v <= max_v; v++, offset += diff)
01484         {
01485                 bool bLastX = false;
01486                 
01487                 for (int u = min_u; u <= max_u; u++, offset++)
01488                 {
01489                         if (input[offset])
01490                         {
01491                                 if (bLastX)
01492                                 {
01493                                         if (bLastY[u])
01494                                         {
01495                                                 output[offset + width + 1] = 255;
01496                                         }
01497                                         else
01498                                         {
01499                                                 output[offset - width + 1] = 255;
01500                                                 output[offset + 1] = 255;
01501                                                 output[offset + width + 1] = 255;
01502                                                 
01503                                                 bLastY[u] = true;
01504                                         }
01505                                 }
01506                                 else
01507                                 {
01508                                         if (bLastY[u])
01509                                         {
01510                                                 output[offset + width - 1] = 255;
01511                                                 output[offset + width] = 255;
01512                                                 output[offset + width + 1] = 255;
01513                                         }
01514                                         else
01515                                         {
01516                                                 output[offset - width - 1] = 255;
01517                                                 output[offset - width] = 255;
01518                                                 output[offset - width + 1] = 255;
01519                                                 output[offset - 1] = 255;
01520                                                 output[offset] = 255;
01521                                                 output[offset + 1] = 255;
01522                                                 output[offset + width - 1] = 255;
01523                                                 output[offset + width] = 255;
01524                                                 output[offset + width + 1] = 255;
01525                                                 
01526                                                 bLastY[u] = true;
01527                                         }
01528                                         
01529                                         bLastX = true;
01530                                 }
01531                         }
01532                         else
01533                         {
01534                                 bLastX = false;
01535                                 bLastY[u] = false;
01536                         }
01537                 }
01538         }
01539         
01540         delete [] bLastY;
01541 
01542         if (pSaveOutputImage)
01543         {
01544                 ImageProcessor::CopyImage(pOutputImage, pSaveOutputImage, pROI, true);
01545                 delete pOutputImage;
01546         }
01547         
01548         OPTIMIZED_FUNCTION_FOOTER
01549 
01550         return true;
01551 }
01552 
01553 static bool Erode3x3(const CByteImage *pInputImage, CByteImage *pOutputImage, const MyRegion *pROI)
01554 {
01555         OPTIMIZED_FUNCTION_HEADER_2_ROI(Erode3x3, pInputImage, pOutputImage, pROI)
01556         
01557         if (pInputImage->width != pOutputImage->width || pInputImage->height != pOutputImage->height ||
01558                 pInputImage->type != pOutputImage->type || pInputImage->type != CByteImage::eGrayScale)
01559         {
01560                 printf("error: input and output image do not match for Erode3x3\n");
01561                 return false;
01562         }
01563                 
01564         CByteImage *pSaveOutputImage = 0;
01565         if (pInputImage->pixels == pOutputImage->pixels)
01566         {
01567                 pSaveOutputImage = pOutputImage;
01568                 pOutputImage = new CByteImage(pInputImage);
01569         }
01570 
01571         ImageProcessor::Zero(pOutputImage, pROI);
01572 
01573         const int width = pInputImage->width;
01574         const int height = pInputImage->height;
01575         
01576         const unsigned char *input = pInputImage->pixels;
01577         unsigned char *output = pOutputImage->pixels;
01578 
01579         int min_u, max_u, min_v, max_v;
01580 
01581         if (pROI)
01582         {
01583                 min_u = pROI->min_x + 1;
01584                 max_u = pROI->max_x - 1;
01585                 min_v = pROI->min_y + 1;
01586                 max_v = pROI->max_y - 1;
01587 
01588                 if (min_u < 1) min_u = 1;
01589                 if (min_u > width - 2) min_u = width - 2;
01590                 if (max_u < 1) max_u = 1;
01591                 if (max_u > width - 2) max_u = width - 2;
01592                 if (min_v < 1) min_v = 1;
01593                 if (min_v > height - 2) min_v = height - 2;
01594                 if (max_v < 1) max_v = 1;
01595                 if (max_v > height - 2) max_v = height - 2;
01596         }
01597         else
01598         {
01599                 min_u = 1;
01600                 max_u = width - 2;
01601                 min_v = 1;
01602                 max_v = height - 2;
01603         }
01604 
01605         const int diff = width - (max_u - min_u + 1);
01606 
01607         bool *bLastY = new bool[width];
01608         memset(bLastY, false, width * sizeof(bool));
01609 
01610         for (int v = min_v, offset = min_v * width + min_u; v <= max_v; v++, offset += diff)
01611         {
01612                 bool bLastX = false;
01613                 
01614                 for (int u = min_u; u <= max_u; u++, offset++)
01615                 {
01616                         if (bLastX)
01617                         {
01618                                 if (bLastY[u])
01619                                 {
01620                                         if (!input[offset + width + 1])
01621                                         {
01622                                                 bLastX = false;
01623                                                 bLastY[u] = false;
01624                                                 continue;
01625                                         }
01626                                 }
01627                                 else
01628                                 {
01629                                         if (!input[offset - width + 1] || !input[offset + 1] || !input[offset + width + 1])
01630                                         {
01631                                                 bLastX = false;
01632                                                 continue;
01633                                         }
01634                                         else
01635                                         {
01636                                                 bLastY[u] = true;
01637                                         }
01638                                 }
01639                         }
01640                         else
01641                         {
01642                                 if (bLastY[u])
01643                                 {
01644                                         if (!input[offset + width - 1] || !input[offset + width] || !input[offset + width + 1])
01645                                         {
01646                                                 bLastY[u] = false;
01647                                                 continue;
01648                                         }
01649                                         else
01650                                         {
01651                                                 bLastX = true;
01652                                         }
01653                                 }
01654                                 else
01655                                 {
01656                                         if (!input[offset - width - 1] || !input[offset - width] || !input[offset - width + 1] ||
01657                                                 !input[offset - 1] || !input[offset] || !input[offset + 1] ||
01658                                                 !input[offset + width - 1] || !input[offset + width] || !input[offset + width + 1])
01659                                         {
01660                                                 continue;
01661                                         }
01662                                         else
01663                                         {
01664                                                 bLastX = true;
01665                                                 bLastY[u] = true;
01666                                         }
01667                                 }
01668                         }
01669                         
01670                         output[offset] = 255;
01671                 }
01672         }
01673         
01674         delete [] bLastY;
01675 
01676         if (pSaveOutputImage)
01677         {
01678                 ImageProcessor::CopyImage(pOutputImage, pSaveOutputImage, pROI, true);
01679                 delete pOutputImage;
01680         }
01681         
01682         OPTIMIZED_FUNCTION_FOOTER
01683 
01684         return true;
01685 }
01686 
01687 bool ImageProcessor::Dilate(const CByteImage *pInputImage, CByteImage *pOutputImage, int nMaskSize, const MyRegion *pROI)
01688 {
01689         if (nMaskSize == 3)
01690         {
01691                 Dilate3x3(pInputImage, pOutputImage, pROI);
01692                 return false;
01693         }
01694 
01695         if (nMaskSize < 2)
01696         {
01697                 printf("error: mask size is too small for ImageProcessor::Dilate\n");
01698                 return false;
01699         }
01700         
01701         if (pInputImage->width != pOutputImage->width || pInputImage->height != pOutputImage->height ||
01702                 pInputImage->type != pOutputImage->type || pInputImage->type != CByteImage::eGrayScale)
01703         {
01704                 printf("error: input and output image do not match for ImageProcessor::Dilate\n");
01705                 return false;
01706         }
01707 
01708         const int k = (nMaskSize - 1) / 2;
01709                 
01710         CByteImage *pSaveOutputImage = 0;
01711         if (pInputImage->pixels == pOutputImage->pixels)
01712         {
01713                 pSaveOutputImage = pOutputImage;
01714                 pOutputImage = new CByteImage(pInputImage);
01715         }
01716 
01717         ImageProcessor::Zero(pOutputImage, pROI);
01718 
01719         const int width = pInputImage->width;
01720         const int height = pInputImage->height;
01721         
01722         const unsigned char *input = pInputImage->pixels;
01723         unsigned char *output = pOutputImage->pixels;
01724 
01725         int min_u, max_u, min_v, max_v;
01726 
01727         if (pROI)
01728         {
01729                 min_u = pROI->min_x + 1;
01730                 max_u = pROI->max_x - 1;
01731                 min_v = pROI->min_y + 1;
01732                 max_v = pROI->max_y - 1;
01733 
01734                 if (min_u < k) min_u = k;
01735                 if (min_u > width - 1 - k) min_u = width - 1 - k;
01736                 if (max_u < k) max_u = k;
01737                 if (max_u > width - 1 - k) max_u = width - 1 - k;
01738                 if (min_v < k) min_v = k;
01739                 if (min_v > height - 1 - k) min_v = height - 1 - k;
01740                 if (max_v < k) max_v = k;
01741                 if (max_v > height - 1 - k) max_v = height - 1 - k;
01742         }
01743         else
01744         {
01745                 min_u = k;
01746                 max_u = width - 1 - k;
01747                 min_v = k;
01748                 max_v = height - 1 - k;
01749         }
01750 
01751         const int diff = width - (max_u - min_u + 1);
01752         
01753         bool *bLastY = new bool[width];
01754         memset(bLastY, false, width * sizeof(bool));
01755 
01756         for (int v = min_v, offset = min_v * width + min_u; v <= max_v; v++, offset += diff)
01757         {
01758                 bool bLastX = false;
01759 
01760                 for (int u = min_u; u <= max_u; u++, offset++)
01761                 {
01762                         if (input[offset])
01763                         {
01764                                 if (bLastX)
01765                                 {
01766                                         if (bLastY[u])
01767                                         {
01768                                                 output[offset + k * width + k] = 255;
01769                                         }
01770                                         else
01771                                         {
01772                                                 for (int i = -k; i <= k; i++)
01773                                                         output[offset + i * width + k] = 255;
01774                                                 
01775                                                 bLastY[u] = true;
01776                                         }
01777                                 }
01778                                 else
01779                                 {
01780                                         if (bLastY[u])
01781                                         {
01782                                                 for (int i = -k; i <= k; i++)
01783                                                         output[offset + k * width + i] = 255;
01784                                         }
01785                                         else
01786                                         {
01787                                                 for (int i = -k; i <= k; i++)
01788                                                         for (int j = -k; j <= k; j++)
01789                                                                 output[offset + i * width + j] = 255;
01790                                                 
01791                                                 bLastY[u] = true;
01792                                         }
01793                                         
01794                                         bLastX = true;
01795                                 }
01796                         }
01797                         else
01798                         {
01799                                 bLastX = false;
01800                                 bLastY[u] = false;
01801                         }
01802                 }
01803         }
01804         
01805         delete [] bLastY;
01806         
01807         if (pSaveOutputImage)
01808         {
01809                 CopyImage(pOutputImage, pSaveOutputImage, pROI, true);
01810                 delete pOutputImage;
01811         }
01812 
01813         return true;
01814 }
01815 
01816 bool ImageProcessor::Erode(const CByteImage *pInputImage, CByteImage *pOutputImage, int nMaskSize, const MyRegion *pROI)
01817 {
01818         if (nMaskSize == 3)
01819         {
01820                 Erode3x3(pInputImage, pOutputImage, pROI);
01821                 return false;
01822         }
01823 
01824         if (nMaskSize < 2)
01825         {
01826                 printf("error: mask size is too small for ImageProcessor::Erode\n");
01827                 return false;
01828         }
01829         
01830         if (pInputImage->width != pOutputImage->width || pInputImage->height != pOutputImage->height ||
01831                 pInputImage->type != pOutputImage->type || pInputImage->type != CByteImage::eGrayScale)
01832         {
01833                 printf("error: input and output image do not match for ImageProcessor::Erode\n");
01834                 return false;
01835         }
01836 
01837         const int k = (nMaskSize - 1) / 2;
01838                 
01839         CByteImage *pSaveOutputImage = 0;
01840         if (pInputImage->pixels == pOutputImage->pixels)
01841         {
01842                 pSaveOutputImage = pOutputImage;
01843                 pOutputImage = new CByteImage(pInputImage);
01844         }
01845 
01846         ImageProcessor::Zero(pOutputImage, pROI);
01847 
01848         const int width = pInputImage->width;
01849         const int height = pInputImage->height;
01850         
01851         const unsigned char *input = pInputImage->pixels;
01852         unsigned char *output = pOutputImage->pixels;
01853 
01854         int min_u, max_u, min_v, max_v;
01855 
01856         if (pROI)
01857         {
01858                 min_u = pROI->min_x + 1;
01859                 max_u = pROI->max_x - 1;
01860                 min_v = pROI->min_y + 1;
01861                 max_v = pROI->max_y - 1;
01862 
01863                 if (min_u < k) min_u = k;
01864                 if (min_u > width - 1 - k) min_u = width - 1 - k;
01865                 if (max_u < k) max_u = k;
01866                 if (max_u > width - 1 - k) max_u = width - 1 - k;
01867                 if (min_v < k) min_v = k;
01868                 if (min_v > height - 1 - k) min_v = height - 1 - k;
01869                 if (max_v < k) max_v = k;
01870                 if (max_v > height - 1 - k) max_v = height - 1 - k;
01871         }
01872         else
01873         {
01874                 min_u = k;
01875                 max_u = width - 1 - k;
01876                 min_v = k;
01877                 max_v = height - 1 - k;
01878         }
01879 
01880         const int diff = width - (max_u - min_u + 1);
01881         
01882         bool *bLastY = new bool[width];
01883         memset(bLastY, false, width * sizeof(bool));
01884 
01885         for (int v = min_v, offset = min_v * width + min_u; v <= max_v; v++, offset += diff)
01886         {
01887                 bool bLastX = false;
01888 
01889                 for (int u = min_u; u <= max_u; u++)
01890                 {
01891                         if (bLastX)
01892                         {
01893                                 if (bLastY[u])
01894                                 {
01895                                         if (!input[offset + k * width + k])
01896                                         {
01897                                                 bLastX = false;
01898                                                 bLastY[u] = false;
01899                                                 goto next;
01900                                         }
01901                                 }
01902                                 else
01903                                 {
01904                                         for (int i = -k; i <= k; i++)
01905                                                 if (!input[offset + i * width + k])
01906                                                 {
01907                                                         bLastX = false;
01908                                                         goto next;
01909                                                 }
01910 
01911                                         bLastY[u] = true;
01912                                 }
01913                         }
01914                         else
01915                         {
01916                                 if (bLastY[u])
01917                                 {
01918                                         for (int i = -k; i <= k; i++)
01919                                                 if (!input[offset + k * width + i])
01920                                                 {
01921                                                         bLastY[u] = false;
01922                                                         goto next;
01923                                                 }
01924                                 }
01925                                 else
01926                                 {
01927                                         for (int i = -k; i <= k; i++)
01928                                                 for (int j = -k; j <= k; j++)
01929                                                         if (!input[offset + i * width + j])
01930                                                                 goto next;
01931 
01932                                         bLastY[u] = true;
01933                                 }
01934                                 
01935                                 bLastX = true;
01936                         }
01937                                 
01938                         output[offset] = 255;
01939                         
01940                         next:
01941                         
01942                         offset++;
01943                 }
01944         }
01945         
01946         delete [] bLastY;
01947         
01948         if (pSaveOutputImage)
01949         {
01950                 CopyImage(pOutputImage, pSaveOutputImage, pROI, true);
01951                 delete pOutputImage;
01952         }
01953 
01954         return true;
01955 }
01956 
01957 
01958 bool ImageProcessor::HistogramEqualization(const CByteImage *pInputImage, CByteImage *pOutputImage)
01959 {
01960         if (pInputImage->width != pOutputImage->width || pInputImage->height != pOutputImage->height ||
01961                 pInputImage->type != CByteImage::eGrayScale || pOutputImage->type != CByteImage::eGrayScale)
01962         {
01963                 printf("error: input and output image do not match for ImageProcessor::HistogramEqualization\n");
01964                 return false;
01965         }
01966         
01967         const int nPixels = pInputImage->width * pInputImage->height;
01968         const unsigned char *input = pInputImage->pixels;
01969         unsigned char *output = pOutputImage->pixels;
01970         const float fNormalizeConstant = 255.0f / nPixels;
01971         int histogram[256] = { 0 };
01972         int i;
01973 
01974         // calculate histogram
01975         for (i = 0; i < nPixels; i++)
01976                 histogram[input[i]]++;
01977 
01978         // calculate normalized accumulated histogram
01979         for (i = 1; i < 256; i++)
01980                 histogram[i] += histogram[i - 1];
01981 
01982         for (i = 0; i < 256; i++)
01983                 histogram[i] = int(histogram[i] * fNormalizeConstant + 0.5f);
01984 
01985         // apply normalization
01986         for (i = 0; i < nPixels; i++)
01987                 output[i] = histogram[input[i]];
01988 
01989         return true;
01990 }
01991 
01992 
01993 bool ImageProcessor::ApplyAffinePointOperation(const CByteImage *pInputImage, CByteImage *pOutputImage, float a, float b)
01994 {
01995         OPTIMIZED_FUNCTION_HEADER_4(ApplyAffinePointOperation, pInputImage, pOutputImage, a, b)
01996         
01997         if (!pInputImage->IsCompatible(pOutputImage))
01998         {
01999                 printf("error: input and output image do not match for ImageProcessor::ApplyAffinePointOperation\n");
02000                 return false;
02001         }
02002         
02003         const int nBytes = pInputImage->width * pInputImage->height * pInputImage->bytesPerPixel;
02004         const unsigned char *input = pInputImage->pixels;
02005         unsigned char *output = pOutputImage->pixels;
02006         
02007         b += 0.5f;
02008         
02009         for (int i = 0; i < nBytes; i++)
02010         {
02011                 const int v = int(a * input[i] + b);
02012                 output[i] = v < 0 ? 0 : (v > 255 ? 255 : (unsigned char) v);
02013         }
02014         
02015         OPTIMIZED_FUNCTION_FOOTER
02016 
02017         return true;
02018 }
02019 
02020 
02021 bool ImageProcessor::Spread(const CByteImage *pInputImage, CByteImage *pOutputImage)
02022 {
02023         if (pInputImage->width != pOutputImage->width || pInputImage->height != pOutputImage->height ||
02024                 pInputImage->type != CByteImage::eGrayScale || pOutputImage->type != CByteImage::eGrayScale)
02025         {
02026                 printf("error: input and output image do not match for ImageProcessor::Spread\n");
02027                 return false;
02028         }
02029         
02030         const int nPixels = pInputImage->width * pInputImage->height;
02031         const unsigned char *input = pInputImage->pixels;
02032         unsigned char min = 255, max = 0;
02033 
02034         // calculate histogram
02035         for (int i = 0; i < nPixels; i++)
02036         {
02037                 if (input[i] < min)
02038                         min = input[i];
02039                         
02040                 if (input[i] > max)
02041                         max = input[i];
02042         }
02043         
02044         if (min == max)
02045         {
02046                 printf("error: input image is homogenous with gray value %i\n", min);
02047                 return false;
02048         }
02049 
02050         const float a = 255.0f / (max - min);
02051         const float b = -(min * 255.0f) / (max - min);
02052         
02053         ApplyAffinePointOperation(pInputImage, pOutputImage, a, b);
02054 
02055         return true;
02056 }
02057 
02058 bool ImageProcessor::HistogramStretching(const CByteImage *pInputImage, CByteImage *pOutputImage, float p_min, float p_max)
02059 {
02060         if (pInputImage->width != pOutputImage->width || pInputImage->height != pOutputImage->height ||
02061                 pInputImage->type != CByteImage::eGrayScale || pOutputImage->type != CByteImage::eGrayScale)
02062         {
02063                 printf("error: input and output image do not match for ImageProcessor::HistogramStretching\n");
02064                 return false;
02065         }
02066         
02067         const int nPixels = pInputImage->width * pInputImage->height;
02068         const unsigned char *input = pInputImage->pixels;
02069         int histogram[256] = { 0 };
02070         int i;
02071 
02072         // calculate histogram
02073         for (i = 0; i < nPixels; i++)
02074                 histogram[input[i]]++;
02075 
02076         // calculate accumulated histogram
02077         for (i = 1; i < 256; i++)
02078                 histogram[i] += histogram[i - 1];
02079 
02080         const float nMinValue = p_min * histogram[255];
02081         const float nMaxValue = p_max * histogram[255];
02082         int min = 0, max = 0;
02083         
02084         for (i = 0; i < 256; i++)
02085         {
02086                 if (histogram[i] >= nMinValue)
02087                 {
02088                         min = i;
02089                         break;
02090                 }
02091         }
02092         
02093         for (i = 0; i < 256; i++)
02094         {
02095                 if (histogram[i] >= nMaxValue)
02096                 {
02097                         max = i;
02098                         break;
02099                 }
02100         }
02101         
02102         if (min == max)
02103         {
02104                 printf("error: input image is homogenous with gray value %i\n", min);
02105                 return false;
02106         }
02107         
02108         const float a = 255.0f / (max - min);
02109         const float b = -(min * 255.0f) / (max - min);
02110         
02111         ApplyAffinePointOperation(pInputImage, pOutputImage, a, b);
02112 
02113         return true;
02114 }
02115 
02116 bool ImageProcessor::Invert(const CByteImage *pInputImage, CByteImage *pOutputImage)
02117 {
02118         OPTIMIZED_FUNCTION_HEADER_2(Invert, pInputImage, pOutputImage)
02119         
02120         if (!pInputImage->IsCompatible(pOutputImage))
02121         {
02122                 printf("error: input and output image do not match for ImageProcessor::Invert\n");
02123                 return false;
02124         }
02125 
02126         const int nBytes = pInputImage->width * pInputImage->height * pInputImage->bytesPerPixel;
02127         const unsigned char *input = pInputImage->pixels;
02128         unsigned char *output = pOutputImage->pixels;
02129         
02130         for (int i = 0; i < nBytes; i++)
02131                 output[i] = 255 - input[i];
02132         
02133         OPTIMIZED_FUNCTION_FOOTER
02134 
02135         return true;
02136 }
02137 
02138 
02139 bool ImageProcessor::ConvertImage(const CByteImage *pInputImage, CByteImage *pOutputImage, bool bFast, const MyRegion *pROI)
02140 {
02141         OPTIMIZED_FUNCTION_HEADER_3_ROI(ConvertImage, pInputImage, pOutputImage, bFast, pROI)
02142         
02143         if (pInputImage->width != pOutputImage->width || pInputImage->height != pOutputImage->height)
02144         {
02145                 printf("error: input and output image do not match for ImageProcessor::ConvertImage\n");
02146                 return false;
02147         }
02148         
02149         if (pInputImage->type == pOutputImage->type)
02150         {
02151                 CopyImage(pInputImage, pOutputImage, pROI, true);
02152                 return true;
02153         }
02154         
02155         const int nPixels = pInputImage->width * pInputImage->height;
02156 
02157         const unsigned char *input = pInputImage->pixels;
02158         unsigned char *output = pOutputImage->pixels;
02159         
02160         if (pROI)
02161         {
02162                 const int width = pInputImage->width;
02163                 const int height = pInputImage->height;
02164 
02165                 int min_x = pROI->min_x;
02166                 int max_x = pROI->max_x;
02167                 int min_y = pROI->min_y;
02168                 int max_y = pROI->max_y;
02169 
02170                 if (min_x < 0) min_x = 0;
02171                 if (min_x > width - 1) min_x = width - 1;
02172                 if (max_x < 0) max_x = 0;
02173                 if (max_x > width - 1) max_x = width - 1;
02174                 if (min_y < 0) min_y = 0;
02175                 if (min_y > height - 1) min_y = height - 1;
02176                 if (max_y < 0) max_y = 0;
02177                 if (max_y > height - 1) max_y = height - 1;
02178 
02179                 const int diff = width - (max_x - min_x + 1);
02180                 const int diff_rgb = 3 * diff;
02181 
02182                 if (pInputImage->type == CByteImage::eRGB24)
02183                 {
02184                         if (pOutputImage->type == CByteImage::eGrayScale)
02185                         {
02186                                 if (bFast)
02187                                 {
02188                                         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)
02189                                                 for (int x = min_x; x <= max_x; x++, offset_output++, offset_input += 3)
02190                                                         output[offset_output] = (input[offset_input] + (input[offset_input + 1] << 1) + input[offset_input + 2] + 2) >> 2;
02191                                 }
02192                                 else
02193                                 {
02194                                         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)
02195                                                 for (int x = min_x; x <= max_x; x++, offset_output++, offset_input += 3)
02196                                                         output[offset_output] = (9797 * input[offset_input] + 19235 * input[offset_input + 1] + 3736 * input[offset_input + 2] + 16384) >> 15;
02197                                 }
02198                         }
02199                         else if (pOutputImage->type == CByteImage::eRGB24Split)
02200                         {
02201                                 unsigned char *pHelperR = output;
02202                                 unsigned char *pHelperG = pHelperR + nPixels;
02203                                 unsigned char *pHelperB = pHelperG + nPixels;
02204                                 
02205                                 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)
02206                                         for (int x = min_x; x <= max_x; x++, offset_output++, offset_input += 3)
02207                                         {
02208                                                 pHelperR[offset_output] = input[offset_input];
02209                                                 pHelperG[offset_output] = input[offset_input + 1];
02210                                                 pHelperB[offset_output] = input[offset_input + 2];
02211                                         }
02212                         }
02213                 }
02214                 if (pInputImage->type == CByteImage::eRGB24Split)
02215                 {
02216                         const unsigned char *pHelperR = input;
02217                         const unsigned char *pHelperG = pHelperR + nPixels;
02218                         const unsigned char *pHelperB = pHelperG + nPixels;
02219                         
02220                         if (pOutputImage->type == CByteImage::eGrayScale)
02221                         {
02222                                 if (bFast)
02223                                 {
02224                                         for (int y = min_y, offset = width * min_y + min_x; y <= max_y; y++, offset += diff)
02225                                                 for (int x = min_x; x <= max_x; x++, offset++)
02226                                                         output[offset] = (pHelperR[offset] + (pHelperG[offset] << 1) + pHelperB[offset] + 2) >> 2;
02227                                 }
02228                                 else
02229                                 {
02230                                         for (int y = min_y, offset = width * min_y + min_x; y <= max_y; y++, offset += diff)
02231                                                 for (int x = min_x; x <= max_x; x++, offset++)
02232                                                         output[offset] = (9797 * pHelperR[offset] + 19235 * pHelperG[offset] + 3736 * pHelperB[offset] + 16384) >> 15;
02233                                 }
02234                         }
02235                         else if (pOutputImage->type == CByteImage::eRGB24)
02236                         {
02237                                 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)
02238                                         for (int x = min_x; x <= max_x; x++, input_offset++, output_offset += 3)
02239                                         {
02240                                                 output[output_offset] = pHelperR[input_offset];
02241                                                 output[output_offset + 1] = pHelperG[input_offset];
02242                                                 output[output_offset + 2] = pHelperB[input_offset];
02243                                         }
02244                         }
02245                 }
02246                 else if (pInputImage->type == CByteImage::eGrayScale)
02247                 {
02248                         if (pOutputImage->type == CByteImage::eRGB24)
02249                         {
02250                                 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)
02251                                         for (int x = min_x; x <= max_x; x++, offset_output += 3, offset_input++)
02252                                         {
02253                                                 output[offset_output + 2] = input[offset_input];
02254                                                 output[offset_output + 1] = input[offset_input];
02255                                                 output[offset_output] = input[offset_input];
02256                                         }
02257                         }
02258                         else if (pOutputImage->type == CByteImage::eRGB24Split)
02259                         {
02260                                 unsigned char *pHelperR = output;
02261                                 unsigned char *pHelperG = pHelperR + nPixels;
02262                                 unsigned char *pHelperB = pHelperG + nPixels;
02263                                 
02264                                 for (int y = min_y, offset = width * min_y + min_x; y <= max_y; y++, offset += diff)
02265                                         for (int x = min_x; x <= max_x; x++, offset++)
02266                                                 pHelperR[offset] = pHelperG[offset] = pHelperB[offset] = input[offset];
02267                         }
02268                 }
02269         }
02270         else
02271         {
02272                 if (pInputImage->type == CByteImage::eRGB24)
02273                 {
02274                         if (pOutputImage->type == CByteImage::eGrayScale)
02275                         {
02276                                 if (bFast)
02277                                 {
02278                                         for (int offset = 0, i = 0; i < nPixels; i++, offset += 3)
02279                                                 output[i] = (input[offset] + (input[offset + 1] << 1) + input[offset + 2] + 2) >> 2;
02280                                 }
02281                                 else
02282                                 {
02283                                         for (int offset = 0, i = 0; i < nPixels; i++, offset += 3)
02284                                                 output[i] = (9797 * input[offset] + 19235 * input[offset + 1] + 3736 * input[offset + 2] + 16384) >> 15;
02285                                 }
02286                         }
02287                         else if (pOutputImage->type == CByteImage::eRGB24Split)
02288                         {
02289                                 unsigned char *pHelperR = output;
02290                                 unsigned char *pHelperG = pHelperR + nPixels;
02291                                 unsigned char *pHelperB = pHelperG + nPixels;
02292                                 
02293                                 for (int offset = 0, i = 0; i < nPixels; i++, offset += 3)
02294                                 {
02295                                         pHelperR[i] = input[offset];
02296                                         pHelperG[i] = input[offset + 1];
02297                                         pHelperB[i] = input[offset + 2];
02298                                 }
02299                         }
02300                 }
02301                 else if (pInputImage->type == CByteImage::eRGB24Split)
02302                 {
02303                         const unsigned char *pHelperR = input;
02304                         const unsigned char *pHelperG = pHelperR + nPixels;
02305                         const unsigned char *pHelperB = pHelperG + nPixels;
02306                         
02307                         if (pOutputImage->type == CByteImage::eGrayScale)
02308                         {
02309                                 if (bFast)
02310                                 {
02311                                         for (int i = 0; i < nPixels; i++)
02312                                                 output[i] = (pHelperR[i] + (pHelperG[i] << 1) + pHelperB[i] + 2) >> 2;
02313                                 }
02314                                 else
02315                                 {
02316                                         for (int i = 0; i < nPixels; i++)
02317                                                 output[i] = (9797 * pHelperR[i] + 19235 * pHelperG[i] + 3736 * pHelperB[i] + 16384) >> 15;
02318                                 }
02319                         }
02320                         else if (pOutputImage->type == CByteImage::eRGB24)
02321                         {
02322                                 for (int offset = 0, i = 0; i < nPixels; i++, offset += 3)
02323                                 {
02324                                         output[offset] = pHelperR[i];
02325                                         output[offset + 1] = pHelperG[i];
02326                                         output[offset + 2] = pHelperB[i];
02327                                 }
02328                         }
02329                 }
02330                 else if (pInputImage->type == CByteImage::eGrayScale)
02331                 {
02332                         if (pOutputImage->type == CByteImage::eRGB24)
02333                         {
02334                                 for (int offset = 0, i = 0; i < nPixels; i++, offset += 3)
02335                                 {
02336                                         output[offset + 2] = input[i];
02337                                         output[offset + 1] = input[i];
02338                                         output[offset] = input[i];
02339                                 }
02340                         }
02341                         else if (pOutputImage->type == CByteImage::eRGB24Split)
02342                         {
02343                                 unsigned char *pHelperR = output;
02344                                 unsigned char *pHelperG = pHelperR + nPixels;
02345                                 unsigned char *pHelperB = pHelperG + nPixels;
02346                                 
02347                                 for (int i = 0; i < nPixels; i++)
02348                                         pHelperR[i] = pHelperG[i] = pHelperB[i] = input[i];
02349                         }
02350                 }
02351         }
02352         
02353         OPTIMIZED_FUNCTION_FOOTER
02354 
02355         return true;
02356 }
02357 
02358 
02359 bool ImageProcessor::ConvertImage(const CFloatImage *pInputImage, CByteImage *pOutputImage, bool equalize)
02360 {
02361     if(pInputImage->numberOfChannels == 1 && pOutputImage->type != CByteImage::eGrayScale)
02362     {
02363         printf("error: ImageProcessor::ConvertImage cannot convert a single channel float image into mulitple channel byte image\n");
02364         return false;
02365     }
02366 
02367     if(pInputImage->numberOfChannels == 3 && pOutputImage->type == CByteImage::eGrayScale)
02368     {
02369         printf("error: ImageProcessor::ConvertImage cannot convert a 3 channel float image into single channel byte image\n");
02370         return false;
02371     }
02372 
02373     if (pInputImage->width != pOutputImage->width || pInputImage->height != pOutputImage->height)
02374     {
02375         printf("error: input and output image dimensions do not match for ImageProcessor::ConvertImage\n");
02376         return false;
02377     }
02378 
02379     const int nPixels = pInputImage->width * pInputImage->height;
02380     const float* input = pInputImage->pixels;
02381     unsigned char* output = pOutputImage->pixels;
02382     float* min = new float[pInputImage->numberOfChannels];
02383     float* max = new float[pInputImage->numberOfChannels];
02384     float* factor = new float[pInputImage->numberOfChannels];
02385     int i, j;
02386     int pixelChannelIndex;
02387     for (i = 0; i < pInputImage->numberOfChannels; i++)
02388     {
02389         min[i] = FLT_MAX;
02390         max[i] = -FLT_MAX;
02391     }
02392 
02393     for (i = 0; i < nPixels; i++)
02394     {
02395         for (j = 0; j < pInputImage->numberOfChannels; j++)
02396         {
02397             pixelChannelIndex = i * pInputImage->numberOfChannels + j;
02398 
02399             if (input[pixelChannelIndex] > max[j])
02400             {
02401                 max[j] = input[pixelChannelIndex];
02402             }
02403 
02404             if (input[pixelChannelIndex] < min[j])
02405             {
02406                 min[j] = input[pixelChannelIndex];
02407             }
02408         }
02409     }
02410 
02411     if (equalize)
02412     {
02413 
02414         for (i = 0; i < pInputImage->numberOfChannels; i++)
02415         {
02416             if((max[i] - min[i]) != 0.0f)
02417             {
02418                 factor[i] = 255.0f / max[i] - min[i];
02419             }
02420             else
02421             {
02422                 factor[i] = 0.0f;
02423             }
02424         }
02425 
02426         for (i = 0; i < nPixels; i++)
02427         {
02428             for (j = 0; j < pInputImage->numberOfChannels; j++)
02429             {
02430                 pixelChannelIndex = i * pInputImage->numberOfChannels + j;
02431 
02432                 output[pixelChannelIndex] = (unsigned char) ((input[pixelChannelIndex] - min[j]) * factor[j]);
02433             }
02434         }
02435     }
02436     else
02437     {
02438         // verify input value ranges
02439         for (i = 0; i < pInputImage->numberOfChannels; i++)
02440         {
02441             if(min[i] < 0.0f || max[i] > 255.0f)
02442             {
02443                 printf("error: float input image values exceed value range of output byte image in ImageProcessor::ConvertImage. Equalization required!\n");
02444                 return false;
02445             }
02446         }
02447 
02448         for (i = 0; i < nPixels; i++)
02449         {
02450             for (j = 0; j < pInputImage->numberOfChannels; j++)
02451             {
02452                 pixelChannelIndex = i * pInputImage->numberOfChannels + j;
02453 
02454                 output[pixelChannelIndex] = (unsigned char) input[pixelChannelIndex];
02455             }
02456         }
02457     }
02458 
02459         return true;
02460 }
02461 
02462 
02463 bool ImageProcessor::ConvertImage(const CByteImage *pInputImage, CFloatImage *pOutputImage)
02464 {
02465     if(pOutputImage->numberOfChannels == 1 && pInputImage->type != CByteImage::eGrayScale)
02466     {
02467         printf("error: ImageProcessor::ConvertImage cannot convert a single channel byte image into single channel byte image\n");
02468         return false;
02469     }
02470 
02471     if(pOutputImage->numberOfChannels == 3 && pInputImage->type == CByteImage::eGrayScale)
02472     {
02473         printf("error: ImageProcessor::ConvertImage cannot convert a single channel byte image into 3-channel float image\n");
02474         return false;
02475     }
02476 
02477     if (pInputImage->width != pOutputImage->width || pInputImage->height != pOutputImage->height)
02478     {
02479         printf("error: input and output image dimensions do not match for ImageProcessor::ConvertImage\n");
02480         return false;
02481     }
02482 
02483     const int nPixels = pInputImage->width * pInputImage->height;
02484     const unsigned char *input = pInputImage->pixels;
02485     float *output = pOutputImage->pixels;
02486     int i, j;
02487     int pixelChannelIndex;
02488 
02489     for (i = 0; i < nPixels; i++)
02490     {
02491         for (j = 0; j < pInputImage->bytesPerPixel; j++)
02492         {
02493             pixelChannelIndex = i * pInputImage->bytesPerPixel + j;
02494 
02495             output[pixelChannelIndex] = (float) input[pixelChannelIndex];
02496         }
02497     }
02498 
02499         return true;
02500 }
02501 
02502 
02503 bool ImageProcessor::ConvertImage(const CFloatMatrix *pInputMatrix, CByteImage *pOutputImage)
02504 {
02505         if (pOutputImage->type != CByteImage::eGrayScale || pInputMatrix->columns != pOutputImage->width || pInputMatrix->rows != pOutputImage->height)
02506         {
02507                 printf("error: input matrix and output image do not match for ImageProcessor::ConvertImage\n");
02508                 return false;
02509         }
02510                 
02511         const int nPixels = pInputMatrix->columns * pInputMatrix->rows;
02512         const float *input = pInputMatrix->data;
02513         unsigned char *output = pOutputImage->pixels;
02514         float min = FLT_MAX, max = -FLT_MAX;
02515         int i;
02516         
02517         for (i = 0; i < nPixels; i++)
02518         {
02519                 if (input[i] > max)
02520                         max = input[i];
02521                         
02522                 if (input[i] < min)
02523                         min = input[i];
02524         }
02525         
02526         const float divider = max - min;
02527         
02528         if (divider == 0.0f)
02529         {
02530                 Zero(pOutputImage);
02531         }
02532         else
02533         {
02534                 const float factor = 255.0f / divider;
02535                 
02536                 for (i = 0; i < nPixels; i++)
02537                         output[i] = (unsigned char) ((input[i] - min) * factor);
02538         }
02539 
02540         return true;
02541 }
02542 
02543 bool ImageProcessor::ConvertImage(const CByteImage *pInputImage, CFloatMatrix *pOutputMatrix)
02544 {
02545         if (pInputImage->type != CByteImage::eGrayScale || pOutputMatrix->columns != pInputImage->width || pOutputMatrix->rows != pInputImage->height)
02546         {
02547                 printf("error: input image and output matrix do not match for ImageProcessor::ConvertImage\n");
02548                 return false;
02549         }
02550                 
02551         const int nPixels = pOutputMatrix->columns * pOutputMatrix->rows;
02552         const unsigned char *input = pInputImage->pixels;
02553         float *output = pOutputMatrix->data;
02554         
02555         for (int i = 0; i < nPixels; i++)
02556                 output[i] = input[i];
02557 
02558         return true;
02559 }
02560 
02561 bool ImageProcessor::ConvertImage(const CShortImage *pInputImage, CByteImage *pOutputImage)
02562 {
02563         if (pOutputImage->type != CByteImage::eGrayScale || pInputImage->width != pOutputImage->width || pInputImage->height != pOutputImage->height)
02564         {
02565                 printf("error: input matrix and output image do not match for ImageProcessor::ConvertImage\n");
02566                 return false;
02567         }
02568                 
02569         const int nPixels = pInputImage->width * pInputImage->height;
02570         const short *input = pInputImage->pixels;
02571         unsigned char *output = pOutputImage->pixels;
02572         short min = SHRT_MAX, max = SHRT_MIN;
02573         int i;
02574         
02575         for (i = 0; i < nPixels; i++)
02576         {
02577                 if (input[i] > max)
02578                         max = input[i];
02579                 
02580                 if (input[i] < min)
02581                         min = input[i];
02582         }
02583 
02584         const short divider = max - min;
02585 
02586         if (divider == 0)
02587         {
02588                 Zero(pOutputImage);
02589         }
02590         else
02591         {
02592                 for (i = 0; i < nPixels; i++)
02593                         output[i] = (unsigned char) ((255 * (input[i] - min)) / divider);
02594         }
02595 
02596         return true;
02597 }
02598 
02599 bool ImageProcessor::ConvertImage(const CByteImage *pInputImage, CShortImage *pOutputImage)
02600 {
02601         if (pInputImage->type != CByteImage::eGrayScale || pOutputImage->width != pInputImage->width || pOutputImage->height != pInputImage->height)
02602         {
02603                 printf("error: input image and output matrix do not match for ImageProcessor::ConvertImage\n");
02604                 return false;
02605         }
02606                 
02607         const int nPixels = pOutputImage->width * pOutputImage->height;
02608         const unsigned char *input = pInputImage->pixels;
02609         short *output = pOutputImage->pixels;
02610         
02611         for (int i = 0; i < nPixels; i++)
02612                 output[i] = (short) input[i];
02613 
02614         return true;
02615 }
02616 
02617 bool ImageProcessor::ConvertImage(const CByteImage *pInputImage, CIntImage *pOutputImage)
02618 {
02619         if (pInputImage->type != CByteImage::eGrayScale || pOutputImage->width != pInputImage->width || pOutputImage->height != pInputImage->height)
02620         {
02621                 printf("error: input image and output matrix do not match for ImageProcessor::ConvertImage\n");
02622                 return false;
02623         }
02624         
02625         const int nPixels = pOutputImage->width * pOutputImage->height;
02626         const unsigned char *input = pInputImage->pixels;
02627         int *output = pOutputImage->pixels;
02628         
02629         for (int i = 0; i < nPixels; i++)
02630                 output[i] = (int) input[i];
02631 
02632         return true;
02633 }
02634 
02635 bool ImageProcessor::ConvertImage(const CIntImage *pInputImage, CByteImage *pOutputImage)
02636 {
02637         if (pOutputImage->type != CByteImage::eGrayScale || pInputImage->width != pOutputImage->width || pInputImage->height != pOutputImage->height)
02638         {
02639                 printf("error: input matrix and output image do not match for ImageProcessor::ConvertImage\n");
02640                 return false;
02641         }
02642         
02643         const int nPixels = pInputImage->width * pInputImage->height;
02644         const int *input = pInputImage->pixels;
02645         unsigned char *output = pOutputImage->pixels;
02646         int min = INT_MAX, max = INT_MIN;
02647         int i;
02648         
02649         for (i = 0; i < nPixels; i++)
02650         {
02651                 if (input[i] > max)
02652                         max = input[i];
02653                 
02654                 if (input[i] < min)
02655                         min = input[i];
02656         }
02657         
02658         const int divider = max - min;
02659         
02660         if (divider == 0)
02661         {
02662                 Zero(pOutputImage);
02663         }
02664         else
02665         {
02666                 for (i = 0; i < nPixels; i++)
02667                         output[i] = (unsigned char) ((255 * (input[i] - min)) / divider);
02668         }
02669 
02670         return true;
02671 }
02672 
02673 
02674 bool ImageProcessor::ConvertMatrix(const CFloatMatrix *pInputMatrix, CDoubleMatrix *pOutputMatrix)
02675 {
02676         if (pInputMatrix->rows != pOutputMatrix->rows || pInputMatrix->columns != pOutputMatrix->columns)
02677         {
02678                 printf("error: input image and output matrix do not match for ImageProcessor::ConvertMatrix\n");
02679                 return false;
02680         }
02681                 
02682         const int nElements = pOutputMatrix->rows * pOutputMatrix->columns;
02683         const float *input = pInputMatrix->data;
02684         double *output = pOutputMatrix->data;
02685         
02686         for (int i = 0; i < nElements; i++)
02687                 output[i] = (double) input[i];
02688 
02689         return true;
02690 }
02691         
02692 bool ImageProcessor::ConvertMatrix(const CDoubleMatrix *pInputMatrix, CFloatMatrix *pOutputMatrix)
02693 {
02694         if (pInputMatrix->rows != pOutputMatrix->rows || pInputMatrix->columns != pOutputMatrix->columns)
02695         {
02696                 printf("error: input image and output matrix do not match for ImageProcessor::ConvertMatrix\n");
02697                 return false;
02698         }
02699                 
02700         const int nElements = pOutputMatrix->rows * pOutputMatrix->columns;
02701         const double *input = pInputMatrix->data;
02702         float *output = pOutputMatrix->data;
02703         
02704         for (int i = 0; i < nElements; i++)
02705                 output[i] = (float) input[i];
02706 
02707         return true;
02708 }
02709 
02710 
02711 bool ImageProcessor::CopyImage(const CByteImage *pInputImage, CByteImage *pOutputImage, const MyRegion *pROI, bool bUseSameSize)
02712 {
02713         if (!pROI || bUseSameSize)
02714         {
02715                 if (pInputImage->width != pOutputImage->width || pInputImage->height != pOutputImage->height || pInputImage->type != pOutputImage->type)
02716                 {
02717                         printf("error: input and output image do not match for ImageProcessor::CopyImage\n");
02718                         return false;
02719                 }
02720         }
02721         else if (pROI && !bUseSameSize)
02722         {
02723                 const int w = pROI->max_x - pROI->min_x + 1;
02724                 const int h = pROI->max_y - pROI->min_y + 1;
02725                 
02726                 if (w != pOutputImage->width || pOutputImage->height != h || pInputImage->type != pOutputImage->type)
02727                 {
02728                         printf("error: ROI and output image do not match for ImageProcessor::CopyImage\n");
02729                         return false;
02730                 }
02731         }
02732 
02733         if (pROI)
02734         {
02735                 const int width = pInputImage->width;
02736                 const int height = pInputImage->height;
02737 
02738                 unsigned char *input = pInputImage->pixels;
02739                 unsigned char *output = pOutputImage->pixels;
02740 
02741                 int min_x = pROI->min_x;
02742                 int max_x = pROI->max_x;
02743                 int min_y = pROI->min_y;
02744                 int max_y = pROI->max_y;
02745                 
02746                 if (!bUseSameSize)
02747                 {
02748                         if (min_x < 0 || min_x > width - 1 || max_x < 0 || max_x > width - 1 ||
02749                                 min_y < 0 || min_y > height - 1 || max_y < 0 || max_y > height - 1)
02750                         {
02751                                 printf("error: ROI is out of image in ImageProcessor::CopyImage\n");
02752                                 return false;
02753                         }
02754                 }
02755 
02756                 if (min_x < 0) min_x = 0;
02757                 if (min_x > width - 1) min_x = width - 1;
02758                 if (max_x < 0) max_x = 0;
02759                 if (max_x > width - 1) max_x = width - 1;
02760                 if (min_y < 0) min_y = 0;
02761                 if (min_y > height - 1) min_y = height - 1;
02762                 if (max_y < 0) max_y = 0;
02763                 if (max_y > height - 1) max_y = height - 1;
02764 
02765                 if (pInputImage->type == CByteImage::eGrayScale)
02766                 {
02767                         const int size = max_x - min_x + 1;
02768                         
02769                         if (bUseSameSize)
02770                         {
02771                                 for (int y = min_y, offset = width * min_y + min_x; y <= max_y; y++, offset += width)
02772                                         memcpy(output + offset, input + offset, size);
02773                         }
02774                         else
02775                         {
02776                                 for (int y = min_y, offset = width * min_y + min_x, output_offset = 0; y <= max_y; y++, offset += width, output_offset += size)
02777                                         memcpy(output + output_offset, input + offset, size);
02778                         }
02779                 }
02780                 else if (pInputImage->type == CByteImage::eRGB24)
02781                 {
02782                         const int size = 3 * (max_x - min_x + 1);
02783                         const int width3 = 3 * width;
02784 
02785                         if (bUseSameSize)
02786                         {
02787                                 for (int y = min_y, offset = 3 * (width * min_y + min_x); y <= max_y; y++, offset += width3)
02788                                         memcpy(output + offset, input + offset, size);
02789                         }
02790                         else
02791                         {
02792                                 for (int y = min_y, offset = 3 * (width * min_y + min_x), output_offset = 0; y <= max_y; y++, offset += width3, output_offset += size)
02793                                         memcpy(output + output_offset, input + offset, size);
02794                         }
02795                 }
02796                 else if (pInputImage->type == CByteImage::eRGB24Split)
02797                 {
02798                         const int size = max_x - min_x + 1;
02799                         
02800                         unsigned char *pHelperR = output;
02801                         unsigned char *pHelperG = pHelperR + width * height;
02802                         unsigned char *pHelperB = pHelperG + width * height;
02803                         
02804                         if (bUseSameSize)
02805                         {
02806                                 for (int y = min_y, offset = width * min_y + min_x; y <= max_y; y++, offset += width)
02807                                 {
02808                                         memcpy(pHelperR + offset, input + offset, size);
02809                                         memcpy(pHelperG + offset, input + offset, size);
02810                                         memcpy(pHelperB + offset, input + offset, size);
02811                                 }
02812                         }
02813                         else
02814                         {
02815                                 for (int y = min_y, offset = 3 * (width * min_y + min_x), output_offset = 0; y <= max_y; y++, offset += width, output_offset += size)
02816                                 {
02817                                         memcpy(pHelperR + output_offset, input + offset, size);
02818                                         memcpy(pHelperG + output_offset, input + offset, size);
02819                                         memcpy(pHelperB + output_offset, input + offset, size);
02820                                 }
02821                         }
02822                 }
02823         }
02824         else
02825         {
02826                 memcpy(pOutputImage->pixels, pInputImage->pixels, pInputImage->width * pInputImage->height * pInputImage->bytesPerPixel);
02827         }
02828 
02829         return true;
02830 }
02831 
02832 bool ImageProcessor::CopyImage(const CShortImage *pInputImage, CShortImage *pOutputImage, const MyRegion *pROI, bool bUseSameSize)
02833 {
02834         if (!pROI || bUseSameSize)
02835         {
02836                 if (pInputImage->width != pOutputImage->width || pInputImage->height != pOutputImage->height)
02837                 {
02838                         printf("error: input and output image do not match for ImageProcessor::CopyImage\n");
02839                         return false;
02840                 }
02841         }
02842         else if (pROI && !bUseSameSize)
02843         {
02844                 const int w = pROI->max_x - pROI->min_x + 1;
02845                 const int h = pROI->max_y - pROI->min_y + 1;
02846                 
02847                 if (w != pOutputImage->width || pOutputImage->height != h)
02848                 {
02849                         printf("error: ROI and output image do not match for ImageProcessor::CopyImage\n");
02850                         return false;
02851                 }
02852         }
02853 
02854         if (pROI)
02855         {
02856                 const int width = pInputImage->width;
02857                 const int height = pInputImage->height;
02858 
02859                 short *input = pInputImage->pixels;
02860                 short *output = pOutputImage->pixels;
02861 
02862                 int min_x = pROI->min_x;
02863                 int max_x = pROI->max_x;
02864                 int min_y = pROI->min_y;
02865                 int max_y = pROI->max_y;
02866                 
02867                 if (!bUseSameSize)
02868                 {
02869                         if (min_x < 0 || min_x > width - 1 || max_x < 0 || max_x > width - 1 ||
02870                                 min_y < 0 || min_y > height - 1 || max_y < 0 || max_y > height - 1)
02871                         {
02872                                 printf("error: ROI is out of image in ImageProcessor::CopyImage\n");
02873                                 return false;
02874                         }
02875                 }
02876 
02877                 if (min_x < 0) min_x = 0;
02878                 if (min_x > width - 1) min_x = width - 1;
02879                 if (max_x < 0) max_x = 0;
02880                 if (max_x > width - 1) max_x = width - 1;
02881                 if (min_y < 0) min_y = 0;
02882                 if (min_y > height - 1) min_y = height - 1;
02883                 if (max_y < 0) max_y = 0;
02884                 if (max_y > height - 1) max_y = height - 1;
02885 
02886                 if (bUseSameSize)
02887                 {
02888                         const int diff = width - (max_x - min_x + 1);
02889 
02890                         for (int y = min_y, offset = width * min_y + min_x; y <= max_y; y++, offset += diff)
02891                                 for (int x = min_x; x <= max_x; x++, offset++)
02892                                         output[offset] = input[offset];
02893                 }
02894                 else
02895                 {
02896                         const int diff = width - (max_x - min_x + 1);
02897 
02898                         for (int y = min_y, offset = width * min_y + min_x, output_offset = 0; y <= max_y; y++, offset += diff)
02899                                 for (int x = min_x; x <= max_x; x++, offset++, output_offset++)
02900                                         output[output_offset] = input[offset];
02901                 }
02902         }
02903         else
02904         {
02905                 memcpy(pOutputImage->pixels, pInputImage->pixels, pInputImage->width * pInputImage->height * sizeof(short));
02906         }
02907 
02908         return true;
02909 }
02910 
02911 
02912 bool ImageProcessor::CopyMatrix(const CFloatMatrix *pInputMatrix, CFloatMatrix *pOutputMatrix)
02913 {
02914         if (pInputMatrix->rows != pOutputMatrix->rows || pInputMatrix->columns != pOutputMatrix->columns)
02915         {
02916                 printf("error: input and output matrix do not match for ImageProcessor::CopyMatrix\n");
02917                 return false;
02918         }
02919 
02920         memcpy(pOutputMatrix->data, pInputMatrix->data, pInputMatrix->rows * pInputMatrix->columns * sizeof(float));
02921 
02922         return true;
02923 }
02924 
02925 bool ImageProcessor::CopyMatrix(const CDoubleMatrix *pInputMatrix, CDoubleMatrix *pOutputMatrix)
02926 {
02927         if (pInputMatrix->rows != pOutputMatrix->rows || pInputMatrix->columns != pOutputMatrix->columns)
02928         {
02929                 printf("error: input and output matrix do not match for ImageProcessor::CopyMatrix\n");
02930                 return false;
02931         }
02932 
02933         memcpy(pOutputMatrix->data, pInputMatrix->data, pInputMatrix->rows * pInputMatrix->columns * sizeof(double));
02934 
02935         return true;
02936 }
02937 
02938 
02939 void ImageProcessor::Zero(CByteImage *pImage, const MyRegion *pROI)
02940 {
02941         if (pROI)
02942         {
02943                 const int width = pImage->width;
02944                 const int height = pImage->height;
02945 
02946                 unsigned char *pixels = pImage->pixels;
02947 
02948                 int min_x = pROI->min_x;
02949                 int max_x = pROI->max_x;
02950                 int min_y = pROI->min_y;
02951                 int max_y = pROI->max_y;
02952 
02953                 if (min_x < 0) min_x = 0;
02954                 if (min_x > width - 1) min_x = width - 1;
02955                 if (max_x < 0) max_x = 0;
02956                 if (max_x > width - 1) max_x = width - 1;
02957                 if (min_y < 0) min_y = 0;
02958                 if (min_y > height - 1) min_y = height - 1;
02959                 if (max_y < 0) max_y = 0;
02960                 if (max_y > height - 1) max_y = height - 1;
02961 
02962                 if (pImage->type == CByteImage::eGrayScale)
02963                 {
02964                         const int size = max_x - min_x + 1;
02965 
02966                         for (int y = min_y, offset = width * min_y + min_x; y <= max_y; y++, offset += width)
02967                                 memset(pixels + offset, 0, size);
02968                 }
02969                 else if (pImage->type == CByteImage::eRGB24)
02970                 {
02971                         const int size = 3 * (max_x - min_x + 1);
02972                         const int width3 = 3 * width;
02973 
02974                         for (int y = min_y, offset = 3 * (width * min_y + min_x); y <= max_y; y++, offset += width3)
02975                                 memset(pixels, 0, size);
02976                 }
02977                 else if (pImage->type == CByteImage::eRGB24Split)
02978                 {
02979                         const int size = max_x - min_x + 1;
02980                         
02981                         unsigned char *pHelperR = pixels;
02982                         unsigned char *pHelperG = pHelperR + width * height;
02983                         unsigned char *pHelperB = pHelperG + width * height;
02984 
02985                         for (int y = min_y, offset = width * min_y + min_x; y <= max_y; y++, offset += width)
02986                         {
02987                                 memset(pHelperR + offset, 0, size);
02988                                 memset(pHelperG + offset, 0, size);
02989                                 memset(pHelperB + offset, 0, size);
02990                         }
02991                 }
02992         }
02993         else
02994         {
02995                 memset(pImage->pixels, 0, pImage->width * pImage->height * pImage->bytesPerPixel);
02996         }
02997 }
02998 
02999 void ImageProcessor::Zero(CShortImage *pImage)
03000 {
03001         memset(pImage->pixels, 0, pImage->width * pImage->height * sizeof(*pImage->pixels));
03002 }
03003 
03004 void ImageProcessor::Zero(CIntImage *pImage)
03005 {
03006         memset(pImage->pixels, 0, pImage->width * pImage->height * sizeof(*pImage->pixels));
03007 }
03008 
03009 void ImageProcessor::Zero(CFloatMatrix *pMatrix)
03010 {
03011         memset(pMatrix->data, 0, pMatrix->columns * pMatrix->rows * sizeof(*pMatrix->data));
03012 }
03013 
03014 void ImageProcessor::Zero(CDoubleMatrix *pMatrix)
03015 {
03016         memset(pMatrix->data, 0, pMatrix->columns * pMatrix->rows * sizeof(*pMatrix->data));
03017 }
03018 
03019 
03020 void ImageProcessor::ZeroFrame(CByteImage *pImage)
03021 {
03022         const int width = pImage->width;
03023         const int height = pImage->height;
03024         unsigned char *pixels = pImage->pixels;
03025         
03026         if (pImage->type == CByteImage::eGrayScale)
03027         {
03028                 // zero top and bottom row
03029                 memset(pixels, 0, width);
03030                 memset(pixels + width * (height - 1), 0, width);
03031                 
03032                 // zero left and right column
03033                 for (int i = 0, offset = 0; i < height; i++, offset += width)
03034                 {
03035                         pixels[offset] = 0;
03036                         pixels[offset + width - 1] = 0;
03037                 }
03038         }
03039         else
03040         {
03041                 const int width3 = 3 * width;
03042                 
03043                 // zero top and bottom row
03044                 memset(pixels, 0, width3);
03045                 memset(pixels + width3 * (height - 1), 0, width3);
03046                 
03047                 // zero left and right column
03048                 for (int i = 0, offset = 0; i < height; i++, offset += width3)
03049                 {
03050                         pixels[offset] = pixels[offset + 1] = pixels[offset + 2] = 0;
03051                         pixels[offset + width3 - 3] = pixels[offset + width3 - 2] = pixels[offset + width3 - 1] = 0;
03052                 }
03053         }
03054 }
03055 
03056 void ImageProcessor::ZeroFrame(CShortImage *pImage)
03057 {
03058         const int width = pImage->width;
03059         const int height = pImage->height;
03060         short *pixels = pImage->pixels;
03061         
03062         // zero top and bottom row
03063         memset(pixels, 0, width * sizeof(short));
03064         memset(pixels + width * (height - 1), 0, width * sizeof(short));
03065         
03066         // zero left and right column
03067         for (int i = 0, offset = 0; i < height; i++, offset += width)
03068         {
03069                 pixels[offset] = 0;
03070                 pixels[offset + width - 1] = 0;
03071         }
03072 }
03073 
03074 void ImageProcessor::ZeroFrame(CIntImage *pImage)
03075 {
03076         const int width = pImage->width;
03077         const int height = pImage->height;
03078         int *pixels = pImage->pixels;
03079         
03080         // zero top and bottom row
03081         memset(pixels, 0, width * sizeof(int));
03082         memset(pixels + width * (height - 1), 0, width * sizeof(int));
03083         
03084         // zero left and right column
03085         for (int i = 0, offset = 0; i < height; i++, offset += width)
03086         {
03087                 pixels[offset] = 0;
03088                 pixels[offset + width - 1] = 0;
03089         }
03090 }
03091 
03092 bool ImageProcessor::CopyFrame(const CByteImage *pInputImage, CByteImage *pOutputImage)
03093 {
03094         if (pInputImage->width != pOutputImage->width || pInputImage->height != pOutputImage->height || pInputImage->type != pOutputImage->type || pInputImage->type == CByteImage::eRGB24Split)
03095         {
03096                 printf("error: input and output images do not match for ImageProcessor::CopyFrame\n");
03097                 return false;
03098         }
03099         
03100         // copy is not necessary in this case
03101         if (pInputImage->pixels == pOutputImage->pixels)
03102                 return true;
03103         
03104         const unsigned char *input = pInputImage->pixels;
03105         unsigned char *output = pOutputImage->pixels;
03106         
03107         const int width = pInputImage->width;
03108         const int height = pInputImage->height;
03109                 
03110         if (pInputImage->type == CByteImage::eGrayScale)
03111         {
03112                 memcpy(output, input, width);
03113                 memcpy(output + width * (height - 1), input + width * (height - 1), width);
03114                 
03115                 unsigned int offset = width;
03116                 const unsigned int offset2 = width - 1;
03117                 for (int y = 1; y < height-1; y++, offset += width)
03118                 {
03119                         output[offset] = input[offset];
03120                         output[offset + offset2] = input[offset + offset2];
03121                 }
03122         }
03123         else if (pInputImage->type == CByteImage::eRGB24)
03124         {
03125                 memcpy(output, input, 3*width);
03126                 memcpy(output + 3 * width * (height - 1), input + 3 * width * (height - 1), 3 * width);
03127                 
03128                 unsigned int offset = 3 * width;
03129                 const unsigned int offset2 = 3 * (width - 1);
03130                 for (int y = 1; y < height - 1; y++, offset += 3 * width)
03131                 {
03132                         output[offset]   = input[offset];
03133                         output[offset + 1] = input[offset + 1];
03134                         output[offset + 2] = input[offset + 2];
03135                         output[offset + offset2] = input[offset + offset2];
03136                         output[offset + offset2 + 1] = input[offset + offset2 + 1];
03137                         output[offset + offset2 + 2] = input[offset + offset2 + 2];
03138                 }
03139         }
03140 
03141         return true;
03142 }
03143 
03144 bool ImageProcessor::AdaptFrame(const CByteImage *pInputImage, CByteImage *pOutputImage)
03145 {
03146         if (pInputImage->width != pOutputImage->width || pInputImage->height != pOutputImage->height || pInputImage->type != pOutputImage->type || pInputImage->type == CByteImage::eRGB24Split)
03147         {
03148                 printf("error: input and output images do not match for ImageProcessor::CopyFrame\n");
03149                 return false;
03150         }
03151         
03152         const unsigned char *input = pInputImage->pixels;
03153         unsigned char *output = pOutputImage->pixels;
03154         
03155         const int width = pInputImage->width;
03156         const int height = pInputImage->height;
03157                 
03158         if (pInputImage->type == CByteImage::eGrayScale)
03159         {
03160                 // adapt the top and bottom row
03161                 memcpy(&output[1], &input[width + 1], width-2);
03162                 memcpy(&output[width*(height-1) + 1], &input[width*(height-2) + 1], width-2);
03163                 
03164                 // adapt the corners
03165                 output[0] = input[width + 1];
03166                 output[width - 1] = input[2*width - 2];
03167                 output[width*(height-1)] = input[width*(height-2) + 1];
03168                 output[width*height - 1] = input[width*height - 2];
03169                 
03170                 // adapt the left and right borders
03171                 unsigned int offset = width;
03172                 const unsigned int offset2 = width-1;
03173                 for (int y = 1; y < height-1; y++, offset += width)
03174                 {
03175                         output[offset] = input[offset+1];
03176                         output[offset + offset2] = input[offset + offset2 - 1];
03177                 }
03178         }
03179         else if (pInputImage->type == CByteImage::eRGB24)
03180         {
03181                 // adapt the top and bottom row
03182                 memcpy(&output[3], &input[3*(width + 1)], 3*(width-2));
03183                 memcpy(&output[3*(width*(height-1) + 1)], &input[3*(width*(height-2) + 1)], 3*(width-2));
03184                 
03185                 // adapt the corners
03186                 output[0] = input[3*(width + 1)];
03187                 output[1] = input[3*(width + 1) + 1];
03188                 output[2] = input[3*(width + 1) + 2];
03189                 output[3*(width - 1)]     = input[3*(2*width - 2)];
03190                 output[3*(width - 1) + 1] = input[3*(2*width - 2) + 1];
03191                 output[3*(width - 1) + 2] = input[3*(2*width - 2) + 2];
03192                 output[3*(width*(height-1))]     = input[3*(width*(height-2) + 1)];
03193                 output[3*(width*(height-1)) + 1] = input[3*(width*(height-2) + 1) + 1];
03194                 output[3*(width*(height-1)) + 2] = input[3*(width*(height-2) + 1) + 2];
03195                 output[3*(width*height - 1)]     = input[3*(width*(height-1) - 2)];
03196                 output[3*(width*height - 1) + 1] = input[3*(width*(height-1) - 2) + 1];
03197                 output[3*(width*height - 1) + 2] = input[3*(width*(height-1) - 2) + 2];
03198                 
03199                 // adapt the left and right borders
03200                 unsigned int offset = 3*width;
03201                 const unsigned int offset2 = 3*(width-1);
03202                 for (int y = 1; y < height-1; y++, offset += 3*width)
03203                 {
03204                         output[offset]     = input[offset + 3];
03205                         output[offset + 1] = input[offset + 3 + 1];
03206                         output[offset + 2] = input[offset + 3 + 2];
03207                         output[offset + offset2]     = input[offset + offset2 - 3];
03208                         output[offset + offset2 + 1] = input[offset + offset2 - 3 + 1];
03209                         output[offset + offset2 + 2] = input[offset + offset2 - 3 + 2];
03210                 }
03211         }
03212 
03213         return true;
03214 }
03215 
03216 
03217 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)
03218 {
03219         const Mat3d A = { a1, a2, a3, a4, a5, a6, a7, a8, 1.0f };
03220         return ApplyHomography(pInputImage, pOutputImage, A, bInterpolation);
03221 }
03222 
03223 bool ImageProcessor::ApplyHomography(const CByteImage *pInputImage, CByteImage *pOutputImage, const Mat3d &A, bool bInterpolation)
03224 {
03225         if (pInputImage->type != pOutputImage->type)
03226         {
03227                 printf("error: input and output image do not match in ImageProcessor::ApplyHomography\n");
03228                 return false;
03229         }
03230 
03231         const float a1 = A.r1;
03232         const float a2 = A.r2;
03233         const float a3 = A.r3;
03234         const float a4 = A.r4;
03235         const float a5 = A.r5;
03236         const float a6 = A.r6;
03237         const float a7 = A.r7;
03238         const float a8 = A.r8;
03239         const float a9 = A.r9;
03240 
03241         CByteImage *pSaveOutputImage = 0;
03242         if (pInputImage->pixels == pOutputImage->pixels)
03243         {
03244                 pSaveOutputImage = pOutputImage;
03245                 pOutputImage = new CByteImage(pInputImage);
03246         }
03247         
03248         const int width = pInputImage->width;
03249         const int height = pInputImage->height;
03250         const int output_width = pOutputImage->width;
03251         const int output_height = pOutputImage->height;
03252         const unsigned char *input = pInputImage->pixels;
03253         unsigned char *output = pOutputImage->pixels;
03254         const CByteImage::ImageType type = pInputImage->type;
03255         
03256         if (bInterpolation)
03257         {
03258                 if (type == CByteImage::eGrayScale)
03259                 {
03260                         for (int v = 0, offset = 0; v < output_height; v++)
03261                         {
03262                                 for (int u = 0; u < output_width; u++, offset++)
03263                                 {
03264                                         const float u_ = (a1 * u + a2 * v + a3) / (a7 * u + a8 * v + a9);
03265                                         const float v_ = (a4 * u + a5 * v + a6) / (a7 * u + a8 * v + a9);
03266 
03267                                         const int u1 = int(floor(u_));
03268                                         const int v1 = int(floor(v_));
03269                                         const int u2 = u1 + 1;
03270                                         const int v2 = v1 + 1;
03271 
03272                                         unsigned char f00 = 0, f10 = 0, f01 = 0, f11 = 0;
03273 
03274                                         const bool v1_ok = v1 >= 0 && v1 < height;
03275                                         const bool v2_ok = v2 >= 0 && v2 < height;
03276 
03277                                         if (u1 >= 0 && u1 < width)
03278                                         {
03279                                                 if (v1_ok)
03280                                                         f00 = input[v1 * width + u1];
03281 
03282                                                 if (v2_ok)
03283                                                         f01 = input[v2 * width + u1];
03284                                         }
03285 
03286                                         if (u2 >= 0 && u2 < width)
03287                                         {
03288                                                 if (v1_ok)
03289                                                         f10 = input[v1 * width + u2];
03290 
03291                                                 if (v2_ok)
03292                                                         f11 = input[v2 * width + u2];
03293                                         }
03294 
03295                                         const float x = u_ - u1;
03296                                         const float y = v_ - v1;
03297 
03298                                         output[offset] = (unsigned char) (f00 * (1 - x) * (1 - y) + f10 * x * (1 - y) + f01 * (1 - x) * y + f11 * x * y + 0.5f);
03299                                 }
03300                         }
03301                 }
03302                 else if (type == CByteImage::eRGB24)
03303                 {
03304                         for (int v = 0, offset = 0; v < height; v++)
03305                         {
03306                                 for (int u = 0; u < width; u++, offset += 3)
03307                                 {
03308                                         const float u_ = (a1 * u + a2 * v + a3) / (a7 * u + a8 * v + a9);
03309                                         const float v_ = (a4 * u + a5 * v + a6) / (a7 * u + a8 * v + a9);
03310 
03311                                         const int u1 = int(floor(u_));
03312                                         const int v1 = int(floor(v_));
03313                                         const int u2 = u1 + 1;
03314                                         const int v2 = v1 + 1;
03315 
03316                                         unsigned char f00_r = 0, f00_g = 0, f00_b = 0;
03317                                         unsigned char f10_r = 0, f10_g = 0, f10_b = 0;
03318                                         unsigned char f01_r = 0, f01_g = 0, f01_b = 0;
03319                                         unsigned char f11_r = 0, f11_g = 0, f11_b = 0;
03320 
03321                                         const bool v1_ok = v1 >= 0 && v1 < height;
03322                                         const bool v2_ok = v2 >= 0 && v2 < height;
03323 
03324                                         if (u1 >= 0 && u1 < width)
03325                                         {
03326                                                 if (v1_ok)
03327                                                 {
03328                                                         const int x = 3 * (v1 * width + u1);
03329                                                         f00_r = input[x];
03330                                                         f00_g = input[x + 1];
03331                                                         f00_b = input[x + 2];
03332                                                 }
03333 
03334                                                 if (v2_ok)
03335                                                 {
03336                                                         const int x = 3 * (v2 * width + u1);
03337                                                         f01_r = input[x];
03338                                                         f01_g = input[x + 1];
03339                                                         f01_b = input[x + 2];
03340                                                 }
03341                                         }
03342 
03343                                         if (u2 >= 0 && u2 < width)
03344                                         {
03345                                                 if (v1_ok)
03346                                                 {
03347                                                         const int x = 3 * (v1 * width + u2);
03348                                                         f10_r = input[x];
03349                                                         f10_g = input[x + 1];
03350                                                         f10_b = input[x + 2];
03351                                                 }
03352 
03353                                                 if (v2_ok)
03354                                                 {
03355                                                         const int x = 3 * (v2 * width + u2);
03356                                                         f11_r = input[x];
03357                                                         f11_g = input[x + 1];
03358                                                         f11_b = input[x + 2];
03359                                                 }
03360                                         }
03361 
03362                                         const float x = u_ - u1;
03363                                         const float y = v_ - v1;
03364 
03365                                         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);
03366                                         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);
03367                                         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);
03368                                 }
03369                         }
03370                 }
03371         }
03372         else
03373         {
03374                 if (type == CByteImage::eGrayScale)
03375                 {
03376                         for (int v = 0, offset = 0; v < output_height; v++)
03377                         {
03378                                 for (int u = 0; u < output_width; u++, offset++)
03379                                 {
03380                                         const int u_ = (int) ((a1 * u + a2 * v + a3) / (a7 * u + a8 * v + 1.0f) + 0.5f);
03381                                         const int v_ = (int) ((a4 * u + a5 * v + a6) / (a7 * u + a8 * v + 1.0f) + 0.5f);
03382                                         
03383                                         if (u_ < 0 || u_ >= width || v_ < 0 || v_ >= height)
03384                                                 output[offset] = 0;
03385                                         else
03386                                                 output[offset] = input[v_ * width + u_];
03387                                 }
03388                         }
03389                 }
03390                 else if (type == CByteImage::eRGB24)
03391                 {
03392                         for (int v = 0, offset = 0; v < output_height; v++)
03393                         {
03394                                 for (int u = 0; u < output_width; u++, offset += 3)
03395                                 {
03396                                         const int u_ = (int) ((a1 * u + a2 * v + a3) / (a7 * u + a8 * v + 1.0f) + 0.5f);
03397                                         const int v_ = (int) ((a4 * u + a5 * v + a6) / (a7 * u + a8 * v + 1.0f) + 0.5f);
03398                                         
03399                                         if (u_ < 0 || u_ >= width || v_ < 0 || v_ >= height)
03400                                                 output[offset] =  output[offset + 1] = output[offset + 2] = 0;
03401                                         else
03402                                         {
03403                                                 const int offset2 = 3 * (v_ * width + u_);
03404                                                 output[offset] = input[offset2];
03405                                                 output[offset + 1] = input[offset2 + 1];
03406                                                 output[offset + 2] = input[offset2 + 2];
03407                                         }
03408                                 }
03409                         }
03410                 }
03411         }
03412 
03413         if (pSaveOutputImage)
03414         {
03415                 CopyImage(pOutputImage, pSaveOutputImage);
03416                 delete pOutputImage;
03417         }
03418 
03419         return true;
03420 }
03421 
03422 bool ImageProcessor::Resize(const CByteImage *pInputImage, CByteImage *pOutputImage, const MyRegion *pROI, bool bInterpolation)
03423 {
03424         if (pInputImage->type != pOutputImage->type || pInputImage->type == CByteImage::eRGB24Split)
03425         {
03426                 printf("error: input and output image do not match in ImageProcessor::Resize\n");
03427                 return false;
03428         }
03429 
03430         if (pInputImage->width == pOutputImage->width && pInputImage->height == pOutputImage->height)
03431         {
03432                 CopyImage(pInputImage, pOutputImage);
03433                 return false;
03434         }
03435 
03436         const CByteImage::ImageType type = pInputImage->type;
03437 
03438         const int output_width = pOutputImage->width;
03439         const int output_height = pOutputImage->height;
03440         unsigned char *output = pOutputImage->pixels;
03441 
03442         const int input_width = pInputImage->width;
03443         const int input_height = pInputImage->height;
03444         const unsigned char *input = pInputImage->pixels;
03445 
03446         const int start_x = pROI ? pROI->min_x : 0;
03447         const int start_y = pROI ? pROI->min_y : 0;
03448 
03449         const int width = pROI ? pROI->max_x - pROI->min_x + 1 : input_width;
03450         const int height = pROI ? pROI->max_y - pROI->min_y + 1 : input_height;
03451 
03452         if (pROI)
03453         {
03454                 if (pROI->min_x < 0 || pROI->min_y < 0 || pROI->max_x >= input_width || pROI->max_y >= input_height)
03455                 {
03456                         printf("error: provided ROI in ImageProcessor::Resize exceeds input image boundaries\n");
03457                         return false;
03458                 }
03459         }
03460 
03461         if (width > output_width && width % output_width == 0 &&
03462                 height > output_height && height % output_height == 0)
03463         {
03464                 if (type == CByteImage::eGrayScale)
03465                 {
03466                         const int a1 = width / output_width;
03467                         const int a4 = height / output_height;
03468                         const int delta = a4 * input_width - width;
03469                         
03470                         for (int v = 0, offset = 0, offset_ = start_y * input_width + start_x; v < output_height; v++, offset_ += delta)
03471                         {
03472                                 for (int u = 0; u < output_width; u++, offset++, offset_ += a1)
03473                                         output[offset] = input[offset_];
03474                         }
03475                 }
03476                 else if (type == CByteImage::eRGB24)
03477                 {
03478                         const int a1 = 3 * (width / output_width);
03479                         const int a4 = height / output_height;
03480                         const int delta = 3 * (a4 * input_width - width);
03481                         
03482                         for (int v = 0, offset = 0, offset_ = 3 * (start_y * input_width + start_x); v < output_height; v++, offset_ += delta)
03483                         {
03484                                 for (int u = 0; u < output_width; u++, offset += 3, offset_ += a1)
03485                                 {
03486                                         output[offset] = input[offset_];
03487                                         output[offset + 1] = input[offset_ + 1];
03488                                         output[offset + 2] = input[offset_ + 2];
03489                                 }
03490                         }
03491                 }
03492                 
03493                 return true;
03494         }
03495 
03496         const float a1 = float(width) / output_width;
03497         const float a4 = float(height) / output_height;
03498 
03499         int *pXOffsets = 0, *pYOffsets = 0;
03500         int *pXCoordinates = 0, *pYCoordinates = 0;
03501 
03502         const int min_width = MY_MIN(width, output_width);
03503         const int min_height = MY_MIN(height, output_height);
03504         int i;
03505 
03506         if (type == CByteImage::eGrayScale)
03507         {
03508                 pXOffsets = new int[output_width];
03509                 pYOffsets = new int[output_height];
03510                 
03511                 if (bInterpolation)
03512                 {
03513                         pXCoordinates = new int[output_width];
03514                         pYCoordinates = new int[output_height];
03515 
03516                         for (i = 0; i < output_width; i++)
03517                         {
03518                                 register int x = (i * width) / output_width;
03519 
03520                                 if (start_x + x < input_width - 1)
03521                                 {
03522                                         pXOffsets[i] = start_x + x;
03523                                         pXCoordinates[i] = int((i * a1 - x) * 1024);
03524                                 }
03525                                 else
03526                                 {
03527                                         pXOffsets[i] = input_width - 2;
03528                                         pXCoordinates[i] = 1024;
03529                                 }
03530                         }
03531 
03532                         for (i = 0; i < output_height; i++)
03533                         {
03534                                 register int y = (i * height) / output_height;
03535 
03536                                 if (start_y + y < input_height - 1)
03537                                 {
03538                                         pYOffsets[i] = input_width * (start_y + y);
03539                                         pYCoordinates[i] = int((i * a4 - y) * 1024);
03540                                 }
03541                                 else
03542                                 {
03543                                         pYOffsets[i] = input_width * (input_height - 2);
03544                                         pYCoordinates[i] = 1024;
03545                                 }
03546                         }
03547                 }
03548                 else
03549                 {
03550                         for (i = 0; i < output_width; i++)
03551                                 pXOffsets[i] = start_x + (((i * width) << 1) + min_width - 1) / (output_width << 1);
03552 
03553                         for (i = 0; i < output_height; i++)
03554                                 pYOffsets[i] = input_width * (start_y + (((i * height) << 1) + min_height - 1) / (output_height << 1));
03555                 }
03556         }
03557         else
03558         {
03559                 pXOffsets = new int[3 * output_width];
03560                 pYOffsets = new int[output_height];
03561                 
03562                 int offset = 0;
03563 
03564                 if (bInterpolation)
03565                 {
03566                         pXCoordinates = new int[3 * output_width];
03567                         pYCoordinates = new int[output_height];
03568 
03569                         for (i = 0; i < output_width; i++, offset += 3)
03570                         {
03571                                 register int x = (i * width) / output_width;
03572 
03573                                 if (start_x + x < input_width - 1)
03574                                 {
03575                                         pXOffsets[offset] = 3 * (start_x + x);
03576                                         pXCoordinates[offset] = int((i * a1 - x) * 1024);
03577                                 }
03578                                 else
03579                                 {
03580                                         pXOffsets[offset] = 3 * (input_width - 2);
03581                                         pXCoordinates[offset] = 1024;
03582                                 }
03583                         }
03584 
03585                         for (i = 0; i < output_height; i++)
03586                         {
03587                                 register int y = (i * height) / output_height;
03588 
03589                                 if (start_y + y < input_height - 1)
03590                                 {
03591                                         pYOffsets[i] = 3 * input_width * (start_y + y);
03592                                         pYCoordinates[i] = int((i * a4 - y) * 1024);
03593                                 }
03594                                 else
03595                                 {
03596                                         pYOffsets[i] = 3 * input_width * (input_height - 2);
03597                                         pYCoordinates[i] = 1024;
03598                                 }
03599                         }
03600                 }
03601                 else
03602                 {
03603                         for (i = 0; i < output_width; i++, offset += 3)
03604                                 pXOffsets[offset] = 3 * (start_x + (((i * width) << 1) + min_width - 1) / (output_width << 1));
03605 
03606                         for (i = 0; i < output_height; i++)
03607                                 pYOffsets[i] = 3 * input_width * (start_y + (((i * height) << 1) + min_height - 1) / (output_height << 1));
03608                 }
03609         }
03610 
03611         if (bInterpolation)
03612         {
03613                 if (type == CByteImage::eGrayScale)
03614                 {
03615                         const int last_u = MY_MAX(0, output_width - output_width % 4);
03616 
03617                         for (int v = 0; v < output_height; v++)
03618                         {
03619                                 const unsigned char *input_helper = input + pYOffsets[v];
03620                                 const int y = pYCoordinates[v];
03621                                 int u;
03622 
03623                                 for (u = 0; u < last_u; u += 4)
03624                                 {
03625                                         int offset;
03626                                         int x;
03627                                         
03628                                         offset = pXOffsets[u];
03629                                         x = pXCoordinates[u];
03630                                         output[u] = (unsigned char) (
03631                                                 ((input_helper[offset] * (1024 - x) * (1024 - y)) +
03632                                                 (input_helper[offset + 1] * x * (1024 - y)) +
03633                                                 (input_helper[offset + input_width] * (1024 - x) * y) +
03634                                                 (input_helper[offset + input_width + 1] * x * y)) >> 20
03635                                         );
03636 
03637                                         offset = pXOffsets[u + 1];
03638                                         x = pXCoordinates[u + 1];
03639                                         output[u + 1] = (unsigned char) (
03640                                                 ((input_helper[offset] * (1024 - x) * (1024 - y)) +
03641                                                 (input_helper[offset + 1] * x * (1024 - y)) +
03642                                                 (input_helper[offset + input_width] * (1024 - x) * y) +
03643                                                 (input_helper[offset + input_width + 1] * x * y)) >> 20
03644                                         );
03645 
03646                                         offset = pXOffsets[u + 2];
03647                                         x = pXCoordinates[u + 2];
03648                                         output[u + 2] = (unsigned char) (
03649                                                 ((input_helper[offset] * (1024 - x) * (1024 - y)) +
03650                                                 (input_helper[offset + 1] * x * (1024 - y)) +
03651                                                 (input_helper[offset + input_width] * (1024 - x) * y) +
03652                                                 (input_helper[offset + input_width + 1] * x * y)) >> 20
03653                                         );
03654 
03655                                         offset = pXOffsets[u + 3];
03656                                         x = pXCoordinates[u + 3];
03657                                         output[u + 3] = (unsigned char) (
03658                                                 ((input_helper[offset] * (1024 - x) * (1024 - y)) +
03659                                                 (input_helper[offset + 1] * x * (1024 - y)) +
03660                                                 (input_helper[offset + input_width] * (1024 - x) * y) +
03661                                                 (input_helper[offset + input_width + 1] * x * y)) >> 20
03662                                         );
03663                                 }
03664 
03665                                 for (u = last_u; u < output_width; u++)
03666                                 {
03667                                         const int offset = pXOffsets[u];
03668                                         const int x = pXCoordinates[u];
03669                                         output[u] = (unsigned char) (
03670                                                 ((input_helper[offset] * (1024 - x) * (1024 - y)) +
03671                                                 (input_helper[offset + 1] * x * (1024 - y)) +
03672                                                 (input_helper[offset + input_width] * (1024 - x) * y) +
03673                                                 (input_helper[offset + input_width + 1] * x * y)) >> 20
03674                                         );
03675                                 }
03676 
03677                                 output += output_width;
03678                         }
03679                 }
03680                 else if (type == CByteImage::eRGB24)
03681                 {
03682                         const int output_width3 = 3 * output_width;
03683                         const int input_width3 = 3 * input_width;
03684 
03685                         for (int v = 0; v < output_height; v++)
03686                         {
03687                                 const unsigned char *input_helper = input + pYOffsets[v];
03688                                 const int y = pYCoordinates[v];
03689 
03690                                 for (int u = 0; u < output_width3; u += 3)
03691                                 {
03692                                         const int x = pXCoordinates[u];
03693                                         const int f00 = (1024 - x) * (1024 - y);
03694                                         const int f10 = x * (1024 - y);
03695                                         const int f01 = (1024 - x) * y;
03696                                         const int f11 = x * y;
03697 
03698                                         register int offset;
03699 
03700                                         offset = pXOffsets[u];
03701                                         output[u] = (unsigned char) (
03702                                                 ((input_helper[offset] * f00) +
03703                                                 (input_helper[offset + 3] * f10) +
03704                                                 (input_helper[offset + input_width3] * f01) +
03705                                                 (input_helper[offset + input_width3 + 3] * f11)) >> 20
03706                                         );
03707 
03708                                         offset++;
03709                                         output[u + 1] = (unsigned char) (
03710                                                 ((input_helper[offset] * f00) +
03711                                                 (input_helper[offset + 3] * f10) +
03712                                                 (input_helper[offset + input_width3] * f01) +
03713                                                 (input_helper[offset + input_width3 + 3] * f11)) >> 20
03714                                         );
03715 
03716                                         offset++;
03717                                         output[u + 2] = (unsigned char) (
03718                                                 ((input_helper[offset] * f00) +
03719                                                 (input_helper[offset + 3] * f10) +
03720                                                 (input_helper[offset + input_width3] * f01) +
03721                                                 (input_helper[offset + input_width3 + 3] * f11)) >> 20
03722                                         );
03723                                 }
03724 
03725                                 output += output_width3;
03726                         }
03727                 }
03728         }
03729         else
03730         {
03731                 if (type == CByteImage::eGrayScale)
03732                 {
03733                         const int last_u = MY_MAX(0, output_width - output_width % 4);
03734 
03735                         for (int v = 0; v < output_height; v++)
03736                         {
03737                                 const unsigned char *input_helper = input + pYOffsets[v];
03738                                 int u;
03739 
03740                                 for (u = 0; u < last_u; u += 4)
03741                                 {
03742                                         output[u] = input_helper[pXOffsets[u]];
03743                                         output[u + 1] = input_helper[pXOffsets[u + 1]];
03744                                         output[u + 2] = input_helper[pXOffsets[u + 2]];
03745                                         output[u + 3] = input_helper[pXOffsets[u + 3]];
03746                                 }
03747 
03748                                 for (u = last_u; u < output_width; u++)
03749                                         output[u] = input_helper[pXOffsets[u]];
03750 
03751                                 output += output_width;
03752                         }
03753                 }
03754                 else if (type == CByteImage::eRGB24)
03755                 {
03756                         const int output_width3 = 3 * output_width;
03757                         const int last_u = 3 * MY_MAX(0, output_width - output_width % 4);
03758                         
03759                         for (int v = 0; v < output_height; v++)
03760                         {
03761                                 const unsigned char *input_helper = input + pYOffsets[v];
03762                                 int u;
03763 
03764                                 for (u = 0; u < last_u; u += 12)
03765                                 {
03766                                         register int input_offset;
03767                                         
03768                                         input_offset = pXOffsets[u];
03769                                         output[u] = input_helper[input_offset];
03770                                         output[u + 1] = input_helper[input_offset + 1];
03771                                         output[u + 2] = input_helper[input_offset + 2];
03772 
03773                                         input_offset = pXOffsets[u + 3];
03774                                         output[u + 3] = input_helper[input_offset];
03775                                         output[u + 4] = input_helper[input_offset + 1];
03776                                         output[u + 5] = input_helper[input_offset + 2];
03777 
03778                                         input_offset = pXOffsets[u + 6];
03779                                         output[u + 6] = input_helper[input_offset];
03780                                         output[u + 7] = input_helper[input_offset + 1];
03781                                         output[u + 8] = input_helper[input_offset + 2];
03782 
03783                                         input_offset = pXOffsets[u + 9];
03784                                         output[u + 9] = input_helper[input_offset];
03785                                         output[u + 10] = input_helper[input_offset + 1];
03786                                         output[u + 11] = input_helper[input_offset + 2];
03787                                 }
03788 
03789                                 for (u = last_u; u < output_width3; u += 3)
03790                                 {
03791                                         register int input_offset = pXOffsets[u];
03792                                         output[u] = input_helper[input_offset];
03793                                         output[u + 1] = input_helper[input_offset + 1];
03794                                         output[u + 2] = input_helper[input_offset + 2];
03795                                 }
03796 
03797                                 output += output_width3;
03798                         }
03799                 }
03800         }
03801 
03802         delete [] pXOffsets;
03803         delete [] pYOffsets;
03804 
03805         if (pXCoordinates)
03806         {
03807                 delete [] pXCoordinates;
03808                 delete [] pYCoordinates;
03809         }
03810 
03811         return true;
03812 }
03813 
03814 
03815 bool ImageProcessor::Rotate(const CByteImage *pInputImage, CByteImage *pOutputImage, float mx, float my, float theta, bool bInterpolation)
03816 {
03817         const float cos_theta = cosf(theta);
03818         const float sin_theta = sinf(theta);
03819         
03820         return ApplyHomography(pInputImage, pOutputImage,
03821                 cos_theta, -sin_theta, mx * (1 - cos_theta) + my * sin_theta,
03822                 sin_theta, cos_theta, my * (1 - cos_theta) - mx * sin_theta,
03823                 0, 0,
03824                 bInterpolation);
03825 }
03826 
03827 bool ImageProcessor::Amplify(const CByteImage *pInputImage, CByteImage *pOutputImage, float fFactor)
03828 {
03829         OPTIMIZED_FUNCTION_HEADER_3(Amplify, pInputImage, pOutputImage, fFactor)
03830         
03831         if (!pInputImage->IsCompatible(pOutputImage))
03832         {
03833                 printf("error: input and output image do not match for ImageProcessor::Amplify\n");
03834                 return false;
03835         }
03836                 
03837         const int nBytes = pInputImage->width * pInputImage->height * pInputImage->bytesPerPixel;
03838         const unsigned char *input = pInputImage->pixels;
03839         unsigned char *output = pOutputImage->pixels;
03840         
03841         for (int i = 0; i < nBytes; i++)
03842         {
03843                 const int v = int(fFactor * input[i] + 0.5f);
03844                 output[i] = v < 0 ? 0 : (v > 255 ? 255 : (unsigned char) v);
03845         }
03846 
03847         OPTIMIZED_FUNCTION_FOOTER
03848 
03849         return true;
03850 }
03851 
03852 
03853 bool ImageProcessor::CalculateSaturationImage(const CByteImage *pInputImage, CByteImage *pOutputImage)
03854 {
03855         if (pInputImage->width != pOutputImage->width || pInputImage->height != pOutputImage->height ||
03856                 (pInputImage->type != CByteImage::eRGB24 && pInputImage->type != CByteImage::eRGB24Split) || pOutputImage->type != CByteImage::eGrayScale)
03857         {
03858                 printf("error: input and output image do not match for ImageProcessor::CalculateSaturationImage\n");
03859                 return false;
03860         }
03861                 
03862         const int nPixels = pInputImage->width * pInputImage->height;
03863         unsigned char *output = pOutputImage->pixels;
03864         
03865         if (pInputImage->type == CByteImage::eRGB24)
03866         {
03867                 const unsigned char *input = pInputImage->pixels;
03868         
03869                 for (int i = 0, offset = 0; i < nPixels; i++)
03870                 {
03871                         const int r = input[offset];
03872                         const int g = input[offset + 1];
03873                         const int b = input[offset + 2];
03874                         const int min = MY_MIN(r, MY_MIN(g, b));
03875                         const int max = MY_MAX(r, MY_MAX(g, b));
03876                         output[i] = (255 * (max - min) * division_table[max]) >> 20;
03877                         offset += 3;
03878                 }
03879         }
03880         else
03881         {
03882                 const unsigned char *input_r = pInputImage->pixels;
03883                 const unsigned char *input_g = input_r + nPixels;
03884                 const unsigned char *input_b = input_g +  nPixels;
03885                 
03886                 for (int i = 0; i < nPixels; i++)
03887                 {
03888                         const int r = input_r[i];
03889                         const int g = input_g[i];
03890                         const int b = input_b[i];
03891                         const int min = MY_MIN(r, MY_MIN(g, b));
03892                         const int max = MY_MAX(r, MY_MAX(g, b));
03893                         output[i] = (255 * (max - min) * division_table[max]) >> 20;
03894                 }
03895         }
03896 
03897         return true;
03898 }
03899 
03900 
03901 bool ImageProcessor::ThresholdBinarize(const CByteImage *pInputImage, CByteImage *pOutputImage, unsigned char nThreshold)
03902 {
03903         OPTIMIZED_FUNCTION_HEADER_3(ThresholdBinarize, pInputImage, pOutputImage, nThreshold)
03904         
03905         if (pInputImage->width != pOutputImage->width || pInputImage->height != pOutputImage->height ||
03906                 pInputImage->type != pOutputImage->type || pInputImage->type != CByteImage::eGrayScale)
03907         {
03908                 printf("error: input and output image do not match for ImageProcessor::ThresholdBinarize\n");
03909                 return false;
03910         }
03911                 
03912         const int nPixels = pInputImage->width * pInputImage->height;
03913         const unsigned char *input = pInputImage->pixels;
03914         unsigned char *output = pOutputImage->pixels;
03915 
03916         for (int i = 0; i < nPixels; i++)
03917                 output[i] = input[i] >= nThreshold ? 255 : 0;
03918                 
03919         OPTIMIZED_FUNCTION_FOOTER
03920 
03921         return true;
03922 }
03923 
03924 bool ImageProcessor::ThresholdBinarize(const CByteImage *pInputImage, CByteImage *pOutputImage, unsigned char nMinThreshold, unsigned char nMaxThreshold)
03925 {
03926         //OPTIMIZED_FUNCTION_HEADER_4(ThresholdBinarize, pInputImage, pOutputImage, nMinThreshold, nMaxThreshold)
03927         
03928         if (pInputImage->width != pOutputImage->width || pInputImage->height != pOutputImage->height ||
03929                 pInputImage->type != pOutputImage->type || pInputImage->type != CByteImage::eGrayScale)
03930         {
03931                 printf("error: input and output image do not match for ImageProcessor::ThresholdBinarize\n");
03932                 return false;
03933         }
03934                 
03935         const int nPixels = pInputImage->width * pInputImage->height;
03936         const unsigned char *input = pInputImage->pixels;
03937         unsigned char *output = pOutputImage->pixels;
03938 
03939         for (int i = 0; i < nPixels; i++)
03940                 output[i] = input[i] >= nMinThreshold && input[i] <= nMaxThreshold ? 255 : 0;
03941                 
03942         //OPTIMIZED_FUNCTION_FOOTER
03943 
03944         return true;
03945 }
03946 
03947 bool ImageProcessor::ThresholdBinarize(const CFloatMatrix *pInputMatrix, CFloatMatrix *pOutputMatrix, float fThreshold)
03948 {
03949         if (pInputMatrix->columns != pOutputMatrix->columns || pInputMatrix->rows != pOutputMatrix->rows)
03950         {
03951                 printf("error: input and output matrix do not match for ImageProcessor::ThresholdBinarize\n");
03952                 return false;
03953         }
03954                 
03955         const int n = pInputMatrix->columns * pInputMatrix->rows;
03956         const float *input = pInputMatrix->data;
03957         float *output = pOutputMatrix->data;
03958         
03959         for (int i = 0; i < n; i++)
03960                 output[i] = input[i] >= fThreshold ? 255.0f : 0;
03961 
03962         return true;
03963 }
03964 
03965 bool ImageProcessor::ThresholdBinarizeInverse(const CByteImage *pInputImage, CByteImage *pOutputImage, unsigned char nThreshold)
03966 {
03967         OPTIMIZED_FUNCTION_HEADER_3(ThresholdBinarizeInverse, pInputImage, pOutputImage, nThreshold)
03968         
03969         if (pInputImage->width != pOutputImage->width || pInputImage->height != pOutputImage->height ||
03970                 pInputImage->type != pOutputImage->type || pInputImage->type != CByteImage::eGrayScale)
03971         {
03972                 printf("error: input and output image do not match for ImageProcessor::ThresholdBinarizeInverse\n");
03973                 return false;
03974         }
03975                 
03976         unsigned char *input = pInputImage->pixels;
03977         unsigned char *output = pOutputImage->pixels;
03978         const int nPixels = pInputImage->width * pInputImage->height;
03979 
03980         for (int i = 0; i < nPixels; i++)
03981                 output[i] = input[i] <= nThreshold ? 255 : 0;
03982         
03983         OPTIMIZED_FUNCTION_FOOTER
03984 
03985         return true;
03986 }
03987 
03988 bool ImageProcessor::ThresholdFilter(const CByteImage *pInputImage, CByteImage *pOutputImage, unsigned char nThreshold)
03989 {
03990         OPTIMIZED_FUNCTION_HEADER_3(ThresholdFilter, pInputImage, pOutputImage, nThreshold)
03991         
03992         if (pInputImage->width != pOutputImage->width || pInputImage->height != pOutputImage->height ||
03993                 pInputImage->type != pOutputImage->type || pInputImage->type != CByteImage::eGrayScale)
03994         {
03995                 printf("error: input and output image do not match for ImageProcessor::ThresholdFilter\n");
03996                 return false;
03997         }
03998         
03999         const int nPixels = pInputImage->width * pInputImage->height;
04000         const unsigned char *input = pInputImage->pixels;
04001         unsigned char *output = pOutputImage->pixels;
04002 
04003         for (int i = 0; i < nPixels; i++)
04004                 output[i] = input[i] >= nThreshold ? input[i] : 0;
04005         
04006         OPTIMIZED_FUNCTION_FOOTER
04007 
04008         return true;
04009 }
04010 
04011 bool ImageProcessor::ThresholdFilterInverse(const CByteImage *pInputImage, CByteImage *pOutputImage, unsigned char nThreshold)
04012 {
04013         OPTIMIZED_FUNCTION_HEADER_3(ThresholdFilterInverse, pInputImage, pOutputImage, nThreshold)
04014         
04015         if (pInputImage->width != pOutputImage->width || pInputImage->height != pOutputImage->height ||
04016                 pInputImage->type != pOutputImage->type || pInputImage->type != CByteImage::eGrayScale)
04017         {
04018                 printf("error: input and output image do not match for ImageProcessor::ThresholdFilterInverse\n");
04019                 return false;
04020         }
04021                 
04022         unsigned char *input = pInputImage->pixels;
04023         unsigned char *output = pOutputImage->pixels;
04024         const int nPixels = pInputImage->width * pInputImage->height;
04025 
04026         for (int i = 0; i < nPixels; i++)
04027                 output[i] = input[i] <= nThreshold ? input[i] : 0;
04028         
04029         OPTIMIZED_FUNCTION_FOOTER
04030 
04031         return true;
04032 }
04033 
04034 
04035 bool ImageProcessor::FilterRGB(const CByteImage *pInputImage, CByteImage *pOutputImage, CRGBColorModel *pColorModel, float fThreshold)
04036 {
04037         if (pInputImage->width != pOutputImage->width || pInputImage->height != pOutputImage->height ||
04038                 pInputImage->type != CByteImage::eRGB24 || pOutputImage->type != CByteImage::eGrayScale)
04039         {
04040                 printf("error: input and output image do not match for ImageProcessor::FilterRGB\n");
04041                 return false;
04042         }
04043                 
04044         const unsigned char *input = pInputImage->pixels;
04045         unsigned char *output = pOutputImage->pixels;
04046         const int nPixels = pInputImage->width * pInputImage->height;
04047         int offset = 0;
04048 
04049         for (int i = 0; i < nPixels; i++, offset += 3)
04050         {
04051                 Vec3d rgb = { input[offset], input[offset + 1], input[offset + 2] };
04052                 output[i] = pColorModel->CalculateColorProbability(rgb) > fThreshold ? 255 : 0;
04053         }
04054 
04055         return true;
04056 }
04057 
04058 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)
04059 {
04060         if (pInputImage->width != pOutputImage->width || pInputImage->height != pOutputImage->height ||
04061                 (pInputImage->type != CByteImage::eRGB24 && pInputImage->type != CByteImage::eRGB24Split) || pOutputImage->type != CByteImage::eGrayScale)
04062         {
04063                 printf("error: input and output image do not match for ImageProcessor::FilterHSV\n");
04064                 return false;
04065         }
04066         
04067         int min_hue = (int) hue - (int) tol_hue;
04068         int max_hue = (int) hue + (int) tol_hue;
04069 
04070         if (min_hue < 0)
04071                 min_hue += 180;
04072 
04073         if (max_hue >= 180)
04074                 max_hue -= 180;
04075 
04076     if(tol_hue > 89)
04077     {
04078         min_hue = 0;
04079         max_hue = 179;
04080     }
04081 
04082         return FilterHSV2(pInputImage, pOutputImage, (unsigned char) min_hue, (unsigned char) max_hue, min_sat, max_sat, min_v, max_v, pROI);
04083 }
04084 
04085 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)
04086 {
04087         OPTIMIZED_FUNCTION_HEADER_8_ROI(FilterHSV2, pInputImage, pOutputImage, min_hue, max_hue, min_sat, max_sat, min_v, max_v, pROI)
04088         
04089         if (pInputImage->width != pOutputImage->width || pInputImage->height != pOutputImage->height ||
04090                 (pInputImage->type != CByteImage::eRGB24 && pInputImage->type != CByteImage::eRGB24Split) || pOutputImage->type != CByteImage::eGrayScale)
04091         {
04092                 printf("error: input and output image do not match for ImageProcessor::FilterHSV2\n");
04093                 return false;
04094         }
04095         
04096         if (pInputImage->type == CByteImage::eRGB24)
04097         {
04098                 const unsigned char *input_h = pInputImage->pixels;
04099                 const unsigned char *input_s = pInputImage->pixels + 1;
04100                 const unsigned char *input_v = pInputImage->pixels + 2;
04101                 unsigned char *output = pOutputImage->pixels;
04102                 
04103                 if (pROI)
04104                 {
04105                         const int width = pInputImage->width;
04106                         const int height = pInputImage->height;
04107                         
04108                         int min_x = pROI->min_x;
04109                         int max_x = pROI->max_x;
04110                         int min_y = pROI->min_y;
04111                         int max_y = pROI->max_y;
04112                         
04113                         if (min_x < 0) min_x = 0;
04114                         if (min_x > width - 1) min_x = width - 1;
04115                         if (max_x < 0) max_x = 0;
04116                         if (max_x > width - 1) max_x = width - 1;
04117                         if (min_y < 0) min_y = 0;
04118                         if (min_y > height - 1) min_y = height - 1;
04119                         if (max_y < 0) max_y = 0;
04120                         if (max_y > height - 1) max_y = height - 1;
04121                         
04122                         const int diff = width - (max_x - min_x + 1);
04123                         const int diff_rgb = 3 * diff;
04124                         
04125                         if (max_hue >= min_hue)
04126                         {
04127                                 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)
04128                                         for (int x = min_x; x <= max_x; x++, offset++, offset_rgb += 3)
04129                                                 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;
04130                         }
04131                         else
04132                         {
04133                                 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)
04134                                         for (int x = min_x; x <= max_x; x++, offset++, offset_rgb += 3)
04135                                                 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;
04136                         }
04137                 }
04138                 else
04139                 {
04140                         const int nPixels = pInputImage->width * pInputImage->height;
04141                         
04142                         if (max_hue >= min_hue)
04143                         {
04144                                 for (int i = 0, offset = 0; i < nPixels; i++, offset += 3)
04145                                         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;
04146                         }
04147                         else
04148                         {
04149                                 for (int i = 0, offset = 0; i < nPixels; i++, offset += 3)
04150                                         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;
04151                         }
04152                 }
04153         }
04154         else
04155         {
04156                 const int width = pInputImage->width;
04157                 const int height = pInputImage->height;
04158                 const int nPixels = width * height;
04159                 
04160                 const unsigned char *input_h = pInputImage->pixels;
04161                 const unsigned char *input_s = input_h + nPixels;
04162                 const unsigned char *input_v = input_s + nPixels;
04163                 unsigned char *output = pOutputImage->pixels;
04164                 
04165                 if (pROI)
04166                 {
04167                         int min_x = pROI->min_x;
04168                         int max_x = pROI->max_x;
04169                         int min_y = pROI->min_y;
04170                         int max_y = pROI->max_y;
04171                         
04172                         if (min_x < 0) min_x = 0;
04173                         if (min_x > width - 1) min_x = width - 1;
04174                         if (max_x < 0) max_x = 0;
04175                         if (max_x > width - 1) max_x = width - 1;
04176                         if (min_y < 0) min_y = 0;
04177                         if (min_y > height - 1) min_y = height - 1;
04178                         if (max_y < 0) max_y = 0;
04179                         if (max_y > height - 1) max_y = height - 1;
04180                         
04181                         const int diff = width - (max_x - min_x + 1);
04182                         
04183                         if (max_hue >= min_hue)
04184                         {
04185                                 for (int y = min_y, offset = min_y * width + min_x; y <= max_y; y++, offset += diff)
04186                                         for (int x = min_x; x <= max_x; x++, offset++)
04187                                                 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;
04188                         }
04189                         else
04190                         {
04191                                 for (int y = min_y, offset = min_y * width + min_x; y <= max_y; y++, offset += diff)
04192                                         for (int x = min_x; x <= max_x; x++, offset++)
04193                                                 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;
04194                         }
04195                 }
04196                 else
04197                 {
04198                         if (max_hue >= min_hue)
04199                         {
04200                                 for (int i = 0; i < nPixels; i++)
04201                                         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;
04202                         }
04203                         else
04204                         {
04205                                 for (int i = 0; i < nPixels; i++)
04206                                         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;
04207                         }
04208                 }
04209         }
04210         
04211         OPTIMIZED_FUNCTION_FOOTER
04212 
04213         return true;
04214 }
04215 
04216 
04217 
04218 bool ImageProcessor::FilterColor(const CByteImage *pInputImage, CByteImage *pOutputImage, ObjectColor cColor, CColorParameterSet* pColorParameterSet, bool bImageIsHSV)
04219 {
04220     const int* pParams = pColorParameterSet->GetColorParameters(cColor);
04221 
04222     bool bRet;
04223     if (bImageIsHSV)
04224     {
04225         bRet = FilterHSV(pInputImage, pOutputImage, pParams[0], pParams[1], pParams[2], pParams[3], pParams[4], pParams[5]);
04226     }
04227     else
04228     {
04229         CByteImage* pImage = new CByteImage(pInputImage);
04230         CalculateHSVImage(pInputImage, pImage);
04231         bRet = FilterHSV(pImage, pOutputImage, pParams[0], pParams[1], pParams[2], pParams[3], pParams[4], pParams[5]);
04232         delete pImage;
04233     }
04234     return bRet;
04235 }
04236 
04237 
04238 
04239 // Original version of this function by Olaf Fischer
04240 bool ImageProcessor::Rotate180Degrees(const CByteImage *pInputImage, CByteImage *pOutputImage)
04241 {
04242         if (pInputImage->width != pOutputImage->width || pInputImage->height != pOutputImage->height || pInputImage->type != pOutputImage->type || pInputImage->type == CByteImage::eRGB24Split)
04243         {
04244                 printf("error: input and output image do not match for ImageProcessor::Rotate180Degrees\n");
04245                 return false;
04246         }
04247         
04248         CByteImage *pSaveOutputImage = 0;
04249         if (pInputImage->pixels == pOutputImage->pixels)
04250         {
04251                 pSaveOutputImage = pOutputImage;
04252                 pOutputImage = new CByteImage(pInputImage);
04253         }
04254         
04255         const int nBytes = pInputImage->width * pInputImage->height * pInputImage->bytesPerPixel; 
04256         const int nLastPixel = nBytes - pInputImage->bytesPerPixel;
04257         const unsigned char *input = pInputImage->pixels;
04258         unsigned char *output = pOutputImage->pixels;
04259 
04260         if (pInputImage->type == CByteImage::eGrayScale)
04261         {
04262                 for (int i = 0; i < nBytes; i++)
04263                         output[i] = input[nLastPixel - i];
04264         }
04265         else if (pInputImage->type == CByteImage::eRGB24)
04266         {
04267                 for (int i = 0; i < nBytes; i += 3)
04268                 {
04269                         output[i + 2] = input[nLastPixel - i + 2];
04270                         output[i + 1] = input[nLastPixel - i + 1];
04271                         output[i] = input[nLastPixel - i];
04272                 }
04273         }
04274   
04275         if (pSaveOutputImage)
04276         {
04277                 CopyImage(pOutputImage, pSaveOutputImage);
04278                 delete pOutputImage;
04279         }
04280 
04281         return true;
04282 }
04283 
04284 
04285 static int _RegionGrowing(unsigned char *pixels, int width, int offset, int *stack, int *region, MyRegion &resultRegion, int nMinimumPointsPerRegion, int nMaximumPointsPerRegion, bool bCalculateBoundingBox)
04286 {
04287         resultRegion.nSeedOffset = offset;
04288 
04289         int sp = 0, nPixels = 0;
04290         
04291         stack[sp++] = offset;
04292         pixels[offset] = 254;
04293         
04294         while (sp--)
04295         {
04296                 const int offset = stack[sp];
04297                 
04298                 if (pixels[offset - width] == 255)
04299                 {
04300                         pixels[offset - width] = 254;
04301                         stack[sp++] = offset - width;
04302                 }
04303                 
04304                 if (pixels[offset - 1] == 255)
04305                 {
04306                         pixels[offset - 1] = 254;
04307                         stack[sp++] = offset - 1;
04308                 }
04309                 
04310                 if (pixels[offset + 1] == 255)
04311                 {
04312                         pixels[offset + 1] = 254;
04313                         stack[sp++] = offset + 1;
04314                 }
04315                 
04316                 if (pixels[offset + width] == 255)
04317                 {
04318                         pixels[offset + width] = 254;
04319                         stack[sp++] = offset + width;
04320                 }
04321                 
04322                 region[nPixels++] = offset;
04323         }
04324         
04325         if ((nMinimumPointsPerRegion > 0 && nPixels < nMinimumPointsPerRegion) || (nMaximumPointsPerRegion > 0 && nPixels > nMaximumPointsPerRegion))
04326                 return 0;
04327         
04328         int cx = 0, cy = 0;
04329         
04330         if (bCalculateBoundingBox)
04331         {
04332                 const int x = offset % width;
04333                 const int y = offset / width;
04334                 int min_x = x, max_x = x, min_y = y, max_y = y;
04335         
04336                 for (int i = 0; i < nPixels; i++)
04337                 {
04338                         const int offset = region[i];
04339                         const int x = offset % width;
04340                         const int y = offset / width;
04341                 
04342                         cx += x;
04343                         cy += y;
04344                 
04345                         if (x < min_x)
04346                                 min_x = x;
04347                         
04348                         if (x > max_x)
04349                                 max_x = x;
04350                         
04351                         if (y < min_y)
04352                                 min_y = y;
04353                         
04354                         if (y > max_y)
04355                                 max_y = y;
04356                 }
04357                 
04358                 resultRegion.min_x = min_x;
04359                 resultRegion.min_y = min_y;
04360                 resultRegion.max_x = max_x;
04361                 resultRegion.max_y = max_y;
04362                 resultRegion.ratio = float(max_x - min_x + 1) / float(max_y - min_y + 1);
04363         }
04364         else
04365         {
04366                 for (int i = 0; i < nPixels; i++)
04367                 {
04368                         const int offset = region[i];
04369                         
04370                         cx += offset % width;
04371                         cy += offset / width;
04372                 }
04373                 
04374                 resultRegion.min_x = -1;
04375                 resultRegion.min_y = -1;
04376                 resultRegion.max_x = -1;
04377                 resultRegion.max_y = -1;
04378                 resultRegion.ratio = 0.0f;
04379         }
04380         
04381         // fill rest of region struct
04382         resultRegion.nPixels = nPixels;
04383         resultRegion.centroid.x = float(cx) / nPixels;
04384         resultRegion.centroid.y = float(cy) / nPixels;
04385         
04386         return nPixels;
04387 }
04388 
04389 int ImageProcessor::RegionGrowing(const CByteImage *pImage, MyRegion &resultRegion, int x, int y, int nMinimumPointsPerRegion, int nMaximumPointsPerRegion, bool bCalculateBoundingBox, bool bStorePixels)
04390 {
04391         if (pImage->type != CByteImage::eGrayScale)
04392         {
04393                 printf("error: input image should be grayscale for ImageProcessor::RegionGrowing\n");
04394                 return -1;
04395         }
04396 
04397         const int width = pImage->width;
04398         const int height = pImage->height;
04399         
04400         if (x < 0 || x >= width || y < 0 || y >= height)
04401         {
04402                 printf("error: x/y is not within bounds of image in ImageProcessor::RegionGrowing\n");
04403                 return -1;
04404         }
04405 
04406         // create image with additional 1 pixel border
04407         CByteImage *pTempImage = new CByteImage(width + 2, height + 2, CByteImage::eGrayScale);
04408 
04409         const int temp_width = pTempImage->width;
04410         const int temp_height = pTempImage->height;
04411 
04412         unsigned char *temp = pTempImage->pixels;
04413                 
04414         // copy contents
04415         unsigned char *temp_helper = temp + temp_width + 1;
04416 
04417         for (int i = 0; i < pImage->height; i++)
04418                 memcpy(temp_helper + i * temp_width, pImage->pixels + i * width, width);
04419 
04420         // zero frame
04421         ImageProcessor::ZeroFrame(pTempImage);
04422 
04423         // allocate memory
04424         const int nPixels = temp_width * temp_height;
04425 
04426         int *pStack = new int[nPixels];
04427         int *pRegionPixels = new int[nPixels];
04428 
04429         // perform region growing
04430         const int nRegionPixels = _RegionGrowing(temp, temp_width, (y + 1) * temp_width + (x + 1), pStack, pRegionPixels, resultRegion, nMinimumPointsPerRegion, nMaximumPointsPerRegion, bCalculateBoundingBox);
04431 
04432         if (resultRegion.pPixels)
04433         {
04434                 delete [] resultRegion.pPixels;
04435                 resultRegion.pPixels = 0;
04436         }
04437         
04438         if (nRegionPixels > 0)
04439         {
04440                 if (bStorePixels)
04441                 {
04442                         resultRegion.pPixels = new int[nRegionPixels];
04443 
04444                         for (int j = 0; j < nRegionPixels; j++)
04445                         {
04446                                 const int x = pRegionPixels[j] % temp_width;
04447                                 const int y = pRegionPixels[j] / temp_width;
04448 
04449                                 resultRegion.pPixels[j] = (y - 1) * width + x - 1;
04450                         }
04451                 }
04452                 
04453                 // correct coordinates
04454                 resultRegion.centroid.x -= 1.0f;
04455                 resultRegion.centroid.y -= 1.0f;
04456 
04457                 resultRegion.min_x -= 1;
04458                 resultRegion.min_y -= 1;
04459                 resultRegion.max_x -= 1;
04460                 resultRegion.max_y -= 1;
04461 
04462                 resultRegion.nSeedOffset = (resultRegion.nSeedOffset / temp_width - 1) * width + (resultRegion.nSeedOffset % temp_width - 1);
04463         }
04464 
04465         // free memory
04466         delete pTempImage;
04467         delete [] pStack;
04468         delete [] pRegionPixels;
04469 
04470         return nRegionPixels;
04471 }
04472 
04473 bool ImageProcessor::FindRegions(const CByteImage *pImage, RegionList &regionList, int nMinimumPointsPerRegion, int nMaximumPointsPerRegion, bool bCalculateBoundingBox, bool bStorePixels)
04474 {
04475         // clear result list
04476         regionList.clear();
04477 
04478         if (pImage->type != CByteImage::eGrayScale)
04479         {
04480                 printf("error: input image should be grayscale for ImageProcessor::FindRegions\n");
04481                 return false;
04482         }
04483 
04484         const int width = pImage->width;
04485         const int height = pImage->height;
04486         
04487         // create image with additional 1 pixel border
04488         CByteImage *pTempImage = new CByteImage(width + 2, height + 2, CByteImage::eGrayScale);
04489 
04490         const int temp_width = pTempImage->width;
04491         const int temp_height = pTempImage->height;
04492 
04493         unsigned char *temp = pTempImage->pixels;
04494                 
04495         // copy contents
04496         unsigned char *temp_helper = temp + temp_width + 1;
04497 
04498         for (int y = 0; y < pImage->height; y++)
04499                 memcpy(temp_helper + y * temp_width, pImage->pixels + y * width, width);
04500 
04501         // zero frame
04502         ImageProcessor::ZeroFrame(pTempImage);
04503 
04504         // allocate memory
04505         const int nPixels = temp_width * temp_height;
04506 
04507         int *pStack = new int[nPixels];
04508         int *pRegionPixels = new int[nPixels];
04509 
04510         // go through image
04511         for (int i = 0; i < nPixels; i++)
04512         {
04513                 if (temp[i] == 255)
04514                 {
04515                         MyRegion region;
04516                                 
04517                         // do region growing
04518                         const int nRegionPixels = _RegionGrowing(temp, temp_width, i, pStack, pRegionPixels, region, nMinimumPointsPerRegion, nMaximumPointsPerRegion, bCalculateBoundingBox);
04519                         
04520                         if (nRegionPixels > 0)
04521                         {
04522                                 // first add
04523                                 regionList.push_back(region);
04524 
04525                                 // then copy (this way a double copy through copy constructor is avoided)
04526                                 // and correct coordinates
04527                                 MyRegion &addedEntry = regionList.back();
04528 
04529                                 // correct coordinates
04530                                 addedEntry.centroid.x -= 1.0f;
04531                                 addedEntry.centroid.y -= 1.0f;
04532 
04533                                 addedEntry.min_x -= 1;
04534                                 addedEntry.min_y -= 1;
04535                                 addedEntry.max_x -= 1;
04536                                 addedEntry.max_y -= 1;
04537 
04538                                 if (bStorePixels)
04539                                 {
04540                                         addedEntry.pPixels = new int[nRegionPixels];
04541 
04542                                         for (int j = 0; j < nRegionPixels; j++)
04543                                         {
04544                                                 const int x = pRegionPixels[j] % temp_width;
04545                                                 const int y = pRegionPixels[j] / temp_width;
04546 
04547                                                 addedEntry.pPixels[j] = (y - 1) * width + x - 1;
04548                                         }
04549                                         
04550                                         addedEntry.nSeedOffset = (addedEntry.nSeedOffset / temp_width - 1) * width + (addedEntry.nSeedOffset % temp_width - 1);
04551                                 }
04552                         }
04553                 }
04554         }
04555 
04556         // free memory
04557         delete pTempImage;
04558         delete [] pStack;
04559         delete [] pRegionPixels;
04560 
04561         return true;
04562 }
04563 
04564 bool ImageProcessor::FindRegions(const CByteImage *pImage, CRegionArray &regionList, int nMinimumPointsPerRegion, int nMaximumPointsPerRegion, bool bCalculateBoundingBox, bool bStorePixels)
04565 {
04566         // clear result list
04567         regionList.Clear();
04568 
04569         if (pImage->type != CByteImage::eGrayScale)
04570         {
04571                 printf("error: input image should be grayscale for ImageProcessor::FindRegions\n");
04572                 return false;
04573         }
04574 
04575         const int width = pImage->width;
04576         const int height = pImage->height;
04577         
04578         // create image with additional 1 pixel border
04579         CByteImage *pTempImage = new CByteImage(width + 2, height + 2, CByteImage::eGrayScale);
04580 
04581         const int temp_width = pTempImage->width;
04582         const int temp_height = pTempImage->height;
04583 
04584         unsigned char *temp = pTempImage->pixels;
04585                 
04586         // copy contents
04587         unsigned char *temp_helper = temp + temp_width + 1;
04588 
04589         for (int y = 0; y < pImage->height; y++)
04590                 memcpy(temp_helper + y * temp_width, pImage->pixels + y * width, width);
04591 
04592         // zero frame
04593         ImageProcessor::ZeroFrame(pTempImage);
04594 
04595         // allocate memory
04596         const int nPixels = temp_width * temp_height;
04597 
04598         int *pStack = new int[nPixels];
04599         int *pRegionPixels = new int[nPixels];
04600 
04601         // go through image
04602         for (int i = 0; i < nPixels; i++)
04603         {
04604                 if (temp[i] == 255)
04605                 {
04606                         MyRegion region;
04607                                 
04608                         // do region growing
04609                         const int nRegionPixels = _RegionGrowing(temp, temp_width, i, pStack, pRegionPixels, region, nMinimumPointsPerRegion, nMaximumPointsPerRegion, bCalculateBoundingBox);
04610                         
04611                         if (nRegionPixels > 0)
04612                         {
04613                                 // first add
04614                                 regionList.AddElement(region);
04615 
04616                                 // then copy (this way a double copy through copy constructor is avoided)
04617                                 // and correct coordinates
04618                                 MyRegion &addedEntry = regionList[regionList.GetSize() - 1];
04619 
04620                                 // correct coordinates
04621                                 addedEntry.centroid.x -= 1.0f;
04622                                 addedEntry.centroid.y -= 1.0f;
04623 
04624                                 addedEntry.min_x -= 1;
04625                                 addedEntry.min_y -= 1;
04626                                 addedEntry.max_x -= 1;
04627                                 addedEntry.max_y -= 1;
04628 
04629                                 if (bStorePixels)
04630                                 {
04631                                         addedEntry.pPixels = new int[nRegionPixels];
04632 
04633                                         for (int j = 0; j < nRegionPixels; j++)
04634                                         {
04635                                                 const int x = pRegionPixels[j] % temp_width;
04636                                                 const int y = pRegionPixels[j] / temp_width;
04637 
04638                                                 addedEntry.pPixels[j] = (y - 1) * width + x - 1;
04639                                         }
04640                                         
04641                                         addedEntry.nSeedOffset = (addedEntry.nSeedOffset / temp_width - 1) * width + (addedEntry.nSeedOffset % temp_width - 1);
04642                                 }
04643                         }
04644                 }
04645         }
04646 
04647         // free memory
04648         delete pTempImage;
04649         delete [] pStack;
04650         delete [] pRegionPixels;
04651 
04652         return true;
04653 }
04654 
04655 
04656 bool ImageProcessor::CalculateHSVImage(const CByteImage *pInputImage, CByteImage *pOutputImage, const MyRegion *pROI)
04657 {
04658         OPTIMIZED_FUNCTION_HEADER_2_ROI(CalculateHSVImage, pInputImage, pOutputImage, pROI)
04659         
04660         if (pInputImage->width != pOutputImage->width || pInputImage->height != pOutputImage->height ||
04661                 pInputImage->type != pOutputImage->type || (pInputImage->type != CByteImage::eRGB24 && pInputImage->type != CByteImage::eRGB24Split))
04662         {
04663                 printf("error: input and output image do not match for ImageProcessor::CalculateHSVImage\n");
04664                 return false;
04665         }
04666                 
04667         const unsigned char *input = pInputImage->pixels;
04668         unsigned char *output = pOutputImage->pixels;
04669         
04670         if (pROI)
04671         {
04672                 if (pInputImage->type == CByteImage::eRGB24)
04673                 {
04674                         const int width = pInputImage->width;
04675                         const int height = pInputImage->height;
04676                         
04677                         int min_x = pROI->min_x;
04678                         int max_x = pROI->max_x;
04679                         int min_y = pROI->min_y;
04680                         int max_y = pROI->max_y;
04681                         
04682                         if (min_x < 0) min_x = 0;
04683                         if (min_x > width - 1) min_x = width - 1;
04684                         if (max_x < 0) max_x = 0;
04685                         if (max_x > width - 1) max_x = width - 1;
04686                         if (min_y < 0) min_y = 0;
04687                         if (min_y > height - 1) min_y = height - 1;
04688                         if (max_y < 0) max_y = 0;
04689                         if (max_y > height - 1) max_y = height - 1;
04690                         
04691                         const int diff = 3 * (width - (max_x - min_x + 1));
04692                         
04693                         for (int y = min_y, offset = 3 * (min_y * width + min_x); y <= max_y; y++, offset += diff)
04694                         {
04695                                 for (int x = min_x; x <= max_x; x++, offset += 3)
04696                                 {
04697                                         const int r = input[offset];
04698                                         const int g = input[offset + 1];
04699                                         const int b = input[offset + 2];
04700                                         
04701                                         const int max = MY_MAX(MY_MAX(r, g), b);
04702                                         const int min = MY_MIN(MY_MIN(r, g), b);
04703                                         const int delta = max - min;
04704                                 
04705                                         // unoptimized: delta * 255 / max;
04706                                         const int s = (255 * delta * division_table[max]) >> 20;
04707                                         int h;
04708                                         
04709                                         // unoptimized: 30 * (g - b) / delta (etc.)
04710                                         if (r == max)
04711                                                 h = g > b ? 180 + ((30 * (g - b) * division_table[delta]) >> 20) : 180 - ((30 * (b - g) * division_table[delta]) >> 20);
04712                                         else if (g == max)
04713                                                 h = b > r ? 60 + ((30 * (b - r) * division_table[delta]) >> 20) : 60 - ((30 * (r - b) * division_table[delta]) >> 20);
04714                                         else
04715                                                 h = r > g ? 120 + ((30 * (r - g) * division_table[delta]) >> 20) : 120 - ((30 * (g - r) * division_table[delta]) >> 20);
04716                                         
04717                                         if (h >= 180) h -= 180;
04718                                         
04719                                         output[offset] = h;
04720                                         output[offset + 1] = s;
04721                                         output[offset + 2] = max;
04722                                 }
04723                         }
04724                 }
04725                 else
04726                 {
04727                         const int width = pInputImage->width;
04728                         const int height = pInputImage->height;
04729                         
04730                         const int nPixels = width * height;
04731                         
04732                         const unsigned char *input_r = input;
04733                         const unsigned char *input_g = input_r + nPixels;
04734                         const unsigned char *input_b = input_g + nPixels;
04735                         unsigned char *output_r = output;
04736                         unsigned char *output_g = output_r + nPixels;
04737                         unsigned char *output_b = output_g + nPixels;
04738                         
04739                         int min_x = pROI->min_x;
04740                         int max_x = pROI->max_x;
04741                         int min_y = pROI->min_y;
04742                         int max_y = pROI->max_y;
04743                         
04744                         if (min_x < 0) min_x = 0;
04745                         if (min_x > width - 1) min_x = width - 1;
04746                         if (max_x < 0) max_x = 0;
04747                         if (max_x > width - 1) max_x = width - 1;
04748                         if (min_y < 0) min_y = 0;
04749                         if (min_y > height - 1) min_y = height - 1;
04750                         if (max_y < 0) max_y = 0;
04751                         if (max_y > height - 1) max_y = height - 1;
04752                         
04753                         const int diff = width - (max_x - min_x + 1);
04754                         
04755                         for (int y = min_y, offset = min_y * width + min_x; y <= max_y; y++, offset += diff)
04756                         {
04757                                 for (int x = min_x; x <= max_x; x++, offset++)
04758                                 {
04759                                         const int r = input_r[offset];
04760                                         const int g = input_g[offset];
04761                                         const int b = input_b[offset];
04762                                         
04763                                         const int max = MY_MAX(MY_MAX(r, g), b);
04764                                         const int min = MY_MIN(MY_MIN(r, g), b);
04765                                         const int delta = max - min;
04766                                         
04767                                         // unoptimized: delta * 255 / max;
04768                                         const int s = (255 * delta * division_table[max]) >> 20;
04769                                         int h;
04770                                         
04771                                         // unoptimized: 30 * (g - b) / delta (etc.)
04772                                         if (r == max)
04773                                                 h = g > b ? 180 + ((30 * (g - b) * division_table[delta]) >> 20) : 180 - ((30 * (b - g) * division_table[delta]) >> 20);
04774                                         else if (g == max)
04775                                                 h = b > r ? 60 + ((30 * (b - r) * division_table[delta]) >> 20) : 60 - ((30 * (r - b) * division_table[delta]) >> 20);
04776                                         else
04777                                                 h = r > g ? 120 + ((30 * (r - g) * division_table[delta]) >> 20) : 120 - ((30 * (g - r) * division_table[delta]) >> 20);
04778                                         
04779                                         if (h >= 180) h -= 180;
04780                                         
04781                                         output_r[offset] = h;
04782                                         output_g[offset] = s;
04783                                         output_b[offset] = max;
04784                                 }
04785                         }
04786                 }
04787         }
04788         else
04789         {
04790                 if (pInputImage->type == CByteImage::eRGB24)
04791                 {
04792                         const int maxi = pInputImage->width * pInputImage->height * 3;
04793                         
04794                         for (int i = 0; i < maxi; i += 3)
04795                         {
04796                                 const int r = input[i];
04797                                 const int g = input[i + 1];
04798                                 const int b = input[i + 2];
04799                                 
04800                                 const int max = MY_MAX(MY_MAX(r, g), b);
04801                                 const int min = MY_MIN(MY_MIN(r, g), b);
04802                                 const int delta = max - min;
04803                         
04804                                 // unoptimized: delta * 255 / max;
04805                                 const int s = (255 * delta * division_table[max]) >> 20;
04806                                 int h;
04807                                 
04808                                 // unoptimized: 30 * (g - b) / delta (etc.)
04809                                 if (r == max)
04810                                         h = g > b ? 180 + ((30 * (g - b) * division_table[delta]) >> 20) : 180 - ((30 * (b - g) * division_table[delta]) >> 20);
04811                                 else if (g == max)
04812                                         h = b > r ? 60 + ((30 * (b - r) * division_table[delta]) >> 20) : 60 - ((30 * (r - b) * division_table[delta]) >> 20);
04813                                 else
04814                                         h = r > g ? 120 + ((30 * (r - g) * division_table[delta]) >> 20) : 120 - ((30 * (g - r) * division_table[delta]) >> 20);
04815                                 
04816                                 if (h >= 180) h -= 180;
04817                                 
04818                                 output[i] = h;
04819                                 output[i + 1] = s;
04820                                 output[i + 2] = max;
04821                         }
04822                 }
04823                 else
04824                 {
04825                         const int nPixels = pInputImage->width * pInputImage->height;
04826                         
04827                         const unsigned char *input_r = input;
04828                         const unsigned char *input_g = input_r + nPixels;
04829                         const unsigned char *input_b = input_g + nPixels;
04830                         unsigned char *output_r = output;
04831                         unsigned char *output_g = output_r + nPixels;
04832                         unsigned char *output_b = output_g + nPixels;
04833                         
04834                         for (int i = 0; i < nPixels; i++)
04835                         {
04836                                 const int r = input_r[i];
04837                                 const int g = input_g[i];
04838                                 const int b = input_b[i];
04839                                 
04840                                 const int max = MY_MAX(MY_MAX(r, g), b);
04841                                 const int min = MY_MIN(MY_MIN(r, g), b);
04842                                 const int delta = max - min;
04843                                 
04844                                 // unoptimized: delta * 255 / max;
04845                                 const int s = (255 * delta * division_table[max]) >> 20;
04846                                 int h;
04847                                 
04848                                 // unoptimized: 30 * (g - b) / delta (etc.)
04849                                 if (r == max)
04850                                         h = g > b ? 180 + ((30 * (g - b) * division_table[delta]) >> 20) : 180 - ((30 * (b - g) * division_table[delta]) >> 20);
04851                                 else if (g == max)
04852                                         h = b > r ? 60 + ((30 * (b - r) * division_table[delta]) >> 20) : 60 - ((30 * (r - b) * division_table[delta]) >> 20);
04853                                 else
04854                                         h = r > g ? 120 + ((30 * (r - g) * division_table[delta]) >> 20) : 120 - ((30 * (g - r) * division_table[delta]) >> 20);
04855                                 
04856                                 if (h >= 180) h -= 180;
04857                                 
04858                                 output_r[i] = h;
04859                                 output_g[i] = s;
04860                                 output_b[i] = max;
04861                         }
04862                 }
04863         }
04864         
04865         OPTIMIZED_FUNCTION_FOOTER
04866 
04867         return true;
04868 }
04869 
04870 
04871 bool ImageProcessor::HoughTransformLines(const CByteImage *pImage, CByteImage *pVisualizationImage, Vec2dList &resultLines, int nLinesToExtract, int nMinHits)
04872 {
04873         if (pImage->type == CByteImage::eGrayScale)
04874         {
04875                 printf("error: input image must be of type CByteImage::eGrayScale\n");
04876                 return false;
04877         }
04878 
04879         const int width = pImage->width;
04880         const int height = pImage->height;
04881         const unsigned char *pixels = pImage->pixels;
04882         
04883         const int m = 1 + 2 * (int(sqrtf(float(width * width + height * height))) + 1);
04884         const int m2 = m / 2;
04885         const float m2f = float(m2) + 0.5f;
04886         const int n = 180;
04887         const int nHoughPixels = n * m;
04888         
04889         CShortImage houghSpace(m, n);
04890         
04891         // reset bins
04892         ImageProcessor::Zero(&houghSpace);
04893         short *houghspace = houghSpace.pixels;
04894         
04895         // initialize lookup tables for sin and cos
04896         // function does initialization only for the first call
04897         InitSinCosTables();
04898         
04899         // perform hough transform
04900         for (int y = 0, offset = 0; y < height; y++)
04901         {
04902                 for (int x = 0; x < width; x++, offset++)
04903                 {
04904                         if (pixels[offset])
04905                         {
04906                                 for (int t = 0; t < n; t++)
04907                                 {
04908                                         const float r = x * cos_table[t] + y * sin_table[t];
04909                                         const int r_ = int(r + m2f);
04910                                         
04911                                         houghspace[t * m + r_]++;
04912                                 }
04913                         }
04914                 }
04915         }
04916         
04917         resultLines.clear();
04918         
04919         // find maxima
04920         for (int nn = 0; nn < nLinesToExtract; nn++)
04921         {
04922                 int max = nMinHits - 1, best_i = -1;
04923 
04924                 for (int i = 0; i < nHoughPixels; i++)
04925                 {
04926                         if (houghspace[i] > max)
04927                         {
04928                                 max = houghspace[i];
04929                                 best_i = i;
04930                         }
04931                 }
04932 
04933                 if (best_i != -1)
04934                 {
04935                         const int t = best_i / m;
04936                         const int r = best_i % m;
04937                         
04938                         const int w = 10;
04939 
04940                         for (int j = -w; j <= w; j++)
04941                         {
04942                                 for (int k = -w; k <= w; k++)
04943                                 {
04944                                         const int r_ = r + j;
04945                                         int t_ = t + k;
04946                                         
04947                                         if (t_ >= n)
04948                                                 t_ -= n;
04949                                         
04950                                         if (t_ < 0)
04951                                                 t_ += n;
04952                                         
04953                                         if (r_ >= 0 && r_ < m)
04954                                                 houghspace[t_ * m + r_] = 0;
04955                                 }
04956                         }
04957 
04958                         const float theta = t * FLOAT_DEG2RAD;
04959                         const int r_value = r - m2;
04960                         
04961                         const Vec2d g = { theta, float(r_value) };
04962                         resultLines.push_back(g);
04963                                         
04964                         if (pVisualizationImage)
04965                         {
04966                                 //printf("%i hits: (theta, r) = (%i, %i)\n", max, t, r_value);
04967                                 PrimitivesDrawer::DrawLinePolar(pVisualizationImage, theta, float(r_value), 255, 0, 0);
04968                         }
04969                 }
04970                 else
04971                         break;
04972         }
04973 
04974         return true;
04975 }
04976 
04977 bool ImageProcessor::HoughTransformCircles(const CByteImage *pImage, CByteImage *pVisualizationImage, Vec3dList &resultCircles, int rmin, int rmax, int nCirclesToExtract, int nMinHits)
04978 {
04979         if (rmin > rmax)
04980         {
04981                 printf("error: rmin (%i) may not be greater than rmax (%i) for ImageProcessor::HoughTransformCircles\n", rmin, rmax);
04982                 return false;
04983         }
04984         
04985         const int width = pImage->width;
04986         const int height = pImage->height;
04987         const unsigned char *pixels = pImage->pixels;
04988 
04989         const int n = width + 2 * rmax;
04990         const int m = height + 2 * rmax;
04991         const int nHoughPixels = n * m * (rmax - rmin + 1);
04992         
04993         short *houghspace = new short[nHoughPixels];
04994         
04995         // reset bins
04996         memset(houghspace, 0, nHoughPixels * sizeof(short));
04997 
04998         // initialize lookup tables for sin and cos
04999         // function does initialization only for the first call
05000         InitSinCosTables();
05001         
05002         const int mn = m * n;
05003         short *helper = houghspace - rmin * mn + rmax * m + rmax;
05004 
05005         // perform hough transform
05006         for (int v = 0, offset = 0; v < height; v++)
05007         {
05008                 for (int u = 0; u < width; u++, offset++)
05009                 {
05010                         if (pixels[offset] == 255)
05011                         {
05012                                 for (int t = 0; t < 180; t++)
05013                                 {
05014                                         for (int r = rmin; r <= rmax; r++)
05015                                         {
05016                                                 const int um = int(u - r * cos_table[t] + 0.5f);
05017                                                 const int vm1 = int(v - r * sin_table[t] + 0.5f);
05018                                                 const int vm2 = int(v + r * sin_table[t] + 0.5f);
05019                                         
05020                                                 //const int base = (r - rmin) * mn + (rmax + um) * m + rmax;
05021                                                 //houghspace[base + vm1]++;
05022                                                 //houghspace[base + vm2]++;
05023                                                 
05024                                                 const int base = r * mn + um * m;
05025                                                 helper[base + vm1]++;
05026                                                 helper[base + vm2]++;
05027                                         }
05028                                 }
05029                         }
05030                 }
05031         }
05032         
05033         resultCircles.clear();
05034 
05035         // find maxima
05036         for (int nn = 0; nn < nCirclesToExtract; nn++)
05037         {
05038                 int max = nMinHits - 1, best_i = -1;
05039 
05040                 for (int i = 0; i < nHoughPixels; i++)
05041                 {
05042                         if (houghspace[i] > max)
05043                         {
05044                                 max = houghspace[i];
05045                                 best_i = i;
05046                         }
05047                 }
05048 
05049                 if (best_i != -1)
05050                 {
05051                         int um = (best_i % mn) / m;
05052                         int vm = (best_i % mn) % m;
05053                         int r = best_i / mn;
05054                         
05055                         const int w = 5;
05056 
05057                         for (int j = -w; j <= w; j++)
05058                         {
05059                                 for (int k = -w; k <= w; k++)
05060                                 {
05061                                         for (int l = -w; l <= w; l++)
05062                                         {
05063                                                 const int um_ = um + j;
05064                                                 const int vm_ = vm + k;
05065                                                 const int r_ = r + l;
05066                                         
05067                                                 if (um_ >= 0 && um_ < n && vm >= 0 && vm < m && r_ >= 0 && r_ <= rmax - rmin)
05068                                                         houghspace[r_ * mn + um_ * m + vm_] = 0;
05069                                         }
05070                                 }
05071                         }
05072 
05073                         um -= rmax;
05074                         vm -= rmax;
05075                         r += rmin;
05076 
05077                         //printf("%i hits: (um vm) = (%i %i) --  r = = %i\n", max, um, vm, r);
05078 
05079                         const Vec3d circle = { float(um), float(vm), float(r) };
05080                         resultCircles.push_back(circle);
05081                                         
05082                         if (pVisualizationImage)
05083                         {
05084                                 Vec2d center = { float(um), float(vm) };
05085                                 PrimitivesDrawer::DrawCircle(pVisualizationImage, center, float(r), 255, 0, 0, 1);
05086                         }
05087                 }
05088                 else
05089                         break;
05090         }
05091         
05092         delete [] houghspace;
05093 
05094         return true;
05095 }
05096 
05097 void ImageProcessor::HoughTransformLines(const CVec2dArray &edgePoints, const CVec2dArray &edgeDirections, int width, int height, int nLinesToExtract, int nMinHits, CVec2dArray &resultLines, CIntArray &resultHits, CByteImage *pVisualizationImage)
05098 {
05099         // clear result list
05100         resultLines.Clear();
05101 
05102         // perform detection
05103         CStraightLine2dArray resultLines_;
05104 
05105         HoughTransformLines(edgePoints, edgeDirections, width, height, nLinesToExtract, nMinHits, resultLines_, resultHits, pVisualizationImage);
05106         
05107         // fill result list
05108         const int nResultLines = resultLines_.GetSize();
05109 
05110         for (int i = 0; i < nResultLines; i++)
05111         {
05112                 const StraightLine2d &line = resultLines_[i];
05113 
05114                 Vec2d x = { atan2f(line.normalVector.y, line.normalVector.x), -line.c };
05115 
05116                 resultLines.AddElement(x);
05117         }
05118 }
05119 
05120 void ImageProcessor::HoughTransformLines(const CVec2dArray &edgePoints, const CVec2dArray &edgeDirections, int width, int height, int nLinesToExtract, int nMinHits, CStraightLine2dArray &resultLines, CIntArray &resultHits, CByteImage *pVisualizationImage)
05121 {
05122         // clear result list
05123         resultLines.Clear();
05124 
05125         const int m = 1 + 2 * (int(sqrtf(float(width * width + height * height))) + 1);
05126         const int m2 = m / 2;
05127         const float m2f = float(m2) + 0.5f;
05128         const int n = 360;
05129         const int nHoughPixels = n * m;
05130         
05131         CShortImage houghSpace(m, n);
05132         
05133         // reset bins
05134         ImageProcessor::Zero(&houghSpace);
05135         short *houghspace = houghSpace.pixels;
05136         
05137         // initialize lookup tables for sin and cos
05138         // function does initialization only for the first call
05139         InitSinCosTables();
05140         
05141         // perform hough transform
05142         const int nEdgePoints = edgePoints.GetSize();
05143         for (int i = 0; i < nEdgePoints; i++)
05144         {
05145                 const Vec2d &point = edgePoints[i];
05146                 const Vec2d &direction = edgeDirections[i];
05147                 
05148                 const float angle = atan2f(direction.y, direction.x) + FLOAT_PI;
05149                 const int t0 = int(angle * FLOAT_RAD2DEG + 0.5f);
05150                 
05151                 const int t1 = t0 - 5;
05152                 const int t2 = t0 + 5;
05153                 
05154                 for (int t = t1; t <= t2; t++)
05155                 {
05156                         const float r = point.x * cos_table[t] + point.y * sin_table[t];
05157                         const int r_ = int(r + m2f);
05158                         
05159                         houghspace[((t + 360) % 360) * m + r_]++;
05160                 }
05161         }
05162         
05163         resultLines.Clear();
05164         resultHits.Clear();
05165         
05166         // find maxima
05167         for (int nn = 0; nn < nLinesToExtract; nn++)
05168         {
05169                 short max = nMinHits - 1;
05170                 int best_i = -1;
05171                 
05172                 for (int i = 0; i < nHoughPixels; i++)
05173                 {
05174                         if (houghspace[i] > max)
05175                         {
05176                                 max = houghspace[i];
05177                                 best_i = i;
05178                         }
05179                 }
05180                 
05181                 if (best_i != -1)
05182                 {
05183                         const int t = best_i / m;
05184                         const int r = best_i % m;
05185                         
05186                         const int w = 10;
05187                         
05188                         for (int j = -w; j <= w; j++)
05189                         {
05190                                 for (int k = -w; k <= w; k++)
05191                                 {
05192                                         const int r_ = r + j;
05193                                         int t_ = t + k;
05194                                         
05195                                         if (t_ >= n)
05196                                                 t_ -= n;
05197                                         
05198                                         if (t_ < 0)
05199                                                 t_ += n;
05200                                         
05201                                         if (r_ >= 0 && r_ < m)
05202                                                 houghspace[t_ * m + r_] = 0;
05203                                 }
05204                         }
05205                         
05206                         const float theta = t * FLOAT_DEG2RAD;
05207                         const int r_value = r - m2;
05208                         
05209                         StraightLine2d line(theta, -float(r_value));
05210                         resultLines.AddElement(line);
05211                         
05212                         if (pVisualizationImage)
05213                         {
05214                                 //printf("%i hits: (theta, r) = (%i, %i)\n", max, t, r_value);
05215                                 PrimitivesDrawer::DrawLine(pVisualizationImage, line, 255, 0, 0);
05216                         }
05217                 }
05218                 else
05219                         break;
05220         }
05221 }
05222 
05223 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)
05224 {
05225         // clear result list
05226         resultCircles.Clear();
05227 
05228         // perform detection
05229         CCircle2dArray resultCircles_;
05230 
05231         if (!HoughTransformCircles(edgePoints, edgeDirections, width, height, rmin, rmax, nCirclesToExtract, nMinHits, resultCircles_, resultHits, pVisualizationImage))
05232                 return false;
05233         
05234         // fill result list
05235         const int nResultCircles = resultCircles_.GetSize();
05236 
05237         for (int i = 0; i < nResultCircles; i++)
05238         {
05239                 const Circle2d &circle = resultCircles_[i];
05240 
05241                 Vec3d x = { circle.center.x, circle.center.y, circle.radius };
05242 
05243                 resultCircles.AddElement(x);
05244         }
05245 
05246         return true;
05247 }
05248 
05249 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)
05250 {
05251         // clear result list
05252         resultCircles.Clear();
05253 
05254         if (rmin > rmax)
05255         {
05256                 printf("error: rmin (%i) may not be greater than rmax (%i) for ImageProcessor::HoughTransformCircles\n", rmin, rmax);
05257                 return false;
05258         }
05259         
05260         const int n = width + 2 * rmax;
05261         const int m = height + 2 * rmax;
05262         const int nHoughPixels = n * m * (rmax - rmin + 1);
05263         
05264         short *houghspace = new short[nHoughPixels];
05265         
05266         // reset bins
05267         memset(houghspace, 0, nHoughPixels * sizeof(short));
05268         
05269         // initialize lookup tables for sin and cos
05270         // function does initialization only for the first call
05271         InitSinCosTables();
05272         
05273         const int mn = m * n;
05274         short *helper = houghspace - rmin * mn + rmax * m + rmax;
05275         
05276         // perform hough transform
05277         const int nEdgePoints = edgePoints.GetSize();
05278         
05279         for (int i = 0; i < nEdgePoints; i++)
05280         {
05281                 const Vec2d &point = edgePoints[i];
05282                 const Vec2d &direction = edgeDirections[i];
05283                 
05284                 const float u = point.x + 0.5f;
05285                 const float v = point.y + 0.5f;
05286                 
05287                 const float angle = atan2f(direction.y, direction.x) + FLOAT_PI;
05288                 const int t0 = int(angle * FLOAT_RAD2DEG + 0.5f);
05289                 
05290                 const int t1 = t0 - 3;
05291                 const int t2 = t0 + 3;
05292                 
05293                 for (int t = t1; t <= t2; t++)
05294                 {
05295                         for (int r = rmin; r <= rmax; r++)
05296                         {
05297                                 int um, vm;
05298                                 
05299                                 um = int(u + r * cos_table[t]);
05300                                 vm = int(v + r * sin_table[t]);
05301                                 helper[r * mn + um * m + vm]++;
05302                                 
05303                                 um = int(u - r * cos_table[t]);
05304                                 vm = int(v - r * sin_table[t]);
05305                                 helper[r * mn + um * m + vm]++;
05306                                 
05307                                 //const int offset = (r - rmin) * mn + (rmax + um) * m + rmax + vm;
05308                         }
05309                 }
05310         }
05311         
05312         resultCircles.Clear();
05313         
05314         // find maxima
05315         for (int nn = 0; nn < nCirclesToExtract; nn++)
05316         {
05317                 int max = nMinHits - 1, best_i = -1;
05318                 
05319                 for (int i = 0; i < nHoughPixels; i++)
05320                 {
05321                         if (houghspace[i] > max)
05322                         {
05323                                 max = houghspace[i];
05324                                 best_i = i;
05325                         }
05326                 }
05327                 
05328                 if (best_i != -1)
05329                 {
05330                         int um = (best_i % mn) / m;
05331                         int vm = (best_i % mn) % m;
05332                         int r = best_i / mn;
05333                         
05334                         const int w = 5;
05335                         
05336                         for (int j = -w; j <= w; j++)
05337                         {
05338                                 for (int k = -w; k <= w; k++)
05339                                 {
05340                                         for (int l = -w; l <= w; l++)
05341                                         {
05342                                                 int um_ = um + j;
05343                                                 int vm_ = vm + k;
05344                                                 int r_ = r + l;
05345                                                 
05346                                                 if (um_ >= 0 && um_ < n && vm >= 0 && vm < m && r_ >= 0 && r_ <= rmax - rmin)
05347                                                         houghspace[r_ * mn + um_ * m + vm_] = 0;
05348                                         }
05349                                 }
05350                         }
05351                         
05352                         um -= rmax;
05353                         vm -= rmax;
05354                         r += rmin;
05355                         
05356                         //printf("%i hits: (um vm) = (%i %i) --  r = = %i\n", max, um, vm, r);
05357                         
05358                         Circle2d circle;
05359                         Math2d::SetVec(circle.center, float(um), float(vm));
05360                         circle.radius = float(r);
05361 
05362                         resultCircles.AddElement(circle);
05363                         resultHits.AddElement(max);
05364                         
05365                         if (pVisualizationImage)
05366                                 PrimitivesDrawer::DrawCircle(pVisualizationImage, circle, 255, 0, 0, 1);
05367                 }
05368                 else
05369                         break;
05370         }
05371         
05372         delete [] houghspace;
05373 
05374         return true;
05375 }
05376 
05377 
05378 
05379 bool ImageProcessor::DetermineHomography(const Vec2d *pSourcePoints, const Vec2d *pTargetPoints, int nPoints,
05380         float &a1, float &a2, float &a3, float &a4, float &a5, float &a6, float &a7, float &a8)
05381 {
05382         Mat3d A;
05383         
05384         if (!LinearAlgebra::DetermineHomography(pSourcePoints, pTargetPoints, nPoints, A, false))
05385                 return false;
05386         
05387         a1 = A.r1;
05388         a2 = A.r2;
05389         a3 = A.r3;
05390         a4 = A.r4;
05391         a5 = A.r5;
05392         a6 = A.r6;
05393         a7 = A.r7;
05394         a8 = A.r8;
05395 
05396         return true;
05397 }
05398 
05399 bool ImageProcessor::DetermineAffineTransformation(const Vec2d *pSourcePoints, const Vec2d *pTargetPoints, int nPoints,
05400         float &a1, float &a2, float &a3, float &a4, float &a5, float &a6)
05401 {
05402         Mat3d A;
05403         
05404         if (!LinearAlgebra::DetermineAffineTransformation(pSourcePoints, pTargetPoints, nPoints, A, false))
05405                 return false;
05406         
05407         a1 = A.r1;
05408         a2 = A.r2;
05409         a3 = A.r3;
05410         a4 = A.r4;
05411         a5 = A.r5;
05412         a6 = A.r6;
05413 
05414         return true;
05415 }
05416 
05417 
05418 bool ImageProcessor::NormalizeColor(const CByteImage *pInputImage, CByteImage *pOutputImage)
05419 {
05420         if (pInputImage->type == CByteImage::eGrayScale)
05421         {
05422                 printf("error: input image must be of type CByteImage::eRGB24 or CByteImage::eRGB24Split for ImageProcessor::NormalizeColor\n");
05423                 return false;
05424         }
05425         
05426         if (!pInputImage->IsCompatible(pOutputImage))
05427         {
05428                 printf("error: input and output image must be of same size and type for ImageProcessor::NormalizeColor\n");
05429                 return false;
05430         }
05431 
05432         const int nPixels = pInputImage->width * pInputImage->height;
05433         const unsigned char *input = pInputImage->pixels;
05434 
05435         int redHistogram[256], greenHistogram[256], blueHistogram[256];
05436         float fNormalizeConstant = 255.0f / nPixels;
05437         int i;
05438 
05439         // reset bins
05440         memset(redHistogram, 0, sizeof(redHistogram));
05441         memset(greenHistogram, 0, sizeof(greenHistogram));
05442         memset(blueHistogram, 0, sizeof(blueHistogram));
05443 
05444         // calculate histograms
05445         int offset = 0;
05446         for (i = 0; i < nPixels; i++)
05447         {
05448                 redHistogram[input[offset]]++;
05449                 greenHistogram[input[offset + 1]]++;
05450                 blueHistogram[input[offset + 2]]++;
05451                 offset += 3;
05452         }
05453 
05454         // normalize histograms
05455         for (i = 1; i < 256; i++)
05456         {
05457                 redHistogram[i] += redHistogram[i - 1];
05458                 greenHistogram[i] += greenHistogram[i - 1];
05459                 blueHistogram[i] += blueHistogram[i - 1];
05460         }
05461 
05462         for (i = 0; i < 256; i++)
05463         {
05464                 redHistogram[i] = int(redHistogram[i] * fNormalizeConstant + 0.5f);
05465                 greenHistogram[i] = int(greenHistogram[i] * fNormalizeConstant + 0.5f);
05466                 blueHistogram[i] = int(blueHistogram[i] * fNormalizeConstant + 0.5f);
05467         }       
05468 
05469         // apply normalization
05470         if (pInputImage->type == CByteImage::eRGB24)
05471         {
05472                 const unsigned char *input_r = input;
05473                 const unsigned char *input_g = input_r + nPixels;
05474                 const unsigned char *input_b = input_g + nPixels;               
05475                 unsigned char *output_r = pOutputImage->pixels;
05476                 unsigned char *output_g = output_r + nPixels;
05477                 unsigned char *output_b = output_g + nPixels;
05478                 
05479                 for (int i = 0; i < nPixels; i++)
05480                 {
05481                         output_r[i] = redHistogram[input_r[i]];
05482                         output_g[i] = greenHistogram[input_g[i]];
05483                         output_b[i] = blueHistogram[input_b[i]];
05484                 }
05485         }
05486         else if (pInputImage->type == CByteImage::eRGB24Split)
05487         {
05488                 unsigned char *output = pOutputImage->pixels;
05489                 
05490                 for (int i = 0, offset = 0; i < nPixels; i++, offset += 3)
05491                 {
05492                         output[offset] = redHistogram[input[offset]];
05493                         output[offset + 1] = greenHistogram[input[offset + 1]];
05494                         output[offset + 2] = blueHistogram[input[offset + 2]];
05495                 }
05496         }
05497 
05498         return true;
05499 }
05500 
05501 
05502 bool ImageProcessor::GaussianSmooth5x5(const CFloatMatrix *pInputImage, CFloatMatrix *pOutputImage, float fVariance)
05503 {
05504         if (pInputImage->columns != pOutputImage->columns || pInputImage->rows != pOutputImage->rows)
05505         {
05506                 printf("error: input and output matrix do not match for ImageProcessor::GaussianSmooth5x5\n");
05507                 return false;
05508         }
05509 
05510         if (pInputImage->columns < 5 || pInputImage->rows < 5)
05511         {
05512                 printf("error: matrices must be at least of size 5x5 for ImageProcessor::GaussianSmooth5x5\n");
05513                 return false;
05514         }
05515 
05516         const int nKernelSize = 5;
05517         const int k = 2;//(nKernelSize - 1) / 2;
05518         
05519         float pFilter[nKernelSize];
05520         float sum = 0.0f;
05521         int i;
05522         
05523         // construct Gaussian kernel
05524         for (i = 0; i < nKernelSize; i++)
05525         {
05526                 pFilter[i] = expf(-(i - k) * (i - k) / (2.0f * fVariance));
05527                 sum += pFilter[i];
05528         }
05529   
05530         for (i = 0; i < nKernelSize; i++) 
05531                 pFilter[i] /= sum;
05532         
05533         // create temp image if necessary
05534         CFloatMatrix *pTempImage = new CFloatMatrix(pInputImage);
05535         
05536         const int width = pInputImage->columns;
05537         const int height = pInputImage->rows;
05538 
05539         const float *input = pInputImage->data;
05540         float *temp = pTempImage->data;
05541         float *output = pOutputImage->data;
05542         
05543         int x, y, d, offset;
05544         
05545         
05546         // x direction
05547         for (y = 0, offset = 0; y < height; y++)
05548         {
05549                 for (x = 0; x < k; x++, offset++)
05550                 {
05551                         float sum = 0.0f;
05552       
05553                         for (d = -k; d < -x; d++) 
05554                                 sum += input[y * width] * pFilter[k + d];
05555       
05556                         for (d = -x; d <= k; d++) 
05557                                 sum += input[offset + d] * pFilter[k + d];
05558       
05559                         temp[offset] = sum;
05560                 }
05561     
05562                 // core loop (optimized)
05563                 for (x = 2 * k; x < width; x++, offset++)
05564                 {
05565                         temp[offset] =
05566                                 input[offset - 2] * pFilter[0] +
05567                                 input[offset - 1] * pFilter[1] +
05568                                 input[offset] * pFilter[2] +
05569                                 input[offset + 1] * pFilter[3] +
05570                                 input[offset + 2] * pFilter[4];
05571                 }
05572     
05573                 for (x = width - k; x < width; x++, offset++)
05574                 {
05575                         float sum = 0.0f;
05576       
05577                         for (d = -k; d < width - x; d++) 
05578                                 sum += input[offset + d] * pFilter[k + d];
05579       
05580                         for (d = width - x; d <= k; d++) 
05581                                 sum += input[y * width + width - 1] * pFilter[k + d];
05582       
05583                         temp[offset] = sum;
05584                 }
05585         }
05586         
05587   
05588         // y direction
05589         for (y = 0; y < k; y++)
05590         {
05591                 for (x = 0; x < width; x++)
05592                 {
05593                         float sum = 0.0f;
05594       
05595                         for (d = -k; d < -y; d++) 
05596                                 sum += temp[x] * pFilter[k + d];
05597       
05598                         for (d = -y; d <= k; d++) 
05599                                 sum += temp[(y + d) * width + x] * pFilter[k + d];
05600         
05601                         output[y * width + x] = sum;
05602                 }
05603         }
05604     
05605         // core loop (optimized)
05606         for (y = 2 * k, offset = k * width; y < height; y++)
05607         {
05608                 for (x = 0; x < width; x++, offset++)
05609                 {
05610                         output[offset] =
05611                                 temp[offset - (width << 1)] * pFilter[0] +
05612                                 temp[offset - width] * pFilter[1] +
05613                                 temp[offset] * pFilter[2] +
05614                                 temp[offset + width] * pFilter[3] +
05615                                 temp[offset + (width << 1)] * pFilter[4];
05616                 }
05617     }
05618         
05619         for (y = height - k; y < height; y++)
05620         {
05621                 for (x = 0; x < width; x++)
05622                 {
05623                         float sum = 0.0f;
05624                 
05625                         for (d = -k; d < height - y; d++) 
05626                                 sum += temp[(y + d) * width + x] * pFilter[k + d];
05627       
05628                         for (d = height - y; d < k; d++) 
05629                                 sum += temp[(height - 1) * width + x] * pFilter[k + d];
05630       
05631                         output[y * width + x] = sum;
05632                 }
05633         }
05634         
05635 
05636         delete pTempImage;
05637 
05638         return true;
05639 }
05640 
05641 bool ImageProcessor::GaussianSmooth(const CByteImage *pInputImage, CByteImage *pOutputImage, float fVariance, int nKernelSize)
05642 {
05643         if (pInputImage->width != pOutputImage->width || pInputImage->height != pOutputImage->height || pInputImage->type != pOutputImage->type || pInputImage->type != CByteImage::eGrayScale)
05644         {
05645                 printf("error: input and output image do not match for ImageProcessor::GaussianSmooth\n");
05646                 return false;
05647         }
05648 
05649         if (pInputImage->width < nKernelSize || pInputImage->height < nKernelSize)
05650         {
05651                 printf("error: image must be at least of size nKernelSize x nKernelSize for ImageProcessor::GaussianSmooth\n");
05652                 return false;
05653         }
05654 
05655         const int k = (nKernelSize - 1) / 2;
05656         
05657         float *pFilter = new float[nKernelSize];
05658         float sum = 0.0f;
05659         int i;
05660         
05661         // construct Gaussian kernel
05662         for (i = 0; i < nKernelSize; i++)
05663         {
05664                 pFilter[i] = expf(-(i - k) * (i - k) / (2.0f * fVariance));
05665                 sum += pFilter[i];
05666         }
05667   
05668         for (i = 0; i < nKernelSize; i++) 
05669                 pFilter[i] /= sum;
05670         
05671         // create temp image
05672         CByteImage *pTempImage = new CByteImage(pInputImage);
05673         
05674         const int width = pInputImage->width;
05675         const int height = pInputImage->height;
05676 
05677         const unsigned char *input = pInputImage->pixels;
05678         unsigned char *temp = pTempImage->pixels;
05679         unsigned char *output = pOutputImage->pixels;
05680         
05681         int x, y, d, offset;
05682         
05683         
05684         // x direction
05685         for (y = 0, offset = 0; y < height; y++)
05686         {
05687                 for (x = 0; x < k; x++, offset++)
05688                 {
05689                         float sum = 0.0f;
05690       
05691                         for (d = -k; d < -x; d++) 
05692                                 sum += input[y * width] * pFilter[k + d];
05693       
05694                         for (d = -x; d <= k; d++) 
05695                                 sum += input[offset + d] * pFilter[k + d];
05696       
05697                         temp[offset] = (unsigned char) (sum + 0.5f);
05698                 }
05699     
05700                 // core loop
05701                 for (x = 2 * k; x < width; x++, offset++)
05702                 {
05703                         float sum = 0.0f;
05704 
05705                         for (d = -k; d <= k; d++)
05706                                 sum += input[offset + d] * pFilter[d + k];
05707 
05708                         temp[offset] = (unsigned char) (sum + 0.5f);
05709                 }
05710     
05711                 for (x = width - k; x < width; x++, offset++)
05712                 {
05713                         float sum = 0.0f;
05714       
05715                         for (d = -k; d < width - x; d++) 
05716                                 sum += input[offset + d] * pFilter[k + d];
05717       
05718                         for (d = width - x; d <= k; d++) 
05719                                 sum += input[y * width + width - 1] * pFilter[k + d];
05720       
05721                         temp[offset] = (unsigned char) (sum + 0.5f);
05722                 }
05723         }
05724         
05725   
05726         // y direction
05727         for (y = 0; y < k; y++)
05728         {
05729                 for (x = 0; x < width; x++)
05730                 {
05731                         float sum = 0.0f;
05732       
05733                         for (d = -k; d < -y; d++) 
05734                                 sum += temp[x] * pFilter[k + d];
05735       
05736                         for (d = -y; d <= k; d++) 
05737                                 sum += temp[(y + d) * width + x] * pFilter[k + d];
05738         
05739                         output[y * width + x] = (unsigned char) (sum + 0.5f);
05740                 }
05741         }
05742     
05743         // core loop
05744         for (y = 2 * k, offset = k * width; y < height; y++)
05745         {
05746                 for (x = 0; x < width; x++, offset++)
05747                 {
05748                         float sum = 0.0f;
05749 
05750                         for (d = -k; d <= k; d++)
05751                                 sum += temp[offset + d * width] * pFilter[d + k];
05752 
05753                         output[offset] = (unsigned char) (sum + 0.5f);
05754                 }
05755     }
05756         
05757         for (y = height - k; y < height; y++)
05758         {
05759                 for (x = 0; x < width; x++)
05760                 {
05761                         float sum = 0.0f;
05762                 
05763                         for (d = -k; d < height - y; d++) 
05764                                 sum += temp[(y + d) * width + x] * pFilter[k + d];
05765       
05766                         for (d = height - y; d < k; d++) 
05767                                 sum += temp[(height - 1) * width + x] * pFilter[k + d];
05768       
05769                         output[y * width + x] = (unsigned char) (sum + 0.5f);
05770                 }
05771         }
05772         
05773 
05774         delete pTempImage;
05775         delete [] pFilter;
05776 
05777         return true;
05778 }
05779 
05780 bool ImageProcessor::GaussianSmooth(const CByteImage *pInputImage, CFloatMatrix *pOutputImage, float fVariance, int nKernelSize)
05781 {
05782         if (pInputImage->width != pOutputImage->columns || pInputImage->height != pOutputImage->rows || pInputImage->type != CByteImage::eGrayScale)
05783         {
05784                 printf("error: input image and output matrix do not match for ImageProcessor::GaussianSmooth\n");
05785                 return false;
05786         }
05787 
05788         if (pInputImage->width < nKernelSize || pInputImage->height < nKernelSize)
05789         {
05790                 printf("error: image must be at least of size nKernelSize x nKernelSize for ImageProcessor::GaussianSmooth\n");
05791                 return false;
05792         }
05793 
05794         const int k = (nKernelSize - 1) / 2;
05795         
05796         float *pFilter = new float[nKernelSize];
05797         float sum = 0.0f;
05798         int i;
05799         
05800         // construct Gaussian kernel
05801         for (i = 0; i < nKernelSize; i++)
05802         {
05803                 pFilter[i] = expf(-(i - k) * (i - k) / (2.0f * fVariance));
05804                 sum += pFilter[i];
05805         }
05806   
05807         for (i = 0; i < nKernelSize; i++) 
05808                 pFilter[i] /= sum;
05809         
05810         // create temp image
05811         CFloatMatrix *pTempImage = new CFloatMatrix(pInputImage->width, pInputImage->height);
05812         
05813         const int width = pInputImage->width;
05814         const int height = pInputImage->height;
05815 
05816         const unsigned char *input = pInputImage->pixels;
05817         float *temp = pTempImage->data;
05818         float *output = pOutputImage->data;
05819         
05820         int x, y, d, offset;
05821         
05822         
05823         // x direction
05824         for (y = 0, offset = 0; y < height; y++)
05825         {
05826                 for (x = 0; x < k; x++, offset++)
05827                 {
05828                         float sum = 0.0f;
05829       
05830                         for (d = -k; d < -x; d++) 
05831                                 sum += input[y * width] * pFilter[k + d];
05832       
05833                         for (d = -x; d <= k; d++) 
05834                                 sum += input[offset + d] * pFilter[k + d];
05835       
05836                         temp[offset] = sum;
05837                 }
05838     
05839                 // core loop
05840                 for (x = 2 * k; x < width; x++, offset++)
05841                 {
05842                         float sum = 0.0f;
05843 
05844                         for (d = -k; d <= k; d++)
05845                                 sum += input[offset + d] * pFilter[d + k];
05846 
05847                         temp[offset] = sum;
05848                 }
05849     
05850                 for (x = width - k; x < width; x++, offset++)
05851                 {
05852                         float sum = 0.0f;
05853       
05854                         for (d = -k; d < width - x; d++) 
05855                                 sum += input[offset + d] * pFilter[k + d];
05856       
05857                         for (d = width - x; d <= k; d++) 
05858                                 sum += input[y * width + width - 1] * pFilter[k + d];
05859       
05860                         temp[offset] = sum;
05861                 }
05862         }
05863         
05864   
05865         // y direction
05866         for (y = 0; y < k; y++)
05867         {
05868                 for (x = 0; x < width; x++)
05869                 {
05870                         float sum = 0.0f;
05871       
05872                         for (d = -k; d < -y; d++) 
05873                                 sum += temp[x] * pFilter[k + d];
05874       
05875                         for (d = -y; d <= k; d++) 
05876                                 sum += temp[(y + d) * width + x] * pFilter[k + d];
05877         
05878                         output[y * width + x] = sum;
05879                 }
05880         }
05881     
05882         // core loop
05883         for (y = 2 * k, offset = k * width; y < height; y++)
05884         {
05885                 for (x = 0; x < width; x++, offset++)
05886                 {
05887                         float sum = 0.0f;
05888 
05889                         for (d = -k; d <= k; d++)
05890                                 sum += temp[offset + d * width] * pFilter[d + k];
05891 
05892                         output[offset] = sum;
05893                 }
05894     }
05895         
05896         for (y = height - k; y < height; y++)
05897         {
05898                 for (x = 0; x < width; x++)
05899                 {
05900                         float sum = 0.0f;
05901                 
05902                         for (d = -k; d < height - y; d++) 
05903                                 sum += temp[(y + d) * width + x] * pFilter[k + d];
05904       
05905                         for (d = height - y; d < k; d++) 
05906                                 sum += temp[(height - 1) * width + x] * pFilter[k + d];
05907       
05908                         output[y * width + x] = sum;
05909                 }
05910         }
05911         
05912 
05913         delete pTempImage;
05914         delete [] pFilter;
05915 
05916         return true;
05917 }
05918 
05919 bool ImageProcessor::GaussianSmooth(const CFloatMatrix *pInputImage, CFloatMatrix *pOutputImage, float fVariance, int nKernelSize)
05920 {
05921         if (pInputImage->columns != pOutputImage->columns || pInputImage->rows != pOutputImage->rows)
05922         {
05923                 printf("error: input and output matrix do not match for ImageProcessor::GaussianSmooth\n");
05924                 return false;
05925         }
05926 
05927         if (pInputImage->columns < nKernelSize || pInputImage->rows < nKernelSize)
05928         {
05929                 printf("error: matrix must be at least of size nKernelSize x nKernelSize for ImageProcessor::GaussianSmooth\n");
05930                 return false;
05931         }
05932 
05933         const int k = (nKernelSize - 1) / 2;
05934         
05935         float *pFilter = new float[nKernelSize];
05936         float sum = 0.0f;
05937         int i;
05938         
05939         // construct Gaussian kernel
05940         for (i = 0; i < nKernelSize; i++)
05941         {
05942                 pFilter[i] = expf(-(i - k) * (i - k) / (2.0f * fVariance));
05943                 sum += pFilter[i];
05944         }
05945   
05946         for (i = 0; i < nKernelSize; i++) 
05947                 pFilter[i] /= sum;
05948         
05949         // create temp image
05950         CFloatMatrix *pTempImage = new CFloatMatrix(pInputImage);
05951         
05952         const int width = pInputImage->columns;
05953         const int height = pInputImage->rows;
05954 
05955         const float *input = pInputImage->data;
05956         float *temp = pTempImage->data;
05957         float *output = pOutputImage->data;
05958         
05959         int x, y, d, offset;
05960         
05961         
05962         // x direction
05963         for (y = 0, offset = 0; y < height; y++)
05964         {
05965                 for (x = 0; x < k; x++, offset++)
05966                 {
05967                         float sum = 0.0f;
05968       
05969                         for (d = -k; d < -x; d++) 
05970                                 sum += input[y * width] * pFilter[k + d];
05971       
05972                         for (d = -x; d <= k; d++) 
05973                                 sum += input[offset + d] * pFilter[k + d];
05974       
05975                         temp[offset] = sum;
05976                 }
05977     
05978                 // core loop
05979                 for (x = 2 * k; x < width; x++, offset++)
05980                 {
05981                         float sum = 0.0f;
05982 
05983                         for (d = -k; d <= k; d++)
05984                                 sum += input[offset + d] * pFilter[d + k];
05985 
05986                         temp[offset] = sum;
05987                 }
05988     
05989                 for (x = width - k; x < width; x++, offset++)
05990                 {
05991                         float sum = 0.0f;
05992       
05993                         for (d = -k; d < width - x; d++) 
05994                                 sum += input[offset + d] * pFilter[k + d];
05995       
05996                         for (d = width - x; d <= k; d++) 
05997                                 sum += input[y * width + width - 1] * pFilter[k + d];
05998       
05999                         temp[offset] = sum;
06000                 }
06001         }
06002         
06003   
06004         // y direction
06005         for (y = 0; y < k; y++)
06006         {
06007                 for (x = 0; x < width; x++)
06008                 {
06009                         float sum = 0.0f;
06010       
06011                         for (d = -k; d < -y; d++) 
06012                                 sum += temp[x] * pFilter[k + d];
06013       
06014                         for (d = -y; d <= k; d++) 
06015                                 sum += temp[(y + d) * width + x] * pFilter[k + d];
06016         
06017                         output[y * width + x] = sum;
06018                 }
06019         }
06020     
06021         // core loop
06022         for (y = 2 * k, offset = k * width; y < height; y++)
06023         {
06024                 for (x = 0; x < width; x++, offset++)
06025                 {
06026                         float sum = 0.0f;
06027 
06028                         for (d = -k; d <= k; d++)
06029                                 sum += temp[offset + d * width] * pFilter[d + k];
06030 
06031                         output[offset] = sum;
06032                 }
06033     }
06034         
06035         for (y = height - k; y < height; y++)
06036         {
06037                 for (x = 0; x < width; x++)
06038                 {
06039                         float sum = 0.0f;
06040                 
06041                         for (d = -k; d < height - y; d++) 
06042                                 sum += temp[(y + d) * width + x] * pFilter[k + d];
06043       
06044                         for (d = height - y; d < k; d++) 
06045                                 sum += temp[(height - 1) * width + x] * pFilter[k + d];
06046       
06047                         output[y * width + x] = sum;
06048                 }
06049         }
06050         
06051 
06052         delete pTempImage;
06053         delete [] pFilter;
06054 
06055         return true;
06056 }
06057 
06058 bool ImageProcessor::HighPassX3(const CFloatMatrix *pInputImage, CFloatMatrix *pOutputImage)
06059 {
06060         if (pInputImage->columns != pOutputImage->columns || pInputImage->rows != pOutputImage->rows)
06061         {
06062                 printf("error: input and output image do not match for ImageProcessor::HighPassX3\n");
06063                 return false;
06064         }
06065         
06066         CFloatMatrix *pSaveOutputImage = 0;
06067         if (pInputImage->data == pOutputImage->data)
06068         {
06069                 pSaveOutputImage = pOutputImage;
06070                 pOutputImage = new CFloatMatrix(pInputImage);
06071         }
06072         
06073         const float *input = pInputImage->data;
06074         float *output = pOutputImage->data;
06075   
06076         const int width = pInputImage->columns;
06077         const int height = pInputImage->rows;
06078   
06079         for (int y = 0, offset = 0; y < height; y++, offset += width)
06080         {
06081                 output[offset] = input[offset + 1] - input[offset];
06082                 
06083                 const int max = offset + width - 1;
06084                 
06085     
06086                 for (int x = offset + 1; x < max; x++) 
06087                         output[x] = (input[x + 1] - input[x - 1]) * 0.5f;
06088                 
06089                 output[offset + width - 1] = input[offset + width - 1] - input[offset + width - 2];
06090         }
06091         
06092         if (pSaveOutputImage)
06093         {
06094                 CopyMatrix(pOutputImage, pSaveOutputImage);
06095                 delete pOutputImage;
06096         }
06097 
06098         return true;
06099 }
06100 
06101 bool ImageProcessor::HighPassY3(const CFloatMatrix *pInputImage, CFloatMatrix *pOutputImage)
06102 {
06103         if (pInputImage->columns != pOutputImage->columns || pInputImage->rows != pOutputImage->rows)
06104         {
06105                 printf("error: input and output image do not match for ImageProcessor::HighPassY3\n");
06106                 return false;
06107         }
06108         
06109         CFloatMatrix *pSaveOutputImage = 0;
06110         if (pInputImage->data == pOutputImage->data)
06111         {
06112                 pSaveOutputImage = pOutputImage;
06113                 pOutputImage = new CFloatMatrix(pInputImage);
06114         }
06115         
06116         const float *input = pInputImage->data;
06117         float *output = pOutputImage->data;
06118   
06119         const int width = pInputImage->columns;
06120         const int height = pInputImage->rows;
06121         
06122         int x;
06123         
06124         for (x = 0; x < width; x++)
06125                 output[x] = input[x + width] - input[x];
06126         
06127         for (int y = 2, offset = width; y < height; y++)
06128                 for (x = 0; x < width; x++, offset++)
06129                         output[offset] = (input[offset + width] - input[offset - width]) * 0.5f;
06130                         
06131         for (x = (height - 1) * width; x < width; x++)
06132                 output[x] = input[x] - input[x - width];
06133                 
06134         if (pSaveOutputImage)
06135         {
06136                 CopyMatrix(pOutputImage, pSaveOutputImage);
06137                 delete pOutputImage;
06138         }
06139 
06140         return true;
06141 }
06142 
06143 bool ImageProcessor::FlipY(const CByteImage *pInputImage, CByteImage *pOutputImage)
06144 {
06145         if (pInputImage->width != pOutputImage->width || pInputImage->height != pOutputImage->height ||
06146                 pInputImage->type != pOutputImage->type)
06147         {
06148                 printf("error: input and output image do not match for ImageProcessor::FlipY\n");
06149                 return false;
06150         }
06151         
06152         const int width = pInputImage->width;
06153         const int height = pInputImage->height;
06154         const int nPixels = width * height;
06155         
06156         unsigned char *input = pInputImage->pixels;
06157         
06158         if (pInputImage->pixels == pOutputImage->pixels)
06159         {
06160                 const int h = height / 2;
06161                 
06162                 if (pInputImage->type == CByteImage::eGrayScale)
06163                 {
06164                         unsigned char *temp = new unsigned char[width];
06165                         unsigned char *output = pOutputImage->pixels + nPixels - width;
06166                         
06167                         for (int y = 0; y < h; y++)
06168                         {
06169                                 memcpy(temp, output, width);
06170                                 memcpy(output, input, width);
06171                                 memcpy(input, temp, width);
06172                                         
06173                                 input += width;
06174                                 output -= width;
06175                         }
06176                         
06177                         delete [] temp;
06178                 }
06179                 else if (pInputImage->type == CByteImage::eRGB24)
06180                 {
06181                         const int nWidthBytes = 3 * width;
06182                         
06183                         unsigned char *temp = new unsigned char[nWidthBytes];
06184                         unsigned char *output = pOutputImage->pixels + 3 * nPixels - nWidthBytes;
06185                         
06186                         for (int y = 0; y < h; y++)
06187                         {
06188                                 memcpy(temp, output, nWidthBytes);
06189                                 memcpy(output, input, nWidthBytes);
06190                                 memcpy(input, temp, nWidthBytes);
06191                                         
06192                                 input += nWidthBytes;
06193                                 output -= nWidthBytes;
06194                         }
06195                         
06196                         delete [] temp;
06197                 }
06198         }
06199         else
06200         {
06201                 if (pInputImage->type == CByteImage::eGrayScale)
06202                 {
06203                         unsigned char *output = pOutputImage->pixels + nPixels - width;
06204                         
06205                         for (int y = 0; y < height; y++)
06206                         {
06207                                 memcpy(output, input, width);
06208                                         
06209                                 input += width;
06210                                 output -= width;
06211                         }
06212                 }
06213                 else if (pInputImage->type == CByteImage::eRGB24)
06214                 {
06215                         const int nWidthBytes = 3 * width;
06216                         unsigned char *output = pOutputImage->pixels + 3 * nPixels - nWidthBytes;
06217                         
06218                         for (int y = 0; y < height; y++)
06219                         {
06220                                 memcpy(output, input, nWidthBytes);
06221                                         
06222                                 input += nWidthBytes;
06223                                 output -= nWidthBytes;
06224                         }
06225                 }
06226         }
06227 
06228         return true;
06229 }
06230 
06231 bool ImageProcessor::CalculateIntegralImage(const CByteImage *pInputImage, CIntImage *pIntegralImage)
06232 {
06233         if (pInputImage->width != pIntegralImage->width || pInputImage->height != pIntegralImage->height || pInputImage->type != CByteImage::eGrayScale)
06234         {
06235                 printf("error: input and output image do not match for ImageProcessor::CalculateIntegralImage\n");
06236                 return false;
06237         }
06238         
06239         const int width = pInputImage->width;
06240         const int height = pInputImage->height;
06241         
06242         const unsigned char *input = pInputImage->pixels;
06243         int *output = pIntegralImage->pixels;
06244         
06245         // top left pixel
06246         *output = *input++;
06247         output++;
06248         
06249         // top row
06250         for (int x = 1; x < width; x++)
06251         {
06252                 *output = *input++ + *(output - 1);
06253                 output++;
06254         }
06255         
06256         // the other rows
06257         for (int y = 1; y < height; y++)
06258         {
06259                 // first entry in a row
06260                 *output = *input++ + *(output - width);
06261                 output++;
06262                 
06263                 // rest of the row
06264                 for (int x = 1; x < width; x++)
06265                 {
06266                         *output = *input++ + *(output - 1) + *(output - width) - *(output - width - 1);
06267                         output++;
06268                 }
06269         }
06270 
06271         return true;
06272 }
06273 
06274 bool ImageProcessor::CalculateSummedAreaTable(const CByteImage *pInputImage, CIntImage *pSummedAreaTable)
06275 {
06276         if (pInputImage->width != pSummedAreaTable->width || pInputImage->height != pSummedAreaTable->height || pInputImage->type != CByteImage::eGrayScale)
06277         {
06278                 printf("error: input and output image do not match for ImageProcessor::CalculateSummedAreaTable\n");
06279                 return false;
06280         }
06281         
06282         return CalculateIntegralImage(pInputImage, pSummedAreaTable);
06283 }
06284 
06285 // counts every pixel != 0 as 1
06286 bool ImageProcessor::CalculateBinarizedSummedAreaTable(const CByteImage *pInputImage, CIntImage *pSummedAreaTable)
06287 {
06288         if (pInputImage->width != pSummedAreaTable->width || pInputImage->height != pSummedAreaTable->height || pInputImage->type != CByteImage::eGrayScale)
06289         {
06290                 printf("error: input and output image do not match for ImageProcessor::CalculateBinarizedSummedAreaTable\n");
06291                 return false;
06292         }
06293         
06294         const int width = pInputImage->width;
06295         const int height = pInputImage->height;
06296         
06297         unsigned char *input = pInputImage->pixels;
06298         int *output = pSummedAreaTable->pixels;
06299         
06300         // top left pixel
06301         int c = *input++;
06302         c = (c != 0 ? 1 : 0);
06303         
06304         *output++ = c;
06305         
06306         // top row
06307         for (int x = 1; x < width; x++)
06308         {
06309                 c = *input++;
06310                 c = (c != 0 ? 1 : 0);
06311                 
06312                 *output = c + *(output-1);
06313                 output++;
06314         }
06315         
06316         // the other rows
06317         for (int y = 1; y < height; y++)
06318         {
06319                 // first entry in a row
06320                 c = *input++;
06321                 c = (c != 0 ? 1 : 0);
06322                 
06323                 *output = c + *(output - width);
06324                 output++;
06325                 
06326                 // rest of the row
06327                 for (int x = 1; x < width; x++)
06328                 {
06329                         c = *input++;
06330                         c = (c != 0 ? 1 : 0);
06331                         
06332                         *output = c + *(output-1) + *(output - width) - *(output - width - 1);
06333                         output++;
06334                 }
06335         }
06336 
06337         return true;
06338 }
06339 
06340 bool ImageProcessor::CalculateReverseSummedAreaTable(const CIntImage *pSummedAreaTable, CByteImage *pOutputImage)
06341 {
06342         if (pOutputImage->width != pSummedAreaTable->width || pOutputImage->height != pSummedAreaTable->height || pOutputImage->type != CByteImage::eGrayScale)
06343         {
06344                 printf("error: input and output image do not match for ImageProcessor::CalculateReverseSummedAreaTable\n");
06345                 return false;
06346         }
06347         
06348         const int width = pSummedAreaTable->width;
06349         const int height = pSummedAreaTable->height;
06350         
06351         int *input = pSummedAreaTable->pixels;
06352         unsigned char *output = pOutputImage->pixels;
06353         
06354         // top left pixel
06355         int c = *input++;
06356         *output++ = c;
06357         
06358         // top row
06359         for (int x = 1; x < width; x++)
06360         {
06361                 c = *input++;
06362                 *output++ = c - *(input - 2);
06363         }
06364         
06365         // the other rows
06366         for (int y = 1; y < height; y++)
06367         {
06368                 // first entry in a row
06369                 c = *input++;
06370                 *output++ = c - *(input - width - 1);
06371                 
06372                 // rest of the row
06373                 for (int x = 1; x < width; x++)
06374                 {
06375                         c = *input++;
06376                         *output++ = c - *(input - 2) - *(input - width - 1) + *(input - width - 2);
06377                 }
06378         }
06379 
06380         return true;
06381 }
06382 
06383 int ImageProcessor::GetAreaSum(const CIntImage *pIntegralImage, int min_x, int min_y, int max_x, int max_y)
06384 {
06385         const int width = pIntegralImage->width;
06386         const int height = pIntegralImage->height;
06387 
06388         // to include the min_x column and the min_y row
06389         min_x--;
06390         min_y--;
06391         
06392         if (min_x >= width) min_x = width - 1;
06393         if (max_x < 0) max_x = 0;
06394         if (max_x >= width) max_x = width - 1;
06395         if (min_y >= height) min_y = height - 1;
06396         if (max_y < 0) max_y = 0;
06397         if (max_y >= height) max_y = height - 1;
06398         
06399         const int *pixels = pIntegralImage->pixels;
06400         const int c1 = min_x < 0 || min_y < 0 ? 0 : pixels[min_y * width + min_x];
06401         const int c2 = min_y < 0 ? 0 : pixels[min_y * width + max_x];
06402         const int c3 = min_x < 0 ? 0 : pixels[max_y * width + min_x];
06403         const int c4 = pixels[max_y * width + max_x];
06404          
06405         return c4 - c3 - c2 + c1;
06406 }
06407 
06408 inline int ImageProcessor::GetAreaSumNoChecks(const CIntImage *pIntegralImage, int min_x, int min_y, int max_x, int max_y)
06409 {
06410         // to include the min_x column and the min_y row
06411         min_x--;
06412         min_y--;
06413         
06414         const int width = pIntegralImage->width;
06415         const int *pixels = pIntegralImage->pixels;
06416         
06417         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];
06418 }
06419 
06420 int ImageProcessor::GetAreaSum(const CIntImage *pIntegralImage, const MyRegion *region)
06421 {
06422         return GetAreaSum(pIntegralImage, region->min_x, region->min_y, region->max_x, region->max_y);
06423 }
06424 
06425 
06426 static void track(unsigned char *magnitudes, int *stack, int offset, int width)
06427 {
06428         int sp = 0;
06429         
06430         stack[sp++] = offset;
06431         
06432         while (sp--)
06433         {
06434                 const int offset = stack[sp];
06435 
06436                 if (magnitudes[offset - width - 1] == 1)
06437                 {
06438                         stack[sp++] = offset - width - 1;
06439                         magnitudes[offset - width - 1] = 255;
06440                 }
06441 
06442                 if (magnitudes[offset + width + 1] == 1)
06443                 {
06444                         stack[sp++] = offset + width + 1;
06445                         magnitudes[offset + width + 1] = 255;
06446                 }
06447 
06448                 if (magnitudes[offset - width + 1] == 1)
06449                 {
06450                         stack[sp++] = offset - width + 1;
06451                         magnitudes[offset - width + 1] = 255;
06452                 }
06453 
06454                 if (magnitudes[offset + width - 1] == 1)
06455                 {
06456                         stack[sp++] = offset + width - 1;
06457                         magnitudes[offset + width - 1] = 255;
06458                 }
06459 
06460                 if (magnitudes[offset - width] == 1)
06461                 {
06462                         stack[sp++] = offset - width;
06463                         magnitudes[offset - width] = 255;
06464                 }
06465 
06466                 if (magnitudes[offset + width] == 1)
06467                 {
06468                         stack[sp++] = offset + width;
06469                         magnitudes[offset + width] = 255;
06470                 }
06471 
06472                 if (magnitudes[offset - 1] == 1)
06473                 {
06474                         stack[sp++] = offset - 1;
06475                         magnitudes[offset - 1] = 255;
06476                 }
06477                                 
06478                 if (magnitudes[offset + 1] == 1)
06479                 {
06480                         stack[sp++] = offset + 1;
06481                         magnitudes[offset + 1] = 255;
06482                 }
06483         }
06484 }
06485 
06486 bool ImageProcessor::Canny(const CByteImage *pInputImage, CByteImage *pOutputImage, int nLowThreshold, int nHighThreshold)
06487 {
06488         OPTIMIZED_FUNCTION_HEADER_4(Canny, pInputImage, pOutputImage, nLowThreshold, nHighThreshold)
06489         
06490         if (pInputImage->width != pOutputImage->width || pInputImage->height != pOutputImage->height ||
06491                 pInputImage->type != pOutputImage->type || pInputImage->type != CByteImage::eGrayScale)
06492         {
06493                 printf("error: input and output image do not match for ImageProcessor::Canny\n");
06494                 return false;
06495         }
06496 
06497         if (nLowThreshold == 0) nLowThreshold = 1;
06498         if (nHighThreshold == 0) nHighThreshold = 1;
06499 
06500         const int width = pInputImage->width;
06501         const int height = pInputImage->height;
06502         const int nPixels = width * height;
06503 
06504         CShortImage gradientsX(width, height), gradientsY(width, height);
06505         SobelX(pInputImage, &gradientsX, false);
06506         SobelY(pInputImage, &gradientsY, false);
06507 
06508         Zero(pOutputImage);
06509         
06510         unsigned char *output = pOutputImage->pixels;
06511         short *magnitudes = gradientsX.pixels; // alias for the gradientX image
06512         
06513         int i;
06514         
06515         // calculate gradients and sectors
06516         for (i = 0; i < nPixels; i++)
06517         {
06518                 const int gx = gradientsX.pixels[i];
06519                 const int gy = gradientsY.pixels[i];
06520                 const int agx = abs(gx);
06521                 const int agy = abs(gy);
06522                 const int g = agx + agy;
06523                 //const int g = short(sqrtf(float(gx * gx + gy * gy)));
06524                 
06525                 magnitudes[i] = g;
06526                 
06527                 if (g >= nLowThreshold)
06528                 {
06529                         if (agx > (agy << 1))
06530                         {
06531                                 output[i] = 10; 
06532                         }
06533                         else if ((agx << 1) > agy)
06534                         {
06535                                 output[i] = gx * gy >= 0 ? 12 : 13;
06536                         }
06537                         else
06538                         {
06539                                 output[i] = 11;
06540                         }       
06541                 }
06542         }
06543         
06544         // apply non maximal supression 
06545         for (i = 0; i < nPixels; i++)
06546         {
06547                 const int g = (int) magnitudes[i];
06548 
06549                 if (g >= nLowThreshold)
06550                 {
06551                         switch (output[i])
06552                         {
06553                                 case 10:
06554                                         if (magnitudes[i + 1] <= g && magnitudes[i - 1] < g)
06555                                                 output[i] = g >= nHighThreshold ? 254 : 1;
06556                                 break;
06557 
06558                                 case 11:
06559                                         if (magnitudes[i + width] <= g && magnitudes[i - width] < g)
06560                                                 output[i] = g >= nHighThreshold ? 254 : 1;
06561                                 break;
06562 
06563                                 case 12:
06564                                         if (magnitudes[i + width + 1] <= g && magnitudes[i - width - 1] < g)
06565                                                 output[i] = g >= nHighThreshold ? 254 : 1;
06566                                 break;
06567                         
06568                                 case 13:
06569                                         if (magnitudes[i + width - 1] <= g && magnitudes[i - width + 1] < g)
06570                                                 output[i] = g >= nHighThreshold ? 254 : 1;
06571                                 break;
06572                         }
06573                 }
06574         }
06575 
06576         // track
06577         int *stack = new int[nPixels];
06578 
06579         for (i = 0; i < nPixels; i++)
06580                 if (output[i] == 254)
06581                 {
06582                         track(output, stack, i, width);
06583                         output[i] = 255;
06584                 }
06585         
06586         for (i = 0; i < nPixels; i++)
06587         {
06588                 if (output[i] != 255)
06589                         output[i] = 0;
06590         }
06591         
06592         delete [] stack;
06593         
06594         OPTIMIZED_FUNCTION_FOOTER
06595 
06596         return true;
06597 }
06598 
06599 
06600 static inline void CalculateSubpixel(const unsigned char *input, int width, int sector, Vec2d &point, Vec2d &direction)
06601 {
06602         int a, b, c, n;
06603         
06604         if (sector == 0)
06605         {
06606                 a = *input - *(input - 2);
06607                 b = *(input + 1) - *(input - 1);
06608                 c = *(input + 2) - *input;
06609                 n = a - 2 * b + c;
06610                 
06611                 if (n != 0)
06612                 {
06613                         const float x = 0.5f * (a - c) / n;
06614 
06615                         if (fabsf(x) < 1.0f)
06616                                 point.x += x;
06617                 }
06618         }
06619         else if (sector == 1)
06620         {
06621                 a = *input - *(input - (width << 1));
06622                 b = *(input + width) - *(input - width);
06623                 c = *(input + (width << 1)) - *input;
06624                 n = a - 2 * b + c;
06625                 
06626                 if (n != 0)
06627                 {
06628                         const float y = 0.5f * (a - c) / n;
06629 
06630                         if (fabsf(y) < 1.0f)
06631                                 point.y += y;
06632                 }
06633         }
06634         else if (sector == 2)
06635         {
06636                 a = *input - *(input - (width << 1) - 2);
06637                 b = *(input + width + 1) - *(input - width - 1);
06638                 c = *(input + (width << 1) + 2) - *input;
06639                 n = a - 2 * b + c;
06640                 
06641                 if (n != 0)
06642                 {
06643                         const float xy = 0.35355339059327378637f * (a - c) / n;
06644 
06645                         if (fabsf(xy) < 1.0f)
06646                         {
06647                                 point.y += xy;
06648                                 point.x += xy;
06649                         }
06650                 }
06651         }
06652         else if (sector == 3)
06653         {
06654                 a = *input - *(input - (width << 1) + 2);
06655                 b = *(input + width - 1) - *(input - width + 1);
06656                 c = *(input + (width << 1) - 2) - *input;
06657                 n = a - 2 * b + c;
06658                 
06659                 if (n != 0)
06660                 {
06661                         const float xy = 0.35355339059327378637f * (a - c) / n;
06662 
06663                         if (fabsf(xy) < 1.0f)
06664                         {
06665                                 point.y += xy;
06666                                 point.x -= xy;
06667                         }
06668                 }
06669         }
06670 
06671         Math2d::SetVec(direction,
06672                 (float) ((input[1] << 1) + input[1 - width] + input[1 + width] - (input[-1] << 1) - input[-1 - width] - input[-1 + width]),
06673                 (float) ((input[width] << 1) + input[width - 1] + input[width + 1] - (input[-width] << 1) - input[-width - 1] - input[-width + 1]));
06674         Math2d::NormalizeVec(direction);
06675 }
06676 
06677 bool ImageProcessor::Canny(const CByteImage *pInputImage, CVec2dArray &resultPoints, CVec2dArray &resultDirections, int nLowThreshold, int nHighThreshold)
06678 {
06679         OPTIMIZED_FUNCTION_HEADER_5(CannyList, pInputImage, resultPoints, resultDirections, nLowThreshold, nHighThreshold)
06680         
06681         if (pInputImage->type != CByteImage::eGrayScale)
06682         {
06683                 printf("error: input image must be of type eGrayScale for ImageProcessor::Canny (list)\n");
06684                 return false;
06685         }
06686 
06687         if (nLowThreshold == 0) nLowThreshold = 1;
06688         if (nHighThreshold == 0) nHighThreshold = 1;
06689 
06690         const int width = pInputImage->width;
06691         const int height = pInputImage->height;
06692         const int nPixels = width * height;
06693 
06694         CShortImage gradientsX(width, height), gradientsY(width, height);
06695         SobelX(pInputImage, &gradientsX, false);
06696         SobelY(pInputImage, &gradientsY, false);
06697 
06698         CByteImage tempImage(width, height, CByteImage::eGrayScale);
06699         CByteImage sectorImage(width, height, CByteImage::eGrayScale);
06700         Zero(&tempImage);
06701         Zero(&sectorImage);
06702         
06703         unsigned char *temp = tempImage.pixels;
06704         unsigned char *sectors = sectorImage.pixels;
06705         short *magnitudes = gradientsX.pixels; // alias for the gradientX image
06706         
06707         int i;
06708 
06709         // calculate gradients and sectors
06710         for (i = 0; i < nPixels; i++)
06711         {
06712                 const int gx = gradientsX.pixels[i];
06713                 const int gy = gradientsY.pixels[i];
06714                 const int agx = abs(gx);
06715                 const int agy = abs(gy);
06716                 const int g = agx + agy;
06717                 //const int g = short(sqrtf(float(gx * gx + gy * gy)));
06718 
06719                 magnitudes[i] = g;
06720                 
06721                 if (g >= nLowThreshold)
06722                 {
06723                         if (agx > (agy << 1))
06724                         {
06725                                 sectors[i] = 0; 
06726                         }
06727                         else if ((agx << 1) > agy)
06728                         {
06729                                 sectors[i] = gx * gy >= 0 ? 2 : 3;
06730                         }
06731                         else
06732                         {
06733                                 sectors[i] = 1;
06734                         }       
06735                 }
06736         }
06737         
06738         // apply non maximal supression 
06739         for (i = 0; i < nPixels; i++)
06740         {
06741                 const int g = (int) magnitudes[i];
06742 
06743                 if (g >= nLowThreshold)
06744                 {
06745                         switch (sectors[i])
06746                         {
06747                                 case 0:
06748                                         if (magnitudes[i + 1] <= g && magnitudes[i - 1] < g)
06749                                                 temp[i] = g >= nHighThreshold ? 254 : 1;
06750                                 break;
06751 
06752                                 case 1:
06753                                         if (magnitudes[i + width] <= g && magnitudes[i - width] < g)
06754                                                 temp[i] = g >= nHighThreshold ? 254 : 1;
06755                                 break;
06756 
06757                                 case 2:
06758                                         if (magnitudes[i + width + 1] <= g && magnitudes[i - width - 1] < g)
06759                                                 temp[i] = g >= nHighThreshold ? 254 : 1;
06760                                 break;
06761                         
06762                                 case 3:
06763                                         if (magnitudes[i + width - 1] <= g && magnitudes[i - width + 1] < g)
06764                                                 temp[i] = g >= nHighThreshold ? 254 : 1;
06765                                 break;
06766                         }
06767                 }
06768         }
06769 
06770         // track
06771         int *stack = new int[nPixels];
06772 
06773         for (i = 0; i < nPixels; i++)
06774                 if (temp[i] == 254)
06775                 {
06776                         track(temp, stack, i, width);
06777                         temp[i] = 255;
06778                 }
06779         
06780         resultPoints.Clear();
06781         resultDirections.Clear();
06782         
06783         int offset;
06784         for (i = height - 4, offset = 2 * width + 2; i; i--, offset += 4)
06785                 for (int j = width - 4; j; j--, offset++)
06786                         if (temp[offset] == 255)
06787                         {
06788                                 Vec2d point;
06789                                 Math2d::SetVec(point, (float) (offset % width), (float) (offset / width));
06790 
06791                                 Vec2d direction;
06792                                 CalculateSubpixel(pInputImage->pixels + offset, width, sectors[offset], point, direction);
06793 
06794                                 resultPoints.AddElement(point);
06795                                 resultDirections.AddElement(direction);
06796                         }
06797         
06798         delete [] stack;
06799         
06800         OPTIMIZED_FUNCTION_FOOTER
06801 
06802         return true;
06803 }
06804 
06805 
06806 
06807 #define HARRIS_WINDOW_SIZE 3 // don't change this define
06808 
06809 bool ImageProcessor::CalculateHarrisMap(const CByteImage *pInputImage, CIntImage *pOutputImage)
06810 {
06811         if (pInputImage->type != CByteImage::eGrayScale || pInputImage->width != pOutputImage->width || pInputImage->height != pOutputImage->height)
06812         {
06813                 printf("error: input image and output matrix do not match for ImageProcessor::CalculateHarrisMap\n");
06814                 return false;
06815         }
06816         
06817         const int width = pInputImage->width;
06818         const int height = pInputImage->height;
06819         const int nPixels = width * height;
06820         
06821         const unsigned char *input = pInputImage->pixels;
06822 
06823         int i, j, offset;
06824 
06825         int *cov = new int[3 * nPixels];
06826         
06827         // calculate gradients
06828         const int stop = nPixels - width - 1;
06829         for (offset = width + 1; offset < stop; offset++)
06830         {
06831                 const int p = int(input[offset + 1]) - int(input[offset - 1]);
06832                 const int q = int(input[offset + width]) - int(input[offset - width]);
06833                 const int offset_ = 3 * offset;
06834 
06835                 cov[offset_    ] = p * p;
06836                 cov[offset_ + 1] = q * q;
06837                 cov[offset_ + 2] = p * q;
06838         }
06839 
06840         // zero R image
06841         Zero(pOutputImage);
06842 
06843         // calculate harris response function
06844         const int diff = HARRIS_WINDOW_SIZE + 1;
06845         const int width3 = 3 * width;
06846         int *R = pOutputImage->pixels + (HARRIS_WINDOW_SIZE / 2) * (width + 1);
06847 
06848         // do not use one-pixel-thick border of cov (gradients are not valid there)
06849         for (i = diff, offset = width + 1; i < height; i++, offset += diff)
06850         {
06851                 for (j = diff; j < width; j++, offset++)
06852                 {
06853                         int ppsum = 0;
06854                         int qqsum = 0;
06855                         int pqsum = 0;
06856 
06857                         for (int k = 0, offset2 = 3 * offset; k < HARRIS_WINDOW_SIZE; k++, offset2 += width3)
06858                         {
06859                                 ppsum += cov[offset2];
06860                                 qqsum += cov[offset2 + 1];
06861                                 pqsum += cov[offset2 + 2];
06862                                 ppsum += cov[offset2 + 3];
06863                                 qqsum += cov[offset2 + 4];
06864                                 pqsum += cov[offset2 + 5];
06865                                 ppsum += cov[offset2 + 6];
06866                                 qqsum += cov[offset2 + 7];
06867                                 pqsum += cov[offset2 + 8];
06868                         }
06869                         
06870                         // NOTE:
06871                         // while abs()  should not be necessary for most targets (the squared result fits into 32bit),
06872                         // some targets (known:  ti 64x) produce faulty code here.
06873                         pqsum = abs(pqsum);
06874                         
06875                         ppsum >>= 4;
06876                         qqsum >>= 4;
06877                         pqsum >>= 4;
06878                         
06879                         //R[offset] = (ppsum * qqsum - pqsum * pqsum) - 0.04f * ((ppsum + qqsum) * (ppsum + qqsum));
06880                         // approximation: 0.04f = 1 / 25. instead: 1 / 16
06881                         R[offset] = (ppsum * qqsum - pqsum * pqsum) - (((ppsum + qqsum) >> 2) * ((ppsum + qqsum) >> 2));
06882                 }
06883         }
06884 
06885         delete [] cov;
06886 
06887         return true;
06888 }
06889 
06890 
06891 static void QuicksortInverse(int *pOffsets, const int *pValues, int nLow, int nHigh)
06892 {
06893         int i = nLow;
06894         int j = nHigh;
06895         
06896         const int x = pValues[pOffsets[(nLow + nHigh) >> 1]];
06897 
06898         while (i <= j)
06899         {    
06900                 while (pValues[pOffsets[i]] > x) i++; 
06901                 while (pValues[pOffsets[j]] < x) j--;
06902         
06903                 if (i <= j)
06904                 {
06905                         const int temp = pOffsets[i];
06906                         pOffsets[i] = pOffsets[j];
06907                         pOffsets[j] = temp;
06908                 
06909                         i++; 
06910                         j--;
06911                 }
06912         }
06913 
06914         if (nLow < j) QuicksortInverse(pOffsets, pValues, nLow, j);
06915         if (i < nHigh) QuicksortInverse(pOffsets, pValues, i, nHigh);
06916 }
06917 
06918 int ImageProcessor::CalculateHarrisInterestPoints(const CByteImage *pInputImage, Vec2d *pInterestPoints, int nMaxPoints, float fQualityLevel, float fMinDistance)
06919 {
06920         OPTIMIZED_FUNCTION_HEADER_5_RET(CalculateHarrisInterestPoints, pInputImage, pInterestPoints, nMaxPoints, fQualityLevel, fMinDistance)
06921                 
06922         if (pInputImage->type != CByteImage::eGrayScale)
06923         {
06924                 printf("error: input image should be grayscale ImageProcessor::CalculateHarrisInterestPoints\n");
06925                 return -1;
06926         }
06927                 
06928         const int width = pInputImage->width;
06929         const int height = pInputImage->height;
06930         const int nPixels = width * height;
06931         
06932         // calculate harris map
06933         CIntImage R(pInputImage->width, pInputImage->height);
06934         CalculateHarrisMap(pInputImage, &R);
06935         
06936         int *data = R.pixels;
06937         int i;
06938 
06939         // determine maximum value
06940         int max = 0;
06941         for (i = 0; i < nPixels; ++i)
06942         {
06943                 if (data[i] > max)
06944                         max = data[i];
06945         }
06946 
06947         int *pCandidateOffsets = new int[nPixels];
06948         int nCandidates = 0;
06949         
06950         // only accept good pixels
06951         max = int(max * fQualityLevel + 0.5f);
06952         for (i = 0; i < nPixels; i++)
06953         {
06954                 if (data[i] >= max)
06955                         pCandidateOffsets[nCandidates++] = i;
06956         }
06957 
06958         // sort by quality
06959         QuicksortInverse(pCandidateOffsets, data, 0, nCandidates - 1);
06960 
06961         // enforce distance constraint
06962         const int nMinDistance = int(fMinDistance + 0.5f);
06963         CByteImage image(width, height, CByteImage::eGrayScale);
06964         Zero(&image);
06965         int nInterestPoints = 0;
06966         for (i = 0; i < nCandidates && nInterestPoints < nMaxPoints; i++)
06967         {
06968                 const int offset = pCandidateOffsets[i];
06969                 
06970                 const int x = offset % width;
06971                 const int y = offset / width;
06972 
06973                 bool bTake = true;
06974 
06975                 const int minx = x - nMinDistance < 0 ? 0 : x - nMinDistance;
06976                 const int miny = y - nMinDistance < 0 ? 0 : y - nMinDistance;
06977                 const int maxx = x + nMinDistance >= width ? width - 1 : x + nMinDistance;
06978                 const int maxy = y + nMinDistance >= height ? height - 1 : y + nMinDistance;
06979                 const int diff = width - (maxx - minx + 1);
06980 
06981                 for (int l = miny, offset2 = miny * width + minx; l <= maxy; l++, offset2 += diff)
06982                         for (int k = minx; k <= maxx; k++, offset2++)
06983                                 if (image.pixels[l * width + k])
06984                                 {
06985                                         bTake = false;
06986                                         break;
06987                                 }
06988 
06989                 if (bTake)
06990                 {
06991                         // store  point
06992                         pInterestPoints[nInterestPoints].x = float(x);
06993                         pInterestPoints[nInterestPoints].y = float(y);
06994                         nInterestPoints++;
06995 
06996                         // mark location in grid for distance constraint check
06997                         image.pixels[offset] = 1;
06998                 }
06999         }
07000 
07001         delete [] pCandidateOffsets;
07002         
07003         return nInterestPoints;
07004 }
07005 
07006 
07007 bool ImageProcessor::And(const CByteImage *pInputImage1, const CByteImage *pInputImage2, CByteImage *pOutputImage)
07008 {
07009         OPTIMIZED_FUNCTION_HEADER_3(And, pInputImage1, pInputImage2, pOutputImage)
07010         
07011         if (!pInputImage1->IsCompatible(pInputImage2) || !pInputImage1->IsCompatible(pOutputImage))
07012         {
07013                 printf("error: input images and output image do not match for ImageProcessor::And\n");
07014                 return false;
07015         }
07016         
07017         const int nBytes = pInputImage1->width * pInputImage1->height * pInputImage1->bytesPerPixel;
07018         
07019         const unsigned char *input1 = pInputImage1->pixels;
07020         const unsigned char *input2 = pInputImage2->pixels;
07021         unsigned char *output = pOutputImage->pixels;
07022         for (int i = 0; i < nBytes; i++)
07023                 output[i] = input1[i] & input2[i];
07024         
07025         OPTIMIZED_FUNCTION_FOOTER
07026 
07027         return true;
07028 }
07029 
07030 bool ImageProcessor::Xor(const CByteImage *pInputImage1, const CByteImage *pInputImage2, CByteImage *pOutputImage)
07031 {
07032         OPTIMIZED_FUNCTION_HEADER_3(Xor, pInputImage1, pInputImage2, pOutputImage)
07033         
07034         if (!pInputImage1->IsCompatible(pInputImage2) || !pInputImage1->IsCompatible(pOutputImage))
07035         {
07036                 printf("error: input images and output image do not match for ImageProcessor::Xor\n");
07037                 return false;
07038         }
07039         
07040         const int nBytes = pInputImage1->width * pInputImage1->height * pInputImage1->bytesPerPixel;
07041         
07042         const unsigned char *input1 = pInputImage1->pixels;
07043         const unsigned char *input2 = pInputImage2->pixels;
07044         unsigned char *output = pOutputImage->pixels;
07045         for (int i = 0; i < nBytes; i++)
07046                 output[i] = input1[i] ^ input2[i];
07047         
07048         OPTIMIZED_FUNCTION_FOOTER
07049 
07050         return true;
07051 }
07052 
07053 bool ImageProcessor::Or(const CByteImage *pInputImage1, const CByteImage *pInputImage2, CByteImage *pOutputImage)
07054 {
07055         OPTIMIZED_FUNCTION_HEADER_3(Or, pInputImage1, pInputImage2, pOutputImage)
07056         
07057         if (!pInputImage1->IsCompatible(pInputImage2) || !pInputImage1->IsCompatible(pOutputImage))
07058         {
07059                 printf("error: input images and output image do not match for ImageProcessor::Or\n");
07060                 return false;
07061         }
07062         
07063         const int nBytes = pInputImage1->width * pInputImage1->height * pInputImage1->bytesPerPixel;
07064         
07065         const unsigned char *input1 = pInputImage1->pixels;
07066         const unsigned char *input2 = pInputImage2->pixels;
07067         unsigned char *output = pOutputImage->pixels;
07068         for (int i = 0; i < nBytes; i++)
07069                 output[i] = input1[i] | input2[i];
07070         
07071         OPTIMIZED_FUNCTION_FOOTER
07072 
07073         return true;
07074 }
07075 
07076 
07077 bool ImageProcessor::Add(const CByteImage *pInputImage1, const CByteImage *pInputImage2, CByteImage *pOutputImage)
07078 {
07079         OPTIMIZED_FUNCTION_HEADER_3(Add, pInputImage1, pInputImage2, pOutputImage)
07080         
07081         if (!pInputImage1->IsCompatible(pInputImage2) || !pInputImage1->IsCompatible(pOutputImage))
07082         {
07083                 printf("error: input images and output image do not match for ImageProcessor::Add\n");
07084                 return false;
07085         }
07086         
07087         const int nBytes = pInputImage1->width * pInputImage1->height * pInputImage1->bytesPerPixel;
07088         
07089         const unsigned char *input1 = pInputImage1->pixels;
07090         const unsigned char *input2 = pInputImage2->pixels;
07091         unsigned char *output = pOutputImage->pixels;
07092 
07093         for (int i = 0; i < nBytes; i++)
07094                 output[i] = input1[i] + input2[i];
07095         
07096         OPTIMIZED_FUNCTION_FOOTER
07097 
07098         return true;
07099 }
07100 
07101 bool ImageProcessor::AddWithSaturation(const CByteImage *pInputImage1, const CByteImage *pInputImage2, CByteImage *pOutputImage)
07102 {
07103         OPTIMIZED_FUNCTION_HEADER_3(AddWithSaturation, pInputImage1, pInputImage2, pOutputImage)
07104         
07105         if (!pInputImage1->IsCompatible(pInputImage2) || !pInputImage1->IsCompatible(pOutputImage))
07106         {
07107                 printf("error: input images and output image do not match for ImageProcessor::AddAndSaturate\n");
07108                 return false;
07109         }
07110                 
07111         const int nBytes = pInputImage1->width * pInputImage1->height * pInputImage1->bytesPerPixel;
07112         
07113         const unsigned char *input1 = pInputImage1->pixels;
07114         const unsigned char *input2 = pInputImage2->pixels;
07115         unsigned char *output = pOutputImage->pixels;
07116 
07117         for (int i = 0; i < nBytes; i++)
07118                 output[i] = MY_MIN((unsigned int) input1[i] + (unsigned int) input2[i], 255);
07119         
07120         OPTIMIZED_FUNCTION_FOOTER
07121 
07122         return true;
07123 }
07124 
07125 bool ImageProcessor::Subtract(const CByteImage *pInputImage1, const CByteImage *pInputImage2, CByteImage *pOutputImage)
07126 {
07127         OPTIMIZED_FUNCTION_HEADER_3(Subtract, pInputImage1, pInputImage2, pOutputImage)
07128         
07129         if (!pInputImage1->IsCompatible(pInputImage2) || !pInputImage1->IsCompatible(pOutputImage))
07130         {
07131                 printf("error: input images and output image do not match for ImageProcessor::Subtract\n");
07132                 return false;
07133         }
07134         
07135         const int nBytes = pInputImage1->width * pInputImage1->height * pInputImage1->bytesPerPixel;
07136         
07137         const unsigned char *input1 = pInputImage1->pixels;
07138         const unsigned char *input2 = pInputImage2->pixels;
07139         unsigned char *output = pOutputImage->pixels;
07140         
07141         for (int i = 0; i < nBytes; i++)
07142                 output[i] = input1[i] - input2[i];
07143         
07144         OPTIMIZED_FUNCTION_FOOTER
07145 
07146         return true;
07147 }
07148 
07149 bool ImageProcessor::SubtractWithSaturation(const CByteImage *pInputImage1, const CByteImage *pInputImage2, CByteImage *pOutputImage)
07150 {
07151         OPTIMIZED_FUNCTION_HEADER_3(SubtractWithSaturation, pInputImage1, pInputImage2, pOutputImage)
07152         
07153         if (!pInputImage1->IsCompatible(pInputImage2) || !pInputImage1->IsCompatible(pOutputImage))
07154         {
07155                 printf("error: input images and output image do not match for ImageProcessor::SubtractAndSaturate\n");
07156                 return false;
07157         }
07158         
07159         const int nBytes = pInputImage1->width * pInputImage1->height * pInputImage1->bytesPerPixel;
07160         
07161         const unsigned char *input1 = pInputImage1->pixels;
07162         const unsigned char *input2 = pInputImage2->pixels;
07163         unsigned char *output = pOutputImage->pixels;
07164         
07165         for (int i = 0; i < nBytes; i++)
07166                 output[i] = MY_MAX((int) input1[i] - (int) input2[i], 0);
07167         
07168         OPTIMIZED_FUNCTION_FOOTER
07169 
07170         return true;
07171 }
07172 
07173 bool ImageProcessor::AbsoluteDifference(const CByteImage *pInputImage1, const CByteImage *pInputImage2, CByteImage *pOutputImage)
07174 {
07175         OPTIMIZED_FUNCTION_HEADER_3(AbsoluteDifference, pInputImage1, pInputImage2, pOutputImage)
07176         
07177         if (!pInputImage1->IsCompatible(pInputImage2) || !pInputImage1->IsCompatible(pOutputImage))
07178         {
07179                 printf("error: input images and output image do not match for ImageProcessor::AbsoluteDifference\n");
07180                 return false;
07181         }
07182                 
07183         const int nBytes = pInputImage1->width * pInputImage1->height * pInputImage1->bytesPerPixel;
07184         
07185         const unsigned char *input1 = pInputImage1->pixels;
07186         const unsigned char *input2 = pInputImage2->pixels;
07187         unsigned char *output = pOutputImage->pixels;
07188         
07189         for (int i = 0; i < nBytes; i++)
07190                 output[i] = abs((int) input1[i] - (int) input2[i]);
07191         
07192         OPTIMIZED_FUNCTION_FOOTER
07193 
07194         return true;
07195 }
07196 
07197 bool ImageProcessor::Average(const CByteImage *pInputImage1, const CByteImage *pInputImage2, CByteImage *pOutputImage)
07198 {
07199         OPTIMIZED_FUNCTION_HEADER_3(Average, pInputImage1, pInputImage2, pOutputImage)
07200         
07201         if (!pInputImage1->IsCompatible(pInputImage2) || !pInputImage1->IsCompatible(pOutputImage))
07202         {
07203                 printf("error: input images and output image do not match for ImageProcessor::Average\n");
07204                 return false;
07205         }
07206                 
07207         const int nBytes = pInputImage1->width * pInputImage1->height * pInputImage1->bytesPerPixel;
07208         
07209         const unsigned char *input1 = pInputImage1->pixels;
07210         const unsigned char *input2 = pInputImage2->pixels;
07211         unsigned char *output = pOutputImage->pixels;
07212         
07213         for (int i = 0; i < nBytes; i++)
07214                 output[i] = ((unsigned int) input1[i] + (unsigned int) input2[i] + 1) >> 1;
07215         
07216         OPTIMIZED_FUNCTION_FOOTER
07217 
07218         return true;
07219 }
07220 
07221 bool ImageProcessor::Min(const CByteImage *pInputImage1, const CByteImage *pInputImage2, CByteImage *pOutputImage)
07222 {
07223         OPTIMIZED_FUNCTION_HEADER_3(Min, pInputImage1, pInputImage2, pOutputImage)
07224         
07225         if (!pInputImage1->IsCompatible(pInputImage2) || !pInputImage1->IsCompatible(pOutputImage))
07226         {
07227                 printf("error: input images and output image do not match for ImageProcessor::Min\n");
07228                 return false;
07229         }
07230                 
07231         const int nBytes = pInputImage1->width * pInputImage1->height * pInputImage1->bytesPerPixel;
07232         
07233         const unsigned char *input1 = pInputImage1->pixels;
07234         const unsigned char *input2 = pInputImage2->pixels;
07235         unsigned char *output = pOutputImage->pixels;
07236         
07237         for (int i = 0; i < nBytes; i++)
07238                 output[i] = MY_MIN(input1[i], input2[i]);
07239         
07240         OPTIMIZED_FUNCTION_FOOTER
07241 
07242         return true;
07243 }
07244 
07245 bool ImageProcessor::Max(const CByteImage *pInputImage1, const CByteImage *pInputImage2, CByteImage *pOutputImage)
07246 {
07247         OPTIMIZED_FUNCTION_HEADER_3(Max, pInputImage1, pInputImage2, pOutputImage)
07248         
07249         if (!pInputImage1->IsCompatible(pInputImage2) || !pInputImage1->IsCompatible(pOutputImage))
07250         {
07251                 printf("error: input images and output image do not match for ImageProcessor::Max\n");
07252                 return false;
07253         }
07254                 
07255         const int nBytes = pInputImage1->width * pInputImage1->height * pInputImage1->bytesPerPixel;
07256         
07257         const unsigned char *input1 = pInputImage1->pixels;
07258         const unsigned char *input2 = pInputImage2->pixels;
07259         unsigned char *output = pOutputImage->pixels;
07260         
07261         for (int i = 0; i < nBytes; i++)
07262                 output[i] = MY_MAX(input1[i], input2[i]);
07263         
07264         OPTIMIZED_FUNCTION_FOOTER
07265 
07266         return true;
07267 }
07268 
07269 
07270 unsigned char ImageProcessor::MaxValue(const CByteImage *pInputImage)
07271 {
07272         unsigned char max;
07273         
07274         OPTIMIZED_FUNCTION_HEADER_2(MaxValue, pInputImage, max)
07275         
07276         if (pInputImage->type != CByteImage::eGrayScale)
07277         {
07278                 printf("error: input image must be of type eGrayScale for ImageProcessor::MaxValue\n");
07279                 return 0;
07280         }
07281         
07282         const int nPixels = pInputImage->width * pInputImage->height;
07283         const unsigned char *input = pInputImage->pixels;
07284         max = 0;
07285         
07286         for (int i = 0; i < nPixels; i++)
07287         {
07288                 if (input[i] > max)
07289                         max = input[i];
07290         }
07291         
07292         OPTIMIZED_FUNCTION_FOOTER
07293         
07294         return max;
07295 }
07296 
07297 short ImageProcessor::MaxValue(const CShortImage *pInputImage)
07298 {
07299         short max;
07300         
07301         OPTIMIZED_FUNCTION_HEADER_2(MaxValue_Short, pInputImage, max)
07302         
07303         const int nPixels = pInputImage->width * pInputImage->height;
07304         const short *input = pInputImage->pixels;
07305         max = SHRT_MIN;
07306         
07307         for (int i = 0; i < nPixels; i++)
07308         {
07309                 if (input[i] > max)
07310                         max = input[i];
07311         }
07312         
07313         OPTIMIZED_FUNCTION_FOOTER
07314         
07315         return max;
07316 }
07317 
07318 int ImageProcessor::MaxValue(const CIntImage *pInputImage)
07319 {
07320         int max;
07321         
07322         OPTIMIZED_FUNCTION_HEADER_2(MaxValue_Int, pInputImage, max)
07323         
07324         const int nPixels = pInputImage->width * pInputImage->height;
07325         const int *input = pInputImage->pixels;
07326         max = INT_MIN;
07327         
07328         for (int i = 0; i < nPixels; i++)
07329         {
07330                 if (input[i] > max)
07331                         max = input[i];
07332         }
07333         
07334         OPTIMIZED_FUNCTION_FOOTER
07335         
07336         return max;
07337 }
07338 
07339 unsigned char ImageProcessor::MinValue(const CByteImage *pInputImage)
07340 {
07341         unsigned char min;
07342         
07343         OPTIMIZED_FUNCTION_HEADER_2(MinValue, pInputImage, min)
07344         
07345         if (pInputImage->type != CByteImage::eGrayScale)
07346         {
07347                 printf("error: input image must be of type eGrayScale for ImageProcessor::MinValue\n");
07348                 return 0;
07349         }
07350         
07351         const int nPixels = pInputImage->width * pInputImage->height;
07352         const unsigned char *input = pInputImage->pixels;
07353         min = 255;
07354         
07355         for (int i = 0; i < nPixels; i++)
07356         {
07357                 if (input[i] < min)
07358                         min = input[i];
07359         }
07360         
07361         OPTIMIZED_FUNCTION_FOOTER
07362         
07363         return min;
07364 }
07365 
07366 short ImageProcessor::MinValue(const CShortImage *pInputImage)
07367 {
07368         short min;
07369         
07370         OPTIMIZED_FUNCTION_HEADER_2(MinValue_Short, pInputImage, min)
07371         
07372         const int nPixels = pInputImage->width * pInputImage->height;
07373         const short *input = pInputImage->pixels;
07374         min = SHRT_MAX;
07375         
07376         for (int i = 0; i < nPixels; i++)
07377         {
07378                 if (input[i] < min)
07379                         min = input[i];
07380         }
07381         
07382         OPTIMIZED_FUNCTION_FOOTER
07383         
07384         return min;
07385 }
07386 
07387 int ImageProcessor::MinValue(const CIntImage *pInputImage)
07388 {
07389         int min;
07390         
07391         OPTIMIZED_FUNCTION_HEADER_2(MinValue_Int, pInputImage, min)
07392         
07393         const int nPixels = pInputImage->width * pInputImage->height;
07394         const int *input = pInputImage->pixels;
07395         min = INT_MAX;
07396         
07397         for (int i = 0; i < nPixels; i++)
07398         {
07399                 if (input[i] < min)
07400                         min = input[i];
07401         }
07402         
07403         OPTIMIZED_FUNCTION_FOOTER
07404         
07405         return min;
07406 }
07407 
07408 bool ImageProcessor::MinMaxValue(const CByteImage *pInputImage, unsigned char &min, unsigned char &max)
07409 {
07410         OPTIMIZED_FUNCTION_HEADER_3(MinMaxValue, pInputImage, min, max)
07411         
07412         if (pInputImage->type != CByteImage::eGrayScale)
07413         {
07414                 printf("error: input image must be of type eGrayScale for ImageProcessor::MinMaxValue\n");
07415                 return false;
07416         }
07417         
07418         const int nPixels = pInputImage->width * pInputImage->height;
07419         const unsigned char *input = pInputImage->pixels;
07420         min = 255;
07421         max = 0;
07422         
07423         for (int i = 0; i < nPixels; i++)
07424         {
07425                 if (input[i] < min)
07426                         min = input[i];
07427                 
07428                 if (input[i] > max)
07429                         max = input[i];
07430         }
07431         
07432         OPTIMIZED_FUNCTION_FOOTER
07433 
07434         return true;
07435 }
07436 
07437 void ImageProcessor::MinMaxValue(const CShortImage *pInputImage, short &min, short &max)
07438 {
07439         OPTIMIZED_FUNCTION_HEADER_3(MinMaxValue_Short, pInputImage, min, max)
07440         
07441         const int nPixels = pInputImage->width * pInputImage->height;
07442         const short *input = pInputImage->pixels;
07443         min = SHRT_MAX;
07444         max = SHRT_MIN;
07445         
07446         for (int i = 0; i < nPixels; i++)
07447         {
07448                 if (input[i] < min)
07449                         min = input[i];
07450                 
07451                 if (input[i] > max)
07452                         max = input[i];
07453         }
07454         
07455         OPTIMIZED_FUNCTION_FOOTER
07456 }
07457 
07458 void ImageProcessor::MinMaxValue(const CIntImage *pInputImage, int &min, int &max)
07459 {
07460         OPTIMIZED_FUNCTION_HEADER_3(MinMaxValue_Int, pInputImage, min, max)
07461         
07462         const int nPixels = pInputImage->width * pInputImage->height;
07463         const int *input = pInputImage->pixels;
07464         min = INT_MAX;
07465         max = INT_MIN;
07466         
07467         for (int i = 0; i < nPixels; i++)
07468         {
07469                 if (input[i] < min)
07470                         min = input[i];
07471                 
07472                 if (input[i] > max)
07473                         max = input[i];
07474         }
07475         
07476         OPTIMIZED_FUNCTION_FOOTER
07477 }
07478 
07479 
07480 unsigned int ImageProcessor::PixelSum(const CByteImage *pImage)
07481 {
07482         unsigned int sum = 0;
07483 
07484         OPTIMIZED_FUNCTION_HEADER_2(PixelSum, pImage, sum)
07485 
07486         if (pImage->type != CByteImage::eGrayScale)
07487         {
07488                 printf("error: input image must be of type eGrayScale for ImageProcessor::PixelSum\n");
07489                 return -1;
07490         }
07491 
07492         const int nPixels = pImage->width * pImage->height;
07493         const unsigned char *pixels = pImage->pixels;
07494         
07495         for (int i = 0; i < nPixels; i++)
07496                 sum += pixels[i];
07497 
07498         OPTIMIZED_FUNCTION_FOOTER
07499         
07500         return sum;
07501 }
07502 
07503 
07504 
07505 
07507 // The Bayer pattern conversion source code is originally from the OpenCV.
07508 // Below is the copyright notice:
07510 //
07511 //  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
07512 //
07513 //  By downloading, copying, installing or using the software you agree to this license.
07514 //  If you do not agree to this license, do not download, install,
07515 //  copy or use the software.
07516 //
07517 //                        Intel License Agreement
07518 //                For Open Source Computer Vision Library
07519 //
07520 // Copyright (C) 2000, Intel Corporation, all rights reserved.
07521 // Third party copyrights are property of their respective owners.
07522 //
07523 // Redistribution and use in source and binary forms, with or without modification,
07524 // are permitted provided that the following conditions are met:
07525 //
07526 //   * Redistribution's of source code must retain the above copyright notice,
07527 //     this list of conditions and the following disclaimer.
07528 //
07529 //   * Redistribution's in binary form must reproduce the above copyright notice,
07530 //     this list of conditions and the following disclaimer in the documentation
07531 //     and/or other materials provided with the distribution.
07532 //
07533 //   * The name of Intel Corporation may not be used to endorse or promote products
07534 //     derived from this software without specific prior written permission.
07535 //
07536 // This software is provided by the copyright holders and contributors "as is" and
07537 // any express or implied warranties, including, but not limited to, the implied
07538 // warranties of merchantability and fitness for a particular purpose are disclaimed.
07539 // In no event shall the Intel Corporation or contributors be liable for any direct,
07540 // indirect, incidental, special, exemplary, or consequential damages
07541 // (including, but not limited to, procurement of substitute goods or services;
07542 // loss of use, data, or profits; or business interruption) however caused
07543 // and on any theory of liability, whether in contract, strict liability,
07544 // or tort (including negligence or otherwise) arising in any way out of
07545 // the use of this software, even if advised of the possibility of such damage.
07547 
07548 bool ImageProcessor::ConvertBayerPattern(const CByteImage *pBayerImage, CByteImage *pOutputImage, BayerPatternType type)
07549 {
07550         if (pBayerImage->type != CByteImage::eGrayScale || pOutputImage->type != CByteImage::eRGB24)
07551         {
07552                 printf("error: input image must be of type eGrayScale and output image of type eRGB24 for ImageProcessor::ConvertBayerPattern\n");
07553                 return false;
07554         }
07555         
07556         const unsigned char *input = pBayerImage->pixels;
07557         unsigned char *output = pOutputImage->pixels;
07558         
07559         const int width = pBayerImage->width;
07560         const int height = pBayerImage->height;
07561         const int width3 = 3 * width;
07562         
07563         int blue = type == eBayerGB || type == eBayerBG ? 1 : -1;
07564         bool bGreenFirst = type == eBayerGR || type == eBayerGB;
07565         
07566         memset(output, 0, width);
07567         memset(output + (height - 1) * width, 0, width);
07568         
07569         for (int i = 2, input_offset = 0, output_offset = width3 + 4; i < height; i++, input_offset += width, output_offset += width3)
07570         {
07571                 const unsigned char *bayer = input + input_offset;
07572                 const unsigned char *bayer_end = bayer + width - 4;
07573                 unsigned char *dst = output + output_offset;
07574                 
07575                 dst[-4] = dst[-3] = dst[-2] = 0;
07576                 
07577                 if (bGreenFirst)
07578                 {
07579                         dst[blue] = (unsigned char) ((bayer[1] + bayer[2 * width + 1] + 1) >> 1);
07580                         dst[0] = bayer[width + 1];
07581                         dst[-blue] = (unsigned char) ((bayer[width] + bayer[width + 2] + 1) >> 1);
07582                         
07583                         bayer++;
07584                         dst += 3;
07585                 }
07586                 
07587                 if (blue > 0)
07588                 {
07589                         for (; bayer <= bayer_end; bayer += 2, dst += 6)
07590                         {
07591                                 register int v = bayer[2] + bayer[2 * width + 2] + 1;
07592                                 
07593                                 dst[4] = (unsigned char) (v >> 1);
07594                                 dst[3] = bayer[width + 2];
07595                                 dst[2] = (unsigned char) ((bayer[width + 1] + bayer[width + 3] + 1) >> 1);
07596                                 
07597                                 dst[1] = (unsigned char) ((bayer[0] + bayer[2 * width] + v + 1) >> 2);
07598                                 dst[0] = (unsigned char) ((bayer[1] + bayer[width] + bayer[width + 2] + bayer[2 * width + 1] + 2) >> 2);
07599                                 dst[-1] = bayer[width + 1];
07600                         }
07601                 }
07602                 else
07603                 {
07604                         for (; bayer <= bayer_end; bayer += 2, dst += 6)
07605                         {
07606                                 register int v = bayer[2] + bayer[2 * width + 2] + 1;
07607                                 
07608                                 dst[2] = (unsigned char) (v >> 1);
07609                                 dst[3] = bayer[width + 2];
07610                                 dst[4] = (unsigned char) ((bayer[width + 1] + bayer[width + 3] + 1) >> 1);
07611                                 
07612                                 dst[-1] = (unsigned char) ((bayer[0] + bayer[2 * width] + v + 1) >> 2);
07613                                 dst[0] = (unsigned char) ((bayer[1] + bayer[width] + bayer[width + 2] + bayer[2 * width + 1] + 2) >> 2);
07614                                 dst[1] = bayer[width + 1];
07615                         }
07616                 }
07617                 
07618                 if (bayer < bayer_end + 2)
07619                 {
07620                         dst[blue] = (unsigned char) ((bayer[0] + bayer[2] + bayer[2 * width] + bayer[2 * width + 2] + 2) >> 2);
07621                         dst[0] = (unsigned char) ((bayer[1] + bayer[width] + bayer[width + 2] + bayer[2 * width + 1] + 2) >> 2);
07622                         dst[-blue] = bayer[width + 1];
07623                         
07624                         bayer++;
07625                         dst += 3;
07626                 }
07627                 
07628                 dst[-1] = dst[0] = dst[1] = 0;
07629                 
07630                 blue = -blue;
07631                 bGreenFirst = !bGreenFirst;
07632         }
07633         
07634         // this removes the black frame of the image by copying the pixels from the inner frame (2 pixels from the border)
07635         // to the frame pixels
07636         AdaptFrame(pOutputImage, pOutputImage);
07637 
07638         return true;
07639 }


asr_ivt
Author(s): Allgeyer Tobias, Hutmacher Robin, Kleinert Daniel, Meißner Pascal, Scholz Jonas, Stöckle Patrick
autogenerated on Thu Jun 6 2019 21:46:57