Leptonica 1.85.0
Image processing and image analysis suite
Loading...
Searching...
No Matches
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
64static 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 */
72static const l_int32 GrayInValue = 200;
73
74/*----------------------------------------------------------------------*
75 * Top-level single page dewarper *
76 *----------------------------------------------------------------------*/
99l_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{
109L_DEWARPA *dewa;
110PIX *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
165l_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{
174PIX *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
225l_ok
227 PIX *pixb,
228 L_DEWARPA *dewa,
229 PIX **ppixd,
230 l_int32 debug)
231{
232const char *debugfile;
233l_int32 vsuccess, ret;
234L_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 *----------------------------------------------------------------------*/
289l_ok
291{
292l_int32 i;
293L_DEWARP *dew;
294NUMA *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
339l_ok
341 l_int32 notests,
342 l_int32 debug)
343{
344l_int32 i, n, maxcurv, diffcurv, diffedge;
345L_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
443l_ok
445 l_int32 notests,
446 l_int32 debug)
447{
448l_int32 i, j, n, val, min, distdown, distup;
449L_DEWARP *dew;
450NUMA *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 */
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
572l_ok
574{
575l_int32 i;
576L_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
611l_ok
613{
614l_int32 i;
615L_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. */
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 *----------------------------------------------------------------------*/
654l_ok
655dewarpaInfo(FILE *fp,
656 L_DEWARPA *dewa)
657{
658l_int32 i, n, pageno, nnone, nvsuccess, nvvalid, nhsuccess, nhvalid, nref;
659L_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
744l_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{
753l_int32 i, n, pageno, nnone, nvsuccess, nvvalid, nhsuccess, nhvalid, nref;
754L_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
810static l_int32
812 L_DEWARP *dew,
813 l_int32 notests)
814{
815l_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
896l_ok
898 l_float32 scalefact,
899 l_int32 first,
900 l_int32 last)
901{
902char buf[256];
903l_int32 i, svd, shd;
904L_BMF *bmf;
905L_DEWARP *dew;
906PIX *pixv, *pixvs, *pixh, *pixhs = NULL, *pixt, *pixd;
907PIXA *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.0f, 0.15f);
940 pixvs = pixScaleBySampling(pixv, scalefact, scalefact);
941 pixDestroy(&pixv);
942 if (shd) {
943 pixh = fpixRenderContours(dew->fullhdispar, 3.0f, 0.15f);
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
990l_ok
992 const char *subdirs,
993 l_int32 index)
994{
995char fname[256];
996char *outdir;
997l_int32 svd, shd;
998PIX *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.0f, 0.15f);
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.0f, 0.15f);
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
1075l_ok
1077 SARRAY *sa,
1078 BOXA *boxa,
1079 l_int32 firstpage,
1080 l_int32 lastpage,
1081 const char *pdfout)
1082{
1083char bufstr[256];
1084l_int32 i, modelpage;
1085L_BMF *bmf;
1086BOX *box;
1087L_DEWARP *dew;
1088PIX *pixs, *pixc, *pixd, *pixt1, *pixt2;
1089PIXA *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}
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
@ L_FLATE_ENCODE
Definition imageio.h:161
@ L_JPEG_ENCODE
Definition imageio.h:159
@ L_ADD_BELOW
Definition pix.h:1003
@ L_CLONE
Definition pix.h:506
@ L_INSERT
Definition pix.h:504
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