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 */
169static l_int32 recogTemplatesAreOK(L_RECOG *recog, l_int32 minsize,
170 l_float32 minfract, l_int32 *pok);
172static l_int32 recogCharsetAvailable(l_int32 type);
173static PIX *pixDisplayOutliers(PIXA *pixas, NUMA *nas);
174static 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. */
181static const l_int32 DefaultMinSetSize = 1; /* minimum number of
182 samples for a valid class */
183static const l_float32 DefaultMinSetFract = 0.4; /* minimum fraction
184 of classes required for a valid recog */
185
186 /* Defaults in pixaRemoveOutliers1() and pixaRemoveOutliers2() */
187static const l_float32 DefaultMinScore = 0.75; /* keep everything above */
188static const l_int32 DefaultMinTarget = 3; /* to be kept if possible */
189static 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 *------------------------------------------------------------------------*/
215l_ok
217 PIX *pixs,
218 BOX *box,
219 char *text,
220 l_int32 debug)
221{
222l_int32 ret;
223PIX *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
264l_ok
266 PIX *pixs,
267 BOX *box,
268 char *text,
269 PIX **ppix)
270{
271char *textdata;
272l_int32 textinpix, textin, nsets;
273NUMA *na;
274PIX *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
355l_ok
357 PIX *pix,
358 l_int32 debug)
359{
360char *text;
361l_int32 npa, charint, index;
362PIXA *pixa1;
363PIXAA *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
420PIX *
422 PIX *pixs)
423{
424l_int32 w, h, empty;
425PIX *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
489l_int32
491 l_int32 debug)
492{
493l_int32 i, nsamp, size, area, bx, by, badclass;
494l_float32 x, y, hratio;
495BOX *box;
496PIXA *pixa1;
497PIX *pix1, *pix2, *pix3;
498PTA *pta1;
499L_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
667l_int32
669 PTA *pta,
670 PIX **ppixd,
671 l_float32 *px,
672 l_float32 *py)
673{
674l_int32 i, n, maxw, maxh, xdiff, ydiff;
675l_int32 *centtab, *sumtab;
676l_float32 xc, yc, xave, yave;
677PIX *pix1, *pix2, *pixsum;
678PTA *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
786l_ok
788 l_int32 modifyflag,
789 l_int32 minsize,
790 l_float32 minfract)
791{
792l_int32 ok, i, j, size, nc, ns, area;
793l_float32 xave, yave;
794PIX *pix, *pixd;
795PIXA *pixa;
796PIXAA *paa;
797PTA *pta;
798PTAA *ptaa;
799L_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
911static l_int32
913 l_int32 minsize,
914 l_float32 minfract,
915 l_int32 *pok)
916{
917l_int32 i, n, validsets, nt;
918l_float32 ratio;
919NUMA *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
973PIXA *
975 l_int32 setsize,
976 l_int32 maxkeep,
977 l_float32 max_ht_ratio,
978 NUMA **pna)
979{
980l_int32 i, j, h90, hj, j1, j2, j90, n, nc;
981l_float32 ratio;
982NUMA *na;
983PIXA *pixa1, *pixa2, *pixa3, *pixa4, *pixa5;
984PIXAA *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
1044PIXAA *
1046 l_int32 setsize)
1047{
1048PIXAA *paa;
1049L_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
1084l_ok
1086 l_float32 minscore,
1087 l_int32 mintarget,
1088 l_int32 minsize,
1089 PIX **ppixsave,
1090 PIX **ppixrem)
1091{
1092PIXA *pixa1, *pixa2;
1093L_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
1162PIXA *
1164 l_float32 minscore,
1165 l_int32 mintarget,
1166 l_int32 minsize,
1167 PIX **ppixsave,
1168 PIX **ppixrem)
1169{
1170l_int32 i, j, debug, n, area1, area2;
1171l_float32 x1, y1, x2, y2, minfract, score, rankscore, threshscore;
1172NUMA *nasum, *narem, *nasave, *nascore;
1173PIX *pix1, *pix2;
1174PIXA *pixa, *pixarem, *pixad;
1175PTA *pta;
1176L_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
1302l_ok
1304 l_float32 minscore,
1305 l_int32 minsize,
1306 PIX **ppixsave,
1307 PIX **ppixrem)
1308{
1309PIXA *pixa1, *pixa2;
1310L_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
1366PIXA *
1368 l_float32 minscore,
1369 l_int32 minsize,
1370 PIX **ppixsave,
1371 PIX **ppixrem)
1372{
1373l_int32 i, j, k, n, area1, area2, maxk, debug;
1374l_float32 x1, y1, x2, y2, score, maxscore;
1375NUMA *nan, *nascore, *nasave;
1376PIX *pix1, *pix2, *pix3;
1377PIXA *pixarem, *pixad;
1378L_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 *------------------------------------------------------------------------*/
1491PIXA *
1493 PIXA *pixas,
1494 l_float32 minscore,
1495 l_int32 threshold,
1496 l_int32 debug)
1497{
1498char *text;
1499l_int32 i, n, same, maxd, scaleh, linew;
1500l_float32 score;
1501PIX *pix1, *pix2, *pixdb;
1502PIXA *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 *------------------------------------------------------------------------*/
1595l_ok
1597 l_int32 scaleh,
1598 l_int32 linew)
1599{
1600PIXA *pixa;
1601L_RECOG *recog1, *recog2;
1602SARRAY *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
1653l_int32
1655 SARRAY **psa)
1656{
1657char *str;
1658l_int32 i, nt, min_nopad, nclass, allclasses;
1659l_float32 minval;
1660NUMA *naclass;
1661SARRAY *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
1712static SARRAY *
1714{
1715char *text;
1716char str[4];
1717l_int32 i, nclass, index, ival;
1718NUMA *na;
1719SARRAY *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
1771PIXA *
1773 SARRAY *sa)
1774{
1775char *str, *text;
1776l_int32 i, j, n, nt;
1777PIX *pix;
1778PIXA *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
1822static l_int32
1824{
1825l_int32 ret;
1826
1827 PROCNAME("recogCharsetAvailable");
1828
1829 switch (type)
1830 {
1831 case L_ARABIC_NUMERALS:
1832 ret = TRUE;
1833 break;
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 *------------------------------------------------------------------------*/
1883L_RECOG *
1885 l_int32 scaleh,
1886 l_int32 linew,
1887 l_int32 maxyshift,
1888 l_int32 debug)
1889
1890{
1891PIXA *pixa;
1892L_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
1920PIXA *
1922 l_int32 debug)
1923{
1924NUMA *na1;
1925PIX *pix1, *pix2, *pix3;
1926PIXA *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 *------------------------------------------------------------------------*/
1984l_ok
1986 L_RECOG *recog,
1987 l_int32 index,
1988 l_int32 display)
1989{
1990char buf[128];
1991l_int32 i, val, count;
1992PIX *pix;
1993NUMA *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
2067l_ok
2069 l_int32 debug)
2070{
2071l_int32 i, j, n, np, index;
2072l_float32 score;
2073PIX *pix1, *pix2, *pix3;
2074PIXA *pixa, *pixat;
2075PIXAA *paa1, *paa2;
2076L_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
2145l_int32
2147{
2148l_int32 i, size;
2149l_float32 x, y;
2150PIX *pix1, *pix2, *pixr;
2151PIXA *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
2223static PIX *
2225 NUMA *nas)
2226{
2227char *text;
2228char buf[16];
2229l_int32 i, n;
2230l_float32 fval;
2231PIX *pix1, *pix2;
2232PIXA *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
2279static PIX *
2281 l_int32 iclass,
2282 l_int32 jsamp,
2283 l_int32 maxclass,
2284 l_float32 maxscore)
2285{
2286char buf[64];
2287PIX *pix1, *pix2, *pix3, *pix4, *pix5;
2288PIXA *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
2334l_ok
2336 PIXA *pixa,
2337 l_float32 minscore,
2338 l_float32 maxscore,
2339 l_int32 display)
2340{
2341l_int32 i, n, index, depth;
2342l_float32 score;
2343NUMA *nascore, *naindex;
2344PIX *pix1, *pix2;
2345PIXA *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
2428PIX *
2430 PIX *pix1,
2431 PIX *pix2,
2432 BOX *box,
2433 l_int32 index,
2434 l_float32 score)
2435{
2436char buf[32];
2437char *text;
2438L_BMF *bmf;
2439PIX *pix3, *pix4, *pix5, *pixd;
2440PIXA *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}
PIXA * l_bootnum_gen1(void)
l_bootnum_gen1()
Definition: bootnumgen1.c:294
PIXA * l_bootnum_gen2(void)
l_bootnum_gen2()
Definition: bootnumgen2.c:277
PIXA * l_bootnum_gen4(l_int32 nsamp)
l_bootnum_gen4()
Definition: bootnumgen4.c:797
void boxDestroy(BOX **pbox)
boxDestroy()
Definition: boxbasic.c:282
l_ok boxGetGeometry(BOX *box, l_int32 *px, l_int32 *py, l_int32 *pw, l_int32 *ph)
boxGetGeometry()
Definition: boxbasic.c:313
l_ok l_dnaGetIValue(L_DNA *da, l_int32 index, l_int32 *pival)
l_dnaGetIValue()
Definition: dnabasic.c:727
l_ok pixRenderBoxArb(PIX *pix, BOX *box, l_int32 width, l_uint8 rval, l_uint8 gval, l_uint8 bval)
pixRenderBoxArb()
Definition: graphics.c:1655
PIX * pixThresholdToBinary(PIX *pixs, l_int32 thresh)
pixThresholdToBinary()
Definition: grayquant.c:447
PIXA * pixaExtendByScaling(PIXA *pixas, NUMA *nasc, l_int32 type, l_int32 include)
pixaExtendByScaling()
Definition: morphapp.c:976
l_ok pixCentroid(PIX *pix, l_int32 *centtab, l_int32 *sumtab, l_float32 *pxave, l_float32 *pyave)
pixCentroid()
Definition: morphapp.c:1533
PIX * pixMorphSequence(PIX *pixs, const char *sequence, l_int32 dispsep)
pixMorphSequence()
Definition: morphseq.c:137
l_ok numaAddNumber(NUMA *na, l_float32 val)
numaAddNumber()
Definition: numabasic.c:478
l_ok numaGetFValue(NUMA *na, l_int32 index, l_float32 *pval)
numaGetFValue()
Definition: numabasic.c:719
NUMA * numaaGetNuma(NUMAA *naa, l_int32 index, l_int32 accessflag)
numaaGetNuma()
Definition: numabasic.c:1740
l_ok numaaAddNumber(NUMAA *naa, l_int32 index, l_float32 val)
numaaAddNumber()
Definition: numabasic.c:1852
l_ok numaaGetValue(NUMAA *naa, l_int32 i, l_int32 j, l_float32 *pfval, l_int32 *pival)
numaaGetValue()
Definition: numabasic.c:1809
void numaDestroy(NUMA **pna)
numaDestroy()
Definition: numabasic.c:366
l_ok numaaTruncate(NUMAA *naa)
numaaTruncate()
Definition: numabasic.c:1476
NUMAA * numaaCreateFull(l_int32 nptr, l_int32 n)
numaaCreateFull()
Definition: numabasic.c:1445
l_ok numaSetValue(NUMA *na, l_int32 index, l_float32 val)
numaSetValue()
Definition: numabasic.c:786
l_int32 numaGetCount(NUMA *na)
numaGetCount()
Definition: numabasic.c:658
l_ok numaGetIValue(NUMA *na, l_int32 index, l_int32 *pival)
numaGetIValue()
Definition: numabasic.c:754
NUMA * numaCreate(l_int32 n)
numaCreate()
Definition: numabasic.c:194
void numaaDestroy(NUMAA **pnaa)
numaaDestroy()
Definition: numabasic.c:1510
l_ok numaGetRankValue(NUMA *na, l_float32 fract, NUMA *nasort, l_int32 usebins, l_float32 *pval)
numaGetRankValue()
Definition: numafunc1.c:3352
l_ok numaGetMin(NUMA *na, l_float32 *pminval, l_int32 *piminloc)
numaGetMin()
Definition: numafunc1.c:453
l_ok numaGetMax(NUMA *na, l_float32 *pmaxval, l_int32 *pimaxloc)
numaGetMax()
Definition: numafunc1.c:496
l_ok numaCountNonzeroRuns(NUMA *na, l_int32 *pcount)
numaCountNonzeroRuns()
Definition: numafunc1.c:1037
void pixDestroy(PIX **ppix)
pixDestroy()
Definition: pix1.c:621
l_ok pixGetDimensions(const PIX *pix, l_int32 *pw, l_int32 *ph, l_int32 *pd)
pixGetDimensions()
Definition: pix1.c:1113
l_ok pixSetText(PIX *pix, const char *textstring)
pixSetText()
Definition: pix1.c:1536
PIX * pixClone(PIX *pixs)
pixClone()
Definition: pix1.c:593
PIX * pixCreate(l_int32 width, l_int32 height, l_int32 depth)
pixCreate()
Definition: pix1.c:315
PIX * pixCopy(PIX *pixd, const PIX *pixs)
pixCopy()
Definition: pix1.c:705
char * pixGetText(PIX *pix)
pixGetText()
Definition: pix1.c:1512
l_ok pixClearAll(PIX *pix)
pixClearAll()
Definition: pix2.c:789
PIX * pixAddBlackOrWhiteBorder(PIX *pixs, l_int32 left, l_int32 right, l_int32 top, l_int32 bot, l_int32 op)
pixAddBlackOrWhiteBorder()
Definition: pix2.c:1863
PIX * pixAddBorder(PIX *pixs, l_int32 npix, l_uint32 val)
pixAddBorder()
Definition: pix2.c:1823
PIX * pixAddBorderGeneral(PIX *pixs, l_int32 left, l_int32 right, l_int32 top, l_int32 bot, l_uint32 val)
pixAddBorderGeneral()
Definition: pix2.c:1917
l_ok pixSetAllArbitrary(PIX *pix, l_uint32 val)
pixSetAllArbitrary()
Definition: pix2.c:951
l_int32 * makePixelSumTab8(void)
makePixelSumTab8()
Definition: pix3.c:2411
l_ok pixZero(PIX *pix, l_int32 *pempty)
pixZero()
Definition: pix3.c:1815
l_ok pixCountPixels(PIX *pixs, l_int32 *pcount, l_int32 *tab8)
pixCountPixels()
Definition: pix3.c:1937
l_int32 * makePixelCentroidTab8(void)
makePixelCentroidTab8()
Definition: pix3.c:2451
NUMA * pixCountByColumn(PIX *pix, BOX *box)
pixCountByColumn()
Definition: pix3.c:2097
PIX * pixInvert(PIX *pixd, PIX *pixs)
pixInvert()
Definition: pix3.c:1509
PIX * pixClipRectangle(PIX *pixs, BOX *box, BOX **pboxc)
pixClipRectangle()
Definition: pix5.c:1026
l_ok pixClipToForeground(PIX *pixs, PIX **ppixd, BOX **pbox)
pixClipToForeground()
Definition: pix5.c:1784
@ L_SORT_BY_HEIGHT
Definition: pix.h:740
@ L_ADD_BELOW
Definition: pix.h:1210
@ L_COPY
Definition: pix.h:712
@ L_CLONE
Definition: pix.h:713
@ L_NOCOPY
Definition: pix.h:710
@ L_INSERT
Definition: pix.h:711
#define PIX_SRC
Definition: pix.h:330
@ L_SORT_INCREASING
Definition: pix.h:729
@ L_GET_WHITE_VAL
Definition: pix.h:915
l_ok pixaAddPix(PIXA *pixa, PIX *pix, l_int32 copyflag)
pixaAddPix()
Definition: pixabasic.c:506
void pixaDestroy(PIXA **ppixa)
pixaDestroy()
Definition: pixabasic.c:412
l_ok pixaVerifyDepth(PIXA *pixa, l_int32 *psame, l_int32 *pmaxd)
pixaVerifyDepth()
Definition: pixabasic.c:960
l_ok pixaaInitFull(PIXAA *paa, PIXA *pixa)
pixaaInitFull()
Definition: pixabasic.c:2457
l_ok pixaaTruncate(PIXAA *paa)
pixaaTruncate()
Definition: pixabasic.c:2563
l_ok pixaaAddPix(PIXAA *paa, l_int32 index, PIX *pix, BOX *box, l_int32 copyflag)
pixaaAddPix()
Definition: pixabasic.c:2083
l_ok pixaaAddPixa(PIXAA *paa, PIXA *pixa, l_int32 copyflag)
pixaaAddPixa()
Definition: pixabasic.c:1998
l_ok pixaGetPixDimensions(PIXA *pixa, l_int32 index, l_int32 *pw, l_int32 *ph, l_int32 *pd)
pixaGetPixDimensions()
Definition: pixabasic.c:726
PIXA * pixaaGetPixa(PIXAA *paa, l_int32 index, l_int32 accesstype)
pixaaGetPixa()
Definition: pixabasic.c:2206
PIXA * pixaCreate(l_int32 n)
pixaCreate()
Definition: pixabasic.c:167
l_int32 pixaGetCount(PIXA *pixa)
pixaGetCount()
Definition: pixabasic.c:650
PIX * pixaGetPix(PIXA *pixa, l_int32 index, l_int32 accesstype)
pixaGetPix()
Definition: pixabasic.c:691
PIX * pixaaGetPix(PIXAA *paa, l_int32 index, l_int32 ipix, l_int32 accessflag)
pixaaGetPix()
Definition: pixabasic.c:2268
void pixaaDestroy(PIXAA **ppaa)
pixaaDestroy()
Definition: pixabasic.c:1957
l_int32 pixaaGetCount(PIXAA *paa, NUMA **pna)
pixaaGetCount()
Definition: pixabasic.c:2157
l_ok pixaJoin(PIXA *pixad, PIXA *pixas, l_int32 istart, l_int32 iend)
pixaJoin()
Definition: pixabasic.c:1673
PIXAA * pixaaCreate(l_int32 n)
pixaaCreate()
Definition: pixabasic.c:1852
PIXA * pixaCopy(PIXA *pixa, l_int32 copyflag)
pixaCopy()
Definition: pixabasic.c:453
l_ok pixaSizeRange(PIXA *pixa, l_int32 *pminw, l_int32 *pminh, l_int32 *pmaxw, l_int32 *pmaxh)
pixaSizeRange()
Definition: pixafunc1.c:2591
PIXA * pixaaFlattenToPixa(PIXAA *paa, NUMA **pnaindex, l_int32 copyflag)
pixaaFlattenToPixa()
Definition: pixafunc1.c:2482
PIXA * pixaSelectRange(PIXA *pixas, l_int32 first, l_int32 last, l_int32 copyflag)
pixaSelectRange()
Definition: pixafunc1.c:1809
PIXA * pixaSort(PIXA *pixas, l_int32 sorttype, l_int32 sortorder, NUMA **pnaindex, l_int32 copyflag)
pixaSort()
Definition: pixafunc1.c:1475
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 * 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
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 * pixFinalAccumulate(PIX *pixs, l_uint32 offset, l_int32 depth)
pixFinalAccumulate()
Definition: pixarith.c:683
l_ok pixAccumulate(PIX *pixd, PIX *pixs, l_int32 op)
pixAccumulate()
Definition: pixarith.c:817
PIX * pixConvertTo32(PIX *pixs)
pixConvertTo32()
Definition: pixconv.c:3332
PIX * pixConvertTo1(PIX *pixs, l_int32 threshold)
pixConvertTo1()
Definition: pixconv.c:3026
l_ok ptaaAddPt(PTAA *ptaa, l_int32 ipta, l_float32 x, l_float32 y)
ptaaAddPt()
Definition: ptabasic.c:1286
PTA * ptaCreate(l_int32 n)
ptaCreate()
Definition: ptabasic.c:120
PTA * ptaClone(PTA *pta)
ptaClone()
Definition: ptabasic.c:297
l_ok ptaaInitFull(PTAA *ptaa, PTA *pta)
ptaaInitFull()
Definition: ptabasic.c:1216
PTA * ptaaGetPta(PTAA *ptaa, l_int32 index, l_int32 accessflag)
ptaaGetPta()
Definition: ptabasic.c:1145
l_ok ptaaGetPt(PTAA *ptaa, l_int32 ipta, l_int32 jpt, l_float32 *px, l_float32 *py)
ptaaGetPt()
Definition: ptabasic.c:1176
l_ok ptaAddPt(PTA *pta, l_float32 x, l_float32 y)
ptaAddPt()
Definition: ptabasic.c:343
l_ok ptaGetPt(PTA *pta, l_int32 index, l_float32 *px, l_float32 *py)
ptaGetPt()
Definition: ptabasic.c:548
l_int32 ptaGetCount(PTA *pta)
ptaGetCount()
Definition: ptabasic.c:527
PTAA * ptaaCreate(l_int32 n)
ptaaCreate()
Definition: ptabasic.c:976
void ptaaDestroy(PTAA **pptaa)
ptaaDestroy()
Definition: ptabasic.c:1003
void ptaDestroy(PTA **ppta)
ptaDestroy()
Definition: ptabasic.c:195
l_ok ptaaTruncate(PTAA *ptaa)
ptaaTruncate()
Definition: ptabasic.c:1321
@ 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_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 l_convertCharstrToInt(const char *str, l_int32 *pval)
l_convertCharstrToInt()
Definition: recogbasic.c:783
l_int32 recogGetClassIndex(L_RECOG *recog, l_int32 val, char *text, l_int32 *pindex)
recogGetClassIndex()
Definition: recogbasic.c:655
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
l_int32 recogGetClassString(L_RECOG *recog, l_int32 index, char **pcharstr)
recogGetClassString()
Definition: recogbasic.c:753
PIXA * recogExtractPixa(L_RECOG *recog)
recogExtractPixa()
Definition: recogbasic.c:1122
void recogDestroy(L_RECOG **precog)
recogDestroy()
Definition: recogbasic.c:480
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_ok recogIdentifyPix(L_RECOG *recog, PIX *pixs, PIX **ppixdb)
recogIdentifyPix()
Definition: recogident.c:975
l_ok recogProcessLabeled(L_RECOG *recog, PIX *pixs, BOX *box, char *text, PIX **ppix)
recogProcessLabeled()
Definition: recogtrain.c:265
l_int32 recogIsPaddingNeeded(L_RECOG *recog, SARRAY **psa)
recogIsPaddingNeeded()
Definition: recogtrain.c:1654
l_ok recogPadDigitTrainingSet(L_RECOG **precog, l_int32 scaleh, l_int32 linew)
recogPadDigitTrainingSet()
Definition: recogtrain.c:1596
l_int32 recogShowAverageTemplates(L_RECOG *recog)
recogShowAverageTemplates()
Definition: recogtrain.c:2146
l_int32 pixaAccumulateSamples(PIXA *pixa, PTA *pta, PIX **ppixd, l_float32 *px, l_float32 *py)
pixaAccumulateSamples()
Definition: recogtrain.c:668
l_ok recogShowMatchesInRange(L_RECOG *recog, PIXA *pixa, l_float32 minscore, l_float32 maxscore, l_int32 display)
recogShowMatchesInRange()
Definition: recogtrain.c:2335
static PIX * pixDisplayOutliers(PIXA *pixas, NUMA *nas)
pixDisplayOutliers()
Definition: recogtrain.c:2224
PIX * recogShowMatch(L_RECOG *recog, PIX *pix1, PIX *pix2, BOX *box, l_int32 index, l_float32 score)
recogShowMatch()
Definition: recogtrain.c:2429
l_ok recogTrainingFinished(L_RECOG **precog, l_int32 modifyflag, l_int32 minsize, l_float32 minfract)
recogTrainingFinished()
Definition: recogtrain.c:787
PIX * recogModifyTemplate(L_RECOG *recog, PIX *pixs)
recogModifyTemplate()
Definition: recogtrain.c:421
PIXA * recogFilterPixaBySize(PIXA *pixas, l_int32 setsize, l_int32 maxkeep, l_float32 max_ht_ratio, NUMA **pna)
recogFilterPixaBySize()
Definition: recogtrain.c:974
PIXA * pixaRemoveOutliers2(PIXA *pixas, l_float32 minscore, l_int32 minsize, PIX **ppixsave, PIX **ppixrem)
pixaRemoveOutliers2()
Definition: recogtrain.c:1367
l_ok recogTrainLabeled(L_RECOG *recog, PIX *pixs, BOX *box, char *text, l_int32 debug)
recogTrainLabeled()
Definition: recogtrain.c:216
l_ok recogRemoveOutliers1(L_RECOG **precog, l_float32 minscore, l_int32 mintarget, l_int32 minsize, PIX **ppixsave, PIX **ppixrem)
recogRemoveOutliers1()
Definition: recogtrain.c:1085
L_RECOG * recogMakeBootDigitRecog(l_int32 nsamp, l_int32 scaleh, l_int32 linew, l_int32 maxyshift, l_int32 debug)
recogMakeBootDigitRecog()
Definition: recogtrain.c:1884
static PIX * recogDisplayOutlier(L_RECOG *recog, l_int32 iclass, l_int32 jsamp, l_int32 maxclass, l_float32 maxscore)
recogDisplayOutlier()
Definition: recogtrain.c:2280
l_ok recogRemoveOutliers2(L_RECOG **precog, l_float32 minscore, l_int32 minsize, PIX **ppixsave, PIX **ppixrem)
recogRemoveOutliers2()
Definition: recogtrain.c:1303
l_ok recogShowContent(FILE *fp, L_RECOG *recog, l_int32 index, l_int32 display)
recogShowContent()
Definition: recogtrain.c:1985
l_int32 recogAverageSamples(L_RECOG **precog, l_int32 debug)
recogAverageSamples()
Definition: recogtrain.c:490
l_ok recogAddSample(L_RECOG *recog, PIX *pix, l_int32 debug)
recogAddSample()
Definition: recogtrain.c:356
static l_int32 recogTemplatesAreOK(L_RECOG *recog, l_int32 minsize, l_float32 minfract, l_int32 *pok)
recogTemplatesAreOK()
Definition: recogtrain.c:912
static SARRAY * recogAddMissingClassStrings(L_RECOG *recog)
recogAddMissingClassStrings()
Definition: recogtrain.c:1713
l_ok recogDebugAverages(L_RECOG **precog, l_int32 debug)
recogDebugAverages()
Definition: recogtrain.c:2068
static l_int32 recogCharsetAvailable(l_int32 type)
recogCharsetAvailable()
Definition: recogtrain.c:1823
PIXA * recogAddDigitPadTemplates(L_RECOG *recog, SARRAY *sa)
recogAddDigitPadTemplates()
Definition: recogtrain.c:1772
PIXA * recogTrainFromBoot(L_RECOG *recogboot, PIXA *pixas, l_float32 minscore, l_int32 threshold, l_int32 debug)
recogTrainFromBoot()
Definition: recogtrain.c:1492
PIXAA * recogSortPixaByClass(PIXA *pixa, l_int32 setsize)
recogSortPixaByClass()
Definition: recogtrain.c:1045
PIXA * recogMakeBootDigitTemplates(l_int32 nsamp, l_int32 debug)
recogMakeBootDigitTemplates()
Definition: recogtrain.c:1921
PIXA * pixaRemoveOutliers1(PIXA *pixas, l_float32 minscore, l_int32 mintarget, l_int32 minsize, PIX **ppixsave, PIX **ppixrem)
pixaRemoveOutliers1()
Definition: recogtrain.c:1163
l_ok pixRasterop(PIX *pixd, l_int32 dx, l_int32 dy, l_int32 dw, l_int32 dh, l_int32 op, PIX *pixs, l_int32 sx, l_int32 sy)
pixRasterop()
Definition: rop.c:204
SARRAY * sarrayCreate(l_int32 n)
sarrayCreate()
Definition: sarray1.c:170
char * sarrayGetString(SARRAY *sa, l_int32 index, l_int32 copyflag)
sarrayGetString()
Definition: sarray1.c:703
l_int32 sarrayGetCount(SARRAY *sa)
sarrayGetCount()
Definition: sarray1.c:643
void sarrayDestroy(SARRAY **psa)
sarrayDestroy()
Definition: sarray1.c:362
l_ok sarrayAddString(SARRAY *sa, const char *string, l_int32 copyflag)
sarrayAddString()
Definition: sarray1.c:451
PIX * pixScaleToSize(PIX *pixs, l_int32 wd, l_int32 hd)
pixScaleToSize()
Definition: scale1.c:323
PIX * pixSeedfillBinary(PIX *pixd, PIX *pixs, PIX *pixm, l_int32 connectivity)
pixSeedfillBinary()
Definition: seedfill.c:247
PIXA * pixaSetStrokeWidth(PIXA *pixas, l_int32 width, l_int32 thinfirst, l_int32 connectivity)
pixaSetStrokeWidth()
Definition: strokes.c:349
PIX * pixSetStrokeWidth(PIX *pixs, l_int32 width, l_int32 thinfirst, l_int32 connectivity)
pixSetStrokeWidth()
Definition: strokes.c:401
Definition: pix.h:481
Definition: bmf.h:47
Definition: recog.h:116
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
Definition: array.h:71
Definition: pix.h:139
char * text
Definition: pix.h:152
Definition: pix.h:456
Definition: pix.h:467
Definition: pix.h:517
Definition: pix.h:531
Definition: array.h:127
PIX * pixAddSingleTextblock(PIX *pixs, L_BMF *bmf, const char *textstr, l_uint32 val, l_int32 location, l_int32 *poverflow)
pixAddSingleTextblock()
Definition: textops.c:120
void lept_stderr(const char *fmt,...)
lept_stderr()
Definition: utils1.c:306
l_int32 lept_mkdir(const char *subdir)
lept_mkdir()
Definition: utils2.c:2218