Leptonica 1.82.0
Image processing and image analysis suite
recogdid.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
156#ifdef HAVE_CONFIG_H
157#include <config_auto.h>
158#endif /* HAVE_CONFIG_H */
159
160#include <string.h>
161#include <math.h>
162#include "allheaders.h"
163
164static l_int32 recogPrepareForDecoding(L_RECOG *recog, PIX *pixs,
165 l_int32 debug);
166static l_int32 recogMakeDecodingArray(L_RECOG *recog, l_int32 index,
167 l_int32 debug);
168static l_int32 recogRunViterbi(L_RECOG *recog, PIX **ppixdb);
169static l_int32 recogRescoreDidResult(L_RECOG *recog, PIX **ppixdb);
170static PIX *recogShowPath(L_RECOG *recog, l_int32 select);
171static l_int32 recogGetWindowedArea(L_RECOG *recog, l_int32 index,
172 l_int32 x, l_int32 *pdely, l_int32 *pwsum);
173static l_int32 recogTransferRchToDid(L_RECOG *recog, l_int32 x, l_int32 y);
174
175 /* Parameters for modeling the decoding */
176static const l_float32 SetwidthFraction = 0.95;
177static const l_int32 MaxYShift = 1;
178
179 /* Channel parameters. alpha[0] is the probability that a bg pixel
180 * is OFF. alpha[1] is the probability that level 1 fg is ON.
181 * The actual values are not too critical, but they must be larger
182 * than 0.5 and smaller than 1.0. For more accuracy in template
183 * matching, use a 4-level template, where levels 2 and 3 are
184 * boundary pixels in the fg and bg, respectively. */
185static const l_float32 DefaultAlpha2[] = {0.95f, 0.9f};
186static const l_float32 DefaultAlpha4[] = {0.95f, 0.9f, 0.75f, 0.25f};
187
188
189/*------------------------------------------------------------------------*
190 * Top-level identification *
191 *------------------------------------------------------------------------*/
218BOXA *
220 PIX *pixs,
221 l_int32 nlevels,
222 PIX **ppixdb)
223{
224l_int32 debug;
225PIX *pix1;
226PIXA *pixa;
227
228 PROCNAME("recogDecode");
229
230 if (ppixdb) *ppixdb = NULL;
231 if (!recog)
232 return (BOXA *)ERROR_PTR("recog not defined", procName, NULL);
233 if (!pixs || pixGetDepth(pixs) != 1)
234 return (BOXA *)ERROR_PTR("pixs undefined or not 1 bpp", procName, NULL);
235 if (!recog->train_done)
236 return (BOXA *)ERROR_PTR("training not finished", procName, NULL);
237 if (nlevels != 2)
238 return (BOXA *)ERROR_PTR("nlevels != 2 (for now)", procName, NULL);
239
240 debug = (ppixdb) ? 1 : 0;
241 if (recogPrepareForDecoding(recog, pixs, debug))
242 return (BOXA *)ERROR_PTR("error making arrays", procName, NULL);
243 recogSetChannelParams(recog, nlevels);
244
245 /* Normal path; just run Viterbi */
246 if (!debug) {
247 if (recogRunViterbi(recog, NULL) == 0)
248 return boxaCopy(recog->did->boxa, L_COPY);
249 else
250 return (BOXA *)ERROR_PTR("error in Viterbi", procName, NULL);
251 }
252
253 /* Debug path */
254 if (recogRunViterbi(recog, &pix1))
255 return (BOXA *)ERROR_PTR("error in viterbi", procName, NULL);
256 pixa = pixaCreate(2);
257 pixaAddPix(pixa, pix1, L_INSERT);
258 if (recogRescoreDidResult(recog, &pix1)) {
259 pixaDestroy(&pixa);
260 return (BOXA *)ERROR_PTR("error in rescoring", procName, NULL);
261 }
262 pixaAddPix(pixa, pix1, L_INSERT);
263 *ppixdb = pixaDisplayTiledInRows(pixa, 32, 2 * pixGetWidth(pix1) + 100,
264 1.0, 0, 30, 2);
265 pixaDestroy(&pixa);
266 return boxaCopy(recog->did->boxa, L_COPY);
267}
268
269
270/*------------------------------------------------------------------------*
271 * Generate decoding arrays *
272 *------------------------------------------------------------------------*/
294static l_int32
296 PIX *pixs,
297 l_int32 debug)
298{
299l_int32 i;
300PIX *pix1;
301L_RDID *did;
302
303 PROCNAME("recogPrepareForDecoding");
304
305 if (!recog)
306 return ERROR_INT("recog not defined", procName, 1);
307 if (!pixs || pixGetDepth(pixs) != 1)
308 return ERROR_INT("pixs not defined or not 1 bpp", procName, 1);
309 if (!recog->train_done)
310 return ERROR_INT("training not finished", procName, 1);
311
312 if (!recog->ave_done)
313 recogAverageSamples(&recog, 0);
314
315 /* Binarize and crop to foreground if necessary */
316 if ((pix1 = recogProcessToIdentify(recog, pixs, 0)) == NULL)
317 return ERROR_INT("pix1 not made", procName, 1);
318
319 /* Remove any existing RecogDID and set up a new one */
320 recogDestroyDid(recog);
321 if (recogCreateDid(recog, pix1)) {
322 pixDestroy(&pix1);
323 return ERROR_INT("decoder not made", procName, 1);
324 }
325
326 /* Compute vertical sum and first moment arrays */
327 did = recogGetDid(recog); /* owned by recog */
328 did->nasum = pixCountPixelsByColumn(pix1);
329 did->namoment = pixGetMomentByColumn(pix1, 1);
330
331 /* Generate the arrays */
332 for (i = 0; i < recog->did->narray; i++)
333 recogMakeDecodingArray(recog, i, debug);
334
335 pixDestroy(&pix1);
336 return 0;
337}
338
339
355static l_int32
357 l_int32 index,
358 l_int32 debug)
359{
360l_int32 i, j, w1, h1, w2, h2, nx, ycent2, count, maxcount, maxdely;
361l_int32 sum, moment, dely, shifty;
362l_int32 *counta, *delya, *ycent1, *arraysum, *arraymoment, *sumtab;
363NUMA *nasum, *namoment;
364PIX *pix1, *pix2, *pix3;
365L_RDID *did;
366
367 PROCNAME("recogMakeDecodingArray");
368
369 if (!recog)
370 return ERROR_INT("recog not defined", procName, 1);
371 if ((did = recogGetDid(recog)) == NULL)
372 return ERROR_INT("did not defined", procName, 1);
373 if (index < 0 || index >= did->narray)
374 return ERROR_INT("invalid index", procName, 1);
375
376 /* Check that pix1 is large enough for this template. */
377 pix1 = did->pixs; /* owned by did; do not destroy */
378 pixGetDimensions(pix1, &w1, &h1, NULL);
379 pix2 = pixaGetPix(recog->pixa_u, index, L_CLONE);
380 pixGetDimensions(pix2, &w2, &h2, NULL);
381 if (w1 < w2) {
382 L_INFO("w1 = %d < w2 = %d for index %d\n", procName, w1, w2, index);
383 pixDestroy(&pix2);
384 return 0;
385 }
386
387 nasum = did->nasum;
388 namoment = did->namoment;
389 ptaGetIPt(recog->pta_u, index, NULL, &ycent2);
390 sumtab = recog->sumtab;
391 counta = did->counta[index];
392 delya = did->delya[index];
393
394 /* Set up the array for ycent1. This gives the y-centroid location
395 * for a window of width w2, starting at location i. */
396 nx = w1 - w2 + 1; /* number of positions w2 can be placed in w1 */
397 ycent1 = (l_int32 *)LEPT_CALLOC(nx, sizeof(l_int32));
398 arraysum = numaGetIArray(nasum);
399 arraymoment = numaGetIArray(namoment);
400 for (i = 0, sum = 0, moment = 0; i < w2; i++) {
401 sum += arraysum[i];
402 moment += arraymoment[i];
403 }
404 for (i = 0; i < nx - 1; i++) {
405 ycent1[i] = (sum == 0) ? ycent2 : (l_float32)moment / (l_float32)sum;
406 sum += arraysum[w2 + i] - arraysum[i];
407 moment += arraymoment[w2 + i] - arraymoment[i];
408 }
409 ycent1[nx - 1] = (sum == 0) ? ycent2 : (l_float32)moment / (l_float32)sum;
410
411 /* Compute the bit-and sum between the template pix2 and pix1, at
412 * locations where the left side of pix2 goes from 0 to nx - 1
413 * in pix1. Do this around the vertical alignment of the pix2
414 * centroid and the windowed pix1 centroid.
415 * (1) Start with pix3 cleared and approximately equal in size to pix1.
416 * (2) Blit the y-shifted pix2 onto pix3. Then all ON pixels
417 * are within the intersection of pix1 and the shifted pix2.
418 * (3) AND pix1 with pix3. */
419 pix3 = pixCreate(w2, h1, 1);
420 for (i = 0; i < nx; i++) {
421 shifty = (l_int32)(ycent1[i] - ycent2 + 0.5);
422 maxcount = 0;
423 maxdely = 0;
424 for (j = -MaxYShift; j <= MaxYShift; j++) {
425 pixClearAll(pix3);
426 dely = shifty + j; /* amount pix2 is shifted relative to pix1 */
427 pixRasterop(pix3, 0, dely, w2, h2, PIX_SRC, pix2, 0, 0);
428 pixRasterop(pix3, 0, 0, w2, h1, PIX_SRC & PIX_DST, pix1, i, 0);
429 pixCountPixels(pix3, &count, sumtab);
430 if (count > maxcount) {
431 maxcount = count;
432 maxdely = dely;
433 }
434 }
435 counta[i] = maxcount;
436 delya[i] = maxdely;
437 }
438 did->fullarrays = TRUE;
439
440 pixDestroy(&pix2);
441 pixDestroy(&pix3);
442 LEPT_FREE(ycent1);
443 LEPT_FREE(arraysum);
444 LEPT_FREE(arraymoment);
445 return 0;
446}
447
448
449/*------------------------------------------------------------------------*
450 * Dynamic programming for best path
451 *------------------------------------------------------------------------*/
480static l_int32
482 PIX **ppixdb)
483{
484l_int32 i, w1, w2, h1, xnz, x, narray, minsetw;
485l_int32 first, templ, xloc, dely, counts, area1;
486l_int32 besttempl, spacetempl;
487l_int32 *setw, *didtempl;
488l_int32 *area2; /* must be freed */
489l_float32 prevscore, matchscore, maxscore, correl;
490l_float32 *didscore;
491BOX *box;
492PIX *pix1;
493L_RDID *did;
494
495 PROCNAME("recogRunViterbi");
496
497 if (ppixdb) *ppixdb = NULL;
498 if (!recog)
499 return ERROR_INT("recog not defined", procName, 1);
500 if ((did = recogGetDid(recog)) == NULL)
501 return ERROR_INT("did not defined", procName, 1);
502 if (did->fullarrays == 0)
503 return ERROR_INT("did full arrays not made", procName, 1);
504
505 /* Compute the minimum setwidth. Bad templates with very small
506 * width can cause havoc because the setwidth is too small. */
507 w1 = did->size;
508 narray = did->narray;
509 spacetempl = narray;
510 setw = did->setwidth;
511 minsetw = 100000;
512 for (i = 0; i < narray; i++) {
513 if (setw[i] < minsetw)
514 minsetw = setw[i];
515 }
516 if (minsetw <= 2)
517 return ERROR_INT("minsetw <= 2; bad templates", procName, 1);
518
519 /* The score array is initialized to 0.0. As we proceed to
520 * the left, the log likelihood for the partial paths goes
521 * negative, and we prune for the max (least negative) path.
522 * No matches will be computed until we reach x = min(setwidth);
523 * until then first == TRUE after looping over templates. */
524 didscore = did->trellisscore;
525 didtempl = did->trellistempl;
526 area2 = numaGetIArray(recog->nasum_u);
527 besttempl = 0; /* just tells compiler it is initialized */
528 maxscore = 0.0; /* ditto */
529 for (x = minsetw; x < w1; x++) { /* will always get a score */
530 first = TRUE;
531 for (i = 0; i < narray; i++) {
532 if (x - setw[i] < 0) continue;
533 matchscore = didscore[x - setw[i]] +
534 did->gamma[1] * did->counta[i][x - setw[i]] +
535 did->beta[1] * area2[i];
536 if (first) {
537 maxscore = matchscore;
538 besttempl = i;
539 first = FALSE;
540 } else {
541 if (matchscore > maxscore) {
542 maxscore = matchscore;
543 besttempl = i;
544 }
545 }
546 }
547
548 /* We can also put down a single pixel space, with no cost
549 * because all pixels are bg. */
550 prevscore = didscore[x - 1];
551 if (prevscore > maxscore) { /* 1 pixel space is best */
552 maxscore = prevscore;
553 besttempl = spacetempl;
554 }
555 didscore[x] = maxscore;
556 didtempl[x] = besttempl;
557 }
558
559 /* Backtrack to get the best path.
560 * Skip over (i.e., ignore) all single pixel spaces. */
561 for (x = w1 - 1; x >= 0; x--) {
562 if (didtempl[x] != spacetempl) break;
563 }
564 h1 = pixGetHeight(did->pixs);
565 while (x > 0) {
566 if (didtempl[x] == spacetempl) { /* skip over spaces */
567 x--;
568 continue;
569 }
570 templ = didtempl[x];
571 xloc = x - setw[templ];
572 if (xloc < 0) break;
573 counts = did->counta[templ][xloc]; /* bit-and counts */
574 recogGetWindowedArea(recog, templ, xloc, &dely, &area1);
575 correl = ((l_float32)(counts) * counts) /
576 (l_float32)(area2[templ] * area1);
577 pix1 = pixaGetPix(recog->pixa_u, templ, L_CLONE);
578 w2 = pixGetWidth(pix1);
579 numaAddNumber(did->natempl, templ);
580 numaAddNumber(did->naxloc, xloc);
581 numaAddNumber(did->nadely, dely);
582 numaAddNumber(did->nawidth, pixGetWidth(pix1));
583 numaAddNumber(did->nascore, correl);
584 xnz = L_MAX(xloc, 0);
585 box = boxCreate(xnz, dely, w2, h1);
586 boxaAddBox(did->boxa, box, L_INSERT);
587 pixDestroy(&pix1);
588 x = xloc;
589 }
590
591 if (ppixdb) {
597 boxaWriteStderr(did->boxa);
598 *ppixdb = recogShowPath(recog, 0);
599 }
600
601 LEPT_FREE(area2);
602 return 0;
603}
604
605
619static l_int32
621 PIX **ppixdb)
622{
623l_int32 i, n, sample, x, dely, index;
624char *text;
625l_float32 score;
626BOX *box1;
627PIX *pixs, *pix1;
628L_RDID *did;
629
630 PROCNAME("recogRescoreDidResult");
631
632 if (ppixdb) *ppixdb = NULL;
633 if (!recog)
634 return ERROR_INT("recog not defined", procName, 1);
635 if ((did = recogGetDid(recog)) == NULL)
636 return ERROR_INT("did not defined", procName, 1);
637 if (did->fullarrays == 0)
638 return ERROR_INT("did full arrays not made", procName, 1);
639 if ((n = numaGetCount(did->naxloc)) == 0)
640 return ERROR_INT("no elements in path", procName, 1);
641
642 pixs = did->pixs;
643 for (i = 0; i < n; i++) {
644 box1 = boxaGetBox(did->boxa, i, L_COPY);
645 boxGetGeometry(box1, &x, &dely, NULL, NULL);
646 pix1 = pixClipRectangle(pixs, box1, NULL);
647 recogIdentifyPix(recog, pix1, NULL);
648 recogTransferRchToDid(recog, x, dely);
649 if (ppixdb) {
650 rchExtract(recog->rch, &index, &score, &text,
651 &sample, NULL, NULL, NULL);
652 lept_stderr("text = %s, index = %d, sample = %d,"
653 " score = %5.3f\n", text, index, sample, score);
654 }
655 pixDestroy(&pix1);
656 boxDestroy(&box1);
657 LEPT_FREE(text);
658 }
659
660 if (ppixdb)
661 *ppixdb = recogShowPath(recog, 1);
662
663 return 0;
664}
665
666
674static PIX *
676 l_int32 select)
677{
678char textstr[16];
679l_int32 i, j, n, index, xloc, dely;
680l_float32 score;
681L_BMF *bmf;
682NUMA *natempl_s, *nasample_s, *nascore_s, *naxloc_s, *nadely_s;
683PIX *pixs, *pix0, *pix1, *pix2, *pix3, *pix4, *pix5;
684L_RDID *did;
685
686 PROCNAME("recogShowPath");
687
688 if (!recog)
689 return (PIX *)ERROR_PTR("recog not defined", procName, NULL);
690 if ((did = recogGetDid(recog)) == NULL)
691 return (PIX *)ERROR_PTR("did not defined", procName, NULL);
692
693 bmf = bmfCreate(NULL, 8);
694 pixs = pixScale(did->pixs, 4.0, 4.0);
695 pix0 = pixAddBorderGeneral(pixs, 0, 0, 0, 40, 0);
696 pix1 = pixConvertTo32(pix0);
697 if (select == 0) { /* Viterbi */
698 natempl_s = did->natempl;
699 nascore_s = did->nascore;
700 naxloc_s = did->naxloc;
701 nadely_s = did->nadely;
702 } else { /* rescored */
703 natempl_s = did->natempl_r;
704 nasample_s = did->nasample_r;
705 nascore_s = did->nascore_r;
706 naxloc_s = did->naxloc_r;
707 nadely_s = did->nadely_r;
708 }
709
710 n = numaGetCount(natempl_s);
711 for (i = 0; i < n; i++) {
712 numaGetIValue(natempl_s, i, &index);
713 if (select == 0) {
714 pix2 = pixaGetPix(recog->pixa_u, index, L_CLONE);
715 } else {
716 numaGetIValue(nasample_s, i, &j);
717 pix2 = pixaaGetPix(recog->pixaa_u, index, j, L_CLONE);
718 }
719 pix3 = pixScale(pix2, 4.0, 4.0);
720 pix4 = pixErodeBrick(NULL, pix3, 5, 5);
721 pixXor(pix4, pix4, pix3);
722 numaGetFValue(nascore_s, i, &score);
723 snprintf(textstr, sizeof(textstr), "%5.3f", score);
724 pix5 = pixAddTextlines(pix4, bmf, textstr, 1, L_ADD_BELOW);
725 numaGetIValue(naxloc_s, i, &xloc);
726 numaGetIValue(nadely_s, i, &dely);
727 pixPaintThroughMask(pix1, pix5, 4 * xloc, 4 * dely, 0xff000000);
728 pixDestroy(&pix2);
729 pixDestroy(&pix3);
730 pixDestroy(&pix4);
731 pixDestroy(&pix5);
732 }
733 pixDestroy(&pixs);
734 pixDestroy(&pix0);
735 bmfDestroy(&bmf);
736 return pix1;
737}
738
739
740/*------------------------------------------------------------------------*
741 * Create/destroy temporary DID data *
742 *------------------------------------------------------------------------*/
750l_ok
752 PIX *pixs)
753{
754l_int32 i;
755PIX *pix1;
756L_RDID *did;
757
758 PROCNAME("recogCreateDid");
759
760 if (!recog)
761 return ERROR_INT("recog not defined", procName, 1);
762 if (!pixs)
763 return ERROR_INT("pixs not defined", procName, 1);
764
765 recogDestroyDid(recog);
766
767 did = (L_RDID *)LEPT_CALLOC(1, sizeof(L_RDID));
768 recog->did = did;
769 did->pixs = pixClone(pixs);
770 did->narray = recog->setsize;
771 did->size = pixGetWidth(pixs);
772 did->natempl = numaCreate(5);
773 did->naxloc = numaCreate(5);
774 did->nadely = numaCreate(5);
775 did->nawidth = numaCreate(5);
776 did->boxa = boxaCreate(5);
777 did->nascore = numaCreate(5);
778 did->natempl_r = numaCreate(5);
779 did->nasample_r = numaCreate(5);
780 did->naxloc_r = numaCreate(5);
781 did->nadely_r = numaCreate(5);
782 did->nawidth_r = numaCreate(5);
783 did->nascore_r = numaCreate(5);
784
785 /* Make the arrays */
786 did->setwidth = (l_int32 *)LEPT_CALLOC(did->narray, sizeof(l_int32));
787 did->counta = (l_int32 **)LEPT_CALLOC(did->narray, sizeof(l_int32 *));
788 did->delya = (l_int32 **)LEPT_CALLOC(did->narray, sizeof(l_int32 *));
789 did->beta = (l_float32 *)LEPT_CALLOC(5, sizeof(l_float32));
790 did->gamma = (l_float32 *)LEPT_CALLOC(5, sizeof(l_float32));
791 did->trellisscore = (l_float32 *)LEPT_CALLOC(did->size, sizeof(l_float32));
792 did->trellistempl = (l_int32 *)LEPT_CALLOC(did->size, sizeof(l_int32));
793 for (i = 0; i < did->narray; i++) {
794 did->counta[i] = (l_int32 *)LEPT_CALLOC(did->size, sizeof(l_int32));
795 did->delya[i] = (l_int32 *)LEPT_CALLOC(did->size, sizeof(l_int32));
796 }
797
798 /* Populate the setwidth array */
799 for (i = 0; i < did->narray; i++) {
800 pix1 = pixaGetPix(recog->pixa_u, i, L_CLONE);
801 did->setwidth[i] = (l_int32)(SetwidthFraction * pixGetWidth(pix1));
802 pixDestroy(&pix1);
803 }
804
805 return 0;
806}
807
808
821l_ok
823{
824l_int32 i;
825L_RDID *did;
826
827 PROCNAME("recogDestroyDid");
828
829 if (!recog)
830 return ERROR_INT("recog not defined", procName, 1);
831
832 if ((did = recog->did) == NULL) return 0;
833 if (!did->counta || !did->delya)
834 return ERROR_INT("ptr array is null; shouldn't happen!", procName, 1);
835
836 for (i = 0; i < did->narray; i++) {
837 LEPT_FREE(did->counta[i]);
838 LEPT_FREE(did->delya[i]);
839 }
840 LEPT_FREE(did->setwidth);
841 LEPT_FREE(did->counta);
842 LEPT_FREE(did->delya);
843 LEPT_FREE(did->beta);
844 LEPT_FREE(did->gamma);
845 LEPT_FREE(did->trellisscore);
846 LEPT_FREE(did->trellistempl);
847 pixDestroy(&did->pixs);
848 numaDestroy(&did->nasum);
849 numaDestroy(&did->namoment);
850 numaDestroy(&did->natempl);
851 numaDestroy(&did->naxloc);
852 numaDestroy(&did->nadely);
853 numaDestroy(&did->nawidth);
854 boxaDestroy(&did->boxa);
855 numaDestroy(&did->nascore);
856 numaDestroy(&did->natempl_r);
857 numaDestroy(&did->nasample_r);
858 numaDestroy(&did->naxloc_r);
859 numaDestroy(&did->nadely_r);
860 numaDestroy(&did->nawidth_r);
861 numaDestroy(&did->nascore_r);
862 LEPT_FREE(did);
863 recog->did = NULL;
864 return 0;
865}
866
867
868/*------------------------------------------------------------------------*
869 * Various helpers *
870 *------------------------------------------------------------------------*/
877l_int32
879{
880 PROCNAME("recogDidExists");
881
882 if (!recog)
883 return ERROR_INT("recog not defined", procName, 0);
884 return (recog->did) ? 1 : 0;
885}
886
887
899L_RDID *
901{
902l_int32 i;
903L_RDID *did;
904
905 PROCNAME("recogGetDid");
906
907 if (!recog)
908 return (L_RDID *)ERROR_PTR("recog not defined", procName, NULL);
909 if ((did = recog->did) == NULL)
910 return (L_RDID *)ERROR_PTR("did not defined", procName, NULL);
911 if (!did->counta || !did->delya)
912 return (L_RDID *)ERROR_PTR("did array ptrs not defined",
913 procName, NULL);
914 for (i = 0; i < did->narray; i++) {
915 if (!did->counta[i] || !did->delya[i])
916 return (L_RDID *)ERROR_PTR("did arrays not defined",
917 procName, NULL);
918 }
919
920 return did;
921}
922
923
944static l_int32
946 l_int32 index,
947 l_int32 x,
948 l_int32 *pdely,
949 l_int32 *pwsum)
950{
951l_int32 w1, h1, w2, h2;
952PIX *pix1, *pix2, *pixt;
953L_RDID *did;
954
955 PROCNAME("recogGetWindowedArea");
956
957 if (pdely) *pdely = 0;
958 if (pwsum) *pwsum = 0;
959 if (!pdely || !pwsum)
960 return ERROR_INT("&dely and &wsum not both defined", procName, 1);
961 if (!recog)
962 return ERROR_INT("recog not defined", procName, 1);
963 if ((did = recogGetDid(recog)) == NULL)
964 return ERROR_INT("did not defined", procName, 1);
965 if (index < 0 || index >= did->narray)
966 return ERROR_INT("invalid index", procName, 1);
967 pix1 = did->pixs;
968 pixGetDimensions(pix1, &w1, &h1, NULL);
969 if (x >= w1)
970 return ERROR_INT("invalid x position", procName, 1);
971
972 pix2 = pixaGetPix(recog->pixa_u, index, L_CLONE);
973 pixGetDimensions(pix2, &w2, &h2, NULL);
974 if (w1 < w2) {
975 L_INFO("template %d too small\n", procName, index);
976 pixDestroy(&pix2);
977 return 0;
978 }
979
980 *pdely = did->delya[index][x];
981 pixt = pixCreate(w2, h1, 1);
982 pixRasterop(pixt, 0, *pdely, w2, h2, PIX_SRC, pix2, 0, 0);
983 pixRasterop(pixt, 0, 0, w2, h1, PIX_SRC & PIX_DST, pix1, x, 0);
984 pixCountPixels(pixt, pwsum, recog->sumtab);
985 pixDestroy(&pix2);
986 pixDestroy(&pixt);
987 return 0;
988}
989
990
1008l_ok
1010 l_int32 nlevels)
1011{
1012l_int32 i;
1013const l_float32 *da;
1014L_RDID *did;
1015
1016 PROCNAME("recogSetChannelParams");
1017
1018 if (!recog)
1019 return ERROR_INT("recog not defined", procName, 1);
1020 if ((did = recogGetDid(recog)) == NULL)
1021 return ERROR_INT("did not defined", procName, 1);
1022 if (nlevels == 2)
1023 da = DefaultAlpha2;
1024 else if (nlevels == 4)
1025 da = DefaultAlpha4;
1026 else
1027 return ERROR_INT("nlevels not 2 or 4", procName, 1);
1028
1029 for (i = 1; i < nlevels; i++) {
1030 did->beta[i] = log((1.0 - da[i]) / da[0]);
1031 did->gamma[i] = log(da[0] * da[i] / ((1.0 - da[0]) * (1.0 - da[i])));
1032/* lept_stderr("beta[%d] = %7.3f, gamma[%d] = %7.3f\n",
1033 i, did->beta[i], i, did->gamma[i]); */
1034 }
1035
1036 return 0;
1037}
1038
1039
1054static l_int32
1056 l_int32 x,
1057 l_int32 y)
1058{
1059L_RDID *did;
1060L_RCH *rch;
1061
1062 PROCNAME("recogTransferRchToDid");
1063
1064 if (!recog)
1065 return ERROR_INT("recog not defined", procName, 1);
1066 if ((did = recogGetDid(recog)) == NULL)
1067 return ERROR_INT("did not defined", procName, 1);
1068 if ((rch = recog->rch) == NULL)
1069 return ERROR_INT("rch not defined", procName, 1);
1070
1071 numaAddNumber(did->natempl_r, rch->index);
1072 numaAddNumber(did->nasample_r, rch->sample);
1073 numaAddNumber(did->naxloc_r, rch->xloc + x);
1074 numaAddNumber(did->nadely_r, rch->yloc + y);
1075 numaAddNumber(did->nawidth_r, rch->width);
1076 numaAddNumber(did->nascore_r, rch->score);
1077 return 0;
1078}
void bmfDestroy(L_BMF **pbmf)
bmfDestroy()
Definition: bmf.c:169
L_BMF * bmfCreate(const char *dir, l_int32 fontsize)
bmfCreate()
Definition: bmf.c:117
BOX * boxaGetBox(BOXA *boxa, l_int32 index, l_int32 accessflag)
boxaGetBox()
Definition: boxbasic.c:779
BOXA * boxaCopy(BOXA *boxa, l_int32 copyflag)
boxaCopy()
Definition: boxbasic.c:537
void boxDestroy(BOX **pbox)
boxDestroy()
Definition: boxbasic.c:282
BOX * boxCreate(l_int32 x, l_int32 y, l_int32 w, l_int32 h)
boxCreate()
Definition: boxbasic.c:172
l_ok boxaWriteStderr(BOXA *boxa)
boxaWriteStderr()
Definition: boxbasic.c:2333
l_ok boxGetGeometry(BOX *box, l_int32 *px, l_int32 *py, l_int32 *pw, l_int32 *ph)
boxGetGeometry()
Definition: boxbasic.c:313
BOXA * boxaCreate(l_int32 n)
boxaCreate()
Definition: boxbasic.c:502
l_ok boxaAddBox(BOXA *boxa, BOX *box, l_int32 copyflag)
boxaAddBox()
Definition: boxbasic.c:620
void boxaDestroy(BOXA **pboxa)
boxaDestroy()
Definition: boxbasic.c:583
PIX * pixErodeBrick(PIX *pixd, PIX *pixs, l_int32 hsize, l_int32 vsize)
pixErodeBrick()
Definition: morph.c:758
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
l_ok numaWriteStderr(NUMA *na)
numaWriteStderr()
Definition: numabasic.c:1313
l_int32 * numaGetIArray(NUMA *na)
numaGetIArray()
Definition: numabasic.c:847
void numaDestroy(NUMA **pna)
numaDestroy()
Definition: numabasic.c:366
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 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
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
l_ok pixClearAll(PIX *pix)
pixClearAll()
Definition: pix2.c:789
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 pixPaintThroughMask(PIX *pixd, PIX *pixm, l_int32 x, l_int32 y, l_uint32 val)
pixPaintThroughMask()
Definition: pix3.c:626
l_ok pixCountPixels(PIX *pixs, l_int32 *pcount, l_int32 *tab8)
pixCountPixels()
Definition: pix3.c:1937
PIX * pixXor(PIX *pixd, PIX *pixs1, PIX *pixs2)
pixXor()
Definition: pix3.c:1688
NUMA * pixCountPixelsByColumn(PIX *pix)
pixCountPixelsByColumn()
Definition: pix3.c:2177
NUMA * pixGetMomentByColumn(PIX *pix, l_int32 order)
pixGetMomentByColumn()
Definition: pix3.c:2281
PIX * pixClipRectangle(PIX *pixs, BOX *box, BOX **pboxc)
pixClipRectangle()
Definition: pix5.c:1026
#define PIX_DST
Definition: pix.h:331
@ L_ADD_BELOW
Definition: pix.h:1210
@ L_COPY
Definition: pix.h:712
@ L_CLONE
Definition: pix.h:713
@ L_INSERT
Definition: pix.h:711
#define PIX_SRC
Definition: pix.h:330
l_ok pixaAddPix(PIXA *pixa, PIX *pix, l_int32 copyflag)
pixaAddPix()
Definition: pixabasic.c:506
void pixaDestroy(PIXA **ppixa)
pixaDestroy()
Definition: pixabasic.c:412
PIXA * pixaCreate(l_int32 n)
pixaCreate()
Definition: pixabasic.c:167
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
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 * pixConvertTo32(PIX *pixs)
pixConvertTo32()
Definition: pixconv.c:3332
l_ok ptaGetIPt(PTA *pta, l_int32 index, l_int32 *px, l_int32 *py)
ptaGetIPt()
Definition: ptabasic.c:578
static l_int32 recogRunViterbi(L_RECOG *recog, PIX **ppixdb)
recogRunViterbi()
Definition: recogdid.c:481
L_RDID * recogGetDid(L_RECOG *recog)
recogGetDid()
Definition: recogdid.c:900
static l_int32 recogTransferRchToDid(L_RECOG *recog, l_int32 x, l_int32 y)
recogTransferRchToDid()
Definition: recogdid.c:1055
l_ok recogDestroyDid(L_RECOG *recog)
recogDestroyDid()
Definition: recogdid.c:822
BOXA * recogDecode(L_RECOG *recog, PIX *pixs, l_int32 nlevels, PIX **ppixdb)
recogDecode()
Definition: recogdid.c:219
static PIX * recogShowPath(L_RECOG *recog, l_int32 select)
recogShowPath()
Definition: recogdid.c:675
l_ok recogCreateDid(L_RECOG *recog, PIX *pixs)
recogCreateDid()
Definition: recogdid.c:751
l_ok recogSetChannelParams(L_RECOG *recog, l_int32 nlevels)
recogSetChannelParams()
Definition: recogdid.c:1009
static l_int32 recogGetWindowedArea(L_RECOG *recog, l_int32 index, l_int32 x, l_int32 *pdely, l_int32 *pwsum)
recogGetWindowedArea()
Definition: recogdid.c:945
static l_int32 recogRescoreDidResult(L_RECOG *recog, PIX **ppixdb)
recogRescoreDidResult()
Definition: recogdid.c:620
l_int32 recogDidExists(L_RECOG *recog)
recogDidExists()
Definition: recogdid.c:878
static l_int32 recogPrepareForDecoding(L_RECOG *recog, PIX *pixs, l_int32 debug)
recogPrepareForDecoding()
Definition: recogdid.c:295
static l_int32 recogMakeDecodingArray(L_RECOG *recog, l_int32 index, l_int32 debug)
recogMakeDecodingArray()
Definition: recogdid.c:356
PIX * recogProcessToIdentify(L_RECOG *recog, PIX *pixs, l_int32 pad)
recogProcessToIdentify()
Definition: recogident.c:1417
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_int32 recogAverageSamples(L_RECOG **precog, l_int32 debug)
recogAverageSamples()
Definition: recogtrain.c:490
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
PIX * pixScale(PIX *pixs, l_float32 scalex, l_float32 scaley)
pixScale()
Definition: scale1.c:250
Definition: pix.h:481
Definition: pix.h:492
Definition: bmf.h:47
Definition: recog.h:182
l_int32 sample
Definition: recog.h:186
l_int32 yloc
Definition: recog.h:189
l_float32 score
Definition: recog.h:184
l_int32 index
Definition: recog.h:183
l_int32 xloc
Definition: recog.h:188
l_int32 width
Definition: recog.h:190
Definition: recog.h:211
struct Numa * naxloc
Definition: recog.h:226
struct Numa * naxloc_r
Definition: recog.h:233
struct Numa * nawidth
Definition: recog.h:228
struct Numa * natempl_r
Definition: recog.h:231
l_int32 * setwidth
Definition: recog.h:217
struct Numa * namoment
Definition: recog.h:219
struct Numa * nawidth_r
Definition: recog.h:235
l_int32 narray
Definition: recog.h:215
l_float32 * trellisscore
Definition: recog.h:223
l_int32 size
Definition: recog.h:216
struct Numa * natempl
Definition: recog.h:225
l_int32 * trellistempl
Definition: recog.h:224
struct Numa * nasum
Definition: recog.h:218
struct Boxa * boxa
Definition: recog.h:229
l_int32 fullarrays
Definition: recog.h:220
l_int32 ** counta
Definition: recog.h:213
struct Numa * nadely_r
Definition: recog.h:234
struct Numa * nascore_r
Definition: recog.h:236
struct Numa * nasample_r
Definition: recog.h:232
l_float32 * gamma
Definition: recog.h:222
struct Numa * nascore
Definition: recog.h:230
l_int32 ** delya
Definition: recog.h:214
struct Pix * pixs
Definition: recog.h:212
struct Numa * nadely
Definition: recog.h:227
l_float32 * beta
Definition: recog.h:221
Definition: recog.h:116
l_int32 ave_done
Definition: recog.h:141
struct L_Rch * rch
Definition: recog.h:174
struct Pixa * pixa_u
Definition: recog.h:158
l_int32 train_done
Definition: recog.h:142
struct Pta * pta_u
Definition: recog.h:159
struct Numa * nasum_u
Definition: recog.h:160
l_int32 * sumtab
Definition: recog.h:151
struct Pixaa * pixaa_u
Definition: recog.h:152
l_int32 setsize
Definition: recog.h:127
struct L_Rdid * did
Definition: recog.h:173
Definition: array.h:71
Definition: pix.h:139
Definition: pix.h:456
PIX * pixAddTextlines(PIX *pixs, L_BMF *bmf, const char *textstr, l_uint32 val, l_int32 location)
pixAddTextlines()
Definition: textops.c:276
void lept_stderr(const char *fmt,...)
lept_stderr()
Definition: utils1.c:306