98 #include "allheaders.h" 101 static const l_float32 DEFAULT_SWEEP_RANGE = 7.;
102 static const l_float32 DEFAULT_SWEEP_DELTA = 1.;
108 static const l_float32 DEFAULT_MINBS_DELTA = 0.01;
111 static const l_int32 DEFAULT_SWEEP_REDUCTION = 4;
112 static const l_int32 DEFAULT_BS_REDUCTION = 2;
115 static const l_float32 MIN_DESKEW_ANGLE = 0.1;
118 static const l_float32 MIN_ALLOWED_CONFIDENCE = 3.0;
121 static const l_int32 MIN_VALID_MAXSCORE = 10000;
126 static const l_float32 MINSCORE_THRESHOLD_CONSTANT = 0.000002;
129 static const l_int32 DEFAULT_BINARY_THRESHOLD = 130;
131 #ifndef NO_CONSOLE_IO 132 #define DEBUG_PRINT_SCORES 0 133 #define DEBUG_PRINT_SWEEP 0 134 #define DEBUG_PRINT_BINARY 0 135 #define DEBUG_PRINT_ORTH 0 136 #define DEBUG_THRESHOLD 0 137 #define DEBUG_PLOT_SCORES 0 165 PIX *pix1, *pix2, *pix3, *pix4;
167 PROCNAME(
"pixDeskewBoth");
170 return (
PIX *)ERROR_PTR(
"pixs not defined", procName, NULL);
172 redsearch = DEFAULT_BS_REDUCTION;
173 else if (redsearch != 1 && redsearch != 2 && redsearch != 4)
174 return (
PIX *)ERROR_PTR(
"redsearch not in {1,2,4}", procName, NULL);
208 PROCNAME(
"pixDeskew");
211 return (
PIX *)ERROR_PTR(
"pixs not defined", procName, NULL);
213 redsearch = DEFAULT_BS_REDUCTION;
214 else if (redsearch != 1 && redsearch != 2 && redsearch != 4)
215 return (
PIX *)ERROR_PTR(
"redsearch not in {1,2,4}", procName, NULL);
246 PROCNAME(
"pixFindSkewAndDeskew");
249 return (
PIX *)ERROR_PTR(
"pixs not defined", procName, NULL);
251 redsearch = DEFAULT_BS_REDUCTION;
252 else if (redsearch != 1 && redsearch != 2 && redsearch != 4)
253 return (
PIX *)ERROR_PTR(
"redsearch not in {1,2,4}", procName, NULL);
287 l_float32 sweeprange,
288 l_float32 sweepdelta,
295 l_float32 angle, conf, deg2rad;
298 PROCNAME(
"pixDeskewGeneral");
300 if (pangle) *pangle = 0.0;
301 if (pconf) *pconf = 0.0;
303 return (
PIX *)ERROR_PTR(
"pixs not defined", procName, NULL);
305 redsweep = DEFAULT_SWEEP_REDUCTION;
306 else if (redsweep != 1 && redsweep != 2 && redsweep != 4)
307 return (
PIX *)ERROR_PTR(
"redsweep not in {1,2,4}", procName, NULL);
308 if (sweeprange == 0.0)
309 sweeprange = DEFAULT_SWEEP_RANGE;
310 if (sweepdelta == 0.0)
311 sweepdelta = DEFAULT_SWEEP_DELTA;
313 redsearch = DEFAULT_BS_REDUCTION;
314 else if (redsearch != 1 && redsearch != 2 && redsearch != 4)
315 return (
PIX *)ERROR_PTR(
"redsearch not in {1,2,4}", procName, NULL);
317 thresh = DEFAULT_BINARY_THRESHOLD;
319 deg2rad = 3.1415926535 / 180.;
322 depth = pixGetDepth(pixs);
330 sweeprange, sweepdelta,
331 DEFAULT_MINBS_DELTA);
333 if (pangle) *pangle = angle;
334 if (pconf) *pconf = conf;
338 if (L_ABS(angle) < MIN_DESKEW_ANGLE || conf < MIN_ALLOWED_CONFIDENCE)
374 PROCNAME(
"pixFindSkew");
376 if (pangle) *pangle = 0.0;
377 if (pconf) *pconf = 0.0;
378 if (!pangle || !pconf)
379 return ERROR_INT(
"&angle and/or &conf not defined", procName, 1);
381 return ERROR_INT(
"pixs not defined", procName, 1);
382 if (pixGetDepth(pixs) != 1)
383 return ERROR_INT(
"pixs not 1 bpp", procName, 1);
386 DEFAULT_SWEEP_REDUCTION,
387 DEFAULT_BS_REDUCTION,
390 DEFAULT_MINBS_DELTA);
417 l_float32 sweeprange,
418 l_float32 sweepdelta)
420 l_int32 ret, bzero, i, nangles;
421 l_float32 deg2rad, theta;
422 l_float32 sum, maxscore, maxangle;
423 NUMA *natheta, *nascore;
426 PROCNAME(
"pixFindSkewSweep");
429 return ERROR_INT(
"&angle not defined", procName, 1);
432 return ERROR_INT(
"pixs not defined", procName, 1);
433 if (pixGetDepth(pixs) != 1)
434 return ERROR_INT(
"pixs not 1 bpp", procName, 1);
435 if (reduction != 1 && reduction != 2 && reduction != 4 && reduction != 8)
436 return ERROR_INT(
"reduction must be in {1,2,4,8}", procName, 1);
438 deg2rad = 3.1415926535 / 180.;
444 else if (reduction == 2)
446 else if (reduction == 4)
457 nangles = (l_int32)((2. * sweeprange) / sweepdelta + 1);
463 ret = ERROR_INT(
"pix and pixt not both made", procName, 1);
466 if (!natheta || !nascore) {
467 ret = ERROR_INT(
"natheta and nascore not both made", procName, 1);
471 for (i = 0; i < nangles; i++) {
472 theta = -sweeprange + i * sweepdelta;
480 #if DEBUG_PRINT_SCORES 481 L_INFO(
"sum(%7.2f) = %7.0f\n", procName, theta, sum);
492 numaFitMax(nascore, &maxscore, natheta, &maxangle);
495 #if DEBUG_PRINT_SWEEP 496 L_INFO(
" From sweep: angle = %7.3f, score = %7.3f\n", procName,
500 #if DEBUG_PLOT_SCORES 511 "Sweep. Variance of difference of ON pixels vs. angle",
512 "angle (deg)",
"score");
513 gplotAddPlot(gplot, natheta, nascore, GPLOT_LINES,
"plot1");
514 gplotAddPlot(gplot, natheta, nascore, GPLOT_POINTS,
"plot2");
563 l_float32 sweeprange,
564 l_float32 sweepdelta,
565 l_float32 minbsdelta)
568 redsweep, redsearch, 0.0, sweeprange,
569 sweepdelta, minbsdelta);
615 l_float32 *pendscore,
618 l_float32 sweepcenter,
619 l_float32 sweeprange,
620 l_float32 sweepdelta,
621 l_float32 minbsdelta)
624 redsweep, redsearch, 0.0,
625 sweeprange, sweepdelta,
664 l_float32 *pendscore,
667 l_float32 sweepcenter,
668 l_float32 sweeprange,
669 l_float32 sweepdelta,
670 l_float32 minbsdelta,
673 l_int32 ret, bzero, i, nangles, n, ratio, maxindex, minloc;
674 l_int32 width, height;
675 l_float32 deg2rad, theta, delta;
676 l_float32 sum, maxscore, maxangle;
677 l_float32 centerangle, leftcenterangle, rightcenterangle;
678 l_float32 lefttemp, righttemp;
679 l_float32 bsearchscore[5];
680 l_float32 minscore, minthresh;
682 NUMA *natheta, *nascore;
683 PIX *pixsw, *pixsch, *pixt1, *pixt2;
685 PROCNAME(
"pixFindSkewSweepAndSearchScorePivot");
687 if (pendscore) *pendscore = 0.0;
688 if (pangle) *pangle = 0.0;
689 if (pconf) *pconf = 0.0;
690 if (!pangle || !pconf)
691 return ERROR_INT(
"&angle and/or &conf not defined", procName, 1);
692 if (!pixs || pixGetDepth(pixs) != 1)
693 return ERROR_INT(
"pixs not defined or not 1 bpp", procName, 1);
694 if (redsweep != 1 && redsweep != 2 && redsweep != 4 && redsweep != 8)
695 return ERROR_INT(
"redsweep must be in {1,2,4,8}", procName, 1);
696 if (redsearch != 1 && redsearch != 2 && redsearch != 4 && redsearch != 8)
697 return ERROR_INT(
"redsearch must be in {1,2,4,8}", procName, 1);
698 if (redsearch > redsweep)
699 return ERROR_INT(
"redsearch must not exceed redsweep", procName, 1);
701 return ERROR_INT(
"invalid pivot", procName, 1);
703 deg2rad = 3.1415926535 / 180.;
709 else if (redsearch == 2)
711 else if (redsearch == 4)
723 ratio = redsweep / redsearch;
741 nangles = (l_int32)((2. * sweeprange) / sweepdelta + 1);
745 if (!pixsch || !pixsw) {
746 ret = ERROR_INT(
"pixsch and pixsw not both made", procName, 1);
749 if (!pixt1 || !pixt2) {
750 ret = ERROR_INT(
"pixt1 and pixt2 not both made", procName, 1);
753 if (!natheta || !nascore) {
754 ret = ERROR_INT(
"natheta and nascore not both made", procName, 1);
759 rangeleft = sweepcenter - sweeprange;
760 for (i = 0; i < nangles; i++) {
761 theta = rangeleft + i * sweepdelta;
772 #if DEBUG_PRINT_SCORES 773 L_INFO(
"sum(%7.2f) = %7.0f\n", procName, theta, sum);
785 #if DEBUG_PRINT_SWEEP 786 L_INFO(
" From sweep: angle = %7.3f, score = %7.3f\n", procName,
790 #if DEBUG_PLOT_SCORES 795 "Sweep. Variance of difference of ON pixels vs. angle",
796 "angle (deg)",
"score");
797 gplotAddPlot(gplot, natheta, nascore, GPLOT_LINES,
"plot1");
798 gplotAddPlot(gplot, natheta, nascore, GPLOT_POINTS,
"plot2");
806 if (maxindex == 0 || maxindex == n - 1) {
807 L_WARNING(
"max found at sweep edge\n", procName);
817 centerangle = maxangle;
846 delta = 0.5 * sweepdelta;
847 while (delta >= minbsdelta)
850 leftcenterangle = centerangle - delta;
862 rightcenterangle = centerangle + delta;
876 maxscore = bsearchscore[1];
878 for (i = 2; i < 4; i++) {
879 if (bsearchscore[i] > maxscore) {
880 maxscore = bsearchscore[i];
886 lefttemp = bsearchscore[maxindex - 1];
887 righttemp = bsearchscore[maxindex + 1];
888 bsearchscore[2] = maxscore;
889 bsearchscore[0] = lefttemp;
890 bsearchscore[4] = righttemp;
893 centerangle = centerangle + delta * (maxindex - 2);
896 *pangle = centerangle;
898 #if DEBUG_PRINT_SCORES 899 L_INFO(
" Binary search score = %7.3f\n", procName, bsearchscore[2]);
903 *pendscore = bsearchscore[2];
917 width = pixGetWidth(pixsch);
918 height = pixGetHeight(pixsch);
919 minthresh = MINSCORE_THRESHOLD_CONSTANT * width * width * height;
922 L_INFO(
" minthresh = %10.2f, minscore = %10.2f\n", procName,
923 minthresh, minscore);
924 L_INFO(
" maxscore = %10.2f\n", procName, maxscore);
927 if (minscore > minthresh)
928 *pconf = maxscore / minscore;
934 if ((centerangle > rangeleft + 2 * sweeprange - sweepdelta) ||
935 (centerangle < rangeleft + sweepdelta) ||
936 (maxscore < MIN_VALID_MAXSCORE))
939 #if DEBUG_PRINT_BINARY 940 fprintf(stderr,
"Binary search: angle = %7.3f, score ratio = %6.2f\n",
942 fprintf(stderr,
" max score = %8.0f\n", maxscore);
945 #if DEBUG_PLOT_SCORES 952 "Binary search. Variance of difference of ON pixels vs. angle",
953 "angle (deg)",
"score");
954 gplotAddPlot(gplot, natheta, nascore, GPLOT_POINTS,
"plot1");
1032 pixFindSkewOrthogonalRange(
PIX *pixs,
1037 l_float32 sweeprange,
1038 l_float32 sweepdelta,
1039 l_float32 minbsdelta,
1040 l_float32 confprior)
1042 l_float32 angle1, conf1, score1, angle2, conf2, score2;
1045 PROCNAME(
"pixFindSkewOrthogonalRange");
1047 if (pangle) *pangle = 0.0;
1048 if (pconf) *pconf = 0.0;
1049 if (!pangle || !pconf)
1050 return ERROR_INT(
"&angle and/or &conf not defined", procName, 1);
1051 if (!pixs || pixGetDepth(pixs) != 1)
1052 return ERROR_INT(
"pixs not defined or not 1 bpp", procName, 1);
1055 redsweep, redsearch, 0.0,
1056 sweeprange, sweepdelta, minbsdelta,
1060 redsweep, redsearch, 0.0,
1061 sweeprange, sweepdelta, minbsdelta,
1065 if (conf1 > conf2 - confprior) {
1069 *pangle = -90.0 + angle2;
1073 #if DEBUG_PRINT_ORTH 1074 fprintf(stderr,
" About 0: angle1 = %7.3f, conf1 = %7.3f, score1 = %f\n",
1075 angle1, conf1, score1);
1076 fprintf(stderr,
" About 90: angle2 = %7.3f, conf2 = %7.3f, score2 = %f\n",
1077 angle2, conf2, score2);
1078 fprintf(stderr,
" Final: angle = %7.3f, conf = %7.3f\n", *pangle, *pconf);
1109 l_int32 w, h, skiph, skip, nskip;
1110 l_float32 val1, val2, diff, sum;
1113 PROCNAME(
"pixFindDifferentialSquareSum");
1116 return ERROR_INT(
"&sum not defined", procName, 1);
1119 return ERROR_INT(
"pixs not defined", procName, 1);
1124 return ERROR_INT(
"na not made", procName, 1);
1129 w = pixGetWidth(pixs);
1130 h = pixGetHeight(pixs);
1131 skiph = (l_int32)(0.05 * w);
1132 skip = L_MIN(h / 10, skiph);
1133 nskip = L_MAX(skip / 2, 1);
1139 for (i = nskip; i < n - nskip; i++) {
1183 l_int32 i, w, h, empty;
1184 l_float32 sum, sumsq, uniform, val;
1188 PROCNAME(
"pixFindNormalizedSquareSum");
1190 if (phratio) *phratio = 0.0;
1191 if (pvratio) *pvratio = 0.0;
1192 if (pfract) *pfract = 0.0;
1193 if (!phratio && !pvratio)
1194 return ERROR_INT(
"nothing to do", procName, 1);
1195 if (!pixs || pixGetDepth(pixs) != 1)
1196 return ERROR_INT(
"pixs not defined or not 1 bpp", procName, 1);
1203 if (pfract) *pfract = sum / (l_float32)(w * h);
1205 uniform = sum * sum / h;
1207 for (i = 0; i < h; i++) {
1211 *phratio = sumsq / uniform;
1219 if (empty == 1)
return 1;
1223 if (pfract) *pfract = sum / (l_float32)(w * h);
1225 uniform = sum * sum / w;
1227 for (i = 0; i < w; i++) {
1231 *pvratio = sumsq / uniform;
l_ok numaGetSum(NUMA *na, l_float32 *psum)
numaGetSum()
void gplotDestroy(GPLOT **pgplot)
gplotDestroy()
NUMA * pixCountPixelsByRow(PIX *pix, l_int32 *tab8)
pixCountPixelsByRow()
PIX * pixConvertTo1(PIX *pixs, l_int32 threshold)
pixConvertTo1()
l_ok numaGetFValue(NUMA *na, l_int32 index, l_float32 *pval)
numaGetFValue()
l_ok numaFitMax(NUMA *na, l_float32 *pmaxval, NUMA *naloc, l_float32 *pmaxloc)
numaFitMax()
PIX * pixDeskew(PIX *pixs, l_int32 redsearch)
pixDeskew()
l_ok gplotAddPlot(GPLOT *gplot, NUMA *nax, NUMA *nay, l_int32 plotstyle, const char *plottitle)
gplotAddPlot()
l_ok pixFindDifferentialSquareSum(PIX *pixs, l_float32 *psum)
pixFindDifferentialSquareSum()
l_ok numaAddNumber(NUMA *na, l_float32 val)
numaAddNumber()
l_ok gplotMakeOutput(GPLOT *gplot)
gplotMakeOutput()
GPLOT * gplotCreate(const char *rootname, l_int32 outformat, const char *title, const char *xlabel, const char *ylabel)
gplotCreate()
PIX * pixDeskewBoth(PIX *pixs, l_int32 redsearch)
pixDeskewBoth()
l_ok pixFindSkewSweep(PIX *pixs, l_float32 *pangle, l_int32 reduction, l_float32 sweeprange, l_float32 sweepdelta)
pixFindSkewSweep()
l_ok pixFindSkewSweepAndSearchScore(PIX *pixs, l_float32 *pangle, l_float32 *pconf, l_float32 *pendscore, l_int32 redsweep, l_int32 redsearch, l_float32 sweepcenter, l_float32 sweeprange, l_float32 sweepdelta, l_float32 minbsdelta)
pixFindSkewSweepAndSearchScore()
PIX * pixFindSkewAndDeskew(PIX *pixs, l_int32 redsearch, l_float32 *pangle, l_float32 *pconf)
pixFindSkewAndDeskew()
l_ok pixFindSkew(PIX *pixs, l_float32 *pangle, l_float32 *pconf)
pixFindSkew()
NUMA * numaCreate(l_int32 n)
numaCreate()
PIX * pixCreateTemplate(PIX *pixs)
pixCreateTemplate()
PIX * pixVShearCenter(PIX *pixd, PIX *pixs, l_float32 radang, l_int32 incolor)
pixVShearCenter()
PIX * pixVShearCorner(PIX *pixd, PIX *pixs, l_float32 radang, l_int32 incolor)
pixVShearCorner()
l_ok pixFindSkewSweepAndSearchScorePivot(PIX *pixs, l_float32 *pangle, l_float32 *pconf, l_float32 *pendscore, l_int32 redsweep, l_int32 redsearch, l_float32 sweepcenter, l_float32 sweeprange, l_float32 sweepdelta, l_float32 minbsdelta, l_int32 pivot)
pixFindSkewSweepAndSearchScorePivot()
l_int32 numaGetCount(NUMA *na)
numaGetCount()
l_ok pixFindNormalizedSquareSum(PIX *pixs, l_float32 *phratio, l_float32 *pvratio, l_float32 *pfract)
pixFindNormalizedSquareSum()
PIX * pixDeskewGeneral(PIX *pixs, l_int32 redsweep, l_float32 sweeprange, l_float32 sweepdelta, l_int32 redsearch, l_int32 thresh, l_float32 *pangle, l_float32 *pconf)
pixDeskewGeneral()
PIX * pixClone(PIX *pixs)
pixClone()
l_ok numaEmpty(NUMA *na)
numaEmpty()
void pixDestroy(PIX **ppix)
pixDestroy()
PIX * pixRotateOrth(PIX *pixs, l_int32 quads)
pixRotateOrth()
void numaDestroy(NUMA **pna)
numaDestroy()
l_ok pixGetDimensions(const PIX *pix, l_int32 *pw, l_int32 *ph, l_int32 *pd)
pixGetDimensions()
l_ok numaGetMin(NUMA *na, l_float32 *pminval, l_int32 *piminloc)
numaGetMin()
l_ok pixZero(PIX *pix, l_int32 *pempty)
pixZero()
l_ok pixFindSkewSweepAndSearch(PIX *pixs, l_float32 *pangle, l_float32 *pconf, l_int32 redsweep, l_int32 redsearch, l_float32 sweeprange, l_float32 sweepdelta, l_float32 minbsdelta)
pixFindSkewSweepAndSearch()
PIX * pixRotate90(PIX *pixs, l_int32 direction)
pixRotate90()
l_ok numaGetMax(NUMA *na, l_float32 *pmaxval, l_int32 *pimaxloc)
numaGetMax()
PIX * pixReduceRankBinaryCascade(PIX *pixs, l_int32 level1, l_int32 level2, l_int32 level3, l_int32 level4)
pixReduceRankBinaryCascade()
PIX * pixRotate(PIX *pixs, l_float32 angle, l_int32 type, l_int32 incolor, l_int32 width, l_int32 height)
pixRotate()