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