00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include <stdio.h>
00023 #include <stdlib.h>
00024 #include <string.h>
00025 #include <iostream>
00026 #include <QDebug>
00027 #include <QVector>
00028 #include <QMap>
00029
00030 #include <qvcore/qvapplication.h>
00031 #include <qvcameras/qvmplayercamera.h>
00032 #include <qvgui/qvdefaultgui.h>
00033 #include <qvip/qvipp/qvipp.h>
00034 #include <qvip/qvpolyline.h>
00035 #include <qvdta/qvdta.h>
00036
00037 #ifndef DOXYGEN_IGNORE_THIS
00038
00039
00040
00041 QList<QPoint> MaxIPP( QVImage<sFloat> &image1, QVImage<sFloat> &image2, QVImage<sFloat> &image3, float threshold)
00042 {
00043
00044 QList<QPoint> listMax;
00045 float max1, min1, aux; int xmax, ymax;
00046 float max2, min2;
00047 float max3, min3;
00048 float max, min;
00049 QRect image1ROI=image1.getROI();
00050 QRect image2ROI=image2.getROI();
00051 QRect image3ROI=image3.getROI();
00052
00053 int rows=image3.getRows(), cols=image3.getCols();
00054 QVImage<sFloat> imageMax1(cols,rows), imageMax2(cols,rows), imageMax3(cols,rows);
00055 int beginx=image3.getROI().x(), beginy=image3.getROI().y();
00056 int endx=image3.getROI().width()+beginx, endy=image3.getROI().height()+beginy;
00057 imageMax1.setMarginROI(beginx);
00058 imageMax2.setMarginROI(beginx);
00059 imageMax3.setMarginROI(beginx);
00060
00061 image1.setMarginROI(beginx);
00062 imageMax1.setMarginROI(beginx);
00063 FilterMax(image1,imageMax1,3,3,QPoint(beginx+1,beginy+1));
00064 image2.setMarginROI(beginx);
00065 imageMax2.setMarginROI(beginx);
00066 FilterMax(image2,imageMax2,3,3,QPoint(beginx+1,beginy+1));
00067 imageMax3.setMarginROI(beginx);
00068 FilterMax(image3,imageMax3,3,3,QPoint(beginx+1,beginy+1));
00069
00070
00071 image1.setROI(image1ROI);
00072 image2.setROI(image2ROI);
00073 image3.setROI(image3ROI);
00074
00075
00076
00077
00078 QVIMAGE_INIT_READ(sFloat,imageMax1);
00079 QVIMAGE_INIT_WRITE(sFloat,imageMax2)
00080 QVIMAGE_INIT_READ(sFloat,imageMax3);
00081 QVIMAGE_INIT_READ(sFloat,image2);
00082
00083 QMap<sFloat,QPoint> listMap;
00084 sFloat faux, fmaxvalue=-1e30, fminvalue=1e30;
00085 for(int i=beginx; i<endx; ++i)
00086 { for(int j=beginy; j<endy; ++j)
00087 { faux = QVIMAGE_PIXEL(imageMax2,i,j,0);
00088 if ((faux == QVIMAGE_PIXEL(image2,i,j,0)) && (faux > QVIMAGE_PIXEL(imageMax1,i,j,0)) && (faux > QVIMAGE_PIXEL(imageMax3,i,j,0)))
00089 { listMap.insertMulti(faux,QPoint(i,j));
00090 }
00091 }
00092 }
00093 QList<QPoint> valuesList = listMap.values();
00094 QList<QPoint> listFiltered;
00095 int miThreshold = threshold * valuesList.size();
00096 for(int i=valuesList.size()-miThreshold; i<valuesList.size(); ++i)
00097 listFiltered.append(valuesList[i]);
00098 return(listFiltered);
00099 }
00100
00101
00102
00103 float applyDxx(const QVImage<sFloat> &integralImage, int x, int y, int octave, int scale)
00104 {
00105
00106
00107 int w = 5 + 4*octave + scale*(4 << octave);
00108 int h = 3 + 2*octave + scale*(2 << octave);
00109
00110 float a,b,c,d,e,f,g,hh;
00111 QVIMAGE_INIT_READ(sFloat,integralImage);
00112 a = QVIMAGE_PIXEL(integralImage,x-h/2-h, y-w/2,0);
00113 b = QVIMAGE_PIXEL(integralImage,x-h/2, y-w/2,0);
00114 c = QVIMAGE_PIXEL(integralImage,x+h/2+1, y-w/2,0);
00115 d = QVIMAGE_PIXEL(integralImage,x+h+h/2+1, y-w/2,0);
00116 e = QVIMAGE_PIXEL(integralImage,x-h/2-h, y+w/2+1,0);
00117 f = QVIMAGE_PIXEL(integralImage,x-h/2, y+w/2+1,0);
00118 g = QVIMAGE_PIXEL(integralImage,x+h/2+1,y+w/2+1,0);
00119 hh = QVIMAGE_PIXEL(integralImage,x+h/2+h+1,y+w/2+1,0);
00120
00121 return((a+hh-d-e+3*(f+c-b-g))/(w*h));
00122 }
00123
00124 float applyDyy(const QVImage<sFloat> &integralImage, int x, int y, int octave, int scale)
00125 {
00126
00127
00128 int w = 5 + 4*octave + scale*(4 << octave);
00129 int h = 3 + 2*octave + scale*(2 << octave);
00130 float a,b,c,d,e,f,g,hh;
00131 QVIMAGE_INIT_READ(sFloat,integralImage);
00132 a = QVIMAGE_PIXEL(integralImage,x-w/2,y-h-h/2,0);
00133 c = QVIMAGE_PIXEL(integralImage,x-w/2,y-h/2,0);
00134 e = QVIMAGE_PIXEL(integralImage,x-w/2,y+h/2+1,0);
00135 g = QVIMAGE_PIXEL(integralImage,x-w/2,y+h+h/2+1,0);
00136 b = QVIMAGE_PIXEL(integralImage,x+w/2+1,y-h-h/2,0);
00137 d = QVIMAGE_PIXEL(integralImage,x+w/2+1,y-h/2,0);
00138 f = QVIMAGE_PIXEL(integralImage,x+w/2+1,y+h/2+1,0);
00139 hh = QVIMAGE_PIXEL(integralImage,x+w/2+1,y+h+h/2+1,0);
00140
00141 return((a-b+hh-g+3*(d+e-c-f))/(w*h));
00142
00143 }
00144
00145 float applyDxy(const QVImage<sFloat> &integralImage, int x, int y, int octave, int scale)
00146 {
00147
00148
00149 int w = 3 + 2*octave + scale*(2 << octave);
00150 int h = 3 + 2*octave + scale*(2 << octave);
00151 float a,b,c,d,e,f,g,hh,i,j,k,l,m,n,o,p;
00152 QVIMAGE_INIT_READ(sFloat,integralImage);
00153 a = QVIMAGE_PIXEL(integralImage,x-w,y-h,0);
00154 c = QVIMAGE_PIXEL(integralImage,x-w,y,0);
00155 i = QVIMAGE_PIXEL(integralImage,x-w,y+1,0);
00156 k = QVIMAGE_PIXEL(integralImage,x-w,y+h+1,0);
00157 b = QVIMAGE_PIXEL(integralImage,x,y-h,0);
00158 d = QVIMAGE_PIXEL(integralImage,x,y,0);
00159 j = QVIMAGE_PIXEL(integralImage,x,y+1,0);
00160 l = QVIMAGE_PIXEL(integralImage,x,y+h+1,0);
00161 e = QVIMAGE_PIXEL(integralImage,x+1,y-h,0);
00162 g = QVIMAGE_PIXEL(integralImage,x+1,y,0);
00163 m = QVIMAGE_PIXEL(integralImage,x+1,y+1,0);
00164 o = QVIMAGE_PIXEL(integralImage,x+1,y+h+1,0);
00165 f = QVIMAGE_PIXEL(integralImage,x+w+1,y-h,0);
00166 hh = QVIMAGE_PIXEL(integralImage,x+w+1,y,0);
00167 n = QVIMAGE_PIXEL(integralImage,x+w+1,y+1,0);
00168 p = QVIMAGE_PIXEL(integralImage,x+w+1,y+h+1,0);
00169
00170 return(((a+d-b-c)+(m+p-n-o)-(e+hh-f-g)-(i+l-j-k))/(w*h));
00171 }
00172
00173
00174
00175 void detHessian(const QVImage<sFloat> &integral, QVImage<sFloat> &hessian, int octave, int scale)
00176 {
00177 QVIMAGE_INIT_WRITE(sFloat,hessian);
00178 sFloat det;
00179 int cols = integral.getCols(), rows = integral.getRows();
00180 int sizeMask=9 + 6*octave + scale*(6 << octave);
00181 int step= 1 << octave;
00182 int colsHessian = cols/step, rowsHessian = rows/step;
00183 int marginHessian = ((sizeMask)/2)/step+1;
00184 int marginImage = marginHessian*step;
00185 for(int j=marginImage,jh=marginHessian; j<rows-marginImage;j+=step,++jh)
00186 for(int i=marginImage,ih=marginHessian; i<cols-marginImage;i+=step,++ih)
00187 { const float Dxy_apply=applyDxy(integral,i,j,octave,scale);
00188 det = ( applyDxx(integral,i,j,octave,scale)
00189 *
00190 applyDyy(integral,i,j,octave,scale)
00191 -0.81*Dxy_apply*Dxy_apply
00192 );
00193 det = (det < 0.0) ? 0.0 : det;
00194 QVIMAGE_PIXEL(hessian,ih,jh,0) = det;
00195 }
00196 hessian.setMarginROI(marginHessian);
00197 integral.setMarginROI(marginImage);
00198 }
00199
00200
00201 QList<QVPolyline> addBlobs(QList<QVPolyline> listBlobs, QList<QPoint> listPoints, int octave, int scale)
00202 { int radius=4+3*octave+scale*(3<<octave);
00203 int sizeMask=9 + 6*octave + scale*(6 << octave);
00204 int step= 1 << octave;
00205
00206 for(QList<QPoint>::const_iterator i=listPoints.constBegin(); i!=listPoints.constEnd(); ++i)
00207 listBlobs.append(QVPolyline::ellipse(10,i->x()*step,i->y()*step,radius,radius,0));
00208 return(listBlobs);
00209 }
00210
00211 QList<QVPolyline> getBlobs(QVImage<sFloat> &integralFloat, float THRESHOLD)
00212 { int cols=integralFloat.getCols(), rows=integralFloat.getRows();
00213 QVImage<sFloat> approxHessian0[4]={QVImage<sFloat>(cols,rows),QVImage<sFloat>(cols,rows),
00214 QVImage<sFloat>(cols,rows),QVImage<sFloat>(cols,rows)};
00215 QVImage<sFloat> approxHessian1[4]={QVImage<sFloat>(cols/2,rows/2),QVImage<sFloat>(cols/2,rows/2),
00216 QVImage<sFloat>(cols/2,rows/2),QVImage<sFloat>(cols/2,rows/2)};
00217 QVImage<sFloat> approxHessian2[4]={QVImage<sFloat>(cols/4,rows/4),QVImage<sFloat>(cols/4,rows/4),
00218 QVImage<sFloat>(cols/4,rows/4),QVImage<sFloat>(cols/4,rows/4)};
00219 QList<QVPolyline> listBlobs;
00220
00221 int oct=0;
00222 for(int sca=0; sca<4; ++sca)
00223 detHessian(integralFloat,approxHessian0[sca],oct,sca);
00224 listBlobs=addBlobs(listBlobs,MaxIPP(approxHessian0[0],approxHessian0[1],approxHessian0[2], THRESHOLD),oct,1);
00225 listBlobs=addBlobs(listBlobs,MaxIPP(approxHessian0[1],approxHessian0[2],approxHessian0[3], THRESHOLD),oct,2);
00226
00227 oct=1;
00228 Resize(approxHessian0[1], approxHessian1[0],IPPI_INTER_NN);
00229 detHessian(integralFloat,approxHessian1[1],oct,1);
00230 detHessian(integralFloat,approxHessian1[2],oct,2);
00231 detHessian(integralFloat,approxHessian1[3],oct,3);
00232 listBlobs=addBlobs(listBlobs,MaxIPP(approxHessian1[0],approxHessian1[1],approxHessian1[2], THRESHOLD),oct,1);
00233 listBlobs=addBlobs(listBlobs,MaxIPP(approxHessian1[1],approxHessian1[2],approxHessian1[3], THRESHOLD),oct,2);
00234
00235 oct=2;
00236 Resize(approxHessian1[1], approxHessian2[0],IPPI_INTER_NN);
00237 detHessian(integralFloat,approxHessian2[1],oct,1);
00238 detHessian(integralFloat,approxHessian2[2],oct,2);
00239 detHessian(integralFloat,approxHessian2[3],oct,3);
00240 listBlobs=addBlobs(listBlobs,MaxIPP(approxHessian2[0],approxHessian2[1],approxHessian2[2], THRESHOLD),oct,1);
00241 listBlobs=addBlobs(listBlobs,MaxIPP(approxHessian2[1],approxHessian2[2],approxHessian2[3], THRESHOLD),oct,2);
00242
00243
00244 return(listBlobs);
00245 }
00246
00247
00248
00249 class MyWorker: public QVWorker
00250 {
00251 public:
00252 MyWorker(QString name): QVWorker(name)
00253 {
00254 addProperty<double>("Threshold", inputFlag, 1.0, "Threshold",0.01,1.0);
00255 addProperty<bool>("Percentage",inputFlag,true);
00256 addProperty< QVImage<uChar> >("Input image", inputFlag|outputFlag);
00257 addProperty< QVImage<uChar> >("Output image 1", outputFlag);
00258 addProperty< QList<QVPolyline> >("BlobsMax1",outputFlag);
00259 }
00260
00261 void iterate()
00262 {
00263 sFloat THRESHOLD = getPropertyValue<sFloat>("Threshold");
00264 QVImage<uChar> input0 = getPropertyValue< QVImage<uChar> >("Input image");
00265 uInt rows = input0.getRows()*2, cols = input0.getCols()*2;
00266
00267 QVImage<uChar> input(cols, rows);
00268 Resize(input0, input,IPPI_INTER_NN);
00269
00270 timeFlag("double size");
00271
00272 QVImage<sFloat> imageGaussian(cols,rows);
00273 FilterGauss(input,imageGaussian,3);
00274 timeFlag("gaussian");
00275
00276 ++cols; ++rows;
00277 QVImage<sFloat> integralFloat(cols,rows);
00278 Integral(imageGaussian,integralFloat,0);
00279
00280 timeFlag("integral");
00281
00282
00283 QList<QVPolyline> listBlobs1=getBlobs(integralFloat,THRESHOLD);
00284
00285 timeFlag("hessiano");
00286
00287
00288 setPropertyValue< QVImage<uChar> >("Output image 1", imageGaussian);
00289 setPropertyValue< QList<QVPolyline > >("BlobsMax1",listBlobs1);
00290 timeFlag("shows");
00291
00292 }
00293 };
00294
00295 int main(int argc, char *argv[])
00296 { ippSetNumThreads(1);
00297 QVApplication app(argc, argv,
00298 "Example program for QVision library. It is an implementation of the SURF algorithm."
00299 );
00300
00301 QVMPlayerCamera camera1("Video 1");
00302 MyWorker worker("Surf Worker");
00303
00304 camera1.link(&worker,"Input image");
00305
00306 QVDefaultGUI interface;
00307
00308
00309 QVImageCanvas imageCanvas("Output image 1");
00310 imageCanvas.linkProperty(worker,"Output image 1");
00311 imageCanvas.linkProperty(worker,"BlobsMax1", Qt::green);
00312
00313 return app.exec();
00314 }
00315
00316 #endif