1 #include <opencv2/core.hpp>
2 #include <opencv2/core/utility.hpp>
3 #include <opencv2/highgui.hpp>
4 #include <opencv2/imgproc.hpp>
5 #include <opencv2/ximgproc.hpp>
6 #include <iostream>
7 
8 using namespace cv;
9 using namespace std;
10 
11 struct ThParameters {
12     int levelNoise;
13     int angle;
14     int scale10;
15     int origin;
16     int xg;
17     int yg;
18     bool update;
19 } ;
20 
21 static vector<Point> NoisyPolygon(vector<Point> pRef, double n);
22 static void UpdateShape(int , void *r);
23 static void AddSlider(String sliderName, String windowName, int minSlider, int maxSlider, int valDefault, int *valSlider, void(*f)(int, void *), void *r);
24 
main(void)25 int main(void)
26 {
27     vector<Point> ctrRef;
28     vector<Point> ctrRotate, ctrNoisy, ctrNoisyRotate, ctrNoisyRotateShift;
29     // build a shape with 5 vertex
30     ctrRef.push_back(Point(250,250)); ctrRef.push_back(Point(400, 250));
31     ctrRef.push_back(Point(400, 300)); ctrRef.push_back(Point(250, 300));ctrRef.push_back(Point(180, 270));
32     Point cg(0,0);
33     for (int i=0;i<static_cast<int>(ctrRef.size());i++)
34         cg+=ctrRef[i];
35     cg.x /= static_cast<int>(ctrRef.size());
36     cg.y /= static_cast<int>(ctrRef.size());
37     ThParameters p;
38     p.levelNoise=6;
39     p.angle=45;
40     p.scale10=5;
41     p.origin=10;
42     p.xg=150;
43     p.yg=150;
44     p.update=true;
45     namedWindow("FD Curve matching");
46     // A rotation with center at (150,150) of angle 45 degrees and a scaling of 5/10
47     AddSlider("Noise", "FD Curve matching", 0, 20, p.levelNoise, &p.levelNoise, UpdateShape, &p);
48     AddSlider("Angle", "FD Curve matching", 0, 359, p.angle, &p.angle, UpdateShape, &p);
49     AddSlider("Scale", "FD Curve matching", 5, 100, p.scale10, &p.scale10, UpdateShape, &p);
50     AddSlider("Origin%%", "FD Curve matching", 0, 100, p.origin, &p.origin, UpdateShape, &p);
51     AddSlider("Xg", "FD Curve matching", 150, 450, p.xg, &p.xg, UpdateShape, &p);
52     AddSlider("Yg", "FD Curve matching", 150, 450, p.yg, &p.yg, UpdateShape, &p);
53     int code=0;
54     double dist;
55     vector<vector<Point> > c;
56     Mat img;
57     cout << "******************** PRESS g TO MATCH CURVES *************\n";
58     do
59     {
60         code = waitKey(30);
61         if (p.update)
62         {
63             Mat r = getRotationMatrix2D(Point(p.xg, p.yg), p.angle, 10.0/ p.scale10);
64             ctrNoisy= NoisyPolygon(ctrRef,static_cast<double>(p.levelNoise));
65             cv::transform(ctrNoisy, ctrNoisyRotate, r);
66             ctrNoisyRotateShift.clear();
67             for (int i=0;i<static_cast<int>(ctrNoisy.size());i++)
68                 ctrNoisyRotateShift.push_back(ctrNoisyRotate[(i+(p.origin*ctrNoisy.size())/100)% ctrNoisy.size()]);
69             // To draw contour using drawcontours
70             c.clear();
71             c.push_back(ctrRef);
72             c.push_back(ctrNoisyRotateShift);
73             p.update = false;
74             Rect rglobal;
75             for (int i = 0; i < static_cast<int>(c.size()); i++)
76             {
77                 rglobal = boundingRect(c[i]) | rglobal;
78             }
79             rglobal.width += 10;
80             rglobal.height += 10;
81             img = Mat::zeros(2 * rglobal.height, 2 * rglobal.width, CV_8UC(3));
82             drawContours(img, c, 0, Scalar(255,0,0));
83             drawContours(img, c, 1, Scalar(0, 255, 0));
84             circle(img, c[0][0], 5, Scalar(255, 0, 0));
85             circle(img, c[1][0], 5, Scalar(0, 255, 0));
86             imshow("FD Curve matching", img);
87         }
88         if (code == 'd')
89         {
90             destroyWindow("FD Curve matching");
91             namedWindow("FD Curve matching");
92             // A rotation with center at (150,150) of angle 45 degrees and a scaling of 5/10
93             AddSlider("Noise", "FD Curve matching", 0, 20, p.levelNoise, &p.levelNoise, UpdateShape, &p);
94             AddSlider("Angle", "FD Curve matching", 0, 359, p.angle, &p.angle, UpdateShape, &p);
95             AddSlider("Scale", "FD Curve matching", 5, 100, p.scale10, &p.scale10, UpdateShape, &p);
96             AddSlider("Origin%%", "FD Curve matching", 0, 100, p.origin, &p.origin, UpdateShape, &p);
97             AddSlider("Xg", "FD Curve matching", 150, 450, p.xg, &p.xg, UpdateShape, &p);
98             AddSlider("Yg", "FD Curve matching", 150, 450, p.yg, &p.yg, UpdateShape, &p);
99 
100         }
101         if (code == 'g')
102         {
103             ximgproc::ContourFitting fit;
104             vector<Point2f> ctrRef2d, ctrRot2d;
105             // sampling contour we want 256 points
106             ximgproc::contourSampling(ctrRef, ctrRef2d, 256); // use a mat
107             ximgproc::contourSampling(ctrNoisyRotateShift, ctrRot2d, 256); // use a vector of points
108             fit.setFDSize(16);
109             Mat t;
110             fit.estimateTransformation(ctrRot2d, ctrRef2d, t, &dist, false);
111             cout << "Transform *********\n "<<"Origin = "<< 1-t.at<double>(0,0) <<" expected "<< p.origin/100.0 <<" ("<< ctrNoisy.size()<<")\n";
112             cout << "Angle = " << t.at<double>(0, 1) * 180 / M_PI << " expected " << p.angle  <<"\n";
113             cout << "Scale = " << t.at<double>(0, 2) << " expected " << p.scale10 / 10.0 << "\n";
114             Mat dst;
115             ximgproc::transformFD(ctrRot2d, t, dst, false);
116             c.push_back(dst);
117             drawContours(img, c, 2, Scalar(0,255,255));
118             circle(img, c[2][0], 5, Scalar(0, 255, 255));
119             imshow("FD Curve matching", img);
120         }
121     }
122     while (code!=27);
123 
124     return 0;
125 }
126 
NoisyPolygon(vector<Point> pRef,double n)127 vector<Point> NoisyPolygon(vector<Point> pRef, double n)
128 {
129     RNG rng;
130     vector<Point> c;
131     vector<Point> p = pRef;
132     vector<vector<Point> > contour;
133     for (int i = 0; i<static_cast<int>(p.size()); i++)
134         p[i] += Point(Point2d(n*rng.uniform((double)-1, (double)1), n*rng.uniform((double)-1, (double)1)));
135     if (n==0)
136         return p;
137     c.push_back(p[0]);
138     int minX = p[0].x, maxX = p[0].x, minY = p[0].y, maxY = p[0].y;
139     for (int i = 0; i <static_cast<int>(p.size()); i++)
140     {
141         int next = i + 1;
142         if (next == static_cast<int>(p.size()))
143             next = 0;
144         Point2d u = p[next] - p[i];
145         int d = static_cast<int>(norm(u));
146         double a = atan2(u.y, u.x);
147         int step = 1;
148         if (n != 0)
149             step = static_cast<int>(d / n);
150         for (int j = 1; j<d; j += max(step, 1))
151         {
152             Point pNew;
153             do
154             {
155 
156                 Point2d pAct = (u*j) / static_cast<double>(d);
157                 double r = n*rng.uniform((double)0, (double)1);
158                 double theta = a + rng.uniform(0., 2 * CV_PI);
159                 pNew = Point(Point2d(r*cos(theta) + pAct.x + p[i].x, r*sin(theta) + pAct.y + p[i].y));
160             } while (pNew.x<0 || pNew.y<0);
161             if (pNew.x<minX)
162                 minX = pNew.x;
163             if (pNew.x>maxX)
164                 maxX = pNew.x;
165             if (pNew.y<minY)
166                 minY = pNew.y;
167             if (pNew.y>maxY)
168                 maxY = pNew.y;
169             c.push_back(pNew);
170         }
171     }
172     return c;
173 }
174 
UpdateShape(int,void * r)175 void UpdateShape(int , void *r)
176 {
177     ((ThParameters *)r)->update = true;
178 }
179 
AddSlider(String sliderName,String windowName,int minSlider,int maxSlider,int valDefault,int * valSlider,void (* f)(int,void *),void * r)180 void AddSlider(String sliderName, String windowName, int minSlider, int maxSlider, int valDefault, int *valSlider, void(*f)(int, void *), void *r)
181 {
182     createTrackbar(sliderName, windowName, valSlider, 1, f, r);
183     setTrackbarMin(sliderName, windowName, minSlider);
184     setTrackbarMax(sliderName, windowName, maxSlider);
185     setTrackbarPos(sliderName, windowName, valDefault);
186 }
187