fourier_descriptors_demo.cpp 7.2 KB

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