examples/features/features.cpp

00001 /*
00002  *      Copyright (C) 2007. 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 
00040 #include <stdio.h>
00041 #include <stdlib.h>
00042 #include <iostream>
00043 #include <QDebug>
00044 
00045 #include <QVApplication>
00046 #include <QVMPlayerCamera>
00047 #include <QVGUI>
00048 #include <QVImageCanvas>
00049 
00050 #include <QVPolyline>
00051 #include <qvdta/qvdta.h>
00052 #include <qvip/qvip.h>
00053 
00054 #ifndef DOXYGEN_IGNORE_THIS
00055 class CannyOperatorWorker: public QVWorker
00056         {
00057         public:
00058                 CannyOperatorWorker(QString name): QVWorker(name)
00059                         {
00060                         addProperty<double>("cannyHigh", inputFlag, 150, "High threshold for Canny operator", 50, 1000);
00061                         addProperty<double>("cannyLow", inputFlag, 50, "Low threshold for Canny operator", 10, 500);
00062                         addProperty<bool>("applyIPE", inputFlag, TRUE, "If we want to apply the IPE algorithm");
00063                         addProperty<double>("paramIPE", inputFlag, 5.0, "IPE parameter (max. allowed distance to line)", 1.0, 25.0);
00064                         addProperty<bool>("intersectLines", inputFlag, TRUE, "If we want IPE to postprocess polyline (intersecting lines)");
00065                         addProperty<int>("minLengthContour", inputFlag, 25, "Minimal length of a contour to be considered", 1, 150);
00066                         addProperty<int>("showNothingCannyImage", inputFlag, 0, "If we want nothing|Canny|original image to be shown",0,2);
00067                         addProperty<bool>("showContours", inputFlag, TRUE, "If we want contours to be shown");
00068 
00069                         addProperty< QVImage<uChar,1> >("Output image", outputFlag);
00070                         addProperty< QVImage<uChar,3> >("Input image", inputFlag|outputFlag);
00071                         addProperty< QList<QVPolyline> >("Output contours", outputFlag);
00072                         }
00073 
00074                 void iterate()
00075                         {
00076                         // 0. Read input parameters
00077                         const double cannyHigh = getPropertyValue<double>("cannyHigh");
00078                         const double cannyLow = getPropertyValue<double>("cannyLow");
00079                         const bool applyIPE = getPropertyValue<bool>("applyIPE");
00080                         const double paramIPE = getPropertyValue<double>("paramIPE");
00081                         const bool intersectLines = getPropertyValue<bool>("intersectLines");
00082                         const int minLengthContour = getPropertyValue<int>("minLengthContour");
00083                         const int showNothingCannyImage = getPropertyValue<int>("showNothingCannyImage");
00084                         const bool showContours = getPropertyValue<bool>("showContours");
00085                         const QVImage<uChar,1> image = getPropertyValue< QVImage<uChar,3> >("Input image");
00086                         const uInt cols = image.getCols(), rows = image.getRows();
00087 
00088                         QVImage<sFloat> imageFloat(cols, rows), dX(cols, rows), dY(cols, rows), dXNeg(cols, rows);
00089                         QVImage<uChar> canny(cols, rows), buffer;
00090                 
00091                         // 1. Convert image from uChar to sShort
00092                         Convert(image, imageFloat);
00093                         timeFlag("Convert image from uChar to sShort");
00094                 
00095                         // 2. Obtain horizontal and vertical gradients from image
00096                         FilterSobelHorizMask(imageFloat,dY,3);
00097                         FilterSobelVertMask(imageFloat,dX,3);
00098                         MulC(dX, dXNeg, -1);
00099                         timeFlag("Obtain horizontal and vertical gradients from image");
00100                 
00101                         // 3. Apply Canny operator
00102                         CannyGetSize(canny, buffer);
00103                         Canny(dXNeg, dY, canny, buffer, cannyLow,cannyHigh);
00104                         timeFlag("Apply Canny operator");
00105 
00106                         // 4. Get contours
00107                         const QList<QVPolyline> contourList = getLineContoursThreshold8Connectivity(canny, 128);
00108                         timeFlag("Get contours");
00109 
00110                         QList<QVPolyline> outputList;
00111                         foreach(QVPolyline contour,contourList)
00112                                 {
00113                                 if(contour.size() > minLengthContour)
00114                                         {
00115                                         if(applyIPE)
00116                                                 {
00117                                                 QVPolyline IPEcontour;
00118                                                 IterativePointElimination(contour,IPEcontour,paramIPE,FALSE,intersectLines);
00119                                                 outputList.append(IPEcontour);
00120                                                 }
00121                                         else
00122                                                 outputList.append(contour);
00123                                         }
00124                                 }
00125                         timeFlag("IPE on contours");
00126                 
00127                         // 5. Publish resulting data
00128                         if(showNothingCannyImage == 1)
00129                                 setPropertyValue< QVImage<uChar,1> >("Output image",canny);
00130                         else if(showNothingCannyImage == 2)
00131                                 setPropertyValue< QVImage<uChar,1> >("Output image",image);
00132                         else    {
00133                                 QVImage<uChar> whiteImage(cols, rows);
00134                                 Set(whiteImage,255);
00135                                 setPropertyValue< QVImage<uChar,1> >("Output image",whiteImage);
00136                                 }
00137                         if(showContours)
00138                                 setPropertyValue< QList< QVPolyline> >("Output contours",outputList);
00139                         else
00140                                 setPropertyValue< QList< QVPolyline> >("Output contours",QList<QVPolyline>());
00141 
00142                         timeFlag("Publish results");
00143                         }
00144         };
00145 
00146 class ContourExtractorWorker: public QVWorker
00147         {
00148         public:
00149                 ContourExtractorWorker(QString name): QVWorker(name)
00150                         {
00151                         addProperty<int>("Threshold", inputFlag,        128, "Threshold for a point to count as pertaining to a region", 0, 255);
00152                         addProperty<int>("MinAreaIPE", inputFlag,       0, "Minimal area to keep points in the IPE algorithm", 0, 50);
00153                         addProperty< QVImage<uChar,3> >("Input image", inputFlag|outputFlag);
00154                         addProperty< QList<QVPolyline> >("Internal contours", outputFlag);
00155                         addProperty< QList<QVPolyline> >("External contours", outputFlag);
00156                         }
00157 
00158                 void iterate()
00159                         {
00160                         // 0. Read input parameters
00161                         const QVImage<uChar,1> image = getPropertyValue< QVImage<uChar,3> >("Input image");
00162                         const uInt      rows = image.getRows(), cols = image.getCols(),
00163                                         threshold = getPropertyValue< int >("Threshold"),
00164                                         minAreaIPE = getPropertyValue< int >("MinAreaIPE");
00165 
00166                         timeFlag("Read input parameters");
00167                 
00168                         // 1. Get contours from image
00169                         const QList<QVPolyline> contours = getConnectedSetBorderContoursThreshold(image, threshold);
00170                         timeFlag("Get contours from image");
00171 
00172                         // 2. Apply IPE
00173                         QList<QVPolyline> ipeContours;
00174 
00175                         foreach(QVPolyline polyline, contours)
00176                                 {
00177                                 QVPolyline ipePolyline;
00178                                 IterativePointElimination(polyline, ipePolyline, minAreaIPE);
00179                                 if (ipePolyline.size() > 0)
00180                                         ipeContours.append(ipePolyline);
00181                                 }
00182 
00183                         timeFlag("IPE filtering");
00184 
00185                         // 3. Export contours to output property
00186                         QList<QVPolyline> internalContours, externalContours;
00187 
00188                         foreach(QVPolyline polyline, ipeContours)
00189                                 if (polyline.direction)
00190                                         internalContours.append(polyline);
00191                                 else
00192                                         externalContours.append(polyline);
00193 
00194                         setPropertyValue< QList< QVPolyline> >("Internal contours",internalContours);
00195                         setPropertyValue< QList< QVPolyline> >("External contours",externalContours);
00196                         timeFlag("Computed output contours");
00197                         }
00198         };
00199 
00200 class HarrisExtractorWorker: public QVWorker
00201         {
00202         public:
00203                 HarrisExtractorWorker(QString name): QVWorker(name)
00204                         {
00205                         addProperty< int >("Points", inputFlag, 15, "window size ", 1, 100);
00206                         addProperty< double >("Threshold", inputFlag, 1.0, "window size ", 0.0, 256.0);
00207 
00208                         addProperty< QVImage<uChar,3> >("Input image", inputFlag|outputFlag);
00209                         //addProperty< QVImage<uChar,1> >("Output image", inputFlag|outputFlag);
00210 
00211                         addProperty< QList<QPointF> >("Corners", outputFlag);
00212                         }
00213 
00214                 void iterate()
00215                         {
00216                         // 0. Read input parameters
00217                         const QVImage<uChar> image = getPropertyValue< QVImage<uChar,3> >("Input image");
00218                         const double threshold = getPropertyValue<double>("Threshold");
00219                         const int pointNumber = getPropertyValue<int>("Points");
00220                         timeFlag("grab Frame");
00221                 
00222                         // 1. Obtain corner response image.
00223                         QVImage<sFloat> cornerResponseImage(image.getRows(), image.getCols());
00224                         FilterHessianCornerResponseImage(image, cornerResponseImage);
00225                         timeFlag("Corner response image");
00226 
00227                         // 2. Local maximal filter.
00228                         QList<QPointF> hotPoints = GetMaximalResponsePoints3(cornerResponseImage, threshold);
00229                         timeFlag("Local maximal filter");
00230 
00231                         // 3. Output resulting data.
00232                         //setPropertyValue< QVImage<uChar,1> >("Output image", image);
00233                         setPropertyValue< QList<QPointF> >("Corners", hotPoints.mid(MAX(0,hotPoints.size() - pointNumber)));
00234                         }
00235         };
00236 
00237 #include <QVMSER>
00238 class MSERExtractorWorker: public QVWorker
00239         {
00240         private:
00241                 const QVImage<uChar> negateImage(const QVImage<uChar> image) const
00242                         {
00243                         const uInt rows = image.getRows(), cols = image.getCols();
00244                         QVImage<uChar> notImage(cols, rows);
00245                         for (uInt col = 0; col < cols; col++)
00246                                 for (uInt row = 0; row < rows; row++)
00247                                         notImage(col, row) = 255 - image(col, row);
00248 
00249                         return notImage;
00250                         }
00251 
00252         public:
00253                 MSERExtractorWorker(QString name): QVWorker(name)
00254                         {
00255                         addProperty<int>("Delta", inputFlag, 10, "MSER parameter, as seen in the paper.", 1, 128);
00256                         addProperty<int>("minAreaMSER", inputFlag, 10, "MSER with area lesser than this value are discarted.", 1, 100*100);
00257                         addProperty<int>("maxAreaMSER", inputFlag, 10000, "MSER with area greater than this value are discarted.", 1, 1000*1000);
00258                         addProperty<double>("diffAreaThreshold", inputFlag, 0.01, "Proportion of the difference in areas to be considered different", 0.0, 1.0);
00259                         addProperty< QVImage<uChar,3> >("Input image", inputFlag|outputFlag);
00260                         addProperty< QList<QVPolyline> >("MSER contours", outputFlag);
00261                         }
00262 
00263                 void iterate()
00264                         {
00265                         // 0. Read parameters
00266                         const int delta = getPropertyValue<int>("Delta"),
00267                                 minArea = getPropertyValue<int>("minAreaMSER"),
00268                                 maxArea = getPropertyValue<int>("maxAreaMSER");
00269                         const double diffAreaThreshold = getPropertyValue<double>("diffAreaThreshold");
00270                         const QVImage<uChar> image = getPropertyValue< QVImage<uChar,3> >("Input image");
00271                         const QVImage<uChar> notImage = negateImage(image);
00272 
00273                         timeFlag("Read parameters");
00274 
00275                         // 1. Apply MSER
00276                         QList<QVMSER> MSERListLow, MSERListHigh;
00277 
00278                         getMSER(image, MSERListLow, delta, minArea, maxArea, diffAreaThreshold);
00279                         timeFlag("MSER Low");
00280 
00281                         getMSER(notImage, MSERListHigh, delta, minArea, maxArea, diffAreaThreshold);
00282                         timeFlag("MSER High");
00283 
00284                         // 2. Publish resulting MSER's
00285                         QList< QVPolyline > polylineMSERList;
00286                         getMSERContours(image, MSERListLow, polylineMSERList);
00287                         getMSERContours(notImage, MSERListHigh, polylineMSERList);
00288 
00289                         setPropertyValue< QList<QVPolyline> >("MSER contours", polylineMSERList);
00290                         timeFlag("Publish resulting images");
00291                         }
00292         };
00293 
00294 int main(int argc, char *argv[])
00295         {
00296         QVApplication app(argc, argv,
00297                 "Example program for QVision library. Obtains several features from input video frames."
00298                 );
00299 
00300         CannyOperatorWorker cannyWorker("Canny Operator Worker");
00301         ContourExtractorWorker contoursWorker("Contours Extractor Worker");
00302         HarrisExtractorWorker cornersWorker("Corners Worker");
00303         MSERExtractorWorker mserWorker("MSER Worker");
00304 
00305         QVMPlayerCamera camera("Video");
00306 
00307         camera.link(&cannyWorker,"Input image");
00308         camera.link(&contoursWorker,"Input image");
00309         camera.link(&cornersWorker,"Input image");
00310         camera.link(&mserWorker,"Input image");
00311 
00312         QVGUI interface;
00313 
00314         QVImageCanvas cannyCanvas("Canny");
00315         cannyCanvas.linkProperty(cannyWorker,"Output image");
00316         cannyCanvas.linkProperty(cannyWorker,"Output contours");
00317 
00318         QVImageCanvas contourCanvas("Contours");
00319         contourCanvas.linkProperty(contoursWorker, "Input image");
00320         contourCanvas.linkProperty(contoursWorker,"Internal contours", Qt::red);
00321         contourCanvas.linkProperty(contoursWorker,"External contours", Qt::blue);
00322 
00323         QVImageCanvas cornersCanvas("Corners");
00324         cornersCanvas.linkProperty(cornersWorker, "Input image");
00325         cornersCanvas.linkProperty(cornersWorker,"Corners", Qt::blue, false);
00326 
00327         QVImageCanvas mserCanvas("MSER Regions");
00328         mserCanvas.linkProperty(mserWorker, "Input image");
00329         mserCanvas.linkProperty(mserWorker,"MSER contours", Qt::red);
00330 
00331         return app.exec();
00332         }
00333 
00334 #endif

Generated on Thu Jul 17 17:23:27 2008 for QVision by  doxygen 1.5.3