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 = rowMaskSize; row < rows-rowMaskSize; row++)
00040 for(int col = colMaskSize; col < cols-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 = row-rowMaskSize; (j < row+rowMaskSize) && (QVIMAGE_PIXEL(dest, col, row, 0) > 0); j++)
00047 for (int i = col-colMaskSize; i < col+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, const QPoint &destROIOffset)
00058 {
00059 const uInt rows = image.getRows(), cols = image.getCols();
00060 QVImage<uChar> buffer;
00061 MinEigenValGetBufferSize(image, buffer);
00062 QVImage<sFloat> eigval(cols, rows);
00063
00064 MinEigenVal(image, eigval, ippKernelSobel, 3, 5, buffer);
00065
00066 result = QVImage<sFloat>(cols, rows);
00067
00068 FilterEqualizeHistogram(eigval, result, destROIOffset);
00069 }
00070
00071 void FilterDoG(const QVImage<uChar> &image, QVImage<sFloat> &result)
00072 {
00073 const uInt rows = image.getRows(), cols = image.getCols();
00074 QVImage<uChar> gauss3x3(cols, rows), gauss5x5(cols, rows);
00075
00076 FilterGauss(image, gauss3x3, ippMskSize3x3);
00077 FilterGauss(image, gauss5x5, ippMskSize5x5);
00078
00079 result = QVImage<sFloat>(cols, rows);
00080 AbsDiff(gauss3x3, gauss5x5, result);
00081 }
00082
00083 void SobelCornerResponseImage(const QVImage<sFloat> &image, QVImage<sFloat> &result)
00084 {
00085 std::cerr << "WARNING: SobelCornerResponseImage is deprecated. Use FilterHessianCornerResponseImage instead." << std::endl;
00086 FilterHessianCornerResponseImage(image, result);
00087 }
00088
00089 void FilterHessianCornerResponseImage(const QVImage<sFloat> &image, QVImage<sFloat> &result, const QPoint &destROIOffset)
00090 {
00091 const uInt cols = image.getCols(), rows = image.getRows();
00092
00093
00094 QVImage<sFloat> Gx(cols, rows), Gy(cols, rows), Gxx(cols, rows),
00095 Gxy(cols, rows), Gyx(cols, rows), Gyy(cols, rows);
00096
00097 FilterSobelHorizMask(image,Gx);
00098 FilterSobelVertMask(image,Gy);
00099
00100 FilterSobelHorizMask(Gx,Gxx);
00101 FilterSobelVertMask(Gy,Gyy);
00102
00103 FilterSobelHorizMask(Gy,Gyx);
00104 FilterSobelVertMask(Gx,Gxy);
00105
00106 QVImage<sFloat> GxyGyx(cols, rows), GxxGyy(cols, rows);
00107
00108 Mul(Gxy, Gyx, GxyGyx);
00109 Mul(Gxx, Gyy, GxxGyy);
00110
00111 QVImage<sFloat> diffGxyGyx_GxxGyy(cols, rows);
00112
00113 Sub(GxyGyx, GxxGyy, diffGxyGyx_GxxGyy);
00114
00115 QVIMAGE_INIT_WRITE(sFloat,diffGxyGyx_GxxGyy);
00116 for (uInt col = 0; col < cols; col++)
00117 for(uInt row = 0; row < rows; row++)
00118 if (QVIMAGE_PIXEL(diffGxyGyx_GxxGyy, col, row, 0) <= 0)
00119 QVIMAGE_PIXEL(diffGxyGyx_GxxGyy, col, row, 0) = 0;
00120
00121 result = QVImage<sFloat>(cols, rows);
00122
00123 FilterEqualizeHistogram(diffGxyGyx_GxxGyy, result, destROIOffset);
00124 }
00125
00126
00127 int myFloodFill(QVImage<uChar> &image, uInt x, uInt y, uInt value, uInt minVal, uInt maxVal)
00128 {
00129
00130 Q_ASSERT( (value <= minVal) || (value >= maxVal) );
00131 Q_ASSERT( minVal <= maxVal );
00132
00133
00134 if ( (x >= image.getCols()) || (y >= image.getRows()))
00135 return 0;
00136
00137 if ( (image(x,y) < minVal) || (image(x,y) > maxVal) )
00138 return 0;
00139
00140 image(x,y) = value;
00141
00142 int val = 1;
00143 val += myFloodFill(image, x-1, y, value, minVal, maxVal);
00144 val += myFloodFill(image, x, y-1, value, minVal, maxVal);
00145 val += myFloodFill(image, x+1, y, value, minVal, maxVal);
00146 val += myFloodFill(image, x, y+1, value, minVal, maxVal);
00147
00148 val += myFloodFill(image, x-1, y-1, value, minVal, maxVal);
00149 val += myFloodFill(image, x-1, y+1, value, minVal, maxVal);
00150 val += myFloodFill(image, x+1, y-1, value, minVal, maxVal);
00151 val += myFloodFill(image, x+1, y+1, value, minVal, maxVal);
00152
00153 return val;
00154 }
00155
00156 void FilterSeparable(const QVImage<sFloat, 1> &image, QVImage<sFloat, 1> &dest,
00157 const QVVector &rowFilter, const QVVector &colFilter, const QPoint &destROIOffset)
00158 {
00159 const uInt cols = image.getCols(), rows = image.getRows();
00160 QVImage<sFloat> rowFiltered(cols, rows);
00161 FilterRow(image, rowFiltered, rowFilter);
00162 FilterColumn(rowFiltered, dest, colFilter, destROIOffset);
00163 }
00164
00166
00167 #include <qvip/qvimagefeatures/qvcomponenttree.h>
00168
00169 void pruneLowComponentTreeAux(QVImage<uChar> &image, QVComponentTree &componentTree, uInt minArea, uInt node, uInt validThreshold)
00170 {
00171 Q_ASSERT(componentTree.area(node)[componentTree.firstThreshold(node)] != 0);
00172 Q_ASSERT(componentTree.area(node)[componentTree.lastThreshold(node)] != 0);
00173 Q_ASSERT(validThreshold >= componentTree.lastThreshold(node));
00174
00175 bool prune = false;
00176 int lastValidThreshold = validThreshold;
00177
00178
00179
00180 for (int threshold = componentTree.lastThreshold(node); threshold >= componentTree.firstThreshold(node) && !prune; threshold--)
00181 if (componentTree.area(node)[threshold] > 0)
00182 {
00183 if (componentTree.area(node)[threshold] < minArea)
00184 prune = true;
00185 else
00186 lastValidThreshold = threshold;
00187 }
00188
00189
00190 if (prune)
00191 myFloodFill(image, componentTree.seedX(node), componentTree.seedY(node), lastValidThreshold, 0, lastValidThreshold-1);
00192 else
00193 for (uInt child = componentTree.firstChild(node); child != NULL_NODE; child = componentTree.nextSibling(child))
00194 pruneLowComponentTreeAux(image, componentTree, minArea, child, lastValidThreshold);
00195 }
00196
00197 void pruneHighComponentTreeAux(QVImage<uChar> &image, QVComponentTree &componentTree, uInt minArea, uInt node, uInt validThreshold)
00198 {
00199 Q_ASSERT(componentTree.area(node)[componentTree.firstThreshold(node)] != 0);
00200 Q_ASSERT(componentTree.area(node)[componentTree.lastThreshold(node)] != 0);
00201 Q_ASSERT(validThreshold >= componentTree.lastThreshold(node));
00202
00203 bool prune = false;
00204 int lastValidThreshold = validThreshold;
00205
00206
00207
00208 for (int threshold = componentTree.lastThreshold(node); threshold >= componentTree.firstThreshold(node) && !prune; threshold--)
00209 if (componentTree.area(node)[threshold] > 0)
00210 {
00211 if (componentTree.area(node)[threshold] < minArea)
00212 prune = true;
00213 else
00214 lastValidThreshold = threshold;
00215 }
00216
00217
00218 if (prune)
00219 myFloodFill(image, componentTree.seedX(node), componentTree.seedY(node), 255-lastValidThreshold, 255-lastValidThreshold+1, 255-0);
00220 else
00221 for (uInt child = componentTree.firstChild(node); child != NULL_NODE; child = componentTree.nextSibling(child))
00222 pruneHighComponentTreeAux(image, componentTree, minArea, child, lastValidThreshold);
00223 }
00224
00225 void FilterPruneComponentTreeSmallRegions(QVImage<uChar> &image, QVComponentTree &componentTree, uInt minArea)
00226 {
00227 qDebug() << "pruneRegions()";
00228 if (componentTree.isInverseTree())
00229 {
00230 if(componentTree.area(componentTree.rootNode())[componentTree.lastThreshold(componentTree.rootNode())] > minArea)
00231 pruneHighComponentTreeAux(image, componentTree, minArea, componentTree.rootNode(), componentTree.lastThreshold(componentTree.rootNode()));
00232 }
00233 else {
00234 if(componentTree.area(componentTree.rootNode())[componentTree.lastThreshold(componentTree.rootNode())] > minArea)
00235 pruneLowComponentTreeAux(image, componentTree, minArea, componentTree.rootNode(), componentTree.lastThreshold(componentTree.rootNode()));
00236 }
00237
00238 qDebug() << "pruneRegions() <~ return";
00239 }
00240
00241 #include <qvmath/qvdisjointset.h>
00242 #include <qvmath/qvvector.h>
00243
00244 QList<QPointF> GetMaximalResponsePoints1(const QVImage<sFloat> &cornerResponseImage, const double threshold)
00245 {
00246 const int sizeMax = 2;
00247 const int cols = cornerResponseImage.getCols(), rows = cornerResponseImage.getRows();
00248 QVImage<uChar> binaryResponseImage(cols, rows);
00249 QVIMAGE_INIT_READ(sFloat,cornerResponseImage);
00250 QVIMAGE_INIT_WRITE(uChar,binaryResponseImage);
00251
00252
00253 Set(0, binaryResponseImage);
00254
00255
00256 for(int row = sizeMax; row < rows-sizeMax; row++)
00257 for(int col = sizeMax; col < cols-sizeMax; col++)
00258 {
00259 sFloat actual = QVIMAGE_PIXEL(cornerResponseImage, col, row,0);
00260 if (actual >= threshold)
00261 {
00262 QVIMAGE_PIXEL(binaryResponseImage, col, row, 0) = IPP_MAX_8U;
00263 for (int j = row-sizeMax; (j < row+sizeMax) && (QVIMAGE_PIXEL(binaryResponseImage, col, row, 0) > 0); j++)
00264 for (int i = col-sizeMax; i < col+sizeMax; i++)
00265 if ( ((i != col) || (j != row)) && (actual <= QVIMAGE_PIXEL(cornerResponseImage, i, j, 0)) )
00266 {
00267 QVIMAGE_PIXEL(binaryResponseImage, col, row, 0) = 0;
00268 break;
00269 }
00270 }
00271 }
00272
00273
00274 QMap<sFloat, QPointF> sortedPoints;
00275 for(uInt row = 0; row < binaryResponseImage.getRows(); row++)
00276 for(uInt col = 0; col < binaryResponseImage.getCols(); col++)
00277 if (QVIMAGE_PIXEL(binaryResponseImage, col, row,0))
00278 sortedPoints.insertMulti(QVIMAGE_PIXEL(cornerResponseImage, col, row,0), QPointF(col+2, row+2));
00279
00280 QList<QPointF> result;
00281 foreach(sFloat key, sortedPoints.uniqueKeys())
00282 result += sortedPoints.values(key);
00283
00284 return result;
00285 }
00286
00287 QList<QPointF> GetMaximalResponsePoints3(const QVImage<sFloat> &cornerResponseImage, const double threshold)
00288 {
00289 static const int xD[4] = { -1, +0, +1, +0 },
00290 yD[4] = { +0, -1, +0, +1 };
00291
00292 const int rows = cornerResponseImage.getRows(), cols = cornerResponseImage.getCols();
00293 QVDisjointSet disjointSet(cornerResponseImage);
00294 QVIMAGE_INIT_READ(sFloat,cornerResponseImage);
00295
00296
00297 for(int row = 1; row < rows-1; row++)
00298 for(int col = 1; col < cols-1; col++)
00299 if (QVIMAGE_PIXEL(cornerResponseImage, col, row,0) >= threshold)
00300 {
00301
00302 int maxDir = -1;
00303 sFloat maxVal = QVIMAGE_PIXEL(cornerResponseImage, col, row, 0);
00304
00305 for (int d = 0; d < 4; d++)
00306 if ( maxVal < QVIMAGE_PIXEL(cornerResponseImage, col + xD[d], row + yD[d], 0) )
00307 {
00308 maxDir = d;
00309 maxVal = QVIMAGE_PIXEL(cornerResponseImage, col + xD[maxDir], row + yD[maxDir], 0);
00310 }
00311
00312
00313 if (maxDir > -1)
00314 disjointSet.unify(col, row, col + xD[maxDir], row + yD[maxDir]);
00315 }
00316
00317
00318 QMap<int, QVVector> hotPoints;
00319 for(int row = 1; row < rows-1; row++)
00320 for(int col = 1; col < cols-1; col++)
00321 {
00322 const sFloat pixelValue = QVIMAGE_PIXEL(cornerResponseImage, col, row, 0);
00323 if (QVIMAGE_PIXEL(cornerResponseImage, col, row, 0) >= threshold)
00324 {
00325 QVVector v(3);
00326 v[0] = pixelValue * col;
00327 v[1] = pixelValue * row;
00328 v[2] = pixelValue;
00329 const int setIndex = disjointSet.find(col, row);
00330 if (hotPoints.contains(setIndex))
00331 hotPoints[setIndex] += v;
00332 else
00333 hotPoints.insert(setIndex, v);
00334 }
00335 }
00336
00337
00338 QMap<sFloat, QPointF> sortedPoints;
00339 foreach(int index, hotPoints.keys())
00340 {
00341 QVVector v = hotPoints[index];
00342 sortedPoints.insertMulti(v[2], QPointF(v[0]/v[2]+2, v[1]/v[2]+2));
00343 }
00344
00345 QList<QPointF> result;
00346 foreach(sFloat key, sortedPoints.uniqueKeys())
00347 foreach (QPointF point, sortedPoints.values(key))
00348 result.append(point);
00349
00350 return result;
00351 }
00352
00353
00355
00356 #define DEFINE_QVDTA_FUNCTION_EQUALIZE_HISTOGRAM(TYPE, C) \
00357 void FilterEqualizeHistogram(const QVImage<TYPE,C> &image, QVImage<TYPE,C> &equalized, const QPoint &destROIOffset) \
00358 { \
00359 uInt rows = image.getRows(), cols = image.getCols(); \
00360 TYPE maxVal, minVal; \
00361 \
00362 Max(image,maxVal); \
00363 Min(image,minVal); \
00364 \
00365 QVImage<TYPE,C> temp(cols, rows), result(cols, rows); \
00366 SubC(image, minVal, temp); \
00367 MulC(temp, 255/(maxVal-minVal), result, 1, destROIOffset); \
00368 equalized = result; \
00369 }
00370
00371 DEFINE_QVDTA_FUNCTION_EQUALIZE_HISTOGRAM(uChar,1);
00372
00373 #define DEFINE_QVDTA_FUNCTION_EQUALIZE_HISTOGRAM2(TYPE, C) \
00374 void FilterEqualizeHistogram(const QVImage<TYPE,C> &image, QVImage<TYPE,C> &equalized, const QPoint &destROIOffset) \
00375 { \
00376 uInt rows = image.getRows(), cols = image.getCols(); \
00377 TYPE maxVal, minVal; \
00378 \
00379 Max(image,maxVal); \
00380 Min(image,minVal); \
00381 \
00382 QVImage<TYPE,C> temp(cols, rows), result(cols, rows); \
00383 SubC(image, minVal, temp); \
00384 MulC(temp, 255/(maxVal-minVal), result, destROIOffset); \
00385 equalized = result; \
00386 }
00387 DEFINE_QVDTA_FUNCTION_EQUALIZE_HISTOGRAM2(sFloat,1);
00388
00389
00390