src/skew.c
l_int32
pixFindSkewOrthogonalRange(PIX        *pixs,
                           l_float32  *pangle,
                           l_float32  *pconf,
                           l_int32     redsweep,
                           l_int32     redsearch,
                           l_float32   sweeprange,
                           l_float32   sweepdelta,
                           l_float32   minbsdelta,
                           l_float32   confprior)
{
l_float32  angle1, conf1, score1, angle2, conf2, score2;
PIX       *pixr;

    PROCNAME("pixFindSkewOrthogonalRange");

    if (!pangle || !pconf)
        return ERROR_INT("&angle and &conf not both defined", procName, 1);
    *pangle = *pconf = 0.0;
    if (!pixs || pixGetDepth(pixs) != 1)
        return ERROR_INT("pixs not defined or not 1 bpp", procName, 1);

    pixFindSkewSweepAndSearchScorePivot(pixs, &angle1, &conf1, &score1,
                                        redsweep, redsearch, 0.0,
                                        sweeprange, sweepdelta, minbsdelta,
                                        L_SHEAR_ABOUT_CORNER);
    pixr = pixRotateOrth(pixs, 1);
    pixFindSkewSweepAndSearchScorePivot(pixr, &angle2, &conf2, &score2,
                                        redsweep, redsearch, 0.0,
                                        sweeprange, sweepdelta, minbsdelta,
                                        L_SHEAR_ABOUT_CORNER);
    pixDestroy(&pixr);

    if (conf1 > conf2 - confprior) {
        *pangle = angle1;
        *pconf = conf1;
    } else {
        *pangle = -90.0 + angle2;
        *pconf = conf2;
    }

#if  DEBUG_PRINT_ORTH
    fprintf(stderr, " About 0:  angle1 = %7.3f, conf1 = %7.3f, score1 = %f\n",
            angle1, conf1, score1);
    fprintf(stderr, " About 90: angle2 = %7.3f, conf2 = %7.3f, score2 = %f\n",
            angle2, conf2, score2);
    fprintf(stderr, " Final:    angle = %7.3f, conf = %7.3f\n", *pangle, *pconf);
#endif  /* DEBUG_PRINT_ORTH */

    return 0;
}
/*
 *   pixFindSkewOrthogonalRange()
 *
 *      Input:  pixs  (1 bpp)
 *              &angle  (<return> angle required to deskew; in degrees cw)
 *              &conf   (<return> confidence given by ratio of max/min score)
 *              redsweep  (sweep reduction factor = 1, 2, 4 or 8)
 *              redsearch  (binary search reduction factor = 1, 2, 4 or 8;
 *                          and must not exceed redsweep)
 *              sweeprange  (half the full range in each orthogonal
 *                           direction, taken about 0, in degrees)
 *              sweepdelta   (angle increment of sweep; in degrees)
 *              minbsdelta   (min binary search increment angle; in degrees)
 *              confprior  (amount by which confidence of 90 degree rotated
 *                          result is reduced when comparing with unrotated
 *                          confidence value)
 *      Return: 0 if OK, 1 on error or if angle measurment not valid
 *
 *  Notes:
 *      (1) This searches for the skew angle, first in the range
 *          [-sweeprange, sweeprange], and then in
 *          [90 - sweeprange, 90 + sweeprange], with angles measured
 *          clockwise.  For exploring the full range of possibilities,
 *          suggest using sweeprange = 47.0 degrees, giving some overlap
 *          at 45 and 135 degrees.  From these results, and discounting
 *          the the second confidence by @confprior, it selects the
 *          angle for maximal differential variance.  If the angle
 *          is larger than pi/4, the angle found after 90 degree rotation
 *          is selected.
 *      (2) The larger the confidence value, the greater the probability
 *          that the proper alignment is given by the angle that maximizes
 *          variance.  It should be compared to a threshold, which depends
 *          on the application.  Values between 3.0 and 6.0 are common.
 *      (3) Allowing for both portrait and landscape searches is more
 *          difficult, because if the signal from the text lines is weak,
 *          a signal from vertical rules can be larger!
 *          The most difficult documents to deskew have some or all of:
 *            (a) Multiple columns, not aligned
 *            (b) Black lines along the vertical edges
 *            (c) Text from two pages, and at different angles
 *          Rule of thumb for resolution:
 *            (a) If the margins are clean, you can work at 75 ppi,
 *                although 100 ppi is safer.
 *            (b) If there are vertical lines in the margins, do not
 *                work below 150 ppi.  The signal from the text lines must
 *                exceed that from the margin lines.
 *      (4) Choosing the @confprior parameter depends on knowing something
 *          about the source of image.  However, we're not using
 *          real probabilities here, so its use is qualitative.
 *          If landscape and portrait are equally likely, use
 *          @confprior = 0.0.  If the likelihood of portrait (non-rotated)
 *          is 100 times higher than that of landscape, we want to reduce
 *          the chance that we rotate to landscape in a situation where
 *          the landscape signal is accidentally larger than the
 *          portrait signal.  To do this use a positive value of
 *          @confprior; say 1.5.
 */


(1) This searches for the skew angle, first in the range
[-sweeprange, sweeprange], and then in
[90 - sweeprange, 90 + sweeprange], with angles measured
clockwise.  For exploring the full range of possibilities,
suggest using sweeprange = 47.0 degrees, giving some overlap
at 45 and 135 degrees.  From these results, and discounting
the the second confidence by @confprior, it selects the
angle for maximal differential variance.  If the angle
is larger than pi/4, the angle found after 90 degree rotation
is selected.
(2) The larger the confidence value, the greater the probability
that the proper alignment is given by the angle that maximizes
variance.  It should be compared to a threshold, which depends
on the application.
( 1 ) This searches for the skew angle first in the range [ - sweeprange sweeprange ] and then in [ 90 - sweeprange 90 + sweeprange ] with angles measured clockwise . For exploring the full range of possibilities suggest using sweeprange = 47 . 0 degrees giving some overlap at 45 and 135 degrees . From these results and discounting the the second confidence by @confprior it selects the angle for maximal differential variance . If the angle is larger than pi / 4 the angle found after 90 degree rotation is selected . ( 2 ) The larger the confidence value the greater the probability that the proper alignment is given by the angle that maximizes variance . It should be compared to a threshold which depends on the application .
l_int32
pixFindSkewOrthogonalRange(PIX        *pixs,
                           l_float32  *pangle,
                           l_float32  *pconf,
                           l_int32     redsweep,
                           l_int32     redsearch,
                           l_float32   sweeprange,
                           l_float32   sweepdelta,
                           l_float32   minbsdelta,
                           l_float32   confprior)
{
l_float32  angle1, conf1, score1, angle2, conf2, score2;
PIX       *pixr;
    PROCNAME("pixFindSkewOrthogonalRange");
    if (!pangle || !pconf)
        return ERROR_INT("&angle and &conf not both defined", procName, 1);
    *pangle = *pconf = 0.0;
    if (!pixs || pixGetDepth(pixs) != 1)
        return ERROR_INT("pixs not defined or not 1 bpp", procName, 1);
    pixFindSkewSweepAndSearchScorePivot(pixs, &angle1, &conf1, &score1,
                                        redsweep, redsearch, 0.0,
                                        sweeprange, sweepdelta, minbsdelta,
                                        L_SHEAR_ABOUT_CORNER);
    pixr = pixRotateOrth(pixs, 1);
    pixFindSkewSweepAndSearchScorePivot(pixr, &angle2, &conf2, &score2,
                                        redsweep, redsearch, 0.0,
                                        sweeprange, sweepdelta, minbsdelta,
                                        L_SHEAR_ABOUT_CORNER);
    pixDestroy(&pixr);
    if (conf1 > conf2 - confprior) {
        *pangle = angle1;
        *pconf = conf1;
    } else {
        *pangle = -90.0 + angle2;
        *pconf = conf2;
    }
#if  DEBUG_PRINT_ORTH
    fprintf(stderr, " About 0:  angle1 = %7.3f, conf1 = %7.3f, score1 = %f\n",
            angle1, conf1, score1);
    fprintf(stderr, " About 90: angle2 = %7.3f, conf2 = %7.3f, score2 = %f\n",
            angle2, conf2, score2);
    fprintf(stderr, " Final:    angle = %7.3f, conf = %7.3f\n", *pangle, *pconf);
#endif  
    return 0;
}
l_int32 pixFindSkewOrthogonalRange ( PIX * pixs , l_float32 * pangle , l_float32 * pconf , l_int32 redsweep , l_int32 redsearch , l_float32 sweeprange , l_float32 sweepdelta , l_float32 minbsdelta , l_float32 confprior ) { l_float32 angle1 , conf1 , score1 , angle2 , conf2 , score2 ; PIX * pixr ; PROCNAME ( " " ) ; if ( ! pangle || ! pconf ) return ERROR_INT ( " " , procName , 1 ) ; * pangle = * pconf = 0.0 ; if ( ! pixs || pixGetDepth ( pixs ) != 1 ) return ERROR_INT ( " " , procName , 1 ) ; pixFindSkewSweepAndSearchScorePivot ( pixs , & angle1 , & conf1 , & score1 , redsweep , redsearch , 0.0 , sweeprange , sweepdelta , minbsdelta , L_SHEAR_ABOUT_CORNER ) ; pixr = pixRotateOrth ( pixs , 1 ) ; pixFindSkewSweepAndSearchScorePivot ( pixr , & angle2 , & conf2 , & score2 , redsweep , redsearch , 0.0 , sweeprange , sweepdelta , minbsdelta , L_SHEAR_ABOUT_CORNER ) ; pixDestroy ( & pixr ) ; if ( conf1 > conf2 - confprior ) { * pangle = angle1 ; * pconf = conf1 ; } else { * pangle = -90.0 + angle2 ; * pconf = conf2 ; } #if DEBUG_PRINT_ORTH fprintf ( stderr , " \n " , angle1 , conf1 , score1 ) ; fprintf ( stderr , " \n " , angle2 , conf2 , score2 ) ; fprintf ( stderr , " \n " , * pangle , * pconf ) ; #endif return 0 ; }
pixFindSkewOrthogonalRange()
      Input:  pixs  (1 bpp)
              &angle  (<return> angle required to deskew; in degrees cw)
              &conf   (<return> confidence given by ratio of max/min score)
              redsweep  (sweep reduction factor = 1, 2, 4 or 8)
              redsearch  (binary search reduction factor = 1, 2, 4 or 8;
                          and must not exceed redsweep)
              sweeprange  (half the full range in each orthogonal
                           direction, taken about 0, in degrees)
              sweepdelta   (angle increment of sweep; in degrees)
              minbsdelta   (min binary search increment angle; in degrees)
              confprior  (amount by which confidence of 90 degree rotated
                          result is reduced when comparing with unrotated
                          confidence value)
      Return: 0 if OK, 1 on error or if angle measurment not valid
pixFindSkewOrthogonalRange () Input : pixs ( 1 bpp ) &angle ( <return > angle required to deskew ; in degrees cw ) &conf ( <return > confidence given by ratio of max / min score ) redsweep ( sweep reduction factor = 1 2 4 or 8 ) redsearch ( binary search reduction factor = 1 2 4 or 8 ; and must not exceed redsweep ) sweeprange ( half the full range in each orthogonal direction taken about 0 in degrees ) sweepdelta ( angle increment of sweep ; in degrees ) minbsdelta ( min binary search increment angle ; in degrees ) confprior ( amount by which confidence of 90 degree rotated result is reduced when comparing with unrotated confidence value ) Return : 0 if OK 1 on error or if angle measurment not valid
/* DEBUG_PRINT_ORTH */