00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00035 #ifndef DOXYGEN_IGNORE_THIS // Do not generate any doxygen documentation from here on.
00036
00037
00038
00039
00040 #include <QVApplication>
00041
00042
00043 #include <QVVideoReaderBlock>
00044
00045
00046 #include <QVDefaultGUI>
00047 #include <QVImageCanvas>
00048 #include <QVFunctionPlot>
00049
00050
00051 #include <qvipp.h>
00052 #include <qvip.h>
00053 #include <qvmatrixalgebra.h>
00054
00055
00056
00057
00058 typedef QMap<sFloat,QPointF> TMapFloatPoints;
00059 Q_DECLARE_METATYPE(TMapFloatPoints);
00060 typedef QList<QLineF> TListLines;
00061 Q_DECLARE_METATYPE(TListLines);
00062
00063
00064
00065 class ResponseImageCanvas : public QVImageCanvas {
00066 public:
00067 ResponseImageCanvas(QString name) : QVImageCanvas(name) {
00068
00069 addProperty<QMap<sFloat,QPointF> >("Max points", inputFlag);
00070 } ;
00071 void custom_viewer() {
00072
00073 QMap<sFloat,QPointF> maxPoints = getPropertyValue< QMap<sFloat,QPointF> >("Max points");
00074
00075
00076 getQVPainter()->setPen(Qt::yellow);
00077 QMap<sFloat, QPointF>::iterator i = maxPoints.begin();
00078 int order = 1;
00079 while (i != maxPoints.end()) {
00080 QPointF point = i.value() + QPointF(0.5,0.5);
00081 sFloat response = i.key();
00082 getQVPainter()->drawLine(point+QPointF(-2,0),point+QPointF(+2,0));
00083 getQVPainter()->drawLine(point+QPointF(0,-2),point+QPointF(0,+2));
00084 getQVPainter()->drawTextUnscaled(point, QString("%1(%2)").arg(order).arg(-response));
00085 i++;
00086 order++;
00087 }
00088 };
00089 };
00090
00091 class CannyImageCanvas : public QVImageCanvas {
00092 public:
00093 CannyImageCanvas(QString name) : QVImageCanvas(name) {
00094 addProperty<int>("lr", inputFlag);
00095 addProperty< QList<QLineF> >("Regression lines", inputFlag);
00096 } ;
00097 void custom_viewer(){
00098 QVPolyline poly = getPropertyValue<QVPolyline>("poly select");
00099 QList<QLineF> regLines = getPropertyValue< QList<QLineF> >("Regression lines");
00100 const int lr = getPropertyValue<int>("lr");
00101 getQVPainter()->setPen(Qt::green);
00102 foreach(QPoint point,poly)
00103 getQVPainter()->drawRect(point.x()-lr,point.y()-lr,2*lr+1,2*lr+1);
00104 getQVPainter()->setPen(Qt::red);
00105 foreach(QLineF line,regLines)
00106 getQVPainter()->drawLine(line.translated(0.5,0.5));
00107 };
00108 };
00109
00110
00111
00112
00113
00114
00115
00116 QMap<sFloat,QPointF> findMaximalPoints(const QVImage<sFloat> &image, const double threshold, const int windowRadius)
00117 {
00118 QVImage<sFloat> maxImage;
00119 FilterMax(image, maxImage,
00120 QSize(2*windowRadius+1,2*windowRadius+1),
00121 QPoint(0,0),
00122 image.getROI().topLeft() + QPoint(windowRadius, windowRadius)
00123 );
00124
00125 const QRect ROI = maxImage.getROI();
00126 const int maxStep = maxImage.getStep() / sizeof(sFloat),
00127 imageStep = image.getStep() / sizeof(sFloat);
00128
00129 QMap<sFloat, QPointF> sortedPoints;
00130
00131 sFloat *actualPtr = (sFloat *) image.getReadData() + (imageStep + 1) * windowRadius;
00132 sFloat *maxPtr = (sFloat *) maxImage.getReadData() + (maxStep + 1) * windowRadius;
00133
00134 for(int j = 0; j < ROI.height(); j++, actualPtr += imageStep, maxPtr += maxStep)
00135 for(int i = 0; i < ROI.width(); i++)
00136 if ( (actualPtr[i] >= threshold) and (maxPtr[i] == actualPtr[i]) )
00137
00138 sortedPoints.insertMulti(-actualPtr[i], QPointF(i+ROI.x(), j+ROI.y()));
00139
00140 return sortedPoints;
00141 }
00142
00143 QVImage<uChar> getCannyImage(const QVImage<uChar> imageGray, QRect CannyROI, const double thrLow, const double thrHigh)
00144 {
00145 uInt cols = imageGray.getCols(), rows = imageGray.getRows();
00146 QVImage<sFloat> imageFloat(imageGray),dX(cols,rows), dY(cols,rows), dXNeg(cols,rows);
00147 QVImage<uChar> imageCanny(cols,rows), buffer;
00148
00149 QVImage<uChar> imageDest(imageGray);
00150 imageFloat.setROI(CannyROI);
00151 imageCanny.setROI(CannyROI);
00152 FilterSobelHorizMask(imageFloat, dY, ippMskSize3x3);
00153 FilterSobelVertMask(imageFloat, dX, ippMskSize3x3);
00154 MulC(dX, -1, dXNeg);
00155 CannyGetSize(imageCanny, buffer);
00156 Canny(dXNeg, dY, imageCanny, qMin(thrLow,thrHigh) , thrHigh, buffer);
00157 Copy(imageCanny, imageDest, QPoint(CannyROI.x(),CannyROI.y()));
00158 imageDest.resetROI();
00159
00160 return imageDest;
00161 }
00162
00163 QList<QLineF> getRegressionLines(const QVImage<uChar> &imageCanny, const QRect &CannyROI,
00164 const QVPolyline &CannySelPoints, int lr)
00165 {
00166 QList<QLineF> regLines;
00167 for(int k=0;k<CannySelPoints.size();k++) {
00168 QPointF mean(0,0);
00169 QList<QPointF> listPoints;
00170 QPointF point = CannySelPoints[k];
00171 for(int j=point.y()-lr;j<=point.y()+lr;j++)
00172 for(int i=point.x()-lr;i<=point.x()+lr;i++)
00173 if(CannyROI.contains(i,j))
00174 if(imageCanny(i,j) == 255) {
00175 listPoints.append(QPointF(i,j));
00176 mean += QPointF(i,j);
00177 }
00178 const int n = listPoints.size();
00179 if(n >= 2) {
00180 mean /= n;
00181 QVMatrix M(n,2);
00182 for(int k=0;k<n;k++) {
00183 M(k,0) = listPoints[k].x() - mean.x();
00184 M(k,1) = listPoints[k].y() - mean.y();
00185 }
00186 QVMatrix covMat = M.transpose()*M / n, Q;
00187 QVVector lambda;
00188 eigenDecomposition(covMat,lambda,Q);
00189 QVVector mainEigenvector = Q.getCol(0);
00190 QPointF pointEV(mainEigenvector(0),mainEigenvector(1));
00191 regLines.append(QLineF(mean+lr*pointEV,mean-lr*pointEV));
00192 }
00193 }
00194 return regLines;
00195 }
00196
00197
00198
00199
00200
00201
00202
00203
00204
00205
00206 class MyProcessingBlock: public QVProcessingBlock {
00207 private:
00208 QVIndexedStringList filterList;
00209
00210 public:
00211 MyProcessingBlock(QString name = QString()): QVProcessingBlock(name) {
00212
00213
00214 addProperty<bool>("box", inputFlag, false, "Apply box filter");
00215 addProperty<int>("boxrows", inputFlag, 3, "Row box size", 1, 5);
00216 addProperty<int>("boxcols", inputFlag, 3, "Col box size", 1, 5);
00217 addProperty<double>("thhi", inputFlag, 150, "High threshold for Canny operator", 50, 1000);
00218 addProperty<double>("thlo", inputFlag, 50, "Low threshold for Canny operator", 10, 500);
00219 addProperty<double>("thMax", inputFlag, 50, "Max threshold for Hessian/Harris", 1.0, 255.0);
00220 addProperty<int>("lr", inputFlag|outputFlag, 5, "Radius for Canny regression lines", 2, 20);
00221
00222
00223 filterList.append("None");
00224 filterList.append("Hessian");
00225 filterList.append("Harris");
00226
00227 addProperty<QVIndexedStringList>("Filter", inputFlag, filterList, "Apply corner response filter");
00228
00229
00230 addProperty<QRect>("CannyROI", inputFlag);
00231 addProperty<QVPolyline>("CannySelPoints", inputFlag);
00232
00233
00234 addProperty< QVImage<uChar,3> >("Input RGB image", inputFlag|outputFlag);
00235 addProperty< QVImage<uChar,1> >("Output image byte", outputFlag);
00236 addProperty< QVImage<sFloat,1> >("Output image float", outputFlag);
00237
00238
00239 addProperty< QMap<sFloat,QPointF> >("Max points", outputFlag);
00240 addProperty< QList<QLineF> >("Regression lines", outputFlag);
00241 addProperty< QList<double> >("R histogram", outputFlag);
00242 addProperty< QList<double> >("G histogram", outputFlag);
00243 addProperty< QList<double> >("B histogram", outputFlag);
00244
00245
00246 addTrigger("Snapshot");
00247 }
00248
00249
00250 void processTrigger(const QString triggerName) {
00251 if(triggerName == "Snapshot") {
00252 QVImage<uchar,3> imageRGB = getPropertyValue< QVImage<uChar,3> >("Input RGB image");
00253 QImage qimage = imageRGB;
00254 qimage.save("snapshot.jpg");
00255 }
00256 }
00257
00258
00259 void iterate() {
00260
00261 QVImage<uchar,3> imageRGB = getPropertyValue< QVImage<uChar,3> >("Input RGB image");
00262
00263
00264 QVImage<uchar,1> imageGray = imageRGB;
00265
00266
00267 const QVIndexedStringList selectedFilter = getPropertyValue<QVIndexedStringList>("Filter");
00268 const bool applyBox = getPropertyValue<bool>("box");
00269 const int boxRows = getPropertyValue<int>("boxrows");
00270 const int boxCols = getPropertyValue<int>("boxcols");
00271 const double thrLow = getPropertyValue<double>("thhi");
00272 const double thrHigh = getPropertyValue<double>("thlo");
00273 const double thMax = getPropertyValue<double>("thMax");
00274 const int lr = getPropertyValue<int>("lr");
00275
00276
00277 QRect CannyROI = getPropertyValue<QRect>("CannyROI");
00278 QVPolyline CannySelPoints = getPropertyValue<QVPolyline>("CannySelPoints");
00279
00280
00281 timeFlag("Read input parameters");
00282
00283
00284 uInt cols = imageGray.getCols(), rows = imageGray.getRows();
00285
00286
00287 bool computeCanny = true;
00288 if (CannyROI == QRect()) {
00289
00290 CannyROI = imageGray.getROI();
00291 } else if(CannyROI.height()>=5 and CannyROI.width()>=5) {
00292
00293 if(CannyROI.bottom() == static_cast<int>(rows)-1)
00294 CannyROI.setBottom(CannyROI.bottom()-1);
00295 } else {
00296
00297 computeCanny = false;
00298 }
00299
00300
00301 QVImage<uChar> imageCanny;
00302 if(computeCanny)
00303 imageCanny = getCannyImage(imageGray,CannyROI,thrLow,thrHigh);
00304 else
00305 imageCanny = imageGray;
00306
00307 timeFlag("Canny operator");
00308
00309
00310 QList<QLineF> regLines = getRegressionLines(imageCanny,CannyROI,CannySelPoints,lr);
00311
00312 timeFlag("Regression lines");
00313
00314
00315 if(applyBox) {
00316
00317 QVImage<uChar> imageGray2(cols,rows);
00318 FilterBox(imageGray, imageGray2, QSize(boxCols,boxRows),
00319 QPoint(0,0), QPoint(boxCols/2,boxRows/2));
00320 imageGray = imageGray2;
00321
00322 imageGray.resetROI();
00323 }
00324 timeFlag("Box filter");
00325
00326
00327 QVImage<sFloat> imageFloat(cols,rows);
00328 int choice = selectedFilter.getIndex();
00329 switch (choice) {
00330 case 0: {
00331 imageFloat = imageGray;
00332 break;
00333 }
00334 case 1: {
00335 FilterHessianCornerResponseImage(imageGray, imageFloat, QPoint(2,2));
00336 break;
00337 }
00338 case 2: {
00339 FilterHarrisCornerResponseImage(imageGray, imageFloat);
00340
00341 break;
00342 }
00343 }
00344 timeFlag("Corner response filter");
00345
00346
00347 imageFloat.resetROI();
00348
00349
00350 FilterNormalize(imageFloat, imageFloat);
00351
00352 timeFlag("Normalization");
00353
00354 QMap<sFloat,QPointF> maxPoints;
00355 if(choice != 0) {
00356 const int radius = 3;
00357 maxPoints = findMaximalPoints(imageFloat, thMax, radius);
00358 }
00359 timeFlag("Get maximum response points");
00360
00361
00362 QVImage<uChar> selected;
00363 Copy(imageRGB,0,selected);
00364 const QVector<int> RHistogramInt = HistogramRange(selected);
00365 Copy(imageRGB,1,selected);
00366 const QVector<int> GHistogramInt = HistogramRange(selected);
00367 Copy(imageRGB,2,selected);
00368 const QVector<int> BHistogramInt = HistogramRange(selected);
00369
00370 QList<double> RHistogram,GHistogram,BHistogram;
00371 foreach(int val,RHistogramInt)
00372 RHistogram.append(val);
00373 foreach(int val,GHistogramInt)
00374 GHistogram.append(val);
00375 foreach(int val,BHistogramInt)
00376 BHistogram.append(val);
00377
00378 timeFlag("Obtain RGB histograms");
00379
00380
00381 setPropertyValue< QVImage<uchar,1> >("Output image byte", imageCanny);
00382 setPropertyValue< QVImage<sFloat,1> >("Output image float", imageFloat);
00383 setPropertyValue< QMap<sFloat,QPointF> >("Max points", maxPoints);
00384 setPropertyValue< QList<QLineF> >("Regression lines", regLines);
00385 setPropertyValue< QList<double> >("R histogram", RHistogram);
00386 setPropertyValue< QList<double> >("G histogram", GHistogram);
00387 setPropertyValue< QList<double> >("B histogram", BHistogram);
00388
00389 timeFlag("Write output parameters");
00390 }
00391 };
00392
00393
00394
00395
00396
00397
00398
00399
00400 int main(int argc, char *argv[]) {
00401
00402 QVApplication app(argc, argv, "Example program for QVision library.");
00403
00404
00405 QVVideoReaderBlock camera("Video");
00406
00407
00408 MyProcessingBlock filterBlock("Image filter block");
00409
00410
00411 QVDefaultGUI interface;
00412 QVImageCanvas inputImage("Input RGB image");
00413 CannyImageCanvas outputImageByte("Output image byte");
00414 ResponseImageCanvas outputImageFloat("Output image float");
00415 QVFunctionPlot RGBHistogramPlot("RGB histogram");
00416
00417
00418 camera.linkProperty(&filterBlock,"Input RGB image");
00419
00420 filterBlock.linkProperty("Input RGB image", inputImage);
00421 filterBlock.linkProperty("Output image byte", outputImageByte);
00422 filterBlock.linkProperty("Regression lines", outputImageByte, "Regression lines");
00423 filterBlock.linkProperty("Output image float", outputImageFloat);
00424 filterBlock.linkProperty("Max points", outputImageFloat,"Max points");
00425 filterBlock.linkProperty("lr",outputImageByte,"lr");
00426 filterBlock.linkProperty("R histogram",RGBHistogramPlot);
00427 filterBlock.linkProperty("G histogram",RGBHistogramPlot);
00428 filterBlock.linkProperty("B histogram",RGBHistogramPlot);
00429 outputImageByte.linkSelectedRectangle(filterBlock,"CannyROI");
00430 outputImageByte.linkSelectedPolyline(filterBlock,"CannySelPoints");
00431
00432
00433 return app.exec();
00434 }
00435
00436 #endif
00437
00438