Leptonica 1.82.0
Image processing and image analysis suite
recogident.c
Go to the documentation of this file.
1/*====================================================================*
2 - Copyright (C) 2001 Leptonica. All rights reserved.
3 -
4 - Redistribution and use in source and binary forms, with or without
5 - modification, are permitted provided that the following conditions
6 - are met:
7 - 1. Redistributions of source code must retain the above copyright
8 - notice, this list of conditions and the following disclaimer.
9 - 2. Redistributions in binary form must reproduce the above
10 - copyright notice, this list of conditions and the following
11 - disclaimer in the documentation and/or other materials
12 - provided with the distribution.
13 -
14 - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
15 - ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
16 - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
17 - A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ANY
18 - CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19 - EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20 - PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
21 - PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
22 - OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
23 - NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
24 - SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 *====================================================================*/
26
92#ifdef HAVE_CONFIG_H
93#include <config_auto.h>
94#endif /* HAVE_CONFIG_H */
95
96#include <string.h>
97#include "allheaders.h"
98
99 /* There are two methods for splitting characters: DID and greedy.
100 * The default method is DID. */
101#define SPLIT_WITH_DID 1
102
103 /* Padding on pix1: added before correlations and removed from result */
104static const l_int32 LeftRightPadding = 32;
105
106 /* Parameters for filtering and sorting connected components in splitter */
107static const l_float32 MinFillFactor = 0.10;
108static const l_int32 DefaultMinHeight = 15; /* min unscaled height */
109static const l_int32 MinOverlap1 = 6; /* in pass 1 of boxaSort2d() */
110static const l_int32 MinOverlap2 = 6; /* in pass 2 of boxaSort2d() */
111static const l_int32 MinHeightPass1 = 5; /* min height to start pass 1 */
112
113
114static l_int32 pixCorrelationBestShift(PIX *pix1, PIX *pix2, NUMA *nasum1,
115 NUMA *namoment1, l_int32 area2,
116 l_int32 ycent2, l_int32 maxyshift,
117 l_int32 *tab8, l_int32 *pdelx,
118 l_int32 *pdely, l_float32 *pscore,
119 l_int32 debugflag );
120static L_RCH *rchCreate(l_int32 index, l_float32 score, char *text,
121 l_int32 sample, l_int32 xloc, l_int32 yloc,
122 l_int32 width);
123static L_RCHA *rchaCreate();
124static l_int32 transferRchToRcha(L_RCH *rch, L_RCHA *rcha);
125static PIX *recogPreSplittingFilter(L_RECOG *recog, PIX *pixs, l_int32 minh,
126 l_float32 minaf, l_int32 debug);
127static l_int32 recogSplittingFilter(L_RECOG *recog, PIX *pixs, l_int32 min,
128 l_float32 minaf, l_int32 *premove,
129 l_int32 debug);
130static void l_showIndicatorSplitValues(NUMA *na1, NUMA *na2, NUMA *na3,
131 NUMA *na4, NUMA *na5, NUMA *na6);
132
133/*------------------------------------------------------------------------*
134 * Identification
135 *------------------------------------------------------------------------*/
161l_ok
163 PIX *pixs,
164 l_int32 minh,
165 l_int32 skipsplit,
166 BOXA **pboxa,
167 PIXA **ppixa,
168 PIX **ppixdb,
169 l_int32 debugsplit)
170{
171l_int32 n;
172BOXA *boxa;
173PIX *pixb;
174PIXA *pixa;
175
176 PROCNAME("recogIdentifyMultiple");
177
178 if (pboxa) *pboxa = NULL;
179 if (ppixa) *ppixa = NULL;
180 if (ppixdb) *ppixdb = NULL;
181 if (!recog)
182 return ERROR_INT("recog not defined", procName, 2);
183 if (!recog->train_done)
184 return ERROR_INT("training not finished", procName, 2);
185 if (!pixs)
186 return ERROR_INT("pixs not defined", procName, 2);
187
188 /* Binarize if necessary */
189 if (pixGetDepth(pixs) > 1)
190 pixb = pixConvertTo1(pixs, recog->threshold);
191 else
192 pixb = pixClone(pixs);
193
194 /* Noise removal and splitting of touching characters */
195 recogSplitIntoCharacters(recog, pixb, minh, skipsplit, &boxa, &pixa,
196 debugsplit);
197 pixDestroy(&pixb);
198 if (!pixa || (n = pixaGetCount(pixa)) == 0) {
199 pixaDestroy(&pixa);
200 boxaDestroy(&boxa);
201 L_WARNING("nothing found\n", procName);
202 return 1;
203 }
204
205 recogIdentifyPixa(recog, pixa, ppixdb);
206 if (pboxa)
207 *pboxa = boxa;
208 else
209 boxaDestroy(&boxa);
210 if (ppixa)
211 *ppixa = pixa;
212 else
213 pixaDestroy(&pixa);
214 return 0;
215}
216
217
218/*------------------------------------------------------------------------*
219 * Segmentation and noise removal *
220 *------------------------------------------------------------------------*/
249l_ok
251 PIX *pixs,
252 l_int32 minh,
253 l_int32 skipsplit,
254 BOXA **pboxa,
255 PIXA **ppixa,
256 l_int32 debug)
257{
258static l_int32 ind = 0;
259char buf[32];
260l_int32 i, xoff, yoff, empty, maxw, bw, ncomp, scaling;
261BOX *box;
262BOXA *boxa1, *boxa2, *boxa3, *boxa4, *boxad;
263BOXAA *baa;
264PIX *pix, *pix1, *pix2, *pix3;
265PIXA *pixa;
266
267 PROCNAME("recogSplitIntoCharacters");
268
269 lept_mkdir("lept/recog");
270
271 if (pboxa) *pboxa = NULL;
272 if (ppixa) *ppixa = NULL;
273 if (!pboxa || !ppixa)
274 return ERROR_INT("&boxa and &pixa not defined", procName, 1);
275 if (!recog)
276 return ERROR_INT("recog not defined", procName, 1);
277 if (!recog->train_done)
278 return ERROR_INT("training not finished", procName, 1);
279 if (!pixs || pixGetDepth(pixs) != 1)
280 return ERROR_INT("pixs not defined or not 1 bpp", procName, 1);
281 if (minh <= 0) minh = DefaultMinHeight;
282 pixZero(pixs, &empty);
283 if (empty) return 1;
284
285 /* Small vertical close for consolidation. Don't do a horizontal
286 * closing, because it might join separate characters. */
287 pix1 = pixMorphSequence(pixs, "c1.3", 0);
288
289 /* Carefully filter out noise */
290 pix2 = recogPreSplittingFilter(recog, pix1, minh, MinFillFactor, debug);
291 pixDestroy(&pix1);
292
293 /* Get the 8-connected components to be split/identified */
294 boxa1 = pixConnComp(pix2, NULL, 8);
295 pixDestroy(&pix2);
296 ncomp = boxaGetCount(boxa1);
297 if (ncomp == 0) {
298 boxaDestroy(&boxa1);
299 L_WARNING("all components removed\n", procName);
300 return 1;
301 }
302
303 /* Save everything and split the large components */
304 boxa2 = boxaCreate(ncomp);
305 maxw = recog->maxwidth_u + 5;
306 scaling = (recog->scalew > 0 || recog->scaleh > 0) ? TRUE : FALSE;
307 pixa = (debug) ? pixaCreate(ncomp) : NULL;
308 for (i = 0; i < ncomp; i++) {
309 box = boxaGetBox(boxa1, i, L_CLONE);
310 boxGetGeometry(box, &xoff, &yoff, &bw, NULL);
311 /* Treat as one character if it is small, if the images
312 * have been scaled, or if splitting is not to be run. */
313 if (bw <= maxw || scaling || skipsplit) {
314 boxaAddBox(boxa2, box, L_INSERT);
315 } else {
316 pix = pixClipRectangle(pixs, box, NULL);
317#if SPLIT_WITH_DID
318 if (!debug) {
319 boxa3 = recogDecode(recog, pix, 2, NULL);
320 } else {
321 boxa3 = recogDecode(recog, pix, 2, &pix2);
322 pixaAddPix(pixa, pix2, L_INSERT);
323 }
324#else /* use greedy splitting */
325 recogCorrelationBestRow(recog, pix, &boxa3, NULL, NULL,
326 NULL, debug);
327 if (debug) {
328 pix2 = pixConvertTo32(pix);
329 pixRenderBoxaArb(pix2, boxa3, 2, 255, 0, 0);
330 pixaAddPix(pixa, pix2, L_INSERT);
331 }
332#endif /* SPLIT_WITH_DID */
333 pixDestroy(&pix);
334 boxDestroy(&box);
335 if (!boxa3) {
336 L_ERROR("boxa3 not found for component %d\n", procName, i);
337 } else {
338 boxa4 = boxaTransform(boxa3, xoff, yoff, 1.0, 1.0);
339 boxaJoin(boxa2, boxa4, 0, -1);
340 boxaDestroy(&boxa3);
341 boxaDestroy(&boxa4);
342 }
343 }
344 }
345 boxaDestroy(&boxa1);
346 if (pixa) { /* debug */
347 pix3 = pixaDisplayTiledInColumns(pixa, 1, 1.0, 20, 2);
348 snprintf(buf, sizeof(buf), "/tmp/lept/recog/decode-%d.png", ind++);
349 pixWrite(buf, pix3, IFF_PNG);
350 pixaDestroy(&pixa);
351 pixDestroy(&pix3);
352 }
353
354 /* Do a 2D sort on the bounding boxes, and flatten the result to 1D.
355 * For the 2D sort, to add a box to an existing boxa, we require
356 * specified minimum vertical overlaps for the first two passes
357 * of the 2D sort. In pass 1, only components with sufficient
358 * height can start a new boxa. */
359 baa = boxaSort2d(boxa2, NULL, MinOverlap1, MinOverlap2, MinHeightPass1);
360 boxa3 = boxaaFlattenToBoxa(baa, NULL, L_CLONE);
361 boxaaDestroy(&baa);
362 boxaDestroy(&boxa2);
363
364 /* Remove smaller components of overlapping pairs.
365 * We only remove the small component if the overlap is
366 * at least half its area and if its area is no more
367 * than 30% of the area of the large component. Because the
368 * components are in a flattened 2D sort, we don't need to
369 * look far ahead in the array to find all overlapping boxes;
370 * 10 boxes is plenty. */
371 boxad = boxaHandleOverlaps(boxa3, L_COMBINE, 10, 0.5, 0.3, NULL);
372 boxaDestroy(&boxa3);
373
374 /* Extract and save the image pieces from the input image. */
375 *ppixa = pixClipRectangles(pixs, boxad);
376 *pboxa = boxad;
377 return 0;
378}
379
380
381/*------------------------------------------------------------------------*
382 * Greedy character splitting *
383 *------------------------------------------------------------------------*/
404l_ok
406 PIX *pixs,
407 BOXA **pboxa,
408 NUMA **pnascore,
409 NUMA **pnaindex,
410 SARRAY **psachar,
411 l_int32 debug)
412{
413char *charstr;
414l_int32 index, remove, w, h, bx, bw, bxc, bwc, w1, w2, w3;
415l_float32 score;
416BOX *box, *boxc, *boxtrans, *boxl, *boxr, *boxlt, *boxrt;
417BOXA *boxat;
418NUMA *nascoret, *naindext, *nasort;
419PIX *pixb, *pixc, *pixl, *pixr, *pixdb, *pixd;
420PIXA *pixar, *pixadb;
421SARRAY *sachart;
422
423l_int32 iter;
424
425 PROCNAME("recogCorrelationBestRow");
426
427 if (pnascore) *pnascore = NULL;
428 if (pnaindex) *pnaindex = NULL;
429 if (psachar) *psachar = NULL;
430 if (!pboxa)
431 return ERROR_INT("&boxa not defined", procName, 1);
432 *pboxa = NULL;
433 if (!recog)
434 return ERROR_INT("recog not defined", procName, 1);
435 if (!pixs || pixGetDepth(pixs) != 1)
436 return ERROR_INT("pixs not defined or not 1 bpp", procName, 1);
437 if (pixGetWidth(pixs) < recog->minwidth_u - 4)
438 return ERROR_INT("pixs too narrow", procName, 1);
439 if (!recog->train_done)
440 return ERROR_INT("training not finished", procName, 1);
441
442 /* Binarize and crop to foreground if necessary */
443 pixb = recogProcessToIdentify(recog, pixs, 0);
444
445 /* Initialize the arrays */
446 boxat = boxaCreate(4);
447 nascoret = numaCreate(4);
448 naindext = numaCreate(4);
449 sachart = sarrayCreate(4);
450 pixadb = (debug) ? pixaCreate(4) : NULL;
451
452 /* Initialize the images remaining to be processed with the input.
453 * These are stored in pixar, which is used here as a queue,
454 * on which we only put image fragments that are large enough to
455 * contain at least one character. */
456 pixar = pixaCreate(1);
457 pixGetDimensions(pixb, &w, &h, NULL);
458 box = boxCreate(0, 0, w, h);
459 pixaAddPix(pixar, pixb, L_INSERT);
460 pixaAddBox(pixar, box, L_INSERT);
461
462 /* Successively split on the best match until nothing is left.
463 * To be safe, we limit the search to 10 characters. */
464 for (iter = 0; iter < 11; iter++) {
465 if (pixaGetCount(pixar) == 0)
466 break;
467 if (iter == 10) {
468 L_WARNING("more than 10 chars; ending search\n", procName);
469 break;
470 }
471
472 /* Pop one from the queue */
473 pixaRemovePixAndSave(pixar, 0, &pixc, &boxc);
474 boxGetGeometry(boxc, &bxc, NULL, &bwc, NULL);
475
476 /* This is a single component; if noise, remove it */
477 recogSplittingFilter(recog, pixc, 0, MinFillFactor, &remove, debug);
478 if (debug)
479 lept_stderr("iter = %d, removed = %d\n", iter, remove);
480 if (remove) {
481 pixDestroy(&pixc);
482 boxDestroy(&boxc);
483 continue;
484 }
485
486 /* Find the best character match */
487 if (debug) {
488 recogCorrelationBestChar(recog, pixc, &box, &score,
489 &index, &charstr, &pixdb);
490 pixaAddPix(pixadb, pixdb, L_INSERT);
491 } else {
492 recogCorrelationBestChar(recog, pixc, &box, &score,
493 &index, &charstr, NULL);
494 }
495
496 /* Find the box in original coordinates, and append
497 * the results to the arrays. */
498 boxtrans = boxTransform(box, bxc, 0, 1.0, 1.0);
499 boxaAddBox(boxat, boxtrans, L_INSERT);
500 numaAddNumber(nascoret, score);
501 numaAddNumber(naindext, index);
502 sarrayAddString(sachart, charstr, L_INSERT);
503
504 /* Split the current pixc into three regions and save
505 * each region if it is large enough. */
506 boxGetGeometry(box, &bx, NULL, &bw, NULL);
507 w1 = bx;
508 w2 = bw;
509 w3 = bwc - bx - bw;
510 if (debug)
511 lept_stderr(" w1 = %d, w2 = %d, w3 = %d\n", w1, w2, w3);
512 if (w1 < recog->minwidth_u - 4) {
513 if (debug) L_INFO("discarding width %d on left\n", procName, w1);
514 } else { /* extract and save left region */
515 boxl = boxCreate(0, 0, bx + 1, h);
516 pixl = pixClipRectangle(pixc, boxl, NULL);
517 boxlt = boxTransform(boxl, bxc, 0, 1.0, 1.0);
518 pixaAddPix(pixar, pixl, L_INSERT);
519 pixaAddBox(pixar, boxlt, L_INSERT);
520 boxDestroy(&boxl);
521 }
522 if (w3 < recog->minwidth_u - 4) {
523 if (debug) L_INFO("discarding width %d on right\n", procName, w3);
524 } else { /* extract and save left region */
525 boxr = boxCreate(bx + bw - 1, 0, w3 + 1, h);
526 pixr = pixClipRectangle(pixc, boxr, NULL);
527 boxrt = boxTransform(boxr, bxc, 0, 1.0, 1.0);
528 pixaAddPix(pixar, pixr, L_INSERT);
529 pixaAddBox(pixar, boxrt, L_INSERT);
530 boxDestroy(&boxr);
531 }
532 pixDestroy(&pixc);
533 boxDestroy(&box);
534 boxDestroy(&boxc);
535 }
536 pixaDestroy(&pixar);
537
538
539 /* Sort the output results by left-to-right in the boxa */
540 *pboxa = boxaSort(boxat, L_SORT_BY_X, L_SORT_INCREASING, &nasort);
541 if (pnascore)
542 *pnascore = numaSortByIndex(nascoret, nasort);
543 if (pnaindex)
544 *pnaindex = numaSortByIndex(naindext, nasort);
545 if (psachar)
546 *psachar = sarraySortByIndex(sachart, nasort);
547 numaDestroy(&nasort);
548 boxaDestroy(&boxat);
549 numaDestroy(&nascoret);
550 numaDestroy(&naindext);
551 sarrayDestroy(&sachart);
552
553 /* Final debug output */
554 if (debug) {
555 pixd = pixaDisplayTiledInRows(pixadb, 32, 2000, 1.0, 0, 15, 2);
556 pixDisplay(pixd, 400, 400);
557 pixaAddPix(recog->pixadb_split, pixd, L_INSERT);
558 pixaDestroy(&pixadb);
559 }
560 return 0;
561}
562
563
586l_ok
588 PIX *pixs,
589 BOX **pbox,
590 l_float32 *pscore,
591 l_int32 *pindex,
592 char **pcharstr,
593 PIX **ppixdb)
594{
595l_int32 i, n, w1, h1, w2, area2, ycent2, delx, dely;
596l_int32 bestdelx, bestdely, bestindex;
597l_float32 score, bestscore;
598BOX *box;
599BOXA *boxa;
600NUMA *nasum, *namoment;
601PIX *pix1, *pix2;
602
603 PROCNAME("recogCorrelationBestChar");
604
605 if (pindex) *pindex = 0;
606 if (pcharstr) *pcharstr = NULL;
607 if (ppixdb) *ppixdb = NULL;
608 if (pbox) *pbox = NULL;
609 if (pscore) *pscore = 0.0;
610 if (!pbox || !pscore)
611 return ERROR_INT("&box and &score not both defined", procName, 1);
612 if (!recog)
613 return ERROR_INT("recog not defined", procName, 1);
614 if (!pixs || pixGetDepth(pixs) != 1)
615 return ERROR_INT("pixs not defined or not 1 bpp", procName, 1);
616 if (!recog->train_done)
617 return ERROR_INT("training not finished", procName, 1);
618
619 /* Binarize and crop to foreground if necessary. Add padding
620 * to both the left and right side; this is compensated for
621 * when reporting the bounding box of the best matched character. */
622 pix1 = recogProcessToIdentify(recog, pixs, LeftRightPadding);
623 pixGetDimensions(pix1, &w1, &h1, NULL);
624
625 /* Compute vertical sum and moment arrays */
626 nasum = pixCountPixelsByColumn(pix1);
627 namoment = pixGetMomentByColumn(pix1, 1);
628
629 /* Do shifted correlation against all averaged templates. */
630 n = recog->setsize;
631 boxa = boxaCreate(n); /* location of best fits for each character */
632 bestscore = 0.0;
633 bestindex = bestdelx = bestdely = 0;
634 for (i = 0; i < n; i++) {
635 pix2 = pixaGetPix(recog->pixa_u, i, L_CLONE);
636 w2 = pixGetWidth(pix2);
637 /* Note that the slightly expended w1 is typically larger
638 * than w2 (the template). */
639 if (w1 >= w2) {
640 numaGetIValue(recog->nasum_u, i, &area2);
641 ptaGetIPt(recog->pta_u, i, NULL, &ycent2);
642 pixCorrelationBestShift(pix1, pix2, nasum, namoment, area2, ycent2,
643 recog->maxyshift, recog->sumtab, &delx,
644 &dely, &score, 1);
645 if (ppixdb) {
647 "Best match template %d: (x,y) = (%d,%d), score = %5.3f\n",
648 i, delx, dely, score);
649 }
650 /* Compensate for padding */
651 box = boxCreate(delx - LeftRightPadding, 0, w2, h1);
652 if (score > bestscore) {
653 bestscore = score;
654 bestdelx = delx - LeftRightPadding;
655 bestdely = dely;
656 bestindex = i;
657 }
658 } else {
659 box = boxCreate(0, 0, 1, 1); /* placeholder */
660 if (ppixdb)
661 lept_stderr("Component too thin: w1 = %d, w2 = %d\n", w1, w2);
662 }
663 boxaAddBox(boxa, box, L_INSERT);
664 pixDestroy(&pix2);
665 }
666
667 *pscore = bestscore;
668 *pbox = boxaGetBox(boxa, bestindex, L_COPY);
669 if (pindex) *pindex = bestindex;
670 if (pcharstr)
671 recogGetClassString(recog, bestindex, pcharstr);
672
673 if (ppixdb) {
674 L_INFO("Best match: class %d; shifts (%d, %d)\n",
675 procName, bestindex, bestdelx, bestdely);
676 pix2 = pixaGetPix(recog->pixa_u, bestindex, L_CLONE);
677 *ppixdb = recogShowMatch(recog, pix1, pix2, NULL, -1, 0.0);
678 pixDestroy(&pix2);
679 }
680
681 pixDestroy(&pix1);
682 boxaDestroy(&boxa);
683 numaDestroy(&nasum);
684 numaDestroy(&namoment);
685 return 0;
686}
687
688
728static l_int32
730 PIX *pix2,
731 NUMA *nasum1,
732 NUMA *namoment1,
733 l_int32 area2,
734 l_int32 ycent2,
735 l_int32 maxyshift,
736 l_int32 *tab8,
737 l_int32 *pdelx,
738 l_int32 *pdely,
739 l_float32 *pscore,
740 l_int32 debugflag)
741{
742l_int32 w1, w2, h1, h2, i, j, nx, shifty, delx, dely;
743l_int32 sum, moment, count;
744l_int32 *tab, *area1, *arraysum, *arraymoment;
745l_float32 maxscore, score;
746l_float32 *ycent1;
747FPIX *fpix;
748PIX *pixt, *pixt1, *pixt2;
749
750 PROCNAME("pixCorrelationBestShift");
751
752 if (pdelx) *pdelx = 0;
753 if (pdely) *pdely = 0;
754 if (pscore) *pscore = 0.0;
755 if (!pix1 || pixGetDepth(pix1) != 1)
756 return ERROR_INT("pix1 not defined or not 1 bpp", procName, 1);
757 if (!pix2 || pixGetDepth(pix2) != 1)
758 return ERROR_INT("pix2 not defined or not 1 bpp", procName, 1);
759 if (!nasum1 || !namoment1)
760 return ERROR_INT("nasum1 and namoment1 not both defined", procName, 1);
761 if (area2 <= 0 || ycent2 <= 0)
762 return ERROR_INT("area2 and ycent2 must be > 0", procName, 1);
763
764 /* If pix1 (the unknown image) is narrower than pix2,
765 * don't bother to try the match. pix1 is already padded with
766 * 2 pixels on each side. */
767 pixGetDimensions(pix1, &w1, &h1, NULL);
768 pixGetDimensions(pix2, &w2, &h2, NULL);
769 if (w1 < w2) {
770 if (debugflag > 0) {
771 L_INFO("skipping match with w1 = %d and w2 = %d\n",
772 procName, w1, w2);
773 }
774 return 0;
775 }
776 nx = w1 - w2 + 1;
777
778 if (debugflag > 0)
779 fpix = fpixCreate(nx, 2 * maxyshift + 1);
780 if (!tab8)
781 tab = makePixelSumTab8();
782 else
783 tab = tab8;
784
785 /* Set up the arrays for area1 and ycent1. We have to do this
786 * for each template (pix2) because the window width is w2. */
787 area1 = (l_int32 *)LEPT_CALLOC(nx, sizeof(l_int32));
788 ycent1 = (l_float32 *)LEPT_CALLOC(nx, sizeof(l_int32));
789 arraysum = numaGetIArray(nasum1);
790 arraymoment = numaGetIArray(namoment1);
791 for (i = 0, sum = 0, moment = 0; i < w2; i++) {
792 sum += arraysum[i];
793 moment += arraymoment[i];
794 }
795 for (i = 0; i < nx - 1; i++) {
796 area1[i] = sum;
797 ycent1[i] = (sum == 0) ? ycent2 : (l_float32)moment / (l_float32)sum;
798 sum += arraysum[w2 + i] - arraysum[i];
799 moment += arraymoment[w2 + i] - arraymoment[i];
800 }
801 area1[nx - 1] = sum;
802 ycent1[nx - 1] = (sum == 0) ? ycent2 : (l_float32)moment / (l_float32)sum;
803
804 /* Find the best match location for pix2. At each location,
805 * to insure that pixels are ON only within the intersection of
806 * pix and the shifted pix2:
807 * (1) Start with pixt cleared and equal in size to pix1.
808 * (2) Blit the shifted pix2 onto pixt. Then all ON pixels
809 * are within the intersection of pix1 and the shifted pix2.
810 * (3) AND pix1 with pixt. */
811 pixt = pixCreate(w2, h1, 1);
812 maxscore = 0;
813 delx = 0;
814 dely = 0; /* amount to shift pix2 relative to pix1 to get alignment */
815 for (i = 0; i < nx; i++) {
816 shifty = (l_int32)(ycent1[i] - ycent2 + 0.5);
817 for (j = -maxyshift; j <= maxyshift; j++) {
818 pixClearAll(pixt);
819 pixRasterop(pixt, 0, shifty + j, w2, h2, PIX_SRC, pix2, 0, 0);
820 pixRasterop(pixt, 0, 0, w2, h1, PIX_SRC & PIX_DST, pix1, i, 0);
821 pixCountPixels(pixt, &count, tab);
822 score = (l_float32)count * (l_float32)count /
823 ((l_float32)area1[i] * (l_float32)area2);
824 if (score > maxscore) {
825 maxscore = score;
826 delx = i;
827 dely = shifty + j;
828 }
829
830 if (debugflag > 0)
831 fpixSetPixel(fpix, i, maxyshift + j, 1000.0 * score);
832 }
833 }
834
835 if (debugflag > 0) {
836 char buf[128];
837 lept_mkdir("lept/recog");
838 pixt1 = fpixDisplayMaxDynamicRange(fpix);
839 pixt2 = pixExpandReplicate(pixt1, 5);
840 snprintf(buf, sizeof(buf), "/tmp/lept/recog/junkbs_%d.png", debugflag);
841 pixWrite(buf, pixt2, IFF_PNG);
842 pixDestroy(&pixt1);
843 pixDestroy(&pixt2);
844 fpixDestroy(&fpix);
845 }
846
847 if (pdelx) *pdelx = delx;
848 if (pdely) *pdely = dely;
849 if (pscore) *pscore = maxscore;
850 if (!tab8) LEPT_FREE(tab);
851 LEPT_FREE(area1);
852 LEPT_FREE(ycent1);
853 LEPT_FREE(arraysum);
854 LEPT_FREE(arraymoment);
855 pixDestroy(&pixt);
856 return 0;
857}
858
859
860/*------------------------------------------------------------------------*
861 * Low-level identification *
862 *------------------------------------------------------------------------*/
881l_ok
883 PIXA *pixa,
884 PIX **ppixdb)
885{
886char *text;
887l_int32 i, n, fail, index, depth;
888l_float32 score;
889PIX *pix1, *pix2, *pix3;
890PIXA *pixa1;
891L_RCH *rch;
892
893 PROCNAME("recogIdentifyPixa");
894
895 if (ppixdb) *ppixdb = NULL;
896 if (!recog)
897 return ERROR_INT("recog not defined", procName, 1);
898 if (!pixa)
899 return ERROR_INT("pixa not defined", procName, 1);
900
901 /* Run the recognizer on the set of images. This writes
902 * the text string into each pix in pixa. */
903 n = pixaGetCount(pixa);
904 rchaDestroy(&recog->rcha);
905 recog->rcha = rchaCreate();
906 pixa1 = (ppixdb) ? pixaCreate(n) : NULL;
907 depth = 1;
908 for (i = 0; i < n; i++) {
909 pix1 = pixaGetPix(pixa, i, L_CLONE);
910 pix2 = NULL;
911 fail = FALSE;
912 if (!ppixdb)
913 fail = recogIdentifyPix(recog, pix1, NULL);
914 else
915 fail = recogIdentifyPix(recog, pix1, &pix2);
916 if (fail)
917 recogSkipIdentify(recog);
918 if ((rch = recog->rch) == NULL) {
919 L_ERROR("rch not found for char %d\n", procName, i);
920 pixDestroy(&pix1);
921 pixDestroy(&pix2);
922 continue;
923 }
924 rchExtract(rch, NULL, NULL, &text, NULL, NULL, NULL, NULL);
925 pixSetText(pix1, text);
926 LEPT_FREE(text);
927 if (ppixdb) {
928 rchExtract(rch, &index, &score, NULL, NULL, NULL, NULL, NULL);
929 pix3 = recogShowMatch(recog, pix2, NULL, NULL, index, score);
930 if (i == 0) depth = pixGetDepth(pix3);
931 pixaAddPix(pixa1, pix3, L_INSERT);
932 pixDestroy(&pix2);
933 }
934 transferRchToRcha(rch, recog->rcha);
935 pixDestroy(&pix1);
936 }
937
938 /* Package the images for debug */
939 if (ppixdb) {
940 *ppixdb = pixaDisplayTiledInRows(pixa1, depth, 2500, 1.0, 0, 20, 1);
941 pixaDestroy(&pixa1);
942 }
943
944 return 0;
945}
946
947
974l_ok
976 PIX *pixs,
977 PIX **ppixdb)
978{
979char *text;
980l_int32 i, j, n, bestindex, bestsample, area1, area2;
981l_int32 shiftx, shifty, bestdelx, bestdely, bestwidth, maxyshift;
982l_float32 x1, y1, x2, y2, delx, dely, score, maxscore;
983NUMA *numa;
984PIX *pix0, *pix1, *pix2;
985PIXA *pixa;
986PTA *pta;
987
988 PROCNAME("recogIdentifyPix");
989
990 if (ppixdb) *ppixdb = NULL;
991 if (!recog)
992 return ERROR_INT("recog not defined", procName, 1);
993 if (!pixs || pixGetDepth(pixs) != 1)
994 return ERROR_INT("pixs not defined or not 1 bpp", procName, 1);
995
996 /* Do the averaging if required and not yet done. */
997 if (recog->templ_use == L_USE_AVERAGE_TEMPLATES && !recog->ave_done) {
998 recogAverageSamples(&recog, 0);
999 if (!recog)
1000 return ERROR_INT("averaging failed", procName, 1);
1001 }
1002
1003 /* Binarize and crop to foreground if necessary */
1004 if ((pix0 = recogProcessToIdentify(recog, pixs, 0)) == NULL)
1005 return ERROR_INT("no fg pixels in pix0", procName, 1);
1006
1007 /* Optionally scale and/or convert to fixed stroke width */
1008 pix1 = recogModifyTemplate(recog, pix0);
1009 pixDestroy(&pix0);
1010 if (!pix1)
1011 return ERROR_INT("no fg pixels in pix1", procName, 1);
1012
1013 /* Do correlation at all positions within +-maxyshift of
1014 * the nominal centroid alignment. */
1015 pixCountPixels(pix1, &area1, recog->sumtab);
1016 pixCentroid(pix1, recog->centtab, recog->sumtab, &x1, &y1);
1017 bestindex = bestsample = bestdelx = bestdely = bestwidth = 0;
1018 maxscore = 0.0;
1019 maxyshift = recog->maxyshift;
1020 if (recog->templ_use == L_USE_AVERAGE_TEMPLATES) {
1021 for (i = 0; i < recog->setsize; i++) {
1022 numaGetIValue(recog->nasum, i, &area2);
1023 if (area2 == 0) continue; /* no template available */
1024 pix2 = pixaGetPix(recog->pixa, i, L_CLONE);
1025 ptaGetPt(recog->pta, i, &x2, &y2);
1026 delx = x1 - x2;
1027 dely = y1 - y2;
1028 for (shifty = -maxyshift; shifty <= maxyshift; shifty++) {
1029 for (shiftx = -maxyshift; shiftx <= maxyshift; shiftx++) {
1030 pixCorrelationScoreSimple(pix1, pix2, area1, area2,
1031 delx + shiftx, dely + shifty,
1032 5, 5, recog->sumtab, &score);
1033 if (score > maxscore) {
1034 bestindex = i;
1035 bestdelx = delx + shiftx;
1036 bestdely = dely + shifty;
1037 maxscore = score;
1038 }
1039 }
1040 }
1041 pixDestroy(&pix2);
1042 }
1043 } else { /* use all the samples */
1044 for (i = 0; i < recog->setsize; i++) {
1045 pixa = pixaaGetPixa(recog->pixaa, i, L_CLONE);
1046 n = pixaGetCount(pixa);
1047 if (n == 0) {
1048 pixaDestroy(&pixa);
1049 continue;
1050 }
1051 numa = numaaGetNuma(recog->naasum, i, L_CLONE);
1052 pta = ptaaGetPta(recog->ptaa, i, L_CLONE);
1053 for (j = 0; j < n; j++) {
1054 pix2 = pixaGetPix(pixa, j, L_CLONE);
1055 numaGetIValue(numa, j, &area2);
1056 ptaGetPt(pta, j, &x2, &y2);
1057 delx = x1 - x2;
1058 dely = y1 - y2;
1059 for (shifty = -maxyshift; shifty <= maxyshift; shifty++) {
1060 for (shiftx = -maxyshift; shiftx <= maxyshift; shiftx++) {
1061 pixCorrelationScoreSimple(pix1, pix2, area1, area2,
1062 delx + shiftx, dely + shifty,
1063 5, 5, recog->sumtab, &score);
1064 if (score > maxscore) {
1065 bestindex = i;
1066 bestsample = j;
1067 bestdelx = delx + shiftx;
1068 bestdely = dely + shifty;
1069 maxscore = score;
1070 bestwidth = pixGetWidth(pix2);
1071 }
1072 }
1073 }
1074 pixDestroy(&pix2);
1075 }
1076 pixaDestroy(&pixa);
1077 numaDestroy(&numa);
1078 ptaDestroy(&pta);
1079 }
1080 }
1081
1082 /* Package up the results */
1083 recogGetClassString(recog, bestindex, &text);
1084 rchDestroy(&recog->rch);
1085 recog->rch = rchCreate(bestindex, maxscore, text, bestsample,
1086 bestdelx, bestdely, bestwidth);
1087
1088 if (ppixdb) {
1089 if (recog->templ_use == L_USE_AVERAGE_TEMPLATES) {
1090 L_INFO("Best match: str %s; class %d; sh (%d, %d); score %5.3f\n",
1091 procName, text, bestindex, bestdelx, bestdely, maxscore);
1092 pix2 = pixaGetPix(recog->pixa, bestindex, L_CLONE);
1093 } else { /* L_USE_ALL_TEMPLATES */
1094 L_INFO("Best match: str %s; sample %d in class %d; score %5.3f\n",
1095 procName, text, bestsample, bestindex, maxscore);
1096 if (maxyshift > 0 && (L_ABS(bestdelx) > 0 || L_ABS(bestdely) > 0)) {
1097 L_INFO(" Best shift: (%d, %d)\n",
1098 procName, bestdelx, bestdely);
1099 }
1100 pix2 = pixaaGetPix(recog->pixaa, bestindex, bestsample, L_CLONE);
1101 }
1102 *ppixdb = recogShowMatch(recog, pix1, pix2, NULL, -1, 0.0);
1103 pixDestroy(&pix2);
1104 }
1105
1106 pixDestroy(&pix1);
1107 return 0;
1108}
1109
1110
1123l_ok
1125{
1126 PROCNAME("recogSkipIdentify");
1127
1128 if (!recog)
1129 return ERROR_INT("recog not defined", procName, 1);
1130
1131 /* Package up placeholder results */
1132 rchDestroy(&recog->rch);
1133 recog->rch = rchCreate(0, 0.0, stringNew(""), 0, 0, 0, 0);
1134 return 0;
1135}
1136
1137
1138/*------------------------------------------------------------------------*
1139 * Operations for handling identification results *
1140 *------------------------------------------------------------------------*/
1149static L_RCHA *
1151{
1152L_RCHA *rcha;
1153
1154 rcha = (L_RCHA *)LEPT_CALLOC(1, sizeof(L_RCHA));
1155 rcha->naindex = numaCreate(0);
1156 rcha->nascore = numaCreate(0);
1157 rcha->satext = sarrayCreate(0);
1158 rcha->nasample = numaCreate(0);
1159 rcha->naxloc = numaCreate(0);
1160 rcha->nayloc = numaCreate(0);
1161 rcha->nawidth = numaCreate(0);
1162 return rcha;
1163}
1164
1165
1171void
1173{
1174L_RCHA *rcha;
1175
1176 PROCNAME("rchaDestroy");
1177
1178 if (prcha == NULL) {
1179 L_WARNING("&rcha is null!\n", procName);
1180 return;
1181 }
1182 if ((rcha = *prcha) == NULL)
1183 return;
1184
1185 numaDestroy(&rcha->naindex);
1186 numaDestroy(&rcha->nascore);
1187 sarrayDestroy(&rcha->satext);
1188 numaDestroy(&rcha->nasample);
1189 numaDestroy(&rcha->naxloc);
1190 numaDestroy(&rcha->nayloc);
1191 numaDestroy(&rcha->nawidth);
1192 LEPT_FREE(rcha);
1193 *prcha = NULL;
1194}
1195
1196
1216static L_RCH *
1217rchCreate(l_int32 index,
1218 l_float32 score,
1219 char *text,
1220 l_int32 sample,
1221 l_int32 xloc,
1222 l_int32 yloc,
1223 l_int32 width)
1224{
1225L_RCH *rch;
1226
1227 rch = (L_RCH *)LEPT_CALLOC(1, sizeof(L_RCH));
1228 rch->index = index;
1229 rch->score = score;
1230 rch->text = text;
1231 rch->sample = sample;
1232 rch->xloc = xloc;
1233 rch->yloc = yloc;
1234 rch->width = width;
1235 return rch;
1236}
1237
1238
1244void
1246{
1247L_RCH *rch;
1248
1249 PROCNAME("rchDestroy");
1250
1251 if (prch == NULL) {
1252 L_WARNING("&rch is null!\n", procName);
1253 return;
1254 }
1255 if ((rch = *prch) == NULL)
1256 return;
1257 LEPT_FREE(rch->text);
1258 LEPT_FREE(rch);
1259 *prch = NULL;
1260}
1261
1262
1282l_ok
1284 NUMA **pnaindex,
1285 NUMA **pnascore,
1286 SARRAY **psatext,
1287 NUMA **pnasample,
1288 NUMA **pnaxloc,
1289 NUMA **pnayloc,
1290 NUMA **pnawidth)
1291{
1292 PROCNAME("rchaExtract");
1293
1294 if (pnaindex) *pnaindex = NULL;
1295 if (pnascore) *pnascore = NULL;
1296 if (psatext) *psatext = NULL;
1297 if (pnasample) *pnasample = NULL;
1298 if (pnaxloc) *pnaxloc = NULL;
1299 if (pnayloc) *pnayloc = NULL;
1300 if (pnawidth) *pnawidth = NULL;
1301 if (!rcha)
1302 return ERROR_INT("rcha not defined", procName, 1);
1303
1304 if (pnaindex) *pnaindex = numaClone(rcha->naindex);
1305 if (pnascore) *pnascore = numaClone(rcha->nascore);
1306 if (psatext) *psatext = sarrayClone(rcha->satext);
1307 if (pnasample) *pnasample = numaClone(rcha->nasample);
1308 if (pnaxloc) *pnaxloc = numaClone(rcha->naxloc);
1309 if (pnayloc) *pnayloc = numaClone(rcha->nayloc);
1310 if (pnawidth) *pnawidth = numaClone(rcha->nawidth);
1311 return 0;
1312}
1313
1314
1328l_ok
1330 l_int32 *pindex,
1331 l_float32 *pscore,
1332 char **ptext,
1333 l_int32 *psample,
1334 l_int32 *pxloc,
1335 l_int32 *pyloc,
1336 l_int32 *pwidth)
1337{
1338 PROCNAME("rchExtract");
1339
1340 if (pindex) *pindex = 0;
1341 if (pscore) *pscore = 0.0;
1342 if (ptext) *ptext = NULL;
1343 if (psample) *psample = 0;
1344 if (pxloc) *pxloc = 0;
1345 if (pyloc) *pyloc = 0;
1346 if (pwidth) *pwidth = 0;
1347 if (!rch)
1348 return ERROR_INT("rch not defined", procName, 1);
1349
1350 if (pindex) *pindex = rch->index;
1351 if (pscore) *pscore = rch->score;
1352 if (ptext) *ptext = stringNew(rch->text); /* new string: owned by caller */
1353 if (psample) *psample = rch->sample;
1354 if (pxloc) *pxloc = rch->xloc;
1355 if (pyloc) *pyloc = rch->yloc;
1356 if (pwidth) *pwidth = rch->width;
1357 return 0;
1358}
1359
1360
1374static l_int32
1376 L_RCHA *rcha)
1377{
1378
1379 PROCNAME("transferRchToRcha");
1380
1381 if (!rch)
1382 return ERROR_INT("rch not defined", procName, 1);
1383 if (!rcha)
1384 return ERROR_INT("rcha not defined", procName, 1);
1385
1386 numaAddNumber(rcha->naindex, rch->index);
1387 numaAddNumber(rcha->nascore, rch->score);
1388 sarrayAddString(rcha->satext, rch->text, L_COPY);
1389 numaAddNumber(rcha->nasample, rch->sample);
1390 numaAddNumber(rcha->naxloc, rch->xloc);
1391 numaAddNumber(rcha->nayloc, rch->yloc);
1392 numaAddNumber(rcha->nawidth, rch->width);
1393 return 0;
1394}
1395
1396
1397/*------------------------------------------------------------------------*
1398 * Preprocessing and filtering *
1399 *------------------------------------------------------------------------*/
1416PIX *
1418 PIX *pixs,
1419 l_int32 pad)
1420{
1421l_int32 canclip;
1422PIX *pix1, *pix2, *pixd;
1423
1424 PROCNAME("recogProcessToIdentify");
1425
1426 if (!recog)
1427 return (PIX *)ERROR_PTR("recog not defined", procName, NULL);
1428 if (!pixs)
1429 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
1430
1431 if (pixGetDepth(pixs) != 1)
1432 pix1 = pixThresholdToBinary(pixs, recog->threshold);
1433 else
1434 pix1 = pixClone(pixs);
1435 pixTestClipToForeground(pix1, &canclip);
1436 if (canclip)
1437 pixClipToForeground(pix1, &pix2, NULL);
1438 else
1439 pix2 = pixClone(pix1);
1440 pixDestroy(&pix1);
1441 if (!pix2)
1442 return (PIX *)ERROR_PTR("no foreground pixels", procName, NULL);
1443
1444 pixd = pixAddBorderGeneral(pix2, pad, pad, 0, 0, 0);
1445 pixDestroy(&pix2);
1446 return pixd;
1447}
1448
1449
1460static PIX *
1462 PIX *pixs,
1463 l_int32 minh,
1464 l_float32 minaf,
1465 l_int32 debug)
1466{
1467l_int32 scaling, minsplitw, maxsplith, maxasp;
1468BOXA *boxas;
1469NUMA *naw, *nah, *na1, *na1c, *na2, *na3, *na4, *na5, *na6, *na7;
1470PIX *pixd;
1471PIXA *pixas;
1472
1473 PROCNAME("recogPreSplittingFilter");
1474
1475 if (!recog)
1476 return (PIX *)ERROR_PTR("recog not defined", procName, NULL);
1477 if (!pixs)
1478 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
1479
1480 /* If there is scaling, do not remove components based on the
1481 * values of min_splitw and max_splith. */
1482 scaling = (recog->scalew > 0 || recog->scaleh > 0) ? TRUE : FALSE;
1483 minsplitw = (scaling) ? 1 : recog->min_splitw - 3;
1484 maxsplith = (scaling) ? 150 : recog->max_splith;
1485 maxasp = recog->max_wh_ratio;
1486
1487 /* Generate an indicator array of connected components to remove:
1488 * short stuff
1489 * tall stuff
1490 * components with large width/height ratio
1491 * components with small area fill fraction */
1492 boxas = pixConnComp(pixs, &pixas, 8);
1493 pixaFindDimensions(pixas, &naw, &nah);
1494 na1 = numaMakeThresholdIndicator(naw, minsplitw, L_SELECT_IF_LT);
1495 na1c = numaCopy(na1);
1497 na3 = numaMakeThresholdIndicator(nah, maxsplith, L_SELECT_IF_GT);
1498 na4 = pixaFindWidthHeightRatio(pixas);
1499 na5 = numaMakeThresholdIndicator(na4, maxasp, L_SELECT_IF_GT);
1500 na6 = pixaFindAreaFraction(pixas);
1501 na7 = numaMakeThresholdIndicator(na6, minaf, L_SELECT_IF_LT);
1502 numaLogicalOp(na1, na1, na2, L_UNION);
1503 numaLogicalOp(na1, na1, na3, L_UNION);
1504 numaLogicalOp(na1, na1, na5, L_UNION);
1505 numaLogicalOp(na1, na1, na7, L_UNION);
1506 pixd = pixCopy(NULL, pixs);
1507 pixRemoveWithIndicator(pixd, pixas, na1);
1508 if (debug)
1509 l_showIndicatorSplitValues(na1c, na2, na3, na5, na7, na1);
1510 numaDestroy(&naw);
1511 numaDestroy(&nah);
1512 numaDestroy(&na1);
1513 numaDestroy(&na1c);
1514 numaDestroy(&na2);
1515 numaDestroy(&na3);
1516 numaDestroy(&na4);
1517 numaDestroy(&na5);
1518 numaDestroy(&na6);
1519 numaDestroy(&na7);
1520 boxaDestroy(&boxas);
1521 pixaDestroy(&pixas);
1522 return pixd;
1523}
1524
1525
1537static l_int32
1539 PIX *pixs,
1540 l_int32 minh,
1541 l_float32 minaf,
1542 l_int32 *premove,
1543 l_int32 debug)
1544{
1545l_int32 w, h;
1546l_float32 aspratio, fract;
1547
1548 PROCNAME("recogSplittingFilter");
1549
1550 if (!premove)
1551 return ERROR_INT("&remove not defined", procName, 1);
1552 *premove = 0;
1553 if (!recog)
1554 return ERROR_INT("recog not defined", procName, 1);
1555 if (!pixs)
1556 return ERROR_INT("pixs not defined", procName, 1);
1557 if (minh <= 0) minh = DefaultMinHeight;
1558
1559 /* Remove from further consideration:
1560 * small stuff
1561 * components with large width/height ratio
1562 * components with small area fill fraction */
1563 pixGetDimensions(pixs, &w, &h, NULL);
1564 if (w < recog->min_splitw) {
1565 if (debug) L_INFO("w = %d < %d\n", procName, w, recog->min_splitw);
1566 *premove = 1;
1567 return 0;
1568 }
1569 if (h < minh) {
1570 if (debug) L_INFO("h = %d < %d\n", procName, h, minh);
1571 *premove = 1;
1572 return 0;
1573 }
1574 aspratio = (l_float32)w / (l_float32)h;
1575 if (aspratio > recog->max_wh_ratio) {
1576 if (debug) L_INFO("w/h = %5.3f too large\n", procName, aspratio);
1577 *premove = 1;
1578 return 0;
1579 }
1580 pixFindAreaFraction(pixs, recog->sumtab, &fract);
1581 if (fract < minaf) {
1582 if (debug) L_INFO("area fill fract %5.3f < %5.3f\n",
1583 procName, fract, minaf);
1584 *premove = 1;
1585 return 0;
1586 }
1587
1588 return 0;
1589}
1590
1591
1592/*------------------------------------------------------------------------*
1593 * Postprocessing *
1594 *------------------------------------------------------------------------*/
1629SARRAY *
1631 BOXA *boxas,
1632 l_float32 scorethresh,
1633 l_int32 spacethresh,
1634 BOXAA **pbaa,
1635 NUMAA **pnaa)
1636{
1637char *str, *text;
1638l_int32 i, n, x1, x2, h_ovl, v_ovl, h_sep, v_sep;
1639l_float32 score;
1640BOX *box, *prebox;
1641BOXA *ba;
1642BOXAA *baa;
1643NUMA *nascore, *na;
1644NUMAA *naa;
1645SARRAY *satext, *sa, *saout;
1646
1647 PROCNAME("recogExtractNumbers");
1648
1649 if (pbaa) *pbaa = NULL;
1650 if (pnaa) *pnaa = NULL;
1651 if (!recog || !recog->rcha)
1652 return (SARRAY *)ERROR_PTR("recog and rcha not both defined",
1653 procName, NULL);
1654 if (!boxas)
1655 return (SARRAY *)ERROR_PTR("boxas not defined", procName, NULL);
1656
1657 if (spacethresh < 0)
1658 spacethresh = L_MAX(recog->maxheight_u, 20);
1659 rchaExtract(recog->rcha, NULL, &nascore, &satext, NULL, NULL, NULL, NULL);
1660 if (!nascore || !satext) {
1661 numaDestroy(&nascore);
1662 sarrayDestroy(&satext);
1663 return (SARRAY *)ERROR_PTR("nascore and satext not both returned",
1664 procName, NULL);
1665 }
1666
1667 saout = sarrayCreate(0);
1668 naa = numaaCreate(0);
1669 baa = boxaaCreate(0);
1670 prebox = NULL;
1671 n = numaGetCount(nascore);
1672 for (i = 0; i < n; i++) {
1673 numaGetFValue(nascore, i, &score);
1674 text = sarrayGetString(satext, i, L_NOCOPY);
1675 if (prebox == NULL) { /* no current run */
1676 if (score < scorethresh) {
1677 continue;
1678 } else { /* start a number run */
1679 sa = sarrayCreate(0);
1680 ba = boxaCreate(0);
1681 na = numaCreate(0);
1682 sarrayAddString(sa, text, L_COPY);
1683 prebox = boxaGetBox(boxas, i, L_CLONE);
1684 boxaAddBox(ba, prebox, L_COPY);
1685 numaAddNumber(na, score);
1686 }
1687 } else { /* in a current number run */
1688 box = boxaGetBox(boxas, i, L_CLONE);
1689 boxGetGeometry(prebox, &x1, NULL, NULL, NULL);
1690 boxGetGeometry(box, &x2, NULL, NULL, NULL);
1691 boxOverlapDistance(box, prebox, &h_ovl, &v_ovl);
1692 h_sep = -h_ovl;
1693 v_sep = -v_ovl;
1694 boxDestroy(&prebox);
1695 if (x1 < x2 && h_sep <= spacethresh &&
1696 v_sep < 0 && score >= scorethresh) { /* add to number */
1697 sarrayAddString(sa, text, L_COPY);
1698 boxaAddBox(ba, box, L_COPY);
1699 numaAddNumber(na, score);
1700 prebox = box;
1701 } else { /* save the completed number */
1702 str = sarrayToString(sa, 0);
1703 sarrayAddString(saout, str, L_INSERT);
1704 sarrayDestroy(&sa);
1705 boxaaAddBoxa(baa, ba, L_INSERT);
1706 numaaAddNuma(naa, na, L_INSERT);
1707 boxDestroy(&box);
1708 if (score >= scorethresh) { /* start a new number */
1709 i--;
1710 continue;
1711 }
1712 }
1713 }
1714 }
1715
1716 if (prebox) { /* save the last number */
1717 str = sarrayToString(sa, 0);
1718 sarrayAddString(saout, str, L_INSERT);
1719 boxaaAddBoxa(baa, ba, L_INSERT);
1720 numaaAddNuma(naa, na, L_INSERT);
1721 sarrayDestroy(&sa);
1722 boxDestroy(&prebox);
1723 }
1724
1725 numaDestroy(&nascore);
1726 sarrayDestroy(&satext);
1727 if (sarrayGetCount(saout) == 0) {
1728 sarrayDestroy(&saout);
1729 boxaaDestroy(&baa);
1730 numaaDestroy(&naa);
1731 L_INFO("saout has no identified text\n", procName);
1732 return NULL;
1733 }
1734
1735 if (pbaa)
1736 *pbaa = baa;
1737 else
1738 boxaaDestroy(&baa);
1739 if (pnaa)
1740 *pnaa = naa;
1741 else
1742 numaaDestroy(&naa);
1743 return saout;
1744}
1745
1764PIXA *
1766 SARRAY *sa,
1767 BOXAA *baa,
1768 NUMAA *naa,
1769 PIX **ppixdb)
1770{
1771char buf[128];
1772char *textstr, *scorestr;
1773l_int32 i, j, n, nchar, len;
1774l_float32 score;
1775L_BMF *bmf;
1776BOX *box1, *box2;
1777BOXA *ba;
1778NUMA *na;
1779PIX *pix1, *pix2, *pix3, *pix4;
1780PIXA *pixa;
1781
1782 PROCNAME("showExtractNumbers");
1783
1784 if (ppixdb) *ppixdb = NULL;
1785 if (!pixs)
1786 return (PIXA *)ERROR_PTR("pixs not defined", procName, NULL);
1787 if (!sa)
1788 return (PIXA *)ERROR_PTR("sa not defined", procName, NULL);
1789 if (!baa)
1790 return (PIXA *)ERROR_PTR("baa not defined", procName, NULL);
1791 if (!naa)
1792 return (PIXA *)ERROR_PTR("naa not defined", procName, NULL);
1793
1794 n = sarrayGetCount(sa);
1795 pixa = pixaCreate(n);
1796 bmf = bmfCreate(NULL, 6);
1797 if (ppixdb) *ppixdb = pixConvertTo8(pixs, 1);
1798 for (i = 0; i < n; i++) {
1799 textstr = sarrayGetString(sa, i, L_NOCOPY);
1800 ba = boxaaGetBoxa(baa, i, L_CLONE);
1801 na = numaaGetNuma(naa, i, L_CLONE);
1802 boxaGetExtent(ba, NULL, NULL, &box1);
1803 box2 = boxAdjustSides(NULL, box1, -5, 5, -5, 5);
1804 if (ppixdb) pixRenderBoxArb(*ppixdb, box2, 3, 255, 0, 0);
1805 pix1 = pixClipRectangle(pixs, box1, NULL);
1806 len = strlen(textstr) + 1;
1807 pix2 = pixAddBlackOrWhiteBorder(pix1, 14 * len, 14 * len,
1808 5, 3, L_SET_WHITE);
1809 pix3 = pixConvertTo8(pix2, 1);
1810 nchar = numaGetCount(na);
1811 scorestr = NULL;
1812 for (j = 0; j < nchar; j++) {
1813 numaGetFValue(na, j, &score);
1814 snprintf(buf, sizeof(buf), "%d", (l_int32)(100 * score));
1815 stringJoinIP(&scorestr, buf);
1816 if (j < nchar - 1) stringJoinIP(&scorestr, ",");
1817 }
1818 snprintf(buf, sizeof(buf), "%s: %s\n", textstr, scorestr);
1819 pix4 = pixAddTextlines(pix3, bmf, buf, 0xff000000, L_ADD_BELOW);
1820 pixaAddPix(pixa, pix4, L_INSERT);
1821 boxDestroy(&box1);
1822 boxDestroy(&box2);
1823 pixDestroy(&pix1);
1824 pixDestroy(&pix2);
1825 pixDestroy(&pix3);
1826 boxaDestroy(&ba);
1827 numaDestroy(&na);
1828 LEPT_FREE(scorestr);
1829 }
1830
1831 bmfDestroy(&bmf);
1832 return pixa;
1833}
1834
1835
1836/*------------------------------------------------------------------------*
1837 * Static debug helper *
1838 *------------------------------------------------------------------------*/
1851static void
1853 NUMA *na2,
1854 NUMA *na3,
1855 NUMA *na4,
1856 NUMA *na5,
1857 NUMA *na6)
1858{
1859l_int32 i, n;
1860
1861 n = numaGetCount(na1);
1862 lept_stderr("================================================\n");
1863 lept_stderr("lt minw: ");
1864 for (i = 0; i < n; i++)
1865 lept_stderr("%4d ", (l_int32)na1->array[i]);
1866 lept_stderr("\nlt minh: ");
1867 for (i = 0; i < n; i++)
1868 lept_stderr("%4d ", (l_int32)na2->array[i]);
1869 lept_stderr("\ngt maxh: ");
1870 for (i = 0; i < n; i++)
1871 lept_stderr("%4d ", (l_int32)na3->array[i]);
1872 lept_stderr("\ngt maxasp: ");
1873 for (i = 0; i < n; i++)
1874 lept_stderr("%4d ", (l_int32)na4->array[i]);
1875 lept_stderr("\nlt minaf: ");
1876 for (i = 0; i < n; i++)
1877 lept_stderr("%4d ", (l_int32)na5->array[i]);
1878 lept_stderr("\n------------------------------------------------");
1879 lept_stderr("\nresult: ");
1880 for (i = 0; i < n; i++)
1881 lept_stderr("%4d ", (l_int32)na6->array[i]);
1882 lept_stderr("\n================================================\n");
1883}
void bmfDestroy(L_BMF **pbmf)
bmfDestroy()
Definition: bmf.c:169
L_BMF * bmfCreate(const char *dir, l_int32 fontsize)
bmfCreate()
Definition: bmf.c:117
BOXA * boxaaGetBoxa(BOXAA *baa, l_int32 index, l_int32 accessflag)
boxaaGetBoxa()
Definition: boxbasic.c:1501
BOX * boxaGetBox(BOXA *boxa, l_int32 index, l_int32 accessflag)
boxaGetBox()
Definition: boxbasic.c:779
void boxDestroy(BOX **pbox)
boxDestroy()
Definition: boxbasic.c:282
BOX * boxCreate(l_int32 x, l_int32 y, l_int32 w, l_int32 h)
boxCreate()
Definition: boxbasic.c:172
BOXAA * boxaaCreate(l_int32 n)
boxaaCreate()
Definition: boxbasic.c:1244
l_int32 boxaGetCount(BOXA *boxa)
boxaGetCount()
Definition: boxbasic.c:734
l_ok boxaaAddBoxa(BOXAA *baa, BOXA *ba, l_int32 copyflag)
boxaaAddBoxa()
Definition: boxbasic.c:1346
l_ok boxGetGeometry(BOX *box, l_int32 *px, l_int32 *py, l_int32 *pw, l_int32 *ph)
boxGetGeometry()
Definition: boxbasic.c:313
BOXA * boxaCreate(l_int32 n)
boxaCreate()
Definition: boxbasic.c:502
l_ok boxaAddBox(BOXA *boxa, BOX *box, l_int32 copyflag)
boxaAddBox()
Definition: boxbasic.c:620
void boxaDestroy(BOXA **pboxa)
boxaDestroy()
Definition: boxbasic.c:583
void boxaaDestroy(BOXAA **pbaa)
boxaaDestroy()
Definition: boxbasic.c:1310
l_ok boxaJoin(BOXA *boxad, BOXA *boxas, l_int32 istart, l_int32 iend)
boxaJoin()
Definition: boxfunc1.c:2537
l_ok boxOverlapDistance(BOX *box1, BOX *box2, l_int32 *ph_ovl, l_int32 *pv_ovl)
boxOverlapDistance()
Definition: boxfunc1.c:1044
BOX * boxAdjustSides(BOX *boxd, BOX *boxs, l_int32 delleft, l_int32 delright, l_int32 deltop, l_int32 delbot)
boxAdjustSides()
Definition: boxfunc1.c:1991
BOXA * boxaHandleOverlaps(BOXA *boxas, l_int32 op, l_int32 range, l_float32 min_overlap, l_float32 max_ratio, NUMA **pnamap)
boxaHandleOverlaps()
Definition: boxfunc1.c:914
BOXA * boxaaFlattenToBoxa(BOXAA *baa, NUMA **pnaindex, l_int32 copyflag)
boxaaFlattenToBoxa()
Definition: boxfunc2.c:1646
BOX * boxTransform(BOX *box, l_int32 shiftx, l_int32 shifty, l_float32 scalex, l_float32 scaley)
boxTransform()
Definition: boxfunc2.c:152
BOXA * boxaTransform(BOXA *boxas, l_int32 shiftx, l_int32 shifty, l_float32 scalex, l_float32 scaley)
boxaTransform()
Definition: boxfunc2.c:102
BOXA * boxaSort(BOXA *boxas, l_int32 sorttype, l_int32 sortorder, NUMA **pnaindex)
boxaSort()
Definition: boxfunc2.c:637
BOXAA * boxaSort2d(BOXA *boxas, NUMAA **pnaad, l_int32 delta1, l_int32 delta2, l_int32 minh1)
boxaSort2d()
Definition: boxfunc2.c:915
l_ok boxaGetExtent(BOXA *boxa, l_int32 *pw, l_int32 *ph, BOX **pbox)
boxaGetExtent()
Definition: boxfunc4.c:953
BOXA * pixConnComp(PIX *pixs, PIXA **ppixa, l_int32 connectivity)
pixConnComp()
Definition: conncomp.c:151
FPIX * fpixCreate(l_int32 width, l_int32 height)
fpixCreate()
Definition: fpix1.c:156
l_ok fpixSetPixel(FPIX *fpix, l_int32 x, l_int32 y, l_float32 val)
fpixSetPixel()
Definition: fpix1.c:600
void fpixDestroy(FPIX **pfpix)
fpixDestroy()
Definition: fpix1.c:292
PIX * fpixDisplayMaxDynamicRange(FPIX *fpixs)
fpixDisplayMaxDynamicRange()
Definition: fpix2.c:428
l_ok pixRenderBoxArb(PIX *pix, BOX *box, l_int32 width, l_uint8 rval, l_uint8 gval, l_uint8 bval)
pixRenderBoxArb()
Definition: graphics.c:1655
l_ok pixRenderBoxaArb(PIX *pix, BOXA *boxa, l_int32 width, l_uint8 rval, l_uint8 gval, l_uint8 bval)
pixRenderBoxaArb()
Definition: graphics.c:1772
PIX * pixThresholdToBinary(PIX *pixs, l_int32 thresh)
pixThresholdToBinary()
Definition: grayquant.c:447
l_ok pixCentroid(PIX *pix, l_int32 *centtab, l_int32 *sumtab, l_float32 *pxave, l_float32 *pyave)
pixCentroid()
Definition: morphapp.c:1533
PIX * pixMorphSequence(PIX *pixs, const char *sequence, l_int32 dispsep)
pixMorphSequence()
Definition: morphseq.c:137
l_ok numaAddNumber(NUMA *na, l_float32 val)
numaAddNumber()
Definition: numabasic.c:478
NUMA * numaCopy(NUMA *na)
numaCopy()
Definition: numabasic.c:399
l_ok numaGetFValue(NUMA *na, l_int32 index, l_float32 *pval)
numaGetFValue()
Definition: numabasic.c:719
NUMA * numaaGetNuma(NUMAA *naa, l_int32 index, l_int32 accessflag)
numaaGetNuma()
Definition: numabasic.c:1740
l_int32 * numaGetIArray(NUMA *na)
numaGetIArray()
Definition: numabasic.c:847
void numaDestroy(NUMA **pna)
numaDestroy()
Definition: numabasic.c:366
l_int32 numaGetCount(NUMA *na)
numaGetCount()
Definition: numabasic.c:658
l_ok numaGetIValue(NUMA *na, l_int32 index, l_int32 *pival)
numaGetIValue()
Definition: numabasic.c:754
NUMA * numaCreate(l_int32 n)
numaCreate()
Definition: numabasic.c:194
l_ok numaaAddNuma(NUMAA *naa, NUMA *na, l_int32 copyflag)
numaaAddNuma()
Definition: numabasic.c:1546
NUMA * numaClone(NUMA *na)
numaClone()
Definition: numabasic.c:428
NUMAA * numaaCreate(l_int32 n)
numaaCreate()
Definition: numabasic.c:1407
void numaaDestroy(NUMAA **pnaa)
numaaDestroy()
Definition: numabasic.c:1510
NUMA * numaSortByIndex(NUMA *nas, NUMA *naindex)
numaSortByIndex()
Definition: numafunc1.c:2916
NUMA * numaMakeThresholdIndicator(NUMA *nas, l_float32 thresh, l_int32 type)
numaMakeThresholdIndicator()
Definition: numafunc1.c:1231
NUMA * numaLogicalOp(NUMA *nad, NUMA *na1, NUMA *na2, l_int32 op)
numaLogicalOp()
Definition: numafunc1.c:253
void pixDestroy(PIX **ppix)
pixDestroy()
Definition: pix1.c:621
l_ok pixGetDimensions(const PIX *pix, l_int32 *pw, l_int32 *ph, l_int32 *pd)
pixGetDimensions()
Definition: pix1.c:1113
l_ok pixSetText(PIX *pix, const char *textstring)
pixSetText()
Definition: pix1.c:1536
PIX * pixClone(PIX *pixs)
pixClone()
Definition: pix1.c:593
PIX * pixCreate(l_int32 width, l_int32 height, l_int32 depth)
pixCreate()
Definition: pix1.c:315
PIX * pixCopy(PIX *pixd, const PIX *pixs)
pixCopy()
Definition: pix1.c:705
l_ok pixClearAll(PIX *pix)
pixClearAll()
Definition: pix2.c:789
PIX * pixAddBlackOrWhiteBorder(PIX *pixs, l_int32 left, l_int32 right, l_int32 top, l_int32 bot, l_int32 op)
pixAddBlackOrWhiteBorder()
Definition: pix2.c:1863
PIX * pixAddBorderGeneral(PIX *pixs, l_int32 left, l_int32 right, l_int32 top, l_int32 bot, l_uint32 val)
pixAddBorderGeneral()
Definition: pix2.c:1917
l_int32 * makePixelSumTab8(void)
makePixelSumTab8()
Definition: pix3.c:2411
l_ok pixZero(PIX *pix, l_int32 *pempty)
pixZero()
Definition: pix3.c:1815
l_ok pixCountPixels(PIX *pixs, l_int32 *pcount, l_int32 *tab8)
pixCountPixels()
Definition: pix3.c:1937
NUMA * pixCountPixelsByColumn(PIX *pix)
pixCountPixelsByColumn()
Definition: pix3.c:2177
NUMA * pixGetMomentByColumn(PIX *pix, l_int32 order)
pixGetMomentByColumn()
Definition: pix3.c:2281
NUMA * pixaFindWidthHeightRatio(PIXA *pixa)
pixaFindWidthHeightRatio()
Definition: pix5.c:670
PIX * pixClipRectangle(PIX *pixs, BOX *box, BOX **pboxc)
pixClipRectangle()
Definition: pix5.c:1026
l_ok pixFindAreaFraction(PIX *pixs, l_int32 *tab, l_float32 *pfract)
pixFindAreaFraction()
Definition: pix5.c:484
NUMA * pixaFindAreaFraction(PIXA *pixa)
pixaFindAreaFraction()
Definition: pix5.c:441
PIXA * pixClipRectangles(PIX *pixs, BOXA *boxa)
pixClipRectangles()
Definition: pix5.c:960
l_ok pixTestClipToForeground(PIX *pixs, l_int32 *pcanclip)
pixTestClipToForeground()
Definition: pix5.c:1884
l_ok pixClipToForeground(PIX *pixs, PIX **ppixd, BOX **pbox)
pixClipToForeground()
Definition: pix5.c:1784
l_ok pixaFindDimensions(PIXA *pixa, NUMA **pnaw, NUMA **pnah)
pixaFindDimensions()
Definition: pix5.c:140
#define PIX_DST
Definition: pix.h:331
@ L_SELECT_IF_LT
Definition: pix.h:782
@ L_SELECT_IF_GT
Definition: pix.h:783
@ L_SORT_BY_X
Definition: pix.h:735
@ L_ADD_BELOW
Definition: pix.h:1210
@ L_COPY
Definition: pix.h:712
@ L_CLONE
Definition: pix.h:713
@ L_NOCOPY
Definition: pix.h:710
@ L_INSERT
Definition: pix.h:711
@ L_SET_WHITE
Definition: pix.h:906
@ L_COMBINE
Definition: pix.h:1087
#define PIX_SRC
Definition: pix.h:330
@ L_SORT_INCREASING
Definition: pix.h:729
l_ok pixaAddPix(PIXA *pixa, PIX *pix, l_int32 copyflag)
pixaAddPix()
Definition: pixabasic.c:506
void pixaDestroy(PIXA **ppixa)
pixaDestroy()
Definition: pixabasic.c:412
l_ok pixaRemovePixAndSave(PIXA *pixa, l_int32 index, PIX **ppix, BOX **pbox)
pixaRemovePixAndSave()
Definition: pixabasic.c:1477
PIXA * pixaaGetPixa(PIXAA *paa, l_int32 index, l_int32 accesstype)
pixaaGetPixa()
Definition: pixabasic.c:2206
PIXA * pixaCreate(l_int32 n)
pixaCreate()
Definition: pixabasic.c:167
l_int32 pixaGetCount(PIXA *pixa)
pixaGetCount()
Definition: pixabasic.c:650
l_ok pixaAddBox(PIXA *pixa, BOX *box, l_int32 copyflag)
pixaAddBox()
Definition: pixabasic.c:555
PIX * pixaGetPix(PIXA *pixa, l_int32 index, l_int32 accesstype)
pixaGetPix()
Definition: pixabasic.c:691
PIX * pixaaGetPix(PIXAA *paa, l_int32 index, l_int32 ipix, l_int32 accessflag)
pixaaGetPix()
Definition: pixabasic.c:2268
l_ok pixRemoveWithIndicator(PIX *pixs, PIXA *pixa, NUMA *na)
pixRemoveWithIndicator()
Definition: pixafunc1.c:1228
PIX * pixaDisplayTiledInColumns(PIXA *pixas, l_int32 nx, l_float32 scalefactor, l_int32 spacing, l_int32 border)
pixaDisplayTiledInColumns()
Definition: pixafunc2.c:930
PIX * pixaDisplayTiledInRows(PIXA *pixa, l_int32 outdepth, l_int32 maxwidth, l_float32 scalefactor, l_int32 background, l_int32 spacing, l_int32 border)
pixaDisplayTiledInRows()
Definition: pixafunc2.c:746
PIX * pixConvertTo8(PIX *pixs, l_int32 cmapflag)
pixConvertTo8()
Definition: pixconv.c:3133
PIX * pixConvertTo32(PIX *pixs)
pixConvertTo32()
Definition: pixconv.c:3332
PIX * pixConvertTo1(PIX *pixs, l_int32 threshold)
pixConvertTo1()
Definition: pixconv.c:3026
l_ok ptaGetIPt(PTA *pta, l_int32 index, l_int32 *px, l_int32 *py)
ptaGetIPt()
Definition: ptabasic.c:578
PTA * ptaaGetPta(PTAA *ptaa, l_int32 index, l_int32 accessflag)
ptaaGetPta()
Definition: ptabasic.c:1145
l_ok ptaGetPt(PTA *pta, l_int32 index, l_float32 *px, l_float32 *py)
ptaGetPt()
Definition: ptabasic.c:548
void ptaDestroy(PTA **ppta)
ptaDestroy()
Definition: ptabasic.c:195
@ L_USE_AVERAGE_TEMPLATES
Definition: recog.h:261
l_int32 recogGetClassString(L_RECOG *recog, l_int32 index, char **pcharstr)
recogGetClassString()
Definition: recogbasic.c:753
BOXA * recogDecode(L_RECOG *recog, PIX *pixs, l_int32 nlevels, PIX **ppixdb)
recogDecode()
Definition: recogdid.c:219
PIX * recogProcessToIdentify(L_RECOG *recog, PIX *pixs, l_int32 pad)
recogProcessToIdentify()
Definition: recogident.c:1417
l_ok recogCorrelationBestChar(L_RECOG *recog, PIX *pixs, BOX **pbox, l_float32 *pscore, l_int32 *pindex, char **pcharstr, PIX **ppixdb)
recogCorrelationBestChar()
Definition: recogident.c:587
void rchaDestroy(L_RCHA **prcha)
rchaDestroy()
Definition: recogident.c:1172
l_ok rchExtract(L_RCH *rch, l_int32 *pindex, l_float32 *pscore, char **ptext, l_int32 *psample, l_int32 *pxloc, l_int32 *pyloc, l_int32 *pwidth)
rchExtract()
Definition: recogident.c:1329
static l_int32 recogSplittingFilter(L_RECOG *recog, PIX *pixs, l_int32 min, l_float32 minaf, l_int32 *premove, l_int32 debug)
recogSplittingFilter()
Definition: recogident.c:1538
static void l_showIndicatorSplitValues(NUMA *na1, NUMA *na2, NUMA *na3, NUMA *na4, NUMA *na5, NUMA *na6)
l_showIndicatorSplitValues()
Definition: recogident.c:1852
static l_int32 transferRchToRcha(L_RCH *rch, L_RCHA *rcha)
transferRchToRcha()
Definition: recogident.c:1375
static l_int32 pixCorrelationBestShift(PIX *pix1, PIX *pix2, NUMA *nasum1, NUMA *namoment1, l_int32 area2, l_int32 ycent2, l_int32 maxyshift, l_int32 *tab8, l_int32 *pdelx, l_int32 *pdely, l_float32 *pscore, l_int32 debugflag)
pixCorrelationBestShift()
Definition: recogident.c:729
void rchDestroy(L_RCH **prch)
rchDestroy()
Definition: recogident.c:1245
l_ok recogIdentifyPixa(L_RECOG *recog, PIXA *pixa, PIX **ppixdb)
recogIdentifyPixa()
Definition: recogident.c:882
l_ok recogIdentifyPix(L_RECOG *recog, PIX *pixs, PIX **ppixdb)
recogIdentifyPix()
Definition: recogident.c:975
SARRAY * recogExtractNumbers(L_RECOG *recog, BOXA *boxas, l_float32 scorethresh, l_int32 spacethresh, BOXAA **pbaa, NUMAA **pnaa)
recogExtractNumbers()
Definition: recogident.c:1630
static L_RCHA * rchaCreate()
rchaCreate()
Definition: recogident.c:1150
l_ok recogCorrelationBestRow(L_RECOG *recog, PIX *pixs, BOXA **pboxa, NUMA **pnascore, NUMA **pnaindex, SARRAY **psachar, l_int32 debug)
recogCorrelationBestRow()
Definition: recogident.c:405
l_ok recogSkipIdentify(L_RECOG *recog)
recogSkipIdentify()
Definition: recogident.c:1124
l_ok recogIdentifyMultiple(L_RECOG *recog, PIX *pixs, l_int32 minh, l_int32 skipsplit, BOXA **pboxa, PIXA **ppixa, PIX **ppixdb, l_int32 debugsplit)
recogIdentifyMultiple()
Definition: recogident.c:162
static PIX * recogPreSplittingFilter(L_RECOG *recog, PIX *pixs, l_int32 minh, l_float32 minaf, l_int32 debug)
recogPreSplittingFilter()
Definition: recogident.c:1461
l_ok recogSplitIntoCharacters(L_RECOG *recog, PIX *pixs, l_int32 minh, l_int32 skipsplit, BOXA **pboxa, PIXA **ppixa, l_int32 debug)
recogSplitIntoCharacters()
Definition: recogident.c:250
l_ok rchaExtract(L_RCHA *rcha, NUMA **pnaindex, NUMA **pnascore, SARRAY **psatext, NUMA **pnasample, NUMA **pnaxloc, NUMA **pnayloc, NUMA **pnawidth)
rchaExtract()
Definition: recogident.c:1283
PIXA * showExtractNumbers(PIX *pixs, SARRAY *sa, BOXAA *baa, NUMAA *naa, PIX **ppixdb)
showExtractNumbers()
Definition: recogident.c:1765
static L_RCH * rchCreate(l_int32 index, l_float32 score, char *text, l_int32 sample, l_int32 xloc, l_int32 yloc, l_int32 width)
rchCreate()
Definition: recogident.c:1217
PIX * recogShowMatch(L_RECOG *recog, PIX *pix1, PIX *pix2, BOX *box, l_int32 index, l_float32 score)
recogShowMatch()
Definition: recogtrain.c:2429
PIX * recogModifyTemplate(L_RECOG *recog, PIX *pixs)
recogModifyTemplate()
Definition: recogtrain.c:421
l_int32 recogAverageSamples(L_RECOG **precog, l_int32 debug)
recogAverageSamples()
Definition: recogtrain.c:490
l_ok pixRasterop(PIX *pixd, l_int32 dx, l_int32 dy, l_int32 dw, l_int32 dh, l_int32 op, PIX *pixs, l_int32 sx, l_int32 sy)
pixRasterop()
Definition: rop.c:204
SARRAY * sarrayCreate(l_int32 n)
sarrayCreate()
Definition: sarray1.c:170
char * sarrayToString(SARRAY *sa, l_int32 addnlflag)
sarrayToString()
Definition: sarray1.c:785
char * sarrayGetString(SARRAY *sa, l_int32 index, l_int32 copyflag)
sarrayGetString()
Definition: sarray1.c:703
l_int32 sarrayGetCount(SARRAY *sa)
sarrayGetCount()
Definition: sarray1.c:643
void sarrayDestroy(SARRAY **psa)
sarrayDestroy()
Definition: sarray1.c:362
l_ok sarrayAddString(SARRAY *sa, const char *string, l_int32 copyflag)
sarrayAddString()
Definition: sarray1.c:451
SARRAY * sarrayClone(SARRAY *sa)
sarrayClone()
Definition: sarray1.c:425
SARRAY * sarraySortByIndex(SARRAY *sain, NUMA *naindex)
sarraySortByIndex()
Definition: sarray2.c:147
PIX * pixExpandReplicate(PIX *pixs, l_int32 factor)
pixExpandReplicate()
Definition: scale2.c:872
Definition: pix.h:481
Definition: pix.h:492
Definition: pix.h:502
Definition: pix.h:579
Definition: bmf.h:47
Definition: recog.h:182
l_int32 sample
Definition: recog.h:186
l_int32 yloc
Definition: recog.h:189
l_float32 score
Definition: recog.h:184
char * text
Definition: recog.h:185
l_int32 index
Definition: recog.h:183
l_int32 xloc
Definition: recog.h:188
l_int32 width
Definition: recog.h:190
Definition: recog.h:197
struct Numa * nasample
Definition: recog.h:201
struct Sarray * satext
Definition: recog.h:200
struct Numa * nascore
Definition: recog.h:199
struct Numa * nawidth
Definition: recog.h:204
struct Numa * naxloc
Definition: recog.h:202
struct Numa * naindex
Definition: recog.h:198
struct Numa * nayloc
Definition: recog.h:203
Definition: recog.h:116
struct Numa * nasum
Definition: recog.h:163
l_int32 ave_done
Definition: recog.h:141
l_int32 templ_use
Definition: recog.h:123
l_int32 * centtab
Definition: recog.h:150
struct L_Rch * rch
Definition: recog.h:174
struct Pixa * pixa_u
Definition: recog.h:158
l_int32 train_done
Definition: recog.h:142
l_int32 maxwidth_u
Definition: recog.h:136
struct Pta * pta_u
Definition: recog.h:159
l_int32 maxyshift
Definition: recog.h:129
l_int32 scalew
Definition: recog.h:117
struct Ptaa * ptaa
Definition: recog.h:156
l_int32 maxheight_u
Definition: recog.h:138
l_int32 min_splitw
Definition: recog.h:146
l_int32 threshold
Definition: recog.h:128
struct Numa * nasum_u
Definition: recog.h:160
struct L_Rcha * rcha
Definition: recog.h:175
l_int32 scaleh
Definition: recog.h:119
l_int32 max_splith
Definition: recog.h:147
l_int32 * sumtab
Definition: recog.h:151
struct Pixa * pixadb_split
Definition: recog.h:170
struct Pta * pta
Definition: recog.h:162
l_int32 minwidth_u
Definition: recog.h:135
struct Numaa * naasum
Definition: recog.h:157
l_float32 max_wh_ratio
Definition: recog.h:144
l_int32 setsize
Definition: recog.h:127
struct Pixaa * pixaa
Definition: recog.h:155
struct Pixa * pixa
Definition: recog.h:161
Definition: array.h:71
l_float32 * array
Definition: array.h:77
Definition: array.h:83
Definition: pix.h:139
Definition: pix.h:456
Definition: pix.h:517
Definition: array.h:127
PIX * pixAddTextlines(PIX *pixs, L_BMF *bmf, const char *textstr, l_uint32 val, l_int32 location)
pixAddTextlines()
Definition: textops.c:276
void lept_stderr(const char *fmt,...)
lept_stderr()
Definition: utils1.c:306
l_ok stringJoinIP(char **psrc1, const char *src2)
stringJoinIP()
Definition: utils2.c:573
l_int32 lept_mkdir(const char *subdir)
lept_mkdir()
Definition: utils2.c:2218
char * stringNew(const char *src)
stringNew()
Definition: utils2.c:223