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