Leptonica  1.77.0
Image processing and image analysis suite
recogtrain.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 
161 #include <string.h>
162 #include "allheaders.h"
163 
164  /* Static functions */
165 static l_int32 recogTemplatesAreOK(L_RECOG *recog, l_int32 minsize,
166  l_float32 minfract, l_int32 *pok);
168 static l_int32 recogCharsetAvailable(l_int32 type);
169 static PIX *pixDisplayOutliers(PIXA *pixas, NUMA *nas);
170 static PIX *recogDisplayOutlier(L_RECOG *recog, l_int32 iclass, l_int32 jsamp,
171  l_int32 maxclass, l_float32 maxscore);
172 
173  /* Default parameters that are used in recogTemplatesAreOK() and
174  * in outlier removal functions, and that use template set size
175  * to decide if the set of templates (before outliers are removed)
176  * is valid. Values are set to accept most sets of sample templates. */
177 static const l_int32 DEFAULT_MIN_SET_SIZE = 1; /* minimum number of
178  samples for a valid class */
179 static const l_float32 DEFAULT_MIN_SET_FRACT = 0.4; /* minimum fraction
180  of classes required for a valid recog */
181 
182  /* Defaults in pixaRemoveOutliers1() and pixaRemoveOutliers2() */
183 static const l_float32 DEFAULT_MIN_SCORE = 0.75; /* keep everything above */
184 static const l_int32 DEFAULT_MIN_TARGET = 3; /* to be kept if possible */
185 static const l_float32 LOWER_SCORE_THRESHOLD = 0.5; /* templates can be
186  * kept down to this score to if needed to retain the
187  * desired minimum number of templates */
188 
189 
190 /*------------------------------------------------------------------------*
191  * Training *
192  *------------------------------------------------------------------------*/
211 l_ok
213  PIX *pixs,
214  BOX *box,
215  char *text,
216  l_int32 debug)
217 {
218 l_int32 ret;
219 PIX *pix;
220 
221  PROCNAME("recogTrainLabeled");
222 
223  if (!recog)
224  return ERROR_INT("recog not defined", procName, 1);
225  if (!pixs)
226  return ERROR_INT("pixs not defined", procName, 1);
227 
228  /* Prepare the sample to be added. This step also acts
229  * as a filter, and can invalidate pixs as a template. */
230  ret = recogProcessLabeled(recog, pixs, box, text, &pix);
231  if (ret) {
232  pixDestroy(&pix);
233  L_WARNING("failure to get sample '%s' for training\n", procName,
234  text);
235  return 1;
236  }
237 
238  recogAddSample(recog, pix, debug);
239  pixDestroy(&pix);
240  return 0;
241 }
242 
243 
260 l_ok
262  PIX *pixs,
263  BOX *box,
264  char *text,
265  PIX **ppix)
266 {
267 char *textdata;
268 l_int32 textinpix, textin, nsets;
269 NUMA *na;
270 PIX *pix1, *pix2, *pix3, *pix4;
271 
272  PROCNAME("recogProcessLabeled");
273 
274  if (!ppix)
275  return ERROR_INT("&pix not defined", procName, 1);
276  *ppix = NULL;
277  if (!recog)
278  return ERROR_INT("recog not defined", procName, 1);
279  if (!pixs)
280  return ERROR_INT("pixs not defined", procName, 1);
281 
282  /* Find the text; this will be stored with the output images */
283  textin = text && (text[0] != '\0');
284  textinpix = (pixs->text && (pixs->text[0] != '\0'));
285  if (!textin && !textinpix) {
286  L_ERROR("no text: %d\n", procName, recog->num_samples);
287  return 1;
288  }
289  textdata = (textin) ? text : pixs->text; /* do not free */
290 
291  /* Crop and binarize if necessary */
292  if (box)
293  pix1 = pixClipRectangle(pixs, box, NULL);
294  else
295  pix1 = pixClone(pixs);
296  if (pixGetDepth(pix1) > 1)
297  pix2 = pixConvertTo1(pix1, recog->threshold);
298  else
299  pix2 = pixClone(pix1);
300  pixDestroy(&pix1);
301 
302  /* Remove isolated noise, using as a criterion all components
303  * that are removed by a vertical opening of size 5. */
304  pix3 = pixMorphSequence(pix2, "o1.5", 0); /* seed */
305  pixSeedfillBinary(pix3, pix3, pix2, 8); /* fill from seed; clip to pix2 */
306  pixDestroy(&pix2);
307 
308  /* Clip to foreground */
309  pixClipToForeground(pix3, &pix4, NULL);
310  pixDestroy(&pix3);
311  if (!pix4)
312  return ERROR_INT("pix4 is empty", procName, 1);
313 
314  /* Verify that if there is more than 1 c.c., they all have
315  * horizontal overlap */
316  na = pixCountByColumn(pix4, NULL);
317  numaCountNonzeroRuns(na, &nsets);
318  numaDestroy(&na);
319  if (nsets > 1) {
320  L_WARNING("found %d sets of horiz separated c.c.; skipping\n",
321  procName, nsets);
322  pixDestroy(&pix4);
323  return 1;
324  }
325 
326  pixSetText(pix4, textdata);
327  *ppix = pix4;
328  return 0;
329 }
330 
331 
351 l_ok
353  PIX *pix,
354  l_int32 debug)
355 {
356 char *text;
357 l_int32 npa, charint, index;
358 PIXA *pixa1;
359 PIXAA *paa;
360 
361  PROCNAME("recogAddSample");
362 
363  if (!recog)
364  return ERROR_INT("recog not defined", procName, 1);
365  if (!pix || pixGetDepth(pix) != 1)
366  return ERROR_INT("pix not defined or not 1 bpp\n", procName, 1);
367  if (recog->train_done)
368  return ERROR_INT("not added: training has been completed", procName, 1);
369  paa = recog->pixaa_u;
370 
371  /* Make sure the character is in the set */
372  text = pixGetText(pix);
373  if (l_convertCharstrToInt(text, &charint) == 1) {
374  L_ERROR("invalid text: %s\n", procName, text);
375  return 1;
376  }
377 
378  /* Determine the class array index. Check if the class
379  * alreadly exists, and if not, add it. */
380  if (recogGetClassIndex(recog, charint, text, &index) == 1) {
381  /* New class must be added */
382  npa = pixaaGetCount(paa, NULL);
383  if (index > npa) {
384  L_ERROR("oops: bad index %d > npa %d!!\n", procName, index, npa);
385  return 1;
386  }
387  if (index == npa) { /* paa needs to be extended */
388  L_INFO("Adding new class and pixa: index = %d, text = %s\n",
389  procName, index, text);
390  pixa1 = pixaCreate(10);
391  pixaaAddPixa(paa, pixa1, L_INSERT);
392  }
393  }
394  if (debug) {
395  L_INFO("Identified text label: %s\n", procName, text);
396  L_INFO("Identified: charint = %d, index = %d\n",
397  procName, charint, index);
398  }
399 
400  /* Insert the unscaled character image into the right pixa.
401  * (Unscaled images are required to split touching characters.) */
402  recog->num_samples++;
403  pixaaAddPix(paa, index, pix, NULL, L_COPY);
404  return 0;
405 }
406 
407 
416 PIX *
418  PIX *pixs)
419 {
420 l_int32 w, h, empty;
421 PIX *pix1, *pix2;
422 
423  PROCNAME("recogModifyTemplate");
424 
425  if (!recog)
426  return (PIX *)ERROR_PTR("recog not defined", procName, NULL);
427  if (!pixs)
428  return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
429 
430  /* Scale first */
431  pixGetDimensions(pixs, &w, &h, NULL);
432  if ((recog->scalew == 0 || recog->scalew == w) &&
433  (recog->scaleh == 0 || recog->scaleh == h)) { /* no scaling */
434  pix1 = pixCopy(NULL, pixs);
435  } else {
436  pix1 = pixScaleToSize(pixs, recog->scalew, recog->scaleh);
437  }
438  if (!pix1)
439  return (PIX *)ERROR_PTR("pix1 not made", procName, NULL);
440 
441  /* Then optionally convert to lines */
442  if (recog->linew <= 0) {
443  pix2 = pixClone(pix1);
444  } else {
445  pix2 = pixSetStrokeWidth(pix1, recog->linew, 1, 8);
446  }
447  pixDestroy(&pix1);
448  if (!pix2)
449  return (PIX *)ERROR_PTR("pix2 not made", procName, NULL);
450 
451  /* Make sure we still have some pixels */
452  pixZero(pix2, &empty);
453  if (empty) {
454  pixDestroy(&pix2);
455  return (PIX *)ERROR_PTR("modified template has no pixels",
456  procName, NULL);
457  }
458  return pix2;
459 }
460 
461 
485 l_int32
487  l_int32 debug)
488 {
489 l_int32 i, nsamp, size, area, bx, by, badclass;
490 l_float32 x, y, hratio;
491 BOX *box;
492 PIXA *pixa1;
493 PIX *pix1, *pix2, *pix3;
494 PTA *pta1;
495 L_RECOG *recog;
496 
497  PROCNAME("recogAverageSamples");
498 
499  if (!precog)
500  return ERROR_INT("&recog not defined", procName, 1);
501  if ((recog = *precog) == NULL)
502  return ERROR_INT("recog not defined", procName, 1);
503 
504  if (recog->ave_done) {
505  if (debug) /* always do this if requested */
507  return 0;
508  }
509 
510  /* Remove any previous averaging data */
511  size = recog->setsize;
512  pixaDestroy(&recog->pixa_u);
513  ptaDestroy(&recog->pta_u);
514  numaDestroy(&recog->nasum_u);
515  recog->pixa_u = pixaCreate(size);
516  recog->pta_u = ptaCreate(size);
517  recog->nasum_u = numaCreate(size);
518 
519  pixaDestroy(&recog->pixa);
520  ptaDestroy(&recog->pta);
521  numaDestroy(&recog->nasum);
522  recog->pixa = pixaCreate(size);
523  recog->pta = ptaCreate(size);
524  recog->nasum = numaCreate(size);
525 
526  /* Unscaled bitmaps: compute averaged bitmap, centroid, and fg area.
527  * Note that when we threshold to 1 bpp the 8 bpp averaged template
528  * that is returned from the accumulator, it will not be cropped
529  * to the foreground. We must crop it, because the correlator
530  * makes that assumption and will return a zero value if the
531  * width or height of the two images differs by several pixels.
532  * But cropping to fg can cause the value of the centroid to
533  * change, if bx > 0 or by > 0. */
534  badclass = FALSE;
535  for (i = 0; i < size; i++) {
536  pixa1 = pixaaGetPixa(recog->pixaa_u, i, L_CLONE);
537  pta1 = ptaaGetPta(recog->ptaa_u, i, L_CLONE);
538  nsamp = pixaGetCount(pixa1);
539  nsamp = L_MIN(nsamp, 256); /* we only use the first 256 */
540  if (nsamp == 0) { /* no information for this class */
541  L_ERROR("no samples in class %d\n", procName, i);
542  badclass = TRUE;
543  pixaDestroy(&pixa1);
544  ptaDestroy(&pta1);
545  break;
546  } else {
547  pixaAccumulateSamples(pixa1, pta1, &pix1, &x, &y);
548  pix2 = pixThresholdToBinary(pix1, L_MAX(1, nsamp / 2));
549  pixInvert(pix2, pix2);
550  pixClipToForeground(pix2, &pix3, &box);
551  if (!box) {
552  L_ERROR("no fg pixels in average for uclass %d\n", procName, i);
553  badclass = TRUE;
554  pixDestroy(&pix1);
555  pixDestroy(&pix2);
556  pixaDestroy(&pixa1);
557  ptaDestroy(&pta1);
558  break;
559  } else {
560  boxGetGeometry(box, &bx, &by, NULL, NULL);
561  pixaAddPix(recog->pixa_u, pix3, L_INSERT);
562  ptaAddPt(recog->pta_u, x - bx, y - by); /* correct centroid */
563  pixCountPixels(pix3, &area, recog->sumtab);
564  numaAddNumber(recog->nasum_u, area); /* foreground */
565  boxDestroy(&box);
566  }
567  pixDestroy(&pix1);
568  pixDestroy(&pix2);
569  }
570  pixaDestroy(&pixa1);
571  ptaDestroy(&pta1);
572  }
573 
574  /* Are any classes bad? If so, destroy the recog and return an error */
575  if (badclass) {
576  recogDestroy(precog);
577  return ERROR_INT("at least 1 bad class; destroying recog", procName, 1);
578  }
579 
580  /* Get the range of sizes of the unscaled average templates.
581  * Reject if the height ratio is too large. */
582  pixaSizeRange(recog->pixa_u, &recog->minwidth_u, &recog->minheight_u,
583  &recog->maxwidth_u, &recog->maxheight_u);
584  hratio = (l_float32)recog->maxheight_u / (l_float32)recog->minheight_u;
585  if (hratio > recog->max_ht_ratio) {
586  L_ERROR("ratio of max/min height of average templates = %4.1f;"
587  " destroying recog\n", procName, hratio);
588  recogDestroy(precog);
589  return 1;
590  }
591 
592  /* Scaled bitmaps: compute averaged bitmap, centroid, and fg area */
593  for (i = 0; i < size; i++) {
594  pixa1 = pixaaGetPixa(recog->pixaa, i, L_CLONE);
595  pta1 = ptaaGetPta(recog->ptaa, i, L_CLONE);
596  nsamp = pixaGetCount(pixa1);
597  nsamp = L_MIN(nsamp, 256); /* we only use the first 256 */
598  pixaAccumulateSamples(pixa1, pta1, &pix1, &x, &y);
599  pix2 = pixThresholdToBinary(pix1, L_MAX(1, nsamp / 2));
600  pixInvert(pix2, pix2);
601  pixClipToForeground(pix2, &pix3, &box);
602  if (!box) {
603  L_ERROR("no fg pixels in average for sclass %d\n", procName, i);
604  badclass = TRUE;
605  pixDestroy(&pix1);
606  pixDestroy(&pix2);
607  pixaDestroy(&pixa1);
608  ptaDestroy(&pta1);
609  break;
610  } else {
611  boxGetGeometry(box, &bx, &by, NULL, NULL);
612  pixaAddPix(recog->pixa, pix3, L_INSERT);
613  ptaAddPt(recog->pta, x - bx, y - by); /* correct centroid */
614  pixCountPixels(pix3, &area, recog->sumtab);
615  numaAddNumber(recog->nasum, area); /* foreground */
616  boxDestroy(&box);
617  }
618  pixDestroy(&pix1);
619  pixDestroy(&pix2);
620  pixaDestroy(&pixa1);
621  ptaDestroy(&pta1);
622  }
623 
624  if (badclass) {
625  recogDestroy(precog);
626  return ERROR_INT("at least 1 bad class; destroying recog", procName, 1);
627  }
628 
629  /* Get the range of widths of the scaled average templates */
630  pixaSizeRange(recog->pixa, &recog->minwidth, NULL, &recog->maxwidth, NULL);
631 
632  /* Get dimensions useful for splitting */
633  recog->min_splitw = L_MAX(5, recog->minwidth_u - 5);
634  recog->max_splith = recog->maxheight_u + 12; /* allow for skew */
635 
636  if (debug)
638 
639  recog->ave_done = TRUE;
640  return 0;
641 }
642 
643 
663 l_int32
665  PTA *pta,
666  PIX **ppixd,
667  l_float32 *px,
668  l_float32 *py)
669 {
670 l_int32 i, n, maxw, maxh, xdiff, ydiff;
671 l_int32 *centtab, *sumtab;
672 l_float32 xc, yc, xave, yave;
673 PIX *pix1, *pix2, *pixsum;
674 PTA *ptac;
675 
676  PROCNAME("pixaAccumulateSamples");
677 
678  if (px) *px = 0;
679  if (py) *py = 0;
680  if (!ppixd)
681  return ERROR_INT("&pixd not defined", procName, 1);
682  *ppixd = NULL;
683  if (!pixa)
684  return ERROR_INT("pixa not defined", procName, 1);
685 
686  n = pixaGetCount(pixa);
687  if (pta && ptaGetCount(pta) != n)
688  return ERROR_INT("pta count differs from pixa count", procName, 1);
689  n = L_MIN(n, 256); /* take the first 256 only */
690  if (n == 0)
691  return ERROR_INT("pixa array empty", procName, 1);
692 
693  /* Find the centroids */
694  if (pta) {
695  ptac = ptaClone(pta);
696  } else { /* generate them here */
697  ptac = ptaCreate(n);
698  centtab = makePixelCentroidTab8();
699  sumtab = makePixelSumTab8();
700  for (i = 0; i < n; i++) {
701  pix1 = pixaGetPix(pixa, i, L_CLONE);
702  pixCentroid(pix1, centtab, sumtab, &xc, &yc);
703  ptaAddPt(ptac, xc, yc);
704  }
705  LEPT_FREE(centtab);
706  LEPT_FREE(sumtab);
707  }
708 
709  /* Find the average value of the centroids */
710  xave = yave = 0;
711  for (i = 0; i < n; i++) {
712  ptaGetPt(pta, i, &xc, &yc);
713  xave += xc;
714  yave += yc;
715  }
716  xave = xave / (l_float32)n;
717  yave = yave / (l_float32)n;
718  if (px) *px = xave;
719  if (py) *py = yave;
720 
721  /* Place all pix with their centroids located at the average
722  * centroid value, and sum the results. Make the accumulator
723  * image slightly larger than the largest sample to insure
724  * that all pixels are represented in the accumulator. */
725  pixaSizeRange(pixa, NULL, NULL, &maxw, &maxh);
726  pixsum = pixInitAccumulate(maxw + 5, maxh + 5, 0);
727  pix1 = pixCreate(maxw, maxh, 1);
728  for (i = 0; i < n; i++) {
729  pix2 = pixaGetPix(pixa, i, L_CLONE);
730  ptaGetPt(ptac, i, &xc, &yc);
731  xdiff = (l_int32)(xave - xc);
732  ydiff = (l_int32)(yave - yc);
733  pixClearAll(pix1);
734  pixRasterop(pix1, xdiff, ydiff, maxw, maxh, PIX_SRC,
735  pix2, 0, 0);
736  pixAccumulate(pixsum, pix1, L_ARITH_ADD);
737  pixDestroy(&pix2);
738  }
739  *ppixd = pixFinalAccumulate(pixsum, 0, 8);
740 
741  pixDestroy(&pix1);
742  pixDestroy(&pixsum);
743  ptaDestroy(&ptac);
744  return 0;
745 }
746 
747 
782 l_ok
784  l_int32 modifyflag,
785  l_int32 minsize,
786  l_float32 minfract)
787 {
788 l_int32 ok, i, j, size, nc, ns, area;
789 l_float32 xave, yave;
790 PIX *pix, *pixd;
791 PIXA *pixa;
792 PIXAA *paa;
793 PTA *pta;
794 PTAA *ptaa;
795 L_RECOG *recog;
796 
797  PROCNAME("recogTrainingFinished");
798 
799  if (!precog)
800  return ERROR_INT("&recog not defined", procName, 1);
801  if ((recog = *precog) == NULL)
802  return ERROR_INT("recog not defined", procName, 1);
803  if (recog->train_done) return 0;
804 
805  /* Test the input templates */
806  recogTemplatesAreOK(recog, minsize, minfract, &ok);
807  if (!ok) {
808  recogDestroy(precog);
809  return ERROR_INT("bad templates", procName, 1);
810  }
811 
812  /* Generate the storage for the possibly-scaled training bitmaps */
813  size = recog->maxarraysize;
814  paa = pixaaCreate(size);
815  pixa = pixaCreate(1);
816  pixaaInitFull(paa, pixa);
817  pixaDestroy(&pixa);
818  pixaaDestroy(&recog->pixaa);
819  recog->pixaa = paa;
820 
821  /* Generate the storage for the unscaled centroid training data */
822  ptaa = ptaaCreate(size);
823  pta = ptaCreate(0);
824  ptaaInitFull(ptaa, pta);
825  ptaaDestroy(&recog->ptaa_u);
826  recog->ptaa_u = ptaa;
827 
828  /* Generate the storage for the possibly-scaled centroid data */
829  ptaa = ptaaCreate(size);
830  ptaaInitFull(ptaa, pta);
831  ptaDestroy(&pta);
832  ptaaDestroy(&recog->ptaa);
833  recog->ptaa = ptaa;
834 
835  /* Generate the storage for the fg area data */
836  numaaDestroy(&recog->naasum_u);
837  numaaDestroy(&recog->naasum);
838  recog->naasum_u = numaaCreateFull(size, 0);
839  recog->naasum = numaaCreateFull(size, 0);
840 
841  paa = recog->pixaa_u;
842  nc = recog->setsize;
843  for (i = 0; i < nc; i++) {
844  pixa = pixaaGetPixa(paa, i, L_CLONE);
845  ns = pixaGetCount(pixa);
846  for (j = 0; j < ns; j++) {
847  /* Save centroid and area data for the unscaled pix */
848  pix = pixaGetPix(pixa, j, L_CLONE);
849  pixCentroid(pix, recog->centtab, recog->sumtab, &xave, &yave);
850  ptaaAddPt(recog->ptaa_u, i, xave, yave);
851  pixCountPixels(pix, &area, recog->sumtab);
852  numaaAddNumber(recog->naasum_u, i, area); /* foreground */
853 
854  /* Insert the (optionally) scaled character image, and
855  * save centroid and area data for it */
856  if (modifyflag == 1)
857  pixd = recogModifyTemplate(recog, pix);
858  else
859  pixd = pixClone(pix);
860  if (pixd) {
861  pixaaAddPix(recog->pixaa, i, pixd, NULL, L_INSERT);
862  pixCentroid(pixd, recog->centtab, recog->sumtab, &xave, &yave);
863  ptaaAddPt(recog->ptaa, i, xave, yave);
864  pixCountPixels(pixd, &area, recog->sumtab);
865  numaaAddNumber(recog->naasum, i, area);
866  } else {
867  L_ERROR("failed: modified template for class %d, sample %d\n",
868  procName, i, j);
869  }
870  pixDestroy(&pix);
871  }
872  pixaDestroy(&pixa);
873  }
874 
875  /* Truncate the arrays to those with non-empty containers */
876  pixaaTruncate(recog->pixaa_u);
877  pixaaTruncate(recog->pixaa);
878  ptaaTruncate(recog->ptaa_u);
879  ptaaTruncate(recog->ptaa);
880  numaaTruncate(recog->naasum_u);
881  numaaTruncate(recog->naasum);
882 
883  recog->train_done = TRUE;
884  return 0;
885 }
886 
887 
907 static l_int32
909  l_int32 minsize,
910  l_float32 minfract,
911  l_int32 *pok)
912 {
913 l_int32 i, n, validsets, nt;
914 l_float32 ratio;
915 NUMA *na;
916 
917  PROCNAME("recogTemplatesAreOK");
918 
919  if (!pok)
920  return ERROR_INT("&ok not defined", procName, 1);
921  *pok = 0;
922  if (!recog)
923  return ERROR_INT("recog not defined", procName, 1);
924 
925  minsize = (minsize < 0) ? DEFAULT_MIN_SET_SIZE : minsize;
926  minfract = (minfract < 0) ? DEFAULT_MIN_SET_FRACT : minfract;
927  n = pixaaGetCount(recog->pixaa_u, &na);
928  validsets = 0;
929  for (i = 0, validsets = 0; i < n; i++) {
930  numaGetIValue(na, i, &nt);
931  if (nt >= minsize)
932  validsets++;
933  }
934  numaDestroy(&na);
935  ratio = (l_float32)validsets / (l_float32)recog->charset_size;
936  *pok = (ratio >= minfract) ? 1 : 0;
937  return 0;
938 }
939 
940 
969 PIXA *
971  l_int32 setsize,
972  l_int32 maxkeep,
973  l_float32 max_ht_ratio,
974  NUMA **pna)
975 {
976 l_int32 i, j, h90, hj, j1, j2, j90, n, nc;
977 l_float32 ratio;
978 NUMA *na;
979 PIXA *pixa1, *pixa2, *pixa3, *pixa4, *pixa5;
980 PIXAA *paa;
981 
982  PROCNAME("recogFilterPixaBySize");
983 
984  if (pna) *pna = NULL;
985  if (!pixas)
986  return (PIXA *)ERROR_PTR("pixas not defined", procName, NULL);
987 
988  if ((paa = recogSortPixaByClass(pixas, setsize)) == NULL)
989  return (PIXA *)ERROR_PTR("paa not made", procName, NULL);
990  nc = pixaaGetCount(paa, NULL);
991  na = (pna) ? numaCreate(0) : NULL;
992  if (pna) *pna = na;
993  pixa5 = pixaCreate(0);
994  for (i = 0; i < nc; i++) {
995  pixa1 = pixaaGetPixa(paa, i, L_CLONE);
996  if ((n = pixaGetCount(pixa1)) == 0) {
997  pixaDestroy(&pixa1);
998  continue;
999  }
1000  pixa2 = pixaSort(pixa1, L_SORT_BY_HEIGHT, L_SORT_INCREASING, NULL,
1001  L_COPY);
1002  j90 = (l_int32)(0.9 * n);
1003  pixaGetPixDimensions(pixa2, j90, NULL, &h90, NULL);
1004  pixa3 = pixaCreate(n);
1005  for (j = 0; j < n; j++) {
1006  pixaGetPixDimensions(pixa2, j, NULL, &hj, NULL);
1007  ratio = (l_float32)h90 / (l_float32)hj;
1008  if (ratio <= max_ht_ratio)
1009  pixaAddPix(pixa3, pixaGetPix(pixa2, j, L_COPY), L_INSERT);
1010  }
1011  n = pixaGetCount(pixa3);
1012  if (n <= maxkeep) {
1013  pixa4 = pixaCopy(pixa3, L_CLONE);
1014  } else {
1015  j1 = (n - maxkeep) / 2;
1016  j2 = j1 + maxkeep - 1;
1017  pixa4 = pixaSelectRange(pixa3, j1, j2, L_CLONE);
1018  }
1019  if (na) numaAddNumber(na, pixaGetCount(pixa4));
1020  pixaJoin(pixa5, pixa4, 0, -1);
1021  pixaDestroy(&pixa1);
1022  pixaDestroy(&pixa2);
1023  pixaDestroy(&pixa3);
1024  pixaDestroy(&pixa4);
1025  }
1026 
1027  pixaaDestroy(&paa);
1028  return pixa5;
1029 }
1030 
1031 
1040 PIXAA *
1042  l_int32 setsize)
1043 {
1044 PIXAA *paa;
1045 L_RECOG *recog;
1046 
1047  PROCNAME("recogSortPixaByClass");
1048 
1049  if (!pixa)
1050  return (PIXAA *)ERROR_PTR("pixa not defined", procName, NULL);
1051 
1052  if ((recog = recogCreateFromPixaNoFinish(pixa, 0, 0, 0, 0, 0)) == NULL)
1053  return (PIXAA *)ERROR_PTR("recog not made", procName, NULL);
1054  paa = recog->pixaa_u; /* grab the paa of unscaled templates */
1055  recog->pixaa_u = NULL;
1056  recogDestroy(&recog);
1057  return paa;
1058 }
1059 
1060 
1080 l_ok
1082  l_float32 minscore,
1083  l_int32 mintarget,
1084  l_int32 minsize,
1085  PIX **ppixsave,
1086  PIX **ppixrem)
1087 {
1088 PIXA *pixa1, *pixa2;
1089 L_RECOG *recog;
1090 
1091  PROCNAME("recogRemoveOutliers1");
1092 
1093  if (!precog)
1094  return ERROR_INT("&recog not defined", procName, 1);
1095  if (*precog == NULL)
1096  return ERROR_INT("recog not defined", procName, 1);
1097 
1098  /* Extract the unscaled templates */
1099  pixa1 = recogExtractPixa(*precog);
1100  recogDestroy(precog);
1101 
1102  pixa2 = pixaRemoveOutliers1(pixa1, minscore, mintarget, minsize,
1103  ppixsave, ppixrem);
1104  pixaDestroy(&pixa1);
1105  if (!pixa2)
1106  return ERROR_INT("failure to remove outliers", procName, 1);
1107 
1108  recog = recogCreateFromPixa(pixa2, 0, 0, 0, 150, 1);
1109  pixaDestroy(&pixa2);
1110  if (!recog)
1111  return ERROR_INT("failure to make recog from pixa sans outliers",
1112  procName, 1);
1113 
1114  *precog = recog;
1115  return 0;
1116 }
1117 
1118 
1158 PIXA *
1160  l_float32 minscore,
1161  l_int32 mintarget,
1162  l_int32 minsize,
1163  PIX **ppixsave,
1164  PIX **ppixrem)
1165 {
1166 l_int32 i, j, debug, n, area1, area2;
1167 l_float32 x1, y1, x2, y2, minfract, score, rankscore, threshscore;
1168 NUMA *nasum, *narem, *nasave, *nascore;
1169 PIX *pix1, *pix2;
1170 PIXA *pixa, *pixarem, *pixad;
1171 PTA *pta;
1172 L_RECOG *recog;
1173 
1174  PROCNAME("pixaRemoveOutliers1");
1175 
1176  if (ppixsave) *ppixsave = NULL;
1177  if (ppixrem) *ppixrem = NULL;
1178  if (!pixas)
1179  return (PIXA *)ERROR_PTR("pixas not defined", procName, NULL);
1180  minscore = L_MIN(minscore, 1.0);
1181  if (minscore <= 0.0)
1182  minscore = DEFAULT_MIN_SCORE;
1183  mintarget = L_MIN(mintarget, 3);
1184  if (mintarget <= 0)
1185  mintarget = DEFAULT_MIN_TARGET;
1186  if (minsize < 0)
1187  minsize = DEFAULT_MIN_SET_SIZE;
1188 
1189  /* Make a special height-scaled recognizer with average templates */
1190  debug = (ppixsave || ppixrem) ? 1 : 0;
1191  recog = recogCreateFromPixa(pixas, 0, 40, 0, 128, 1);
1192  if (!recog)
1193  return (PIXA *)ERROR_PTR("bad pixas; recog not made", procName, NULL);
1194  recogAverageSamples(&recog, debug);
1195  if (!recog)
1196  return (PIXA *)ERROR_PTR("bad templates", procName, NULL);
1197 
1198  nasave = (ppixsave) ? numaCreate(0) : NULL;
1199  pixarem = (ppixrem) ? pixaCreate(0) : NULL;
1200  narem = (ppixrem) ? numaCreate(0) : NULL;
1201 
1202  pixad = pixaCreate(0);
1203  for (i = 0; i < recog->setsize; i++) {
1204  /* Access the average template and values for scaled
1205  * images in this class */
1206  pix1 = pixaGetPix(recog->pixa, i, L_CLONE);
1207  ptaGetPt(recog->pta, i, &x1, &y1);
1208  numaGetIValue(recog->nasum, i, &area1);
1209 
1210  /* Get the scores for each sample in the class */
1211  pixa = pixaaGetPixa(recog->pixaa, i, L_CLONE);
1212  pta = ptaaGetPta(recog->ptaa, i, L_CLONE); /* centroids */
1213  nasum = numaaGetNuma(recog->naasum, i, L_CLONE); /* fg areas */
1214  n = pixaGetCount(pixa);
1215  nascore = numaCreate(n);
1216  for (j = 0; j < n; j++) {
1217  pix2 = pixaGetPix(pixa, j, L_CLONE);
1218  ptaGetPt(pta, j, &x2, &y2); /* centroid average */
1219  numaGetIValue(nasum, j, &area2); /* fg sum average */
1220  pixCorrelationScoreSimple(pix1, pix2, area1, area2,
1221  x1 - x2, y1 - y2, 5, 5,
1222  recog->sumtab, &score);
1223  numaAddNumber(nascore, score);
1224  if (debug && score == 0.0) /* typ. large size difference */
1225  fprintf(stderr, "Got 0 score for i = %d, j = %d\n", i, j);
1226  pixDestroy(&pix2);
1227  }
1228  pixDestroy(&pix1);
1229 
1230  /* Find the rankscore, corresponding to the 1.0 - minfract.
1231  * To attempt to maintain the minfract of templates, use as a
1232  * cutoff the minimum of minscore and the rank score. However,
1233  * no template is saved with an actual score less than
1234  * that at least one template is kept. */
1235  minfract = (l_float32)mintarget / (l_float32)n;
1236  numaGetRankValue(nascore, 1.0 - minfract, NULL, 0, &rankscore);
1237  threshscore = L_MAX(LOWER_SCORE_THRESHOLD,
1238  L_MIN(minscore, rankscore));
1239  if (debug) {
1240  L_INFO("minscore = %4.2f, rankscore = %4.2f, threshscore = %4.2f\n",
1241  procName, minscore, rankscore, threshscore);
1242  }
1243 
1244  /* Save templates that are at or above threshold.
1245  * Toss any classes with less than %minsize templates. */
1246  for (j = 0; j < n; j++) {
1247  numaGetFValue(nascore, j, &score);
1248  pix1 = pixaaGetPix(recog->pixaa_u, i, j, L_COPY);
1249  if (score >= threshscore && n >= minsize) {
1250  pixaAddPix(pixad, pix1, L_INSERT);
1251  if (nasave) numaAddNumber(nasave, score);
1252  } else if (debug) {
1253  pixaAddPix(pixarem, pix1, L_INSERT);
1254  numaAddNumber(narem, score);
1255  } else {
1256  pixDestroy(&pix1);
1257  }
1258  }
1259 
1260  pixaDestroy(&pixa);
1261  ptaDestroy(&pta);
1262  numaDestroy(&nasum);
1263  numaDestroy(&nascore);
1264  }
1265 
1266  if (ppixsave) {
1267  *ppixsave = pixDisplayOutliers(pixad, nasave);
1268  numaDestroy(&nasave);
1269  }
1270  if (ppixrem) {
1271  *ppixrem = pixDisplayOutliers(pixarem, narem);
1272  pixaDestroy(&pixarem);
1273  numaDestroy(&narem);
1274  }
1275  recogDestroy(&recog);
1276  return pixad;
1277 }
1278 
1279 
1298 l_ok
1300  l_float32 minscore,
1301  l_int32 minsize,
1302  PIX **ppixsave,
1303  PIX **ppixrem)
1304 {
1305 PIXA *pixa1, *pixa2;
1306 L_RECOG *recog;
1307 
1308  PROCNAME("recogRemoveOutliers2");
1309 
1310  if (!precog)
1311  return ERROR_INT("&recog not defined", procName, 1);
1312  if (*precog == NULL)
1313  return ERROR_INT("recog not defined", procName, 1);
1314 
1315  /* Extract the unscaled templates */
1316  pixa1 = recogExtractPixa(*precog);
1317  recogDestroy(precog);
1318 
1319  pixa2 = pixaRemoveOutliers2(pixa1, minscore, minsize, ppixsave, ppixrem);
1320  pixaDestroy(&pixa1);
1321  if (!pixa2)
1322  return ERROR_INT("failure to remove outliers", procName, 1);
1323 
1324  recog = recogCreateFromPixa(pixa2, 0, 0, 0, 150, 1);
1325  pixaDestroy(&pixa2);
1326  if (!recog)
1327  return ERROR_INT("failure to make recog from pixa sans outliers",
1328  procName, 1);
1329 
1330  *precog = recog;
1331  return 0;
1332 }
1333 
1334 
1362 PIXA *
1364  l_float32 minscore,
1365  l_int32 minsize,
1366  PIX **ppixsave,
1367  PIX **ppixrem)
1368 {
1369 l_int32 i, j, k, n, area1, area2, maxk, debug;
1370 l_float32 x1, y1, x2, y2, score, maxscore;
1371 NUMA *nan, *nascore, *nasave;
1372 PIX *pix1, *pix2, *pix3;
1373 PIXA *pixarem, *pixad;
1374 L_RECOG *recog;
1375 
1376  PROCNAME("pixaRemoveOutliers2");
1377 
1378  if (ppixsave) *ppixsave = NULL;
1379  if (ppixrem) *ppixrem = NULL;
1380  if (!pixas)
1381  return (PIXA *)ERROR_PTR("pixas not defined", procName, NULL);
1382  minscore = L_MIN(minscore, 1.0);
1383  if (minscore <= 0.0)
1384  minscore = DEFAULT_MIN_SCORE;
1385  if (minsize < 0)
1386  minsize = DEFAULT_MIN_SET_SIZE;
1387 
1388  /* Make a special height-scaled recognizer with average templates */
1389  debug = (ppixsave || ppixrem) ? 1 : 0;
1390  recog = recogCreateFromPixa(pixas, 0, 40, 0, 128, 1);
1391  if (!recog)
1392  return (PIXA *)ERROR_PTR("bad pixas; recog not made", procName, NULL);
1393  recogAverageSamples(&recog, debug);
1394  if (!recog)
1395  return (PIXA *)ERROR_PTR("bad templates", procName, NULL);
1396 
1397  nasave = (ppixsave) ? numaCreate(0) : NULL;
1398  pixarem = (ppixrem) ? pixaCreate(0) : NULL;
1399 
1400  pixad = pixaCreate(0);
1401  pixaaGetCount(recog->pixaa, &nan); /* number of templates in each class */
1402  for (i = 0; i < recog->setsize; i++) {
1403  /* Get the scores for each sample in the class, when comparing
1404  * with averages from all the classes. */
1405  numaGetIValue(nan, i, &n);
1406  for (j = 0; j < n; j++) {
1407  pix1 = pixaaGetPix(recog->pixaa, i, j, L_CLONE);
1408  ptaaGetPt(recog->ptaa, i, j, &x1, &y1); /* centroid */
1409  numaaGetValue(recog->naasum, i, j, NULL, &area1); /* fg sum */
1410  nascore = numaCreate(n);
1411  for (k = 0; k < recog->setsize; k++) { /* average templates */
1412  pix2 = pixaGetPix(recog->pixa, k, L_CLONE);
1413  ptaGetPt(recog->pta, k, &x2, &y2); /* average centroid */
1414  numaGetIValue(recog->nasum, k, &area2); /* average fg sum */
1415  pixCorrelationScoreSimple(pix1, pix2, area1, area2,
1416  x1 - x2, y1 - y2, 5, 5,
1417  recog->sumtab, &score);
1418  numaAddNumber(nascore, score);
1419  pixDestroy(&pix2);
1420  }
1421 
1422  /* Save templates that are in the correct class and
1423  * at or above threshold. Toss any classes with less
1424  * than %minsize templates. */
1425  numaGetMax(nascore, &maxscore, &maxk);
1426  if (maxk == i && maxscore >= minscore && n >= minsize) {
1427  /* save it */
1428  pix3 = pixaaGetPix(recog->pixaa_u, i, j, L_COPY);
1429  pixaAddPix(pixad, pix3, L_INSERT);
1430  if (nasave) numaAddNumber(nasave, maxscore);
1431  } else if (ppixrem) { /* outlier */
1432  pix3 = recogDisplayOutlier(recog, i, j, maxk, maxscore);
1433  pixaAddPix(pixarem, pix3, L_INSERT);
1434  }
1435  numaDestroy(&nascore);
1436  pixDestroy(&pix1);
1437  }
1438  }
1439 
1440  if (ppixsave) {
1441  *ppixsave = pixDisplayOutliers(pixad, nasave);
1442  numaDestroy(&nasave);
1443  }
1444  if (ppixrem) {
1445  *ppixrem = pixaDisplayTiledInRows(pixarem, 32, 1500, 1.0, 0, 20, 2);
1446  pixaDestroy(&pixarem);
1447  }
1448 
1449  numaDestroy(&nan);
1450  recogDestroy(&recog);
1451  return pixad;
1452 }
1453 
1454 
1455 /*------------------------------------------------------------------------*
1456  * Training on unlabeled data *
1457  *------------------------------------------------------------------------*/
1487 PIXA *
1489  PIXA *pixas,
1490  l_float32 minscore,
1491  l_int32 threshold,
1492  l_int32 debug)
1493 {
1494 char *text;
1495 l_int32 i, n, same, maxd, scaleh, linew;
1496 l_float32 score;
1497 PIX *pix1, *pix2, *pixdb;
1498 PIXA *pixa1, *pixa2, *pixa3, *pixad;
1499 
1500  PROCNAME("recogTrainFromBoot");
1501 
1502  if (!recogboot)
1503  return (PIXA *)ERROR_PTR("recogboot not defined", procName, NULL);
1504  if (!pixas)
1505  return (PIXA *)ERROR_PTR("pixas not defined", procName, NULL);
1506 
1507  /* Make sure all input pix are 1 bpp */
1508  if ((n = pixaGetCount(pixas)) == 0)
1509  return (PIXA *)ERROR_PTR("no pix in pixa", procName, NULL);
1510  pixaVerifyDepth(pixas, &same, &maxd);
1511  if (maxd == 1) {
1512  pixa1 = pixaCopy(pixas, L_COPY);
1513  } else {
1514  pixa1 = pixaCreate(n);
1515  for (i = 0; i < n; i++) {
1516  pix1 = pixaGetPix(pixas, i, L_CLONE);
1517  pix2 = pixConvertTo1(pix1, threshold);
1518  pixaAddPix(pixa1, pix2, L_INSERT);
1519  pixDestroy(&pix1);
1520  }
1521  }
1522 
1523  /* Scale the input images to match the BSR */
1524  scaleh = recogboot->scaleh;
1525  linew = recogboot->linew;
1526  pixa2 = pixaCreate(n);
1527  for (i = 0; i < n; i++) {
1528  pix1 = pixaGetPix(pixa1, i, L_CLONE);
1529  pix2 = pixScaleToSize(pix1, 0, scaleh);
1530  pixaAddPix(pixa2, pix2, L_INSERT);
1531  pixDestroy(&pix1);
1532  }
1533  pixaDestroy(&pixa1);
1534 
1535  /* Optionally convert to width-normalized line */
1536  if (linew > 0)
1537  pixa3 = pixaSetStrokeWidth(pixa2, linew, 4, 8);
1538  else
1539  pixa3 = pixaCopy(pixa2, L_CLONE);
1540  pixaDestroy(&pixa2);
1541 
1542  /* Identify using recogboot */
1543  n = pixaGetCount(pixa3);
1544  pixad = pixaCreate(n);
1545  for (i = 0; i < n; i++) {
1546  pix1 = pixaGetPix(pixa3, i, L_COPY);
1547  pixSetText(pix1, NULL); /* remove any existing text or labelling */
1548  if (!debug) {
1549  recogIdentifyPix(recogboot, pix1, NULL);
1550  } else {
1551  recogIdentifyPix(recogboot, pix1, &pixdb);
1552  pixaAddPix(recogboot->pixadb_boot, pixdb, L_INSERT);
1553  }
1554  rchExtract(recogboot->rch, NULL, &score, &text, NULL, NULL, NULL, NULL);
1555  if (score >= minscore) {
1556  pix2 = pixaGetPix(pixas, i, L_COPY);
1557  pixSetText(pix2, text);
1558  pixaAddPix(pixad, pix2, L_INSERT);
1559  pixaAddPix(recogboot->pixadb_boot, pixdb, L_COPY);
1560  }
1561  LEPT_FREE(text);
1562  pixDestroy(&pix1);
1563  }
1564  pixaDestroy(&pixa3);
1565 
1566  return pixad;
1567 }
1568 
1569 
1570 /*------------------------------------------------------------------------*
1571  * Padding the digit training set *
1572  *------------------------------------------------------------------------*/
1591 l_ok
1593  l_int32 scaleh,
1594  l_int32 linew)
1595 {
1596 PIXA *pixa;
1597 L_RECOG *recog1, *recog2;
1598 SARRAY *sa;
1599 
1600  PROCNAME("recogPadDigitTrainingSet");
1601 
1602  if (!precog)
1603  return ERROR_INT("&recog not defined", procName, 1);
1604  recog1 = *precog;
1605 
1606  recogIsPaddingNeeded(recog1, &sa);
1607  if (!sa) return 0;
1608 
1609  /* Get a new pixa with the padding templates added */
1610  pixa = recogAddDigitPadTemplates(recog1, sa);
1611  sarrayDestroy(&sa);
1612  if (!pixa)
1613  return ERROR_INT("pixa not made", procName, 1);
1614 
1615  /* Need to use templates that are scaled to a fixed height. */
1616  if (scaleh <= 0) {
1617  L_WARNING("templates must be scaled to fixed height; using %d\n",
1618  procName, 40);
1619  scaleh = 40;
1620  }
1621 
1622  /* Create a hybrid recog, composed of templates from both
1623  * the original and bootstrap sources. */
1624  recog2 = recogCreateFromPixa(pixa, 0, scaleh, linew, recog1->threshold,
1625  recog1->maxyshift);
1626  pixaDestroy(&pixa);
1627  recogDestroy(precog);
1628  *precog = recog2;
1629  return 0;
1630 }
1631 
1632 
1649 l_int32
1651  SARRAY **psa)
1652 {
1653 char *str;
1654 l_int32 i, nt, min_nopad, nclass, allclasses;
1655 l_float32 minval;
1656 NUMA *naclass;
1657 SARRAY *sa;
1658 
1659  PROCNAME("recogIsPaddingNeeded");
1660 
1661  if (!psa)
1662  return ERROR_INT("&sa not defined", procName, 1);
1663  *psa = NULL;
1664  if (!recog)
1665  return ERROR_INT("recog not defined", procName, 1);
1666 
1667  /* Do we have samples from all classes? */
1668  nclass = pixaaGetCount(recog->pixaa_u, &naclass); /* unscaled bitmaps */
1669  allclasses = (nclass == recog->charset_size) ? 1 : 0;
1670 
1671  /* Are there enough samples in each class already? */
1672  min_nopad = recog->min_nopad;
1673  numaGetMin(naclass, &minval, NULL);
1674  if (allclasses && (minval >= min_nopad)) {
1675  numaDestroy(&naclass);
1676  return 0;
1677  }
1678 
1679  /* Are any classes not represented? */
1680  sa = recogAddMissingClassStrings(recog);
1681  *psa = sa;
1682 
1683  /* Are any other classes under-represented? */
1684  for (i = 0; i < nclass; i++) {
1685  numaGetIValue(naclass, i, &nt);
1686  if (nt < min_nopad) {
1687  str = sarrayGetString(recog->sa_text, i, L_COPY);
1688  sarrayAddString(sa, str, L_INSERT);
1689  }
1690  }
1691  numaDestroy(&naclass);
1692  return 0;
1693 }
1694 
1695 
1708 static SARRAY *
1710 {
1711 char *text;
1712 char str[4];
1713 l_int32 i, nclass, index, ival;
1714 NUMA *na;
1715 SARRAY *sa;
1716 
1717  PROCNAME("recogAddMissingClassStrings");
1718 
1719  if (!recog)
1720  return (SARRAY *)ERROR_PTR("recog not defined", procName, NULL);
1721 
1722  /* Only handling digits */
1723  nclass = pixaaGetCount(recog->pixaa_u, NULL); /* unscaled bitmaps */
1724  if (recog->charset_type != 1 || nclass == 10)
1725  return sarrayCreate(0); /* empty */
1726 
1727  /* Make an indicator array for missing classes */
1728  na = numaCreate(0);
1729  sa = sarrayCreate(0);
1730  for (i = 0; i < recog->charset_size; i++)
1731  numaAddNumber(na, 1);
1732  for (i = 0; i < nclass; i++) {
1733  text = sarrayGetString(recog->sa_text, i, L_NOCOPY);
1734  index = text[0] - '0';
1735  numaSetValue(na, index, 0);
1736  }
1737 
1738  /* Convert to string and add to output */
1739  for (i = 0; i < nclass; i++) {
1740  numaGetIValue(na, i, &ival);
1741  if (ival == 1) {
1742  str[0] = '0' + i;
1743  str[1] = '\0';
1744  sarrayAddString(sa, str, L_COPY);
1745  }
1746  }
1747  numaDestroy(&na);
1748  return sa;
1749 }
1750 
1751 
1767 PIXA *
1769  SARRAY *sa)
1770 {
1771 char *str, *text;
1772 l_int32 i, j, n, nt;
1773 PIX *pix;
1774 PIXA *pixa1, *pixa2;
1775 
1776  PROCNAME("recogAddDigitPadTemplates");
1777 
1778  if (!recog)
1779  return (PIXA *)ERROR_PTR("recog not defined", procName, NULL);
1780  if (!sa)
1781  return (PIXA *)ERROR_PTR("sa not defined", procName, NULL);
1782  if (recogCharsetAvailable(recog->charset_type) == FALSE)
1783  return (PIXA *)ERROR_PTR("boot charset not available", procName, NULL);
1784 
1785  /* Make boot recog templates */
1786  pixa1 = recogMakeBootDigitTemplates(0, 0);
1787  n = pixaGetCount(pixa1);
1788 
1789  /* Extract the unscaled templates from %recog */
1790  pixa2 = recogExtractPixa(recog);
1791 
1792  /* Add selected boot recog templates based on the text strings in sa */
1793  nt = sarrayGetCount(sa);
1794  for (i = 0; i < n; i++) {
1795  pix = pixaGetPix(pixa1, i, L_CLONE);
1796  text = pixGetText(pix);
1797  for (j = 0; j < nt; j++) {
1798  str = sarrayGetString(sa, j, L_NOCOPY);
1799  if (!strcmp(text, str)) {
1800  pixaAddPix(pixa2, pix, L_COPY);
1801  break;
1802  }
1803  }
1804  pixDestroy(&pix);
1805  }
1806 
1807  pixaDestroy(&pixa1);
1808  return pixa2;
1809 }
1810 
1811 
1818 static l_int32
1820 {
1821 l_int32 ret;
1822 
1823  PROCNAME("recogCharsetAvailable");
1824 
1825  switch (type)
1826  {
1827  case L_ARABIC_NUMERALS:
1828  ret = TRUE;
1829  break;
1830  case L_LC_ROMAN_NUMERALS:
1831  case L_UC_ROMAN_NUMERALS:
1832  case L_LC_ALPHA:
1833  case L_UC_ALPHA:
1834  L_INFO("charset type %d not available\n", procName, type);
1835  ret = FALSE;
1836  break;
1837  default:
1838  L_INFO("charset type %d is unknown\n", procName, type);
1839  ret = FALSE;
1840  break;
1841  }
1842 
1843  return ret;
1844 }
1845 
1846 
1847 /*------------------------------------------------------------------------*
1848  * Making a boot digit recognizer *
1849  *------------------------------------------------------------------------*/
1879 L_RECOG *
1881  l_int32 scaleh,
1882  l_int32 linew,
1883  l_int32 maxyshift,
1884  l_int32 debug)
1885 
1886 {
1887 PIXA *pixa;
1888 L_RECOG *recog;
1889 
1890  /* Get the templates, extended by horizontal scaling */
1891  pixa = recogMakeBootDigitTemplates(nsamp, debug);
1892 
1893  /* Make the boot recog; recogModifyTemplate() will scale the
1894  * templates and optionally turn them into strokes of fixed width. */
1895  recog = recogCreateFromPixa(pixa, 0, scaleh, linew, 128, maxyshift);
1896  pixaDestroy(&pixa);
1897  if (debug)
1898  recogShowContent(stderr, recog, 0, 1);
1899 
1900  return recog;
1901 }
1902 
1903 
1916 PIXA *
1918  l_int32 debug)
1919 {
1920 NUMA *na1;
1921 PIX *pix1, *pix2, *pix3;
1922 PIXA *pixa1, *pixa2, *pixa3;
1923 
1924  if (nsamp > 0) {
1925  pixa1 = l_bootnum_gen4(nsamp);
1926  if (debug) {
1927  pix1 = pixaDisplayTiledWithText(pixa1, 1500, 1.0, 10,
1928  2, 6, 0xff000000);
1929  pixDisplay(pix1, 0, 0);
1930  pixDestroy(&pix1);
1931  }
1932  return pixa1;
1933  }
1934 
1935  /* Else, generate from 3 pixa */
1936  pixa1 = l_bootnum_gen1();
1937  pixa2 = l_bootnum_gen2();
1938  pixa3 = l_bootnum_gen3();
1939  if (debug) {
1940  pix1 = pixaDisplayTiledWithText(pixa1, 1500, 1.0, 10, 2, 6, 0xff000000);
1941  pix2 = pixaDisplayTiledWithText(pixa2, 1500, 1.0, 10, 2, 6, 0xff000000);
1942  pix3 = pixaDisplayTiledWithText(pixa3, 1500, 1.0, 10, 2, 6, 0xff000000);
1943  pixDisplay(pix1, 0, 0);
1944  pixDisplay(pix2, 600, 0);
1945  pixDisplay(pix3, 1200, 0);
1946  pixDestroy(&pix1);
1947  pixDestroy(&pix2);
1948  pixDestroy(&pix3);
1949  }
1950  pixaJoin(pixa1, pixa2, 0, -1);
1951  pixaJoin(pixa1, pixa3, 0, -1);
1952  pixaDestroy(&pixa2);
1953  pixaDestroy(&pixa3);
1954 
1955  /* Extend by horizontal scaling */
1956  na1 = numaCreate(4);
1957  numaAddNumber(na1, 0.9);
1958  numaAddNumber(na1, 1.1);
1959  numaAddNumber(na1, 1.2);
1960  pixa2 = pixaExtendByScaling(pixa1, na1, L_HORIZ, 1);
1961 
1962  pixaDestroy(&pixa1);
1963  numaDestroy(&na1);
1964  return pixa2;
1965 }
1966 
1967 
1968 /*------------------------------------------------------------------------*
1969  * Debugging *
1970  *------------------------------------------------------------------------*/
1980 l_ok
1982  L_RECOG *recog,
1983  l_int32 index,
1984  l_int32 display)
1985 {
1986 char buf[128];
1987 l_int32 i, val, count;
1988 PIX *pix;
1989 NUMA *na;
1990 
1991  PROCNAME("recogShowContent");
1992 
1993  if (!fp)
1994  return ERROR_INT("stream not defined", procName, 1);
1995  if (!recog)
1996  return ERROR_INT("recog not defined", procName, 1);
1997 
1998  fprintf(fp, "Debug print of recog contents\n");
1999  fprintf(fp, " Setsize: %d\n", recog->setsize);
2000  fprintf(fp, " Binarization threshold: %d\n", recog->threshold);
2001  fprintf(fp, " Maximum matching y-jiggle: %d\n", recog->maxyshift);
2002  if (recog->linew <= 0)
2003  fprintf(fp, " Using image templates for matching\n");
2004  else
2005  fprintf(fp, " Using templates with fixed line width for matching\n");
2006  if (recog->scalew == 0)
2007  fprintf(fp, " No width scaling of templates\n");
2008  else
2009  fprintf(fp, " Template width scaled to %d\n", recog->scalew);
2010  if (recog->scaleh == 0)
2011  fprintf(fp, " No height scaling of templates\n");
2012  else
2013  fprintf(fp, " Template height scaled to %d\n", recog->scaleh);
2014  fprintf(fp, " Number of samples in each class:\n");
2015  pixaaGetCount(recog->pixaa_u, &na);
2016  for (i = 0; i < recog->setsize; i++) {
2017  l_dnaGetIValue(recog->dna_tochar, i, &val);
2018  numaGetIValue(na, i, &count);
2019  if (val < 128)
2020  fprintf(fp, " class %d, char %c: %d\n", i, val, count);
2021  else
2022  fprintf(fp, " class %d, val %d: %d\n", i, val, count);
2023  }
2024  numaDestroy(&na);
2025 
2026  if (display) {
2027  lept_mkdir("lept/recog");
2028  pix = pixaaDisplayByPixa(recog->pixaa_u, 20, 20, 1000);
2029  snprintf(buf, sizeof(buf), "/tmp/lept/recog/templates_u.%d.png", index);
2030  pixWriteDebug(buf, pix, IFF_PNG);
2031  pixDisplay(pix, 0, 200 * index);
2032  pixDestroy(&pix);
2033  if (recog->train_done) {
2034  pix = pixaaDisplayByPixa(recog->pixaa, 20, 20, 1000);
2035  snprintf(buf, sizeof(buf),
2036  "/tmp/lept/recog/templates.%d.png", index);
2037  pixWriteDebug(buf, pix, IFF_PNG);
2038  pixDisplay(pix, 800, 200 * index);
2039  pixDestroy(&pix);
2040  }
2041  }
2042  return 0;
2043 }
2044 
2045 
2063 l_ok
2065  l_int32 debug)
2066 {
2067 l_int32 i, j, n, np, index;
2068 l_float32 score;
2069 PIX *pix1, *pix2, *pix3;
2070 PIXA *pixa, *pixat;
2071 PIXAA *paa1, *paa2;
2072 L_RECOG *recog;
2073 
2074  PROCNAME("recogDebugAverages");
2075 
2076  if (!precog)
2077  return ERROR_INT("&recog not defined", procName, 1);
2078  if ((recog = *precog) == NULL)
2079  return ERROR_INT("recog not defined", procName, 1);
2080 
2081  /* Mark the training as finished if necessary, and make sure
2082  * that the average templates have been built. */
2083  recogAverageSamples(&recog, 0);
2084  if (!recog)
2085  return ERROR_INT("averaging failed; recog destroyed", procName, 1);
2086 
2087  /* Save a pixa of all the training examples */
2088  paa1 = recog->pixaa;
2089  if (!recog->pixa_tr)
2090  recog->pixa_tr = pixaaFlattenToPixa(paa1, NULL, L_CLONE);
2091 
2092  /* Destroy any existing image and make a new one */
2093  if (recog->pixdb_ave)
2094  pixDestroy(&recog->pixdb_ave);
2095  n = pixaaGetCount(paa1, NULL);
2096  paa2 = pixaaCreate(n);
2097  for (i = 0; i < n; i++) {
2098  pixa = pixaCreate(0);
2099  pixat = pixaaGetPixa(paa1, i, L_CLONE);
2100  np = pixaGetCount(pixat);
2101  for (j = 0; j < np; j++) {
2102  pix1 = pixaaGetPix(paa1, i, j, L_CLONE);
2103  recogIdentifyPix(recog, pix1, &pix2);
2104  rchExtract(recog->rch, &index, &score, NULL, NULL, NULL,
2105  NULL, NULL);
2106  if (debug >= 2)
2107  fprintf(stderr, "index = %d, score = %7.3f\n", index, score);
2108  pix3 = pixAddBorder(pix2, 2, 1);
2109  pixaAddPix(pixa, pix3, L_INSERT);
2110  pixDestroy(&pix1);
2111  pixDestroy(&pix2);
2112  }
2113  pixaaAddPixa(paa2, pixa, L_INSERT);
2114  pixaDestroy(&pixat);
2115  }
2116  recog->pixdb_ave = pixaaDisplayByPixa(paa2, 20, 20, 2500);
2117  if (debug % 2) {
2118  lept_mkdir("lept/recog");
2119  pixWriteDebug("/tmp/lept/recog/templ_match.png", recog->pixdb_ave,
2120  IFF_PNG);
2121  pixDisplay(recog->pixdb_ave, 100, 100);
2122  }
2123 
2124  pixaaDestroy(&paa2);
2125  return 0;
2126 }
2127 
2128 
2141 l_int32
2143 {
2144 l_int32 i, size;
2145 l_float32 x, y;
2146 PIX *pix1, *pix2, *pixr;
2147 PIXA *pixat, *pixadb;
2148 
2149  PROCNAME("recogShowAverageTemplates");
2150 
2151  if (!recog)
2152  return ERROR_INT("recog not defined", procName, 1);
2153 
2154  fprintf(stderr, "min/max width_u = (%d,%d); min/max height_u = (%d,%d)\n",
2155  recog->minwidth_u, recog->maxwidth_u,
2156  recog->minheight_u, recog->maxheight_u);
2157  fprintf(stderr, "min splitw = %d, max splith = %d\n",
2158  recog->min_splitw, recog->max_splith);
2159 
2160  pixaDestroy(&recog->pixadb_ave);
2161 
2162  pixr = pixCreate(3, 3, 32); /* 3x3 red square for centroid location */
2163  pixSetAllArbitrary(pixr, 0xff000000);
2164  pixadb = pixaCreate(2);
2165 
2166  /* Unscaled bitmaps */
2167  size = recog->setsize;
2168  pixat = pixaCreate(size);
2169  for (i = 0; i < size; i++) {
2170  if ((pix1 = pixaGetPix(recog->pixa_u, i, L_CLONE)) == NULL)
2171  continue;
2172  pix2 = pixConvertTo32(pix1);
2173  ptaGetPt(recog->pta_u, i, &x, &y);
2174  pixRasterop(pix2, (l_int32)(x - 0.5), (l_int32)(y - 0.5), 3, 3,
2175  PIX_SRC, pixr, 0, 0);
2176  pixaAddPix(pixat, pix2, L_INSERT);
2177  pixDestroy(&pix1);
2178  }
2179  pix1 = pixaDisplayTiledInRows(pixat, 32, 3000, 1.0, 0, 20, 0);
2180  pixaAddPix(pixadb, pix1, L_INSERT);
2181  pixDisplay(pix1, 100, 100);
2182  pixaDestroy(&pixat);
2183 
2184  /* Scaled bitmaps */
2185  pixat = pixaCreate(size);
2186  for (i = 0; i < size; i++) {
2187  if ((pix1 = pixaGetPix(recog->pixa, i, L_CLONE)) == NULL)
2188  continue;
2189  pix2 = pixConvertTo32(pix1);
2190  ptaGetPt(recog->pta, i, &x, &y);
2191  pixRasterop(pix2, (l_int32)(x - 0.5), (l_int32)(y - 0.5), 3, 3,
2192  PIX_SRC, pixr, 0, 0);
2193  pixaAddPix(pixat, pix2, L_INSERT);
2194  pixDestroy(&pix1);
2195  }
2196  pix1 = pixaDisplayTiledInRows(pixat, 32, 3000, 1.0, 0, 20, 0);
2197  pixaAddPix(pixadb, pix1, L_INSERT);
2198  pixDisplay(pix1, 100, 100);
2199  pixaDestroy(&pixat);
2200  pixDestroy(&pixr);
2201  recog->pixadb_ave = pixadb;
2202  return 0;
2203 }
2204 
2205 
2219 static PIX *
2221  NUMA *nas)
2222 {
2223 char *text;
2224 char buf[16];
2225 l_int32 i, n;
2226 l_float32 fval;
2227 PIX *pix1, *pix2;
2228 PIXA *pixa1;
2229 
2230  PROCNAME("pixDisplayOutliers");
2231 
2232  if (!pixas)
2233  return (PIX *)ERROR_PTR("pixas not defined", procName, NULL);
2234  if (!nas)
2235  return (PIX *)ERROR_PTR("nas not defined", procName, NULL);
2236  n = pixaGetCount(pixas);
2237  if (numaGetCount(nas) != n)
2238  return (PIX *)ERROR_PTR("pixas and nas sizes differ", procName, NULL);
2239 
2240  pixa1 = pixaCreate(n);
2241  for (i = 0; i < n; i++) {
2242  pix1 = pixaGetPix(pixas, i, L_CLONE);
2243  pix2 = pixAddBlackOrWhiteBorder(pix1, 25, 25, 0, 0, L_GET_WHITE_VAL);
2244  text = pixGetText(pix1);
2245  numaGetFValue(nas, i, &fval);
2246  snprintf(buf, sizeof(buf), "'%s': %5.2f", text, fval);
2247  pixSetText(pix2, buf);
2248  pixaAddPix(pixa1, pix2, L_INSERT);
2249  pixDestroy(&pix1);
2250  }
2251  pix1 = pixaDisplayTiledWithText(pixa1, 1500, 1.0, 20, 2, 6, 0xff000000);
2252  pixaDestroy(&pixa1);
2253  return pix1;
2254 }
2255 
2256 
2275 static PIX *
2277  l_int32 iclass,
2278  l_int32 jsamp,
2279  l_int32 maxclass,
2280  l_float32 maxscore)
2281 {
2282 char buf[64];
2283 PIX *pix1, *pix2, *pix3, *pix4, *pix5;
2284 PIXA *pixa;
2285 
2286  PROCNAME("recogDisplayOutlier");
2287 
2288  if (!recog)
2289  return (PIX *)ERROR_PTR("recog not defined", procName, NULL);
2290 
2291  pix1 = pixaaGetPix(recog->pixaa, iclass, jsamp, L_CLONE);
2292  pix2 = pixaGetPix(recog->pixa, iclass, L_CLONE);
2293  pix3 = pixaGetPix(recog->pixa, maxclass, L_CLONE);
2294  pixa = pixaCreate(3);
2295  pixaAddPix(pixa, pix1, L_INSERT);
2296  pixaAddPix(pixa, pix2, L_INSERT);
2297  pixaAddPix(pixa, pix3, L_INSERT);
2298  pix4 = pixaDisplayTiledInRows(pixa, 32, 400, 2.0, 0, 12, 2);
2299  snprintf(buf, sizeof(buf), "C=%d, BAC=%d, S=%4.2f", iclass, maxclass,
2300  maxscore);
2301  pix5 = pixAddSingleTextblock(pix4, recog->bmf, buf, 0xff000000,
2302  L_ADD_BELOW, NULL);
2303  pixDestroy(&pix4);
2304  pixaDestroy(&pixa);
2305  return pix5;
2306 }
2307 
2308 
2330 l_ok
2332  PIXA *pixa,
2333  l_float32 minscore,
2334  l_float32 maxscore,
2335  l_int32 display)
2336 {
2337 l_int32 i, n, index, depth;
2338 l_float32 score;
2339 NUMA *nascore, *naindex;
2340 PIX *pix1, *pix2;
2341 PIXA *pixa1, *pixa2;
2342 
2343  PROCNAME("recogShowMatchesInRange");
2344 
2345  if (!recog)
2346  return ERROR_INT("recog not defined", procName, 1);
2347  if (!pixa)
2348  return ERROR_INT("pixa not defined", procName, 1);
2349 
2350  /* Run the recognizer on the set of images */
2351  n = pixaGetCount(pixa);
2352  nascore = numaCreate(n);
2353  naindex = numaCreate(n);
2354  pixa1 = pixaCreate(n);
2355  for (i = 0; i < n; i++) {
2356  pix1 = pixaGetPix(pixa, i, L_CLONE);
2357  recogIdentifyPix(recog, pix1, &pix2);
2358  rchExtract(recog->rch, &index, &score, NULL, NULL, NULL, NULL, NULL);
2359  numaAddNumber(nascore, score);
2360  numaAddNumber(naindex, index);
2361  pixaAddPix(pixa1, pix2, L_INSERT);
2362  pixDestroy(&pix1);
2363  }
2364 
2365  /* Filter the set and optionally add text to each */
2366  pixa2 = pixaCreate(n);
2367  depth = 1;
2368  for (i = 0; i < n; i++) {
2369  numaGetFValue(nascore, i, &score);
2370  if (score < minscore || score > maxscore) continue;
2371  pix1 = pixaGetPix(pixa1, i, L_CLONE);
2372  numaGetIValue(naindex, i, &index);
2373  pix2 = recogShowMatch(recog, pix1, NULL, NULL, index, score);
2374  if (i == 0) depth = pixGetDepth(pix2);
2375  pixaAddPix(pixa2, pix2, L_INSERT);
2376  pixDestroy(&pix1);
2377  }
2378 
2379  /* Package it up */
2380  pixDestroy(&recog->pixdb_range);
2381  if (pixaGetCount(pixa2) > 0) {
2382  recog->pixdb_range =
2383  pixaDisplayTiledInRows(pixa2, depth, 2500, 1.0, 0, 20, 1);
2384  if (display)
2385  pixDisplay(recog->pixdb_range, 300, 100);
2386  } else {
2387  L_INFO("no character matches in the range of scores\n", procName);
2388  }
2389 
2390  pixaDestroy(&pixa1);
2391  pixaDestroy(&pixa2);
2392  numaDestroy(&nascore);
2393  numaDestroy(&naindex);
2394  return 0;
2395 }
2396 
2397 
2424 PIX *
2426  PIX *pix1,
2427  PIX *pix2,
2428  BOX *box,
2429  l_int32 index,
2430  l_float32 score)
2431 {
2432 char buf[32];
2433 char *text;
2434 L_BMF *bmf;
2435 PIX *pix3, *pix4, *pix5, *pixd;
2436 PIXA *pixa;
2437 
2438  PROCNAME("recogShowMatch");
2439 
2440  if (!recog)
2441  return (PIX *)ERROR_PTR("recog not defined", procName, NULL);
2442  if (!pix1)
2443  return (PIX *)ERROR_PTR("pix1 not defined", procName, NULL);
2444 
2445  bmf = (recog->bmf && index >= 0) ? recog->bmf : NULL;
2446  if (!pix2 && !box && !bmf) /* nothing to do */
2447  return pixCopy(NULL, pix1);
2448 
2449  pix3 = pixConvertTo32(pix1);
2450  if (box)
2451  pixRenderBoxArb(pix3, box, 1, 255, 0, 0);
2452 
2453  if (pix2) {
2454  pixa = pixaCreate(2);
2455  pixaAddPix(pixa, pix3, L_CLONE);
2456  pixaAddPix(pixa, pix2, L_CLONE);
2457  pix4 = pixaDisplayTiledInRows(pixa, 1, 500, 1.0, 0, 15, 0);
2458  pixaDestroy(&pixa);
2459  } else {
2460  pix4 = pixCopy(NULL, pix3);
2461  }
2462  pixDestroy(&pix3);
2463 
2464  if (bmf) {
2465  pix5 = pixAddBorderGeneral(pix4, 55, 55, 0, 0, 0xffffff00);
2466  recogGetClassString(recog, index, &text);
2467  snprintf(buf, sizeof(buf), "C=%s, S=%4.3f, I=%d", text, score, index);
2468  pixd = pixAddSingleTextblock(pix5, bmf, buf, 0xff000000,
2469  L_ADD_BELOW, NULL);
2470  pixDestroy(&pix5);
2471  LEPT_FREE(text);
2472  } else {
2473  pixd = pixClone(pix4);
2474  }
2475  pixDestroy(&pix4);
2476 
2477  return pixd;
2478 }
l_ok recogRemoveOutliers1(L_RECOG **precog, l_float32 minscore, l_int32 mintarget, l_int32 minsize, PIX **ppixsave, PIX **ppixrem)
recogRemoveOutliers1()
Definition: recogtrain.c:1081
struct Numa * nasum
Definition: recog.h:218
struct Pixaa * pixaa_u
Definition: recog.h:152
void pixaaDestroy(PIXAA **ppaa)
pixaaDestroy()
Definition: pixabasic.c:1932
struct Pixa * pixadb_boot
Definition: recog.h:169
PIX * pixConvertTo1(PIX *pixs, l_int32 threshold)
pixConvertTo1()
Definition: pixconv.c:2933
PIXAA * pixaaCreate(l_int32 n)
pixaaCreate()
Definition: pixabasic.c:1825
l_ok numaGetFValue(NUMA *na, l_int32 index, l_float32 *pval)
numaGetFValue()
Definition: numabasic.c:692
l_ok recogDebugAverages(L_RECOG **precog, l_int32 debug)
recogDebugAverages()
Definition: recogtrain.c:2064
l_ok ptaaGetPt(PTAA *ptaa, l_int32 ipta, l_int32 jpt, l_float32 *px, l_float32 *py)
ptaaGetPt()
Definition: ptabasic.c:1125
l_int32 maxwidth
Definition: recog.h:140
l_int32 lept_mkdir(const char *subdir)
lept_mkdir()
Definition: utils2.c:1944
Definition: pix.h:717
l_int32 threshold
Definition: recog.h:128
struct Pixa * pixa_u
Definition: recog.h:158
l_int32 minwidth_u
Definition: recog.h:135
l_ok pixCentroid(PIX *pix, l_int32 *centtab, l_int32 *sumtab, l_float32 *pxave, l_float32 *pyave)
pixCentroid()
Definition: morphapp.c:1528
l_int32 minwidth
Definition: recog.h:139
PIX * pixConvertTo32(PIX *pixs)
pixConvertTo32()
Definition: pixconv.c:3233
l_int32 * makePixelCentroidTab8(void)
makePixelCentroidTab8()
Definition: pix3.c:2337
l_ok recogTrainLabeled(L_RECOG *recog, PIX *pixs, BOX *box, char *text, l_int32 debug)
recogTrainLabeled()
Definition: recogtrain.c:212
l_ok ptaaAddPt(PTAA *ptaa, l_int32 ipta, l_float32 x, l_float32 y)
ptaaAddPt()
Definition: ptabasic.c:1235
l_ok pixaVerifyDepth(PIXA *pixa, l_int32 *psame, l_int32 *pmaxd)
pixaVerifyDepth()
Definition: pixabasic.c:941
PIXA * pixaRemoveOutliers2(PIXA *pixas, l_float32 minscore, l_int32 minsize, PIX **ppixsave, PIX **ppixrem)
pixaRemoveOutliers2()
Definition: recogtrain.c:1363
struct Pta * pta
Definition: recog.h:162
l_ok ptaAddPt(PTA *pta, l_float32 x, l_float32 y)
ptaAddPt()
Definition: ptabasic.c:342
l_ok numaAddNumber(NUMA *na, l_float32 val)
numaAddNumber()
Definition: numabasic.c:473
PIXA * recogFilterPixaBySize(PIXA *pixas, l_int32 setsize, l_int32 maxkeep, l_float32 max_ht_ratio, NUMA **pna)
recogFilterPixaBySize()
Definition: recogtrain.c:970
PIXA * pixaCreate(l_int32 n)
pixaCreate()
Definition: pixabasic.c:163
l_ok recogAddSample(L_RECOG *recog, PIX *pix, l_int32 debug)
recogAddSample()
Definition: recogtrain.c:352
Definition: recog.h:116
Definition: pix.h:716
l_int32 scalew
Definition: recog.h:117
l_ok pixaJoin(PIXA *pixad, PIXA *pixas, l_int32 istart, l_int32 iend)
pixaJoin()
Definition: pixabasic.c:1646
L_RECOG * recogCreateFromPixa(PIXA *pixa, l_int32 scalew, l_int32 scaleh, l_int32 linew, l_int32 threshold, l_int32 maxyshift)
recogCreateFromPixa()
Definition: recogbasic.c:281
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:193
PTA * ptaCreate(l_int32 n)
ptaCreate()
Definition: ptabasic.c:116
PIXA * pixaaGetPixa(PIXAA *paa, l_int32 index, l_int32 accesstype)
pixaaGetPixa()
Definition: pixabasic.c:2168
l_int32 linew
Definition: recog.h:121
l_int32 charset_type
Definition: recog.h:131
l_int32 recogGetClassString(L_RECOG *recog, l_int32 index, char **pcharstr)
recogGetClassString()
Definition: recogbasic.c:752
struct Numa * nasum
Definition: recog.h:163
PIXA * l_bootnum_gen1(void)
l_bootnum_gen1()
Definition: bootnumgen1.c:290
struct Numa * nasum_u
Definition: recog.h:160
l_int32 pixaaGetCount(PIXAA *paa, NUMA **pna)
pixaaGetCount()
Definition: pixabasic.c:2119
PIXA * l_bootnum_gen2(void)
l_bootnum_gen2()
Definition: bootnumgen2.c:273
l_ok l_dnaGetIValue(L_DNA *da, l_int32 index, l_int32 *pival)
l_dnaGetIValue()
Definition: dnabasic.c:693
PIXA * pixaaFlattenToPixa(PIXAA *paa, NUMA **pnaindex, l_int32 copyflag)
pixaaFlattenToPixa()
Definition: pixafunc1.c:2341
PIX * pixCreate(l_int32 width, l_int32 height, l_int32 depth)
pixCreate()
Definition: pix1.c:302
l_ok ptaaTruncate(PTAA *ptaa)
ptaaTruncate()
Definition: ptabasic.c:1270
struct Sarray * sa_text
Definition: recog.h:148
SARRAY * sarrayCreate(l_int32 n)
sarrayCreate()
Definition: sarray1.c:163
l_ok numaCountNonzeroRuns(NUMA *na, l_int32 *pcount)
numaCountNonzeroRuns()
Definition: numafunc1.c:967
PIX * pixInvert(PIX *pixd, PIX *pixs)
pixInvert()
Definition: pix3.c:1395
NUMA * numaCreate(l_int32 n)
numaCreate()
Definition: numabasic.c:187
l_int32 ptaGetCount(PTA *pta)
ptaGetCount()
Definition: ptabasic.c:504
PIX * pixAddBlackOrWhiteBorder(PIX *pixs, l_int32 left, l_int32 right, l_int32 top, l_int32 bot, l_int32 op)
pixAddBlackOrWhiteBorder()
Definition: pix2.c:1788
static l_int32 recogCharsetAvailable(l_int32 type)
recogCharsetAvailable()
Definition: recogtrain.c:1819
l_int32 recogIsPaddingNeeded(L_RECOG *recog, SARRAY **psa)
recogIsPaddingNeeded()
Definition: recogtrain.c:1650
PIX * pixThresholdToBinary(PIX *pixs, l_int32 thresh)
pixThresholdToBinary()
Definition: grayquant.c:443
PIX * pixClipRectangle(PIX *pixs, BOX *box, BOX **pboxc)
pixClipRectangle()
Definition: pix5.c:1020
struct Numaa * naasum
Definition: recog.h:157
l_int32 maxarraysize
Definition: recog.h:126
l_ok numaSetValue(NUMA *na, l_int32 index, l_float32 val)
numaSetValue()
Definition: numabasic.c:759
void numaaDestroy(NUMAA **pnaa)
numaaDestroy()
Definition: numabasic.c:1444
Definition: bmf.h:45
PIX * pixaaGetPix(PIXAA *paa, l_int32 index, l_int32 ipix, l_int32 accessflag)
pixaaGetPix()
Definition: pixabasic.c:2230
Definition: array.h:116
struct Pixa * pixadb_ave
Definition: recog.h:165
PIX * pixAddBorder(PIX *pixs, l_int32 npix, l_uint32 val)
pixAddBorder()
Definition: pix2.c:1748
l_ok pixSetText(PIX *pix, const char *textstring)
pixSetText()
Definition: pix1.c:1483
struct Pix * pixs
Definition: recog.h:212
l_ok recogTrainingFinished(L_RECOG **precog, l_int32 modifyflag, l_int32 minsize, l_float32 minfract)
recogTrainingFinished()
Definition: recogtrain.c:783
l_ok pixSetAllArbitrary(PIX *pix, l_uint32 val)
pixSetAllArbitrary()
Definition: pix2.c:876
l_ok pixClipToForeground(PIX *pixs, PIX **ppixd, BOX **pbox)
pixClipToForeground()
Definition: pix5.c:1660
PIXA * pixaCopy(PIXA *pixa, l_int32 copyflag)
pixaCopy()
Definition: pixabasic.c:450
NUMA * numaaGetNuma(NUMAA *naa, l_int32 index, l_int32 accessflag)
numaaGetNuma()
Definition: numabasic.c:1659
PTA * ptaaGetPta(PTAA *ptaa, l_int32 index, l_int32 accessflag)
ptaaGetPta()
Definition: ptabasic.c:1094
l_ok numaGetIValue(NUMA *na, l_int32 index, l_int32 *pival)
numaGetIValue()
Definition: numabasic.c:727
l_int32 setsize
Definition: recog.h:127
l_ok pixaAddPix(PIXA *pixa, PIX *pix, l_int32 copyflag)
pixaAddPix()
Definition: pixabasic.c:503
Definition: array.h:59
l_ok recogIdentifyPix(L_RECOG *recog, PIX *pixs, PIX **ppixdb)
recogIdentifyPix()
Definition: recogident.c:972
struct Numaa * naasum_u
Definition: recog.h:154
char * text
Definition: pix.h:148
l_int32 numaGetCount(NUMA *na)
numaGetCount()
Definition: numabasic.c:631
l_int32 * sumtab
Definition: recog.h:151
l_ok sarrayAddString(SARRAY *sa, const char *string, l_int32 copyflag)
sarrayAddString()
Definition: sarray1.c:446
struct Pix * pixdb_ave
Definition: recog.h:167
l_int32 max_splith
Definition: recog.h:147
PIXA * pixaSetStrokeWidth(PIXA *pixas, l_int32 width, l_int32 thinfirst, l_int32 connectivity)
pixaSetStrokeWidth()
Definition: strokes.c:345
l_ok pixClearAll(PIX *pix)
pixClearAll()
Definition: pix2.c:712
PTA * ptaClone(PTA *pta)
ptaClone()
Definition: ptabasic.c:296
l_ok l_convertCharstrToInt(const char *str, l_int32 *pval)
l_convertCharstrToInt()
Definition: recogbasic.c:782
struct Numa * nascore
Definition: recog.h:230
Definition: pix.h:532
l_int32 scaleh
Definition: recog.h:119
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:836
PIX * pixInitAccumulate(l_int32 w, l_int32 h, l_uint32 offset)
pixInitAccumulate()
Definition: pixarith.c:551
PIX * pixMorphSequence(PIX *pixs, const char *sequence, l_int32 dispsep)
pixMorphSequence()
Definition: morphseq.c:133
l_ok pixAccumulate(PIX *pixd, PIX *pixs, l_int32 op)
pixAccumulate()
Definition: pixarith.c:719
void ptaaDestroy(PTAA **pptaa)
ptaaDestroy()
Definition: ptabasic.c:967
l_ok pixCountPixels(PIX *pixs, l_int32 *pcount, l_int32 *tab8)
pixCountPixels()
Definition: pix3.c:1823
struct L_Bmf * bmf
Definition: recog.h:171
l_ok ptaGetPt(PTA *pta, l_int32 index, l_float32 *px, l_float32 *py)
ptaGetPt()
Definition: ptabasic.c:525
l_int32 * makePixelSumTab8(void)
makePixelSumTab8()
Definition: pix3.c:2297
PIX * pixSetStrokeWidth(PIX *pixs, l_int32 width, l_int32 thinfirst, l_int32 connectivity)
pixSetStrokeWidth()
Definition: strokes.c:397
struct Pta * pta_u
Definition: recog.h:159
l_int32 recogShowAverageTemplates(L_RECOG *recog)
recogShowAverageTemplates()
Definition: recogtrain.c:2142
l_int32 recogGetClassIndex(L_RECOG *recog, l_int32 val, char *text, l_int32 *pindex)
recogGetClassIndex()
Definition: recogbasic.c:654
l_ok pixaaTruncate(PIXAA *paa)
pixaaTruncate()
Definition: pixabasic.c:2525
l_float32 max_ht_ratio
Definition: recog.h:145
static l_int32 recogTemplatesAreOK(L_RECOG *recog, l_int32 minsize, l_float32 minfract, l_int32 *pok)
recogTemplatesAreOK()
Definition: recogtrain.c:908
l_int32 maxheight_u
Definition: recog.h:138
char * sarrayGetString(SARRAY *sa, l_int32 index, l_int32 copyflag)
sarrayGetString()
Definition: sarray1.c:681
struct Ptaa * ptaa
Definition: recog.h:156
l_ok ptaaInitFull(PTAA *ptaa, PTA *pta)
ptaaInitFull()
Definition: ptabasic.c:1165
static SARRAY * recogAddMissingClassStrings(L_RECOG *recog)
recogAddMissingClassStrings()
Definition: recogtrain.c:1709
l_int32 num_samples
Definition: recog.h:134
l_ok recogProcessLabeled(L_RECOG *recog, PIX *pixs, BOX *box, char *text, PIX **ppix)
recogProcessLabeled()
Definition: recogtrain.c:261
PIX * pixClone(PIX *pixs)
pixClone()
Definition: pix1.c:515
l_int32 pixaAccumulateSamples(PIXA *pixa, PTA *pta, PIX **ppixd, l_float32 *px, l_float32 *py)
pixaAccumulateSamples()
Definition: recogtrain.c:664
struct Pixa * pixa_tr
Definition: recog.h:164
PIX * pixScaleToSize(PIX *pixs, l_int32 wd, l_int32 hd)
pixScaleToSize()
Definition: scale1.c:317
l_int32 size
Definition: recog.h:216
PIX * pixFinalAccumulate(PIX *pixs, l_uint32 offset, l_int32 depth)
pixFinalAccumulate()
Definition: pixarith.c:585
l_ok numaaTruncate(NUMAA *naa)
numaaTruncate()
Definition: numabasic.c:1410
struct L_Dna * dna_tochar
Definition: recog.h:149
void pixDestroy(PIX **ppix)
pixDestroy()
Definition: pix1.c:543
PIXA * recogAddDigitPadTemplates(L_RECOG *recog, SARRAY *sa)
recogAddDigitPadTemplates()
Definition: recogtrain.c:1768
PIXA * pixaSort(PIXA *pixas, l_int32 sorttype, l_int32 sortorder, NUMA **pnaindex, l_int32 copyflag)
pixaSort()
Definition: pixafunc1.c:1334
l_ok numaaAddNumber(NUMAA *naa, l_int32 index, l_float32 val)
numaaAddNumber()
Definition: numabasic.c:1771
l_int32 recogAverageSamples(L_RECOG **precog, l_int32 debug)
recogAverageSamples()
Definition: recogtrain.c:486
l_ok recogShowContent(FILE *fp, L_RECOG *recog, l_int32 index, l_int32 display)
recogShowContent()
Definition: recogtrain.c:1981
Definition: pix.h:454
PIX * pixaaDisplayByPixa(PIXAA *paa, l_int32 xspace, l_int32 yspace, l_int32 maxw)
pixaaDisplayByPixa()
Definition: pixafunc2.c:1588
struct Pix * pixdb_range
Definition: recog.h:168
void numaDestroy(NUMA **pna)
numaDestroy()
Definition: numabasic.c:360
Definition: pix.h:465
PIX * pixSeedfillBinary(PIX *pixd, PIX *pixs, PIX *pixm, l_int32 connectivity)
pixSeedfillBinary()
Definition: seedfill.c:243
l_ok pixGetDimensions(const PIX *pix, l_int32 *pw, l_int32 *ph, l_int32 *pd)
pixGetDimensions()
Definition: pix1.c:1065
PIX * recogShowMatch(L_RECOG *recog, PIX *pix1, PIX *pix2, BOX *box, l_int32 index, l_float32 score)
recogShowMatch()
Definition: recogtrain.c:2425
l_int32 maxwidth_u
Definition: recog.h:136
l_ok numaGetMin(NUMA *na, l_float32 *pminval, l_int32 *piminloc)
numaGetMin()
Definition: numafunc1.c:444
l_ok numaaGetValue(NUMAA *naa, l_int32 i, l_int32 j, l_float32 *pfval, l_int32 *pival)
numaaGetValue()
Definition: numabasic.c:1728
PIXA * recogTrainFromBoot(L_RECOG *recogboot, PIXA *pixas, l_float32 minscore, l_int32 threshold, l_int32 debug)
recogTrainFromBoot()
Definition: recogtrain.c:1488
struct Pixaa * pixaa
Definition: recog.h:155
NUMA * pixCountByColumn(PIX *pix, BOX *box)
pixCountByColumn()
Definition: pix3.c:1983
l_ok pixaSizeRange(PIXA *pixa, l_int32 *pminw, l_int32 *pminh, l_int32 *pmaxw, l_int32 *pmaxh)
pixaSizeRange()
Definition: pixafunc1.c:2450
PIXA * l_bootnum_gen4(l_int32 nsamp)
l_bootnum_gen4()
Definition: bootnumgen4.c:793
l_int32 sarrayGetCount(SARRAY *sa)
sarrayGetCount()
Definition: sarray1.c:621
struct Ptaa * ptaa_u
Definition: recog.h:153
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:1328
l_int32 ave_done
Definition: recog.h:141
char * pixGetText(PIX *pix)
pixGetText()
Definition: pix1.c:1459
static PIX * recogDisplayOutlier(L_RECOG *recog, l_int32 iclass, l_int32 jsamp, l_int32 maxclass, l_float32 maxscore)
recogDisplayOutlier()
Definition: recogtrain.c:2276
PIXA * recogMakeBootDigitTemplates(l_int32 nsamp, l_int32 debug)
recogMakeBootDigitTemplates()
Definition: recogtrain.c:1917
L_RECOG * recogMakeBootDigitRecog(l_int32 nsamp, l_int32 scaleh, l_int32 linew, l_int32 maxyshift, l_int32 debug)
recogMakeBootDigitRecog()
Definition: recogtrain.c:1880
PIXA * recogExtractPixa(L_RECOG *recog)
recogExtractPixa()
Definition: recogbasic.c:1118
l_int32 train_done
Definition: recog.h:142
PIX * pixaGetPix(PIXA *pixa, l_int32 index, l_int32 accesstype)
pixaGetPix()
Definition: pixabasic.c:672
Definition: pix.h:718
l_ok pixRenderBoxArb(PIX *pix, BOX *box, l_int32 width, l_uint8 rval, l_uint8 gval, l_uint8 bval)
pixRenderBoxArb()
Definition: graphics.c:1642
l_ok pixaaInitFull(PIXAA *paa, PIXA *pixa)
pixaaInitFull()
Definition: pixabasic.c:2419
l_ok pixaaAddPixa(PIXAA *paa, PIXA *pixa, l_int32 copyflag)
pixaaAddPixa()
Definition: pixabasic.c:1976
PIXAA * recogSortPixaByClass(PIXA *pixa, l_int32 setsize)
recogSortPixaByClass()
Definition: recogtrain.c:1041
L_RECOG * recogCreateFromPixaNoFinish(PIXA *pixa, l_int32 scalew, l_int32 scaleh, l_int32 linew, l_int32 threshold, l_int32 maxyshift)
recogCreateFromPixaNoFinish()
Definition: recogbasic.c:327
Definition: pix.h:134
l_int32 min_splitw
Definition: recog.h:146
Definition: pix.h:719
void ptaDestroy(PTA **ppta)
ptaDestroy()
Definition: ptabasic.c:192
l_ok pixZero(PIX *pix, l_int32 *pempty)
pixZero()
Definition: pix3.c:1701
l_ok recogPadDigitTrainingSet(L_RECOG **precog, l_int32 scaleh, l_int32 linew)
recogPadDigitTrainingSet()
Definition: recogtrain.c:1592
l_ok pixaGetPixDimensions(PIXA *pixa, l_int32 index, l_int32 *pw, l_int32 *ph, l_int32 *pd)
pixaGetPixDimensions()
Definition: pixabasic.c:707
#define PIX_SRC
Definition: pix.h:327
PIX * pixCopy(PIX *pixd, PIX *pixs)
pixCopy()
Definition: pix1.c:628
PIX * recogModifyTemplate(L_RECOG *recog, PIX *pixs)
recogModifyTemplate()
Definition: recogtrain.c:417
void boxDestroy(BOX **pbox)
boxDestroy()
Definition: boxbasic.c:278
PIXA * pixaRemoveOutliers1(PIXA *pixas, l_float32 minscore, l_int32 mintarget, l_int32 minsize, PIX **ppixsave, PIX **ppixrem)
pixaRemoveOutliers1()
Definition: recogtrain.c:1159
NUMAA * numaaCreateFull(l_int32 nptr, l_int32 n)
numaaCreateFull()
Definition: numabasic.c:1379
l_int32 * centtab
Definition: recog.h:150
l_int32 minheight_u
Definition: recog.h:137
l_ok recogShowMatchesInRange(L_RECOG *recog, PIXA *pixa, l_float32 minscore, l_float32 maxscore, l_int32 display)
recogShowMatchesInRange()
Definition: recogtrain.c:2331
l_ok numaGetMax(NUMA *na, l_float32 *pmaxval, l_int32 *pimaxloc)
numaGetMax()
Definition: numafunc1.c:486
l_int32 maxyshift
Definition: recog.h:129
PIXA * pixaSelectRange(PIXA *pixas, l_int32 first, l_int32 last, l_int32 copyflag)
pixaSelectRange()
Definition: pixafunc1.c:1668
l_int32 charset_size
Definition: recog.h:132
l_int32 min_nopad
Definition: recog.h:133
PIX * pixaDisplayTiledWithText(PIXA *pixa, l_int32 maxwidth, l_float32 scalefactor, l_int32 spacing, l_int32 border, l_int32 fontsize, l_uint32 textcolor)
pixaDisplayTiledWithText()
Definition: pixafunc2.c:1292
l_ok boxGetGeometry(BOX *box, l_int32 *px, l_int32 *py, l_int32 *pw, l_int32 *ph)
boxGetGeometry()
Definition: boxbasic.c:310
Definition: pix.h:480
static PIX * pixDisplayOutliers(PIXA *pixas, NUMA *nas)
pixDisplayOutliers()
Definition: recogtrain.c:2220
void pixaDestroy(PIXA **ppixa)
pixaDestroy()
Definition: pixabasic.c:408
PIX * pixAddSingleTextblock(PIX *pixs, L_BMF *bmf, const char *textstr, l_uint32 val, l_int32 location, l_int32 *poverflow)
pixAddSingleTextblock()
Definition: textops.c:115
l_ok recogRemoveOutliers2(L_RECOG **precog, l_float32 minscore, l_int32 minsize, PIX **ppixsave, PIX **ppixrem)
recogRemoveOutliers2()
Definition: recogtrain.c:1299
struct Pixa * pixa
Definition: recog.h:161
l_int32 pixaGetCount(PIXA *pixa)
pixaGetCount()
Definition: pixabasic.c:631
l_ok numaGetRankValue(NUMA *na, l_float32 fract, NUMA *nasort, l_int32 usebins, l_float32 *pval)
numaGetRankValue()
Definition: numafunc1.c:3081
PTAA * ptaaCreate(l_int32 n)
ptaaCreate()
Definition: ptabasic.c:939
void recogDestroy(L_RECOG **precog)
recogDestroy()
Definition: recogbasic.c:478
PIX * pixAddBorderGeneral(PIX *pixs, l_int32 left, l_int32 right, l_int32 top, l_int32 bot, l_uint32 val)
pixAddBorderGeneral()
Definition: pix2.c:1842
Definition: pix.h:517
l_ok pixaaAddPix(PIXAA *paa, l_int32 index, PIX *pix, BOX *box, l_int32 copyflag)
pixaaAddPix()
Definition: pixabasic.c:2045
void sarrayDestroy(SARRAY **psa)
sarrayDestroy()
Definition: sarray1.c:355
struct L_Rch * rch
Definition: recog.h:174
PIXA * pixaExtendByScaling(PIXA *pixas, NUMA *nasc, l_int32 type, l_int32 include)
pixaExtendByScaling()
Definition: morphapp.c:973