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