examples/tutorial/features3/features.cpp

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 
00036 #include <QVApplication>
00037 #include <QVMPlayerCamera>
00038 #include <QVDefaultGUI>
00039 #include <QVImageCanvas>
00040 #include <QVPolyline>
00041 #include <QVFilterSelectorWorker>
00042 
00043 #ifndef DOXYGEN_IGNORE_THIS
00044 class CannyOperatorWorker: public QVWorker
00045         {
00046         public:
00047                 CannyOperatorWorker(QString name): QVWorker(name)
00048                         {
00049                         addProperty<double>("cannyHigh", inputFlag, 150, "High threshold for Canny operator", 50, 1000);
00050                         addProperty<double>("cannyLow", inputFlag, 50, "Low threshold for Canny operator", 10, 500);
00051                         addProperty<bool>("applyIPE", inputFlag, TRUE, "If we want to apply the IPE algorithm");
00052                         addProperty<double>("paramIPE", inputFlag, 5.0, "IPE parameter (max. allowed distance to line)", 1.0, 25.0);
00053                         addProperty<bool>("intersectLines", inputFlag, TRUE, "If we want IPE to postprocess polyline (intersecting lines)");
00054                         addProperty<int>("minLengthContour", inputFlag, 25, "Minimal length of a contour to be considered", 1, 150);
00055                         addProperty<int>("showNothingCannyImage", inputFlag, 0, "If we want nothing|Canny|original image to be shown",0,2);
00056                         addProperty<bool>("showContours", inputFlag, TRUE, "If we want contours to be shown");
00057 
00058                         addProperty< QVImage<uChar,1> >("Output image", outputFlag);
00059                         addProperty< QVImage<uChar,3> >("Input image", inputFlag|outputFlag);
00060                         addProperty< QList<QVPolyline> >("Output contours", outputFlag);
00061                         }
00062 
00063                 void iterate()
00064                         {
00065                         // 0. Read input parameters
00066                         const double cannyHigh = getPropertyValue<double>("cannyHigh");
00067                         const double cannyLow = getPropertyValue<double>("cannyLow");
00068                         const bool applyIPE = getPropertyValue<bool>("applyIPE");
00069                         const double paramIPE = getPropertyValue<double>("paramIPE");
00070                         const bool intersectLines = getPropertyValue<bool>("intersectLines");
00071                         const int minLengthContour = getPropertyValue<int>("minLengthContour");
00072                         const int showNothingCannyImage = getPropertyValue<int>("showNothingCannyImage");
00073                         const bool showContours = getPropertyValue<bool>("showContours");
00074                         QVImage<uChar,1> image = getPropertyValue< QVImage<uChar,3> >("Input image");
00075                         const uInt cols = image.getCols(), rows = image.getRows();
00076 
00077                         QVImage<sFloat> imageFloat(cols, rows), dX(cols, rows), dY(cols, rows), dXNeg(cols, rows);
00078                         QVImage<uChar> canny(cols, rows), buffer;
00079 
00080                         // 1. Convert image from uChar to sShort
00081                         Convert(image, imageFloat);
00082                         timeFlag("Convert image from uChar to sShort");
00083                 
00084                         // 2. Obtain horizontal and vertical gradients from image
00085                         FilterSobelHorizMask(imageFloat,dY,3);
00086                         FilterSobelVertMask(imageFloat,dX,3);
00087                         MulC(dX, dXNeg, -1);
00088                         timeFlag("Obtain horizontal and vertical gradients from image");
00089                 
00090                         // 3. Apply Canny operator
00091                         CannyGetSize(canny, buffer);
00092                         Canny(dXNeg, dY, canny, buffer, cannyLow,cannyHigh);
00093                         timeFlag("Apply Canny operator");
00094 
00095                         // 4. Get contours
00096                         const QList<QVPolyline> contourList = getLineContoursThreshold8Connectivity(canny, 128);
00097                         timeFlag("Get contours");
00098 
00099                         QList<QVPolyline> outputList;
00100                         foreach(QVPolyline contour,contourList)
00101                                 {
00102                                 if(contour.size() > minLengthContour)
00103                                         {
00104                                         if(applyIPE)
00105                                                 {
00106                                                 QVPolyline IPEcontour;
00107                                                 IterativePointElimination(contour,IPEcontour,paramIPE,FALSE,intersectLines);
00108                                                 outputList.append(IPEcontour);
00109                                                 }
00110                                         else
00111                                                 outputList.append(contour);
00112                                         }
00113                                 }
00114                         timeFlag("IPE on contours");
00115 
00116                         // 5. Publish resulting data
00117                         if(showNothingCannyImage == 1)
00118                                 setPropertyValue< QVImage<uChar,1> >("Output image",canny);
00119                         else if(showNothingCannyImage == 2)
00120                                 setPropertyValue< QVImage<uChar,1> >("Output image",image);
00121                         else    {
00122                                 QVImage<uChar> whiteImage(cols, rows);
00123                                 Set(whiteImage,255);
00124                                 setPropertyValue< QVImage<uChar,1> >("Output image",whiteImage);
00125                                 }
00126                         if(showContours)
00127                                 setPropertyValue< QList< QVPolyline> >("Output contours",outputList);
00128                         else
00129                                 setPropertyValue< QList< QVPolyline> >("Output contours",QList<QVPolyline>());
00130 
00131                         timeFlag("Publish results");
00132                         }
00133         };
00134 
00135 class ContourExtractorWorker: public QVWorker
00136         {
00137         public:
00138                 ContourExtractorWorker(QString name): QVWorker(name)
00139                         {
00140                         addProperty<int>("Threshold", inputFlag, 128, "Threshold for a point to count as pertaining to a region", 0, 255);
00141                         addProperty<int>("MinAreaIPE", inputFlag, 0, "Minimal area to keep points in the IPE algorithm", 0, 50);
00142                         addProperty< QVImage<uChar,3> >("Input image", inputFlag|outputFlag);
00143                         addProperty< QList<QVPolyline> >("Internal contours", outputFlag);
00144                         addProperty< QList<QVPolyline> >("External contours", outputFlag);
00145                         }
00146 
00147                 void iterate()
00148                         {
00149                         // 0. Read input parameters
00150                         QVImage<uChar,1> image = getPropertyValue< QVImage<uChar,3> >("Input image");
00151                         const uInt      threshold = getPropertyValue< int >("Threshold"),
00152                                         minAreaIPE = getPropertyValue< int >("MinAreaIPE");
00153 
00154                         timeFlag("Read input parameters");
00155                 
00156                         // 1. Get contours from image
00157                         const QList<QVPolyline> contours = getConnectedSetBorderContoursThreshold(image, threshold);
00158                         timeFlag("Get contours from image");
00159 
00160                         // 2. Apply IPE
00161                         QList<QVPolyline> ipeContours;
00162 
00163                         foreach(QVPolyline polyline, contours)
00164                                 {
00165                                 QVPolyline ipePolyline;
00166                                 IterativePointElimination(polyline, ipePolyline, minAreaIPE);
00167                                 if (ipePolyline.size() > 0)
00168                                         ipeContours.append(ipePolyline);
00169                                 }
00170 
00171                         timeFlag("IPE filtering");
00172 
00173                         // 3. Export contours to output property
00174                         QList<QVPolyline> internalContours, externalContours;
00175 
00176                         foreach(QVPolyline polyline, ipeContours)
00177                                 if (polyline.direction)
00178                                         internalContours.append(polyline);
00179                                 else
00180                                         externalContours.append(polyline);
00181 
00182                         setPropertyValue< QList< QVPolyline> >("Internal contours",internalContours);
00183                         setPropertyValue< QList< QVPolyline> >("External contours",externalContours);
00184                         timeFlag("Computed output contours");
00185                         }
00186         };
00187 
00188 class HarrisExtractorWorker: public QVWorker
00189         {
00190         public:
00191                 HarrisExtractorWorker(QString name): QVWorker(name)
00192                         {
00193                         addProperty< int >("Points", inputFlag, 15, "window size ", 1, 100);
00194                         addProperty< double >("Threshold", inputFlag, 1.0, "window size ", 0.0, 256.0);
00195                         addProperty< QVImage<uChar,3> >("Input image", inputFlag|outputFlag);
00196                         addProperty< QList<QPointF> >("Corners", outputFlag);
00197                         }
00198 
00199                 void iterate()
00200                         {
00201                         // 0. Read input parameters
00202                         QVImage<uChar> image = getPropertyValue< QVImage<uChar,3> >("Input image");
00203                         const double threshold = getPropertyValue<double>("Threshold");
00204                         const int pointNumber = getPropertyValue<int>("Points");
00205                         timeFlag("grab Frame");
00206                 
00207                         // 1. Obtain corner response image.
00208                         QVImage<sFloat> cornerResponseImage(image.getRows(), image.getCols());
00209                         FilterHessianCornerResponseImage(image, cornerResponseImage);
00210                         timeFlag("Corner response image");
00211 
00212                         // 2. Local maximal filter.
00213                         QList<QPointF> hotPoints = GetMaximalResponsePoints3(cornerResponseImage, threshold);
00214                         timeFlag("Local maximal filter");
00215 
00216                         // 3. Output resulting data.
00217                         setPropertyValue< QList<QPointF> >("Corners", hotPoints.mid(MAX(0,hotPoints.size() - pointNumber)));
00218                         }
00219         };
00220 
00221 int main(int argc, char *argv[])
00222         {
00223         QVApplication app(argc, argv,
00224                 "Example program for QVision library. Obtains several features from input video frames."
00225                 );
00226 
00227         QVFilterSelectorWorker<uChar, 3> filterWorker("Filter worker");
00228         CannyOperatorWorker cannyWorker("Canny Operator Worker");
00229         ContourExtractorWorker contoursWorker("Contours Extractor Worker");
00230         HarrisExtractorWorker cornersWorker("Corners Worker");
00231 
00232         QVMPlayerCamera camera("Video");
00233         camera.link(&filterWorker, "Input image");
00234 
00235         filterWorker.linkProperty("Output image", &cannyWorker, "Input image", QVWorker::SynchronousLink);
00236         filterWorker.linkProperty("Output image", &contoursWorker, "Input image", QVWorker::SynchronousLink);
00237         filterWorker.linkProperty("Output image", &cornersWorker, "Input image", QVWorker::SynchronousLink);
00238 
00239         QVDefaultGUI interface;
00240 
00241         QVImageCanvas filteredCanvas("Input");
00242         filteredCanvas.linkProperty(filterWorker, "Output image");
00243 
00244         QVImageCanvas cannyCanvas("Canny");
00245         cannyCanvas.linkProperty(cannyWorker,"Output image");
00246         cannyCanvas.linkProperty(cannyWorker,"Output contours");
00247 
00248         QVImageCanvas contourCanvas("Contours");
00249         contourCanvas.linkProperty(contoursWorker, "Input image");
00250         contourCanvas.linkProperty(contoursWorker,"Internal contours", Qt::red);
00251         contourCanvas.linkProperty(contoursWorker,"External contours", Qt::blue);
00252 
00253         QVImageCanvas cornersCanvas("Corners");
00254         cornersCanvas.linkProperty(cornersWorker, "Input image");
00255         cornersCanvas.linkProperty(cornersWorker,"Corners", Qt::blue, false);
00256 
00257         return app.exec();
00258         }
00259 
00260 #endif