1import numpy as np
2import cv2 as cv
3import math
4
5class ThParameters:
6    def __init__(self):
7        self.levelNoise=6
8        self.angle=45
9        self.scale10=5
10        self.origin=10
11        self.xg=150
12        self.yg=150
13        self.update=True
14
15def UpdateShape(x ):
16    p.update = True
17
18def union(a,b):
19  x = min(a[0], b[0])
20  y = min(a[1], b[1])
21  w = max(a[0]+a[2], b[0]+b[2]) - x
22  h = max(a[1]+a[3], b[1]+b[3]) - y
23  return (x, y, w, h)
24
25def intersection(a,b):
26  x = max(a[0], b[0])
27  y = max(a[1], b[1])
28  w = min(a[0]+a[2], b[0]+b[2]) - x
29  h = min(a[1]+a[3], b[1]+b[3]) - y
30  if w<0 or h<0: return () # or (0,0,0,0) ?
31  return (x, y, w, h)
32
33def NoisyPolygon(pRef,n):
34#    vector<Point> c
35    p = pRef;
36#    vector<vector<Point> > contour;
37    p = p+n*np.random.random_sample((p.shape[0],p.shape[1]))-n/2.0
38    if (n==0):
39        return p
40    c = np.empty(shape=[0, 2])
41    minX = p[0][0]
42    maxX = p[0][0]
43    minY = p[0][1]
44    maxY = p[0][1]
45    for i in range( 0,p.shape[0]):
46        next = i + 1;
47        if (next == p.shape[0]):
48            next = 0;
49        u = p[next] - p[i]
50        d = int(cv.norm(u))
51        a = np.arctan2(u[1], u[0])
52        step = 1
53        if (n != 0):
54            step = d // n
55        for j in range( 1,int(d),int(max(step, 1))):
56            while  True:
57                pAct = (u*j) / (d)
58                r = n*np.random.random_sample()
59                theta = a + 2*math.pi*np.random.random_sample()
60#                pNew = Point(Point2d(r*cos(theta) + pAct.x + p[i].x, r*sin(theta) + pAct.y + p[i].y));
61                pNew = np.array([(r*np.cos(theta) + pAct[0] + p[i][0], r*np.sin(theta) + pAct[1] + p[i][1])])
62                if (pNew[0][0]>=0 and pNew[0][1]>=0):
63                    break
64            if (pNew[0][0]<minX):
65                minX = pNew[0][0]
66            if (pNew[0][0]>maxX):
67                maxX = pNew[0][0]
68            if (pNew[0][1]<minY):
69                minY = pNew[0][1]
70            if (pNew[0][1]>maxY):
71                maxY = pNew[0][1]
72            c = np.append(c,pNew,axis = 0)
73    return c
74
75#static vector<Point> NoisyPolygon(vector<Point> pRef, double n);
76#static void UpdateShape(int , void *r);
77#static void AddSlider(String sliderName, String windowName, int minSlider, int maxSlider, int valDefault, int *valSlider, void(*f)(int, void *), void *r);
78def AddSlider(sliderName,windowName,minSlider,maxSlider,valDefault, update):
79    cv.createTrackbar(sliderName, windowName, valDefault,maxSlider-minSlider+1, update)
80    cv.setTrackbarMin(sliderName, windowName, minSlider)
81    cv.setTrackbarMax(sliderName, windowName, maxSlider)
82    cv.setTrackbarPos(sliderName, windowName, valDefault)
83
84#    vector<Point> ctrRef;
85#    vector<Point> ctrRotate, ctrNoisy, ctrNoisyRotate, ctrNoisyRotateShift;
86#    // build a shape with 5 vertex
87ctrRef = np.array([(250,250),(400, 250),(400, 300),(250, 300),(180, 270)])
88cg = np.mean(ctrRef,axis=0)
89p=ThParameters()
90cv.namedWindow("FD Curve matching");
91# A rotation with center at (150,150) of angle 45 degrees and a scaling of 5/10
92AddSlider("Noise", "FD Curve matching", 0, 20, p.levelNoise,  UpdateShape)
93AddSlider("Angle", "FD Curve matching", 0, 359, p.angle,  UpdateShape)
94AddSlider("Scale", "FD Curve matching", 5, 100, p.scale10, UpdateShape)
95AddSlider("Origin", "FD Curve matching", 0, 100, p.origin, UpdateShape)
96AddSlider("Xg", "FD Curve matching", 150, 450, p.xg, UpdateShape)
97AddSlider("Yg", "FD Curve matching", 150, 450, p.yg, UpdateShape)
98code = 0
99img = np.zeros((300,512,3), np.uint8)
100print ("******************** PRESS g TO MATCH CURVES *************\n")
101
102while (code!=27):
103    code = cv.waitKey(60)
104    if p.update:
105        p.levelNoise=cv.getTrackbarPos('Noise','FD Curve matching')
106        p.angle=cv.getTrackbarPos('Angle','FD Curve matching')
107        p.scale10=cv.getTrackbarPos('Scale','FD Curve matching')
108        p.origin=cv.getTrackbarPos('Origin','FD Curve matching')
109        p.xg=cv.getTrackbarPos('Xg','FD Curve matching')
110        p.yg=cv.getTrackbarPos('Yg','FD Curve matching')
111
112        r = cv.getRotationMatrix2D((p.xg, p.yg), angle=p.angle, scale=10.0/ p.scale10);
113        ctrNoisy= NoisyPolygon(ctrRef,p.levelNoise)
114        ctrNoisy1 = np.reshape(ctrNoisy,(ctrNoisy.shape[0],1,2))
115        ctrNoisyRotate = cv.transform(ctrNoisy1,r)
116        ctrNoisyRotateShift = np.empty([ctrNoisyRotate.shape[0],1,2],dtype=np.int32)
117        for  i in range(0,ctrNoisy.shape[0]):
118            k=(i+(p.origin*ctrNoisy.shape[0])//100)% ctrNoisyRotate.shape[0]
119            ctrNoisyRotateShift[i] = ctrNoisyRotate[k]
120#       To draw contour using drawcontours
121        cc= np.reshape(ctrNoisyRotateShift,[ctrNoisyRotateShift.shape[0],2])
122        c = [ ctrRef,cc]
123        p.update = False;
124        rglobal =(0,0,0,0)
125        for i in range(0,2):
126            r = cv.boundingRect(c[i])
127            rglobal = union(rglobal,r)
128        r = list(rglobal)
129        r[2] = r[2]+10
130        r[3] = r[3]+10
131        rglobal = tuple(r)
132        img = np.zeros((2 * rglobal[3], 2 * rglobal[2], 3), np.uint8)
133        cv.drawContours(img, c, 0, (255,0,0),1);
134        cv.drawContours(img, c, 1, (0, 255, 0),1);
135        cv.circle(img, tuple(c[0][0]), 5, (255, 0, 0),3);
136        cv.circle(img, tuple(c[1][0]), 5, (0, 255, 0),3);
137        cv.imshow("FD Curve matching", img);
138    if code == ord('d') :
139        cv.destroyWindow("FD Curve matching");
140        cv.namedWindow("FD Curve matching");
141# A rotation with center at (150,150) of angle 45 degrees and a scaling of 5/10
142        AddSlider("Noise", "FD Curve matching", 0, 20, p.levelNoise,  UpdateShape)
143        AddSlider("Angle", "FD Curve matching", 0, 359, p.angle,  UpdateShape)
144        AddSlider("Scale", "FD Curve matching", 5, 100, p.scale10,  UpdateShape)
145        AddSlider("Origin%%", "FD Curve matching", 0, 100, p.origin, UpdateShape)
146        AddSlider("Xg", "FD Curve matching", 150, 450, p.xg,  UpdateShape)
147        AddSlider("Yg", "FD Curve matching", 150, 450, p.yg,  UpdateShape)
148    if  code == ord('g'):
149        fit = cv.ximgproc.createContourFitting(1024,16);
150# sampling contour we want 256 points
151        cn= np.reshape(ctrRef,[ctrRef.shape[0],1,2])
152
153        ctrRef2d = cv.ximgproc.contourSampling(cn,  256)
154        ctrRot2d = cv.ximgproc.contourSampling(ctrNoisyRotateShift,  256)
155        fit.setFDSize(16)
156        c1 = ctrRef2d
157        c2 = ctrRot2d
158        alphaPhiST, dist	 = fit.estimateTransformation(ctrRot2d, ctrRef2d)
159        print( "Transform *********\n Origin = ", 1-alphaPhiST[0,0] ," expected ", p.origin / 100. ,"\n")
160        print( "Angle = ", alphaPhiST[0,1] * 180 / math.pi ," expected " , p.angle,"\n")
161        print( "Scale = " ,alphaPhiST[0,2] ," expected " , p.scale10 / 10.0 , "\n")
162        dst = cv.ximgproc.transformFD(ctrRot2d, alphaPhiST,cn, False);
163        ctmp= np.reshape(dst,[dst.shape[0],2])
164        cdst=ctmp.astype(int)
165
166        c = [ ctrRef,cc,cdst]
167        cv.drawContours(img, c, 2, (0,0,255),1);
168        cv.circle(img, (int(c[2][0][0]),int(c[2][0][1])), 5, (0, 0, 255),5);
169        cv.imshow("FD Curve matching", img);
170