Leptonica  1.83.1
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 #include "array_internal.h"
99 
100  /* There are two methods for splitting characters: DID and greedy.
101  * The default method is DID. */
102 #define SPLIT_WITH_DID 1
103 
104  /* Padding on pix1: added before correlations and removed from result */
105 static const l_int32 LeftRightPadding = 32;
106 
107  /* Parameters for filtering and sorting connected components in splitter */
108 static const l_float32 MinFillFactor = 0.10;
109 static const l_int32 DefaultMinHeight = 15; /* min unscaled height */
110 static const l_int32 MinOverlap1 = 6; /* in pass 1 of boxaSort2d() */
111 static const l_int32 MinOverlap2 = 6; /* in pass 2 of boxaSort2d() */
112 static const l_int32 MinHeightPass1 = 5; /* min height to start pass 1 */
113 
114 
115 static l_int32 pixCorrelationBestShift(PIX *pix1, PIX *pix2, NUMA *nasum1,
116  NUMA *namoment1, l_int32 area2,
117  l_int32 ycent2, l_int32 maxyshift,
118  l_int32 *tab8, l_int32 *pdelx,
119  l_int32 *pdely, l_float32 *pscore,
120  l_int32 debugflag );
121 static L_RCH *rchCreate(l_int32 index, l_float32 score, char *text,
122  l_int32 sample, l_int32 xloc, l_int32 yloc,
123  l_int32 width);
124 static L_RCHA *rchaCreate();
125 static l_int32 transferRchToRcha(L_RCH *rch, L_RCHA *rcha);
126 static PIX *recogPreSplittingFilter(L_RECOG *recog, PIX *pixs, l_int32 minh,
127  l_float32 minaf, l_int32 debug);
128 static l_int32 recogSplittingFilter(L_RECOG *recog, PIX *pixs, l_int32 min,
129  l_float32 minaf, l_int32 *premove,
130  l_int32 debug);
131 static void l_showIndicatorSplitValues(NUMA *na1, NUMA *na2, NUMA *na3,
132  NUMA *na4, NUMA *na5, NUMA *na6);
133 
134 /*------------------------------------------------------------------------*
135  * Identification
136  *------------------------------------------------------------------------*/
162 l_ok
164  PIX *pixs,
165  l_int32 minh,
166  l_int32 skipsplit,
167  BOXA **pboxa,
168  PIXA **ppixa,
169  PIX **ppixdb,
170  l_int32 debugsplit)
171 {
172 l_int32 n;
173 BOXA *boxa;
174 PIX *pixb;
175 PIXA *pixa;
176 
177  if (pboxa) *pboxa = NULL;
178  if (ppixa) *ppixa = NULL;
179  if (ppixdb) *ppixdb = NULL;
180  if (!recog)
181  return ERROR_INT("recog not defined", __func__, 2);
182  if (!recog->train_done)
183  return ERROR_INT("training not finished", __func__, 2);
184  if (!pixs)
185  return ERROR_INT("pixs not defined", __func__, 2);
186 
187  /* Binarize if necessary */
188  if (pixGetDepth(pixs) > 1)
189  pixb = pixConvertTo1(pixs, recog->threshold);
190  else
191  pixb = pixClone(pixs);
192 
193  /* Noise removal and splitting of touching characters */
194  recogSplitIntoCharacters(recog, pixb, minh, skipsplit, &boxa, &pixa,
195  debugsplit);
196  pixDestroy(&pixb);
197  if (!pixa || (n = pixaGetCount(pixa)) == 0) {
198  pixaDestroy(&pixa);
199  boxaDestroy(&boxa);
200  L_WARNING("nothing found\n", __func__);
201  return 1;
202  }
203 
204  recogIdentifyPixa(recog, pixa, ppixdb);
205  if (pboxa)
206  *pboxa = boxa;
207  else
208  boxaDestroy(&boxa);
209  if (ppixa)
210  *ppixa = pixa;
211  else
212  pixaDestroy(&pixa);
213  return 0;
214 }
215 
216 
217 /*------------------------------------------------------------------------*
218  * Segmentation and noise removal *
219  *------------------------------------------------------------------------*/
248 l_ok
250  PIX *pixs,
251  l_int32 minh,
252  l_int32 skipsplit,
253  BOXA **pboxa,
254  PIXA **ppixa,
255  l_int32 debug)
256 {
257 static l_int32 ind = 0;
258 char buf[32];
259 l_int32 i, xoff, yoff, empty, maxw, bw, ncomp, scaling;
260 BOX *box;
261 BOXA *boxa1, *boxa2, *boxa3, *boxa4, *boxad;
262 BOXAA *baa;
263 PIX *pix, *pix1, *pix2, *pix3;
264 PIXA *pixa;
265 
266  lept_mkdir("lept/recog");
267 
268  if (pboxa) *pboxa = NULL;
269  if (ppixa) *ppixa = NULL;
270  if (!pboxa || !ppixa)
271  return ERROR_INT("&boxa and &pixa not defined", __func__, 1);
272  if (!recog)
273  return ERROR_INT("recog not defined", __func__, 1);
274  if (!recog->train_done)
275  return ERROR_INT("training not finished", __func__, 1);
276  if (!pixs || pixGetDepth(pixs) != 1)
277  return ERROR_INT("pixs not defined or not 1 bpp", __func__, 1);
278  if (minh <= 0) minh = DefaultMinHeight;
279  pixZero(pixs, &empty);
280  if (empty) return 1;
281 
282  /* Small vertical close for consolidation. Don't do a horizontal
283  * closing, because it might join separate characters. */
284  pix1 = pixMorphSequence(pixs, "c1.3", 0);
285 
286  /* Carefully filter out noise */
287  pix2 = recogPreSplittingFilter(recog, pix1, minh, MinFillFactor, debug);
288  pixDestroy(&pix1);
289 
290  /* Get the 8-connected components to be split/identified */
291  boxa1 = pixConnComp(pix2, NULL, 8);
292  pixDestroy(&pix2);
293  ncomp = boxaGetCount(boxa1);
294  if (ncomp == 0) {
295  boxaDestroy(&boxa1);
296  L_WARNING("all components removed\n", __func__);
297  return 1;
298  }
299 
300  /* Save everything and split the large components */
301  boxa2 = boxaCreate(ncomp);
302  maxw = recog->maxwidth_u + 5;
303  scaling = (recog->scalew > 0 || recog->scaleh > 0) ? TRUE : FALSE;
304  pixa = (debug) ? pixaCreate(ncomp) : NULL;
305  for (i = 0; i < ncomp; i++) {
306  box = boxaGetBox(boxa1, i, L_CLONE);
307  boxGetGeometry(box, &xoff, &yoff, &bw, NULL);
308  /* Treat as one character if it is small, if the images
309  * have been scaled, or if splitting is not to be run. */
310  if (bw <= maxw || scaling || skipsplit) {
311  boxaAddBox(boxa2, box, L_INSERT);
312  } else {
313  pix = pixClipRectangle(pixs, box, NULL);
314 #if SPLIT_WITH_DID
315  if (!debug) {
316  boxa3 = recogDecode(recog, pix, 2, NULL);
317  } else {
318  boxa3 = recogDecode(recog, pix, 2, &pix2);
319  pixaAddPix(pixa, pix2, L_INSERT);
320  }
321 #else /* use greedy splitting */
322  recogCorrelationBestRow(recog, pix, &boxa3, NULL, NULL,
323  NULL, debug);
324  if (debug) {
325  pix2 = pixConvertTo32(pix);
326  pixRenderBoxaArb(pix2, boxa3, 2, 255, 0, 0);
327  pixaAddPix(pixa, pix2, L_INSERT);
328  }
329 #endif /* SPLIT_WITH_DID */
330  pixDestroy(&pix);
331  boxDestroy(&box);
332  if (!boxa3) {
333  L_ERROR("boxa3 not found for component %d\n", __func__, i);
334  } else {
335  boxa4 = boxaTransform(boxa3, xoff, yoff, 1.0, 1.0);
336  boxaJoin(boxa2, boxa4, 0, -1);
337  boxaDestroy(&boxa3);
338  boxaDestroy(&boxa4);
339  }
340  }
341  }
342  boxaDestroy(&boxa1);
343  if (pixa) { /* debug */
344  pix3 = pixaDisplayTiledInColumns(pixa, 1, 1.0, 20, 2);
345  snprintf(buf, sizeof(buf), "/tmp/lept/recog/decode-%d.png", ind++);
346  pixWrite(buf, pix3, IFF_PNG);
347  pixaDestroy(&pixa);
348  pixDestroy(&pix3);
349  }
350 
351  /* Do a 2D sort on the bounding boxes, and flatten the result to 1D.
352  * For the 2D sort, to add a box to an existing boxa, we require
353  * specified minimum vertical overlaps for the first two passes
354  * of the 2D sort. In pass 1, only components with sufficient
355  * height can start a new boxa. */
356  baa = boxaSort2d(boxa2, NULL, MinOverlap1, MinOverlap2, MinHeightPass1);
357  boxa3 = boxaaFlattenToBoxa(baa, NULL, L_CLONE);
358  boxaaDestroy(&baa);
359  boxaDestroy(&boxa2);
360 
361  /* Remove smaller components of overlapping pairs.
362  * We only remove the small component if the overlap is
363  * at least half its area and if its area is no more
364  * than 30% of the area of the large component. Because the
365  * components are in a flattened 2D sort, we don't need to
366  * look far ahead in the array to find all overlapping boxes;
367  * 10 boxes is plenty. */
368  boxad = boxaHandleOverlaps(boxa3, L_COMBINE, 10, 0.5, 0.3, NULL);
369  boxaDestroy(&boxa3);
370 
371  /* Extract and save the image pieces from the input image. */
372  *ppixa = pixClipRectangles(pixs, boxad);
373  *pboxa = boxad;
374  return 0;
375 }
376 
377 
378 /*------------------------------------------------------------------------*
379  * Greedy character splitting *
380  *------------------------------------------------------------------------*/
401 l_ok
403  PIX *pixs,
404  BOXA **pboxa,
405  NUMA **pnascore,
406  NUMA **pnaindex,
407  SARRAY **psachar,
408  l_int32 debug)
409 {
410 char *charstr;
411 l_int32 index, remove, w, h, bx, bw, bxc, bwc, w1, w2, w3;
412 l_float32 score;
413 BOX *box, *boxc, *boxtrans, *boxl, *boxr, *boxlt, *boxrt;
414 BOXA *boxat;
415 NUMA *nascoret, *naindext, *nasort;
416 PIX *pixb, *pixc, *pixl, *pixr, *pixdb, *pixd;
417 PIXA *pixar, *pixadb;
418 SARRAY *sachart;
419 
420 l_int32 iter;
421 
422  if (pnascore) *pnascore = NULL;
423  if (pnaindex) *pnaindex = NULL;
424  if (psachar) *psachar = NULL;
425  if (!pboxa)
426  return ERROR_INT("&boxa not defined", __func__, 1);
427  *pboxa = NULL;
428  if (!recog)
429  return ERROR_INT("recog not defined", __func__, 1);
430  if (!pixs || pixGetDepth(pixs) != 1)
431  return ERROR_INT("pixs not defined or not 1 bpp", __func__, 1);
432  if (pixGetWidth(pixs) < recog->minwidth_u - 4)
433  return ERROR_INT("pixs too narrow", __func__, 1);
434  if (!recog->train_done)
435  return ERROR_INT("training not finished", __func__, 1);
436 
437  /* Binarize and crop to foreground if necessary */
438  pixb = recogProcessToIdentify(recog, pixs, 0);
439 
440  /* Initialize the arrays */
441  boxat = boxaCreate(4);
442  nascoret = numaCreate(4);
443  naindext = numaCreate(4);
444  sachart = sarrayCreate(4);
445  pixadb = (debug) ? pixaCreate(4) : NULL;
446 
447  /* Initialize the images remaining to be processed with the input.
448  * These are stored in pixar, which is used here as a queue,
449  * on which we only put image fragments that are large enough to
450  * contain at least one character. */
451  pixar = pixaCreate(1);
452  pixGetDimensions(pixb, &w, &h, NULL);
453  box = boxCreate(0, 0, w, h);
454  pixaAddPix(pixar, pixb, L_INSERT);
455  pixaAddBox(pixar, box, L_INSERT);
456 
457  /* Successively split on the best match until nothing is left.
458  * To be safe, we limit the search to 10 characters. */
459  for (iter = 0; iter < 11; iter++) {
460  if (pixaGetCount(pixar) == 0)
461  break;
462  if (iter == 10) {
463  L_WARNING("more than 10 chars; ending search\n", __func__);
464  break;
465  }
466 
467  /* Pop one from the queue */
468  pixaRemovePixAndSave(pixar, 0, &pixc, &boxc);
469  boxGetGeometry(boxc, &bxc, NULL, &bwc, NULL);
470 
471  /* This is a single component; if noise, remove it */
472  recogSplittingFilter(recog, pixc, 0, MinFillFactor, &remove, debug);
473  if (debug)
474  lept_stderr("iter = %d, removed = %d\n", iter, remove);
475  if (remove) {
476  pixDestroy(&pixc);
477  boxDestroy(&boxc);
478  continue;
479  }
480 
481  /* Find the best character match */
482  if (debug) {
483  recogCorrelationBestChar(recog, pixc, &box, &score,
484  &index, &charstr, &pixdb);
485  pixaAddPix(pixadb, pixdb, L_INSERT);
486  } else {
487  recogCorrelationBestChar(recog, pixc, &box, &score,
488  &index, &charstr, NULL);
489  }
490 
491  /* Find the box in original coordinates, and append
492  * the results to the arrays. */
493  boxtrans = boxTransform(box, bxc, 0, 1.0, 1.0);
494  boxaAddBox(boxat, boxtrans, L_INSERT);
495  numaAddNumber(nascoret, score);
496  numaAddNumber(naindext, index);
497  sarrayAddString(sachart, charstr, L_INSERT);
498 
499  /* Split the current pixc into three regions and save
500  * each region if it is large enough. */
501  boxGetGeometry(box, &bx, NULL, &bw, NULL);
502  w1 = bx;
503  w2 = bw;
504  w3 = bwc - bx - bw;
505  if (debug)
506  lept_stderr(" w1 = %d, w2 = %d, w3 = %d\n", w1, w2, w3);
507  if (w1 < recog->minwidth_u - 4) {
508  if (debug) L_INFO("discarding width %d on left\n", __func__, w1);
509  } else { /* extract and save left region */
510  boxl = boxCreate(0, 0, bx + 1, h);
511  pixl = pixClipRectangle(pixc, boxl, NULL);
512  boxlt = boxTransform(boxl, bxc, 0, 1.0, 1.0);
513  pixaAddPix(pixar, pixl, L_INSERT);
514  pixaAddBox(pixar, boxlt, L_INSERT);
515  boxDestroy(&boxl);
516  }
517  if (w3 < recog->minwidth_u - 4) {
518  if (debug) L_INFO("discarding width %d on right\n", __func__, w3);
519  } else { /* extract and save left region */
520  boxr = boxCreate(bx + bw - 1, 0, w3 + 1, h);
521  pixr = pixClipRectangle(pixc, boxr, NULL);
522  boxrt = boxTransform(boxr, bxc, 0, 1.0, 1.0);
523  pixaAddPix(pixar, pixr, L_INSERT);
524  pixaAddBox(pixar, boxrt, L_INSERT);
525  boxDestroy(&boxr);
526  }
527  pixDestroy(&pixc);
528  boxDestroy(&box);
529  boxDestroy(&boxc);
530  }
531  pixaDestroy(&pixar);
532 
533 
534  /* Sort the output results by left-to-right in the boxa */
535  *pboxa = boxaSort(boxat, L_SORT_BY_X, L_SORT_INCREASING, &nasort);
536  if (pnascore)
537  *pnascore = numaSortByIndex(nascoret, nasort);
538  if (pnaindex)
539  *pnaindex = numaSortByIndex(naindext, nasort);
540  if (psachar)
541  *psachar = sarraySortByIndex(sachart, nasort);
542  numaDestroy(&nasort);
543  boxaDestroy(&boxat);
544  numaDestroy(&nascoret);
545  numaDestroy(&naindext);
546  sarrayDestroy(&sachart);
547 
548  /* Final debug output */
549  if (debug) {
550  pixd = pixaDisplayTiledInRows(pixadb, 32, 2000, 1.0, 0, 15, 2);
551  pixDisplay(pixd, 400, 400);
552  pixaAddPix(recog->pixadb_split, pixd, L_INSERT);
553  pixaDestroy(&pixadb);
554  }
555  return 0;
556 }
557 
558 
581 l_ok
583  PIX *pixs,
584  BOX **pbox,
585  l_float32 *pscore,
586  l_int32 *pindex,
587  char **pcharstr,
588  PIX **ppixdb)
589 {
590 l_int32 i, n, w1, h1, w2, area2, ycent2, delx, dely;
591 l_int32 bestdelx, bestdely, bestindex;
592 l_float32 score, bestscore;
593 BOX *box;
594 BOXA *boxa;
595 NUMA *nasum, *namoment;
596 PIX *pix1, *pix2;
597 
598  if (pindex) *pindex = 0;
599  if (pcharstr) *pcharstr = NULL;
600  if (ppixdb) *ppixdb = NULL;
601  if (pbox) *pbox = NULL;
602  if (pscore) *pscore = 0.0;
603  if (!pbox || !pscore)
604  return ERROR_INT("&box and &score not both defined", __func__, 1);
605  if (!recog)
606  return ERROR_INT("recog not defined", __func__, 1);
607  if (!pixs || pixGetDepth(pixs) != 1)
608  return ERROR_INT("pixs not defined or not 1 bpp", __func__, 1);
609  if (!recog->train_done)
610  return ERROR_INT("training not finished", __func__, 1);
611 
612  /* Binarize and crop to foreground if necessary. Add padding
613  * to both the left and right side; this is compensated for
614  * when reporting the bounding box of the best matched character. */
615  pix1 = recogProcessToIdentify(recog, pixs, LeftRightPadding);
616  pixGetDimensions(pix1, &w1, &h1, NULL);
617 
618  /* Compute vertical sum and moment arrays */
619  nasum = pixCountPixelsByColumn(pix1);
620  namoment = pixGetMomentByColumn(pix1, 1);
621 
622  /* Do shifted correlation against all averaged templates. */
623  n = recog->setsize;
624  boxa = boxaCreate(n); /* location of best fits for each character */
625  bestscore = 0.0;
626  bestindex = bestdelx = bestdely = 0;
627  for (i = 0; i < n; i++) {
628  pix2 = pixaGetPix(recog->pixa_u, i, L_CLONE);
629  w2 = pixGetWidth(pix2);
630  /* Note that the slightly expended w1 is typically larger
631  * than w2 (the template). */
632  if (w1 >= w2) {
633  numaGetIValue(recog->nasum_u, i, &area2);
634  ptaGetIPt(recog->pta_u, i, NULL, &ycent2);
635  pixCorrelationBestShift(pix1, pix2, nasum, namoment, area2, ycent2,
636  recog->maxyshift, recog->sumtab, &delx,
637  &dely, &score, 1);
638  if (ppixdb) {
639  lept_stderr(
640  "Best match template %d: (x,y) = (%d,%d), score = %5.3f\n",
641  i, delx, dely, score);
642  }
643  /* Compensate for padding */
644  box = boxCreate(delx - LeftRightPadding, 0, w2, h1);
645  if (score > bestscore) {
646  bestscore = score;
647  bestdelx = delx - LeftRightPadding;
648  bestdely = dely;
649  bestindex = i;
650  }
651  } else {
652  box = boxCreate(0, 0, 1, 1); /* placeholder */
653  if (ppixdb)
654  lept_stderr("Component too thin: w1 = %d, w2 = %d\n", w1, w2);
655  }
656  boxaAddBox(boxa, box, L_INSERT);
657  pixDestroy(&pix2);
658  }
659 
660  *pscore = bestscore;
661  *pbox = boxaGetBox(boxa, bestindex, L_COPY);
662  if (pindex) *pindex = bestindex;
663  if (pcharstr)
664  recogGetClassString(recog, bestindex, pcharstr);
665 
666  if (ppixdb) {
667  L_INFO("Best match: class %d; shifts (%d, %d)\n",
668  __func__, bestindex, bestdelx, bestdely);
669  pix2 = pixaGetPix(recog->pixa_u, bestindex, L_CLONE);
670  *ppixdb = recogShowMatch(recog, pix1, pix2, NULL, -1, 0.0);
671  pixDestroy(&pix2);
672  }
673 
674  pixDestroy(&pix1);
675  boxaDestroy(&boxa);
676  numaDestroy(&nasum);
677  numaDestroy(&namoment);
678  return 0;
679 }
680 
681 
721 static l_int32
723  PIX *pix2,
724  NUMA *nasum1,
725  NUMA *namoment1,
726  l_int32 area2,
727  l_int32 ycent2,
728  l_int32 maxyshift,
729  l_int32 *tab8,
730  l_int32 *pdelx,
731  l_int32 *pdely,
732  l_float32 *pscore,
733  l_int32 debugflag)
734 {
735 l_int32 w1, w2, h1, h2, i, j, nx, shifty, delx, dely;
736 l_int32 sum, moment, count;
737 l_int32 *tab, *area1, *arraysum, *arraymoment;
738 l_float32 maxscore, score;
739 l_float32 *ycent1;
740 FPIX *fpix;
741 PIX *pixt, *pixt1, *pixt2;
742 
743  if (pdelx) *pdelx = 0;
744  if (pdely) *pdely = 0;
745  if (pscore) *pscore = 0.0;
746  if (!pix1 || pixGetDepth(pix1) != 1)
747  return ERROR_INT("pix1 not defined or not 1 bpp", __func__, 1);
748  if (!pix2 || pixGetDepth(pix2) != 1)
749  return ERROR_INT("pix2 not defined or not 1 bpp", __func__, 1);
750  if (!nasum1 || !namoment1)
751  return ERROR_INT("nasum1 and namoment1 not both defined", __func__, 1);
752  if (area2 <= 0 || ycent2 <= 0)
753  return ERROR_INT("area2 and ycent2 must be > 0", __func__, 1);
754 
755  /* If pix1 (the unknown image) is narrower than pix2,
756  * don't bother to try the match. pix1 is already padded with
757  * 2 pixels on each side. */
758  pixGetDimensions(pix1, &w1, &h1, NULL);
759  pixGetDimensions(pix2, &w2, &h2, NULL);
760  if (w1 < w2) {
761  if (debugflag > 0) {
762  L_INFO("skipping match with w1 = %d and w2 = %d\n",
763  __func__, w1, w2);
764  }
765  return 0;
766  }
767  nx = w1 - w2 + 1;
768 
769  if (debugflag > 0)
770  fpix = fpixCreate(nx, 2 * maxyshift + 1);
771  if (!tab8)
772  tab = makePixelSumTab8();
773  else
774  tab = tab8;
775 
776  /* Set up the arrays for area1 and ycent1. We have to do this
777  * for each template (pix2) because the window width is w2. */
778  area1 = (l_int32 *)LEPT_CALLOC(nx, sizeof(l_int32));
779  ycent1 = (l_float32 *)LEPT_CALLOC(nx, sizeof(l_int32));
780  arraysum = numaGetIArray(nasum1);
781  arraymoment = numaGetIArray(namoment1);
782  for (i = 0, sum = 0, moment = 0; i < w2; i++) {
783  sum += arraysum[i];
784  moment += arraymoment[i];
785  }
786  for (i = 0; i < nx - 1; i++) {
787  area1[i] = sum;
788  ycent1[i] = (sum == 0) ? ycent2 : (l_float32)moment / (l_float32)sum;
789  sum += arraysum[w2 + i] - arraysum[i];
790  moment += arraymoment[w2 + i] - arraymoment[i];
791  }
792  area1[nx - 1] = sum;
793  ycent1[nx - 1] = (sum == 0) ? ycent2 : (l_float32)moment / (l_float32)sum;
794 
795  /* Find the best match location for pix2. At each location,
796  * to insure that pixels are ON only within the intersection of
797  * pix and the shifted pix2:
798  * (1) Start with pixt cleared and equal in size to pix1.
799  * (2) Blit the shifted pix2 onto pixt. Then all ON pixels
800  * are within the intersection of pix1 and the shifted pix2.
801  * (3) AND pix1 with pixt. */
802  pixt = pixCreate(w2, h1, 1);
803  maxscore = 0;
804  delx = 0;
805  dely = 0; /* amount to shift pix2 relative to pix1 to get alignment */
806  for (i = 0; i < nx; i++) {
807  shifty = (l_int32)(ycent1[i] - ycent2 + 0.5);
808  for (j = -maxyshift; j <= maxyshift; j++) {
809  pixClearAll(pixt);
810  pixRasterop(pixt, 0, shifty + j, w2, h2, PIX_SRC, pix2, 0, 0);
811  pixRasterop(pixt, 0, 0, w2, h1, PIX_SRC & PIX_DST, pix1, i, 0);
812  pixCountPixels(pixt, &count, tab);
813  score = (l_float32)count * (l_float32)count /
814  ((l_float32)area1[i] * (l_float32)area2);
815  if (score > maxscore) {
816  maxscore = score;
817  delx = i;
818  dely = shifty + j;
819  }
820 
821  if (debugflag > 0)
822  fpixSetPixel(fpix, i, maxyshift + j, 1000.0 * score);
823  }
824  }
825 
826  if (debugflag > 0) {
827  char buf[128];
828  lept_mkdir("lept/recog");
829  pixt1 = fpixDisplayMaxDynamicRange(fpix);
830  pixt2 = pixExpandReplicate(pixt1, 5);
831  snprintf(buf, sizeof(buf), "/tmp/lept/recog/junkbs_%d.png", debugflag);
832  pixWrite(buf, pixt2, IFF_PNG);
833  pixDestroy(&pixt1);
834  pixDestroy(&pixt2);
835  fpixDestroy(&fpix);
836  }
837 
838  if (pdelx) *pdelx = delx;
839  if (pdely) *pdely = dely;
840  if (pscore) *pscore = maxscore;
841  if (!tab8) LEPT_FREE(tab);
842  LEPT_FREE(area1);
843  LEPT_FREE(ycent1);
844  LEPT_FREE(arraysum);
845  LEPT_FREE(arraymoment);
846  pixDestroy(&pixt);
847  return 0;
848 }
849 
850 
851 /*------------------------------------------------------------------------*
852  * Low-level identification *
853  *------------------------------------------------------------------------*/
872 l_ok
874  PIXA *pixa,
875  PIX **ppixdb)
876 {
877 char *text;
878 l_int32 i, n, fail, index, depth;
879 l_float32 score;
880 PIX *pix1, *pix2, *pix3;
881 PIXA *pixa1;
882 L_RCH *rch;
883 
884  if (ppixdb) *ppixdb = NULL;
885  if (!recog)
886  return ERROR_INT("recog not defined", __func__, 1);
887  if (!pixa)
888  return ERROR_INT("pixa not defined", __func__, 1);
889 
890  /* Run the recognizer on the set of images. This writes
891  * the text string into each pix in pixa. */
892  n = pixaGetCount(pixa);
893  rchaDestroy(&recog->rcha);
894  recog->rcha = rchaCreate();
895  pixa1 = (ppixdb) ? pixaCreate(n) : NULL;
896  depth = 1;
897  for (i = 0; i < n; i++) {
898  pix1 = pixaGetPix(pixa, i, L_CLONE);
899  pix2 = NULL;
900  fail = FALSE;
901  if (!ppixdb)
902  fail = recogIdentifyPix(recog, pix1, NULL);
903  else
904  fail = recogIdentifyPix(recog, pix1, &pix2);
905  if (fail)
906  recogSkipIdentify(recog);
907  if ((rch = recog->rch) == NULL) {
908  L_ERROR("rch not found for char %d\n", __func__, i);
909  pixDestroy(&pix1);
910  pixDestroy(&pix2);
911  continue;
912  }
913  rchExtract(rch, NULL, NULL, &text, NULL, NULL, NULL, NULL);
914  pixSetText(pix1, text);
915  LEPT_FREE(text);
916  if (ppixdb) {
917  rchExtract(rch, &index, &score, NULL, NULL, NULL, NULL, NULL);
918  pix3 = recogShowMatch(recog, pix2, NULL, NULL, index, score);
919  if (i == 0) depth = pixGetDepth(pix3);
920  pixaAddPix(pixa1, pix3, L_INSERT);
921  pixDestroy(&pix2);
922  }
923  transferRchToRcha(rch, recog->rcha);
924  pixDestroy(&pix1);
925  }
926 
927  /* Package the images for debug */
928  if (ppixdb) {
929  *ppixdb = pixaDisplayTiledInRows(pixa1, depth, 2500, 1.0, 0, 20, 1);
930  pixaDestroy(&pixa1);
931  }
932 
933  return 0;
934 }
935 
936 
963 l_ok
965  PIX *pixs,
966  PIX **ppixdb)
967 {
968 char *text;
969 l_int32 i, j, n, bestindex, bestsample, area1, area2, ret;
970 l_int32 shiftx, shifty, bestdelx, bestdely, bestwidth, maxyshift;
971 l_float32 x1, y1, x2, y2, delx, dely, score, maxscore;
972 NUMA *numa;
973 PIX *pix0, *pix1, *pix2;
974 PIXA *pixa;
975 PTA *pta;
976 
977  if (ppixdb) *ppixdb = NULL;
978  if (!recog)
979  return ERROR_INT("recog not defined", __func__, 1);
980  if (!pixs || pixGetDepth(pixs) != 1)
981  return ERROR_INT("pixs not defined or not 1 bpp", __func__, 1);
982 
983  /* Do the averaging if required and not yet done. */
984  if (recog->templ_use == L_USE_AVERAGE_TEMPLATES && !recog->ave_done) {
985  ret = recogAverageSamples(recog, 0);
986  if (ret)
987  return ERROR_INT("averaging failed", __func__, 1);
988  }
989 
990  /* Binarize and crop to foreground if necessary */
991  if ((pix0 = recogProcessToIdentify(recog, pixs, 0)) == NULL)
992  return ERROR_INT("no fg pixels in pix0", __func__, 1);
993 
994  /* Optionally scale and/or convert to fixed stroke width */
995  pix1 = recogModifyTemplate(recog, pix0);
996  pixDestroy(&pix0);
997  if (!pix1)
998  return ERROR_INT("no fg pixels in pix1", __func__, 1);
999 
1000  /* Do correlation at all positions within +-maxyshift of
1001  * the nominal centroid alignment. */
1002  pixCountPixels(pix1, &area1, recog->sumtab);
1003  pixCentroid(pix1, recog->centtab, recog->sumtab, &x1, &y1);
1004  bestindex = bestsample = bestdelx = bestdely = bestwidth = 0;
1005  maxscore = 0.0;
1006  maxyshift = recog->maxyshift;
1007  if (recog->templ_use == L_USE_AVERAGE_TEMPLATES) {
1008  for (i = 0; i < recog->setsize; i++) {
1009  numaGetIValue(recog->nasum, i, &area2);
1010  if (area2 == 0) continue; /* no template available */
1011  pix2 = pixaGetPix(recog->pixa, i, L_CLONE);
1012  ptaGetPt(recog->pta, i, &x2, &y2);
1013  delx = x1 - x2;
1014  dely = y1 - y2;
1015  for (shifty = -maxyshift; shifty <= maxyshift; shifty++) {
1016  for (shiftx = -maxyshift; shiftx <= maxyshift; shiftx++) {
1017  pixCorrelationScoreSimple(pix1, pix2, area1, area2,
1018  delx + shiftx, dely + shifty,
1019  5, 5, recog->sumtab, &score);
1020  if (score > maxscore) {
1021  bestindex = i;
1022  bestdelx = delx + shiftx;
1023  bestdely = dely + shifty;
1024  maxscore = score;
1025  }
1026  }
1027  }
1028  pixDestroy(&pix2);
1029  }
1030  } else { /* use all the samples */
1031  for (i = 0; i < recog->setsize; i++) {
1032  pixa = pixaaGetPixa(recog->pixaa, i, L_CLONE);
1033  n = pixaGetCount(pixa);
1034  if (n == 0) {
1035  pixaDestroy(&pixa);
1036  continue;
1037  }
1038  numa = numaaGetNuma(recog->naasum, i, L_CLONE);
1039  pta = ptaaGetPta(recog->ptaa, i, L_CLONE);
1040  for (j = 0; j < n; j++) {
1041  pix2 = pixaGetPix(pixa, j, L_CLONE);
1042  numaGetIValue(numa, j, &area2);
1043  ptaGetPt(pta, j, &x2, &y2);
1044  delx = x1 - x2;
1045  dely = y1 - y2;
1046  for (shifty = -maxyshift; shifty <= maxyshift; shifty++) {
1047  for (shiftx = -maxyshift; shiftx <= maxyshift; shiftx++) {
1048  pixCorrelationScoreSimple(pix1, pix2, area1, area2,
1049  delx + shiftx, dely + shifty,
1050  5, 5, recog->sumtab, &score);
1051  if (score > maxscore) {
1052  bestindex = i;
1053  bestsample = j;
1054  bestdelx = delx + shiftx;
1055  bestdely = dely + shifty;
1056  maxscore = score;
1057  bestwidth = pixGetWidth(pix2);
1058  }
1059  }
1060  }
1061  pixDestroy(&pix2);
1062  }
1063  pixaDestroy(&pixa);
1064  numaDestroy(&numa);
1065  ptaDestroy(&pta);
1066  }
1067  }
1068 
1069  /* Package up the results */
1070  recogGetClassString(recog, bestindex, &text);
1071  rchDestroy(&recog->rch);
1072  recog->rch = rchCreate(bestindex, maxscore, text, bestsample,
1073  bestdelx, bestdely, bestwidth);
1074 
1075  if (ppixdb) {
1076  if (recog->templ_use == L_USE_AVERAGE_TEMPLATES) {
1077  L_INFO("Best match: str %s; class %d; sh (%d, %d); score %5.3f\n",
1078  __func__, text, bestindex, bestdelx, bestdely, maxscore);
1079  pix2 = pixaGetPix(recog->pixa, bestindex, L_CLONE);
1080  } else { /* L_USE_ALL_TEMPLATES */
1081  L_INFO("Best match: str %s; sample %d in class %d; score %5.3f\n",
1082  __func__, text, bestsample, bestindex, maxscore);
1083  if (maxyshift > 0 && (L_ABS(bestdelx) > 0 || L_ABS(bestdely) > 0)) {
1084  L_INFO(" Best shift: (%d, %d)\n",
1085  __func__, bestdelx, bestdely);
1086  }
1087  pix2 = pixaaGetPix(recog->pixaa, bestindex, bestsample, L_CLONE);
1088  }
1089  *ppixdb = recogShowMatch(recog, pix1, pix2, NULL, -1, 0.0);
1090  pixDestroy(&pix2);
1091  }
1092 
1093  pixDestroy(&pix1);
1094  return 0;
1095 }
1096 
1097 
1110 l_ok
1112 {
1113  if (!recog)
1114  return ERROR_INT("recog not defined", __func__, 1);
1115 
1116  /* Package up placeholder results */
1117  rchDestroy(&recog->rch);
1118  recog->rch = rchCreate(0, 0.0, stringNew(""), 0, 0, 0, 0);
1119  return 0;
1120 }
1121 
1122 
1123 /*------------------------------------------------------------------------*
1124  * Operations for handling identification results *
1125  *------------------------------------------------------------------------*/
1134 static L_RCHA *
1136 {
1137 L_RCHA *rcha;
1138 
1139  rcha = (L_RCHA *)LEPT_CALLOC(1, sizeof(L_RCHA));
1140  rcha->naindex = numaCreate(0);
1141  rcha->nascore = numaCreate(0);
1142  rcha->satext = sarrayCreate(0);
1143  rcha->nasample = numaCreate(0);
1144  rcha->naxloc = numaCreate(0);
1145  rcha->nayloc = numaCreate(0);
1146  rcha->nawidth = numaCreate(0);
1147  return rcha;
1148 }
1149 
1150 
1156 void
1158 {
1159 L_RCHA *rcha;
1160 
1161  if (prcha == NULL) {
1162  L_WARNING("&rcha is null!\n", __func__);
1163  return;
1164  }
1165  if ((rcha = *prcha) == NULL)
1166  return;
1167 
1168  numaDestroy(&rcha->naindex);
1169  numaDestroy(&rcha->nascore);
1170  sarrayDestroy(&rcha->satext);
1171  numaDestroy(&rcha->nasample);
1172  numaDestroy(&rcha->naxloc);
1173  numaDestroy(&rcha->nayloc);
1174  numaDestroy(&rcha->nawidth);
1175  LEPT_FREE(rcha);
1176  *prcha = NULL;
1177 }
1178 
1179 
1199 static L_RCH *
1200 rchCreate(l_int32 index,
1201  l_float32 score,
1202  char *text,
1203  l_int32 sample,
1204  l_int32 xloc,
1205  l_int32 yloc,
1206  l_int32 width)
1207 {
1208 L_RCH *rch;
1209 
1210  rch = (L_RCH *)LEPT_CALLOC(1, sizeof(L_RCH));
1211  rch->index = index;
1212  rch->score = score;
1213  rch->text = text;
1214  rch->sample = sample;
1215  rch->xloc = xloc;
1216  rch->yloc = yloc;
1217  rch->width = width;
1218  return rch;
1219 }
1220 
1221 
1227 void
1229 {
1230 L_RCH *rch;
1231 
1232  if (prch == NULL) {
1233  L_WARNING("&rch is null!\n", __func__);
1234  return;
1235  }
1236  if ((rch = *prch) == NULL)
1237  return;
1238  LEPT_FREE(rch->text);
1239  LEPT_FREE(rch);
1240  *prch = NULL;
1241 }
1242 
1243 
1263 l_ok
1265  NUMA **pnaindex,
1266  NUMA **pnascore,
1267  SARRAY **psatext,
1268  NUMA **pnasample,
1269  NUMA **pnaxloc,
1270  NUMA **pnayloc,
1271  NUMA **pnawidth)
1272 {
1273  if (pnaindex) *pnaindex = NULL;
1274  if (pnascore) *pnascore = NULL;
1275  if (psatext) *psatext = NULL;
1276  if (pnasample) *pnasample = NULL;
1277  if (pnaxloc) *pnaxloc = NULL;
1278  if (pnayloc) *pnayloc = NULL;
1279  if (pnawidth) *pnawidth = NULL;
1280  if (!rcha)
1281  return ERROR_INT("rcha not defined", __func__, 1);
1282 
1283  if (pnaindex) *pnaindex = numaClone(rcha->naindex);
1284  if (pnascore) *pnascore = numaClone(rcha->nascore);
1285  if (psatext) *psatext = sarrayClone(rcha->satext);
1286  if (pnasample) *pnasample = numaClone(rcha->nasample);
1287  if (pnaxloc) *pnaxloc = numaClone(rcha->naxloc);
1288  if (pnayloc) *pnayloc = numaClone(rcha->nayloc);
1289  if (pnawidth) *pnawidth = numaClone(rcha->nawidth);
1290  return 0;
1291 }
1292 
1293 
1307 l_ok
1309  l_int32 *pindex,
1310  l_float32 *pscore,
1311  char **ptext,
1312  l_int32 *psample,
1313  l_int32 *pxloc,
1314  l_int32 *pyloc,
1315  l_int32 *pwidth)
1316 {
1317  if (pindex) *pindex = 0;
1318  if (pscore) *pscore = 0.0;
1319  if (ptext) *ptext = NULL;
1320  if (psample) *psample = 0;
1321  if (pxloc) *pxloc = 0;
1322  if (pyloc) *pyloc = 0;
1323  if (pwidth) *pwidth = 0;
1324  if (!rch)
1325  return ERROR_INT("rch not defined", __func__, 1);
1326 
1327  if (pindex) *pindex = rch->index;
1328  if (pscore) *pscore = rch->score;
1329  if (ptext) *ptext = stringNew(rch->text); /* new string: owned by caller */
1330  if (psample) *psample = rch->sample;
1331  if (pxloc) *pxloc = rch->xloc;
1332  if (pyloc) *pyloc = rch->yloc;
1333  if (pwidth) *pwidth = rch->width;
1334  return 0;
1335 }
1336 
1337 
1351 static l_int32
1353  L_RCHA *rcha)
1354 {
1355 
1356  if (!rch)
1357  return ERROR_INT("rch not defined", __func__, 1);
1358  if (!rcha)
1359  return ERROR_INT("rcha not defined", __func__, 1);
1360 
1361  numaAddNumber(rcha->naindex, rch->index);
1362  numaAddNumber(rcha->nascore, rch->score);
1363  sarrayAddString(rcha->satext, rch->text, L_COPY);
1364  numaAddNumber(rcha->nasample, rch->sample);
1365  numaAddNumber(rcha->naxloc, rch->xloc);
1366  numaAddNumber(rcha->nayloc, rch->yloc);
1367  numaAddNumber(rcha->nawidth, rch->width);
1368  return 0;
1369 }
1370 
1371 
1372 /*------------------------------------------------------------------------*
1373  * Preprocessing and filtering *
1374  *------------------------------------------------------------------------*/
1391 PIX *
1393  PIX *pixs,
1394  l_int32 pad)
1395 {
1396 l_int32 canclip;
1397 PIX *pix1, *pix2, *pixd;
1398 
1399  if (!recog)
1400  return (PIX *)ERROR_PTR("recog not defined", __func__, NULL);
1401  if (!pixs)
1402  return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
1403 
1404  if (pixGetDepth(pixs) != 1)
1405  pix1 = pixThresholdToBinary(pixs, recog->threshold);
1406  else
1407  pix1 = pixClone(pixs);
1408  pixTestClipToForeground(pix1, &canclip);
1409  if (canclip)
1410  pixClipToForeground(pix1, &pix2, NULL);
1411  else
1412  pix2 = pixClone(pix1);
1413  pixDestroy(&pix1);
1414  if (!pix2)
1415  return (PIX *)ERROR_PTR("no foreground pixels", __func__, NULL);
1416 
1417  pixd = pixAddBorderGeneral(pix2, pad, pad, 0, 0, 0);
1418  pixDestroy(&pix2);
1419  return pixd;
1420 }
1421 
1422 
1433 static PIX *
1435  PIX *pixs,
1436  l_int32 minh,
1437  l_float32 minaf,
1438  l_int32 debug)
1439 {
1440 l_int32 scaling, minsplitw, maxsplith, maxasp;
1441 BOXA *boxas;
1442 NUMA *naw, *nah, *na1, *na1c, *na2, *na3, *na4, *na5, *na6, *na7;
1443 PIX *pixd;
1444 PIXA *pixas;
1445 
1446  if (!recog)
1447  return (PIX *)ERROR_PTR("recog not defined", __func__, NULL);
1448  if (!pixs)
1449  return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
1450 
1451  /* If there is scaling, do not remove components based on the
1452  * values of min_splitw and max_splith. */
1453  scaling = (recog->scalew > 0 || recog->scaleh > 0) ? TRUE : FALSE;
1454  minsplitw = (scaling) ? 1 : recog->min_splitw - 3;
1455  maxsplith = (scaling) ? 150 : recog->max_splith;
1456  maxasp = recog->max_wh_ratio;
1457 
1458  /* Generate an indicator array of connected components to remove:
1459  * short stuff
1460  * tall stuff
1461  * components with large width/height ratio
1462  * components with small area fill fraction */
1463  boxas = pixConnComp(pixs, &pixas, 8);
1464  pixaFindDimensions(pixas, &naw, &nah);
1465  na1 = numaMakeThresholdIndicator(naw, minsplitw, L_SELECT_IF_LT);
1466  na1c = numaCopy(na1);
1467  na2 = numaMakeThresholdIndicator(nah, minh, L_SELECT_IF_LT);
1468  na3 = numaMakeThresholdIndicator(nah, maxsplith, L_SELECT_IF_GT);
1469  na4 = pixaFindWidthHeightRatio(pixas);
1470  na5 = numaMakeThresholdIndicator(na4, maxasp, L_SELECT_IF_GT);
1471  na6 = pixaFindAreaFraction(pixas);
1472  na7 = numaMakeThresholdIndicator(na6, minaf, L_SELECT_IF_LT);
1473  numaLogicalOp(na1, na1, na2, L_UNION);
1474  numaLogicalOp(na1, na1, na3, L_UNION);
1475  numaLogicalOp(na1, na1, na5, L_UNION);
1476  numaLogicalOp(na1, na1, na7, L_UNION);
1477  pixd = pixCopy(NULL, pixs);
1478  pixRemoveWithIndicator(pixd, pixas, na1);
1479  if (debug)
1480  l_showIndicatorSplitValues(na1c, na2, na3, na5, na7, na1);
1481  numaDestroy(&naw);
1482  numaDestroy(&nah);
1483  numaDestroy(&na1);
1484  numaDestroy(&na1c);
1485  numaDestroy(&na2);
1486  numaDestroy(&na3);
1487  numaDestroy(&na4);
1488  numaDestroy(&na5);
1489  numaDestroy(&na6);
1490  numaDestroy(&na7);
1491  boxaDestroy(&boxas);
1492  pixaDestroy(&pixas);
1493  return pixd;
1494 }
1495 
1496 
1508 static l_int32
1510  PIX *pixs,
1511  l_int32 minh,
1512  l_float32 minaf,
1513  l_int32 *premove,
1514  l_int32 debug)
1515 {
1516 l_int32 w, h;
1517 l_float32 aspratio, fract;
1518 
1519  if (!premove)
1520  return ERROR_INT("&remove not defined", __func__, 1);
1521  *premove = 0;
1522  if (!recog)
1523  return ERROR_INT("recog not defined", __func__, 1);
1524  if (!pixs)
1525  return ERROR_INT("pixs not defined", __func__, 1);
1526  if (minh <= 0) minh = DefaultMinHeight;
1527 
1528  /* Remove from further consideration:
1529  * small stuff
1530  * components with large width/height ratio
1531  * components with small area fill fraction */
1532  pixGetDimensions(pixs, &w, &h, NULL);
1533  if (w < recog->min_splitw) {
1534  if (debug) L_INFO("w = %d < %d\n", __func__, w, recog->min_splitw);
1535  *premove = 1;
1536  return 0;
1537  }
1538  if (h < minh) {
1539  if (debug) L_INFO("h = %d < %d\n", __func__, h, minh);
1540  *premove = 1;
1541  return 0;
1542  }
1543  aspratio = (l_float32)w / (l_float32)h;
1544  if (aspratio > recog->max_wh_ratio) {
1545  if (debug) L_INFO("w/h = %5.3f too large\n", __func__, aspratio);
1546  *premove = 1;
1547  return 0;
1548  }
1549  pixFindAreaFraction(pixs, recog->sumtab, &fract);
1550  if (fract < minaf) {
1551  if (debug) L_INFO("area fill fract %5.3f < %5.3f\n",
1552  __func__, fract, minaf);
1553  *premove = 1;
1554  return 0;
1555  }
1556 
1557  return 0;
1558 }
1559 
1560 
1561 /*------------------------------------------------------------------------*
1562  * Postprocessing *
1563  *------------------------------------------------------------------------*/
1598 SARRAY *
1600  BOXA *boxas,
1601  l_float32 scorethresh,
1602  l_int32 spacethresh,
1603  BOXAA **pbaa,
1604  NUMAA **pnaa)
1605 {
1606 char *str, *text;
1607 l_int32 i, n, x1, x2, h_ovl, v_ovl, h_sep, v_sep;
1608 l_float32 score;
1609 BOX *box, *prebox;
1610 BOXA *ba;
1611 BOXAA *baa;
1612 NUMA *nascore, *na;
1613 NUMAA *naa;
1614 SARRAY *satext, *sa, *saout;
1615 
1616  if (pbaa) *pbaa = NULL;
1617  if (pnaa) *pnaa = NULL;
1618  if (!recog || !recog->rcha)
1619  return (SARRAY *)ERROR_PTR("recog and rcha not both defined",
1620  __func__, NULL);
1621  if (!boxas)
1622  return (SARRAY *)ERROR_PTR("boxas not defined", __func__, NULL);
1623 
1624  if (spacethresh < 0)
1625  spacethresh = L_MAX(recog->maxheight_u, 20);
1626  rchaExtract(recog->rcha, NULL, &nascore, &satext, NULL, NULL, NULL, NULL);
1627  if (!nascore || !satext) {
1628  numaDestroy(&nascore);
1629  sarrayDestroy(&satext);
1630  return (SARRAY *)ERROR_PTR("nascore and satext not both returned",
1631  __func__, NULL);
1632  }
1633 
1634  saout = sarrayCreate(0);
1635  naa = numaaCreate(0);
1636  baa = boxaaCreate(0);
1637  prebox = NULL;
1638  n = numaGetCount(nascore);
1639  for (i = 0; i < n; i++) {
1640  numaGetFValue(nascore, i, &score);
1641  text = sarrayGetString(satext, i, L_NOCOPY);
1642  if (prebox == NULL) { /* no current run */
1643  if (score < scorethresh) {
1644  continue;
1645  } else { /* start a number run */
1646  sa = sarrayCreate(0);
1647  ba = boxaCreate(0);
1648  na = numaCreate(0);
1649  sarrayAddString(sa, text, L_COPY);
1650  prebox = boxaGetBox(boxas, i, L_CLONE);
1651  boxaAddBox(ba, prebox, L_COPY);
1652  numaAddNumber(na, score);
1653  }
1654  } else { /* in a current number run */
1655  box = boxaGetBox(boxas, i, L_CLONE);
1656  boxGetGeometry(prebox, &x1, NULL, NULL, NULL);
1657  boxGetGeometry(box, &x2, NULL, NULL, NULL);
1658  boxOverlapDistance(box, prebox, &h_ovl, &v_ovl);
1659  h_sep = -h_ovl;
1660  v_sep = -v_ovl;
1661  boxDestroy(&prebox);
1662  if (x1 < x2 && h_sep <= spacethresh &&
1663  v_sep < 0 && score >= scorethresh) { /* add to number */
1664  sarrayAddString(sa, text, L_COPY);
1665  boxaAddBox(ba, box, L_COPY);
1666  numaAddNumber(na, score);
1667  prebox = box;
1668  } else { /* save the completed number */
1669  str = sarrayToString(sa, 0);
1670  sarrayAddString(saout, str, L_INSERT);
1671  sarrayDestroy(&sa);
1672  boxaaAddBoxa(baa, ba, L_INSERT);
1673  numaaAddNuma(naa, na, L_INSERT);
1674  boxDestroy(&box);
1675  if (score >= scorethresh) { /* start a new number */
1676  i--;
1677  continue;
1678  }
1679  }
1680  }
1681  }
1682 
1683  if (prebox) { /* save the last number */
1684  str = sarrayToString(sa, 0);
1685  sarrayAddString(saout, str, L_INSERT);
1686  boxaaAddBoxa(baa, ba, L_INSERT);
1687  numaaAddNuma(naa, na, L_INSERT);
1688  sarrayDestroy(&sa);
1689  boxDestroy(&prebox);
1690  }
1691 
1692  numaDestroy(&nascore);
1693  sarrayDestroy(&satext);
1694  if (sarrayGetCount(saout) == 0) {
1695  sarrayDestroy(&saout);
1696  boxaaDestroy(&baa);
1697  numaaDestroy(&naa);
1698  L_INFO("saout has no identified text\n", __func__);
1699  return NULL;
1700  }
1701 
1702  if (pbaa)
1703  *pbaa = baa;
1704  else
1705  boxaaDestroy(&baa);
1706  if (pnaa)
1707  *pnaa = naa;
1708  else
1709  numaaDestroy(&naa);
1710  return saout;
1711 }
1712 
1731 PIXA *
1733  SARRAY *sa,
1734  BOXAA *baa,
1735  NUMAA *naa,
1736  PIX **ppixdb)
1737 {
1738 char buf[128];
1739 char *textstr, *scorestr;
1740 l_int32 i, j, n, nchar, len;
1741 l_float32 score;
1742 L_BMF *bmf;
1743 BOX *box1, *box2;
1744 BOXA *ba;
1745 NUMA *na;
1746 PIX *pix1, *pix2, *pix3, *pix4;
1747 PIXA *pixa;
1748 
1749  if (ppixdb) *ppixdb = NULL;
1750  if (!pixs)
1751  return (PIXA *)ERROR_PTR("pixs not defined", __func__, NULL);
1752  if (!sa)
1753  return (PIXA *)ERROR_PTR("sa not defined", __func__, NULL);
1754  if (!baa)
1755  return (PIXA *)ERROR_PTR("baa not defined", __func__, NULL);
1756  if (!naa)
1757  return (PIXA *)ERROR_PTR("naa not defined", __func__, NULL);
1758 
1759  n = sarrayGetCount(sa);
1760  pixa = pixaCreate(n);
1761  bmf = bmfCreate(NULL, 6);
1762  if (ppixdb) *ppixdb = pixConvertTo8(pixs, 1);
1763  for (i = 0; i < n; i++) {
1764  textstr = sarrayGetString(sa, i, L_NOCOPY);
1765  ba = boxaaGetBoxa(baa, i, L_CLONE);
1766  na = numaaGetNuma(naa, i, L_CLONE);
1767  boxaGetExtent(ba, NULL, NULL, &box1);
1768  box2 = boxAdjustSides(NULL, box1, -5, 5, -5, 5);
1769  if (ppixdb) pixRenderBoxArb(*ppixdb, box2, 3, 255, 0, 0);
1770  pix1 = pixClipRectangle(pixs, box1, NULL);
1771  len = strlen(textstr) + 1;
1772  pix2 = pixAddBlackOrWhiteBorder(pix1, 14 * len, 14 * len,
1773  5, 3, L_SET_WHITE);
1774  pix3 = pixConvertTo8(pix2, 1);
1775  nchar = numaGetCount(na);
1776  scorestr = NULL;
1777  for (j = 0; j < nchar; j++) {
1778  numaGetFValue(na, j, &score);
1779  snprintf(buf, sizeof(buf), "%d", (l_int32)(100 * score));
1780  stringJoinIP(&scorestr, buf);
1781  if (j < nchar - 1) stringJoinIP(&scorestr, ",");
1782  }
1783  snprintf(buf, sizeof(buf), "%s: %s\n", textstr, scorestr);
1784  pix4 = pixAddTextlines(pix3, bmf, buf, 0xff000000, L_ADD_BELOW);
1785  pixaAddPix(pixa, pix4, L_INSERT);
1786  boxDestroy(&box1);
1787  boxDestroy(&box2);
1788  pixDestroy(&pix1);
1789  pixDestroy(&pix2);
1790  pixDestroy(&pix3);
1791  boxaDestroy(&ba);
1792  numaDestroy(&na);
1793  LEPT_FREE(scorestr);
1794  }
1795 
1796  bmfDestroy(&bmf);
1797  return pixa;
1798 }
1799 
1800 
1801 /*------------------------------------------------------------------------*
1802  * Static debug helper *
1803  *------------------------------------------------------------------------*/
1816 static void
1818  NUMA *na2,
1819  NUMA *na3,
1820  NUMA *na4,
1821  NUMA *na5,
1822  NUMA *na6)
1823 {
1824 l_int32 i, n;
1825 
1826  n = numaGetCount(na1);
1827  lept_stderr("================================================\n");
1828  lept_stderr("lt minw: ");
1829  for (i = 0; i < n; i++)
1830  lept_stderr("%4d ", (l_int32)na1->array[i]);
1831  lept_stderr("\nlt minh: ");
1832  for (i = 0; i < n; i++)
1833  lept_stderr("%4d ", (l_int32)na2->array[i]);
1834  lept_stderr("\ngt maxh: ");
1835  for (i = 0; i < n; i++)
1836  lept_stderr("%4d ", (l_int32)na3->array[i]);
1837  lept_stderr("\ngt maxasp: ");
1838  for (i = 0; i < n; i++)
1839  lept_stderr("%4d ", (l_int32)na4->array[i]);
1840  lept_stderr("\nlt minaf: ");
1841  for (i = 0; i < n; i++)
1842  lept_stderr("%4d ", (l_int32)na5->array[i]);
1843  lept_stderr("\n------------------------------------------------");
1844  lept_stderr("\nresult: ");
1845  for (i = 0; i < n; i++)
1846  lept_stderr("%4d ", (l_int32)na6->array[i]);
1847  lept_stderr("\n================================================\n");
1848 }
void bmfDestroy(L_BMF **pbmf)
bmfDestroy()
Definition: bmf.c:168
L_BMF * bmfCreate(const char *dir, l_int32 fontsize)
bmfCreate()
Definition: bmf.c:118
l_ok boxGetGeometry(const BOX *box, l_int32 *px, l_int32 *py, l_int32 *pw, l_int32 *ph)
boxGetGeometry()
Definition: boxbasic.c:301
void boxDestroy(BOX **pbox)
boxDestroy()
Definition: boxbasic.c:273
BOXAA * boxaaCreate(l_int32 n)
boxaaCreate()
Definition: boxbasic.c:1145
l_ok boxaaAddBoxa(BOXAA *baa, BOXA *ba, l_int32 copyflag)
boxaaAddBoxa()
Definition: boxbasic.c:1241
l_ok boxaAddBox(BOXA *boxa, BOX *box, l_int32 copyflag)
boxaAddBox()
Definition: boxbasic.c:553
void boxaDestroy(BOXA **pboxa)
boxaDestroy()
Definition: boxbasic.c:519
l_int32 boxaGetCount(const BOXA *boxa)
boxaGetCount()
Definition: boxbasic.c:661
BOXA * boxaaGetBoxa(BOXAA *baa, l_int32 index, l_int32 accessflag)
boxaaGetBoxa()
Definition: boxbasic.c:1386
BOX * boxaGetBox(BOXA *boxa, l_int32 index, l_int32 accessflag)
boxaGetBox()
Definition: boxbasic.c:702
void boxaaDestroy(BOXAA **pbaa)
boxaaDestroy()
Definition: boxbasic.c:1207
BOX * boxCreate(l_int32 x, l_int32 y, l_int32 w, l_int32 h)
boxCreate()
Definition: boxbasic.c:171
BOXA * boxaCreate(l_int32 n)
boxaCreate()
Definition: boxbasic.c:442
l_ok boxaJoin(BOXA *boxad, BOXA *boxas, l_int32 istart, l_int32 iend)
boxaJoin()
Definition: boxfunc1.c:2460
l_ok boxOverlapDistance(BOX *box1, BOX *box2, l_int32 *ph_ovl, l_int32 *pv_ovl)
boxOverlapDistance()
Definition: boxfunc1.c:1015
BOXA * boxaHandleOverlaps(BOXA *boxas, l_int32 op, l_int32 range, l_float32 min_overlap, l_float32 max_ratio, NUMA **pnamap)
boxaHandleOverlaps()
Definition: boxfunc1.c:887
BOX * boxAdjustSides(BOX *boxd, BOX *boxs, l_int32 delleft, l_int32 delright, l_int32 deltop, l_int32 delbot)
boxAdjustSides()
Definition: boxfunc1.c:1932
BOX * boxTransform(BOX *box, l_int32 shiftx, l_int32 shifty, l_float32 scalex, l_float32 scaley)
boxTransform()
Definition: boxfunc2.c:151
BOXA * boxaTransform(BOXA *boxas, l_int32 shiftx, l_int32 shifty, l_float32 scalex, l_float32 scaley)
boxaTransform()
Definition: boxfunc2.c:103
BOXA * boxaaFlattenToBoxa(BOXAA *baa, NUMA **pnaindex, l_int32 copyflag)
boxaaFlattenToBoxa()
Definition: boxfunc2.c:1609
BOXA * boxaSort(BOXA *boxas, l_int32 sorttype, l_int32 sortorder, NUMA **pnaindex)
boxaSort()
Definition: boxfunc2.c:624
BOXAA * boxaSort2d(BOXA *boxas, NUMAA **pnaad, l_int32 delta1, l_int32 delta2, l_int32 minh1)
boxaSort2d()
Definition: boxfunc2.c:896
l_ok boxaGetExtent(BOXA *boxa, l_int32 *pw, l_int32 *ph, BOX **pbox)
boxaGetExtent()
Definition: boxfunc4.c:922
BOXA * pixConnComp(PIX *pixs, PIXA **ppixa, l_int32 connectivity)
pixConnComp()
Definition: conncomp.c:152
l_ok fpixSetPixel(FPIX *fpix, l_int32 x, l_int32 y, l_float32 val)
fpixSetPixel()
Definition: fpix1.c:527
void fpixDestroy(FPIX **pfpix)
fpixDestroy()
Definition: fpix1.c:280
FPIX * fpixCreate(l_int32 width, l_int32 height)
fpixCreate()
Definition: fpix1.c:152
PIX * fpixDisplayMaxDynamicRange(FPIX *fpixs)
fpixDisplayMaxDynamicRange()
Definition: fpix2.c:422
l_ok pixRenderBoxArb(PIX *pix, BOX *box, l_int32 width, l_uint8 rval, l_uint8 gval, l_uint8 bval)
pixRenderBoxArb()
Definition: graphics.c:1606
l_ok pixRenderBoxaArb(PIX *pix, BOXA *boxa, l_int32 width, l_uint8 rval, l_uint8 gval, l_uint8 bval)
pixRenderBoxaArb()
Definition: graphics.c:1717
PIX * pixThresholdToBinary(PIX *pixs, l_int32 thresh)
pixThresholdToBinary()
Definition: grayquant.c:443
l_ok pixCentroid(PIX *pix, l_int32 *centtab, l_int32 *sumtab, l_float32 *pxave, l_float32 *pyave)
pixCentroid()
Definition: morphapp.c:1494
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:460
l_ok numaGetFValue(NUMA *na, l_int32 index, l_float32 *pval)
numaGetFValue()
Definition: numabasic.c:687
NUMA * numaCreate(l_int32 n)
numaCreate()
Definition: numabasic.c:193
NUMA * numaaGetNuma(NUMAA *naa, l_int32 index, l_int32 accessflag)
numaaGetNuma()
Definition: numabasic.c:1617
NUMA * numaClone(NUMA *na)
numaClone()
Definition: numabasic.c:414
void numaDestroy(NUMA **pna)
numaDestroy()
Definition: numabasic.c:357
NUMAA * numaaCreate(l_int32 n)
numaaCreate()
Definition: numabasic.c:1302
l_int32 numaGetCount(NUMA *na)
numaGetCount()
Definition: numabasic.c:630
l_ok numaGetIValue(NUMA *na, l_int32 index, l_int32 *pival)
numaGetIValue()
Definition: numabasic.c:720
l_ok numaaAddNuma(NUMAA *naa, NUMA *na, l_int32 copyflag)
numaaAddNuma()
Definition: numabasic.c:1435
NUMA * numaCopy(NUMA *na)
numaCopy()
Definition: numabasic.c:387
l_int32 * numaGetIArray(NUMA *na)
numaGetIArray()
Definition: numabasic.c:807
void numaaDestroy(NUMAA **pnaa)
numaaDestroy()
Definition: numabasic.c:1401
NUMA * numaMakeThresholdIndicator(NUMA *nas, l_float32 thresh, l_int32 type)
numaMakeThresholdIndicator()
Definition: numafunc1.c:1184
NUMA * numaLogicalOp(NUMA *nad, NUMA *na1, NUMA *na2, l_int32 op)
numaLogicalOp()
Definition: numafunc1.c:252
NUMA * numaSortByIndex(NUMA *nas, NUMA *naindex)
numaSortByIndex()
Definition: numafunc1.c:2825
void pixDestroy(PIX **ppix)
pixDestroy()
Definition: pix1.c:608
l_ok pixGetDimensions(const PIX *pix, l_int32 *pw, l_int32 *ph, l_int32 *pd)
pixGetDimensions()
Definition: pix1.c:1074
l_ok pixSetText(PIX *pix, const char *textstring)
pixSetText()
Definition: pix1.c:1430
PIX * pixCopy(PIX *pixd, const PIX *pixs)
pixCopy()
Definition: pix1.c:689
PIX * pixCreate(l_int32 width, l_int32 height, l_int32 depth)
pixCreate()
Definition: pix1.c:315
PIX * pixClone(PIX *pixs)
pixClone()
Definition: pix1.c:582
l_ok pixClearAll(PIX *pix)
pixClearAll()
Definition: pix2.c:773
PIX * pixAddBorderGeneral(PIX *pixs, l_int32 left, l_int32 right, l_int32 top, l_int32 bot, l_uint32 val)
pixAddBorderGeneral()
Definition: pix2.c:1863
PIX * pixAddBlackOrWhiteBorder(PIX *pixs, l_int32 left, l_int32 right, l_int32 top, l_int32 bot, l_int32 op)
pixAddBlackOrWhiteBorder()
Definition: pix2.c:1811
l_ok pixZero(PIX *pix, l_int32 *pempty)
pixZero()
Definition: pix3.c:1777
l_ok pixCountPixels(PIX *pixs, l_int32 *pcount, l_int32 *tab8)
pixCountPixels()
Definition: pix3.c:1893
NUMA * pixCountPixelsByColumn(PIX *pix)
pixCountPixelsByColumn()
Definition: pix3.c:2128
NUMA * pixGetMomentByColumn(PIX *pix, l_int32 order)
pixGetMomentByColumn()
Definition: pix3.c:2228
l_int32 * makePixelSumTab8(void)
makePixelSumTab8()
Definition: pix3.c:2354
NUMA * pixaFindAreaFraction(PIXA *pixa)
pixaFindAreaFraction()
Definition: pix5.c:429
l_ok pixFindAreaFraction(PIX *pixs, l_int32 *tab, l_float32 *pfract)
pixFindAreaFraction()
Definition: pix5.c:470
PIX * pixClipRectangle(PIX *pixs, BOX *box, BOX **pboxc)
pixClipRectangle()
Definition: pix5.c:994
l_ok pixTestClipToForeground(PIX *pixs, l_int32 *pcanclip)
pixTestClipToForeground()
Definition: pix5.c:1826
NUMA * pixaFindWidthHeightRatio(PIXA *pixa)
pixaFindWidthHeightRatio()
Definition: pix5.c:650
l_ok pixClipToForeground(PIX *pixs, PIX **ppixd, BOX **pbox)
pixClipToForeground()
Definition: pix5.c:1728
l_ok pixaFindDimensions(PIXA *pixa, NUMA **pnaw, NUMA **pnah)
pixaFindDimensions()
Definition: pix5.c:140
PIXA * pixClipRectangles(PIX *pixs, BOXA *boxa)
pixClipRectangles()
Definition: pix5.c:930
#define PIX_DST
Definition: pix.h:445
@ L_SELECT_IF_LT
Definition: pix.h:575
@ L_SELECT_IF_GT
Definition: pix.h:576
@ L_SORT_BY_X
Definition: pix.h:528
@ L_ADD_BELOW
Definition: pix.h:1003
@ L_COPY
Definition: pix.h:505
@ L_CLONE
Definition: pix.h:506
@ L_NOCOPY
Definition: pix.h:503
@ L_INSERT
Definition: pix.h:504
@ L_SET_WHITE
Definition: pix.h:699
@ L_COMBINE
Definition: pix.h:880
#define PIX_SRC
Definition: pix.h:444
@ L_SORT_INCREASING
Definition: pix.h:522
l_ok pixaAddPix(PIXA *pixa, PIX *pix, l_int32 copyflag)
pixaAddPix()
Definition: pixabasic.c:493
void pixaDestroy(PIXA **ppixa)
pixaDestroy()
Definition: pixabasic.c:404
PIXA * pixaCreate(l_int32 n)
pixaCreate()
Definition: pixabasic.c:167
l_ok pixaRemovePixAndSave(PIXA *pixa, l_int32 index, PIX **ppix, BOX **pbox)
pixaRemovePixAndSave()
Definition: pixabasic.c:1397
l_int32 pixaGetCount(PIXA *pixa)
pixaGetCount()
Definition: pixabasic.c:629
l_ok pixaAddBox(PIXA *pixa, BOX *box, l_int32 copyflag)
pixaAddBox()
Definition: pixabasic.c:540
PIX * pixaaGetPix(PIXAA *paa, l_int32 index, l_int32 ipix, l_int32 accessflag)
pixaaGetPix()
Definition: pixabasic.c:2154
PIXA * pixaaGetPixa(PIXAA *paa, l_int32 index, l_int32 accesstype)
pixaaGetPixa()
Definition: pixabasic.c:2096
PIX * pixaGetPix(PIXA *pixa, l_int32 index, l_int32 accesstype)
pixaGetPix()
Definition: pixabasic.c:647
l_ok pixRemoveWithIndicator(PIX *pixs, PIXA *pixa, NUMA *na)
pixRemoveWithIndicator()
Definition: pixafunc1.c:1199
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:730
PIX * pixaDisplayTiledInColumns(PIXA *pixas, l_int32 nx, l_float32 scalefactor, l_int32 spacing, l_int32 border)
pixaDisplayTiledInColumns()
Definition: pixafunc2.c:912
PIX * pixConvertTo1(PIX *pixs, l_int32 threshold)
pixConvertTo1()
Definition: pixconv.c:2952
PIX * pixConvertTo8(PIX *pixs, l_int32 cmapflag)
pixConvertTo8()
Definition: pixconv.c:3055
PIX * pixConvertTo32(PIX *pixs)
pixConvertTo32()
Definition: pixconv.c:3246
PTA * ptaaGetPta(PTAA *ptaa, l_int32 index, l_int32 accessflag)
ptaaGetPta()
Definition: ptabasic.c:1064
l_ok ptaGetIPt(PTA *pta, l_int32 index, l_int32 *px, l_int32 *py)
ptaGetIPt()
Definition: ptabasic.c:527
l_ok ptaGetPt(PTA *pta, l_int32 index, l_float32 *px, l_float32 *py)
ptaGetPt()
Definition: ptabasic.c:499
void ptaDestroy(PTA **ppta)
ptaDestroy()
Definition: ptabasic.c:191
@ L_USE_AVERAGE_TEMPLATES
Definition: recog.h:261
l_int32 recogGetClassString(L_RECOG *recog, l_int32 index, char **pcharstr)
recogGetClassString()
Definition: recogbasic.c:733
BOXA * recogDecode(L_RECOG *recog, PIX *pixs, l_int32 nlevels, PIX **ppixdb)
recogDecode()
Definition: recogdid.c:219
PIXA * showExtractNumbers(PIX *pixs, SARRAY *sa, BOXAA *baa, NUMAA *naa, PIX **ppixdb)
showExtractNumbers()
Definition: recogident.c:1732
SARRAY * recogExtractNumbers(L_RECOG *recog, BOXA *boxas, l_float32 scorethresh, l_int32 spacethresh, BOXAA **pbaa, NUMAA **pnaa)
recogExtractNumbers()
Definition: recogident.c:1599
l_ok recogCorrelationBestChar(L_RECOG *recog, PIX *pixs, BOX **pbox, l_float32 *pscore, l_int32 *pindex, char **pcharstr, PIX **ppixdb)
recogCorrelationBestChar()
Definition: recogident.c:582
void rchaDestroy(L_RCHA **prcha)
rchaDestroy()
Definition: recogident.c:1157
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:1308
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:1509
static void l_showIndicatorSplitValues(NUMA *na1, NUMA *na2, NUMA *na3, NUMA *na4, NUMA *na5, NUMA *na6)
l_showIndicatorSplitValues()
Definition: recogident.c:1817
static l_int32 transferRchToRcha(L_RCH *rch, L_RCHA *rcha)
transferRchToRcha()
Definition: recogident.c:1352
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:722
void rchDestroy(L_RCH **prch)
rchDestroy()
Definition: recogident.c:1228
l_ok recogIdentifyPixa(L_RECOG *recog, PIXA *pixa, PIX **ppixdb)
recogIdentifyPixa()
Definition: recogident.c:873
l_ok recogIdentifyPix(L_RECOG *recog, PIX *pixs, PIX **ppixdb)
recogIdentifyPix()
Definition: recogident.c:964
static L_RCHA * rchaCreate()
rchaCreate()
Definition: recogident.c:1135
l_ok recogCorrelationBestRow(L_RECOG *recog, PIX *pixs, BOXA **pboxa, NUMA **pnascore, NUMA **pnaindex, SARRAY **psachar, l_int32 debug)
recogCorrelationBestRow()
Definition: recogident.c:402
l_ok recogSkipIdentify(L_RECOG *recog)
recogSkipIdentify()
Definition: recogident.c:1111
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:163
static PIX * recogPreSplittingFilter(L_RECOG *recog, PIX *pixs, l_int32 minh, l_float32 minaf, l_int32 debug)
recogPreSplittingFilter()
Definition: recogident.c:1434
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:249
l_ok rchaExtract(L_RCHA *rcha, NUMA **pnaindex, NUMA **pnascore, SARRAY **psatext, NUMA **pnasample, NUMA **pnaxloc, NUMA **pnayloc, NUMA **pnawidth)
rchaExtract()
Definition: recogident.c:1264
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:1200
PIX * recogProcessToIdentify(L_RECOG *recog, PIX *pixs, l_int32 pad)
recogProcessToIdentify()
Definition: recogident.c:1392
PIX * recogShowMatch(L_RECOG *recog, PIX *pix1, PIX *pix2, BOX *box, l_int32 index, l_float32 score)
recogShowMatch()
Definition: recogtrain.c:2369
PIX * recogModifyTemplate(L_RECOG *recog, PIX *pixs)
recogModifyTemplate()
Definition: recogtrain.c:416
l_int32 recogAverageSamples(L_RECOG *recog, l_int32 debug)
recogAverageSamples()
Definition: recogtrain.c:484
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:169
char * sarrayGetString(SARRAY *sa, l_int32 index, l_int32 copyflag)
sarrayGetString()
Definition: sarray1.c:673
SARRAY * sarrayClone(SARRAY *sa)
sarrayClone()
Definition: sarray1.c:411
l_int32 sarrayGetCount(SARRAY *sa)
sarrayGetCount()
Definition: sarray1.c:617
void sarrayDestroy(SARRAY **psa)
sarrayDestroy()
Definition: sarray1.c:353
l_ok sarrayAddString(SARRAY *sa, const char *string, l_int32 copyflag)
sarrayAddString()
Definition: sarray1.c:435
char * sarrayToString(SARRAY *sa, l_int32 addnlflag)
sarrayToString()
Definition: sarray1.c:716
SARRAY * sarraySortByIndex(SARRAY *sain, NUMA *naindex)
sarraySortByIndex()
Definition: sarray2.c:146
PIX * pixExpandReplicate(PIX *pixs, l_int32 factor)
pixExpandReplicate()
Definition: scale2.c:852
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
l_float32 * array
PIX * pixAddTextlines(PIX *pixs, L_BMF *bmf, const char *textstr, l_uint32 val, l_int32 location)
pixAddTextlines()
Definition: textops.c:274
void lept_stderr(const char *fmt,...)
lept_stderr()
Definition: utils1.c:306
char * stringNew(const char *src)
stringNew()
Definition: utils2.c:223
l_ok stringJoinIP(char **psrc1, const char *src2)
stringJoinIP()
Definition: utils2.c:559
l_int32 lept_mkdir(const char *subdir)
lept_mkdir()
Definition: utils2.c:2138