1
2
3 #include "autopos.h"
4 #include "cleanupcommon.h"
5
6 #include <sstream>
7
8 using namespace CleanupTypes;
9
10 /*
11 guardare DAFARE
12 guardare assumo
13 autoalign rgb ->ora viene chiamata con un buffer rgbm ! modificare
14 opportunamente
15
16 fare resize e realloc size dello stack a 65000 unita'
17
18 */
19
20 #define SECURITY_MARGIN_MM 4.0
21
22 static bool Debug_flag = false;
23
24 /*===========================================================================*/
25 /*
26
27 AUTOALIGNMENT
28
29
30 */
31
32 #define AUTOAL_BLACK_COLS 2
33 #define AUTOAL_WHITE_COLS 2
34 #define AUTOAL_THRESHOLD 160
35
autoalign_gr8(UCHAR * buffer_gr8,int wrap,int lx,int ly,int pix_origin,int dpix_dx,int dpix_dy,int strip_width)36 static bool autoalign_gr8(UCHAR *buffer_gr8, int wrap, int lx, int ly,
37 int pix_origin, int dpix_dx, int dpix_dy,
38 int strip_width) {
39 int first_x[2], dx_dcol[2], target[2];
40 int i, x, y, cols;
41 int col_value, threshold;
42 int consec_black_cols, consec_white_cols, black_strip_edge;
43 UCHAR *pix, *origin;
44 int delta_x, delta_pix;
45
46 origin = buffer_gr8 + pix_origin;
47
48 first_x[0] = 0;
49 dx_dcol[0] = 1;
50 target[0] = strip_width / 2;
51 first_x[1] = lx - 1;
52 dx_dcol[1] = -1;
53 target[1] = lx - 1 - strip_width / 2;
54
55 threshold = AUTOAL_THRESHOLD * ly;
56
57 for (i = 0; i < 2; i++) {
58 consec_black_cols = 0;
59 consec_white_cols = 0;
60 black_strip_edge = 0;
61 for (x = first_x[i], cols = 0; cols < strip_width;
62 x += dx_dcol[i], cols++) {
63 col_value = 0;
64 pix = origin + x * dpix_dx;
65 for (y = 0; y < ly; y++) {
66 col_value += *pix;
67 pix += dpix_dy;
68 }
69 if (col_value < threshold) {
70 consec_white_cols = 0;
71 consec_black_cols++;
72 if (consec_black_cols >= AUTOAL_BLACK_COLS) black_strip_edge = x;
73 } else {
74 consec_black_cols = 0;
75 consec_white_cols++;
76 if (consec_white_cols >= AUTOAL_WHITE_COLS && black_strip_edge)
77 goto found;
78 }
79 }
80 }
81 return false;
82
83 found:
84
85 for (x = first_x[i], cols = 0; cols < strip_width; x += dx_dcol[i], cols++) {
86 pix = origin + x * dpix_dx;
87 for (y = 0; y < ly; y++) {
88 *pix = 255;
89 pix += dpix_dy;
90 }
91 }
92 delta_x = target[i] - black_strip_edge;
93 delta_pix = delta_x * dpix_dx;
94 if (delta_x > 0) {
95 for (x = lx - 1 - delta_x; x >= 0; x--) {
96 pix = origin + x * dpix_dx;
97 for (y = 0; y < ly; y++) {
98 *(pix + delta_pix) = *pix;
99 pix += dpix_dy;
100 }
101 }
102 for (x = lx - delta_x; x < lx; x++) {
103 pix = origin + x * dpix_dx;
104 for (y = 0; y < ly; y++) {
105 *pix = 255;
106 pix += dpix_dy;
107 }
108 }
109 } else if (delta_x < 0) {
110 for (x = -delta_x; x < lx; x++) {
111 pix = origin + x * dpix_dx;
112 for (y = 0; y < ly; y++) {
113 *(pix + delta_pix) = *pix;
114 pix += dpix_dy;
115 }
116 }
117 for (x = 0; x < -delta_x; x++) {
118 pix = origin + x * dpix_dx;
119 for (y = 0; y < ly; y++) {
120 *pix = 255;
121 pix += dpix_dy;
122 }
123 }
124 }
125 return true;
126 }
127
128 /*---------------------------------------------------------------------------*/
129
autoalign_rgb(TPixel32 * buffer_rgb,int wrap,int lx,int ly,int pix_origin,int dpix_dx,int dpix_dy,int strip_width)130 static bool autoalign_rgb(TPixel32 *buffer_rgb, int wrap, int lx, int ly,
131 int pix_origin, int dpix_dx, int dpix_dy,
132 int strip_width) {
133 int first_x[2], dx_dcol[2], target[2];
134 int i, x, y, cols;
135 int col_value, threshold;
136 int consec_black_cols, consec_white_cols, black_strip_edge;
137 TPixel32 *pix, *origin;
138 int delta_x, delta_pix;
139
140 origin = buffer_rgb + pix_origin;
141
142 first_x[0] = 0;
143 dx_dcol[0] = 1;
144 target[0] = strip_width / 2;
145 first_x[1] = lx - 1;
146 dx_dcol[1] = -1;
147 target[1] = lx - 1 - strip_width / 2;
148
149 threshold = AUTOAL_THRESHOLD * ly;
150
151 for (i = 0; i < 2; i++) {
152 consec_black_cols = 0;
153 consec_white_cols = 0;
154 black_strip_edge = 0;
155 for (x = first_x[i], cols = 0; cols < strip_width;
156 x += dx_dcol[i], cols++) {
157 col_value = 0;
158 pix = origin + x * dpix_dx;
159 for (y = 0; y < ly; y++) {
160 col_value += (pix->r * 2 + pix->g * 5 + pix->b) >> 3;
161 pix += dpix_dy;
162 }
163 if (col_value < threshold) {
164 consec_white_cols = 0;
165 consec_black_cols++;
166 if (consec_black_cols >= AUTOAL_BLACK_COLS) black_strip_edge = x;
167 } else {
168 consec_black_cols = 0;
169 consec_white_cols++;
170 if (consec_white_cols >= AUTOAL_WHITE_COLS && black_strip_edge)
171 goto found;
172 }
173 }
174 }
175 return false;
176
177 found:
178
179 for (x = first_x[i], cols = 0; cols < strip_width; x += dx_dcol[i], cols++) {
180 pix = origin + x * dpix_dx;
181 for (y = 0; y < ly; y++) {
182 pix->r = pix->g = pix->b = 255;
183 pix += dpix_dy;
184 }
185 }
186 delta_x = target[i] - black_strip_edge;
187 delta_pix = delta_x * dpix_dx;
188 if (delta_x > 0) {
189 for (x = lx - 1 - delta_x; x >= 0; x--) {
190 pix = origin + x * dpix_dx;
191 for (y = 0; y < ly; y++) {
192 (pix + delta_pix)->r = pix->r;
193 (pix + delta_pix)->g = pix->g;
194 (pix + delta_pix)->b = pix->b;
195 pix += dpix_dy;
196 }
197 }
198 for (x = lx - delta_x; x < lx; x++) {
199 pix = origin + x * dpix_dx;
200 for (y = 0; y < ly; y++) {
201 pix->r = pix->g = pix->b = 255;
202 pix += dpix_dy;
203 }
204 }
205 } else if (delta_x < 0) {
206 for (x = -delta_x; x < lx; x++) {
207 pix = origin + x * dpix_dx;
208 for (y = 0; y < ly; y++) {
209 (pix + delta_pix)->r = pix->r;
210 (pix + delta_pix)->g = pix->g;
211 (pix + delta_pix)->b = pix->b;
212 pix += dpix_dy;
213 }
214 }
215 for (x = 0; x < -delta_x; x++) {
216 pix = origin + x * dpix_dx;
217 for (y = 0; y < ly; y++) {
218 pix->r = pix->g = pix->b = 255;
219 pix += dpix_dy;
220 }
221 }
222 }
223 return true;
224 }
225
226 /*---------------------------------------------------------------------------*/
227
do_autoalign(const TRasterImageP & image)228 bool do_autoalign(const TRasterImageP &image) {
229 int wrap, lx, ly, mx, my;
230 int pix_origin, dpix_dx, dpix_dy;
231 int strip_width;
232
233 // assumo che sia sempre orientata nel modo corretto
234
235 TRasterP ras = image->getRaster();
236 wrap = ras->getWrap();
237 assert(TRaster32P(ras) ||
238 TRasterGR8P(ras)); // per ricordare di gestire le img bw!
239
240 // assumo TOR_BOTLEFT:__OR TOR_BOTRIGHT:__OR TOR_TOPLEFT:__OR TOR_TOPRIGHT:
241 double dpix, dpiy;
242 image->getDpi(dpix, dpiy);
243 strip_width = (int)mmToPixel(5.0, dpix);
244 lx = ras->getLx();
245 ly = ras->getLy();
246
247 mx = lx - 1;
248 my = ly - 1;
249
250 // assumo CASE TOR_BOTLEFT:
251 pix_origin = 0;
252 dpix_dx = 1;
253 dpix_dy = wrap;
254
255 TRasterGR8P ras8(ras);
256 TRaster32P ras32(ras);
257 ras->lock();
258 bool ret = false;
259
260 if (ras8)
261 ret = autoalign_gr8(ras8->getRawData(), wrap, lx, ly, pix_origin, dpix_dx,
262 dpix_dy, strip_width);
263
264 else if (ras32)
265 ret = autoalign_rgb(ras32->pixels(), wrap, lx, ly, pix_origin, dpix_dx,
266 dpix_dy, strip_width);
267 else
268 assert(!"Unsupported pixel type");
269
270 ras->unlock();
271
272 return false;
273 }
274
275 /*===========================================================================*/
276 /*
277
278 AUTOCENTERING
279
280
281 */
282 /*
283 * Calcoli in millimetri per questa funzione che alla fine restituisce un
284 * valore per la striscia di ricerca direttamente in pixel
285 */
286
compute_strip_pixel(FDG_INFO * fdg,double dpi)287 int compute_strip_pixel(FDG_INFO *fdg, double dpi) {
288 int i, strip_size_pix;
289 double half_size, max_half_size, strip_size_mm;
290
291 max_half_size = -1.0;
292 for (i = 0; i < (int)fdg->dots.size(); i++) {
293 half_size = (double)fdg->dots[i].lx * 0.5;
294 if (max_half_size < half_size) max_half_size = half_size;
295 }
296 strip_size_mm =
297 fdg->dist_ctr_hole_to_edge + max_half_size + SECURITY_MARGIN_MM;
298
299 strip_size_pix = (int)mmToPixel(strip_size_mm, dpi);
300
301 if (Debug_flag)
302 printf("Controllo una striscia larga %g mm e %d pixels\n", strip_size_mm,
303 strip_size_pix);
304
305 return strip_size_pix;
306 }
307
308 /*---------------------------------------------------------------------------*/
309
310 #define SQMM_TO_SQPIXEL(area, x_res, y_res) \
311 ((double)((x_res) * (y_res)) * (double)(area) * ((1.0 / 25.4) * (1.0 / 25.4)))
312
313 /*---------------------------------------------------------------------------*/
convert_dots_mm_to_pixel(DOT * dots,int nd,double x_res,double y_res)314 void convert_dots_mm_to_pixel(DOT *dots, int nd, double x_res, double y_res) {
315 int i;
316
317 for (i = 0; i < nd; i++) {
318 dots[i].x1 = troundp(mmToPixel(dots[i].x1, x_res));
319 dots[i].y1 = troundp(mmToPixel(dots[i].y1, y_res));
320 dots[i].x2 = troundp(mmToPixel(dots[i].x2, x_res));
321 dots[i].y2 = troundp(mmToPixel(dots[i].y2, y_res));
322 dots[i].x = (float)mmToPixel(dots[i].x, x_res);
323 dots[i].y = (float)mmToPixel(dots[i].y, y_res);
324 dots[i].lx = troundp(mmToPixel(dots[i].lx, x_res));
325 dots[i].ly = troundp(mmToPixel(dots[i].ly, y_res));
326 dots[i].area = troundp(SQMM_TO_SQPIXEL(dots[i].area, x_res, y_res));
327 }
328 return;
329 }
330
331 /*---------------------------------------------------------------------------*/
332
333 static char *Done = 0;
334 static int Done_rowsize = 0;
335 static int Done_colsize = 0;
336 #define DONE_MASK(I, J) (1 << (((I) + (J)*Done_rowsize) & 7))
337 #define DONE_BYTE(I, J) (((I) + (J)*Done_rowsize) >> 3)
338 #define SET_DONE(I, J) (Done[DONE_BYTE(I, J)] |= DONE_MASK(I, J))
339 #define NOT_DONE(I, J) (!(Done[DONE_BYTE(I, J)] & DONE_MASK(I, J)))
340
341 static int Pix_ystep = 0;
342
343 typedef struct big { unsigned lo, hi; } BIG;
344 #define CLEARBIG(B) ((B).lo = 0, (B).hi = 0, (B))
345 #define ADDBIG(B, X) \
346 ((B).lo += (unsigned)(X), (B).hi += (B).lo >> 30, (B).lo &= 0x3fffffff, (B))
347 #define BIG_TO_DOUBLE(B) ((double)(B).hi * (double)0x40000000 + (double)(B).lo)
348
349 #define IS_BLACK_GR8(PIX) (*(PIX) < 110)
350 #define IS_VERY_BLACK_GR8(PIX) (*(PIX) < 30)
351 #define BLACK_WEIGHT_GR8(PIX) (256 - *(PIX))
352
353 #define RGBR(PIX) ((PIX)->r << 1)
354 #define RGBG(PIX) ((PIX)->g << 2)
355 #define RGBB(PIX) ((PIX)->b)
356 #define RGBVAL(PIX) (RGBR(PIX) + RGBG(PIX) + RGBB(PIX))
357
358 #define IS_BLACK_RGB(PIX) (RGBVAL(PIX) < 110 * 7)
359 #define IS_VERY_BLACK_RGB(PIX) (RGBVAL(PIX) < 30 * 7)
360 #define BLACK_WEIGHT_RGB(PIX) ((256 * 7 - RGBVAL(PIX)) >> 3)
361
362 static BIG Xsum, Ysum, Weightsum;
363 static int Xmin, Xmax, Ymin, Ymax, Npix;
364 #ifdef RECURSIVE_VERSION
365 static int Level, Max_level;
366 #endif
367 static bool Very_black_found;
368
369 #ifdef DAFARE
370 #ifdef RECURSIVE_VERSION
371 static int Black_pixel = 0;
372 #endif
373 #endif
374
375 #ifdef DAFARE
376 static int find_dots_bw(const TRasterP &img, int strip_width,
377 PEGS_SIDE pegs_side, DOT dotarray[], int dotarray_size,
378 int max_area);
379 #endif
380 static int find_dots_gr8(const TRasterGR8P &img, int strip_width,
381 PEGS_SIDE pegs_side, DOT dotarray[], int dotarray_size,
382 int max_area);
383 static int find_dots_rgb(const TRaster32P &img, int strip_width,
384 PEGS_SIDE pegs_side, DOT dotarray[], int dotarray_size,
385 int max_area);
386 static void
387 #ifdef DAFARE
388 visit_bw(int i, int j, int x, int y, int bit, UCHAR *byte),
389 #endif
390 visit_gr8(int i, int j, int x, int y, UCHAR *pix),
391 visit_rgb(int i, int j, int x, int y, TPixel32 *pix),
392 stampa_dot(DOT const *dot);
393
394 //! \brief Find the best matching pegs
395 //!
396 //! The found pegs are in array dots. The function checks, which of those best
397 //! fits the reference in
398 //! reference. The three best matching dots are returned in parameters i, j, k.
399 static bool compare_dots(DOT const dots[], int ndots, DOT reference[],
400 int ref_dot, int &i, int &j, int &k);
401
402 #define REVERSE(byte, bit) \
403 { \
404 unsigned char mask; \
405 mask = 1 << (bit); \
406 *(byte) ^= mask; \
407 }
408
409 /*---------------------------------------------------------------------------*/
410
411 typedef struct {
412 short ret, bit;
413 int x, y, i, j;
414 void *ptr;
415 } STACK_INFO;
416
417 static STACK_INFO *Stack = 0;
418 static int Stack_alloc_size = 0;
419 static int Stack_size = 0;
420
421 #define CREATE_STACK \
422 { \
423 assert(!Stack); \
424 Stack_alloc_size = 65500; \
425 Stack_size = 0; \
426 Stack = (STACK_INFO *)malloc(Stack_alloc_size * sizeof(STACK_INFO)); \
427 if (!Stack) return false; \
428 }
429
430 #define DESTROY_STACK \
431 { \
432 Stack_alloc_size = 0; \
433 Stack_size = 0; \
434 free(Stack); \
435 Stack = 0; \
436 }
437
438 #define STACK_IS_EMPTY (!Stack_size)
439
440 #define PUSH_ONTO_STACK(RET, X, Y, I, J, BIT, PTR) \
441 { \
442 if (Stack_size >= Stack_alloc_size) { \
443 Stack_alloc_size += 65500; \
444 Stack = \
445 (STACK_INFO *)realloc(Stack, Stack_alloc_size * sizeof(STACK_INFO)); \
446 if (!Stack) return; \
447 } \
448 Stack[Stack_size].ret = (RET); \
449 Stack[Stack_size].x = (X); \
450 Stack[Stack_size].y = (Y); \
451 Stack[Stack_size].i = (I); \
452 Stack[Stack_size].j = (J); \
453 Stack[Stack_size].bit = (BIT); \
454 Stack[Stack_size].ptr = (PTR); \
455 Stack_size++; \
456 }
457
458 #define POP_FROM_STACK_U(RET, X, Y, I, J, BIT, PTR) \
459 { \
460 Stack_size--; \
461 (RET) = Stack[Stack_size].ret; \
462 (X) = Stack[Stack_size].x; \
463 (Y) = Stack[Stack_size].y; \
464 (I) = Stack[Stack_size].i; \
465 (J) = Stack[Stack_size].j; \
466 (BIT) = Stack[Stack_size].bit; \
467 (PTR) = (UCHAR *)Stack[Stack_size].ptr; \
468 }
469
470 #define POP_FROM_STACK_TPIXEL32(RET, X, Y, I, J, BIT, PTR) \
471 { \
472 Stack_size--; \
473 (RET) = Stack[Stack_size].ret; \
474 (X) = Stack[Stack_size].x; \
475 (Y) = Stack[Stack_size].y; \
476 (I) = Stack[Stack_size].i; \
477 (J) = Stack[Stack_size].j; \
478 (BIT) = Stack[Stack_size].bit; \
479 (PTR) = (TPixel32 *)Stack[Stack_size].ptr; \
480 }
481
482 /*---------------------------------------------------------------------------*/
483
find_dots(const TRasterP & img,int strip_width,PEGS_SIDE pegs_side,DOT dotarray[],int dotarray_size,int max_area)484 static int find_dots(const TRasterP &img, int strip_width, PEGS_SIDE pegs_side,
485 DOT dotarray[], int dotarray_size, int max_area) {
486 TRaster32P ras32(img);
487 if (ras32)
488 return find_dots_rgb(ras32, strip_width, pegs_side, dotarray, dotarray_size,
489 max_area);
490 TRasterGR8P ras8(img);
491 if (ras8)
492 return find_dots_gr8(ras8, strip_width, pegs_side, dotarray, dotarray_size,
493 max_area);
494 assert(!"Unsupported pixel type");
495
496 return 0;
497 }
498
499 /*---------------------------------------------------------------------------*/
500 #ifdef DAFARE
find_dots_bw(const TRasterP & img,int strip_width,PEGS_SIDE pegs_side,DOT dotarray[],int dotarray_size,int max_area)501 static int find_dots_bw(const TRasterP &img, int strip_width,
502 PEGS_SIDE pegs_side, DOT dotarray[], int dotarray_size,
503 int max_area) {
504 int n_dots, ins, shift;
505 int x, y; // coords in img coord system
506 int i, j; // coords in done coord system
507 int x0, y0, xsize, ysize, xlast, ylast, bit;
508 UCHAR *byte, *buffer;
509 int dot_lx, dot_ly;
510 float dot_x, dot_y;
511 bool vertical;
512
513 if (img->type == RAS_WB)
514 Black_pixel = 1;
515 else if (img->type == RAS_BW)
516 Black_pixel = 0;
517 else {
518 TERROR("find dots error: bad image type");
519 return 0;
520 }
521
522 switch (pegs_side) {
523 case PEGS_BOTTOM:
524 case PEGS_TOP:
525 x0 = 0;
526 y0 = pegs_side == PEGS_BOTTOM ? 0 : img->ly - strip_width;
527 xsize = img->lx;
528 ysize = strip_width;
529 vertical = false;
530 break;
531
532 case PEGS_LEFT:
533 case PEGS_RIGHT:
534 x0 = pegs_side == PEGS_LEFT ? 0 : img->lx - strip_width;
535 y0 = 0;
536 xsize = strip_width;
537 ysize = img->ly;
538 vertical = true;
539 break;
540
541 default: {
542 std::ostringstream os;
543 os << "find dots internal error: pegs_side = " << std::hex << pegs_side
544 << '\0';
545 throw TCleanupException(os.str().c_str());
546 x0 = y0 = xsize = ysize = 0;
547 vertical = false;
548 }
549 }
550 xlast = x0 + xsize - 1;
551 ylast = y0 + ysize - 1;
552 n_dots = 0;
553 Done_rowsize = xsize + 2;
554 Done_colsize = ysize + 2;
555 Done = (char *)calloc((size_t)((Done_rowsize * Done_colsize + 7) >> 3),
556 sizeof(char));
557 if (!Done) {
558 throw TCleanupException("find_dots: out of memory");
559 }
560 for (i = 0; i < Done_rowsize; i++) {
561 SET_DONE(i, 0);
562 SET_DONE(i, Done_colsize - 1);
563 }
564 for (j = 0; j < Done_colsize; j++) {
565 SET_DONE(0, j);
566 SET_DONE(Done_rowsize - 1, j);
567 }
568 buffer = (UCHAR *)img->buffer;
569 Pix_ystep = (img->wrap + 7) >> 3;
570
571 if (Debug_flag) {
572 printf("Zona di scansione: (%d,%d) -- (%d,%d)\n", x0, y0, xlast, ylast);
573 printf("wrap: %d\n", img->wrap);
574 }
575
576 #ifdef RECURSIVE_VERSION
577 Max_level = max_area * 6 / 5;
578 #endif
579
580 CREATE_STACK
581 for (j = 1, y = y0; y <= ylast; j++, y++) {
582 bit = 7 - (x0 & 7);
583 byte = buffer + (x0 >> 3) + y * Pix_ystep;
584 for (i = 1, x = x0; x <= xlast; i++, x++) {
585 if (NOT_DONE(i, j) && ((*byte >> bit) & 1) == Black_pixel) {
586 CLEARBIG(Xsum);
587 CLEARBIG(Ysum);
588 CLEARBIG(Weightsum);
589 Xmin = Xmax = x;
590 Ymin = Ymax = y;
591 Npix = 0;
592 #ifdef RECURSIVE_VERSION
593 Level = 0;
594 #endif
595 visit_bw(i, j, x, y, bit, byte);
596 dot_lx = Xmax - Xmin + 1;
597 dot_ly = Ymax - Ymin + 1;
598 if (Npix < max_area * 3 / 2 && dot_lx > 3 && dot_lx < (xsize >> 1) &&
599 dot_ly > 3 && dot_ly < (ysize >> 1) && Xmin > x0 && Xmax < xlast &&
600 Ymin > y0 && Ymax < ylast) {
601 dot_x = BIG_TO_DOUBLE(Xsum) / BIG_TO_DOUBLE(Weightsum);
602 dot_y = BIG_TO_DOUBLE(Ysum) / BIG_TO_DOUBLE(Weightsum);
603 if (vertical) {
604 for (ins = 0; ins < n_dots; ins++)
605 if (dotarray[ins].y > dot_y) break;
606 } else {
607 for (ins = 0; ins < n_dots; ins++)
608 if (dotarray[ins].x > dot_x) break;
609 }
610 for (shift = n_dots - 1; shift >= ins; shift--)
611 dotarray[shift + 1] = dotarray[shift];
612 n_dots++;
613 dotarray[ins].x1 = Xmin;
614 dotarray[ins].x2 = Xmax;
615 dotarray[ins].y1 = Ymin;
616 dotarray[ins].y2 = Ymax;
617 dotarray[ins].lx = dot_lx;
618 dotarray[ins].ly = dot_ly;
619 dotarray[ins].area = Npix;
620 dotarray[ins].x = dot_x;
621 dotarray[ins].y = dot_y;
622 if (n_dots >= dotarray_size) goto end_loop;
623 }
624 }
625 if (bit == 0) {
626 bit = 7;
627 byte++;
628 } else
629 bit--;
630 }
631 }
632 end_loop:
633 DESTROY_STACK
634 free(Done);
635 Done = NIL;
636 return n_dots;
637 }
638 #endif
639 /*---------------------------------------------------------------------------*/
640
find_dots_gr8(const TRasterGR8P & img,int strip_width,PEGS_SIDE pegs_side,DOT dotarray[],int dotarray_size,int max_area)641 static int find_dots_gr8(const TRasterGR8P &img, int strip_width,
642 PEGS_SIDE pegs_side, DOT dotarray[], int dotarray_size,
643 int max_area) {
644 int n_dots, ins, shift;
645 int x, y; /* coords in img coord system */
646 int i, j; /* coords in done coord system */
647 int x0, y0, xsize, ysize, xlast, ylast;
648 UCHAR *pix, *buffer;
649 int dot_lx, dot_ly;
650 float dot_x, dot_y;
651 bool vertical;
652
653 switch (pegs_side) {
654 case PEGS_BOTTOM:
655 case PEGS_TOP:
656 x0 = 0;
657 y0 = pegs_side == PEGS_BOTTOM ? 0 : img->getLy() - strip_width;
658 xsize = img->getLx();
659 ysize = strip_width;
660 vertical = false;
661 break;
662 case PEGS_LEFT:
663 case PEGS_RIGHT:
664 x0 = pegs_side == PEGS_LEFT ? 0 : img->getLx() - strip_width;
665 y0 = 0;
666 xsize = strip_width;
667 ysize = img->getLy();
668 vertical = true;
669 break;
670 default: {
671 std::ostringstream os;
672 os << "find dots internal error: pegs_side = " << std::hex << pegs_side
673 << '\0';
674 throw TCleanupException(os.str().c_str());
675 x0 = y0 = xsize = ysize = 0;
676 vertical = false;
677 }
678 }
679
680 xlast = x0 + xsize - 1;
681 ylast = y0 + ysize - 1;
682 n_dots = 0;
683 Done_rowsize = xsize + 2;
684 Done_colsize = ysize + 2;
685 Done = (char *)calloc((size_t)((Done_rowsize * Done_colsize + 7) >> 3),
686 sizeof(char));
687 if (!Done) {
688 throw TCleanupException("find_dots: out of memory");
689 }
690 for (i = 0; i < Done_rowsize; i++) {
691 SET_DONE(i, 0);
692 SET_DONE(i, Done_colsize - 1);
693 }
694 for (j = 0; j < Done_colsize; j++) {
695 SET_DONE(0, j);
696 SET_DONE(Done_rowsize - 1, j);
697 }
698
699 Pix_ystep = img->getWrap();
700 if (Debug_flag) {
701 printf("Zona di scansione: (%d,%d) -- (%d,%d)\n", x0, y0, xlast, ylast);
702 printf("wrap: %d\n", img->getWrap());
703 }
704 #ifdef RECURSIVE_VERSION
705 Max_level = max_area * 6 / 5;
706 #endif
707
708 img->lock();
709
710 buffer = (UCHAR *)img->getRawData();
711 CREATE_STACK
712 for (j = 1, y = y0; y <= ylast; j++, y++)
713 for (i = 1, x = x0, pix = buffer + x0 + y * Pix_ystep; x <= xlast;
714 i++, x++, pix++)
715 if (NOT_DONE(i, j) && IS_BLACK_GR8(pix)) {
716 CLEARBIG(Xsum);
717 CLEARBIG(Ysum);
718 CLEARBIG(Weightsum);
719 Xmin = Xmax = x;
720 Ymin = Ymax = y;
721 Npix = 0;
722 #ifdef RECURSIVE_VERSION
723 Level = 0;
724 #endif
725 visit_gr8(i, j, x, y, pix);
726 dot_lx = Xmax - Xmin + 1;
727 dot_ly = Ymax - Ymin + 1;
728 if (Npix < max_area * 3 / 2 && dot_lx > 3 && dot_lx < (xsize >> 1) &&
729 dot_ly > 3 && dot_ly < (ysize >> 1) && Xmin > x0 && Xmax < xlast &&
730 Ymin > y0 && Ymax < ylast) {
731 dot_x = (float)(BIG_TO_DOUBLE(Xsum) / BIG_TO_DOUBLE(Weightsum));
732 dot_y = (float)(BIG_TO_DOUBLE(Ysum) / BIG_TO_DOUBLE(Weightsum));
733 if (vertical) {
734 for (ins = 0; ins < n_dots; ins++)
735 if (dotarray[ins].y > dot_y) break;
736 } else {
737 for (ins = 0; ins < n_dots; ins++)
738 if (dotarray[ins].x > dot_x) break;
739 }
740 for (shift = n_dots - 1; shift >= ins; shift--)
741 dotarray[shift + 1] = dotarray[shift];
742 n_dots++;
743 dotarray[ins].x1 = Xmin;
744 dotarray[ins].x2 = Xmax;
745 dotarray[ins].y1 = Ymin;
746 dotarray[ins].y2 = Ymax;
747 dotarray[ins].lx = dot_lx;
748 dotarray[ins].ly = dot_ly;
749 dotarray[ins].area = Npix;
750 dotarray[ins].x = dot_x;
751 dotarray[ins].y = dot_y;
752 if (n_dots >= dotarray_size) goto end_loop;
753 }
754 }
755 end_loop:
756 DESTROY_STACK
757
758 free(Done);
759 Done = 0;
760 img->unlock();
761 return n_dots;
762 }
763
764 /*---------------------------------------------------------------------------*/
765
find_dots_rgb(const TRaster32P & img,int strip_width,PEGS_SIDE pegs_side,DOT dotarray[],int dotarray_size,int max_area)766 static int find_dots_rgb(const TRaster32P &img, int strip_width,
767 PEGS_SIDE pegs_side, DOT dotarray[], int dotarray_size,
768 int max_area) {
769 int n_dots, ins, shift;
770 int x, y; /* coords in img coord system */
771 int i, j; /* coords in done coord system */
772 int x0, y0, xsize, ysize, xlast, ylast;
773 TPixel32 *pix, *buffer;
774 int dot_lx, dot_ly;
775 float dot_x, dot_y;
776 bool vertical;
777
778 assert(img->getPixelSize() ==
779 4); /*questo e' per ricordare che l'algo e' per RGB*/
780 switch (pegs_side) {
781 case PEGS_BOTTOM:
782 case PEGS_TOP:
783 x0 = 0;
784 y0 = pegs_side == PEGS_BOTTOM ? 0 : img->getLy() - strip_width;
785 xsize = img->getLx();
786 ysize = strip_width;
787 vertical = false;
788 break;
789 case PEGS_LEFT:
790 case PEGS_RIGHT:
791 x0 = pegs_side == PEGS_LEFT ? 0 : img->getLx() - strip_width;
792 y0 = 0;
793 xsize = strip_width;
794 ysize = img->getLy();
795 vertical = true;
796 break;
797 default: {
798 std::ostringstream os;
799 os << "find dots internal error: pegs_side = " << std::hex << pegs_side
800 << '\0';
801 throw TCleanupException(os.str().c_str());
802 x0 = y0 = xsize = ysize = 0;
803 vertical = false;
804 break;
805 }
806 }
807 xlast = x0 + xsize - 1;
808 ylast = y0 + ysize - 1;
809 n_dots = 0;
810 Done_rowsize = xsize + 2;
811 Done_colsize = ysize + 2;
812 Done = (char *)calloc((size_t)((Done_rowsize * Done_colsize + 7) >> 3),
813 sizeof(char));
814 if (!Done) {
815 throw TCleanupException("find_dots: out of memory");
816 }
817 for (i = 0; i < Done_rowsize; i++) {
818 SET_DONE(i, 0);
819 SET_DONE(i, Done_colsize - 1);
820 }
821 for (j = 0; j < Done_colsize; j++) {
822 SET_DONE(0, j);
823 SET_DONE(Done_rowsize - 1, j);
824 }
825 buffer = img->pixels();
826 Pix_ystep = img->getWrap();
827 if (Debug_flag) {
828 printf("Zona di scansione: (%d,%d) -- (%d,%d)\n", x0, y0, xlast, ylast);
829 printf("wrap: %d\n", img->getWrap());
830 }
831 #ifdef RECURSIVE_VERSION
832 Max_level = max_area * 6 / 5;
833 #endif
834
835 CREATE_STACK
836 for (j = 1, y = y0; y <= ylast; j++, y++)
837 for (i = 1, x = x0, pix = buffer + x0 + y * Pix_ystep; x <= xlast;
838 i++, x++, pix++)
839 if (NOT_DONE(i, j) && IS_BLACK_RGB(pix)) {
840 CLEARBIG(Xsum);
841 CLEARBIG(Ysum);
842 CLEARBIG(Weightsum);
843 Xmin = Xmax = x;
844 Ymin = Ymax = y;
845 Npix = 0;
846 #ifdef RECURSIVE_VERSION
847 Level = 0;
848 #endif
849 visit_rgb(i, j, x, y, pix);
850 dot_lx = Xmax - Xmin + 1;
851 dot_ly = Ymax - Ymin + 1;
852 if (Npix < max_area * 3 / 2 && dot_lx > 3 && dot_lx < (xsize >> 1) &&
853 dot_ly > 3 && dot_ly < (ysize >> 1) && Xmin > x0 && Xmax <= xlast &&
854 Ymin > y0 && Ymax <= ylast) {
855 dot_x = (float)(BIG_TO_DOUBLE(Xsum) / BIG_TO_DOUBLE(Weightsum));
856 dot_y = (float)(BIG_TO_DOUBLE(Ysum) / BIG_TO_DOUBLE(Weightsum));
857 if (vertical) {
858 for (ins = 0; ins < n_dots; ins++)
859 if (dotarray[ins].y > dot_y) break;
860 } else {
861 for (ins = 0; ins < n_dots; ins++)
862 if (dotarray[ins].x > dot_x) break;
863 }
864 for (shift = n_dots - 1; shift >= ins; shift--)
865 dotarray[shift + 1] = dotarray[shift];
866 n_dots++;
867 dotarray[ins].x1 = Xmin;
868 dotarray[ins].x2 = Xmax;
869 dotarray[ins].y1 = Ymin;
870 dotarray[ins].y2 = Ymax;
871 dotarray[ins].lx = dot_lx;
872 dotarray[ins].ly = dot_ly;
873 dotarray[ins].area = Npix;
874 dotarray[ins].x = dot_x;
875 dotarray[ins].y = dot_y;
876 if (n_dots >= dotarray_size) goto end_loop;
877 }
878 }
879 end_loop:
880 DESTROY_STACK
881 free(Done);
882 Done = 0;
883 return n_dots;
884 }
885
886 /*---------------------------------------------------------------------------*/
887 #ifdef DAFARE
visit_bw(int i,int j,int x,int y,int bit,UCHAR * byte)888 static void visit_bw(int i, int j, int x, int y, int bit, UCHAR *byte) {
889 int ret, next_bit, prev_bit;
890 UCHAR *next_byte, *prev_byte;
891
892 start:
893 ADDBIG(Xsum, x);
894 ADDBIG(Ysum, y);
895 ADDBIG(Weightsum, 1);
896 if (x < Xmin) Xmin = x;
897 if (x > Xmax) Xmax = x;
898 if (y < Ymin) Ymin = y;
899 if (y > Ymax) Ymax = y;
900 Npix++;
901 SET_DONE(i, j);
902
903 next_bit = bit - 1;
904 if (next_bit < 0) {
905 next_bit = 7;
906 next_byte = byte + 1;
907 } else
908 next_byte = byte;
909 if (NOT_DONE(i + 1, j) && ((*next_byte >> next_bit) & 1) == Black_pixel) {
910 PUSH_ONTO_STACK(1, x, y, i, j, bit, byte)
911 i++;
912 x++;
913 bit = next_bit;
914 byte = next_byte;
915 goto start;
916 return_1:;
917 }
918 prev_bit = bit + 1;
919 if (prev_bit > 7) {
920 prev_bit = 0;
921 prev_byte = byte - 1;
922 } else
923 prev_byte = byte;
924 if (NOT_DONE(i - 1, j) && ((*prev_byte >> prev_bit) & 1) == Black_pixel) {
925 PUSH_ONTO_STACK(2, x, y, i, j, bit, byte)
926 i--;
927 x--;
928 bit = prev_bit;
929 byte = prev_byte;
930 goto start;
931 return_2:;
932 }
933 if (NOT_DONE(i, j + 1) && ((*(byte + Pix_ystep) >> bit) & 1) == Black_pixel) {
934 PUSH_ONTO_STACK(3, x, y, i, j, bit, byte)
935 j++;
936 y++;
937 byte += Pix_ystep;
938 goto start;
939 return_3:;
940 }
941 if (NOT_DONE(i, j - 1) && ((*(byte - Pix_ystep) >> bit) & 1) == Black_pixel) {
942 PUSH_ONTO_STACK(4, x, y, i, j, bit, byte)
943 j--;
944 y--;
945 byte -= Pix_ystep;
946 goto start;
947 return_4:;
948 }
949 if (!STACK_IS_EMPTY) {
950 POP_FROM_STACK_U(ret, x, y, i, j, bit, byte);
951 switch (ret) {
952 case 1:
953 goto return_1;
954 case 2:
955 goto return_2;
956 case 3:
957 goto return_3;
958 case 4:
959 goto return_4;
960 default:
961 abort();
962 }
963 }
964 }
965 #endif
966 /*---------------------------------------------------------------------------*/
967
968 #ifdef RECURSIVE_VERSION
969
visit_bw(int i,int j,int x,int y,int bit,UCHAR * byte)970 static void visit_bw(int i, int j, int x, int y, int bit, UCHAR *byte) {
971 int next_bit, prev_bit;
972 UCHAR *next_byte, *prev_byte;
973
974 if (Level >= Max_level)
975 return;
976 else
977 Level++;
978
979 ADDBIG(Xsum, x);
980 ADDBIG(Ysum, y);
981 ADDBIG(Weightsum, 1);
982
983 if (x < Xmin) Xmin = x;
984 if (x > Xmax) Xmax = x;
985 if (y < Ymin) Ymin = y;
986 if (y > Ymax) Ymax = y;
987 Npix++;
988 SET_DONE(i, j);
989
990 next_bit = bit - 1;
991 if (next_bit < 0) {
992 next_byte = byte + 1;
993 next_bit = 7;
994 } else
995 next_byte = byte;
996
997 prev_bit = bit + 1;
998 if (prev_bit > 7) {
999 prev_byte = byte - 1;
1000 prev_bit = 0;
1001 } else
1002 prev_byte = byte;
1003
1004 if (NOT_DONE(i + 1, j) && ((*next_byte >> next_bit) & 1) == Black_pixel)
1005 visit_bw(i + 1, j, x + 1, y, next_bit, next_byte);
1006
1007 if (NOT_DONE(i - 1, j) && ((*prev_byte >> prev_bit) & 1) == Black_pixel)
1008 visit_bw(i - 1, j, x - 1, y, prev_bit, prev_byte);
1009
1010 if (NOT_DONE(i, j + 1) && ((*(byte + Pix_ystep) >> bit) & 1) == Black_pixel)
1011 visit_bw(i, j + 1, x, y + 1, bit, byte + Pix_ystep);
1012
1013 if (NOT_DONE(i, j - 1) && ((*(byte - Pix_ystep) >> bit) & 1) == Black_pixel)
1014 visit_bw(i, j - 1, x, y - 1, bit, byte - Pix_ystep);
1015
1016 Level--;
1017 }
1018
1019 #endif
1020
1021 /*---------------------------------------------------------------------------*/
1022
visit_gr8(int i,int j,int x,int y,UCHAR * pix)1023 static void visit_gr8(int i, int j, int x, int y, UCHAR *pix) {
1024 int weight, ret, dummy;
1025
1026 start:
1027 weight = BLACK_WEIGHT_GR8(pix);
1028 ADDBIG(Xsum, x * weight);
1029 ADDBIG(Ysum, y * weight);
1030 ADDBIG(Weightsum, weight);
1031 if (IS_VERY_BLACK_GR8(pix)) Very_black_found = true;
1032 if (x < Xmin) Xmin = x;
1033 if (x > Xmax) Xmax = x;
1034 if (y < Ymin) Ymin = y;
1035 if (y > Ymax) Ymax = y;
1036 Npix++;
1037 SET_DONE(i, j);
1038
1039 if (NOT_DONE(i + 1, j) && IS_BLACK_GR8(pix + 1)) {
1040 PUSH_ONTO_STACK(1, x, y, i, j, 0, pix)
1041 i++;
1042 x++;
1043 pix++;
1044 goto start;
1045 return_1:;
1046 }
1047 if (NOT_DONE(i - 1, j) && IS_BLACK_GR8(pix - 1)) {
1048 PUSH_ONTO_STACK(2, x, y, i, j, 0, pix)
1049 i--;
1050 x--;
1051 pix--;
1052 goto start;
1053 return_2:;
1054 }
1055 if (NOT_DONE(i, j + 1) && IS_BLACK_GR8(pix + Pix_ystep)) {
1056 PUSH_ONTO_STACK(3, x, y, i, j, 0, pix)
1057 j++;
1058 y++;
1059 pix += Pix_ystep;
1060 goto start;
1061 return_3:;
1062 }
1063 if (NOT_DONE(i, j - 1) && IS_BLACK_GR8(pix - Pix_ystep)) {
1064 PUSH_ONTO_STACK(4, x, y, i, j, 0, pix)
1065 j--;
1066 y--;
1067 pix -= Pix_ystep;
1068 goto start;
1069 return_4:;
1070 }
1071 if (!STACK_IS_EMPTY) {
1072 POP_FROM_STACK_U(ret, x, y, i, j, dummy, pix);
1073 switch (ret) {
1074 case 1:
1075 goto return_1;
1076 case 2:
1077 goto return_2;
1078 case 3:
1079 goto return_3;
1080 case 4:
1081 goto return_4;
1082 default:
1083 abort();
1084 }
1085 }
1086 }
1087
1088 /*---------------------------------------------------------------------------*/
1089
1090 #ifdef RECURSIVE_VERSION
1091
visit_gr8(int i,int j,int x,int y,UCHAR * pix)1092 static void visit_gr8(int i, int j, int x, int y, UCHAR *pix) {
1093 int weight;
1094
1095 if (Level >= Max_level)
1096 return;
1097 else
1098 Level++;
1099
1100 weight = BLACK_WEIGHT_GR8(pix);
1101 ADDBIG(Xsum, x * weight);
1102 ADDBIG(Ysum, y * weight);
1103 ADDBIG(Weightsum, weight);
1104 if (IS_VERY_BLACK_GR8(pix)) Very_black_found = true;
1105 if (x < Xmin) Xmin = x;
1106 if (x > Xmax) Xmax = x;
1107 if (y < Ymin) Ymin = y;
1108 if (y > Ymax) Ymax = y;
1109 Npix++;
1110 SET_DONE(i, j);
1111
1112 if (NOT_DONE(i + 1, j) && IS_BLACK_GR8(pix + 1))
1113 visit_gr8(i + 1, j, x + 1, y, pix + 1);
1114 if (NOT_DONE(i - 1, j) && IS_BLACK_GR8(pix - 1))
1115 visit_gr8(i - 1, j, x - 1, y, pix - 1);
1116 if (NOT_DONE(i, j + 1) && IS_BLACK_GR8(pix + Pix_ystep))
1117 visit_gr8(i, j + 1, x, y + 1, pix + Pix_ystep);
1118 if (NOT_DONE(i, j - 1) && IS_BLACK_GR8(pix - Pix_ystep))
1119 visit_gr8(i, j - 1, x, y - 1, pix - Pix_ystep);
1120
1121 Level--;
1122 }
1123
1124 #endif
1125
1126 /*---------------------------------------------------------------------------*/
1127
visit_rgb(int i,int j,int x,int y,TPixel32 * pix)1128 static void visit_rgb(int i, int j, int x, int y, TPixel32 *pix) {
1129 int weight, ret, dummy;
1130
1131 start:
1132 weight = BLACK_WEIGHT_RGB(pix);
1133 ADDBIG(Xsum, x * weight);
1134 ADDBIG(Ysum, y * weight);
1135 ADDBIG(Weightsum, weight);
1136 if (IS_VERY_BLACK_RGB(pix)) Very_black_found = true;
1137 if (x < Xmin) Xmin = x;
1138 if (x > Xmax) Xmax = x;
1139 if (y < Ymin) Ymin = y;
1140 if (y > Ymax) Ymax = y;
1141 Npix++;
1142 SET_DONE(i, j);
1143
1144 if (NOT_DONE(i + 1, j) && IS_BLACK_RGB(pix + 1)) {
1145 PUSH_ONTO_STACK(1, x, y, i, j, 0, pix)
1146 i++;
1147 x++;
1148 pix += 1;
1149 goto start;
1150 return_1:;
1151 }
1152 if (NOT_DONE(i - 1, j) && IS_BLACK_RGB(pix - 1)) {
1153 PUSH_ONTO_STACK(2, x, y, i, j, 0, pix)
1154 i--;
1155 x--;
1156 pix -= 1;
1157 goto start;
1158 return_2:;
1159 }
1160 if (NOT_DONE(i, j + 1) && IS_BLACK_RGB(pix + Pix_ystep)) {
1161 PUSH_ONTO_STACK(3, x, y, i, j, 0, pix)
1162 j++;
1163 y++;
1164 pix += Pix_ystep;
1165 goto start;
1166 return_3:;
1167 }
1168 if (NOT_DONE(i, j - 1) && IS_BLACK_RGB(pix - Pix_ystep)) {
1169 PUSH_ONTO_STACK(4, x, y, i, j, 0, pix)
1170 j--;
1171 y--;
1172 pix -= Pix_ystep;
1173 goto start;
1174 return_4:;
1175 }
1176 if (!STACK_IS_EMPTY) {
1177 POP_FROM_STACK_TPIXEL32(ret, x, y, i, j, dummy, pix);
1178 switch (ret) {
1179 case 1:
1180 goto return_1;
1181 case 2:
1182 goto return_2;
1183 case 3:
1184 goto return_3;
1185 case 4:
1186 goto return_4;
1187 default:
1188 abort();
1189 }
1190 }
1191 }
1192
1193 /*---------------------------------------------------------------------------*/
1194
1195 #ifdef RECURSIVE_VERSION
1196
visit_rgb(int i,int j,int x,int y,TPixel32 * pix)1197 static void visit_rgb(int i, int j, int x, int y, TPixel32 *pix) {
1198 int weight;
1199
1200 if (Level >= Max_level)
1201 return;
1202 else
1203 Level++;
1204
1205 weight = BLACK_WEIGHT_RGB(pix);
1206 ADDBIG(Xsum, x * weight);
1207 ADDBIG(Ysum, y * weight);
1208 ADDBIG(Weightsum, weight);
1209 if (IS_VERY_BLACK_RGB(pix)) Very_black_found = true;
1210 if (x < Xmin) Xmin = x;
1211 if (x > Xmax) Xmax = x;
1212 if (y < Ymin) Ymin = y;
1213 if (y > Ymax) Ymax = y;
1214 Npix++;
1215 SET_DONE(i, j);
1216
1217 if (NOT_DONE(i + 1, j) && IS_BLACK_RGB(pix + 1))
1218 visit_rgb(i + 1, j, x + 1, y, pix + 1);
1219 if (NOT_DONE(i - 1, j) && IS_BLACK_RGB(pix - 1))
1220 visit_rgb(i - 1, j, x - 1, y, pix - 1);
1221 if (NOT_DONE(i, j + 1) && IS_BLACK_RGB(pix + Pix_ystep))
1222 visit_rgb(i, j + 1, x, y + 1, pix + Pix_ystep);
1223 if (NOT_DONE(i, j - 1) && IS_BLACK_RGB(pix - Pix_ystep))
1224 visit_rgb(i, j - 1, x, y - 1, pix - Pix_ystep);
1225
1226 Level--;
1227 }
1228
1229 #endif
1230
1231 #define PERCENT (40.0 / 100.0)
1232 /*---------------------------------------------------------------------------*/
1233 /*
1234 * Attenzione: tutti i controlli e i calcoli vengono fatti in pixel.
1235 * Quindi bisogna convertire tutti i valori in pixel prima di arrivare a
1236 * questo livello.
1237 * Inoltre: la pegs_side si riferisce alle coordinate di raster.
1238 */
get_image_rotation_and_center(const TRasterP & img,int strip_width,PEGS_SIDE pegs_side,double * p_ang,double * cx,double * cy,DOT ref[],int ref_dot)1239 bool get_image_rotation_and_center(const TRasterP &img, int strip_width,
1240 PEGS_SIDE pegs_side, double *p_ang,
1241 double *cx, double *cy, DOT ref[],
1242 int ref_dot) {
1243 double angle;
1244 int i;
1245 bool found;
1246 float dx, dy;
1247 DOT _dotarray[MAX_DOT];
1248 DOT *dotarray = _dotarray;
1249 int ndot;
1250 int max_area, min_area;
1251
1252 *p_ang = 0.0;
1253
1254 if (Debug_flag) {
1255 for (i = 0; i < ref_dot; i++) {
1256 printf("Reference dot <%d>\n", i);
1257 stampa_dot(ref + i);
1258 }
1259 }
1260
1261 max_area = 0;
1262 if (ref_dot > 0) {
1263 min_area = ref[0].area;
1264 }
1265 for (i = 0; i < ref_dot; i++) {
1266 if (ref[i].area > max_area) {
1267 max_area = ref[i].area;
1268 }
1269 if (ref[i].area < min_area) {
1270 min_area = ref[i].area;
1271 }
1272 }
1273
1274 ndot = find_dots(img, strip_width, pegs_side, dotarray, MAX_DOT, max_area);
1275 if (Debug_flag) printf(">>>> %d dots found\n", ndot);
1276
1277 i = 0;
1278 while (i < ndot) // elimino i dots troppo piccoli
1279 {
1280 if (dotarray[i].area < min_area * PERCENT) {
1281 for (int j = i; j < ndot - 1; j++) dotarray[j] = dotarray[j + 1];
1282 ndot--;
1283 } else
1284 i++;
1285 }
1286
1287 /* controllo il pattern delle perforazioni */
1288 if (ndot <= 1) {
1289 return false;
1290 }
1291
1292 int indexArray[3] = {0, 1, 2};
1293 found = compare_dots(dotarray, ndot, ref, ref_dot, indexArray[0],
1294 indexArray[1], indexArray[2]);
1295
1296 if (Debug_flag)
1297 for (i = 0; i < ndot; i++) {
1298 printf("**** Dot[%d]\n", i);
1299 stampa_dot(dotarray + i);
1300 }
1301
1302 if (!found) return false;
1303
1304 angle = 0;
1305 for (i = 0; i < 2; i++) {
1306 dx = dotarray[indexArray[i + 1]].x - dotarray[indexArray[i]].x;
1307 dy = dotarray[indexArray[i + 1]].y - dotarray[indexArray[i]].y;
1308 switch (pegs_side) {
1309 case PEGS_LEFT:
1310 case PEGS_RIGHT:
1311 angle += dy == 0.0 ? M_PI_2 : atan(dx / dy);
1312 break;
1313 default:
1314 angle -= dx == 0.0 ? M_PI_2 : atan(dy / dx);
1315 break;
1316 }
1317 }
1318
1319 *p_ang = angle / 2;
1320
1321 // Now calculate the center, we have to get the offset of the center for the
1322 // dot at point indexArray[1]
1323 // from the reference and then use the angle to calculate the offsets for the
1324 // center.
1325 //
1326 // It is assumed, that the holes are all on one line.
1327 float pegWidth =
1328 sqrt((ref[ref_dot - 1].x - ref[0].x) * (ref[ref_dot - 1].x - ref[0].x) +
1329 (ref[ref_dot - 1].y - ref[0].y) * (ref[ref_dot - 1].y - ref[0].y));
1330 float refPegOffset = sqrt(
1331 (ref[indexArray[1]].x - ref[0].x) * (ref[indexArray[1]].x - ref[0].x) +
1332 (ref[indexArray[1]].y - ref[0].y) * (ref[indexArray[1]].y - ref[0].y));
1333 *cx = dotarray[indexArray[1]].x +
1334 cos(*p_ang) * (pegWidth / 2.0f - refPegOffset);
1335 *cy = dotarray[indexArray[1]].y +
1336 sin(*p_ang) * (pegWidth / 2.0f - refPegOffset);
1337
1338 if (Debug_flag) {
1339 printf("\nang: %g\ncx : %g\ncy : %g\n\n", *p_ang, *cx, *cy);
1340 }
1341
1342 return true;
1343 }
1344
1345 /*---------------------------------------------------------------------------*/
1346 #define MIN_V 100.0
1347
compare_dots(DOT const dots[],int ndots,DOT reference[],int ref_dot,int & i_ok,int & j_ok,int & k_ok)1348 static bool compare_dots(DOT const dots[], int ndots, DOT reference[],
1349 int ref_dot, int &i_ok, int &j_ok, int &k_ok) {
1350 int found;
1351 int toll;
1352 float tolld;
1353 int i, j, k;
1354 bool *dot_ok = 0;
1355 float *ref_dis = 0, dx, dy;
1356 float vmin, v, dist_i_j, dist_i_k, dist_j_k, del1, del2;
1357 float ref_dis_0_1, ref_dis_1_2;
1358
1359 i_ok = 0;
1360 j_ok = 0;
1361 k_ok = 0;
1362
1363 /* questa funz e' indipendente da posizione e orientamento dei dots */
1364
1365 if (ndots < 1 || ref_dot < 1) {
1366 goto error;
1367 }
1368
1369 /* controllo quanti dots sono realmente buoni per il confronto */
1370 dot_ok = (bool *)calloc(ndots, sizeof(bool));
1371 found = 0;
1372
1373 for (i = 0; i < ndots; i++) {
1374 dot_ok[i] = false;
1375 for (j = 0; j < ref_dot; j++) {
1376 toll = (int)((float)reference[j].area * PERCENT);
1377 if (abs(dots[i].area - reference[j].area) < toll) {
1378 dot_ok[i] = true;
1379 found++;
1380 break;
1381 }
1382 }
1383 }
1384
1385 if (!found) {
1386 goto error;
1387 }
1388
1389 ref_dis = (float *)calloc(ref_dot, sizeof(float));
1390
1391 /* calcolo le distanze di riferimento e la tolleranza stessa */
1392
1393 tolld = (float)reference[0].lx;
1394 if (tolld < reference[0].ly) tolld = (float)reference[0].ly;
1395 for (i = 1; i < ref_dot; i++) {
1396 dx = reference[0].x - reference[i].x;
1397 dy = reference[0].y - reference[i].y;
1398 ref_dis[i - 1] = sqrtf((dx * dx) + (dy * dy));
1399 if (tolld < reference[i].lx) tolld = (float)reference[i].lx;
1400 if (tolld < reference[i].ly) tolld = (float)reference[i].ly;
1401 }
1402
1403 // I suspect that the following expects symmetry in the holes layout...
1404 // Besides, if the layout is not symmetric, the peg is supposed to be rotated
1405 // OR translated
1406 // switching from, say, top to bottom? (Daniele)
1407
1408 i_ok = -1;
1409 v = vmin = 10000000.0;
1410 for (i = 0; i < ndots - 2; i++) {
1411 if (!dot_ok[i]) continue;
1412
1413 for (j = i + 1; j < ndots - 1; j++) {
1414 if (!dot_ok[j]) continue;
1415 for (k = j + 1; k < ndots; k++) {
1416 if (!dot_ok[k]) continue;
1417
1418 // Build square discrepancies from the reference relative hole distances
1419 dx = dots[i].x - dots[j].x;
1420 dy = dots[i].y - dots[j].y;
1421 dist_i_j = sqrtf((dx * dx) + (dy * dy));
1422 dx = dots[i].x - dots[k].x;
1423 dy = dots[i].y - dots[k].y;
1424 dist_i_k = sqrtf((dx * dx) + (dy * dy));
1425 del1 = (dist_i_j - ref_dis[0]);
1426 del2 = (dist_i_k - ref_dis[1]);
1427 v = ((del1 * del1) + (del2 * del2));
1428
1429 // Furthermore, add discrepancies from the reference hole areas
1430 v += abs(dots[i].area -
1431 reference[0].area); // fabs since areas are already squared
1432 v += abs(dots[j].area - reference[1].area);
1433 v += abs(dots[k].area - reference[2].area);
1434
1435 if (v < vmin) {
1436 i_ok = i;
1437 j_ok = j;
1438 k_ok = k;
1439 vmin = v;
1440 }
1441 }
1442 }
1443 }
1444
1445 if (Debug_flag) {
1446 printf("Ho trovato v = %f su %f per %d %d %d \n", v, vmin, i_ok, j_ok,
1447 k_ok);
1448 printf("---- Dot <%d> ----\n", i_ok);
1449 stampa_dot(dots + i_ok);
1450 printf("---- Dot <%d> ----\n", j_ok);
1451 stampa_dot(dots + j_ok);
1452 printf("---- Dot <%d> ----\n", k_ok);
1453 stampa_dot(dots + k_ok);
1454 }
1455
1456 if (i_ok < 0)
1457 goto error;
1458 else {
1459 dx = dots[i_ok].x - dots[j_ok].x;
1460 dy = dots[i_ok].y - dots[j_ok].y;
1461 dist_i_j = sqrtf((dx * dx) + (dy * dy));
1462
1463 dx = dots[k_ok].x - dots[j_ok].x;
1464 dy = dots[k_ok].y - dots[j_ok].y;
1465 dist_j_k = sqrtf((dx * dx) + (dy * dy));
1466
1467 ref_dis_0_1 = ref_dis[0];
1468
1469 dx = reference[1].x - reference[2].x;
1470 dy = reference[1].y - reference[2].y;
1471 ref_dis_1_2 = sqrtf((dx * dx) + (dy * dy));
1472
1473 if (fabsf(dist_i_j - ref_dis_0_1) >= tolld ||
1474 fabsf(dist_j_k - ref_dis_1_2) >= tolld) {
1475 i_ok = 0;
1476 j_ok = 1;
1477 k_ok = 2;
1478 }
1479 }
1480
1481 if (ref_dis) free(ref_dis);
1482 if (dot_ok) free(dot_ok);
1483
1484 return true;
1485
1486 error:
1487 if (ref_dis) free(ref_dis);
1488 if (dot_ok) free(dot_ok);
1489 return false;
1490 }
1491 /*---------------------------------------------------------------------------*/
1492
stampa_dot(DOT const * dot)1493 static void stampa_dot(DOT const *dot) {
1494 printf("Dimensioni: %d,\t%d\n", dot->lx, dot->ly);
1495 printf("Start : %d,\t%d\n", dot->x1, dot->y1);
1496 printf("End : %d,\t%d\n", dot->x2, dot->y2);
1497 printf("Baricentro: %5.3f,\t%5.3f\n", dot->x, dot->y);
1498 printf("Area : %d\n", dot->area);
1499 }
1500