123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186 |
- #include <opencv2/core.hpp>
- #include <opencv2/core/utility.hpp>
- #include <opencv2/highgui.hpp>
- #include <opencv2/imgproc.hpp>
- #include <opencv2/ximgproc.hpp>
- #include <iostream>
- using namespace cv;
- using namespace std;
- struct ThParameters {
- int levelNoise;
- int angle;
- int scale10;
- int origin;
- int xg;
- int yg;
- bool update;
- } ;
- static vector<Point> NoisyPolygon(vector<Point> pRef, double n);
- static void UpdateShape(int , void *r);
- static void AddSlider(String sliderName, String windowName, int minSlider, int maxSlider, int valDefault, int *valSlider, void(*f)(int, void *), void *r);
- int main(void)
- {
- vector<Point> ctrRef;
- vector<Point> ctrRotate, ctrNoisy, ctrNoisyRotate, ctrNoisyRotateShift;
- // build a shape with 5 vertex
- ctrRef.push_back(Point(250,250)); ctrRef.push_back(Point(400, 250));
- ctrRef.push_back(Point(400, 300)); ctrRef.push_back(Point(250, 300));ctrRef.push_back(Point(180, 270));
- Point cg(0,0);
- for (int i=0;i<static_cast<int>(ctrRef.size());i++)
- cg+=ctrRef[i];
- cg.x /= static_cast<int>(ctrRef.size());
- cg.y /= static_cast<int>(ctrRef.size());
- ThParameters p;
- p.levelNoise=6;
- p.angle=45;
- p.scale10=5;
- p.origin=10;
- p.xg=150;
- p.yg=150;
- p.update=true;
- namedWindow("FD Curve matching");
- // A rotation with center at (150,150) of angle 45 degrees and a scaling of 5/10
- AddSlider("Noise", "FD Curve matching", 0, 20, p.levelNoise, &p.levelNoise, UpdateShape, &p);
- AddSlider("Angle", "FD Curve matching", 0, 359, p.angle, &p.angle, UpdateShape, &p);
- AddSlider("Scale", "FD Curve matching", 5, 100, p.scale10, &p.scale10, UpdateShape, &p);
- AddSlider("Origin%%", "FD Curve matching", 0, 100, p.origin, &p.origin, UpdateShape, &p);
- AddSlider("Xg", "FD Curve matching", 150, 450, p.xg, &p.xg, UpdateShape, &p);
- AddSlider("Yg", "FD Curve matching", 150, 450, p.yg, &p.yg, UpdateShape, &p);
- int code=0;
- double dist;
- vector<vector<Point> > c;
- Mat img;
- cout << "******************** PRESS g TO MATCH CURVES *************\n";
- do
- {
- code = waitKey(30);
- if (p.update)
- {
- Mat r = getRotationMatrix2D(Point(p.xg, p.yg), p.angle, 10.0/ p.scale10);
- ctrNoisy= NoisyPolygon(ctrRef,static_cast<double>(p.levelNoise));
- cv::transform(ctrNoisy, ctrNoisyRotate, r);
- ctrNoisyRotateShift.clear();
- for (int i=0;i<static_cast<int>(ctrNoisy.size());i++)
- ctrNoisyRotateShift.push_back(ctrNoisyRotate[(i+(p.origin*ctrNoisy.size())/100)% ctrNoisy.size()]);
- // To draw contour using drawcontours
- c.clear();
- c.push_back(ctrRef);
- c.push_back(ctrNoisyRotateShift);
- p.update = false;
- Rect rglobal;
- for (int i = 0; i < static_cast<int>(c.size()); i++)
- {
- rglobal = boundingRect(c[i]) | rglobal;
- }
- rglobal.width += 10;
- rglobal.height += 10;
- img = Mat::zeros(2 * rglobal.height, 2 * rglobal.width, CV_8UC(3));
- drawContours(img, c, 0, Scalar(255,0,0));
- drawContours(img, c, 1, Scalar(0, 255, 0));
- circle(img, c[0][0], 5, Scalar(255, 0, 0));
- circle(img, c[1][0], 5, Scalar(0, 255, 0));
- imshow("FD Curve matching", img);
- }
- if (code == 'd')
- {
- destroyWindow("FD Curve matching");
- namedWindow("FD Curve matching");
- // A rotation with center at (150,150) of angle 45 degrees and a scaling of 5/10
- AddSlider("Noise", "FD Curve matching", 0, 20, p.levelNoise, &p.levelNoise, UpdateShape, &p);
- AddSlider("Angle", "FD Curve matching", 0, 359, p.angle, &p.angle, UpdateShape, &p);
- AddSlider("Scale", "FD Curve matching", 5, 100, p.scale10, &p.scale10, UpdateShape, &p);
- AddSlider("Origin%%", "FD Curve matching", 0, 100, p.origin, &p.origin, UpdateShape, &p);
- AddSlider("Xg", "FD Curve matching", 150, 450, p.xg, &p.xg, UpdateShape, &p);
- AddSlider("Yg", "FD Curve matching", 150, 450, p.yg, &p.yg, UpdateShape, &p);
- }
- if (code == 'g')
- {
- ximgproc::ContourFitting fit;
- vector<Point2f> ctrRef2d, ctrRot2d;
- // sampling contour we want 256 points
- ximgproc::contourSampling(ctrRef, ctrRef2d, 256); // use a mat
- ximgproc::contourSampling(ctrNoisyRotateShift, ctrRot2d, 256); // use a vector of points
- fit.setFDSize(16);
- Mat t;
- fit.estimateTransformation(ctrRot2d, ctrRef2d, t, &dist, false);
- cout << "Transform *********\n "<<"Origin = "<< 1-t.at<double>(0,0) <<" expected "<< p.origin/100.0 <<" ("<< ctrNoisy.size()<<")\n";
- cout << "Angle = " << t.at<double>(0, 1) * 180 / M_PI << " expected " << p.angle <<"\n";
- cout << "Scale = " << t.at<double>(0, 2) << " expected " << p.scale10 / 10.0 << "\n";
- Mat dst;
- ximgproc::transformFD(ctrRot2d, t, dst, false);
- c.push_back(dst);
- drawContours(img, c, 2, Scalar(0,255,255));
- circle(img, c[2][0], 5, Scalar(0, 255, 255));
- imshow("FD Curve matching", img);
- }
- }
- while (code!=27);
- return 0;
- }
- vector<Point> NoisyPolygon(vector<Point> pRef, double n)
- {
- RNG rng;
- vector<Point> c;
- vector<Point> p = pRef;
- vector<vector<Point> > contour;
- for (int i = 0; i<static_cast<int>(p.size()); i++)
- p[i] += Point(Point2d(n*rng.uniform((double)-1, (double)1), n*rng.uniform((double)-1, (double)1)));
- if (n==0)
- return p;
- c.push_back(p[0]);
- int minX = p[0].x, maxX = p[0].x, minY = p[0].y, maxY = p[0].y;
- for (int i = 0; i <static_cast<int>(p.size()); i++)
- {
- int next = i + 1;
- if (next == static_cast<int>(p.size()))
- next = 0;
- Point2d u = p[next] - p[i];
- int d = static_cast<int>(norm(u));
- double a = atan2(u.y, u.x);
- int step = 1;
- if (n != 0)
- step = static_cast<int>(d / n);
- for (int j = 1; j<d; j += max(step, 1))
- {
- Point pNew;
- do
- {
- Point2d pAct = (u*j) / static_cast<double>(d);
- double r = n*rng.uniform((double)0, (double)1);
- double theta = a + rng.uniform(0., 2 * CV_PI);
- pNew = Point(Point2d(r*cos(theta) + pAct.x + p[i].x, r*sin(theta) + pAct.y + p[i].y));
- } while (pNew.x<0 || pNew.y<0);
- if (pNew.x<minX)
- minX = pNew.x;
- if (pNew.x>maxX)
- maxX = pNew.x;
- if (pNew.y<minY)
- minY = pNew.y;
- if (pNew.y>maxY)
- maxY = pNew.y;
- c.push_back(pNew);
- }
- }
- return c;
- }
- void UpdateShape(int , void *r)
- {
- ((ThParameters *)r)->update = true;
- }
- void AddSlider(String sliderName, String windowName, int minSlider, int maxSlider, int valDefault, int *valSlider, void(*f)(int, void *), void *r)
- {
- createTrackbar(sliderName, windowName, valSlider, 1, f, r);
- setTrackbarMin(sliderName, windowName, minSlider);
- setTrackbarMax(sliderName, windowName, maxSlider);
- setTrackbarPos(sliderName, windowName, valDefault);
- }
|