00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054 #include <new>
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
00088
00089
00090
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
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
00527
00528
00529
00530
00531
00532
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
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
00575 imageHeaderInputGrayscale.pixels = pInputImage->pixels;
00576 imageHeaderOutputGrayscale.pixels = pOutputImage->pixels;
00577 GaussianSmooth5x5(&imageHeaderInputGrayscale, &imageHeaderOutputGrayscale);
00578
00579
00580 imageHeaderInputGrayscale.pixels = pInputImage->pixels + nPixels;
00581 imageHeaderOutputGrayscale.pixels = pOutputImage->pixels + nPixels;
00582 GaussianSmooth5x5(&imageHeaderInputGrayscale, &imageHeaderOutputGrayscale);
00583
00584
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
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
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
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
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
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
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
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
01975 for (i = 0; i < nPixels; i++)
01976 histogram[input[i]]++;
01977
01978
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
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
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
02073 for (i = 0; i < nPixels; i++)
02074 histogram[input[i]]++;
02075
02076
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
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
03029 memset(pixels, 0, width);
03030 memset(pixels + width * (height - 1), 0, width);
03031
03032
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
03044 memset(pixels, 0, width3);
03045 memset(pixels + width3 * (height - 1), 0, width3);
03046
03047
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
03063 memset(pixels, 0, width * sizeof(short));
03064 memset(pixels + width * (height - 1), 0, width * sizeof(short));
03065
03066
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
03081 memset(pixels, 0, width * sizeof(int));
03082 memset(pixels + width * (height - 1), 0, width * sizeof(int));
03083
03084
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
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
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
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
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
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
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
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
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
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
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
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
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
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
04421 ImageProcessor::ZeroFrame(pTempImage);
04422
04423
04424 const int nPixels = temp_width * temp_height;
04425
04426 int *pStack = new int[nPixels];
04427 int *pRegionPixels = new int[nPixels];
04428
04429
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
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
04466 delete pTempImage;
04467 delete [] pStack;
04468 delete [] pRegionPixels;
04469
04470 return nRegionPixels;
04471 }
04472
04473 bool ImageProcessor::FindRegions(const CByteImage *pImage, RegionList ®ionList, int nMinimumPointsPerRegion, int nMaximumPointsPerRegion, bool bCalculateBoundingBox, bool bStorePixels)
04474 {
04475
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
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
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
04502 ImageProcessor::ZeroFrame(pTempImage);
04503
04504
04505 const int nPixels = temp_width * temp_height;
04506
04507 int *pStack = new int[nPixels];
04508 int *pRegionPixels = new int[nPixels];
04509
04510
04511 for (int i = 0; i < nPixels; i++)
04512 {
04513 if (temp[i] == 255)
04514 {
04515 MyRegion region;
04516
04517
04518 const int nRegionPixels = _RegionGrowing(temp, temp_width, i, pStack, pRegionPixels, region, nMinimumPointsPerRegion, nMaximumPointsPerRegion, bCalculateBoundingBox);
04519
04520 if (nRegionPixels > 0)
04521 {
04522
04523 regionList.push_back(region);
04524
04525
04526
04527 MyRegion &addedEntry = regionList.back();
04528
04529
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
04557 delete pTempImage;
04558 delete [] pStack;
04559 delete [] pRegionPixels;
04560
04561 return true;
04562 }
04563
04564 bool ImageProcessor::FindRegions(const CByteImage *pImage, CRegionArray ®ionList, int nMinimumPointsPerRegion, int nMaximumPointsPerRegion, bool bCalculateBoundingBox, bool bStorePixels)
04565 {
04566
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
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
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
04593 ImageProcessor::ZeroFrame(pTempImage);
04594
04595
04596 const int nPixels = temp_width * temp_height;
04597
04598 int *pStack = new int[nPixels];
04599 int *pRegionPixels = new int[nPixels];
04600
04601
04602 for (int i = 0; i < nPixels; i++)
04603 {
04604 if (temp[i] == 255)
04605 {
04606 MyRegion region;
04607
04608
04609 const int nRegionPixels = _RegionGrowing(temp, temp_width, i, pStack, pRegionPixels, region, nMinimumPointsPerRegion, nMaximumPointsPerRegion, bCalculateBoundingBox);
04610
04611 if (nRegionPixels > 0)
04612 {
04613
04614 regionList.AddElement(region);
04615
04616
04617
04618 MyRegion &addedEntry = regionList[regionList.GetSize() - 1];
04619
04620
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
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
04706 const int s = (255 * delta * division_table[max]) >> 20;
04707 int h;
04708
04709
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
04768 const int s = (255 * delta * division_table[max]) >> 20;
04769 int h;
04770
04771
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
04805 const int s = (255 * delta * division_table[max]) >> 20;
04806 int h;
04807
04808
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
04845 const int s = (255 * delta * division_table[max]) >> 20;
04846 int h;
04847
04848
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
04892 ImageProcessor::Zero(&houghSpace);
04893 short *houghspace = houghSpace.pixels;
04894
04895
04896
04897 InitSinCosTables();
04898
04899
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
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
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
04996 memset(houghspace, 0, nHoughPixels * sizeof(short));
04997
04998
04999
05000 InitSinCosTables();
05001
05002 const int mn = m * n;
05003 short *helper = houghspace - rmin * mn + rmax * m + rmax;
05004
05005
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
05021
05022
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
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
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
05100 resultLines.Clear();
05101
05102
05103 CStraightLine2dArray resultLines_;
05104
05105 HoughTransformLines(edgePoints, edgeDirections, width, height, nLinesToExtract, nMinHits, resultLines_, resultHits, pVisualizationImage);
05106
05107
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
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
05134 ImageProcessor::Zero(&houghSpace);
05135 short *houghspace = houghSpace.pixels;
05136
05137
05138
05139 InitSinCosTables();
05140
05141
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
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
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
05226 resultCircles.Clear();
05227
05228
05229 CCircle2dArray resultCircles_;
05230
05231 if (!HoughTransformCircles(edgePoints, edgeDirections, width, height, rmin, rmax, nCirclesToExtract, nMinHits, resultCircles_, resultHits, pVisualizationImage))
05232 return false;
05233
05234
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
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
05267 memset(houghspace, 0, nHoughPixels * sizeof(short));
05268
05269
05270
05271 InitSinCosTables();
05272
05273 const int mn = m * n;
05274 short *helper = houghspace - rmin * mn + rmax * m + rmax;
05275
05276
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
05308 }
05309 }
05310 }
05311
05312 resultCircles.Clear();
05313
05314
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
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
05440 memset(redHistogram, 0, sizeof(redHistogram));
05441 memset(greenHistogram, 0, sizeof(greenHistogram));
05442 memset(blueHistogram, 0, sizeof(blueHistogram));
05443
05444
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
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
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;
05518
05519 float pFilter[nKernelSize];
05520 float sum = 0.0f;
05521 int i;
05522
05523
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
06246 *output = *input++;
06247 output++;
06248
06249
06250 for (int x = 1; x < width; x++)
06251 {
06252 *output = *input++ + *(output - 1);
06253 output++;
06254 }
06255
06256
06257 for (int y = 1; y < height; y++)
06258 {
06259
06260 *output = *input++ + *(output - width);
06261 output++;
06262
06263
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
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
06301 int c = *input++;
06302 c = (c != 0 ? 1 : 0);
06303
06304 *output++ = c;
06305
06306
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
06317 for (int y = 1; y < height; y++)
06318 {
06319
06320 c = *input++;
06321 c = (c != 0 ? 1 : 0);
06322
06323 *output = c + *(output - width);
06324 output++;
06325
06326
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
06355 int c = *input++;
06356 *output++ = c;
06357
06358
06359 for (int x = 1; x < width; x++)
06360 {
06361 c = *input++;
06362 *output++ = c - *(input - 2);
06363 }
06364
06365
06366 for (int y = 1; y < height; y++)
06367 {
06368
06369 c = *input++;
06370 *output++ = c - *(input - width - 1);
06371
06372
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
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
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;
06512
06513 int i;
06514
06515
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
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
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
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(§orImage);
06702
06703 unsigned char *temp = tempImage.pixels;
06704 unsigned char *sectors = sectorImage.pixels;
06705 short *magnitudes = gradientsX.pixels;
06706
06707 int i;
06708
06709
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
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
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
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
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
06841 Zero(pOutputImage);
06842
06843
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
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
06871
06872
06873 pqsum = abs(pqsum);
06874
06875 ppsum >>= 4;
06876 qqsum >>= 4;
06877 pqsum >>= 4;
06878
06879
06880
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
06933 CIntImage R(pInputImage->width, pInputImage->height);
06934 CalculateHarrisMap(pInputImage, &R);
06935
06936 int *data = R.pixels;
06937 int i;
06938
06939
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
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
06959 QuicksortInverse(pCandidateOffsets, data, 0, nCandidates - 1);
06960
06961
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
06992 pInterestPoints[nInterestPoints].x = float(x);
06993 pInterestPoints[nInterestPoints].y = float(y);
06994 nInterestPoints++;
06995
06996
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
07508
07510
07511
07512
07513
07514
07515
07516
07517
07518
07519
07520
07521
07522
07523
07524
07525
07526
07527
07528
07529
07530
07531
07532
07533
07534
07535
07536
07537
07538
07539
07540
07541
07542
07543
07544
07545
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
07635
07636 AdaptFrame(pOutputImage, pOutputImage);
07637
07638 return true;
07639 }