#include #include #include #include #include #include using namespace cv; using namespace std; struct ThParameters { int levelNoise; int angle; int scale10; int origin; int xg; int yg; bool update; } ; static vector NoisyPolygon(vector 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 ctrRef; vector 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(ctrRef.size());i++) cg+=ctrRef[i]; cg.x /= static_cast(ctrRef.size()); cg.y /= static_cast(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 > 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(p.levelNoise)); cv::transform(ctrNoisy, ctrNoisyRotate, r); ctrNoisyRotateShift.clear(); for (int i=0;i(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(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 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(0,0) <<" expected "<< p.origin/100.0 <<" ("<< ctrNoisy.size()<<")\n"; cout << "Angle = " << t.at(0, 1) * 180 / M_PI << " expected " << p.angle <<"\n"; cout << "Scale = " << t.at(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 NoisyPolygon(vector pRef, double n) { RNG rng; vector c; vector p = pRef; vector > contour; for (int i = 0; i(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 (p.size()); i++) { int next = i + 1; if (next == static_cast(p.size())) next = 0; Point2d u = p[next] - p[i]; int d = static_cast(norm(u)); double a = atan2(u.y, u.x); int step = 1; if (n != 0) step = static_cast(d / n); for (int j = 1; j(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.xmaxX) maxX = pNew.x; if (pNew.ymaxY) 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); }