diff options
Diffstat (limited to 'SD-VBS/common/toolbox/lagrcv/lagrcv.cpp')
-rwxr-xr-x | SD-VBS/common/toolbox/lagrcv/lagrcv.cpp | 840 |
1 files changed, 840 insertions, 0 deletions
diff --git a/SD-VBS/common/toolbox/lagrcv/lagrcv.cpp b/SD-VBS/common/toolbox/lagrcv/lagrcv.cpp new file mode 100755 index 0000000..4f24b5d --- /dev/null +++ b/SD-VBS/common/toolbox/lagrcv/lagrcv.cpp | |||
@@ -0,0 +1,840 @@ | |||
1 | #include "lagrcv.h" | ||
2 | /* | ||
3 | void calcImagePyr(char *src, int sizeY, int sizeX, int level, char *pyr){ | ||
4 | pyr=(char*) malloc(sizeof(char)*(int)sizeY*sizeX*4/3); | ||
5 | int i, startPnt, nX, nY; | ||
6 | |||
7 | memcpy(pyr,src, sizeY*sizeX); | ||
8 | nY=sizeY; | ||
9 | nX=sizeX; | ||
10 | for(i=0; i<level; i++){ | ||
11 | nY = (nY + 1) >> 1; | ||
12 | nX = (nX + 1) >> 1; | ||
13 | calcSubsample(pyr, sizeY, sizeX, pyr+sizeY*sizeX) | ||
14 | } | ||
15 | free(pyr); | ||
16 | } | ||
17 | */ | ||
18 | |||
19 | void calcSubSampleAvg(double *src, int sizeY, int sizeX, double *dest, int destSizeY, int destSizeX){ | ||
20 | int i, j, idx, | ||
21 | destI, destJ, idxDest; | ||
22 | for(i=0, destI=0; destI<destSizeX; i+=2, destI++){ | ||
23 | for(j=0, destJ=0; destJ<destSizeY; j+=2, destJ++){ | ||
24 | idx=i*sizeX+j; | ||
25 | idxDest=destI*destSizeY+destJ; | ||
26 | dest[idxDest]=(src[idx]+src[idx+1]+src[idx+sizeY]+src[idx+sizeY+1])/4; | ||
27 | } | ||
28 | } | ||
29 | } | ||
30 | void calcImgBlur(double *src, int sizeY, int sizeX, double *dest){ | ||
31 | double kernel[]={0.0625, 0.25, 0.375, 0.25, 0.0625}; | ||
32 | double *temp; | ||
33 | temp=(double*) malloc(sizeof(double)*sizeY*sizeX); | ||
34 | int i, j, idx, idxCol; | ||
35 | for(i=2; i<sizeX-2;i++){ | ||
36 | idxCol=i*sizeY; | ||
37 | for(j=0;j<sizeY; j++){ | ||
38 | idx=idxCol+j; | ||
39 | temp[idx]=src[idx-2*sizeY]/16+src[idx-sizeY]/4 | ||
40 | +src[idx]*3/8+src[idx+sizeY]/4+src[idx+2*sizeY]/16; | ||
41 | } | ||
42 | } | ||
43 | for(i=0; i<sizeX;i++){ | ||
44 | idxCol=i*sizeY; | ||
45 | for(j=2;j<sizeY-2; j++){ | ||
46 | idx=idxCol+j; | ||
47 | dest[idx]=temp[idx-2]/16+temp[idx-1]/4 | ||
48 | +temp[idx]*3/8+temp[idx+1]/4+temp[idx+2]/16; | ||
49 | } | ||
50 | } | ||
51 | free(temp); | ||
52 | } | ||
53 | void calcImgResize(double *src, int sizeY, int sizeX, double *dest, int dstSizeY, int dstSizeX){ | ||
54 | double ker[]={ 0.0039, 0.0156, 0.0234, 0.0156, 0.0039, | ||
55 | 0.0156, 0.0625, 0.0938, 0.0625, 0.0156, | ||
56 | 0.0234, 0.0938, 0.1406, 0.0938, 0.0234, | ||
57 | 0.0156, 0.0625, 0.0938, 0.0625, 0.0156, | ||
58 | 0.0039, 0.0156, 0.0234, 0.0156, 0.0039}; | ||
59 | int srcI, srcJ, dstI, dstJ, srcIdx, dstIdx, idxCol_1, idxCol1, idxCol_2, idxCol2; | ||
60 | for(srcI=2, dstI=1; srcI<sizeX-2; srcI+=2, dstI++){ | ||
61 | for(srcJ=2, dstJ=1; srcJ<sizeY-2; srcJ+=2, dstJ++){ | ||
62 | srcIdx=srcI*sizeY+srcJ; | ||
63 | dstIdx=dstI*dstSizeY+dstJ; | ||
64 | idxCol_1=srcIdx-sizeY; | ||
65 | idxCol_2=srcIdx-2*sizeY; | ||
66 | idxCol1=srcIdx+sizeY; | ||
67 | idxCol2=srcIdx+2*sizeY; | ||
68 | dest[dstIdx]= | ||
69 | src[idxCol_2-2]*ker[0]+src[idxCol_1-2]*ker[1] | ||
70 | +src[srcIdx-2]*ker[2]+src[idxCol1-2]*ker[3]+src[idxCol2-2]*ker[4] | ||
71 | +src[idxCol_2-1]*ker[5]+src[idxCol_1-1]*ker[6] | ||
72 | +src[srcIdx-1]*ker[7]+src[idxCol1-1]*ker[8]+src[idxCol2-1]*ker[9] | ||
73 | +src[idxCol_2]*ker[10]+src[idxCol_1]*ker[11] | ||
74 | +src[srcIdx]*ker[12]+src[idxCol1]*ker[13]+src[idxCol2]*ker[14] | ||
75 | +src[idxCol_2+1]*ker[5]+src[idxCol_1+1]*ker[16] | ||
76 | +src[srcIdx+1]*ker[17]+src[idxCol1+1]*ker[18]+src[idxCol2+1]*ker[19]; | ||
77 | +src[idxCol_2+2]*ker[20]+src[idxCol_1+2]*ker[21] | ||
78 | +src[srcIdx+2]*ker[22]+src[idxCol1+2]*ker[23]+src[idxCol2+2]*ker[24]; | ||
79 | } | ||
80 | } | ||
81 | } | ||
82 | |||
83 | void calcGradient(double *src, int sizeY, int sizeX, double *dX, double *dY){ | ||
84 | int i, j, idx; | ||
85 | for(i=1; i<sizeX; i++){ | ||
86 | for(j=1; j<sizeY; j++){ | ||
87 | idx=i*sizeY+j; | ||
88 | dX[idx]=src[idx]-src[idx-sizeY]; | ||
89 | dY[idx]=src[idx]-src[idx-1]; | ||
90 | } | ||
91 | } | ||
92 | } | ||
93 | void calcGradient(char *src, int sizeY, int sizeX, char *dX, char *dY){ | ||
94 | int i, j, idx; | ||
95 | for(i=1; i<sizeX; i++){ | ||
96 | for(j=1; j<sizeY; j++){ | ||
97 | idx=i*sizeY+j; | ||
98 | dX[idx]=src[idx]-src[idx-sizeY]; | ||
99 | dY[idx]=src[idx]-src[idx-1]; | ||
100 | } | ||
101 | } | ||
102 | } | ||
103 | void calcSobel(double *src, int sizeY, int sizeX, double *dX, double *dY){ | ||
104 | //char kernelV[9]={-1, -2, -1, 0, 0, 0, 1, 2, 1}; | ||
105 | //char kernelH[9]={-1, 0, 1, -2, 0, 2, -1, 0, 1}; | ||
106 | //const int kerSize=3; | ||
107 | int i, j, idx, idxPrevCol, idxNextCol; | ||
108 | for(i=1; i<sizeX-1; i++){ | ||
109 | for(j=1; j<sizeY-1; j++){ | ||
110 | idx=i*sizeY+j; | ||
111 | idxPrevCol=idx-sizeY; | ||
112 | idxNextCol=idx+sizeY; | ||
113 | dX[idx]=src[idxPrevCol-1]*-0.0938f+src[idxPrevCol]*-0.3125f+src[idxPrevCol+1]*-0.0938f | ||
114 | +src[idxNextCol-1]*0.0938f+src[idxNextCol]*0.3125f+src[idxNextCol+1]*0.0938f; | ||
115 | dY[idx]=src[idxPrevCol-1]*-0.0938f+src[idx-1]*-0.3125f+src[idxNextCol-1]*-0.0938f | ||
116 | +src[idxPrevCol+1]*0.0938f+src[idx+1]*0.3125f+src[idxNextCol+1]*0.0938f; | ||
117 | /* | ||
118 | dX[idx]=(src[idxPrevCol-1]*-1+src[idxPrevCol]*-2+src[idxPrevCol+1]*-1 | ||
119 | +src[idxNextCol-1]*1+src[idxNextCol]*2+src[idxNextCol+1]*1)*0.0625; | ||
120 | dY[idx]=(src[idxPrevCol-1]*-1+src[idx-1]*-2+src[idxNextCol-1]*-1 | ||
121 | +src[idxPrevCol+1]*1+src[idx+1]*2+src[idxNextCol+1]*1)*0.0625; | ||
122 | */ | ||
123 | } | ||
124 | } | ||
125 | } | ||
126 | |||
127 | void calcGoodFeature(double *dX, double *dY, int sizeY, int sizeX, int winSize, double* lambda, double* tr, double* det, | ||
128 | double* c_xx, double* c_xy, double* c_yy){ | ||
129 | double *xx, *xy, *yy; | ||
130 | int i,j,idx; | ||
131 | xx=(double*)malloc(sizeof(double)*sizeY*sizeX); | ||
132 | xy=(double*)malloc(sizeof(double)*sizeY*sizeX); | ||
133 | yy=(double*)malloc(sizeof(double)*sizeY*sizeX); | ||
134 | for(idx=0; idx<sizeX*sizeY; idx++){ | ||
135 | xx[idx]=dX[idx]*dX[idx]; | ||
136 | xy[idx]=dX[idx]*dY[idx]; | ||
137 | yy[idx]=dY[idx]*dY[idx]; | ||
138 | } | ||
139 | calcAreaSum(xx, sizeY, sizeX, winSize, c_xx); | ||
140 | calcAreaSum(xy, sizeY, sizeX, winSize, c_xy); | ||
141 | calcAreaSum(yy, sizeY, sizeX, winSize, c_yy); | ||
142 | for(idx=0; idx<sizeX*sizeY; idx++){ | ||
143 | tr[idx]=c_xx[idx]+c_yy[idx]; | ||
144 | det[idx]=c_xx[idx]*c_yy[idx]-c_xy[idx]*c_xy[idx]; | ||
145 | lambda[idx]=det[idx]/(tr[idx] + 0.00001); | ||
146 | } | ||
147 | free(xx); | ||
148 | free(xy); | ||
149 | free(yy); | ||
150 | } | ||
151 | void calcGoodFeature(char *dX, char *dY, int sizeY, int sizeX, int winSize, float* lambda, float* tr, float* det){ | ||
152 | int *xx, *xy, *yy; | ||
153 | int *c_xx, *c_xy, *c_yy; | ||
154 | int i,j,idx; | ||
155 | xx=(int*)malloc(sizeof(int)*sizeY*sizeX); | ||
156 | xy=(int*)malloc(sizeof(int)*sizeY*sizeX); | ||
157 | yy=(int*)malloc(sizeof(int)*sizeY*sizeX); | ||
158 | c_xx=(int*)malloc(sizeof(int)*sizeY*sizeX); | ||
159 | c_xy=(int*)malloc(sizeof(int)*sizeY*sizeX); | ||
160 | c_yy=(int*)malloc(sizeof(int)*sizeY*sizeX); | ||
161 | for(i=0; i<sizeX; i++){ | ||
162 | for(j=0; j<sizeY; j++){ | ||
163 | idx=i*sizeY+j; | ||
164 | xx[idx]=dX[idx]*dX[idx]; | ||
165 | xy[idx]=dX[idx]*dY[idx]; | ||
166 | yy[idx]=dY[idx]*dY[idx]; | ||
167 | } | ||
168 | } | ||
169 | calcAreaSum(xx, sizeY, sizeX, winSize, c_xx); | ||
170 | calcAreaSum(xy, sizeY, sizeX, winSize, c_xy); | ||
171 | calcAreaSum(yy, sizeY, sizeX, winSize, c_yy); | ||
172 | for(i=0; i<sizeX; i++){ | ||
173 | for(j=0; j<sizeY; j++){ | ||
174 | idx=i*sizeY+j; | ||
175 | tr[idx]=c_xx[idx]+c_yy[idx]; | ||
176 | det[idx]=c_xx[idx]*c_yy[idx]-c_xy[idx]*c_xy[idx]; | ||
177 | lambda[i*sizeY+j]=det[idx]/(tr[idx] + 0.00001); | ||
178 | } | ||
179 | } | ||
180 | } | ||
181 | void calcMinEigenValue(char *dX, char *dY, int sizeY, int sizeX, float* lambda){ | ||
182 | int xx, xy, yy; | ||
183 | int tr; | ||
184 | int i,j; | ||
185 | for(i=0; i<sizeX; i++){ | ||
186 | for(j=0; j<sizeY; j++){ | ||
187 | xx=dX[i*sizeY+j]*dX[i*sizeY+j]; | ||
188 | xy=dX[i*sizeY+j]*dY[i*sizeY+j]; | ||
189 | yy=dY[i*sizeY+j]*dY[i*sizeY+j]; | ||
190 | tr=xx+yy; | ||
191 | lambda[i*sizeY+j]=(float)(tr-pow((xx-yy)*(xx-yy)+4*xy*xy,0.5))/2; | ||
192 | } | ||
193 | } | ||
194 | } | ||
195 | |||
196 | void calcAreaSum(double *src, int sizeY, int sizeX, int winSize, double *ret){ | ||
197 | /**/ | ||
198 | const int MAX_COLS = 1024; | ||
199 | double *a_array[MAX_COLS], *b_array[MAX_COLS]; | ||
200 | double a1[MAX_COLS], a1sum; | ||
201 | |||
202 | int nave = winSize; | ||
203 | int nave_half = (int)floor((nave+1)/2)-1; | ||
204 | |||
205 | double *a_ptr = src; | ||
206 | |||
207 | int nx = sizeY; | ||
208 | int ny = sizeX; | ||
209 | |||
210 | double *b_ptr = ret; | ||
211 | |||
212 | // Construct array pointers | ||
213 | for (int iy = 0; iy < ny; iy++) { | ||
214 | a_array[iy] = a_ptr + iy*nx; | ||
215 | b_array[iy] = b_ptr + iy*nx; | ||
216 | } | ||
217 | |||
218 | // Initialize a1 array | ||
219 | for (int i = 0; i < nx+nave; i++) | ||
220 | a1[i] = 0.0; | ||
221 | // Sum over cols: | ||
222 | for (int iy = 0; iy < ny; iy++) { | ||
223 | // Copy col into temp array: | ||
224 | for (int ix = 0; ix < nx; ix++) | ||
225 | a1[ix+nave_half] = a_array[iy][ix]; | ||
226 | |||
227 | a1sum = 0.0; | ||
228 | for (int i = 0; i < nave; i++) | ||
229 | a1sum += a1[i]; | ||
230 | |||
231 | for (int ix = 0; ix < nx; ix++) { | ||
232 | b_array[iy][ix] = a1sum; | ||
233 | a1sum += a1[ix+nave]-a1[ix]; | ||
234 | } | ||
235 | } | ||
236 | // Re-initialize a1 array | ||
237 | for (int i = 0; i < ny+nave; i++) | ||
238 | a1[i] = 0.0; | ||
239 | // Sum over rows: | ||
240 | for (int ix = 0; ix < nx; ix++) { | ||
241 | // Copy row into temp array: | ||
242 | for (int iy = 0; iy < ny; iy++) | ||
243 | a1[iy+nave_half] = b_array[iy][ix]; | ||
244 | |||
245 | a1sum = 0.0; | ||
246 | for (int i = 0; i < nave; i++) | ||
247 | a1sum += a1[i]; | ||
248 | |||
249 | for (int iy = 0; iy < ny; iy++) { | ||
250 | b_array[iy][ix] = a1sum; | ||
251 | a1sum += a1[iy+nave]-a1[iy]; | ||
252 | } | ||
253 | } | ||
254 | /**/ | ||
255 | // 8n^2+2n | ||
256 | /* | ||
257 | // 10n^2 | ||
258 | int idx, idxCol, idx_1, idx_win, idx_Y, idx_win_Y; | ||
259 | double* sum=(double*)malloc(sizeof(double)*sizeX*sizeY); | ||
260 | //sum up along Y | ||
261 | for(idx=idxCol=0; idx<(sizeX*sizeY); idxCol=idx){ | ||
262 | sum[idx]=src[idx]; | ||
263 | idx++; | ||
264 | for(idx_1=idx-1;idx<(idxCol+winSize);idx++, | ||
265 | idx_1++){ | ||
266 | sum[idx]=sum[idx_1]+src[idx]; | ||
267 | } | ||
268 | for(idx_win=idx-winSize;idx<(idxCol+sizeY);idx++, | ||
269 | idx_1++, | ||
270 | idx_win++){ | ||
271 | sum[idx]=sum[idx_1]+src[idx]-src[idx_win]; | ||
272 | } | ||
273 | } | ||
274 | //sum up along X | ||
275 | for(idx=0;idx<sizeY;idx++){ | ||
276 | ret[idx]=sum[idx]; | ||
277 | } | ||
278 | for(idx_Y=idx-sizeY;idx<(winSize*sizeY);idx++, | ||
279 | idx_Y++){ | ||
280 | ret[idx]+=sum[idx]+ret[idx_Y]; | ||
281 | } | ||
282 | for(idx_win_Y=idx-winSize*sizeY;idx<(sizeX*sizeY); idx++, | ||
283 | idx_win_Y++, | ||
284 | idx_Y++){ | ||
285 | ret[idx]+=sum[idx]+ret[idx_Y]-sum[idx_win_Y]; | ||
286 | } | ||
287 | free(sum); | ||
288 | /**/ | ||
289 | /* | ||
290 | // 8n^2+2n | ||
291 | int i,j; | ||
292 | int idx,idxCol; | ||
293 | int idxDelta[4]; | ||
294 | double* sum=(double*)malloc(sizeof(double)*sizeX*sizeY); | ||
295 | int halfSize=(int)winSize/2; | ||
296 | ret[0]=src[0]; | ||
297 | for(i=1; i<sizeY; i++){ | ||
298 | sum[i]=src[i]+sum[i-1]; | ||
299 | } | ||
300 | for(i=1; i<sizeX; i++){ | ||
301 | idx=i*sizeY; | ||
302 | sum[idx]=src[idx]+sum[idx-sizeY]; | ||
303 | } | ||
304 | for(i=1; i<sizeX; i++){ | ||
305 | for(j=1; j<sizeY; j++){ | ||
306 | idx=i*sizeY+j; | ||
307 | sum[idx]=src[idx] | ||
308 | + sum[idx-1] | ||
309 | + sum[idx-sizeY] | ||
310 | - sum[idx-sizeY-1]; | ||
311 | } | ||
312 | } | ||
313 | idxDelta[0]=halfSize*sizeY+halfSize; | ||
314 | idxDelta[1]=-halfSize*sizeY+halfSize; | ||
315 | idxDelta[2]=halfSize*sizeY-halfSize; | ||
316 | idxDelta[3]=-halfSize*sizeY-halfSize; | ||
317 | for(i=halfSize; i<sizeX-halfSize; i++){ | ||
318 | for(j=halfSize; j<sizeY-halfSize; j++){ | ||
319 | idx=i*sizeY+j; | ||
320 | ret[i*sizeY+j]=sum[idx+idxDelta[0]]-sum[idx+idxDelta[1]]-sum[idx+idxDelta[2]]+sum[idx+idxDelta[3]]; | ||
321 | } | ||
322 | } | ||
323 | free(sum); | ||
324 | /**/ | ||
325 | } | ||
326 | void calcAreaSum(int *src, int sizeY, int sizeX, int sizeSum, int *ret){ | ||
327 | // 8n^2+2n | ||
328 | int i,j; | ||
329 | int idx,idxCol; | ||
330 | int idxDelta[4]; | ||
331 | int *sum; | ||
332 | sum=(int*)malloc(sizeof(int)*sizeY*sizeX); | ||
333 | int halfSize=(int)sizeSum/2; | ||
334 | ret[0]=src[0]; | ||
335 | for(i=1; i<sizeY; i++){ | ||
336 | sum[i]=src[i]+sum[i-1]; | ||
337 | } | ||
338 | for(i=0; i<sizeX; i++){ | ||
339 | idx=i*sizeY; | ||
340 | sum[idx]=src[idx]+sum[idx-sizeY]; | ||
341 | } | ||
342 | for(i=1; i<sizeX; i++){ | ||
343 | for(j=1; j<sizeY; j++){ | ||
344 | idx=i*sizeY+j; | ||
345 | sum[idx]=src[idx] | ||
346 | + sum[idx-1] | ||
347 | + sum[idx-sizeY] | ||
348 | - sum[idx-sizeY-1]; | ||
349 | } | ||
350 | } | ||
351 | /* | ||
352 | for(i=0; i<sizeX; i++){ | ||
353 | for(j=0; j<sizeY; j++){ | ||
354 | idx=i*sizeY+j; | ||
355 | sum[idx]=src[idx] | ||
356 | + ((j>0)?sum[idx-1]:0) | ||
357 | + ((i>0)?sum[idx-sizeY]:0) | ||
358 | - ((i>0&&j>0)?sum[idx-sizeY-1]:0); | ||
359 | } | ||
360 | } | ||
361 | */ | ||
362 | idxDelta[0]=halfSize*sizeY+halfSize; | ||
363 | idxDelta[1]=-halfSize*sizeY+halfSize; | ||
364 | idxDelta[2]=halfSize*sizeY-halfSize; | ||
365 | idxDelta[3]=-halfSize*sizeY-halfSize; | ||
366 | for(i=halfSize; i<sizeX-halfSize; i++){ | ||
367 | for(j=halfSize; j<sizeY-halfSize; j++){ | ||
368 | idx=i*sizeY+j; | ||
369 | ret[i*sizeY+j]=sum[idx+idxDelta[0]]-sum[idx+idxDelta[1]]-sum[idx+idxDelta[2]]+sum[idx+idxDelta[3]]; | ||
370 | } | ||
371 | } | ||
372 | |||
373 | free(sum); | ||
374 | } | ||
375 | |||
376 | |||
377 | void getInterpolatePatch(double* srcImg, int* srcDims, double centerX, double centerY, int winSize, double* dstImg){ | ||
378 | double a, b, a11, a12, a21, a22, b1, b2; | ||
379 | int srcIdxX, srcIdx; | ||
380 | int dstIdxX, dstIdx; | ||
381 | a=centerX-(double)((int)centerX); | ||
382 | b=centerY-(double)((int)centerY); | ||
383 | a11=(1.f-a)*(1.f-b); | ||
384 | a12=a*(1.f-b); | ||
385 | a21=(1.f-a)*b; | ||
386 | a22=a*b; | ||
387 | b1=1.f-b; | ||
388 | b2=b; | ||
389 | |||
390 | for(int i=-winSize; i<winSize; i++){ | ||
391 | srcIdxX=(int)centerX+i; | ||
392 | dstIdxX=i+winSize; | ||
393 | for(int j=-winSize; j<winSize; j++){ | ||
394 | srcIdx=(int)srcIdxX*srcDims[0]+(int)centerY+j; | ||
395 | dstIdx=dstIdxX*2*winSize+j+winSize; | ||
396 | dstImg[dstIdx]=srcImg[srcIdx]*a11 | ||
397 | +srcImg[srcIdx+1]*a12 | ||
398 | +srcImg[srcIdx+srcDims[0]]*a21 | ||
399 | +srcImg[srcIdx+srcDims[0]+1]*a22; | ||
400 | } | ||
401 | } | ||
402 | } | ||
403 | void calcPyrLKTrack(double** iP, double** iDxP, double** iDyP, double** jP, const int* imgDims, int pLevel, | ||
404 | double* fPnt, int nFeatures, int winSize, | ||
405 | double* newFPnt, char* valid){ | ||
406 | calcPyrLKTrack( iP, iDxP, iDyP, jP, imgDims, pLevel, | ||
407 | fPnt, nFeatures, winSize, | ||
408 | newFPnt, valid, LK_ACCURACY_TH, LK_MAX_ITER); | ||
409 | } | ||
410 | void calcPyrLKTrackWInit(double** iP, double** jP, const int* imgDims, int pLevel, | ||
411 | double* fPnt, int nFeatures, int winSize, | ||
412 | double* newFPnt, double* initFPnt, | ||
413 | char* valid, double accuracy_th, int max_iter){ | ||
414 | |||
415 | double x, y, eX, eY, dX, dY, mX, mY, prevMX, prevMY, c_xx, c_xy, c_yy, c_det, dIt; | ||
416 | double* iPatch, *jPatch, *iDxPatch, *iDyPatch; | ||
417 | int level, winSizeSq, winSizeSqWBorder; | ||
418 | int i, k, idx; | ||
419 | int imgSize[2]; | ||
420 | |||
421 | static const double rate[]={1, 0.5, 0.25, 0.125, 0.0625, 0.03125}; | ||
422 | winSizeSq=4*winSize*winSize; | ||
423 | winSizeSqWBorder=4*(winSize+1)*(winSize+1); | ||
424 | |||
425 | iPatch=(double*) malloc(sizeof(double)*winSizeSqWBorder); | ||
426 | jPatch=(double*) malloc(sizeof(double)*winSizeSq); | ||
427 | iDxPatch=(double*) malloc(sizeof(double)*winSizeSqWBorder); | ||
428 | iDyPatch=(double*) malloc(sizeof(double)*winSizeSqWBorder); | ||
429 | |||
430 | for(i=0; i<nFeatures; i++){ | ||
431 | dX=(initFPnt[i*2+0]-fPnt[i*2+0])*rate[pLevel]; | ||
432 | dY=(initFPnt[i*2+1]-fPnt[i*2+1])*rate[pLevel]; | ||
433 | x=fPnt[i*2+0]*rate[pLevel];//half size of real level | ||
434 | y=fPnt[i*2+1]*rate[pLevel]; | ||
435 | for(level=pLevel-1; level>=0; level--){ | ||
436 | x+=x; y+=y; dX+=dX; dY+=dY; | ||
437 | imgSize[0]=imgDims[level*2+0]; //y,x | ||
438 | imgSize[1]=imgDims[level*2+1]; //y,x | ||
439 | |||
440 | c_xx=c_xy=c_yy=0; | ||
441 | //when feature goes out to the boundary. | ||
442 | if((x-winSize-1)<0 || (y-winSize-1)<0 | ||
443 | || (y+winSize+1+1)>=imgSize[0] || (x+winSize+1+1)>=imgSize[1]){ | ||
444 | //winSize+1due to interpolation | ||
445 | //error or skip the level?? | ||
446 | valid[i]=0; | ||
447 | break; | ||
448 | } | ||
449 | |||
450 | getInterpolatePatch(iP[level], imgSize, x, y, winSize+1, iPatch); //to calculate iDx, iDy | ||
451 | calcSobel(iPatch, (winSize+1)*2, (winSize+1)*2, iDxPatch, iDyPatch); | ||
452 | for(k=0; k <(winSize*2); k++ ){ | ||
453 | memcpy( iPatch + k*winSize*2, iPatch + (k+1)*(winSize+1)*2 + 1, winSize*2 ); | ||
454 | memcpy( iDxPatch + k*winSize*2, iDxPatch + (k+1)*(winSize+1)*2 + 1, winSize*2 ); | ||
455 | memcpy( iDyPatch + k*winSize*2, iDyPatch + (k+1)*(winSize+1)*2 + 1, winSize*2 ); | ||
456 | } | ||
457 | |||
458 | for(idx=0; idx<winSizeSq;idx++){ | ||
459 | c_xx+=iDxPatch[idx]*iDxPatch[idx]; | ||
460 | c_xy+=iDxPatch[idx]*iDyPatch[idx]; | ||
461 | c_yy+=iDyPatch[idx]*iDyPatch[idx]; | ||
462 | } | ||
463 | c_det=c_xx*c_yy-c_xy*c_xy; | ||
464 | if(c_det/(c_xx+c_yy+0.00000001)<GOOD_FEATURE_LAMBDA_TH){ | ||
465 | //just skip? | ||
466 | valid[i]=0; | ||
467 | break; | ||
468 | } | ||
469 | c_det=1/c_det; | ||
470 | for(k=0; k<max_iter; k++){ | ||
471 | if((x+dX-winSize)<0 || (y+dY-winSize)<0 | ||
472 | || (y+dY+winSize+1)>=imgSize[0] || (x+dX+winSize+1)>=imgSize[1]){ | ||
473 | //winSize+1due to interpolation | ||
474 | //error or skip the level?? | ||
475 | valid[i]=0; | ||
476 | break; | ||
477 | } | ||
478 | getInterpolatePatch(jP[level], imgSize, x+dX, y+dY, winSize, jPatch); | ||
479 | eX=eY=0; | ||
480 | for(idx=0;idx<winSizeSq;idx++){ | ||
481 | dIt=iPatch[idx]-jPatch[idx]; | ||
482 | eX+=dIt*iDxPatch[idx]; | ||
483 | eY+=dIt*iDyPatch[idx]; | ||
484 | } | ||
485 | mX=c_det*(eX*c_yy-eY*c_xy); | ||
486 | mY=c_det*(-eX*c_xy+eY*c_xx); | ||
487 | dX+=mX; | ||
488 | dY+=mY; | ||
489 | if((mX*mX+mY*mY)<accuracy_th) break; | ||
490 | if( k>0 && (mX + prevMX) < 0.01 && (mX+prevMX) > -0.01 | ||
491 | && (mY + prevMY) < 0.01 && (mY+prevMY) > -0.01) | ||
492 | { | ||
493 | dX -= mX*0.5f; | ||
494 | dY -= mY*0.5f; | ||
495 | break; | ||
496 | } | ||
497 | prevMX=mX; | ||
498 | prevMY=mY; | ||
499 | } | ||
500 | if(k==max_iter){ | ||
501 | valid[i]=0; | ||
502 | } | ||
503 | } | ||
504 | newFPnt[i*2+0]=fPnt[i*2+0]+dX; | ||
505 | newFPnt[i*2+1]=fPnt[i*2+1]+dY; | ||
506 | /* | ||
507 | if(valid[i] | ||
508 | || (x+dX-winSize)<0 || (y+dY-winSize)<0 | ||
509 | || (y+dY+winSize+1)>=imgSize[0] || (x+dX+winSize+1)>=imgSize[1]){ | ||
510 | newFPnt[i*2+0]=fPnt[i*2+0]+dX; | ||
511 | newFPnt[i*2+1]=fPnt[i*2+1]+dY; | ||
512 | getInterpolatePatch(jP[0], imgSize, newFPnt[i*2+0], newFPnt[i*2+0], winSize, jPatch); | ||
513 | dIt=0; | ||
514 | for(idx=0;idx<winSizeSq;idx++){ | ||
515 | dIt+=(iPatch[idx]-jPatch[idx])*(iPatch[idx]-jPatch[idx]); | ||
516 | } | ||
517 | if(dIt>winSizeSq*50000){ | ||
518 | valid[i]=0; | ||
519 | } | ||
520 | }else{ | ||
521 | newFPnt[i*2+0]=0; | ||
522 | newFPnt[i*2+1]=0; | ||
523 | } | ||
524 | */ | ||
525 | } | ||
526 | free(iPatch); | ||
527 | free(jPatch); | ||
528 | free(iDxPatch); | ||
529 | free(iDyPatch); | ||
530 | } | ||
531 | void calcPyrLKTrackWInit(double** iP, double** iDxP, double** iDyP, double** jP, const int* imgDims, int pLevel, | ||
532 | double* fPnt, int nFeatures, int winSize, | ||
533 | double* newFPnt, double* initFPnt, | ||
534 | char* valid, double accuracy_th, int max_iter){ | ||
535 | |||
536 | double x, y, eX, eY, dX, dY, mX, mY, prevMX, prevMY, c_xx, c_xy, c_yy, c_det, dIt; | ||
537 | double* iPatch, *jPatch, *iDxPatch, *iDyPatch; | ||
538 | int level, winSizeSq; | ||
539 | int i, k, idx; | ||
540 | int imgSize[2]; | ||
541 | |||
542 | static const double rate[]={1, 0.5, 0.25, 0.125, 0.0625, 0.03125}; | ||
543 | winSizeSq=4*winSize*winSize; | ||
544 | |||
545 | iPatch=(double*) malloc(sizeof(double)*winSizeSq); | ||
546 | jPatch=(double*) malloc(sizeof(double)*winSizeSq); | ||
547 | iDxPatch=(double*) malloc(sizeof(double)*winSizeSq); | ||
548 | iDyPatch=(double*) malloc(sizeof(double)*winSizeSq); | ||
549 | |||
550 | for(i=0; i<nFeatures; i++){ | ||
551 | dX=(initFPnt[i*2+0]-fPnt[i*2+0])*rate[pLevel]; | ||
552 | dY=(initFPnt[i*2+1]-fPnt[i*2+1])*rate[pLevel]; | ||
553 | x=fPnt[i*2+0]*rate[pLevel];//half size of real level | ||
554 | y=fPnt[i*2+1]*rate[pLevel]; | ||
555 | for(level=pLevel-1; level>=0; level--){ | ||
556 | x+=x; y+=y; dX+=dX; dY+=dY; | ||
557 | imgSize[0]=imgDims[level*2+0]; //y,x | ||
558 | imgSize[1]=imgDims[level*2+1]; //y,x | ||
559 | |||
560 | c_xx=c_xy=c_yy=0; | ||
561 | //when feature goes out to the boundary. | ||
562 | if((x-winSize)<0 || (y-winSize)<0 | ||
563 | || (y+winSize+1)>=imgSize[0] || (x+winSize+1)>=imgSize[1]){ | ||
564 | //winSize+1due to interpolation | ||
565 | //error or skip the level?? | ||
566 | valid[i]=0; | ||
567 | break; | ||
568 | } | ||
569 | |||
570 | getInterpolatePatch(iP[level], imgSize, x, y, winSize, iPatch); | ||
571 | getInterpolatePatch(iDxP[level], imgSize, x, y, winSize, iDxPatch); | ||
572 | getInterpolatePatch(iDyP[level], imgSize, x, y, winSize, iDyPatch); | ||
573 | |||
574 | for(idx=0; idx<winSizeSq;idx++){ | ||
575 | c_xx+=iDxPatch[idx]*iDxPatch[idx]; | ||
576 | c_xy+=iDxPatch[idx]*iDyPatch[idx]; | ||
577 | c_yy+=iDyPatch[idx]*iDyPatch[idx]; | ||
578 | } | ||
579 | c_det=c_xx*c_yy-c_xy*c_xy; | ||
580 | if(c_det/(c_xx+c_yy+0.00000001)<GOOD_FEATURE_LAMBDA_TH){ | ||
581 | //just skip? | ||
582 | valid[i]=0; | ||
583 | break; | ||
584 | } | ||
585 | c_det=1/c_det; | ||
586 | for(k=0; k<max_iter; k++){ | ||
587 | if((x+dX-winSize)<0 || (y+dY-winSize)<0 | ||
588 | || (y+dY+winSize+1)>=imgSize[0] || (x+dX+winSize+1)>=imgSize[1]){ | ||
589 | //winSize+1due to interpolation | ||
590 | //error or skip the level?? | ||
591 | valid[i]=0; | ||
592 | break; | ||
593 | } | ||
594 | getInterpolatePatch(jP[level], imgSize, x+dX, y+dY, winSize, jPatch); | ||
595 | eX=eY=0; | ||
596 | for(idx=0;idx<winSizeSq;idx++){ | ||
597 | dIt=iPatch[idx]-jPatch[idx]; | ||
598 | eX+=dIt*iDxPatch[idx]; | ||
599 | eY+=dIt*iDyPatch[idx]; | ||
600 | } | ||
601 | mX=c_det*(eX*c_yy-eY*c_xy); | ||
602 | mY=c_det*(-eX*c_xy+eY*c_xx); | ||
603 | dX+=mX; | ||
604 | dY+=mY; | ||
605 | if((mX*mX+mY*mY)<accuracy_th) break; | ||
606 | if( k>0 && (mX + prevMX) < 0.01 && (mX+prevMX) > -0.01 | ||
607 | && (mY + prevMY) < 0.01 && (mY+prevMY) > -0.01) | ||
608 | { | ||
609 | dX -= mX*0.5f; | ||
610 | dY -= mY*0.5f; | ||
611 | break; | ||
612 | } | ||
613 | prevMX=mX; | ||
614 | prevMY=mY; | ||
615 | } | ||
616 | if(k==max_iter){ | ||
617 | valid[i]=0; | ||
618 | } | ||
619 | } | ||
620 | newFPnt[i*2+0]=fPnt[i*2+0]+dX; | ||
621 | newFPnt[i*2+1]=fPnt[i*2+1]+dY; | ||
622 | /* | ||
623 | if(valid[i] | ||
624 | || (x+dX-winSize)<0 || (y+dY-winSize)<0 | ||
625 | || (y+dY+winSize+1)>=imgSize[0] || (x+dX+winSize+1)>=imgSize[1]){ | ||
626 | newFPnt[i*2+0]=fPnt[i*2+0]+dX; | ||
627 | newFPnt[i*2+1]=fPnt[i*2+1]+dY; | ||
628 | getInterpolatePatch(jP[0], imgSize, newFPnt[i*2+0], newFPnt[i*2+0], winSize, jPatch); | ||
629 | dIt=0; | ||
630 | for(idx=0;idx<winSizeSq;idx++){ | ||
631 | dIt+=(iPatch[idx]-jPatch[idx])*(iPatch[idx]-jPatch[idx]); | ||
632 | } | ||
633 | if(dIt>winSizeSq*50000){ | ||
634 | valid[i]=0; | ||
635 | } | ||
636 | }else{ | ||
637 | newFPnt[i*2+0]=0; | ||
638 | newFPnt[i*2+1]=0; | ||
639 | } | ||
640 | */ | ||
641 | } | ||
642 | free(iPatch); | ||
643 | free(jPatch); | ||
644 | free(iDxPatch); | ||
645 | free(iDyPatch); | ||
646 | } | ||
647 | void calcPyrLKTrack(double** iP, double** iDxP, double** iDyP, double** jP, const int* imgDims, int pLevel, | ||
648 | double* fPnt, int nFeatures, int winSize, | ||
649 | double* newFPnt, char* valid, double accuracy_th, int max_iter){ | ||
650 | |||
651 | double x, y, eX, eY, dX, dY, mX, mY, c_xx, c_xy, c_yy, c_det, dIt; | ||
652 | double* iPatch, *jPatch, *iDxPatch, *iDyPatch; | ||
653 | int level, winSizeSq; | ||
654 | int i, k, idx; | ||
655 | int imgSize[2]; | ||
656 | |||
657 | static const double rate[]={1, 0.5, 0.25, 0.125, 0.0625, 0.03125}; | ||
658 | winSizeSq=4*winSize*winSize; | ||
659 | |||
660 | iPatch=(double*) malloc(sizeof(double)*winSizeSq); | ||
661 | jPatch=(double*) malloc(sizeof(double)*winSizeSq); | ||
662 | iDxPatch=(double*) malloc(sizeof(double)*winSizeSq); | ||
663 | iDyPatch=(double*) malloc(sizeof(double)*winSizeSq); | ||
664 | |||
665 | for(i=0; i<nFeatures; i++){ | ||
666 | dX=0; | ||
667 | dY=0; | ||
668 | x=fPnt[i*2+0]*rate[pLevel];//half size of real level | ||
669 | y=fPnt[i*2+1]*rate[pLevel]; | ||
670 | for(level=pLevel-1; level>=0; level--){ | ||
671 | x+=x; y+=y; dX+=dX; dY+=dY; | ||
672 | imgSize[0]=imgDims[level*2+0]; //y,x | ||
673 | imgSize[1]=imgDims[level*2+1]; //y,x | ||
674 | |||
675 | c_xx=c_xy=c_yy=0; | ||
676 | //when feature goes out to the boundary. | ||
677 | if((x-winSize)<0 || (y-winSize)<0 | ||
678 | || (y+winSize+1)>=imgSize[0] || (x+winSize+1)>=imgSize[1]){ | ||
679 | //winSize+1due to interpolation | ||
680 | //error or skip the level?? | ||
681 | valid[i]=0; | ||
682 | break; | ||
683 | } | ||
684 | |||
685 | getInterpolatePatch(iP[level], imgSize, x, y, winSize, iPatch); | ||
686 | getInterpolatePatch(iDxP[level], imgSize, x, y, winSize, iDxPatch); | ||
687 | getInterpolatePatch(iDyP[level], imgSize, x, y, winSize, iDyPatch); | ||
688 | |||
689 | for(idx=0; idx<winSizeSq;idx++){ | ||
690 | c_xx+=iDxPatch[idx]*iDxPatch[idx]; | ||
691 | c_xy+=iDxPatch[idx]*iDyPatch[idx]; | ||
692 | c_yy+=iDyPatch[idx]*iDyPatch[idx]; | ||
693 | } | ||
694 | c_det=c_xx*c_yy-c_xy*c_xy; | ||
695 | if(c_det/(c_xx+c_yy+0.00000001)<GOOD_FEATURE_LAMBDA_TH){ | ||
696 | valid[i]=0; | ||
697 | break; | ||
698 | } | ||
699 | c_det=1/c_det; | ||
700 | for(k=0; k<max_iter; k++){ | ||
701 | if((x+dX-winSize)<0 || (y+dY-winSize)<0 | ||
702 | || (y+dY+winSize+1)>=imgSize[0] || (x+dX+winSize+1)>=imgSize[1]){ | ||
703 | //winSize+1due to interpolation | ||
704 | //error or skip the level?? | ||
705 | valid[i]=0; | ||
706 | break; | ||
707 | } | ||
708 | getInterpolatePatch(jP[level], imgSize, x+dX, y+dY, winSize, jPatch); | ||
709 | eX=eY=0; | ||
710 | for(idx=0;idx<winSizeSq;idx++){ | ||
711 | dIt=iPatch[idx]-jPatch[idx]; | ||
712 | eX+=dIt*iDxPatch[idx]; | ||
713 | eY+=dIt*iDyPatch[idx]; | ||
714 | } | ||
715 | mX=c_det*(eX*c_yy-eY*c_xy); | ||
716 | mY=c_det*(-eX*c_xy+eY*c_xx); | ||
717 | dX+=mX; | ||
718 | dY+=mY; | ||
719 | if((mX*mX+mY*mY)<accuracy_th) break; | ||
720 | } | ||
721 | } | ||
722 | newFPnt[i*2+0]=fPnt[i*2+0]+dX; | ||
723 | newFPnt[i*2+1]=fPnt[i*2+1]+dY; | ||
724 | /* | ||
725 | if(valid[i] | ||
726 | || (x+dX-winSize)<0 || (y+dY-winSize)<0 | ||
727 | || (y+dY+winSize+1)>=imgSize[0] || (x+dX+winSize+1)>=imgSize[1]){ | ||
728 | newFPnt[i*2+0]=fPnt[i*2+0]+dX; | ||
729 | newFPnt[i*2+1]=fPnt[i*2+1]+dY; | ||
730 | getInterpolatePatch(jP[0], imgSize, newFPnt[i*2+0], newFPnt[i*2+0], winSize, jPatch); | ||
731 | dIt=0; | ||
732 | for(idx=0;idx<winSizeSq;idx++){ | ||
733 | dIt+=(iPatch[idx]-jPatch[idx])*(iPatch[idx]-jPatch[idx]); | ||
734 | } | ||
735 | if(dIt>winSizeSq*50000){ | ||
736 | valid[i]=0; | ||
737 | } | ||
738 | }else{ | ||
739 | newFPnt[i*2+0]=0; | ||
740 | newFPnt[i*2+1]=0; | ||
741 | } | ||
742 | */ | ||
743 | } | ||
744 | free(iPatch); | ||
745 | free(jPatch); | ||
746 | free(iDxPatch); | ||
747 | free(iDyPatch); | ||
748 | } | ||
749 | void getPatch(double* srcImg, const int* srcDims, double centerX, double centerY, int winSize, double** dstImg){ | ||
750 | int srcIdxX, srcIdxY, dstIdxX; | ||
751 | srcIdxY=(int)centerY-winSize; | ||
752 | for(int i=-winSize; i<winSize; i++){ | ||
753 | srcIdxX=(int)centerX+i; | ||
754 | dstIdxX=i+winSize; | ||
755 | dstImg[dstIdxX]=srcImg+srcIdxX*winSize*2+srcIdxY; | ||
756 | } | ||
757 | } | ||
758 | void calcLKTrack(double* imgI, double* iDx, double* iDy, double* imgJ, const int* imdims, | ||
759 | double* c_xx, double* c_xy, double* c_yy, | ||
760 | double* fPnt, double* initPnt, int nFeatures, int winSize, | ||
761 | double* newFPnt, char* valid){ | ||
762 | calcLKTrack( imgI, iDx, iDy, imgJ, imdims, | ||
763 | c_xx, c_xy, c_yy, | ||
764 | fPnt, initPnt, nFeatures, winSize, | ||
765 | newFPnt, valid, LK_ACCURACY_TH, LK_MAX_ITER); | ||
766 | } | ||
767 | void calcLKTrack(double* imgI, double* iDx, double* iDy, double* imgJ, const int* imdims, | ||
768 | double* c_xx, double* c_xy, double* c_yy, | ||
769 | double* fPnt, double* initPnt, int nFeatures, int winSize, | ||
770 | double* newFPnt, char* valid, | ||
771 | double accuracy_th, int max_iter){ | ||
772 | double x, y, eX, eY, dX, dY, mX, mY, c_det, dIt; | ||
773 | double* iPatch[LK_MAX_WIN], *iDxPatch[LK_MAX_WIN], *iDyPatch[LK_MAX_WIN]; | ||
774 | double* jPatch; | ||
775 | int level, winSizeSq; | ||
776 | int i, k, idxCol, idxRow, idx; | ||
777 | int imgSize[2]; | ||
778 | |||
779 | jPatch=(double*) malloc(sizeof(double)*winSizeSq); | ||
780 | winSizeSq=4*winSize*winSize; | ||
781 | imgSize[0]=imdims[0]; | ||
782 | imgSize[1]=imdims[1]; | ||
783 | for(i=0; i<nFeatures; i++){ | ||
784 | x=fPnt[i*2+0];//half size of real level | ||
785 | y=fPnt[i*2+1]; | ||
786 | dX=initPnt[i*2+0]-x; | ||
787 | dY=initPnt[i*2+1]-y; | ||
788 | //printf("input dx dy %.2f %.2f:", dX, dY); | ||
789 | |||
790 | //when feature goes out to the boundary. | ||
791 | if((x-winSize)<0 || (y-winSize)<0 | ||
792 | || (y+winSize)>=imdims[0] || (x+winSize)>=imdims[1]){ | ||
793 | //error or skip the level?? | ||
794 | valid[i]=0; | ||
795 | continue; | ||
796 | } | ||
797 | |||
798 | getPatch(imgI, imdims, x, y, winSize, iPatch); | ||
799 | getPatch(iDx, imdims, x, y, winSize, iDxPatch); | ||
800 | getPatch(iDy, imdims, x, y, winSize, iDyPatch); | ||
801 | |||
802 | idx=(int)x*imdims[0]+(int)y; | ||
803 | c_det=c_xx[i]*c_yy[i]-c_xy[i]*c_xy[i]; | ||
804 | if(c_det/(c_xx[i]+c_yy[i]+0.00000001)<GOOD_FEATURE_LAMBDA_TH*100){ | ||
805 | valid[i]=0; | ||
806 | continue; | ||
807 | } | ||
808 | c_det=1/c_det; | ||
809 | for(k=0; k<max_iter; k++){ | ||
810 | if((x+dX-winSize)<0 || (y+dY-winSize)<0 | ||
811 | || (y+dY+winSize+1)>=imdims[0] || (x+dX+winSize+1)>=imdims[1]){ | ||
812 | //winSize+1due to interpolation | ||
813 | //error or skip the level?? | ||
814 | valid[i]=0; | ||
815 | break; | ||
816 | } | ||
817 | getInterpolatePatch(imgJ, imgSize, x+dX, y+dY, winSize, jPatch); | ||
818 | eX=eY=0; | ||
819 | for(idxCol=0;idxCol<2*winSize;idxCol++){ | ||
820 | for(idxRow=0;idxRow<2*winSize;idxRow++){ | ||
821 | dIt=iPatch[idxCol][idxRow]-jPatch[idxCol*winSize*2+idxRow]; | ||
822 | eX+=dIt*iDxPatch[idxCol][idxRow]; | ||
823 | eY+=dIt*iDyPatch[idxCol][idxRow]; | ||
824 | } | ||
825 | } | ||
826 | mX=c_det*(eX*c_yy[i]-eY*c_xy[i]); | ||
827 | mY=c_det*(-eX*c_xy[i]+eY*c_xx[i]); | ||
828 | dX+=mX; | ||
829 | dY+=mY; | ||
830 | if((mX*mX+mY*mY)<accuracy_th) break; | ||
831 | } | ||
832 | if(k==max_iter){ | ||
833 | valid[i]=0; | ||
834 | } | ||
835 | newFPnt[i*2+0]=x+dX; | ||
836 | newFPnt[i*2+1]=y+dY; | ||
837 | } | ||
838 | free(jPatch); | ||
839 | } | ||
840 | |||