Leptonica 1.85.0
Image processing and image analysis suite
Loading...
Searching...
No Matches
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#include "pix_internal.h"
168
169 /* Static functions */
170static l_int32 recogTemplatesAreOK(L_RECOG *recog, l_int32 minsize,
171 l_float32 minfract, l_int32 *pok);
173static l_int32 recogCharsetAvailable(l_int32 type);
174static PIX *pixDisplayOutliers(PIXA *pixas, NUMA *nas);
175static PIX *recogDisplayOutlier(L_RECOG *recog, l_int32 iclass, l_int32 jsamp,
176 l_int32 maxclass, l_float32 maxscore);
177
178 /* Default parameters that are used in recogTemplatesAreOK() and
179 * in outlier removal functions, and that use template set size
180 * to decide if the set of templates (before outliers are removed)
181 * is valid. Values are set to accept most sets of sample templates. */
182static const l_int32 DefaultMinSetSize = 1; /* minimum number of
183 samples for a valid class */
184static const l_float32 DefaultMinSetFract = 0.4f; /* minimum fraction
185 of classes required for a valid recog */
186
187 /* Defaults in pixaRemoveOutliers1() and pixaRemoveOutliers2() */
188static const l_float32 DefaultMinScore = 0.75; /* keep everything above */
189static const l_int32 DefaultMinTarget = 3; /* to be kept if possible */
190static const l_float32 LowerScoreThreshold = 0.5; /* templates can be
191 * kept down to this score to if needed to retain the
192 * desired minimum number of templates */
193
194
195/*------------------------------------------------------------------------*
196 * Training *
197 *------------------------------------------------------------------------*/
216l_ok
218 PIX *pixs,
219 BOX *box,
220 char *text,
221 l_int32 debug)
222{
223l_int32 ret;
224PIX *pix;
225
226 if (!recog)
227 return ERROR_INT("recog not defined", __func__, 1);
228 if (!pixs)
229 return ERROR_INT("pixs not defined", __func__, 1);
230
231 /* Prepare the sample to be added. This step also acts
232 * as a filter, and can invalidate pixs as a template. */
233 ret = recogProcessLabeled(recog, pixs, box, text, &pix);
234 if (ret) {
235 pixDestroy(&pix);
236 L_WARNING("failure to get sample '%s' for training\n", __func__,
237 text);
238 return 1;
239 }
240
241 recogAddSample(recog, pix, debug);
242 pixDestroy(&pix);
243 return 0;
244}
245
246
263l_ok
265 PIX *pixs,
266 BOX *box,
267 char *text,
268 PIX **ppix)
269{
270char *textdata;
271l_int32 textinpix, textin, nsets;
272NUMA *na;
273PIX *pix1, *pix2, *pix3, *pix4;
274
275 if (!ppix)
276 return ERROR_INT("&pix not defined", __func__, 1);
277 *ppix = NULL;
278 if (!recog)
279 return ERROR_INT("recog not defined", __func__, 1);
280 if (!pixs)
281 return ERROR_INT("pixs not defined", __func__, 1);
282
283 /* Find the text; this will be stored with the output images */
284 textin = text && (text[0] != '\0');
285 textinpix = (pixs->text && (pixs->text[0] != '\0'));
286 if (!textin && !textinpix) {
287 L_ERROR("no text: %d\n", __func__, recog->num_samples);
288 return 1;
289 }
290 textdata = (textin) ? text : pixs->text; /* do not free */
291
292 /* Crop and binarize if necessary */
293 if (box)
294 pix1 = pixClipRectangle(pixs, box, NULL);
295 else
296 pix1 = pixClone(pixs);
297 if (pixGetDepth(pix1) > 1)
298 pix2 = pixConvertTo1(pix1, recog->threshold);
299 else
300 pix2 = pixClone(pix1);
301 pixDestroy(&pix1);
302
303 /* Remove isolated noise, using as a criterion all components
304 * that are removed by a vertical opening of size 5. */
305 pix3 = pixMorphSequence(pix2, "o1.5", 0); /* seed */
306 pixSeedfillBinary(pix3, pix3, pix2, 8); /* fill from seed; clip to pix2 */
307 pixDestroy(&pix2);
308
309 /* Clip to foreground */
310 pixClipToForeground(pix3, &pix4, NULL);
311 pixDestroy(&pix3);
312 if (!pix4)
313 return ERROR_INT("pix4 is empty", __func__, 1);
314
315 /* Verify that if there is more than 1 c.c., they all have
316 * horizontal overlap */
317 na = pixCountByColumn(pix4, NULL);
318 numaCountNonzeroRuns(na, &nsets);
319 numaDestroy(&na);
320 if (nsets > 1) {
321 L_WARNING("found %d sets of horiz separated c.c.; skipping\n",
322 __func__, nsets);
323 pixDestroy(&pix4);
324 return 1;
325 }
326
327 pixSetText(pix4, textdata);
328 *ppix = pix4;
329 return 0;
330}
331
332
352l_ok
354 PIX *pix,
355 l_int32 debug)
356{
357char *text;
358l_int32 npa, charint, index;
359PIXA *pixa1;
360PIXAA *paa;
361
362 if (!recog)
363 return ERROR_INT("recog not defined", __func__, 1);
364 if (!pix || pixGetDepth(pix) != 1)
365 return ERROR_INT("pix not defined or not 1 bpp\n", __func__, 1);
366 if (recog->train_done)
367 return ERROR_INT("not added: training has been completed", __func__, 1);
368 paa = recog->pixaa_u;
369
370 /* Make sure the character is in the set */
371 text = pixGetText(pix);
372 if (l_convertCharstrToInt(text, &charint) == 1) {
373 L_ERROR("invalid text: %s\n", __func__, text);
374 return 1;
375 }
376
377 /* Determine the class array index. Check if the class
378 * already exists, and if not, add it. */
379 if (recogGetClassIndex(recog, charint, text, &index) == 1) {
380 /* New class must be added */
381 npa = pixaaGetCount(paa, NULL);
382 if (index > npa) {
383 L_ERROR("oops: bad index %d > npa %d!!\n", __func__, index, npa);
384 return 1;
385 }
386 if (index == npa) { /* paa needs to be extended */
387 L_INFO("Adding new class and pixa: index = %d, text = %s\n",
388 __func__, index, text);
389 pixa1 = pixaCreate(10);
390 pixaaAddPixa(paa, pixa1, L_INSERT);
391 }
392 }
393 if (debug) {
394 L_INFO("Identified text label: %s\n", __func__, text);
395 L_INFO("Identified: charint = %d, index = %d\n",
396 __func__, charint, index);
397 }
398
399 /* Insert the unscaled character image into the right pixa.
400 * (Unscaled images are required to split touching characters.) */
401 recog->num_samples++;
402 pixaaAddPix(paa, index, pix, NULL, L_COPY);
403 return 0;
404}
405
406
415PIX *
417 PIX *pixs)
418{
419l_int32 w, h, empty;
420PIX *pix1, *pix2;
421
422 if (!recog)
423 return (PIX *)ERROR_PTR("recog not defined", __func__, NULL);
424 if (!pixs)
425 return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
426
427 /* Scale first */
428 pixGetDimensions(pixs, &w, &h, NULL);
429 if ((recog->scalew == 0 || recog->scalew == w) &&
430 (recog->scaleh == 0 || recog->scaleh == h)) { /* no scaling */
431 pix1 = pixCopy(NULL, pixs);
432 } else {
433 pix1 = pixScaleToSize(pixs, recog->scalew, recog->scaleh);
434 }
435 if (!pix1)
436 return (PIX *)ERROR_PTR("pix1 not made", __func__, NULL);
437
438 /* Then optionally convert to lines */
439 if (recog->linew <= 0) {
440 pix2 = pixClone(pix1);
441 } else {
442 pix2 = pixSetStrokeWidth(pix1, recog->linew, 1, 8);
443 }
444 pixDestroy(&pix1);
445 if (!pix2)
446 return (PIX *)ERROR_PTR("pix2 not made", __func__, NULL);
447
448 /* Make sure we still have some pixels */
449 pixZero(pix2, &empty);
450 if (empty) {
451 pixDestroy(&pix2);
452 return (PIX *)ERROR_PTR("modified template has no pixels",
453 __func__, NULL);
454 }
455 return pix2;
456}
457
458
483l_int32
485 l_int32 debug)
486{
487l_int32 i, nsamp, size, area, bx, by, badclass;
488l_float32 x, y, hratio;
489BOX *box;
490PIXA *pixa1;
491PIX *pix1, *pix2, *pix3;
492PTA *pta1;
493
494 if (!recog)
495 return ERROR_INT("recog not defined", __func__, 1);
496
497 if (recog->ave_done) {
498 if (debug) /* always do this if requested */
500 return 0;
501 }
502
503 /* Remove any previous averaging data */
504 size = recog->setsize;
505 pixaDestroy(&recog->pixa_u);
506 ptaDestroy(&recog->pta_u);
507 numaDestroy(&recog->nasum_u);
508 recog->pixa_u = pixaCreate(size);
509 recog->pta_u = ptaCreate(size);
510 recog->nasum_u = numaCreate(size);
511
512 pixaDestroy(&recog->pixa);
513 ptaDestroy(&recog->pta);
514 numaDestroy(&recog->nasum);
515 recog->pixa = pixaCreate(size);
516 recog->pta = ptaCreate(size);
517 recog->nasum = numaCreate(size);
518
519 /* Unscaled bitmaps: compute averaged bitmap, centroid, and fg area.
520 * Note that when we threshold to 1 bpp the 8 bpp averaged template
521 * that is returned from the accumulator, it will not be cropped
522 * to the foreground. We must crop it, because the correlator
523 * makes that assumption and will return a zero value if the
524 * width or height of the two images differs by several pixels.
525 * But cropping to fg can cause the value of the centroid to
526 * change, if bx > 0 or by > 0. */
527 badclass = FALSE;
528 for (i = 0; i < size; i++) {
529 pixa1 = pixaaGetPixa(recog->pixaa_u, i, L_CLONE);
530 pta1 = ptaaGetPta(recog->ptaa_u, i, L_CLONE);
531 nsamp = pixaGetCount(pixa1);
532 nsamp = L_MIN(nsamp, 256); /* we only use the first 256 */
533 if (nsamp == 0) { /* no information for this class */
534 L_ERROR("no samples in class %d\n", __func__, i);
535 badclass = TRUE;
536 pixaDestroy(&pixa1);
537 ptaDestroy(&pta1);
538 break;
539 } else {
540 pixaAccumulateSamples(pixa1, pta1, &pix1, &x, &y);
541 pix2 = pixThresholdToBinary(pix1, L_MAX(1, nsamp / 2));
542 pixInvert(pix2, pix2);
543 pixClipToForeground(pix2, &pix3, &box);
544 if (!box) {
545 L_ERROR("no fg pixels in average for uclass %d\n", __func__, i);
546 badclass = TRUE;
547 pixDestroy(&pix1);
548 pixDestroy(&pix2);
549 pixaDestroy(&pixa1);
550 ptaDestroy(&pta1);
551 break;
552 } else {
553 boxGetGeometry(box, &bx, &by, NULL, NULL);
554 pixaAddPix(recog->pixa_u, pix3, L_INSERT);
555 ptaAddPt(recog->pta_u, x - bx, y - by); /* correct centroid */
556 pixCountPixels(pix3, &area, recog->sumtab);
557 numaAddNumber(recog->nasum_u, area); /* foreground */
558 boxDestroy(&box);
559 }
560 pixDestroy(&pix1);
561 pixDestroy(&pix2);
562 }
563 pixaDestroy(&pixa1);
564 ptaDestroy(&pta1);
565 }
566
567 /* Are any classes bad? */
568 if (badclass)
569 return ERROR_INT("at least 1 bad class", __func__, 1);
570
571 /* Get the range of sizes of the unscaled average templates.
572 * Reject if the height ratio is too large. */
573 pixaSizeRange(recog->pixa_u, &recog->minwidth_u, &recog->minheight_u,
574 &recog->maxwidth_u, &recog->maxheight_u);
575 hratio = (l_float32)recog->maxheight_u / (l_float32)recog->minheight_u;
576 if (hratio > recog->max_ht_ratio) {
577 L_ERROR("ratio of max/min height of average templates = %4.1f\n",
578 __func__, hratio);
579 return 1;
580 }
581
582 /* Scaled bitmaps: compute averaged bitmap, centroid, and fg area */
583 for (i = 0; i < size; i++) {
584 pixa1 = pixaaGetPixa(recog->pixaa, i, L_CLONE);
585 pta1 = ptaaGetPta(recog->ptaa, i, L_CLONE);
586 nsamp = pixaGetCount(pixa1);
587 nsamp = L_MIN(nsamp, 256); /* we only use the first 256 */
588 pixaAccumulateSamples(pixa1, pta1, &pix1, &x, &y);
589 pix2 = pixThresholdToBinary(pix1, L_MAX(1, nsamp / 2));
590 pixInvert(pix2, pix2);
591 pixClipToForeground(pix2, &pix3, &box);
592 if (!box) {
593 L_ERROR("no fg pixels in average for class %d\n", __func__, i);
594 badclass = TRUE;
595 pixDestroy(&pix1);
596 pixDestroy(&pix2);
597 pixaDestroy(&pixa1);
598 ptaDestroy(&pta1);
599 break;
600 } else {
601 boxGetGeometry(box, &bx, &by, NULL, NULL);
602 pixaAddPix(recog->pixa, pix3, L_INSERT);
603 ptaAddPt(recog->pta, x - bx, y - by); /* correct centroid */
604 pixCountPixels(pix3, &area, recog->sumtab);
605 numaAddNumber(recog->nasum, area); /* foreground */
606 boxDestroy(&box);
607 }
608 pixDestroy(&pix1);
609 pixDestroy(&pix2);
610 pixaDestroy(&pixa1);
611 ptaDestroy(&pta1);
612 }
613
614 if (badclass)
615 return ERROR_INT("no fg pixels in at least 1 class", __func__, 1);
616
617 /* Get the range of widths of the scaled average templates */
618 pixaSizeRange(recog->pixa, &recog->minwidth, NULL, &recog->maxwidth, NULL);
619
620 /* Get dimensions useful for splitting */
621 recog->min_splitw = L_MAX(5, recog->minwidth_u - 5);
622 recog->max_splith = recog->maxheight_u + 12; /* allow for skew */
623
624 if (debug)
626
627 recog->ave_done = TRUE;
628 return 0;
629}
630
631
651l_int32
653 PTA *pta,
654 PIX **ppixd,
655 l_float32 *px,
656 l_float32 *py)
657{
658l_int32 i, n, maxw, maxh, xdiff, ydiff;
659l_int32 *centtab, *sumtab;
660l_float32 xc, yc, xave, yave;
661PIX *pix1, *pix2, *pixsum;
662PTA *ptac;
663
664 if (px) *px = 0;
665 if (py) *py = 0;
666 if (!ppixd)
667 return ERROR_INT("&pixd not defined", __func__, 1);
668 *ppixd = NULL;
669 if (!pixa)
670 return ERROR_INT("pixa not defined", __func__, 1);
671
672 n = pixaGetCount(pixa);
673 if (pta && ptaGetCount(pta) != n)
674 return ERROR_INT("pta count differs from pixa count", __func__, 1);
675 n = L_MIN(n, 256); /* take the first 256 only */
676 if (n == 0)
677 return ERROR_INT("pixa array empty", __func__, 1);
678
679 /* Find the centroids */
680 if (pta) {
681 ptac = ptaClone(pta);
682 } else { /* generate them here */
683 ptac = ptaCreate(n);
684 centtab = makePixelCentroidTab8();
685 sumtab = makePixelSumTab8();
686 for (i = 0; i < n; i++) {
687 pix1 = pixaGetPix(pixa, i, L_CLONE);
688 pixCentroid(pix1, centtab, sumtab, &xc, &yc);
689 ptaAddPt(ptac, xc, yc);
690 }
691 LEPT_FREE(centtab);
692 LEPT_FREE(sumtab);
693 }
694
695 /* Find the average value of the centroids */
696 xave = yave = 0;
697 for (i = 0; i < n; i++) {
698 ptaGetPt(pta, i, &xc, &yc);
699 xave += xc;
700 yave += yc;
701 }
702 xave = xave / (l_float32)n;
703 yave = yave / (l_float32)n;
704 if (px) *px = xave;
705 if (py) *py = yave;
706
707 /* Place all pix with their centroids located at the average
708 * centroid value, and sum the results. Make the accumulator
709 * image slightly larger than the largest sample to insure
710 * that all pixels are represented in the accumulator. */
711 pixaSizeRange(pixa, NULL, NULL, &maxw, &maxh);
712 pixsum = pixInitAccumulate(maxw + 5, maxh + 5, 0);
713 pix1 = pixCreate(maxw, maxh, 1);
714 for (i = 0; i < n; i++) {
715 pix2 = pixaGetPix(pixa, i, L_CLONE);
716 ptaGetPt(ptac, i, &xc, &yc);
717 xdiff = (l_int32)(xave - xc);
718 ydiff = (l_int32)(yave - yc);
719 pixClearAll(pix1);
720 pixRasterop(pix1, xdiff, ydiff, maxw, maxh, PIX_SRC,
721 pix2, 0, 0);
722 pixAccumulate(pixsum, pix1, L_ARITH_ADD);
723 pixDestroy(&pix2);
724 }
725 *ppixd = pixFinalAccumulate(pixsum, 0, 8);
726
727 pixDestroy(&pix1);
728 pixDestroy(&pixsum);
729 ptaDestroy(&ptac);
730 return 0;
731}
732
733
768l_ok
770 l_int32 modifyflag,
771 l_int32 minsize,
772 l_float32 minfract)
773{
774l_int32 ok, i, j, size, nc, ns, area;
775l_float32 xave, yave;
776PIX *pix, *pixd;
777PIXA *pixa;
778PIXAA *paa;
779PTA *pta;
780PTAA *ptaa;
781L_RECOG *recog;
782
783 if (!precog)
784 return ERROR_INT("&recog not defined", __func__, 1);
785 if ((recog = *precog) == NULL)
786 return ERROR_INT("recog not defined", __func__, 1);
787 if (recog->train_done) return 0;
788
789 /* Test the input templates */
790 recogTemplatesAreOK(recog, minsize, minfract, &ok);
791 if (!ok) {
792 recogDestroy(precog);
793 return ERROR_INT("bad templates", __func__, 1);
794 }
795
796 /* Generate the storage for the possibly-scaled training bitmaps */
797 size = recog->maxarraysize;
798 paa = pixaaCreate(size);
799 pixa = pixaCreate(1);
800 pixaaInitFull(paa, pixa);
801 pixaDestroy(&pixa);
802 pixaaDestroy(&recog->pixaa);
803 recog->pixaa = paa;
804
805 /* Generate the storage for the unscaled centroid training data */
806 ptaa = ptaaCreate(size);
807 pta = ptaCreate(0);
808 ptaaInitFull(ptaa, pta);
809 ptaaDestroy(&recog->ptaa_u);
810 recog->ptaa_u = ptaa;
811
812 /* Generate the storage for the possibly-scaled centroid data */
813 ptaa = ptaaCreate(size);
814 ptaaInitFull(ptaa, pta);
815 ptaDestroy(&pta);
816 ptaaDestroy(&recog->ptaa);
817 recog->ptaa = ptaa;
818
819 /* Generate the storage for the fg area data */
820 numaaDestroy(&recog->naasum_u);
821 numaaDestroy(&recog->naasum);
822 recog->naasum_u = numaaCreateFull(size, 0);
823 recog->naasum = numaaCreateFull(size, 0);
824
825 paa = recog->pixaa_u;
826 nc = recog->setsize;
827 for (i = 0; i < nc; i++) {
828 pixa = pixaaGetPixa(paa, i, L_CLONE);
829 ns = pixaGetCount(pixa);
830 for (j = 0; j < ns; j++) {
831 /* Save centroid and area data for the unscaled pix */
832 pix = pixaGetPix(pixa, j, L_CLONE);
833 pixCentroid(pix, recog->centtab, recog->sumtab, &xave, &yave);
834 ptaaAddPt(recog->ptaa_u, i, xave, yave);
835 pixCountPixels(pix, &area, recog->sumtab);
836 numaaAddNumber(recog->naasum_u, i, area); /* foreground */
837
838 /* Insert the (optionally) scaled character image, and
839 * save centroid and area data for it */
840 if (modifyflag == 1)
841 pixd = recogModifyTemplate(recog, pix);
842 else
843 pixd = pixClone(pix);
844 if (pixd) {
845 pixaaAddPix(recog->pixaa, i, pixd, NULL, L_INSERT);
846 pixCentroid(pixd, recog->centtab, recog->sumtab, &xave, &yave);
847 ptaaAddPt(recog->ptaa, i, xave, yave);
848 pixCountPixels(pixd, &area, recog->sumtab);
849 numaaAddNumber(recog->naasum, i, area);
850 } else {
851 L_ERROR("failed: modified template for class %d, sample %d\n",
852 __func__, i, j);
853 }
854 pixDestroy(&pix);
855 }
856 pixaDestroy(&pixa);
857 }
858
859 /* Truncate the arrays to those with non-empty containers */
860 pixaaTruncate(recog->pixaa_u);
861 pixaaTruncate(recog->pixaa);
862 ptaaTruncate(recog->ptaa_u);
863 ptaaTruncate(recog->ptaa);
864 numaaTruncate(recog->naasum_u);
865 numaaTruncate(recog->naasum);
866
867 recog->train_done = TRUE;
868 return 0;
869}
870
871
891static l_int32
893 l_int32 minsize,
894 l_float32 minfract,
895 l_int32 *pok)
896{
897l_int32 i, n, validsets, nt;
898l_float32 ratio;
899NUMA *na;
900
901 if (!pok)
902 return ERROR_INT("&ok not defined", __func__, 1);
903 *pok = 0;
904 if (!recog)
905 return ERROR_INT("recog not defined", __func__, 1);
906
907 minsize = (minsize < 0) ? DefaultMinSetSize : minsize;
908 minfract = (minfract < 0) ? DefaultMinSetFract : minfract;
909 n = pixaaGetCount(recog->pixaa_u, &na);
910 validsets = 0;
911 for (i = 0, validsets = 0; i < n; i++) {
912 numaGetIValue(na, i, &nt);
913 if (nt >= minsize)
914 validsets++;
915 }
916 numaDestroy(&na);
917 ratio = (l_float32)validsets / (l_float32)recog->charset_size;
918 *pok = (ratio >= minfract) ? 1 : 0;
919 return 0;
920}
921
922
951PIXA *
953 l_int32 setsize,
954 l_int32 maxkeep,
955 l_float32 max_ht_ratio,
956 NUMA **pna)
957{
958l_int32 i, j, h90, hj, j1, j2, j90, n, nc;
959l_float32 ratio;
960NUMA *na;
961PIXA *pixa1, *pixa2, *pixa3, *pixa4, *pixa5;
962PIXAA *paa;
963
964 if (pna) *pna = NULL;
965 if (!pixas)
966 return (PIXA *)ERROR_PTR("pixas not defined", __func__, NULL);
967
968 if ((paa = recogSortPixaByClass(pixas, setsize)) == NULL)
969 return (PIXA *)ERROR_PTR("paa not made", __func__, NULL);
970 nc = pixaaGetCount(paa, NULL);
971 na = (pna) ? numaCreate(0) : NULL;
972 if (pna) *pna = na;
973 pixa5 = pixaCreate(0);
974 for (i = 0; i < nc; i++) {
975 pixa1 = pixaaGetPixa(paa, i, L_CLONE);
976 if ((n = pixaGetCount(pixa1)) == 0) {
977 pixaDestroy(&pixa1);
978 continue;
979 }
980 pixa2 = pixaSort(pixa1, L_SORT_BY_HEIGHT, L_SORT_INCREASING, NULL,
981 L_COPY);
982 j90 = (l_int32)(0.9 * n);
983 pixaGetPixDimensions(pixa2, j90, NULL, &h90, NULL);
984 pixa3 = pixaCreate(n);
985 for (j = 0; j < n; j++) {
986 pixaGetPixDimensions(pixa2, j, NULL, &hj, NULL);
987 ratio = (l_float32)h90 / (l_float32)hj;
988 if (ratio <= max_ht_ratio)
989 pixaAddPix(pixa3, pixaGetPix(pixa2, j, L_COPY), L_INSERT);
990 }
991 n = pixaGetCount(pixa3);
992 if (n <= maxkeep) {
993 pixa4 = pixaCopy(pixa3, L_CLONE);
994 } else {
995 j1 = (n - maxkeep) / 2;
996 j2 = j1 + maxkeep - 1;
997 pixa4 = pixaSelectRange(pixa3, j1, j2, L_CLONE);
998 }
999 if (na) numaAddNumber(na, pixaGetCount(pixa4));
1000 pixaJoin(pixa5, pixa4, 0, -1);
1001 pixaDestroy(&pixa1);
1002 pixaDestroy(&pixa2);
1003 pixaDestroy(&pixa3);
1004 pixaDestroy(&pixa4);
1005 }
1006
1007 pixaaDestroy(&paa);
1008 return pixa5;
1009}
1010
1011
1020PIXAA *
1022 l_int32 setsize)
1023{
1024PIXAA *paa;
1025L_RECOG *recog;
1026
1027 if (!pixa)
1028 return (PIXAA *)ERROR_PTR("pixa not defined", __func__, NULL);
1029
1030 if ((recog = recogCreateFromPixaNoFinish(pixa, 0, 0, 0, 0, 0)) == NULL)
1031 return (PIXAA *)ERROR_PTR("recog not made", __func__, NULL);
1032 paa = recog->pixaa_u; /* grab the paa of unscaled templates */
1033 recog->pixaa_u = NULL;
1034 recogDestroy(&recog);
1035 return paa;
1036}
1037
1038
1058l_ok
1060 l_float32 minscore,
1061 l_int32 mintarget,
1062 l_int32 minsize,
1063 PIX **ppixsave,
1064 PIX **ppixrem)
1065{
1066PIXA *pixa1, *pixa2;
1067L_RECOG *recog;
1068
1069 if (!precog)
1070 return ERROR_INT("&recog not defined", __func__, 1);
1071 if (*precog == NULL)
1072 return ERROR_INT("recog not defined", __func__, 1);
1073
1074 /* Extract the unscaled templates */
1075 pixa1 = recogExtractPixa(*precog);
1076 recogDestroy(precog);
1077
1078 pixa2 = pixaRemoveOutliers1(pixa1, minscore, mintarget, minsize,
1079 ppixsave, ppixrem);
1080 pixaDestroy(&pixa1);
1081 if (!pixa2)
1082 return ERROR_INT("failure to remove outliers", __func__, 1);
1083
1084 recog = recogCreateFromPixa(pixa2, 0, 0, 0, 150, 1);
1085 pixaDestroy(&pixa2);
1086 if (!recog)
1087 return ERROR_INT("failure to make recog from pixa sans outliers",
1088 __func__, 1);
1089
1090 *precog = recog;
1091 return 0;
1092}
1093
1094
1134PIXA *
1136 l_float32 minscore,
1137 l_int32 mintarget,
1138 l_int32 minsize,
1139 PIX **ppixsave,
1140 PIX **ppixrem)
1141{
1142l_int32 i, j, debug, n, area1, area2;
1143l_float32 x1, y1, x2, y2, minfract, score, rankscore, threshscore;
1144NUMA *nasum, *narem, *nasave, *nascore;
1145PIX *pix1, *pix2;
1146PIXA *pixa, *pixarem, *pixad;
1147PTA *pta;
1148L_RECOG *recog;
1149
1150 if (ppixsave) *ppixsave = NULL;
1151 if (ppixrem) *ppixrem = NULL;
1152 if (!pixas)
1153 return (PIXA *)ERROR_PTR("pixas not defined", __func__, NULL);
1154 minscore = L_MIN(minscore, 1.0);
1155 if (minscore <= 0.0)
1156 minscore = DefaultMinScore;
1157 mintarget = L_MIN(mintarget, 3);
1158 if (mintarget <= 0)
1159 mintarget = DefaultMinTarget;
1160 if (minsize < 0)
1161 minsize = DefaultMinSetSize;
1162
1163 /* Make a special height-scaled recognizer with average templates */
1164 debug = (ppixsave || ppixrem) ? 1 : 0;
1165 recog = recogCreateFromPixa(pixas, 0, 40, 0, 128, 1);
1166 if (!recog)
1167 return (PIXA *)ERROR_PTR("bad pixas; recog not made", __func__, NULL);
1168 if (recogAverageSamples(recog, debug) != 0) {
1169 recogDestroy(&recog);
1170 return (PIXA *)ERROR_PTR("bad templates", __func__, NULL);
1171 }
1172
1173 nasave = (ppixsave) ? numaCreate(0) : NULL;
1174 pixarem = (ppixrem) ? pixaCreate(0) : NULL;
1175 narem = (ppixrem) ? numaCreate(0) : NULL;
1176
1177 pixad = pixaCreate(0);
1178 for (i = 0; i < recog->setsize; i++) {
1179 /* Access the average template and values for scaled
1180 * images in this class */
1181 pix1 = pixaGetPix(recog->pixa, i, L_CLONE);
1182 ptaGetPt(recog->pta, i, &x1, &y1);
1183 numaGetIValue(recog->nasum, i, &area1);
1184
1185 /* Get the scores for each sample in the class */
1186 pixa = pixaaGetPixa(recog->pixaa, i, L_CLONE);
1187 pta = ptaaGetPta(recog->ptaa, i, L_CLONE); /* centroids */
1188 nasum = numaaGetNuma(recog->naasum, i, L_CLONE); /* fg areas */
1189 n = pixaGetCount(pixa);
1190 nascore = numaCreate(n);
1191 for (j = 0; j < n; j++) {
1192 pix2 = pixaGetPix(pixa, j, L_CLONE);
1193 ptaGetPt(pta, j, &x2, &y2); /* centroid average */
1194 numaGetIValue(nasum, j, &area2); /* fg sum average */
1195 pixCorrelationScoreSimple(pix1, pix2, area1, area2,
1196 x1 - x2, y1 - y2, 5, 5,
1197 recog->sumtab, &score);
1198 numaAddNumber(nascore, score);
1199 if (debug && score == 0.0) /* typ. large size difference */
1200 lept_stderr("Got 0 score for i = %d, j = %d\n", i, j);
1201 pixDestroy(&pix2);
1202 }
1203 pixDestroy(&pix1);
1204
1205 /* Find the rankscore, corresponding to the 1.0 - minfract.
1206 * To attempt to maintain the minfract of templates, use as a
1207 * cutoff the minimum of minscore and the rank score. However,
1208 * no template is saved with an actual score less than
1209 * that at least one template is kept. */
1210 minfract = (l_float32)mintarget / (l_float32)n;
1211 numaGetRankValue(nascore, 1.0 - minfract, NULL, 0, &rankscore);
1212 threshscore = L_MAX(LowerScoreThreshold,
1213 L_MIN(minscore, rankscore));
1214 if (debug) {
1215 L_INFO("minscore = %4.2f, rankscore = %4.2f, threshscore = %4.2f\n",
1216 __func__, minscore, rankscore, threshscore);
1217 }
1218
1219 /* Save templates that are at or above threshold.
1220 * Toss any classes with less than %minsize templates. */
1221 for (j = 0; j < n; j++) {
1222 numaGetFValue(nascore, j, &score);
1223 pix1 = pixaaGetPix(recog->pixaa_u, i, j, L_COPY);
1224 if (score >= threshscore && n >= minsize) {
1225 pixaAddPix(pixad, pix1, L_INSERT);
1226 if (nasave) numaAddNumber(nasave, score);
1227 } else if (debug) {
1228 pixaAddPix(pixarem, pix1, L_INSERT);
1229 numaAddNumber(narem, score);
1230 } else {
1231 pixDestroy(&pix1);
1232 }
1233 }
1234
1235 pixaDestroy(&pixa);
1236 ptaDestroy(&pta);
1237 numaDestroy(&nasum);
1238 numaDestroy(&nascore);
1239 }
1240
1241 if (ppixsave) {
1242 *ppixsave = pixDisplayOutliers(pixad, nasave);
1243 numaDestroy(&nasave);
1244 }
1245 if (ppixrem) {
1246 *ppixrem = pixDisplayOutliers(pixarem, narem);
1247 pixaDestroy(&pixarem);
1248 numaDestroy(&narem);
1249 }
1250 recogDestroy(&recog);
1251 return pixad;
1252}
1253
1254
1273l_ok
1275 l_float32 minscore,
1276 l_int32 minsize,
1277 PIX **ppixsave,
1278 PIX **ppixrem)
1279{
1280PIXA *pixa1, *pixa2;
1281L_RECOG *recog;
1282
1283 if (!precog)
1284 return ERROR_INT("&recog not defined", __func__, 1);
1285 if (*precog == NULL)
1286 return ERROR_INT("recog not defined", __func__, 1);
1287
1288 /* Extract the unscaled templates */
1289 pixa1 = recogExtractPixa(*precog);
1290 recogDestroy(precog);
1291
1292 pixa2 = pixaRemoveOutliers2(pixa1, minscore, minsize, ppixsave, ppixrem);
1293 pixaDestroy(&pixa1);
1294 if (!pixa2)
1295 return ERROR_INT("failure to remove outliers", __func__, 1);
1296
1297 recog = recogCreateFromPixa(pixa2, 0, 0, 0, 150, 1);
1298 pixaDestroy(&pixa2);
1299 if (!recog)
1300 return ERROR_INT("failure to make recog from pixa sans outliers",
1301 __func__, 1);
1302
1303 *precog = recog;
1304 return 0;
1305}
1306
1307
1335PIXA *
1337 l_float32 minscore,
1338 l_int32 minsize,
1339 PIX **ppixsave,
1340 PIX **ppixrem)
1341{
1342l_int32 i, j, k, n, area1, area2, maxk, debug;
1343l_float32 x1, y1, x2, y2, score, maxscore;
1344NUMA *nan, *nascore, *nasave;
1345PIX *pix1, *pix2, *pix3;
1346PIXA *pixarem, *pixad;
1347L_RECOG *recog;
1348
1349 if (ppixsave) *ppixsave = NULL;
1350 if (ppixrem) *ppixrem = NULL;
1351 if (!pixas)
1352 return (PIXA *)ERROR_PTR("pixas not defined", __func__, NULL);
1353 minscore = L_MIN(minscore, 1.0);
1354 if (minscore <= 0.0)
1355 minscore = DefaultMinScore;
1356 if (minsize < 0)
1357 minsize = DefaultMinSetSize;
1358
1359 /* Make a special height-scaled recognizer with average templates */
1360 debug = (ppixsave || ppixrem) ? 1 : 0;
1361 recog = recogCreateFromPixa(pixas, 0, 40, 0, 128, 1);
1362 if (!recog)
1363 return (PIXA *)ERROR_PTR("bad pixas; recog not made", __func__, NULL);
1364 if (recogAverageSamples(recog, debug) != 0) {
1365 recogDestroy(&recog);
1366 return (PIXA *)ERROR_PTR("bad templates", __func__, NULL);
1367 }
1368
1369 nasave = (ppixsave) ? numaCreate(0) : NULL;
1370 pixarem = (ppixrem) ? pixaCreate(0) : NULL;
1371
1372 pixad = pixaCreate(0);
1373 pixaaGetCount(recog->pixaa, &nan); /* number of templates in each class */
1374 for (i = 0; i < recog->setsize; i++) {
1375 /* Get the scores for each sample in the class, when comparing
1376 * with averages from all the classes. */
1377 numaGetIValue(nan, i, &n);
1378 for (j = 0; j < n; j++) {
1379 pix1 = pixaaGetPix(recog->pixaa, i, j, L_CLONE);
1380 ptaaGetPt(recog->ptaa, i, j, &x1, &y1); /* centroid */
1381 numaaGetValue(recog->naasum, i, j, NULL, &area1); /* fg sum */
1382 nascore = numaCreate(n);
1383 for (k = 0; k < recog->setsize; k++) { /* average templates */
1384 pix2 = pixaGetPix(recog->pixa, k, L_CLONE);
1385 ptaGetPt(recog->pta, k, &x2, &y2); /* average centroid */
1386 numaGetIValue(recog->nasum, k, &area2); /* average fg sum */
1387 pixCorrelationScoreSimple(pix1, pix2, area1, area2,
1388 x1 - x2, y1 - y2, 5, 5,
1389 recog->sumtab, &score);
1390 numaAddNumber(nascore, score);
1391 pixDestroy(&pix2);
1392 }
1393
1394 /* Save templates that are in the correct class and
1395 * at or above threshold. Toss any classes with less
1396 * than %minsize templates. */
1397 numaGetMax(nascore, &maxscore, &maxk);
1398 if (maxk == i && maxscore >= minscore && n >= minsize) {
1399 /* save it */
1400 pix3 = pixaaGetPix(recog->pixaa_u, i, j, L_COPY);
1401 pixaAddPix(pixad, pix3, L_INSERT);
1402 if (nasave) numaAddNumber(nasave, maxscore);
1403 } else if (ppixrem) { /* outlier */
1404 pix3 = recogDisplayOutlier(recog, i, j, maxk, maxscore);
1405 pixaAddPix(pixarem, pix3, L_INSERT);
1406 }
1407 numaDestroy(&nascore);
1408 pixDestroy(&pix1);
1409 }
1410 }
1411
1412 if (ppixsave) {
1413 *ppixsave = pixDisplayOutliers(pixad, nasave);
1414 numaDestroy(&nasave);
1415 }
1416 if (ppixrem) {
1417 *ppixrem = pixaDisplayTiledInRows(pixarem, 32, 1500, 1.0, 0, 20, 2);
1418 pixaDestroy(&pixarem);
1419 }
1420
1421 numaDestroy(&nan);
1422 recogDestroy(&recog);
1423 return pixad;
1424}
1425
1426
1427/*------------------------------------------------------------------------*
1428 * Training on unlabeled data *
1429 *------------------------------------------------------------------------*/
1459PIXA *
1461 PIXA *pixas,
1462 l_float32 minscore,
1463 l_int32 threshold,
1464 l_int32 debug)
1465{
1466char *text;
1467l_int32 i, n, same, maxd, scaleh, linew;
1468l_float32 score;
1469PIX *pix1, *pix2, *pixdb = NULL;
1470PIXA *pixa1, *pixa2, *pixa3, *pixad;
1471
1472 if (!recogboot)
1473 return (PIXA *)ERROR_PTR("recogboot not defined", __func__, NULL);
1474 if (!pixas)
1475 return (PIXA *)ERROR_PTR("pixas not defined", __func__, NULL);
1476
1477 /* Make sure all input pix are 1 bpp */
1478 if ((n = pixaGetCount(pixas)) == 0)
1479 return (PIXA *)ERROR_PTR("no pix in pixa", __func__, NULL);
1480 pixaVerifyDepth(pixas, &same, &maxd);
1481 if (maxd == 1) {
1482 pixa1 = pixaCopy(pixas, L_COPY);
1483 } else {
1484 pixa1 = pixaCreate(n);
1485 for (i = 0; i < n; i++) {
1486 pix1 = pixaGetPix(pixas, i, L_CLONE);
1487 pix2 = pixConvertTo1(pix1, threshold);
1488 pixaAddPix(pixa1, pix2, L_INSERT);
1489 pixDestroy(&pix1);
1490 }
1491 }
1492
1493 /* Scale the input images to match the BSR */
1494 scaleh = recogboot->scaleh;
1495 linew = recogboot->linew;
1496 pixa2 = pixaCreate(n);
1497 for (i = 0; i < n; i++) {
1498 pix1 = pixaGetPix(pixa1, i, L_CLONE);
1499 pix2 = pixScaleToSize(pix1, 0, scaleh);
1500 pixaAddPix(pixa2, pix2, L_INSERT);
1501 pixDestroy(&pix1);
1502 }
1503 pixaDestroy(&pixa1);
1504
1505 /* Optionally convert to width-normalized line */
1506 if (linew > 0)
1507 pixa3 = pixaSetStrokeWidth(pixa2, linew, 4, 8);
1508 else
1509 pixa3 = pixaCopy(pixa2, L_CLONE);
1510 pixaDestroy(&pixa2);
1511
1512 /* Identify using recogboot */
1513 n = pixaGetCount(pixa3);
1514 pixad = pixaCreate(n);
1515 for (i = 0; i < n; i++) {
1516 pix1 = pixaGetPix(pixa3, i, L_COPY);
1517 pixSetText(pix1, NULL); /* remove any existing text or labelling */
1518 if (!debug) {
1519 recogIdentifyPix(recogboot, pix1, NULL);
1520 } else {
1521 recogIdentifyPix(recogboot, pix1, &pixdb);
1522 pixaAddPix(recogboot->pixadb_boot, pixdb, L_INSERT);
1523 }
1524 rchExtract(recogboot->rch, NULL, &score, &text, NULL, NULL, NULL, NULL);
1525 if (score >= minscore) {
1526 pix2 = pixaGetPix(pixas, i, L_COPY);
1527 pixSetText(pix2, text);
1528 pixaAddPix(pixad, pix2, L_INSERT);
1529 pixaAddPix(recogboot->pixadb_boot, pixdb, L_COPY);
1530 }
1531 LEPT_FREE(text);
1532 pixDestroy(&pix1);
1533 }
1534 pixaDestroy(&pixa3);
1535
1536 return pixad;
1537}
1538
1539
1540/*------------------------------------------------------------------------*
1541 * Padding the digit training set *
1542 *------------------------------------------------------------------------*/
1561l_ok
1563 l_int32 scaleh,
1564 l_int32 linew)
1565{
1566PIXA *pixa;
1567L_RECOG *recog1, *recog2;
1568SARRAY *sa;
1569
1570 if (!precog)
1571 return ERROR_INT("&recog not defined", __func__, 1);
1572 recog1 = *precog;
1573
1574 recogIsPaddingNeeded(recog1, &sa);
1575 if (!sa) return 0;
1576
1577 /* Get a new pixa with the padding templates added */
1578 pixa = recogAddDigitPadTemplates(recog1, sa);
1579 sarrayDestroy(&sa);
1580 if (!pixa)
1581 return ERROR_INT("pixa not made", __func__, 1);
1582
1583 /* Need to use templates that are scaled to a fixed height. */
1584 if (scaleh <= 0) {
1585 L_WARNING("templates must be scaled to fixed height; using %d\n",
1586 __func__, 40);
1587 scaleh = 40;
1588 }
1589
1590 /* Create a hybrid recog, composed of templates from both
1591 * the original and bootstrap sources. */
1592 recog2 = recogCreateFromPixa(pixa, 0, scaleh, linew, recog1->threshold,
1593 recog1->maxyshift);
1594 pixaDestroy(&pixa);
1595 recogDestroy(precog);
1596 *precog = recog2;
1597 return 0;
1598}
1599
1600
1617l_int32
1619 SARRAY **psa)
1620{
1621char *str;
1622l_int32 i, nt, min_nopad, nclass, allclasses;
1623l_float32 minval;
1624NUMA *naclass;
1625SARRAY *sa;
1626
1627 if (!psa)
1628 return ERROR_INT("&sa not defined", __func__, 1);
1629 *psa = NULL;
1630 if (!recog)
1631 return ERROR_INT("recog not defined", __func__, 1);
1632
1633 /* Do we have samples from all classes? */
1634 nclass = pixaaGetCount(recog->pixaa_u, &naclass); /* unscaled bitmaps */
1635 allclasses = (nclass == recog->charset_size) ? 1 : 0;
1636
1637 /* Are there enough samples in each class already? */
1638 min_nopad = recog->min_nopad;
1639 numaGetMin(naclass, &minval, NULL);
1640 if (allclasses && (minval >= min_nopad)) {
1641 numaDestroy(&naclass);
1642 return 0;
1643 }
1644
1645 /* Are any classes not represented? */
1646 sa = recogAddMissingClassStrings(recog);
1647 *psa = sa;
1648
1649 /* Are any other classes under-represented? */
1650 for (i = 0; i < nclass; i++) {
1651 numaGetIValue(naclass, i, &nt);
1652 if (nt < min_nopad) {
1653 str = sarrayGetString(recog->sa_text, i, L_COPY);
1654 sarrayAddString(sa, str, L_INSERT);
1655 }
1656 }
1657 numaDestroy(&naclass);
1658 return 0;
1659}
1660
1661
1674static SARRAY *
1676{
1677char *text;
1678char str[4];
1679l_int32 i, nclass, index, ival;
1680NUMA *na;
1681SARRAY *sa;
1682
1683 if (!recog)
1684 return (SARRAY *)ERROR_PTR("recog not defined", __func__, NULL);
1685
1686 /* Only handling digits */
1687 nclass = pixaaGetCount(recog->pixaa_u, NULL); /* unscaled bitmaps */
1688 if (recog->charset_type != 1 || nclass == 10)
1689 return sarrayCreate(0); /* empty */
1690
1691 /* Make an indicator array for missing classes */
1692 na = numaCreate(0);
1693 sa = sarrayCreate(0);
1694 for (i = 0; i < recog->charset_size; i++)
1695 numaAddNumber(na, 1);
1696 for (i = 0; i < nclass; i++) {
1697 text = sarrayGetString(recog->sa_text, i, L_NOCOPY);
1698 index = text[0] - '0';
1699 numaSetValue(na, index, 0);
1700 }
1701
1702 /* Convert to string and add to output */
1703 for (i = 0; i < nclass; i++) {
1704 numaGetIValue(na, i, &ival);
1705 if (ival == 1) {
1706 str[0] = '0' + i;
1707 str[1] = '\0';
1708 sarrayAddString(sa, str, L_COPY);
1709 }
1710 }
1711 numaDestroy(&na);
1712 return sa;
1713}
1714
1715
1731PIXA *
1733 SARRAY *sa)
1734{
1735char *str, *text;
1736l_int32 i, j, n, nt;
1737PIX *pix;
1738PIXA *pixa1, *pixa2;
1739
1740 if (!recog)
1741 return (PIXA *)ERROR_PTR("recog not defined", __func__, NULL);
1742 if (!sa)
1743 return (PIXA *)ERROR_PTR("sa not defined", __func__, NULL);
1744 if (recogCharsetAvailable(recog->charset_type) == FALSE)
1745 return (PIXA *)ERROR_PTR("boot charset not available", __func__, NULL);
1746
1747 /* Make boot recog templates */
1748 pixa1 = recogMakeBootDigitTemplates(0, 0);
1749 n = pixaGetCount(pixa1);
1750
1751 /* Extract the unscaled templates from %recog */
1752 pixa2 = recogExtractPixa(recog);
1753
1754 /* Add selected boot recog templates based on the text strings in sa */
1755 nt = sarrayGetCount(sa);
1756 for (i = 0; i < n; i++) {
1757 pix = pixaGetPix(pixa1, i, L_CLONE);
1758 text = pixGetText(pix);
1759 for (j = 0; j < nt; j++) {
1760 str = sarrayGetString(sa, j, L_NOCOPY);
1761 if (!strcmp(text, str)) {
1762 pixaAddPix(pixa2, pix, L_COPY);
1763 break;
1764 }
1765 }
1766 pixDestroy(&pix);
1767 }
1768
1769 pixaDestroy(&pixa1);
1770 return pixa2;
1771}
1772
1773
1780static l_int32
1782{
1783l_int32 ret;
1784
1785 switch (type)
1786 {
1787 case L_ARABIC_NUMERALS:
1788 ret = TRUE;
1789 break;
1792 case L_LC_ALPHA:
1793 case L_UC_ALPHA:
1794 L_INFO("charset type %d not available\n", __func__, type);
1795 ret = FALSE;
1796 break;
1797 default:
1798 L_INFO("charset type %d is unknown\n", __func__, type);
1799 ret = FALSE;
1800 break;
1801 }
1802
1803 return ret;
1804}
1805
1806
1807/*------------------------------------------------------------------------*
1808 * Making a boot digit recognizer *
1809 *------------------------------------------------------------------------*/
1839L_RECOG *
1841 l_int32 scaleh,
1842 l_int32 linew,
1843 l_int32 maxyshift,
1844 l_int32 debug)
1845
1846{
1847PIXA *pixa;
1848L_RECOG *recog;
1849
1850 /* Get the templates, extended by horizontal scaling */
1851 pixa = recogMakeBootDigitTemplates(nsamp, debug);
1852
1853 /* Make the boot recog; recogModifyTemplate() will scale the
1854 * templates and optionally turn them into strokes of fixed width. */
1855 recog = recogCreateFromPixa(pixa, 0, scaleh, linew, 128, maxyshift);
1856 pixaDestroy(&pixa);
1857 if (debug)
1858 recogShowContent(stderr, recog, 0, 1);
1859
1860 return recog;
1861}
1862
1863
1876PIXA *
1878 l_int32 debug)
1879{
1880NUMA *na1;
1881PIX *pix1, *pix2, *pix3;
1882PIXA *pixa1, *pixa2, *pixa3;
1883
1884 if (nsamp > 0) {
1885 pixa1 = l_bootnum_gen4(nsamp);
1886 if (debug) {
1887 pix1 = pixaDisplayTiledWithText(pixa1, 1500, 1.0, 10,
1888 2, 6, 0xff000000);
1889 pixDisplay(pix1, 0, 0);
1890 pixDestroy(&pix1);
1891 }
1892 return pixa1;
1893 }
1894
1895 /* Else, generate from 3 pixa */
1896 pixa1 = l_bootnum_gen1();
1897 pixa2 = l_bootnum_gen2();
1898 pixa3 = l_bootnum_gen3();
1899 if (debug) {
1900 pix1 = pixaDisplayTiledWithText(pixa1, 1500, 1.0, 10, 2, 6, 0xff000000);
1901 pix2 = pixaDisplayTiledWithText(pixa2, 1500, 1.0, 10, 2, 6, 0xff000000);
1902 pix3 = pixaDisplayTiledWithText(pixa3, 1500, 1.0, 10, 2, 6, 0xff000000);
1903 pixDisplay(pix1, 0, 0);
1904 pixDisplay(pix2, 600, 0);
1905 pixDisplay(pix3, 1200, 0);
1906 pixDestroy(&pix1);
1907 pixDestroy(&pix2);
1908 pixDestroy(&pix3);
1909 }
1910 pixaJoin(pixa1, pixa2, 0, -1);
1911 pixaJoin(pixa1, pixa3, 0, -1);
1912 pixaDestroy(&pixa2);
1913 pixaDestroy(&pixa3);
1914
1915 /* Extend by horizontal scaling */
1916 na1 = numaCreate(4);
1917 numaAddNumber(na1, 0.9f);
1918 numaAddNumber(na1, 1.1f);
1919 numaAddNumber(na1, 1.2f);
1920 pixa2 = pixaExtendByScaling(pixa1, na1, L_HORIZ, 1);
1921
1922 pixaDestroy(&pixa1);
1923 numaDestroy(&na1);
1924 return pixa2;
1925}
1926
1927
1928/*------------------------------------------------------------------------*
1929 * Debugging *
1930 *------------------------------------------------------------------------*/
1940l_ok
1942 L_RECOG *recog,
1943 l_int32 index,
1944 l_int32 display)
1945{
1946char buf[128];
1947l_int32 i, val, count;
1948PIX *pix;
1949NUMA *na;
1950
1951 if (!fp)
1952 return ERROR_INT("stream not defined", __func__, 1);
1953 if (!recog)
1954 return ERROR_INT("recog not defined", __func__, 1);
1955
1956 fprintf(fp, "Debug print of recog contents\n");
1957 fprintf(fp, " Setsize: %d\n", recog->setsize);
1958 fprintf(fp, " Binarization threshold: %d\n", recog->threshold);
1959 fprintf(fp, " Maximum matching y-jiggle: %d\n", recog->maxyshift);
1960 if (recog->linew <= 0)
1961 fprintf(fp, " Using image templates for matching\n");
1962 else
1963 fprintf(fp, " Using templates with fixed line width for matching\n");
1964 if (recog->scalew == 0)
1965 fprintf(fp, " No width scaling of templates\n");
1966 else
1967 fprintf(fp, " Template width scaled to %d\n", recog->scalew);
1968 if (recog->scaleh == 0)
1969 fprintf(fp, " No height scaling of templates\n");
1970 else
1971 fprintf(fp, " Template height scaled to %d\n", recog->scaleh);
1972 fprintf(fp, " Number of samples in each class:\n");
1973 pixaaGetCount(recog->pixaa_u, &na);
1974 for (i = 0; i < recog->setsize; i++) {
1975 l_dnaGetIValue(recog->dna_tochar, i, &val);
1976 numaGetIValue(na, i, &count);
1977 if (val < 128)
1978 fprintf(fp, " class %d, char %c: %d\n", i, val, count);
1979 else
1980 fprintf(fp, " class %d, val %d: %d\n", i, val, count);
1981 }
1982 numaDestroy(&na);
1983
1984 if (display) {
1985 lept_mkdir("lept/recog");
1986 pix = pixaaDisplayByPixa(recog->pixaa_u, 50, 1.0, 20, 20, 0);
1987 snprintf(buf, sizeof(buf), "/tmp/lept/recog/templates_u.%d.png", index);
1988 pixWriteDebug(buf, pix, IFF_PNG);
1989 pixDisplay(pix, 0, 200 * index);
1990 pixDestroy(&pix);
1991 if (recog->train_done) {
1992 pix = pixaaDisplayByPixa(recog->pixaa, 50, 1.0, 20, 20, 0);
1993 snprintf(buf, sizeof(buf),
1994 "/tmp/lept/recog/templates.%d.png", index);
1995 pixWriteDebug(buf, pix, IFF_PNG);
1996 pixDisplay(pix, 800, 200 * index);
1997 pixDestroy(&pix);
1998 }
1999 }
2000 return 0;
2001}
2002
2003
2021l_ok
2023 l_int32 debug)
2024{
2025l_int32 i, j, n, np, index;
2026l_float32 score;
2027PIX *pix1, *pix2, *pix3;
2028PIXA *pixa, *pixat;
2029PIXAA *paa1, *paa2;
2030
2031 if (!recog)
2032 return ERROR_INT("recog not defined", __func__, 1);
2033
2034 /* Mark the training as finished if necessary, and make sure
2035 * that the average templates have been built. */
2036 if (recogAverageSamples(recog, 0) != 0)
2037 return ERROR_INT("averaging failed", __func__, 1);
2038
2039 /* Save a pixa of all the training examples */
2040 paa1 = recog->pixaa;
2041 if (!recog->pixa_tr)
2042 recog->pixa_tr = pixaaFlattenToPixa(paa1, NULL, L_CLONE);
2043
2044 /* Destroy any existing image and make a new one */
2045 if (recog->pixdb_ave)
2046 pixDestroy(&recog->pixdb_ave);
2047 n = pixaaGetCount(paa1, NULL);
2048 paa2 = pixaaCreate(n);
2049 for (i = 0; i < n; i++) {
2050 pixa = pixaCreate(0);
2051 pixat = pixaaGetPixa(paa1, i, L_CLONE);
2052 np = pixaGetCount(pixat);
2053 for (j = 0; j < np; j++) {
2054 pix1 = pixaaGetPix(paa1, i, j, L_CLONE);
2055 recogIdentifyPix(recog, pix1, &pix2);
2056 rchExtract(recog->rch, &index, &score, NULL, NULL, NULL,
2057 NULL, NULL);
2058 if (debug >= 2)
2059 lept_stderr("index = %d, score = %7.3f\n", index, score);
2060 pix3 = pixAddBorder(pix2, 2, 1);
2061 pixaAddPix(pixa, pix3, L_INSERT);
2062 pixDestroy(&pix1);
2063 pixDestroy(&pix2);
2064 }
2065 pixaaAddPixa(paa2, pixa, L_INSERT);
2066 pixaDestroy(&pixat);
2067 }
2068 recog->pixdb_ave = pixaaDisplayByPixa(paa2, 50, 1.0, 20, 20, 0);
2069 if (debug % 2) {
2070 lept_mkdir("lept/recog");
2071 pixWriteDebug("/tmp/lept/recog/templ_match.png", recog->pixdb_ave,
2072 IFF_PNG);
2073 pixDisplay(recog->pixdb_ave, 100, 100);
2074 }
2075
2076 pixaaDestroy(&paa2);
2077 return 0;
2078}
2079
2080
2093l_int32
2095{
2096l_int32 i, size;
2097l_float32 x, y;
2098PIX *pix1, *pix2, *pixr;
2099PIXA *pixat, *pixadb;
2100
2101 if (!recog)
2102 return ERROR_INT("recog not defined", __func__, 1);
2103
2104 lept_stderr("min/max width_u = (%d,%d); min/max height_u = (%d,%d)\n",
2105 recog->minwidth_u, recog->maxwidth_u,
2106 recog->minheight_u, recog->maxheight_u);
2107 lept_stderr("min splitw = %d, max splith = %d\n",
2108 recog->min_splitw, recog->max_splith);
2109
2110 pixaDestroy(&recog->pixadb_ave);
2111
2112 pixr = pixCreate(3, 3, 32); /* 3x3 red square for centroid location */
2113 pixSetAllArbitrary(pixr, 0xff000000);
2114 pixadb = pixaCreate(2);
2115
2116 /* Unscaled bitmaps */
2117 size = recog->setsize;
2118 pixat = pixaCreate(size);
2119 for (i = 0; i < size; i++) {
2120 if ((pix1 = pixaGetPix(recog->pixa_u, i, L_CLONE)) == NULL)
2121 continue;
2122 pix2 = pixConvertTo32(pix1);
2123 ptaGetPt(recog->pta_u, i, &x, &y);
2124 pixRasterop(pix2, (l_int32)(x - 0.5), (l_int32)(y - 0.5), 3, 3,
2125 PIX_SRC, pixr, 0, 0);
2126 pixaAddPix(pixat, pix2, L_INSERT);
2127 pixDestroy(&pix1);
2128 }
2129 pix1 = pixaDisplayTiledInRows(pixat, 32, 3000, 1.0, 0, 20, 0);
2130 pixaAddPix(pixadb, pix1, L_INSERT);
2131 pixDisplay(pix1, 100, 100);
2132 pixaDestroy(&pixat);
2133
2134 /* Scaled bitmaps */
2135 pixat = pixaCreate(size);
2136 for (i = 0; i < size; i++) {
2137 if ((pix1 = pixaGetPix(recog->pixa, i, L_CLONE)) == NULL)
2138 continue;
2139 pix2 = pixConvertTo32(pix1);
2140 ptaGetPt(recog->pta, i, &x, &y);
2141 pixRasterop(pix2, (l_int32)(x - 0.5), (l_int32)(y - 0.5), 3, 3,
2142 PIX_SRC, pixr, 0, 0);
2143 pixaAddPix(pixat, pix2, L_INSERT);
2144 pixDestroy(&pix1);
2145 }
2146 pix1 = pixaDisplayTiledInRows(pixat, 32, 3000, 1.0, 0, 20, 0);
2147 pixaAddPix(pixadb, pix1, L_INSERT);
2148 pixDisplay(pix1, 100, 100);
2149 pixaDestroy(&pixat);
2150 pixDestroy(&pixr);
2151 recog->pixadb_ave = pixadb;
2152 return 0;
2153}
2154
2155
2169static PIX *
2171 NUMA *nas)
2172{
2173char *text;
2174char buf[16];
2175l_int32 i, n;
2176l_float32 fval;
2177PIX *pix1, *pix2;
2178PIXA *pixa1;
2179
2180 if (!pixas)
2181 return (PIX *)ERROR_PTR("pixas not defined", __func__, NULL);
2182 if (!nas)
2183 return (PIX *)ERROR_PTR("nas not defined", __func__, NULL);
2184 n = pixaGetCount(pixas);
2185 if (numaGetCount(nas) != n)
2186 return (PIX *)ERROR_PTR("pixas and nas sizes differ", __func__, NULL);
2187
2188 pixa1 = pixaCreate(n);
2189 for (i = 0; i < n; i++) {
2190 pix1 = pixaGetPix(pixas, i, L_CLONE);
2191 pix2 = pixAddBlackOrWhiteBorder(pix1, 25, 25, 0, 0, L_GET_WHITE_VAL);
2192 text = pixGetText(pix1);
2193 numaGetFValue(nas, i, &fval);
2194 snprintf(buf, sizeof(buf), "'%s': %5.2f", text, fval);
2195 pixSetText(pix2, buf);
2196 pixaAddPix(pixa1, pix2, L_INSERT);
2197 pixDestroy(&pix1);
2198 }
2199 pix1 = pixaDisplayTiledWithText(pixa1, 1500, 1.0, 20, 2, 6, 0xff000000);
2200 pixaDestroy(&pixa1);
2201 return pix1;
2202}
2203
2204
2223static PIX *
2225 l_int32 iclass,
2226 l_int32 jsamp,
2227 l_int32 maxclass,
2228 l_float32 maxscore)
2229{
2230char buf[64];
2231PIX *pix1, *pix2, *pix3, *pix4, *pix5;
2232PIXA *pixa;
2233
2234 if (!recog)
2235 return (PIX *)ERROR_PTR("recog not defined", __func__, NULL);
2236
2237 pix1 = pixaaGetPix(recog->pixaa, iclass, jsamp, L_CLONE);
2238 pix2 = pixaGetPix(recog->pixa, iclass, L_CLONE);
2239 pix3 = pixaGetPix(recog->pixa, maxclass, L_CLONE);
2240 pixa = pixaCreate(3);
2241 pixaAddPix(pixa, pix1, L_INSERT);
2242 pixaAddPix(pixa, pix2, L_INSERT);
2243 pixaAddPix(pixa, pix3, L_INSERT);
2244 pix4 = pixaDisplayTiledInRows(pixa, 32, 400, 2.0, 0, 12, 2);
2245 snprintf(buf, sizeof(buf), "C=%d, BAC=%d, S=%4.2f", iclass, maxclass,
2246 maxscore);
2247 pix5 = pixAddSingleTextblock(pix4, recog->bmf, buf, 0xff000000,
2248 L_ADD_BELOW, NULL);
2249 pixDestroy(&pix4);
2250 pixaDestroy(&pixa);
2251 return pix5;
2252}
2253
2254
2276l_ok
2278 PIXA *pixa,
2279 l_float32 minscore,
2280 l_float32 maxscore,
2281 l_int32 display)
2282{
2283l_int32 i, n, index, depth;
2284l_float32 score;
2285NUMA *nascore, *naindex;
2286PIX *pix1, *pix2;
2287PIXA *pixa1, *pixa2;
2288
2289 if (!recog)
2290 return ERROR_INT("recog not defined", __func__, 1);
2291 if (!pixa)
2292 return ERROR_INT("pixa not defined", __func__, 1);
2293
2294 /* Run the recognizer on the set of images */
2295 n = pixaGetCount(pixa);
2296 nascore = numaCreate(n);
2297 naindex = numaCreate(n);
2298 pixa1 = pixaCreate(n);
2299 for (i = 0; i < n; i++) {
2300 pix1 = pixaGetPix(pixa, i, L_CLONE);
2301 recogIdentifyPix(recog, pix1, &pix2);
2302 rchExtract(recog->rch, &index, &score, NULL, NULL, NULL, NULL, NULL);
2303 numaAddNumber(nascore, score);
2304 numaAddNumber(naindex, index);
2305 pixaAddPix(pixa1, pix2, L_INSERT);
2306 pixDestroy(&pix1);
2307 }
2308
2309 /* Filter the set and optionally add text to each */
2310 pixa2 = pixaCreate(n);
2311 depth = 1;
2312 for (i = 0; i < n; i++) {
2313 numaGetFValue(nascore, i, &score);
2314 if (score < minscore || score > maxscore) continue;
2315 pix1 = pixaGetPix(pixa1, i, L_CLONE);
2316 numaGetIValue(naindex, i, &index);
2317 pix2 = recogShowMatch(recog, pix1, NULL, NULL, index, score);
2318 if (i == 0) depth = pixGetDepth(pix2);
2319 pixaAddPix(pixa2, pix2, L_INSERT);
2320 pixDestroy(&pix1);
2321 }
2322
2323 /* Package it up */
2324 pixDestroy(&recog->pixdb_range);
2325 if (pixaGetCount(pixa2) > 0) {
2326 recog->pixdb_range =
2327 pixaDisplayTiledInRows(pixa2, depth, 2500, 1.0, 0, 20, 1);
2328 if (display)
2329 pixDisplay(recog->pixdb_range, 300, 100);
2330 } else {
2331 L_INFO("no character matches in the range of scores\n", __func__);
2332 }
2333
2334 pixaDestroy(&pixa1);
2335 pixaDestroy(&pixa2);
2336 numaDestroy(&nascore);
2337 numaDestroy(&naindex);
2338 return 0;
2339}
2340
2341
2368PIX *
2370 PIX *pix1,
2371 PIX *pix2,
2372 BOX *box,
2373 l_int32 index,
2374 l_float32 score)
2375{
2376char buf[32];
2377char *text;
2378L_BMF *bmf;
2379PIX *pix3, *pix4, *pix5, *pixd;
2380PIXA *pixa;
2381
2382 if (!recog)
2383 return (PIX *)ERROR_PTR("recog not defined", __func__, NULL);
2384 if (!pix1)
2385 return (PIX *)ERROR_PTR("pix1 not defined", __func__, NULL);
2386
2387 bmf = (recog->bmf && index >= 0) ? recog->bmf : NULL;
2388 if (!pix2 && !box && !bmf) /* nothing to do */
2389 return pixCopy(NULL, pix1);
2390
2391 pix3 = pixConvertTo32(pix1);
2392 if (box)
2393 pixRenderBoxArb(pix3, box, 1, 255, 0, 0);
2394
2395 if (pix2) {
2396 pixa = pixaCreate(2);
2397 pixaAddPix(pixa, pix3, L_CLONE);
2398 pixaAddPix(pixa, pix2, L_CLONE);
2399 pix4 = pixaDisplayTiledInRows(pixa, 1, 500, 1.0, 0, 15, 0);
2400 pixaDestroy(&pixa);
2401 } else {
2402 pix4 = pixCopy(NULL, pix3);
2403 }
2404 pixDestroy(&pix3);
2405
2406 if (bmf) {
2407 pix5 = pixAddBorderGeneral(pix4, 55, 55, 0, 0, 0xffffff00);
2408 recogGetClassString(recog, index, &text);
2409 snprintf(buf, sizeof(buf), "C=%s, S=%4.3f, I=%d", text, score, index);
2410 pixd = pixAddSingleTextblock(pix5, bmf, buf, 0xff000000,
2411 L_ADD_BELOW, NULL);
2412 pixDestroy(&pix5);
2413 LEPT_FREE(text);
2414 } else {
2415 pixd = pixClone(pix4);
2416 }
2417 pixDestroy(&pix4);
2418
2419 return pixd;
2420}
@ L_SORT_BY_HEIGHT
Definition pix.h:533
@ L_ADD_BELOW
Definition pix.h:1003
@ L_COPY
Definition pix.h:505
@ L_CLONE
Definition pix.h:506
@ L_NOCOPY
Definition pix.h:503
@ L_INSERT
Definition pix.h:504
#define PIX_SRC
Definition pix.h:444
@ L_SORT_INCREASING
Definition pix.h:522
@ L_GET_WHITE_VAL
Definition pix.h:708
@ L_LC_ALPHA
Definition recog.h:250
@ L_ARABIC_NUMERALS
Definition recog.h:247
@ L_UC_ALPHA
Definition recog.h:251
@ L_LC_ROMAN_NUMERALS
Definition recog.h:248
@ L_UC_ROMAN_NUMERALS
Definition recog.h:249
l_ok recogProcessLabeled(L_RECOG *recog, PIX *pixs, BOX *box, char *text, PIX **ppix)
recogProcessLabeled()
Definition recogtrain.c:264
l_int32 recogIsPaddingNeeded(L_RECOG *recog, SARRAY **psa)
recogIsPaddingNeeded()
l_ok recogPadDigitTrainingSet(L_RECOG **precog, l_int32 scaleh, l_int32 linew)
recogPadDigitTrainingSet()
l_int32 recogShowAverageTemplates(L_RECOG *recog)
recogShowAverageTemplates()
l_int32 pixaAccumulateSamples(PIXA *pixa, PTA *pta, PIX **ppixd, l_float32 *px, l_float32 *py)
pixaAccumulateSamples()
Definition recogtrain.c:652
l_ok recogShowMatchesInRange(L_RECOG *recog, PIXA *pixa, l_float32 minscore, l_float32 maxscore, l_int32 display)
recogShowMatchesInRange()
static PIX * pixDisplayOutliers(PIXA *pixas, NUMA *nas)
pixDisplayOutliers()
PIX * recogShowMatch(L_RECOG *recog, PIX *pix1, PIX *pix2, BOX *box, l_int32 index, l_float32 score)
recogShowMatch()
l_ok recogTrainingFinished(L_RECOG **precog, l_int32 modifyflag, l_int32 minsize, l_float32 minfract)
recogTrainingFinished()
Definition recogtrain.c:769
PIX * recogModifyTemplate(L_RECOG *recog, PIX *pixs)
recogModifyTemplate()
Definition recogtrain.c:416
PIXA * recogFilterPixaBySize(PIXA *pixas, l_int32 setsize, l_int32 maxkeep, l_float32 max_ht_ratio, NUMA **pna)
recogFilterPixaBySize()
Definition recogtrain.c:952
PIXA * pixaRemoveOutliers2(PIXA *pixas, l_float32 minscore, l_int32 minsize, PIX **ppixsave, PIX **ppixrem)
pixaRemoveOutliers2()
l_ok recogTrainLabeled(L_RECOG *recog, PIX *pixs, BOX *box, char *text, l_int32 debug)
recogTrainLabeled()
Definition recogtrain.c:217
l_ok recogRemoveOutliers1(L_RECOG **precog, l_float32 minscore, l_int32 mintarget, l_int32 minsize, PIX **ppixsave, PIX **ppixrem)
recogRemoveOutliers1()
L_RECOG * recogMakeBootDigitRecog(l_int32 nsamp, l_int32 scaleh, l_int32 linew, l_int32 maxyshift, l_int32 debug)
recogMakeBootDigitRecog()
static PIX * recogDisplayOutlier(L_RECOG *recog, l_int32 iclass, l_int32 jsamp, l_int32 maxclass, l_float32 maxscore)
recogDisplayOutlier()
l_int32 recogAverageSamples(L_RECOG *recog, l_int32 debug)
recogAverageSamples()
Definition recogtrain.c:484
l_ok recogRemoveOutliers2(L_RECOG **precog, l_float32 minscore, l_int32 minsize, PIX **ppixsave, PIX **ppixrem)
recogRemoveOutliers2()
l_ok recogShowContent(FILE *fp, L_RECOG *recog, l_int32 index, l_int32 display)
recogShowContent()
l_ok recogAddSample(L_RECOG *recog, PIX *pix, l_int32 debug)
recogAddSample()
Definition recogtrain.c:353
static l_int32 recogTemplatesAreOK(L_RECOG *recog, l_int32 minsize, l_float32 minfract, l_int32 *pok)
recogTemplatesAreOK()
Definition recogtrain.c:892
static SARRAY * recogAddMissingClassStrings(L_RECOG *recog)
recogAddMissingClassStrings()
static l_int32 recogCharsetAvailable(l_int32 type)
recogCharsetAvailable()
PIXA * recogAddDigitPadTemplates(L_RECOG *recog, SARRAY *sa)
recogAddDigitPadTemplates()
PIXA * recogTrainFromBoot(L_RECOG *recogboot, PIXA *pixas, l_float32 minscore, l_int32 threshold, l_int32 debug)
recogTrainFromBoot()
PIXAA * recogSortPixaByClass(PIXA *pixa, l_int32 setsize)
recogSortPixaByClass()
PIXA * recogMakeBootDigitTemplates(l_int32 nsamp, l_int32 debug)
recogMakeBootDigitTemplates()
l_ok recogDebugAverages(L_RECOG *recog, l_int32 debug)
recogDebugAverages()
PIXA * pixaRemoveOutliers1(PIXA *pixas, l_float32 minscore, l_int32 mintarget, l_int32 minsize, PIX **ppixsave, PIX **ppixrem)
pixaRemoveOutliers1()
Definition bmf.h:47
l_int32 charset_size
Definition recog.h:132
struct Numa * nasum
Definition recog.h:163
struct L_Dna * dna_tochar
Definition recog.h:149
l_int32 ave_done
Definition recog.h:141
l_int32 maxwidth
Definition recog.h:140
l_int32 num_samples
Definition recog.h:134
l_int32 * centtab
Definition recog.h:150
l_int32 min_nopad
Definition recog.h:133
struct L_Rch * rch
Definition recog.h:174
struct Pixa * pixa_u
Definition recog.h:158
l_int32 train_done
Definition recog.h:142
l_int32 maxwidth_u
Definition recog.h:136
struct Pta * pta_u
Definition recog.h:159
struct Ptaa * ptaa_u
Definition recog.h:153
l_int32 maxyshift
Definition recog.h:129
l_int32 linew
Definition recog.h:121
struct Numaa * naasum_u
Definition recog.h:154
l_int32 scalew
Definition recog.h:117
struct Ptaa * ptaa
Definition recog.h:156
l_int32 maxheight_u
Definition recog.h:138
l_int32 min_splitw
Definition recog.h:146
l_float32 max_ht_ratio
Definition recog.h:145
struct Pixa * pixadb_ave
Definition recog.h:165
l_int32 minwidth
Definition recog.h:139
l_int32 minheight_u
Definition recog.h:137
struct Pixa * pixa_tr
Definition recog.h:164
l_int32 threshold
Definition recog.h:128
struct Numa * nasum_u
Definition recog.h:160
l_int32 scaleh
Definition recog.h:119
l_int32 max_splith
Definition recog.h:147
struct Pix * pixdb_range
Definition recog.h:168
l_int32 * sumtab
Definition recog.h:151
struct Pix * pixdb_ave
Definition recog.h:167
struct Pta * pta
Definition recog.h:162
l_int32 minwidth_u
Definition recog.h:135
l_int32 charset_type
Definition recog.h:131
struct Numaa * naasum
Definition recog.h:157
struct Pixaa * pixaa_u
Definition recog.h:152
l_int32 setsize
Definition recog.h:127
struct Sarray * sa_text
Definition recog.h:148
struct L_Bmf * bmf
Definition recog.h:171
struct Pixa * pixadb_boot
Definition recog.h:169
struct Pixaa * pixaa
Definition recog.h:155
struct Pixa * pixa
Definition recog.h:161
l_int32 maxarraysize
Definition recog.h:126
char * text