00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
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
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
00092 Convert(image, imageFloat);
00093 timeFlag("Convert image from uChar to sShort");
00094
00095
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
00102 CannyGetSize(canny, buffer);
00103 Canny(dXNeg, dY, canny, buffer, cannyLow,cannyHigh);
00104 timeFlag("Apply Canny operator");
00105
00106
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
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
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
00169 const QList<QVPolyline> contours = getConnectedSetBorderContoursThreshold(image, threshold);
00170 timeFlag("Get contours from image");
00171
00172
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
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
00210
00211 addProperty< QList<QPointF> >("Corners", outputFlag);
00212 }
00213
00214 void iterate()
00215 {
00216
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
00223 QVImage<sFloat> cornerResponseImage(image.getRows(), image.getCols());
00224 FilterHessianCornerResponseImage(image, cornerResponseImage);
00225 timeFlag("Corner response image");
00226
00227
00228 QList<QPointF> hotPoints = GetMaximalResponsePoints3(cornerResponseImage, threshold);
00229 timeFlag("Local maximal filter");
00230
00231
00232
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
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
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
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