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 QRect ROI = cornerResponseImage.getROI();
00247 const int sizeMax = 2;
00248 const int cols = cornerResponseImage.getCols(), rows = cornerResponseImage.getRows();
00249 const int x0 = ROI.x() + sizeMax,
00250 y0 = ROI.y() + sizeMax,
00251 x1 = ROI.x() + ROI.width() - sizeMax,
00252 y1 = ROI.y() + ROI.height() - sizeMax;
00253
00254 QVImage<uChar> binaryResponseImage(cols, rows);
00255 QVIMAGE_INIT_READ(sFloat,cornerResponseImage);
00256 QVIMAGE_INIT_WRITE(uChar,binaryResponseImage);
00257
00258
00259 Set(0, binaryResponseImage);
00260
00261
00262 for(int row = y0; row < y1; row++)
00263 for(int col = x0; col < x1; col++)
00264 {
00265 sFloat actual = QVIMAGE_PIXEL(cornerResponseImage, col, row,0);
00266 if (actual >= threshold)
00267 {
00268 QVIMAGE_PIXEL(binaryResponseImage, col, row, 0) = IPP_MAX_8U;
00269 for (int j = row-sizeMax; (j < row+sizeMax) && (QVIMAGE_PIXEL(binaryResponseImage, col, row, 0) > 0); j++)
00270 for (int i = col-sizeMax; i < col+sizeMax; i++)
00271 if ( ((i != col) || (j != row)) && (actual <= QVIMAGE_PIXEL(cornerResponseImage, i, j, 0)) )
00272 {
00273 QVIMAGE_PIXEL(binaryResponseImage, col, row, 0) = 0;
00274 break;
00275 }
00276 }
00277 }
00278
00279
00280 QMap<sFloat, QPointF> sortedPoints;
00281 for(int row = y0; row < y1; row++)
00282 for(int col = x0; col < x1; col++)
00283
00284
00285 if (QVIMAGE_PIXEL(binaryResponseImage, col, row,0))
00286 sortedPoints.insertMulti(QVIMAGE_PIXEL(cornerResponseImage, col, row,0), QPointF(col+2, row+2));
00287
00288 QList<QPointF> result;
00289 foreach(sFloat key, sortedPoints.uniqueKeys())
00290 result += sortedPoints.values(key);
00291
00292 return result;
00293 }
00294
00295 QList<QPointF> GetMaximalResponsePoints3(const QVImage<sFloat> &cornerResponseImage, const double threshold)
00296 {
00297 static const int xD[4] = { -1, +0, +1, +0 },
00298 yD[4] = { +0, -1, +0, +1 };
00299
00300 const int rows = cornerResponseImage.getRows(), cols = cornerResponseImage.getCols();
00301 QVDisjointSet disjointSet(cornerResponseImage);
00302 QVIMAGE_INIT_READ(sFloat,cornerResponseImage);
00303
00304
00305 for(int row = 1; row < rows-1; row++)
00306 for(int col = 1; col < cols-1; col++)
00307 if (QVIMAGE_PIXEL(cornerResponseImage, col, row,0) >= threshold)
00308 {
00309
00310 int maxDir = -1;
00311 sFloat maxVal = QVIMAGE_PIXEL(cornerResponseImage, col, row, 0);
00312
00313 for (int d = 0; d < 4; d++)
00314 if ( maxVal < QVIMAGE_PIXEL(cornerResponseImage, col + xD[d], row + yD[d], 0) )
00315 {
00316 maxDir = d;
00317 maxVal = QVIMAGE_PIXEL(cornerResponseImage, col + xD[maxDir], row + yD[maxDir], 0);
00318 }
00319
00320
00321 if (maxDir > -1)
00322 disjointSet.unify(col, row, col + xD[maxDir], row + yD[maxDir]);
00323 }
00324
00325
00326 QMap<int, QVVector> hotPoints;
00327 for(int row = 1; row < rows-1; row++)
00328 for(int col = 1; col < cols-1; col++)
00329 {
00330 const sFloat pixelValue = QVIMAGE_PIXEL(cornerResponseImage, col, row, 0);
00331 if (QVIMAGE_PIXEL(cornerResponseImage, col, row, 0) >= threshold)
00332 {
00333 QVVector v(3);
00334 v[0] = pixelValue * col;
00335 v[1] = pixelValue * row;
00336 v[2] = pixelValue;
00337 const int setIndex = disjointSet.find(col, row);
00338 if (hotPoints.contains(setIndex))
00339 hotPoints[setIndex] += v;
00340 else
00341 hotPoints.insert(setIndex, v);
00342 }
00343 }
00344
00345
00346 QMap<sFloat, QPointF> sortedPoints;
00347 foreach(int index, hotPoints.keys())
00348 {
00349 QVVector v = hotPoints[index];
00350 sortedPoints.insertMulti(v[2], QPointF(v[0]/v[2]+2, v[1]/v[2]+2));
00351 }
00352
00353 QList<QPointF> result;
00354 foreach(sFloat key, sortedPoints.uniqueKeys())
00355 foreach (QPointF point, sortedPoints.values(key))
00356 result.append(point);
00357
00358 return result;
00359 }
00360
00361
00363
00364 #define DEFINE_QVDTA_FUNCTION_EQUALIZE_HISTOGRAM(TYPE, C) \
00365 void FilterEqualizeHistogram(const QVImage<TYPE,C> &image, QVImage<TYPE,C> &equalized, const QPoint &destROIOffset) \
00366 { \
00367 uInt rows = image.getRows(), cols = image.getCols(); \
00368 TYPE maxVal, minVal; \
00369 \
00370 Max(image,maxVal); \
00371 Min(image,minVal); \
00372 \
00373 QVImage<TYPE,C> temp(cols, rows), result(cols, rows); \
00374 SubC(image, minVal, temp); \
00375 MulC(temp, 255/(maxVal-minVal), result, 1, destROIOffset); \
00376 equalized = result; \
00377 }
00378
00379 DEFINE_QVDTA_FUNCTION_EQUALIZE_HISTOGRAM(uChar,1);
00380
00381 #define DEFINE_QVDTA_FUNCTION_EQUALIZE_HISTOGRAM2(TYPE, C) \
00382 void FilterEqualizeHistogram(const QVImage<TYPE,C> &image, QVImage<TYPE,C> &equalized, const QPoint &destROIOffset) \
00383 { \
00384 uInt rows = image.getRows(), cols = image.getCols(); \
00385 TYPE maxVal, minVal; \
00386 \
00387 Max(image,maxVal); \
00388 Min(image,minVal); \
00389 \
00390 QVImage<TYPE,C> temp(cols, rows), result(cols, rows); \
00391 SubC(image, minVal, temp); \
00392 MulC(temp, 255/(maxVal-minVal), result, destROIOffset); \
00393 equalized = result; \
00394 }
00395 DEFINE_QVDTA_FUNCTION_EQUALIZE_HISTOGRAM2(sFloat,1);
00396
00397
00398