PARP Research Group University of Murcia, Spain


src/qvip/qvip.cpp

Go to the documentation of this file.
00001 /*
00002  *      Copyright (C) 2007, 2008, 2009. PARP Research Group.
00003  *      <http://perception.inf.um.es>
00004  *      University of Murcia, Spain.
00005  *
00006  *      This file is part of the QVision library.
00007  *
00008  *      QVision is free software: you can redistribute it and/or modify
00009  *      it under the terms of the GNU Lesser General Public License as
00010  *      published by the Free Software Foundation, version 3 of the License.
00011  *
00012  *      QVision is distributed in the hope that it will be useful,
00013  *      but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015  *      GNU Lesser General Public License for more details.
00016  *
00017  *      You should have received a copy of the GNU Lesser General Public
00018  *      License along with QVision. If not, see <http://www.gnu.org/licenses/>.
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 &/*destROIOffset*/)
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         // Value should be inside range [minVal, maxVal]
00103         Q_ASSERT( (value <= minVal) || (value >= maxVal) );
00104         Q_ASSERT( minVal <= maxVal );
00105 
00106         // Coordinates should be inside the image.
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         // Here we decide if this node should be directly pruned
00152         // or if there's any sub-node we should prune
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         // We prune node, or get on with it's childrens
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         // Here we decide if this node should be directly pruned
00180         // or if there's any sub-node we should prune
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         // We prune node, or get on with it's childrens
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         // Recorremos la imagen
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 /*QList<QPointF> GetMaximalResponsePoints1(const QVImage<sFloat> &cornerResponseImage, const double threshold)
00253         {
00254         const QRect ROI = cornerResponseImage.getROI();
00255         const int sizeMax = 2;
00256         const int cols = cornerResponseImage.getCols(), rows = cornerResponseImage.getRows();
00257         const int       x0 = ROI.x() + sizeMax,
00258                         y0 = ROI.y() + sizeMax,
00259                         x1 = ROI.x() + ROI.width() - sizeMax,
00260                         y1 = ROI.y() + ROI.height() - sizeMax;
00261 
00262         QVImage<uChar> binaryResponseImage(cols, rows);
00263         QVIMAGE_INIT_READ(sFloat,cornerResponseImage);
00264         QVIMAGE_INIT_WRITE(uChar,binaryResponseImage);
00265 
00266         // 1. Get image with local maximums
00267         Set(0, binaryResponseImage);
00268 
00269         // Recorremos la imagen
00270         for(int row = y0; row < y1; row++)
00271                 for(int col = x0; col < x1; col++)
00272                         {
00273                         sFloat actual = QVIMAGE_PIXEL(cornerResponseImage, col, row,0);
00274                         if (actual >= threshold)
00275                                 {
00276                                 QVIMAGE_PIXEL(binaryResponseImage, col, row, 0) = IPP_MAX_8U;
00277                                 for (int j = row-sizeMax; (j < row+sizeMax) && (QVIMAGE_PIXEL(binaryResponseImage, col, row, 0) > 0); j++)
00278                                         for (int i = col-sizeMax; i < col+sizeMax; i++)
00279                                                 if ( ((i != col) || (j != row)) && (actual <= QVIMAGE_PIXEL(cornerResponseImage, i, j, 0)) )
00280                                                         {
00281                                                         QVIMAGE_PIXEL(binaryResponseImage, col, row, 0) = 0;
00282                                                         break;
00283                                                         }
00284                                 }
00285                         }
00286 
00287         // 2. Get sorted list of points
00288         QMap<sFloat, QPointF> sortedPoints;
00289         for(int row = y0; row < y1; row++)
00290                 for(int col = x0; col < x1; col++)
00291         //for(uInt row = 0; row < binaryResponseImage.getRows(); row++)
00292         //      for(uInt col = 0; col < binaryResponseImage.getCols(); col++)
00293                         if (QVIMAGE_PIXEL(binaryResponseImage, col, row,0))
00294                                 sortedPoints.insertMulti(QVIMAGE_PIXEL(cornerResponseImage, col, row,0), QPointF(col+2, row+2));
00295 
00296         QList<QPointF> result;
00297         foreach(sFloat key, sortedPoints.uniqueKeys())
00298                 result += sortedPoints.values(key);
00299 
00300         return result;
00301         }
00302 
00303 QList<QPointF> GetMaximalResponsePoints3(const QVImage<sFloat> &cornerResponseImage, const double threshold)
00304         {
00305         static const int        xD[4] = { -1, +0, +1, +0 },
00306                                 yD[4] = { +0, -1, +0, +1 };
00307 
00308         const int rows = cornerResponseImage.getRows(), cols = cornerResponseImage.getCols();
00309         QVDisjointSet disjointSet(cornerResponseImage);
00310         QVIMAGE_INIT_READ(sFloat,cornerResponseImage);
00311 
00312         // 1. Join in the disjoint set all the neighbour pixels
00313         for(int row = 1; row < rows-1; row++)
00314                 for(int col = 1; col < cols-1; col++)
00315                         if (QVIMAGE_PIXEL(cornerResponseImage, col, row,0) >= threshold)
00316                                 {
00317                                 // a. Look for the maximum neighbour for the actual pixel.
00318                                 int maxDir = -1;
00319                                 sFloat maxVal = QVIMAGE_PIXEL(cornerResponseImage, col, row, 0);
00320 
00321                                 for (int d = 0; d < 4; d++)
00322                                         if ( maxVal < QVIMAGE_PIXEL(cornerResponseImage, col + xD[d], row + yD[d], 0) )
00323                                                 {
00324                                                 maxDir = d;
00325                                                 maxVal = QVIMAGE_PIXEL(cornerResponseImage, col + xD[maxDir], row + yD[maxDir], 0);
00326                                                 }
00327         
00328                                 // b. If found, join actual pixel to its group.
00329                                 if (maxDir > -1)
00330                                         disjointSet.unify(col, row, col + xD[maxDir], row + yD[maxDir]);
00331                                 }
00332 
00333         // 2. Create sets for all the sets of pixels with more than one element.
00334         QMap<int, QVVector> hotPoints;
00335         for(int row = 1; row < rows-1; row++)
00336                 for(int col = 1; col < cols-1; col++)
00337                         {
00338                         const sFloat pixelValue = QVIMAGE_PIXEL(cornerResponseImage, col, row, 0);
00339                         if (QVIMAGE_PIXEL(cornerResponseImage, col, row, 0) >= threshold)
00340                                 {
00341                                 QVVector v(3);
00342                                 v[0] = pixelValue * col;
00343                                 v[1] = pixelValue * row;
00344                                 v[2] = pixelValue;
00345                                 const int setIndex = disjointSet.find(col, row);
00346                                 if (hotPoints.contains(setIndex))
00347                                         hotPoints[setIndex] += v;
00348                                 else
00349                                         hotPoints.insert(setIndex, v);
00350                                 }
00351                         }
00352 
00353         // 3. Get sorted list of points
00354         QMap<sFloat, QPointF> sortedPoints;
00355         foreach(int index, hotPoints.keys())
00356                 {
00357                 QVVector v = hotPoints[index];
00358                 sortedPoints.insertMulti(v[2], QPointF(v[0]/v[2]+2, v[1]/v[2]+2));
00359                 }
00360 
00361         QList<QPointF> result;
00362         foreach(sFloat key, sortedPoints.uniqueKeys())
00363                 foreach (QPointF point, sortedPoints.values(key))
00364                 result.append(point);
00365 
00366         return result;
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 



QVision framework. PARP research group, copyright 2007, 2008.