1 #include <opencv2/opencv.hpp>
2 #include "opencv2/core/opengl.hpp"
3 #include "opencv2/cvconfig.h"
4 
5 #include <vector>
6 #include <map>
7 #include <iostream>
8 #ifdef HAVE_OPENGL
9 #ifdef WIN32
10 #define WIN32_LEAN_AND_MEAN 1
11 #define NOMINMAX 1
12 #include <windows.h>
13 #endif
14 #if defined(_WIN64)
15 #include <windows.h>
16 #endif
17 
18 #if defined(__APPLE__)
19 #include <OpenGL/gl.h>
20 #include <OpenGL/glu.h>
21 #else
22 #include <GL/gl.h>
23 #include <GL/glu.h>
24 #endif
25 #endif
26 
27 
28 using namespace std;
29 using namespace cv;
30 
31 
help()32 static void help()
33 {
34     cout << "\n This program demonstrates how to use MSER to detect extremal regions \n"
35         "Usage: \n"
36         "  ./detect_mser <image1(without parameter a syntehtic image is used as default)>\n"
37         "Press esc key when image window is active to change  descriptor parameter\n"
38         "Press 2, 8, 4, 6, +,- or 5 keys in openGL windows to change view or use mouse\n";
39 }
40 
41 struct MSERParams
42 {
MSERParamsMSERParams43     MSERParams(int _delta = 5, int _min_area = 60, int _max_area = 14400,
44     double _max_variation = 0.25, double _min_diversity = .2,
45     int _max_evolution = 200, double _area_threshold = 1.01,
46     double _min_margin = 0.003, int _edge_blur_size = 5)
47         {
48         delta = _delta;
49         minArea = _min_area;
50         maxArea = _max_area;
51         maxVariation = _max_variation;
52         minDiversity = _min_diversity;
53         maxEvolution = _max_evolution;
54         areaThreshold = _area_threshold;
55         minMargin = _min_margin;
56         edgeBlurSize = _edge_blur_size;
57         pass2Only = false;
58         }
59 
60     int delta;
61     int minArea;
62     int maxArea;
63     double maxVariation;
64     double minDiversity;
65     bool pass2Only;
66 
67     int maxEvolution;
68     double areaThreshold;
69     double minMargin;
70     int edgeBlurSize;
71 };
72 
Legende(MSERParams & pAct)73 static String Legende(MSERParams &pAct)
74 {
75     String s="";
76     String inf = static_cast<ostringstream*>(&(ostringstream() << pAct.minArea))->str();
77     String sup = static_cast<ostringstream*>(&(ostringstream() << pAct.maxArea))->str();
78     s = " Area[" + inf + "," + sup + "]";
79 
80     inf = static_cast<ostringstream*>(&(ostringstream() << pAct.delta))->str();
81     s += " del. [" + inf + "]";
82     inf = static_cast<ostringstream*>(&(ostringstream() << pAct.maxVariation))->str();
83     s += " var. [" + inf + "]";
84     inf = static_cast<ostringstream*>(&(ostringstream() << (int)pAct.minDiversity))->str();
85     s += " div. [" + inf + "]";
86     inf = static_cast<ostringstream*>(&(ostringstream() << (int)pAct.pass2Only))->str();
87     s += " pas. [" + inf + "]";
88     inf = static_cast<ostringstream*>(&(ostringstream() << (int)pAct.maxEvolution))->str();
89     s += "RGb-> evo. [" + inf + "]";
90     inf = static_cast<ostringstream*>(&(ostringstream() << (int)pAct.areaThreshold))->str();
91     s += " are. [" + inf + "]";
92     inf = static_cast<ostringstream*>(&(ostringstream() << (int)pAct.minMargin))->str();
93     s += " mar. [" + inf + "]";
94     inf = static_cast<ostringstream*>(&(ostringstream() << (int)pAct.edgeBlurSize))->str();
95     s += " siz. [" + inf + "]";
96     return s;
97 }
98 
99 
100 const int win_width = 800;
101 const int win_height = 640;
102 bool    rotateEnable=true;
103 bool    keyPressed=false;
104 
105 Vec4f   rotAxis(1,0,1,0);
106 Vec3f  zoom(1,0,0);
107 
108 float	obsX = (float)0, obsY = (float)0, obsZ = (float)-10, tx = (float)0, ty = (float)0;
109 float	thetaObs = (float)-1.570, phiObs = (float)1.570, rObs = (float)10;
110 int prevX=-1,prevY=-1,prevTheta=-1000,prevPhi=-1000;
111 
112 #ifdef HAVE_OPENGL
113 struct DrawData
114 
115     {
116     ogl::Arrays arr;
117     ogl::Texture2D tex;
118     ogl::Buffer indices;
119     };
120 
121 
draw(void * userdata)122 static void draw(void* userdata)
123 {
124     DrawData* data = static_cast<DrawData*>(userdata);
125     glMatrixMode(GL_MODELVIEW);
126     glLoadIdentity();
127     gluLookAt(obsX, obsY, obsZ, 0, 0, .0, .0, 10.0, 0.0);
128     glTranslatef(tx,ty,0);
129     keyPressed = false;
130     ogl::render(data->arr, data->indices, ogl::TRIANGLES);
131 }
132 
onMouse(int event,int x,int y,int flags,void *)133 static void onMouse(int event, int x, int y, int flags, void*)
134 {
135     if (event == EVENT_RBUTTONDOWN)
136     {
137         prevX = x;
138         prevY = y;
139     }
140     if (event == EVENT_RBUTTONUP)
141     {
142         prevX = -1;
143         prevY = -1;
144     }
145     if (prevX != -1)
146     {
147         tx += float((x - prevX) / 100.0);
148         ty -= float((y - prevY) / 100.0);
149         prevX = x;
150         prevY = y;
151     }
152     if (event == EVENT_LBUTTONDOWN)
153     {
154         prevTheta = x;
155         prevPhi = y;
156     }
157     if (event == EVENT_LBUTTONUP)
158     {
159         prevTheta = -1000;
160         prevPhi = -1000;
161     }
162     if (prevTheta != -1000)
163     {
164         if (x - prevTheta<0)
165         {
166             thetaObs +=(float)0.02;
167         }
168         else if (x - prevTheta>0)
169         {
170             thetaObs -= (float)0.02;
171         }
172         if (y - prevPhi<0)
173         {
174             phiObs -= (float)0.02;
175         }
176         else if (y - prevPhi>0)
177         {
178             phiObs += (float)0.02;
179         }
180         prevTheta = x;
181         prevPhi = y;
182     }
183     if (event==EVENT_MOUSEWHEEL)
184     {
185         if (getMouseWheelDelta(flags)>0)
186             rObs += (float)0.1;
187         else
188             rObs -= (float)0.1;
189     }
190     float pi = (float)acos(-1.0);
191     if (thetaObs>pi)
192     {
193         thetaObs = -2 * pi + thetaObs;
194     }
195     if (thetaObs<-pi)
196     {
197         thetaObs = 2 * pi + thetaObs;
198     }
199     if (phiObs>pi / 2)
200     {
201         phiObs = pi / 2 - (float)0.0001;
202     }
203     if (phiObs<-pi / 2)
204     {
205         phiObs = -pi / 2 + (float)0.00001;
206     }
207     if (rObs<0)
208     {
209         rObs = 0;
210     }
211 
212 }
213 #endif
214 
215 #ifdef HAVE_OPENGL
DrawOpenGLMSER(Mat img,Mat result)216 static void DrawOpenGLMSER(Mat img, Mat result)
217 {
218     Mat imgGray;
219     if (img.type() != CV_8UC1)
220         cvtColor(img, imgGray, COLOR_BGR2GRAY);
221     else
222         imgGray = img;
223     namedWindow("OpenGL", WINDOW_OPENGL);
224     setMouseCallback("OpenGL", onMouse, NULL);
225 
226     Mat_<Vec3f> vertex(1, img.cols*img.rows);
227     Mat_<Vec2f> texCoords(1, img.cols*img.rows);
228     for (int i = 0, nbPix = 0; i<img.rows; i++)
229         {
230         for (int j = 0; j<img.cols; j++, nbPix++)
231             {
232             float x = (j) / (float)img.cols;
233             float y = (i) / (float)img.rows;
234             vertex.at< Vec3f >(0, nbPix) = Vec3f(float(2 * (x - 0.5)), float(2 * (0.5 - y)), float(imgGray.at<uchar>(i, j) / 512.0));
235             texCoords.at< Vec2f>(0, nbPix) = Vec2f(x, y);
236             }
237         }
238 
239     Mat_<int> indices(1, (img.rows - 1)*(6 * img.cols));
240     for (int i = 1, nbPix = 0; i<img.rows; i++)
241         {
242         for (int j = 1; j<img.cols; j++)
243             {
244             int c = i*img.cols + j;
245             indices.at<int>(0, nbPix++) = c ;
246             indices.at<int>(0, nbPix++) = c - 1;
247             indices.at<int>(0, nbPix++) = c- img.cols - 1;
248             indices.at<int>(0, nbPix++) = c- img.cols - 1;
249             indices.at<int>(0, nbPix++) = c - img.cols;
250             indices.at<int>(0, nbPix++) = c ;
251             }
252         }
253 
254     DrawData *data = new DrawData;
255 
256     data->arr.setVertexArray(vertex);
257     data->arr.setTexCoordArray(texCoords);
258     data->indices.copyFrom(indices);
259     data->tex.copyFrom(result);
260 
261     glMatrixMode(GL_PROJECTION);
262     glLoadIdentity();
263     gluPerspective(45.0, (double)win_width / win_height, 0.0, 1000.0);
264 
265     glMatrixMode(GL_MODELVIEW);
266     glLoadIdentity();
267 
268     glEnable(GL_TEXTURE_2D);
269     data->tex.bind();
270 
271     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
272     glTexEnvi(GL_TEXTURE_2D, GL_TEXTURE_ENV_MODE, GL_REPLACE);
273 
274     glDisable(GL_CULL_FACE);
275     setOpenGlDrawCallback("OpenGL", draw, data);
276 
277     for (;;)
278         {
279         updateWindow("OpenGL");
280         int key = waitKey(40);
281         if ((key & 0xff) == 27)
282             break;
283         if (key == 0x20)
284             rotateEnable = !rotateEnable;
285         float	pi = (float)acos(-1);
286 
287         switch (key) {
288             case '5':
289                 obsX = 0, obsY = 0, obsZ = -10;
290                 thetaObs = -pi/2, phiObs = pi/2, rObs = 10;
291                 tx=0;ty=0;
292                 break;
293             case '4':
294                 thetaObs += (float)0.1;
295                 break;
296             case '6':
297                 thetaObs -= (float)0.1;
298                 break;
299             case '2':
300                 phiObs -= (float).1;
301                 break;
302             case '8':
303                 phiObs += (float).1;
304                 break;
305             case '+':
306                 rObs -= (float).1;
307                 break;
308             case '-':
309                 rObs += (float).1;
310                 break;
311         }
312         if (thetaObs>pi)
313         {
314             thetaObs = -2 * pi + thetaObs;
315         }
316         if (thetaObs<-pi)
317             thetaObs = 2 * pi + thetaObs;
318         if (phiObs>pi / 2)
319             phiObs = pi / 2 - (float)0.0001;
320         if (phiObs<-pi / 2)
321             phiObs = -pi / 2 + (float)0.00001;
322         if (rObs<0)
323             rObs = 0;
324         obsX = rObs*cos(thetaObs)*cos(phiObs);
325         obsY = rObs*sin(thetaObs)*cos(phiObs);
326         obsZ = rObs*sin(phiObs);
327     }
328     setOpenGlDrawCallback("OpenGL", 0, 0);
329     destroyAllWindows();
330 }
331 #endif
332 
MakeSyntheticImage()333 static Mat MakeSyntheticImage()
334 {
335     Mat img(800, 800, CV_8UC1);
336     map<int, char> val;
337     int fond = 0;
338     img = Scalar(fond);
339     val[fond] = 1;
340     int width1[] = { 390, 380, 300, 290, 280, 270, 260, 250, 210, 190, 150, 100, 80, 70 };
341     int color1[] = { 80, 180, 160, 140, 120, 100, 90, 110, 170, 150, 140, 100, 220 };
342     Point p0(10, 10);
343     int *width, *color;
344 
345     width = width1;
346     color = color1;
347     for (int i = 0; i<13; i++)
348         {
349         rectangle(img, Rect(p0, Size(width[i], width[i])), Scalar(color[i]), 1);
350         p0 += Point((width[i] - width[i + 1]) / 2, (width[i] - width[i + 1]) / 2);
351         floodFill(img, p0, Scalar(color[i]));
352 
353         }
354     int color2[] = { 81, 181, 161, 141, 121, 101, 91, 111, 171, 151, 141, 101, 221 };
355     color = color2;
356     p0 = Point(200, 600);
357     for (int i = 0; i<13; i++)
358         {
359         circle(img, p0, width[i] / 2, Scalar(color[i]), 1);
360         floodFill(img, p0, Scalar(color[i]));
361 
362         }
363     int color3[] = { 175,75,95,115,135,155,165,145,85,105,115,156 };
364     color = color3;
365     p0 = Point(410, 10);
366     for (int i = 0; i<13; i++)
367         {
368         rectangle(img, Rect(p0, Size(width[i], width[i])), Scalar(color[i]), 1);
369         p0 += Point((width[i] - width[i + 1]) / 2, (width[i] - width[i + 1]) / 2);
370         floodFill(img, p0, Scalar(color[i]));
371 
372         }
373     int color4[] = { 173,73,93,113,133,153,163,143,83,103,114,154 };
374     color = color4;
375 
376     p0 = Point(600, 600);
377     for (int i = 0; i<13; i++)
378     {
379         circle(img, p0, width[i] / 2, Scalar(color[i]), 1);
380         floodFill(img, p0, Scalar(color[i]));
381     }
382     int histSize = 256;
383     float range[] = { 0, 256 };
384     const float* histRange[] = { range };
385     Mat hist;
386     // we compute the histogram
387     calcHist(&img, 1, 0, Mat(), hist, 1, &histSize, histRange, true, false);
388     cout << "****************Maximal region************************\n";
389     for (int i = 0; i < hist.rows ; i++)
390     {
391         if (hist.at<float>(i, 0)!=0)
392         {
393             cout << "h" << i << "=\t" << hist.at<float>(i, 0) <<  "\n";
394         }
395     }
396 
397     return img;
398 }
399 
main(int argc,char * argv[])400 int main(int argc, char *argv[])
401 {
402     vector<String> fileName;
403     Mat imgOrig,img;
404     Size blurSize(5,5);
405     if (argc==2)
406     {
407         fileName.push_back(argv[1]);
408         imgOrig = imread(fileName[0], IMREAD_GRAYSCALE);    blur(imgOrig, img, blurSize);
409 
410     }
411     else
412     {
413         fileName.push_back("SyntheticImage.bmp");
414         imgOrig = MakeSyntheticImage();
415         img=imgOrig;
416     }
417 
418     MSERParams pDefaultMSER;
419     // Descriptor array MSER
420     vector<String> typeDesc;
421     // Param array for MSER
422     vector<MSERParams> pMSER;
423     vector<MSERParams>::iterator itMSER;
424 
425     // Color palette
426     vector<Vec3b>  palette;
427     for (int i = 0; i<65536; i++)
428         palette.push_back(Vec3b((uchar)rand(), (uchar)rand(), (uchar)rand()));
429     help();
430 
431     typeDesc.push_back("MSER");
432     pMSER.push_back(pDefaultMSER);
433     pMSER.back().delta = 10;
434     pMSER.back().minArea = 100;
435     pMSER.back().maxArea = 5000;
436     pMSER.back().maxVariation = 2;
437     pMSER.back().minDiversity = 0;
438     pMSER.back().pass2Only = true;
439     typeDesc.push_back("MSER");
440     pMSER.push_back(pDefaultMSER);
441     pMSER.back().delta = 10;
442     pMSER.back().minArea = 100;
443     pMSER.back().maxArea = 5000;
444     pMSER.back().maxVariation = 2;
445     pMSER.back().minDiversity = 0;
446     pMSER.back().pass2Only = false;
447     typeDesc.push_back("MSER");
448     pMSER.push_back(pDefaultMSER);
449     pMSER.back().delta = 100;
450     pMSER.back().minArea = 100;
451     pMSER.back().maxArea = 5000;
452     pMSER.back().maxVariation = 2;
453     pMSER.back().minDiversity = 0;
454     pMSER.back().pass2Only = false;
455     itMSER = pMSER.begin();
456     vector<double> desMethCmp;
457     Ptr<Feature2D> b;
458     String label;
459     // Descriptor loop
460     vector<String>::iterator itDesc;
461     Mat result(img.rows, img.cols, CV_8UC3);
462     for (itDesc = typeDesc.begin(); itDesc != typeDesc.end(); itDesc++)
463     {
464         vector<KeyPoint> keyImg1;
465         if (*itDesc == "MSER"){
466             if (img.type() == CV_8UC3)
467             {
468                 b = MSER::create(itMSER->delta, itMSER->minArea, itMSER->maxArea, itMSER->maxVariation, itMSER->minDiversity, itMSER->maxEvolution,
469                                  itMSER->areaThreshold, itMSER->minMargin, itMSER->edgeBlurSize);
470                 label = Legende(*itMSER);
471                 itMSER++;
472 
473             }
474             else
475             {
476                 b = MSER::create(itMSER->delta, itMSER->minArea, itMSER->maxArea, itMSER->maxVariation, itMSER->minDiversity);
477                 b.dynamicCast<MSER>()->setPass2Only(itMSER->pass2Only);
478                 label = Legende(*itMSER);
479                 itMSER++;
480             }
481         }
482         if (img.type()==CV_8UC3)
483         {
484             img.copyTo(result);
485         }
486         else
487         {
488             vector<Mat> plan;
489             plan.push_back(img);
490             plan.push_back(img);
491             plan.push_back(img);
492             merge(plan,result);
493         }
494         try
495         {
496             // We can detect regions using detectRegions method
497             vector<KeyPoint>  keyImg;
498             vector<Rect>  zone;
499             vector<vector <Point> >  region;
500             Mat     desc;
501 
502             if (b.dynamicCast<MSER>() != NULL)
503             {
504                 Ptr<MSER> sbd = b.dynamicCast<MSER>();
505                 sbd->detectRegions(img, region, zone);
506                 int i = 0;
507                 //result = Scalar(0, 0, 0);
508                 int nbPixelInMSER=0;
509                 for (vector<vector <Point> >::iterator itr = region.begin(); itr != region.end(); itr++, i++)
510                 {
511                     for (vector <Point>::iterator itp = region[i].begin(); itp != region[i].end(); itp ++)
512                     {
513                         // all pixels belonging to region become blue
514                         result.at<Vec3b>(itp->y, itp->x) = Vec3b(128, 0, 0);
515                         nbPixelInMSER++;
516                     }
517                 }
518                 cout << "Number of MSER region " << region.size()<<" Number of pixels in all MSER region : "<<nbPixelInMSER<<"\n";
519             }
520             namedWindow(*itDesc + label, WINDOW_AUTOSIZE);
521             imshow(*itDesc + label, result);
522             imshow("Original", img);
523         }
524         catch (Exception& e)
525         {
526             cout << "Feature : " << *itDesc << "\n";
527             cout << e.msg << endl;
528         }
529 #ifdef HAVE_OPENGL
530         DrawOpenGLMSER(img, result);
531 #endif
532         waitKey();
533     }
534     return 0;
535 }
536