PARP Research Group University of Murcia, Spain


src/qvip/qvip.cpp

Go to the documentation of this file.
00001 /*
00002  *      Copyright (C) 2007, 2008. 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 = 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         //const QVImage<sFloat> imageSFloat = image;
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         // Value should be inside range [minVal, maxVal]
00130         Q_ASSERT( (value <= minVal) || (value >= maxVal) );
00131         Q_ASSERT( minVal <= maxVal );
00132 
00133         // Coordinates should be inside the image.
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         // Here we decide if this node should be directly pruned
00179         // or if there's any sub-node we should prune
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         // We prune node, or get on with it's childrens
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         // Here we decide if this node should be directly pruned
00207         // or if there's any sub-node we should prune
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         // We prune node, or get on with it's childrens
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         // 1. Get image with local maximums
00259         Set(0, binaryResponseImage);
00260 
00261         // Recorremos la imagen
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         // 2. Get sorted list of points
00280         QMap<sFloat, QPointF> sortedPoints;
00281         for(int row = y0; row < y1; row++)
00282                 for(int col = x0; col < x1; col++)
00283         //for(uInt row = 0; row < binaryResponseImage.getRows(); row++)
00284         //      for(uInt col = 0; col < binaryResponseImage.getCols(); col++)
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         // 1. Join in the disjoint set all the neighbour pixels
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                                 // a. Look for the maximum neighbour for the actual pixel.
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                                 // b. If found, join actual pixel to its group.
00321                                 if (maxDir > -1)
00322                                         disjointSet.unify(col, row, col + xD[maxDir], row + yD[maxDir]);
00323                                 }
00324 
00325         // 2. Create sets for all the sets of pixels with more than one element.
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         // 3. Get sorted list of points
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 



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