Leptonica  1.83.1
Image processing and image analysis suite
dewarp4.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 
57 #ifdef HAVE_CONFIG_H
58 #include <config_auto.h>
59 #endif /* HAVE_CONFIG_H */
60 
61 #include <math.h>
62 #include "allheaders.h"
63 
64 static l_int32 dewarpaTestForValidModel(L_DEWARPA *dewa, L_DEWARP *dew,
65  l_int32 notests);
66 
67 #ifndef NO_CONSOLE_IO
68 #define DEBUG_INVALID_MODELS 0 /* set this to 1 for debugging */
69 #endif /* !NO_CONSOLE_IO */
70 
71  /* Special parameter value */
72 static const l_int32 GrayInValue = 200;
73 
74 /*----------------------------------------------------------------------*
75  * Top-level single page dewarper *
76  *----------------------------------------------------------------------*/
99 l_ok
101  l_int32 thresh,
102  l_int32 adaptive,
103  l_int32 useboth,
104  l_int32 check_columns,
105  PIX **ppixd,
106  L_DEWARPA **pdewa,
107  l_int32 debug)
108 {
109 L_DEWARPA *dewa;
110 PIX *pixb;
111 
112  if (!ppixd)
113  return ERROR_INT("&pixd not defined", __func__, 1);
114  *ppixd = NULL;
115  if (pdewa) *pdewa = NULL;
116  if (!pixs)
117  return ERROR_INT("pixs not defined", __func__, 1);
118 
119  dewarpSinglePageInit(pixs, thresh, adaptive, useboth,
120  check_columns, &pixb, &dewa);
121  if (!pixb) {
122  dewarpaDestroy(&dewa);
123  return ERROR_INT("pixb not made", __func__, 1);
124  }
125 
126  dewarpSinglePageRun(pixs, pixb, dewa, ppixd, debug);
127 
128  if (pdewa)
129  *pdewa = dewa;
130  else
131  dewarpaDestroy(&dewa);
132  pixDestroy(&pixb);
133  return 0;
134 }
135 
136 
165 l_ok
167  l_int32 thresh,
168  l_int32 adaptive,
169  l_int32 useboth,
170  l_int32 check_columns,
171  PIX **ppixb,
172  L_DEWARPA **pdewa)
173 {
174 PIX *pix1, *pix2;
175 
176  if (ppixb) *ppixb = NULL;
177  if (pdewa) *pdewa = NULL;
178  if (!ppixb || !pdewa)
179  return ERROR_INT("&pixb and &dewa not both defined", __func__, 1);
180  if (!pixs)
181  return ERROR_INT("pixs not defined", __func__, 1);
182 
183  /* Generate a binary image, if necessary */
184  if (pixGetDepth(pixs) > 1) {
185  if ((pix1 = pixConvertTo8(pixs, 0)) == NULL)
186  return ERROR_INT("pix1 not made", __func__, 1);
187  if (adaptive)
188  pix2 = pixAdaptThresholdToBinary(pix1, NULL, 1.0);
189  else
190  pix2 = pixThresholdToBinary(pix1, thresh);
191  pixDestroy(&pix1);
192  if (!pix2)
193  return ERROR_INT("pix2 not made", __func__, 1);
194  *ppixb = pix2;
195  } else {
196  *ppixb = pixClone(pixs);
197  }
198 
199  *pdewa = dewarpaCreate(1, 0, 1, 0, -1);
200  dewarpaUseBothArrays(*pdewa, useboth);
201  dewarpaSetCheckColumns(*pdewa, check_columns);
202  return 0;
203 }
204 
205 
225 l_ok
227  PIX *pixb,
228  L_DEWARPA *dewa,
229  PIX **ppixd,
230  l_int32 debug)
231 {
232 const char *debugfile;
233 l_int32 vsuccess, ret;
234 L_DEWARP *dew;
235 
236  if (!ppixd)
237  return ERROR_INT("&pixd not defined", __func__, 1);
238  *ppixd = NULL;
239  if (!pixs)
240  return ERROR_INT("pixs not defined", __func__, 1);
241  if (!pixb)
242  return ERROR_INT("pixb not defined", __func__, 1);
243  if (!dewa)
244  return ERROR_INT("dewa not defined", __func__, 1);
245 
246  if (debug)
247  lept_mkdir("lept/dewarp");
248 
249  /* Generate the page model */
250  dew = dewarpCreate(pixb, 0);
251  dewarpaInsertDewarp(dewa, dew);
252  debugfile = (debug) ? "/tmp/lept/dewarp/singlepage_model.pdf" : NULL;
253  dewarpBuildPageModel(dew, debugfile);
254  dewarpaModelStatus(dewa, 0, &vsuccess, NULL);
255  if (vsuccess == 0) {
256  L_ERROR("failure to build model for vertical disparity\n", __func__);
257  *ppixd = pixCopy(NULL, pixs);
258  return 0;
259  }
260 
261  /* Apply the page model */
262  debugfile = (debug) ? "/tmp/lept/dewarp/singlepage_apply.pdf" : NULL;
263  ret = dewarpaApplyDisparity(dewa, 0, pixs, 255, 0, 0, ppixd, debugfile);
264  if (ret)
265  L_ERROR("invalid model; failure to apply disparity\n", __func__);
266  return 0;
267 }
268 
269 
270 /*----------------------------------------------------------------------*
271  * Operations on dewarpa *
272  *----------------------------------------------------------------------*/
289 l_ok
291 {
292 l_int32 i;
293 L_DEWARP *dew;
294 NUMA *namodels, *napages;
295 
296  if (!dewa)
297  return ERROR_INT("dewa not defined", __func__, 1);
298 
299  numaDestroy(&dewa->namodels);
300  numaDestroy(&dewa->napages);
301  namodels = numaCreate(dewa->maxpage + 1);
302  napages = numaCreate(dewa->maxpage + 1);
303  dewa->namodels = namodels;
304  dewa->napages = napages;
305  for (i = 0; i <= dewa->maxpage; i++) {
306  if ((dew = dewarpaGetDewarp(dewa, i)) != NULL) {
307  if (dew->hasref == 0)
308  numaAddNumber(namodels, dew->pageno);
309  numaAddNumber(napages, dew->pageno);
310  }
311  }
312  return 0;
313 }
314 
315 
339 l_ok
341  l_int32 notests,
342  l_int32 debug)
343 {
344 l_int32 i, n, maxcurv, diffcurv, diffedge;
345 L_DEWARP *dew;
346 
347  if (!dewa)
348  return ERROR_INT("dewa not defined", __func__, 1);
349 
350  n = dewa->maxpage + 1;
351  for (i = 0; i < n; i++) {
352  if ((dew = dewarpaGetDewarp(dewa, i)) == NULL)
353  continue;
354 
355  if (debug) {
356  if (dew->hasref == 1) {
357  L_INFO("page %d: has only a ref model\n", __func__, i);
358  } else if (dew->vsuccess == 0) {
359  L_INFO("page %d: no model successfully built\n",
360  __func__, i);
361  } else if (!notests) {
362  maxcurv = L_MAX(L_ABS(dew->mincurv), L_ABS(dew->maxcurv));
363  diffcurv = dew->maxcurv - dew->mincurv;
364  if (dewa->useboth && !dew->hsuccess)
365  L_INFO("page %d: useboth, but no horiz disparity\n",
366  __func__, i);
367  if (maxcurv > dewa->max_linecurv)
368  L_INFO("page %d: max curvature %d > max_linecurv\n",
369  __func__, i, diffcurv);
370  if (diffcurv < dewa->min_diff_linecurv)
371  L_INFO("page %d: diff curv %d < min_diff_linecurv\n",
372  __func__, i, diffcurv);
373  if (diffcurv > dewa->max_diff_linecurv)
374  L_INFO("page %d: abs diff curv %d > max_diff_linecurv\n",
375  __func__, i, diffcurv);
376  if (dew->hsuccess) {
377  if (L_ABS(dew->leftslope) > dewa->max_edgeslope)
378  L_INFO("page %d: abs left slope %d > max_edgeslope\n",
379  __func__, i, dew->leftslope);
380  if (L_ABS(dew->rightslope) > dewa->max_edgeslope)
381  L_INFO("page %d: abs right slope %d > max_edgeslope\n",
382  __func__, i, dew->rightslope);
383  diffedge = L_ABS(dew->leftcurv - dew->rightcurv);
384  if (L_ABS(dew->leftcurv) > dewa->max_edgecurv)
385  L_INFO("page %d: left curvature %d > max_edgecurv\n",
386  __func__, i, dew->leftcurv);
387  if (L_ABS(dew->rightcurv) > dewa->max_edgecurv)
388  L_INFO("page %d: right curvature %d > max_edgecurv\n",
389  __func__, i, dew->rightcurv);
390  if (diffedge > dewa->max_diff_edgecurv)
391  L_INFO("page %d: abs diff left-right curv %d > "
392  "max_diff_edgecurv\n", __func__, i, diffedge);
393  }
394  }
395  }
396 
397  dewarpaTestForValidModel(dewa, dew, notests);
398  }
399 
400  return 0;
401 }
402 
403 
443 l_ok
445  l_int32 notests,
446  l_int32 debug)
447 {
448 l_int32 i, j, n, val, min, distdown, distup;
449 L_DEWARP *dew;
450 NUMA *na, *nah;
451 
452  if (!dewa)
453  return ERROR_INT("dewa not defined", __func__, 1);
454  if (dewa->maxdist < 2)
455  L_INFO("maxdist < 2; no ref models can be used\n", __func__);
456 
457  /* Make an indicator numa for pages with valid models. */
458  dewarpaSetValidModels(dewa, notests, debug);
459  n = dewa->maxpage + 1;
460  na = numaMakeConstant(0, n);
461  for (i = 0; i < n; i++) {
462  dew = dewarpaGetDewarp(dewa, i);
463  if (dew && dew->vvalid)
464  numaReplaceNumber(na, i, 1);
465  }
466 
467  /* Remove all existing ref models and restore models from cache */
468  dewarpaRestoreModels(dewa);
469 
470  /* Move invalid models to the cache, and insert reference dewarps
471  * for pages that need to borrow a model.
472  * First, try to find a valid model for each page. */
473  for (i = 0; i < n; i++) {
474  numaGetIValue(na, i, &val);
475  if (val == 1) continue; /* already has a valid model */
476  if ((dew = dewa->dewarp[i]) != NULL) { /* exists but is not valid; */
477  dewa->dewarpcache[i] = dew; /* move it to the cache */
478  dewa->dewarp[i] = NULL;
479  }
480  if (dewa->maxdist < 2) continue; /* can't use a ref model */
481  /* Look back for nearest model */
482  distdown = distup = dewa->maxdist + 1;
483  for (j = i - 2; j >= 0 && distdown > dewa->maxdist; j -= 2) {
484  numaGetIValue(na, j, &val);
485  if (val == 1) distdown = i - j;
486  }
487  /* Look ahead for nearest model */
488  for (j = i + 2; j < n && distup > dewa->maxdist; j += 2) {
489  numaGetIValue(na, j, &val);
490  if (val == 1) distup = j - i;
491  }
492  min = L_MIN(distdown, distup);
493  if (min > dewa->maxdist) continue; /* no valid model in range */
494  if (distdown <= distup)
495  dewarpaInsertDewarp(dewa, dewarpCreateRef(i, i - distdown));
496  else
497  dewarpaInsertDewarp(dewa, dewarpCreateRef(i, i + distup));
498  }
499  numaDestroy(&na);
500 
501  /* If a valid model will do, we're finished. */
502  if (dewa->useboth == 0) {
503  dewa->modelsready = 1; /* validated */
504  return 0;
505  }
506 
507  /* The request is useboth == 1. Now try to find an hvalid model */
508  nah = numaMakeConstant(0, n);
509  for (i = 0; i < n; i++) {
510  dew = dewarpaGetDewarp(dewa, i);
511  if (dew && dew->hvalid)
512  numaReplaceNumber(nah, i, 1);
513  }
514  for (i = 0; i < n; i++) {
515  numaGetIValue(nah, i, &val);
516  if (val == 1) continue; /* already has a hvalid model */
517  if (dewa->maxdist < 2) continue; /* can't use a ref model */
518  distdown = distup = 100000;
519  for (j = i - 2; j >= 0; j -= 2) { /* look back for nearest model */
520  numaGetIValue(nah, j, &val);
521  if (val == 1) {
522  distdown = i - j;
523  break;
524  }
525  }
526  for (j = i + 2; j < n; j += 2) { /* look ahead for nearest model */
527  numaGetIValue(nah, j, &val);
528  if (val == 1) {
529  distup = j - i;
530  break;
531  }
532  }
533  min = L_MIN(distdown, distup);
534  if (min > dewa->maxdist) continue; /* no hvalid model within range */
535 
536  /* We can replace the existing valid model with an hvalid model.
537  * If it's not a reference, save it in the cache. */
538  if ((dew = dewarpaGetDewarp(dewa, i)) == NULL) {
539  L_ERROR("dew is null for page %d!\n", __func__, i);
540  } else {
541  if (dew->hasref == 0) { /* not a ref model */
542  dewa->dewarpcache[i] = dew; /* move it to the cache */
543  dewa->dewarp[i] = NULL; /* must null the ptr */
544  }
545  }
546  if (distdown <= distup) /* insert the hvalid ref model */
547  dewarpaInsertDewarp(dewa, dewarpCreateRef(i, i - distdown));
548  else
549  dewarpaInsertDewarp(dewa, dewarpCreateRef(i, i + distup));
550  }
551  numaDestroy(&nah);
552 
553  dewa->modelsready = 1; /* validated */
554  return 0;
555 }
556 
557 
572 l_ok
574 {
575 l_int32 i;
576 L_DEWARP *dew;
577 
578  if (!dewa)
579  return ERROR_INT("dewa not defined", __func__, 1);
580 
581  for (i = 0; i <= dewa->maxpage; i++) {
582  if ((dew = dewarpaGetDewarp(dewa, i)) != NULL) {
583  if (dew->hasref)
584  dewarpDestroy(&dewa->dewarp[i]);
585  }
586  }
587  dewa->modelsready = 0;
588 
589  /* Regenerate the page lists */
590  dewarpaListPages(dewa);
591  return 0;
592 }
593 
594 
611 l_ok
613 {
614 l_int32 i;
615 L_DEWARP *dew;
616 
617  if (!dewa)
618  return ERROR_INT("dewa not defined", __func__, 1);
619 
620  /* Strip out ref models. Then only real models will be in the
621  * primary dewarp array. */
622  dewarpaStripRefModels(dewa);
623 
624  /* The cache holds only real models, which are not necessarily valid. */
625  for (i = 0; i <= dewa->maxpage; i++) {
626  if ((dew = dewa->dewarpcache[i]) != NULL) {
627  if (dewa->dewarp[i]) {
628  L_ERROR("dew in both cache and main array!: page %d\n",
629  __func__, i);
630  } else {
631  dewa->dewarp[i] = dew;
632  dewa->dewarpcache[i] = NULL;
633  }
634  }
635  }
636  dewa->modelsready = 0; /* new ref models not yet inserted */
637 
638  /* Regenerate the page lists */
639  dewarpaListPages(dewa);
640  return 0;
641 }
642 
643 
644 /*----------------------------------------------------------------------*
645  * Dewarp debugging output *
646  *----------------------------------------------------------------------*/
654 l_ok
655 dewarpaInfo(FILE *fp,
656  L_DEWARPA *dewa)
657 {
658 l_int32 i, n, pageno, nnone, nvsuccess, nvvalid, nhsuccess, nhvalid, nref;
659 L_DEWARP *dew;
660 
661  if (!fp)
662  return ERROR_INT("dewa not defined", __func__, 1);
663  if (!dewa)
664  return ERROR_INT("dewa not defined", __func__, 1);
665 
666  fprintf(fp, "\nDewarpaInfo: %p\n", dewa);
667  fprintf(fp, "nalloc = %d, maxpage = %d\n", dewa->nalloc, dewa->maxpage);
668  fprintf(fp, "sampling = %d, redfactor = %d, minlines = %d\n",
669  dewa->sampling, dewa->redfactor, dewa->minlines);
670  fprintf(fp, "maxdist = %d, useboth = %d\n",
671  dewa->maxdist, dewa->useboth);
672 
673  dewarpaModelStats(dewa, &nnone, &nvsuccess, &nvvalid,
674  &nhsuccess, &nhvalid, &nref);
675  n = numaGetCount(dewa->napages);
676  lept_stderr("Total number of pages with a dew = %d\n", n);
677  lept_stderr("Number of pages without any models = %d\n", nnone);
678  lept_stderr("Number of pages with a vert model = %d\n", nvsuccess);
679  lept_stderr("Number of pages with a valid vert model = %d\n", nvvalid);
680  lept_stderr("Number of pages with both models = %d\n", nhsuccess);
681  lept_stderr("Number of pages with both models valid = %d\n", nhvalid);
682  lept_stderr("Number of pages with a ref model = %d\n", nref);
683 
684  for (i = 0; i < n; i++) {
685  numaGetIValue(dewa->napages, i, &pageno);
686  if ((dew = dewarpaGetDewarp(dewa, pageno)) == NULL)
687  continue;
688  lept_stderr("Page: %d\n", dew->pageno);
689  lept_stderr(" hasref = %d, refpage = %d\n",
690  dew->hasref, dew->refpage);
691  lept_stderr(" nlines = %d\n", dew->nlines);
692  lept_stderr(" w = %d, h = %d, nx = %d, ny = %d\n",
693  dew->w, dew->h, dew->nx, dew->ny);
694  if (dew->sampvdispar)
695  lept_stderr(" Vertical disparity builds:\n"
696  " (min,max,abs-diff) line curvature = (%d,%d,%d)\n",
697  dew->mincurv, dew->maxcurv, dew->maxcurv - dew->mincurv);
698  if (dew->samphdispar)
699  lept_stderr(" Horizontal disparity builds:\n"
700  " left edge slope = %d, right edge slope = %d\n"
701  " (left,right,abs-diff) edge curvature = (%d,%d,%d)\n",
702  dew->leftslope, dew->rightslope, dew->leftcurv,
703  dew->rightcurv, L_ABS(dew->leftcurv - dew->rightcurv));
704  }
705  return 0;
706 }
707 
708 
744 l_ok
746  l_int32 *pnnone,
747  l_int32 *pnvsuccess,
748  l_int32 *pnvvalid,
749  l_int32 *pnhsuccess,
750  l_int32 *pnhvalid,
751  l_int32 *pnref)
752 {
753 l_int32 i, n, pageno, nnone, nvsuccess, nvvalid, nhsuccess, nhvalid, nref;
754 L_DEWARP *dew;
755 
756  if (!dewa)
757  return ERROR_INT("dewa not defined", __func__, 1);
758 
759  dewarpaListPages(dewa);
760  n = numaGetCount(dewa->napages);
761  nnone = nref = nvsuccess = nvvalid = nhsuccess = nhvalid = 0;
762  for (i = 0; i < n; i++) {
763  numaGetIValue(dewa->napages, i, &pageno);
764  dew = dewarpaGetDewarp(dewa, pageno);
765  if (!dew) {
766  nnone++;
767  continue;
768  }
769  if (dew->hasref == 1)
770  nref++;
771  if (dew->vsuccess == 1)
772  nvsuccess++;
773  if (dew->hsuccess == 1)
774  nhsuccess++;
775  dewarpaTestForValidModel(dewa, dew, 0);
776  if (dew->vvalid == 1)
777  nvvalid++;
778  if (dew->hvalid == 1)
779  nhvalid++;
780  }
781 
782  if (pnnone) *pnnone = nnone;
783  if (pnref) *pnref = nref;
784  if (pnvsuccess) *pnvsuccess = nvsuccess;
785  if (pnvvalid) *pnvvalid = nvvalid;
786  if (pnhsuccess) *pnhsuccess = nhsuccess;
787  if (pnhvalid) *pnhvalid = nhvalid;
788  return 0;
789 }
790 
791 
810 static l_int32
812  L_DEWARP *dew,
813  l_int32 notests)
814 {
815 l_int32 maxcurv, diffcurv, diffedge;
816 
817  if (!dewa || !dew)
818  return ERROR_INT("dewa and dew not both defined", __func__, 1);
819 
820  if (notests) {
821  dew->vvalid = dew->vsuccess;
822  dew->hvalid = dew->hsuccess;
823  return 0;
824  }
825 
826  /* No actual model was built */
827  if (dew->vsuccess == 0) return 0;
828 
829  /* Was previously found not to have a valid model */
830  if (dew->hasref == 1) return 0;
831 
832  /* vsuccess == 1; a vertical (line) model exists.
833  * First test that the vertical curvatures are within allowed
834  * bounds. Note that all curvatures are signed.*/
835  maxcurv = L_MAX(L_ABS(dew->mincurv), L_ABS(dew->maxcurv));
836  diffcurv = dew->maxcurv - dew->mincurv;
837  if (maxcurv <= dewa->max_linecurv &&
838  diffcurv >= dewa->min_diff_linecurv &&
839  diffcurv <= dewa->max_diff_linecurv) {
840  dew->vvalid = 1;
841  } else {
842  L_INFO("invalid vert model for page %d:\n", __func__, dew->pageno);
843 #if DEBUG_INVALID_MODELS
844  lept_stderr(" max line curv = %d, max allowed = %d\n",
845  maxcurv, dewa->max_linecurv);
846  lept_stderr(" diff line curv = %d, max allowed = %d\n",
847  diffcurv, dewa->max_diff_linecurv);
848 #endif /* DEBUG_INVALID_MODELS */
849  }
850 
851  /* If a horizontal (edge) model exists, test for validity. */
852  if (dew->hsuccess) {
853  diffedge = L_ABS(dew->leftcurv - dew->rightcurv);
854  if (L_ABS(dew->leftslope) <= dewa->max_edgeslope &&
855  L_ABS(dew->rightslope) <= dewa->max_edgeslope &&
856  L_ABS(dew->leftcurv) <= dewa->max_edgecurv &&
857  L_ABS(dew->rightcurv) <= dewa->max_edgecurv &&
858  diffedge <= dewa->max_diff_edgecurv) {
859  dew->hvalid = 1;
860  } else {
861  L_INFO("invalid horiz model for page %d:\n", __func__, dew->pageno);
862 #if DEBUG_INVALID_MODELS
863  lept_stderr(" left edge slope = %d, max allowed = %d\n",
864  dew->leftslope, dewa->max_edgeslope);
865  lept_stderr(" right edge slope = %d, max allowed = %d\n",
866  dew->rightslope, dewa->max_edgeslope);
867  lept_stderr(" left edge curv = %d, max allowed = %d\n",
868  dew->leftcurv, dewa->max_edgecurv);
869  lept_stderr(" right edge curv = %d, max allowed = %d\n",
870  dew->rightcurv, dewa->max_edgecurv);
871  lept_stderr(" diff edge curv = %d, max allowed = %d\n",
872  diffedge, dewa->max_diff_edgecurv);
873 #endif /* DEBUG_INVALID_MODELS */
874  }
875  }
876 
877  return 0;
878 }
879 
880 
896 l_ok
898  l_float32 scalefact,
899  l_int32 first,
900  l_int32 last)
901 {
902 char buf[256];
903 l_int32 i, svd, shd;
904 L_BMF *bmf;
905 L_DEWARP *dew;
906 PIX *pixv, *pixvs, *pixh, *pixhs, *pixt, *pixd;
907 PIXA *pixa;
908 
909  if (!dewa)
910  return ERROR_INT("dew not defined", __func__, 1);
911  if (first < 0 || first > dewa->maxpage)
912  return ERROR_INT("first out of bounds", __func__, 1);
913  if (last <= 0 || last > dewa->maxpage) last = dewa->maxpage;
914  if (last < first)
915  return ERROR_INT("last < first", __func__, 1);
916 
917  lept_rmdir("lept/dewarp1"); /* temp directory for contour plots */
918  lept_mkdir("lept/dewarp1");
919  if ((bmf = bmfCreate(NULL, 8)) == NULL)
920  L_ERROR("bmf not made; page info not displayed", __func__);
921 
922  lept_stderr("Generating contour plots\n");
923  for (i = first; i <= last; i++) {
924  if (i && ((i % 10) == 0))
925  lept_stderr(" .. %d", i);
926  dew = dewarpaGetDewarp(dewa, i);
927  if (!dew) continue;
928  if (dew->hasref == 1) continue;
929  svd = shd = 0;
930  if (dew->sampvdispar) svd = 1;
931  if (dew->samphdispar) shd = 1;
932  if (!svd) {
933  L_ERROR("sampvdispar not made for page %d!\n", __func__, i);
934  continue;
935  }
936 
937  /* Generate contour plots at reduced resolution */
938  dewarpPopulateFullRes(dew, NULL, 0, 0);
939  pixv = fpixRenderContours(dew->fullvdispar, 3.0, 0.15);
940  pixvs = pixScaleBySampling(pixv, scalefact, scalefact);
941  pixDestroy(&pixv);
942  if (shd) {
943  pixh = fpixRenderContours(dew->fullhdispar, 3.0, 0.15);
944  pixhs = pixScaleBySampling(pixh, scalefact, scalefact);
945  pixDestroy(&pixh);
946  }
947  dewarpMinimize(dew);
948 
949  /* Save side-by-side */
950  pixa = pixaCreate(2);
951  pixaAddPix(pixa, pixvs, L_INSERT);
952  if (shd)
953  pixaAddPix(pixa, pixhs, L_INSERT);
954  pixt = pixaDisplayTiledInRows(pixa, 32, 1500, 1.0, 0, 30, 2);
955  snprintf(buf, sizeof(buf), "Page %d", i);
956  pixd = pixAddSingleTextblock(pixt, bmf, buf, 0x0000ff00,
957  L_ADD_BELOW, NULL);
958  snprintf(buf, sizeof(buf), "/tmp/lept/dewarp1/arrays_%04d.png", i);
959  pixWriteDebug(buf, pixd, IFF_PNG);
960  pixaDestroy(&pixa);
961  pixDestroy(&pixt);
962  pixDestroy(&pixd);
963  }
964  bmfDestroy(&bmf);
965  lept_stderr("\n");
966 
967  lept_stderr("Generating pdf of contour plots\n");
968  convertFilesToPdf("/tmp/lept/dewarp1", "arrays_", 90, 1.0, L_FLATE_ENCODE,
969  0, "Disparity arrays", "/tmp/lept/disparity_arrays.pdf");
970  lept_stderr("Output written to: /tmp/lept/disparity_arrays.pdf\n");
971  return 0;
972 }
973 
974 
990 l_ok
992  const char *subdirs,
993  l_int32 index)
994 {
995 char fname[256];
996 char *outdir;
997 l_int32 svd, shd;
998 PIX *pixv, *pixh;
999 
1000  if (!dew)
1001  return ERROR_INT("dew not defined", __func__, 1);
1002  if (!subdirs)
1003  return ERROR_INT("subdirs not defined", __func__, 1);
1004 
1005  lept_stderr("pageno = %d, hasref = %d, refpage = %d\n",
1006  dew->pageno, dew->hasref, dew->refpage);
1007  lept_stderr("sampling = %d, redfactor = %d, minlines = %d\n",
1008  dew->sampling, dew->redfactor, dew->minlines);
1009  svd = shd = 0;
1010  if (!dew->hasref) {
1011  if (dew->sampvdispar) svd = 1;
1012  if (dew->samphdispar) shd = 1;
1013  lept_stderr("sampv = %d, samph = %d\n", svd, shd);
1014  lept_stderr("w = %d, h = %d\n", dew->w, dew->h);
1015  lept_stderr("nx = %d, ny = %d\n", dew->nx, dew->ny);
1016  lept_stderr("nlines = %d\n", dew->nlines);
1017  if (svd) {
1018  lept_stderr("(min,max,abs-diff) line curvature = (%d,%d,%d)\n",
1019  dew->mincurv, dew->maxcurv, dew->maxcurv - dew->mincurv);
1020  }
1021  if (shd) {
1022  lept_stderr("(left edge slope = %d, right edge slope = %d\n",
1023  dew->leftslope, dew->rightslope);
1024  lept_stderr("(left,right,abs-diff) edge curvature = "
1025  "(%d,%d,%d)\n", dew->leftcurv, dew->rightcurv,
1026  L_ABS(dew->leftcurv - dew->rightcurv));
1027  }
1028  }
1029  if (!svd && !shd) {
1030  lept_stderr("No disparity arrays\n");
1031  return 0;
1032  }
1033 
1034  dewarpPopulateFullRes(dew, NULL, 0, 0);
1035  lept_mkdir(subdirs);
1036  outdir = pathJoin("/tmp", subdirs);
1037  if (svd) {
1038  pixv = fpixRenderContours(dew->fullvdispar, 3.0, 0.15);
1039  snprintf(fname, sizeof(fname), "%s/pixv_%d.png", outdir, index);
1040  pixWriteDebug(fname, pixv, IFF_PNG);
1041  pixDestroy(&pixv);
1042  }
1043  if (shd) {
1044  pixh = fpixRenderContours(dew->fullhdispar, 3.0, 0.15);
1045  snprintf(fname, sizeof(fname), "%s/pixh_%d.png", outdir, index);
1046  pixWriteDebug(fname, pixh, IFF_PNG);
1047  pixDestroy(&pixh);
1048  }
1049  LEPT_FREE(outdir);
1050  return 0;
1051 }
1052 
1053 
1075 l_ok
1077  SARRAY *sa,
1078  BOXA *boxa,
1079  l_int32 firstpage,
1080  l_int32 lastpage,
1081  const char *pdfout)
1082 {
1083 char bufstr[256];
1084 l_int32 i, modelpage;
1085 L_BMF *bmf;
1086 BOX *box;
1087 L_DEWARP *dew;
1088 PIX *pixs, *pixc, *pixd, *pixt1, *pixt2;
1089 PIXA *pixa;
1090 
1091  if (!dewa)
1092  return ERROR_INT("dewa not defined", __func__, 1);
1093  if (!sa)
1094  return ERROR_INT("sa not defined", __func__, 1);
1095  if (!pdfout)
1096  return ERROR_INT("pdfout not defined", __func__, 1);
1097  if (firstpage > lastpage)
1098  return ERROR_INT("invalid first/last page numbers", __func__, 1);
1099 
1100  lept_rmdir("lept/dewarp_pdfout");
1101  lept_mkdir("lept/dewarp_pdfout");
1102  bmf = bmfCreate(NULL, 6);
1103 
1104  lept_stderr("Dewarping and generating s/by/s view\n");
1105  for (i = firstpage; i <= lastpage; i++) {
1106  if (i && (i % 10 == 0)) lept_stderr(".. %d ", i);
1107  pixs = pixReadIndexed(sa, i);
1108  if (boxa) {
1109  box = boxaGetBox(boxa, i, L_CLONE);
1110  pixc = pixClipRectangle(pixs, box, NULL);
1111  boxDestroy(&box);
1112  }
1113  else
1114  pixc = pixClone(pixs);
1115  dew = dewarpaGetDewarp(dewa, i);
1116  pixd = NULL;
1117  if (dew) {
1118  dewarpaApplyDisparity(dewa, dew->pageno, pixc,
1119  GrayInValue, 0, 0, &pixd, NULL);
1120  dewarpMinimize(dew);
1121  }
1122  pixa = pixaCreate(2);
1123  pixaAddPix(pixa, pixc, L_INSERT);
1124  if (pixd)
1125  pixaAddPix(pixa, pixd, L_INSERT);
1126  pixt1 = pixaDisplayTiledAndScaled(pixa, 32, 500, 2, 0, 35, 2);
1127  if (dew) {
1128  modelpage = (dew->hasref) ? dew->refpage : dew->pageno;
1129  snprintf(bufstr, sizeof(bufstr), "Page %d; using %d\n",
1130  i, modelpage);
1131  }
1132  else
1133  snprintf(bufstr, sizeof(bufstr), "Page %d; no dewarp\n", i);
1134  pixt2 = pixAddSingleTextblock(pixt1, bmf, bufstr, 0x0000ff00,
1135  L_ADD_BELOW, 0);
1136  snprintf(bufstr, sizeof(bufstr), "/tmp/lept/dewarp_pdfout/%05d", i);
1137  pixWriteDebug(bufstr, pixt2, IFF_JFIF_JPEG);
1138  pixaDestroy(&pixa);
1139  pixDestroy(&pixs);
1140  pixDestroy(&pixt1);
1141  pixDestroy(&pixt2);
1142  }
1143  lept_stderr("\n");
1144 
1145  lept_stderr("Generating pdf of result\n");
1146  convertFilesToPdf("/tmp/lept/dewarp_pdfout", NULL, 100, 1.0, L_JPEG_ENCODE,
1147  0, "Dewarp sequence", pdfout);
1148  lept_stderr("Output written to: %s\n", pdfout);
1149  bmfDestroy(&bmf);
1150  return 0;
1151 }
void bmfDestroy(L_BMF **pbmf)
bmfDestroy()
Definition: bmf.c:168
L_BMF * bmfCreate(const char *dir, l_int32 fontsize)
bmfCreate()
Definition: bmf.c:118
void boxDestroy(BOX **pbox)
boxDestroy()
Definition: boxbasic.c:273
BOX * boxaGetBox(BOXA *boxa, l_int32 index, l_int32 accessflag)
boxaGetBox()
Definition: boxbasic.c:702
l_ok dewarpaUseBothArrays(L_DEWARPA *dewa, l_int32 useboth)
dewarpaUseBothArrays()
Definition: dewarp1.c:1024
L_DEWARP * dewarpCreateRef(l_int32 pageno, l_int32 refpage)
dewarpCreateRef()
Definition: dewarp1.c:496
void dewarpaDestroy(L_DEWARPA **pdewa)
dewarpaDestroy()
Definition: dewarp1.c:722
l_ok dewarpaInsertDewarp(L_DEWARPA *dewa, L_DEWARP *dew)
dewarpaInsertDewarp()
Definition: dewarp1.c:800
void dewarpDestroy(L_DEWARP **pdew)
dewarpDestroy()
Definition: dewarp1.c:516
l_ok dewarpaSetCheckColumns(L_DEWARPA *dewa, l_int32 check_columns)
dewarpaSetCheckColumns()
Definition: dewarp1.c:1061
L_DEWARP * dewarpaGetDewarp(L_DEWARPA *dewa, l_int32 index)
dewarpaGetDewarp()
Definition: dewarp1.c:895
L_DEWARPA * dewarpaCreate(l_int32 nptrs, l_int32 sampling, l_int32 redfactor, l_int32 minlines, l_int32 maxdist)
dewarpaCreate()
Definition: dewarp1.c:576
L_DEWARP * dewarpCreate(PIX *pixs, l_int32 pageno)
dewarpCreate()
Definition: dewarp1.c:459
l_ok dewarpBuildPageModel(L_DEWARP *dew, const char *debugfile)
dewarpBuildPageModel()
Definition: dewarp2.c:156
l_ok dewarpaModelStatus(L_DEWARPA *dewa, l_int32 pageno, l_int32 *pvsuccess, l_int32 *phsuccess)
dewarpaModelStatus()
Definition: dewarp2.c:1892
l_ok dewarpaApplyDisparity(L_DEWARPA *dewa, l_int32 pageno, PIX *pixs, l_int32 grayin, l_int32 x, l_int32 y, PIX **ppixd, const char *debugfile)
dewarpaApplyDisparity()
Definition: dewarp3.c:116
l_ok dewarpMinimize(L_DEWARP *dew)
dewarpMinimize()
Definition: dewarp3.c:719
l_ok dewarpPopulateFullRes(L_DEWARP *dew, PIX *pix, l_int32 x, l_int32 y)
dewarpPopulateFullRes()
Definition: dewarp3.c:773
l_ok dewarpaStripRefModels(L_DEWARPA *dewa)
dewarpaStripRefModels()
Definition: dewarp4.c:573
l_ok dewarpaInfo(FILE *fp, L_DEWARPA *dewa)
dewarpaInfo()
Definition: dewarp4.c:655
l_ok dewarpSinglePageRun(PIX *pixs, PIX *pixb, L_DEWARPA *dewa, PIX **ppixd, l_int32 debug)
dewarpSinglePageRun()
Definition: dewarp4.c:226
l_ok dewarpaShowArrays(L_DEWARPA *dewa, l_float32 scalefact, l_int32 first, l_int32 last)
dewarpaShowArrays()
Definition: dewarp4.c:897
l_ok dewarpaListPages(L_DEWARPA *dewa)
dewarpaListPages()
Definition: dewarp4.c:290
l_ok dewarpaSetValidModels(L_DEWARPA *dewa, l_int32 notests, l_int32 debug)
dewarpaSetValidModels()
Definition: dewarp4.c:340
l_ok dewarpDebug(L_DEWARP *dew, const char *subdirs, l_int32 index)
dewarpDebug()
Definition: dewarp4.c:991
l_ok dewarpaModelStats(L_DEWARPA *dewa, l_int32 *pnnone, l_int32 *pnvsuccess, l_int32 *pnvvalid, l_int32 *pnhsuccess, l_int32 *pnhvalid, l_int32 *pnref)
dewarpaModelStats()
Definition: dewarp4.c:745
l_ok dewarpSinglePage(PIX *pixs, l_int32 thresh, l_int32 adaptive, l_int32 useboth, l_int32 check_columns, PIX **ppixd, L_DEWARPA **pdewa, l_int32 debug)
dewarpSinglePage()
Definition: dewarp4.c:100
l_ok dewarpaInsertRefModels(L_DEWARPA *dewa, l_int32 notests, l_int32 debug)
dewarpaInsertRefModels()
Definition: dewarp4.c:444
l_ok dewarpaRestoreModels(L_DEWARPA *dewa)
dewarpaRestoreModels()
Definition: dewarp4.c:612
l_ok dewarpSinglePageInit(PIX *pixs, l_int32 thresh, l_int32 adaptive, l_int32 useboth, l_int32 check_columns, PIX **ppixb, L_DEWARPA **pdewa)
dewarpSinglePageInit()
Definition: dewarp4.c:166
l_ok dewarpShowResults(L_DEWARPA *dewa, SARRAY *sa, BOXA *boxa, l_int32 firstpage, l_int32 lastpage, const char *pdfout)
dewarpShowResults()
Definition: dewarp4.c:1076
static l_int32 dewarpaTestForValidModel(L_DEWARPA *dewa, L_DEWARP *dew, l_int32 notests)
dewarpaTestForValidModel()
Definition: dewarp4.c:811
PIX * fpixRenderContours(FPIX *fpixs, l_float32 incr, l_float32 proxim)
fpixRenderContours()
Definition: graphics.c:2720
PIX * pixAdaptThresholdToBinary(PIX *pixs, PIX *pixm, l_float32 gamma)
pixAdaptThresholdToBinary()
Definition: grayquant.c:720
PIX * pixThresholdToBinary(PIX *pixs, l_int32 thresh)
pixThresholdToBinary()
Definition: grayquant.c:443
@ L_FLATE_ENCODE
Definition: imageio.h:161
@ L_JPEG_ENCODE
Definition: imageio.h:159
l_ok numaAddNumber(NUMA *na, l_float32 val)
numaAddNumber()
Definition: numabasic.c:460
l_ok numaReplaceNumber(NUMA *na, l_int32 index, l_float32 val)
numaReplaceNumber()
Definition: numabasic.c:601
NUMA * numaCreate(l_int32 n)
numaCreate()
Definition: numabasic.c:193
void numaDestroy(NUMA **pna)
numaDestroy()
Definition: numabasic.c:357
l_int32 numaGetCount(NUMA *na)
numaGetCount()
Definition: numabasic.c:630
l_ok numaGetIValue(NUMA *na, l_int32 index, l_int32 *pival)
numaGetIValue()
Definition: numabasic.c:720
NUMA * numaMakeConstant(l_float32 val, l_int32 size)
numaMakeConstant()
Definition: numafunc1.c:820
l_ok convertFilesToPdf(const char *dirname, const char *substr, l_int32 res, l_float32 scalefactor, l_int32 type, l_int32 quality, const char *title, const char *fileout)
convertFilesToPdf()
Definition: pdfio1.c:252
void pixDestroy(PIX **ppix)
pixDestroy()
Definition: pix1.c:608
PIX * pixCopy(PIX *pixd, const PIX *pixs)
pixCopy()
Definition: pix1.c:689
PIX * pixClone(PIX *pixs)
pixClone()
Definition: pix1.c:582
PIX * pixClipRectangle(PIX *pixs, BOX *box, BOX **pboxc)
pixClipRectangle()
Definition: pix5.c:994
@ L_ADD_BELOW
Definition: pix.h:1003
@ L_CLONE
Definition: pix.h:506
@ L_INSERT
Definition: pix.h:504
l_ok pixaAddPix(PIXA *pixa, PIX *pix, l_int32 copyflag)
pixaAddPix()
Definition: pixabasic.c:493
void pixaDestroy(PIXA **ppixa)
pixaDestroy()
Definition: pixabasic.c:404
PIXA * pixaCreate(l_int32 n)
pixaCreate()
Definition: pixabasic.c:167
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:730
PIX * pixaDisplayTiledAndScaled(PIXA *pixa, l_int32 outdepth, l_int32 tilewidth, l_int32 ncols, l_int32 background, l_int32 spacing, l_int32 border)
pixaDisplayTiledAndScaled()
Definition: pixafunc2.c:1025
PIX * pixConvertTo8(PIX *pixs, l_int32 cmapflag)
pixConvertTo8()
Definition: pixconv.c:3055
PIX * pixReadIndexed(SARRAY *sa, l_int32 index)
pixReadIndexed()
Definition: readfile.c:273
PIX * pixScaleBySampling(PIX *pixs, l_float32 scalex, l_float32 scaley)
pixScaleBySampling()
Definition: scale1.c:1306
Definition: bmf.h:47
l_int32 minlines
Definition: dewarp.h:168
struct FPix * fullvdispar
Definition: dewarp.h:158
l_int32 mincurv
Definition: dewarp.h:170
l_int32 pageno
Definition: dewarp.h:165
l_int32 vsuccess
Definition: dewarp.h:180
l_int32 hasref
Definition: dewarp.h:178
l_int32 h
Definition: dewarp.h:164
l_int32 sampling
Definition: dewarp.h:166
l_int32 hsuccess
Definition: dewarp.h:181
l_int32 leftcurv
Definition: dewarp.h:174
l_int32 vvalid
Definition: dewarp.h:183
l_int32 w
Definition: dewarp.h:163
l_int32 redfactor
Definition: dewarp.h:167
l_int32 nx
Definition: dewarp.h:176
l_int32 nlines
Definition: dewarp.h:169
l_int32 hvalid
Definition: dewarp.h:184
l_int32 maxcurv
Definition: dewarp.h:171
l_int32 refpage
Definition: dewarp.h:179
struct FPix * fullhdispar
Definition: dewarp.h:159
struct FPix * sampvdispar
Definition: dewarp.h:155
l_int32 ny
Definition: dewarp.h:177
struct FPix * samphdispar
Definition: dewarp.h:156
l_int32 rightcurv
Definition: dewarp.h:175
l_int32 leftslope
Definition: dewarp.h:172
l_int32 rightslope
Definition: dewarp.h:173
l_int32 min_diff_linecurv
Definition: dewarp.h:129
l_int32 maxdist
Definition: dewarp.h:126
struct L_Dewarp ** dewarp
Definition: dewarp.h:117
l_int32 max_diff_linecurv
Definition: dewarp.h:131
l_int32 sampling
Definition: dewarp.h:124
l_int32 max_edgeslope
Definition: dewarp.h:133
l_int32 maxpage
Definition: dewarp.h:116
l_int32 max_edgecurv
Definition: dewarp.h:135
struct L_Dewarp ** dewarpcache
Definition: dewarp.h:118
l_int32 minlines
Definition: dewarp.h:125
l_int32 nalloc
Definition: dewarp.h:115
struct Numa * namodels
Definition: dewarp.h:119
l_int32 max_diff_edgecurv
Definition: dewarp.h:137
l_int32 max_linecurv
Definition: dewarp.h:127
struct Numa * napages
Definition: dewarp.h:121
l_int32 redfactor
Definition: dewarp.h:123
l_int32 modelsready
Definition: dewarp.h:144
l_int32 useboth
Definition: dewarp.h:139
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_rmdir(const char *subdir)
lept_rmdir()
Definition: utils2.c:2213
char * pathJoin(const char *dir, const char *fname)
pathJoin()
Definition: utils2.c:2873
l_int32 lept_mkdir(const char *subdir)
lept_mkdir()
Definition: utils2.c:2138