00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00024
00025 #include <stdio.h>
00026 #include <stdlib.h>
00027 #include <iostream>
00028
00029 #include <qvip.h>
00030 #include <qvipp.h>
00031
00032 void FilterLocalMax(const QVImage<sFloat> &src, QVImage<uChar> &dest, uInt colMaskSize, uInt rowMaskSize, sFloat threshold)
00033 {
00034 const int cols = src.getCols(), rows = src.getRows();
00035 Set(0, dest);
00036 sFloat actual;
00037 QVIMAGE_INIT_READ(sFloat,src);
00038 QVIMAGE_INIT_WRITE(uChar,dest);
00039 for(int row = ((int)rowMaskSize); row < rows-((int)rowMaskSize); row++)
00040 for(int col = ((int)colMaskSize); col < cols-((int)colMaskSize); col++)
00041 {
00042 actual = QVIMAGE_PIXEL(src, col, row,0);
00043 if (actual >= threshold)
00044 {
00045 QVIMAGE_PIXEL(dest, col, row, 0) = IPP_MAX_8U;
00046 for (int j = ((int)row-rowMaskSize); (j < row+((int)rowMaskSize)) && (QVIMAGE_PIXEL(dest, col, row, 0) > 0); j++)
00047 for (int i = ((int)col-colMaskSize); i < col+((int)colMaskSize); i++)
00048 if ( ((i != col) || (j != row)) && (actual <= QVIMAGE_PIXEL(src, i, j, 0)) )
00049 {
00050 QVIMAGE_PIXEL(dest, col, row, 0) = 0;
00051 break;
00052 }
00053 }
00054 }
00055 }
00056
00057 void FilterHarrisCornerResponseImage(const QVImage<uChar> &image, QVImage<sFloat> &result, int aperture, int avgwindow, const QPoint &)
00058 {
00059 QVImage<uChar> buffer;
00060 MinEigenValGetBufferSize(image, buffer);
00061
00062 MinEigenVal(image, result, ippKernelSobel, aperture, avgwindow, buffer);
00063 }
00064
00065 void FilterDoG(const QVImage<uChar> &image, QVImage<sFloat> &result)
00066 {
00067 const uInt rows = image.getRows(), cols = image.getCols();
00068 QVImage<uChar> gauss3x3(cols, rows), gauss5x5(cols, rows);
00069
00070 FilterGauss(image, gauss3x3, ippMskSize3x3);
00071 FilterGauss(image, gauss5x5, ippMskSize5x5);
00072
00073 result = QVImage<sFloat>(cols, rows);
00074 AbsDiff(gauss3x3, gauss5x5, result);
00075 }
00076
00077 void SobelCornerResponseImage(const QVImage<sFloat> &image, QVImage<sFloat> &result)
00078 {
00079 std::cerr << "WARNING: SobelCornerResponseImage is deprecated. Use FilterHessianCornerResponseImage instead." << std::endl;
00080 FilterHessianCornerResponseImage(image, result);
00081 }
00082
00083 void FilterHessianCornerResponseImage(const QVImage<sFloat> &image, QVImage<sFloat> &result, const IppiMaskSize maskSize, const QPoint &destROIOffset)
00084 {
00085 QVImage<sFloat> Gx, Gy, Gxx, Gxy, Gyx, Gyy, GxyGyx, GxxGyy;
00086
00087 FilterSobelHorizMask(image,Gx, maskSize);
00088 FilterSobelVertMask(image,Gy, maskSize);
00089
00090 FilterSobelHorizMask(Gx,Gxx, maskSize);
00091 FilterSobelVertMask(Gy,Gyy, maskSize);
00092 FilterSobelHorizMask(Gy,Gyx, maskSize);
00093 FilterSobelVertMask(Gx,Gxy, maskSize);
00094 Mul(Gxy, Gyx, GxyGyx);
00095 Mul(Gxx, Gyy, GxxGyy);
00096 AbsDiff(GxyGyx, GxxGyy, result,destROIOffset);
00097 }
00098
00100 int myFloodFill(QVImage<uChar> &image, uInt x, uInt y, uInt value, uInt minVal, uInt maxVal)
00101 {
00102
00103 Q_ASSERT( (value <= minVal) || (value >= maxVal) );
00104 Q_ASSERT( minVal <= maxVal );
00105
00106
00107 if ( (x >= image.getCols()) || (y >= image.getRows()))
00108 return 0;
00109
00110 if ( (image(x,y) < minVal) || (image(x,y) > maxVal) )
00111 return 0;
00112
00113 image(x,y) = value;
00114
00115 int val = 1;
00116 val += myFloodFill(image, x-1, y, value, minVal, maxVal);
00117 val += myFloodFill(image, x, y-1, value, minVal, maxVal);
00118 val += myFloodFill(image, x+1, y, value, minVal, maxVal);
00119 val += myFloodFill(image, x, y+1, value, minVal, maxVal);
00120
00121 val += myFloodFill(image, x-1, y-1, value, minVal, maxVal);
00122 val += myFloodFill(image, x-1, y+1, value, minVal, maxVal);
00123 val += myFloodFill(image, x+1, y-1, value, minVal, maxVal);
00124 val += myFloodFill(image, x+1, y+1, value, minVal, maxVal);
00125
00126 return val;
00127 }
00128
00129 void FilterSeparable(const QVImage<sFloat, 1> &image, QVImage<sFloat, 1> &dest,
00130 const QVVector &rowFilter, const QVVector &colFilter, const QPoint &destROIOffset)
00131 {
00132 const uInt cols = image.getCols(), rows = image.getRows();
00133 QVImage<sFloat> rowFiltered(cols, rows);
00134 FilterRow(image, rowFiltered, rowFilter);
00135 FilterColumn(rowFiltered, dest, colFilter, destROIOffset);
00136 }
00137
00139
00140 #include <qvip/qvimagefeatures/qvcomponenttree.h>
00141
00142 void pruneLowComponentTreeAux(QVImage<uChar> &image, QVComponentTree &componentTree, uInt minArea, uInt node, uInt validThreshold)
00143 {
00144 Q_ASSERT(componentTree.area(node)[componentTree.firstThreshold(node)] != 0);
00145 Q_ASSERT(componentTree.area(node)[componentTree.lastThreshold(node)] != 0);
00146 Q_ASSERT(validThreshold >= componentTree.lastThreshold(node));
00147
00148 bool prune = false;
00149 int lastValidThreshold = validThreshold;
00150
00151
00152
00153 for (int threshold = componentTree.lastThreshold(node); threshold >= componentTree.firstThreshold(node) && !prune; threshold--)
00154 if (componentTree.area(node)[threshold] > 0)
00155 {
00156 if (componentTree.area(node)[threshold] < minArea)
00157 prune = true;
00158 else
00159 lastValidThreshold = threshold;
00160 }
00161
00162
00163 if (prune)
00164 myFloodFill(image, componentTree.seedX(node), componentTree.seedY(node), lastValidThreshold, 0, lastValidThreshold-1);
00165 else
00166 for (uInt child = componentTree.firstChild(node); child != NULL_NODE; child = componentTree.nextSibling(child))
00167 pruneLowComponentTreeAux(image, componentTree, minArea, child, lastValidThreshold);
00168 }
00169
00170 void pruneHighComponentTreeAux(QVImage<uChar> &image, QVComponentTree &componentTree, uInt minArea, uInt node, uInt validThreshold)
00171 {
00172 Q_ASSERT(componentTree.area(node)[componentTree.firstThreshold(node)] != 0);
00173 Q_ASSERT(componentTree.area(node)[componentTree.lastThreshold(node)] != 0);
00174 Q_ASSERT(validThreshold >= componentTree.lastThreshold(node));
00175
00176 bool prune = false;
00177 int lastValidThreshold = validThreshold;
00178
00179
00180
00181 for (int threshold = componentTree.lastThreshold(node); threshold >= componentTree.firstThreshold(node) && !prune; threshold--)
00182 if (componentTree.area(node)[threshold] > 0)
00183 {
00184 if (componentTree.area(node)[threshold] < minArea)
00185 prune = true;
00186 else
00187 lastValidThreshold = threshold;
00188 }
00189
00190
00191 if (prune)
00192 myFloodFill(image, componentTree.seedX(node), componentTree.seedY(node), 255-lastValidThreshold, 255-lastValidThreshold+1, 255-0);
00193 else
00194 for (uInt child = componentTree.firstChild(node); child != NULL_NODE; child = componentTree.nextSibling(child))
00195 pruneHighComponentTreeAux(image, componentTree, minArea, child, lastValidThreshold);
00196 }
00197
00198 void FilterPruneComponentTreeSmallRegions(QVImage<uChar> &image, QVComponentTree &componentTree, uInt minArea)
00199 {
00200 qDebug() << "pruneRegions()";
00201 if (componentTree.isInverseTree())
00202 {
00203 if(componentTree.area(componentTree.rootNode())[componentTree.lastThreshold(componentTree.rootNode())] > minArea)
00204 pruneHighComponentTreeAux(image, componentTree, minArea, componentTree.rootNode(), componentTree.lastThreshold(componentTree.rootNode()));
00205 }
00206 else {
00207 if(componentTree.area(componentTree.rootNode())[componentTree.lastThreshold(componentTree.rootNode())] > minArea)
00208 pruneLowComponentTreeAux(image, componentTree, minArea, componentTree.rootNode(), componentTree.lastThreshold(componentTree.rootNode()));
00209 }
00210
00211 qDebug() << "pruneRegions() <~ return";
00212 }
00213
00214 #include <qvmath/qvdisjointset.h>
00215 #include <qvmath/qvvector.h>
00216
00217 QMap<sFloat, QPointF> GetMaximalResponsePoints(const QVImage<sFloat> &cornerResponseImage, const double threshold, const int windowSize)
00218 {
00219
00220 const QRect ROI = cornerResponseImage.getROI();
00221 const int step = cornerResponseImage.getStep() / sizeof(sFloat),
00222 cols = cornerResponseImage.getCols(),
00223 rows = cornerResponseImage.getRows(),
00224 windowSizeX2 = windowSize * 2;
00225
00226 QVIMAGE_INIT_READ(sFloat,cornerResponseImage);
00227
00228
00229 QMap<sFloat, QPointF> sortedPoints;
00230 for(int row = ROI.y() + windowSize; row < ROI.y() + ROI.height() - windowSize; row++)
00231 for(int col = ROI.x() + windowSize; col < ROI.x() + ROI.width() - windowSize; col++)
00232 {
00233 const sFloat actual = QVIMAGE_PIXEL(cornerResponseImage, col, row, 0);
00234 if (actual >= threshold)
00235 {
00236 bool cond = true;
00237
00238 sFloat const * pixel = & QVIMAGE_PIXEL(cornerResponseImage, col, row, 0) - windowSize * (1 + step);
00239 for (int j = 0; j <= windowSizeX2 && cond; j++, pixel += step - windowSizeX2 -1)
00240 for (int i = 0; i <= windowSizeX2 && cond; i++, pixel++)
00241 if ( ( i != windowSize || j != windowSize ) && ( actual <= *pixel) )
00242 cond = false;
00243
00244 if (cond)
00245 sortedPoints.insertMulti(-QVIMAGE_PIXEL(cornerResponseImage, col, row,0), QPointF(col+2, row+2));
00246 }
00247 }
00248
00249 return sortedPoints;
00250 }
00251
00252
00253
00254
00255
00256
00257
00258
00259
00260
00261
00262
00263
00264
00265
00266
00267
00268
00269
00270
00271
00272
00273
00274
00275
00276
00277
00278
00279
00280
00281
00282
00283
00284
00285
00286
00287
00288
00289
00290
00291
00292
00293
00294
00295
00296
00297
00298
00299
00300
00301
00302
00303
00304
00305
00306
00307
00308
00309
00310
00311
00312
00313
00314
00315
00316
00317
00318
00319
00320
00321
00322
00323
00324
00325
00326
00327
00328
00329
00330
00331
00332
00333
00334
00335
00336
00337
00338
00339
00340
00341
00342
00343
00344
00345
00346
00347
00348
00349
00350
00351
00352
00353
00354
00355
00356
00357
00358
00359
00360
00361
00362
00363
00364
00365
00366
00367
00368
00369 QVector< QVector< QPoint > > CountingSort(const QVImage<uChar, 1> &image)
00370 {
00371 QVector< QVector <QPoint> > result(256);
00372 const QVector<int> histogram = HistogramRange(image);
00373
00374 for (int k=0; k<256; k++)
00375 result[k].reserve(histogram[k]);
00376
00377 QVIMAGE_INIT_READ(uChar,image);
00378 for(uInt row = 0; row < image.getRows(); row++)
00379 for(uInt col = 0; col < image.getCols(); col++)
00380 result[QVIMAGE_PIXEL(image, col, row,0)].append(QPoint(col, row));
00381
00382 return result;
00383 }
00384
00385
00387
00388 #define DEFINE_QVDTA_FUNCTION_NORMALIZE(TYPE, C) \
00389 void FilterNormalize(const QVImage<TYPE,C> &image, QVImage<TYPE,C> &equalized, const QPoint &destROIOffset) \
00390 { \
00391 TYPE maxVal, minVal; \
00392 \
00393 Max(image,maxVal); \
00394 Min(image,minVal); \
00395 \
00396 QVImage<TYPE,C> temp, result; \
00397 SubC(image, minVal, temp); \
00398 MulC(temp, 255/(maxVal-minVal), result, 1, destROIOffset); \
00399 equalized = result; \
00400 }
00401
00402 DEFINE_QVDTA_FUNCTION_NORMALIZE(uChar,1);
00403
00404 #define DEFINE_QVDTA_FUNCTION_NORMALIZE2(TYPE, C) \
00405 void FilterNormalize(const QVImage<TYPE,C> &image, QVImage<TYPE,C> &equalized, const QPoint &destROIOffset) \
00406 { \
00407 uInt rows = image.getRows(), cols = image.getCols(); \
00408 TYPE maxVal, minVal; \
00409 \
00410 Max(image,maxVal); \
00411 Min(image,minVal); \
00412 \
00413 QVImage<TYPE,C> temp(cols, rows), result(cols, rows); \
00414 SubC(image, minVal, temp); \
00415 MulC(temp, 255/(maxVal-minVal), result, destROIOffset); \
00416 equalized = result; \
00417 }
00418 DEFINE_QVDTA_FUNCTION_NORMALIZE2(sFloat,1);
00419
00420
00421