src/boxfunc5.c
BOXA *
boxaReconcileEvenOddHeight(BOXA      *boxas,
                           l_int32    sides,
                           l_int32    delh,
                           l_int32    op,
                           l_float32  factor,
                           l_int32    start)
{
l_int32    n, he, ho, hmed, doeven;
l_float32  del1, del2;
BOXA      *boxae, *boxao, *boxa1e, *boxa1o, *boxad;

    PROCNAME("boxaReconcileEvenOddHeight");

    if (!boxas)
        return (BOXA *)ERROR_PTR("boxas not defined", procName, NULL);
    if (sides != L_ADJUST_TOP && sides != L_ADJUST_BOT &&
        sides != L_ADJUST_TOP_AND_BOT) {
        L_WARNING("no action requested; returning copy\n", procName);
        return boxaCopy(boxas, L_COPY);
    }
    if ((n = boxaGetValidCount(boxas)) < 6) {
        L_WARNING("need at least 6 valid boxes; returning copy\n", procName);
        return boxaCopy(boxas, L_COPY);
    }
    if (factor <= 0.0) {
        L_WARNING("invalid factor; setting to 1.0\n", procName);
        factor = 1.0;
    }

        /* Require at least 3 valid boxes of both types */
    boxaSplitEvenOdd(boxas, 0, &boxae, &boxao);
    if (boxaGetValidCount(boxae) < 3 || boxaGetValidCount(boxao) < 3) {
        boxaDestroy(&boxae);
        boxaDestroy(&boxao);
        return boxaCopy(boxas, L_COPY);
    }

        /* Get the median heights for each set */
    boxaGetMedianVals(boxae, NULL, NULL, NULL, NULL, NULL, &he);
    boxaGetMedianVals(boxao, NULL, NULL, NULL, NULL, NULL, &ho);
    L_INFO("median he = %d, median ho = %d\n", procName, he, ho);

        /* If the difference in median height reaches the threshold %delh,
         * only adjust the side(s) of one of the sets.  If we choose
         * the minimum median height as the target, allow the target
         * to be scaled by a factor, typically near 1.0, of the
         * minimum median height.  And similarly if the target is
         * the maximum median height. */
    if (L_ABS(he - ho) > delh) {
        if (op == L_ADJUST_CHOOSE_MIN) {
            doeven = (ho < he) ? TRUE : FALSE;
            hmed = (l_int32)(factor * L_MIN(he, ho));
            hmed = L_MIN(hmed, L_MAX(he, ho));  /* don't make it bigger! */
        } else {  /* max height */
            doeven = (ho > he) ? TRUE : FALSE;
            hmed = (l_int32)(factor * L_MAX(he, ho));
            hmed = L_MAX(hmed, L_MIN(he, ho));  /* don't make it smaller! */
        }
        if (doeven) {
            boxa1e = boxaAdjustHeightToTarget(NULL, boxae, sides, hmed, delh);
            boxa1o = boxaCopy(boxao, L_COPY);
        } else {  /* !doeven */
            boxa1e = boxaCopy(boxae, L_COPY);
            boxa1o = boxaAdjustHeightToTarget(NULL, boxao, sides, hmed, delh);
        }
    } else {
        boxa1e = boxaCopy(boxae, L_CLONE);
        boxa1o = boxaCopy(boxao, L_CLONE);
    }
    boxaDestroy(&boxae);
    boxaDestroy(&boxao);

        /* It can happen that the median is not a good measure for an
         * entire book.  In that case, the reconciliation above can do
         * more harm than good.  Sanity check by comparing height and y
         * differences of adjacent even/odd boxes, before and after
         * reconciliation.  */
    boxad = boxaMergeEvenOdd(boxa1e, boxa1o, 0);
    boxaTestEvenOddHeight(boxas, boxad, start, &del1, &del2);
    boxaDestroy(&boxa1e);
    boxaDestroy(&boxa1o);
    if (del2 < del1 + 10.)
        return boxad;

        /* Using the median made it worse.  Skip reconciliation:
         * forcing all pairs of top and bottom values to have
         * maximum extent does not improve the situation either. */
    L_INFO("Got worse: del2 = %f > del1 = %f\n", procName, del2, del1);
    boxaDestroy(&boxad);
    return boxaCopy(boxas, L_COPY);
}
/*!
 * \brief   boxaReconcileEvenOddHeight()
 *
 * \param[in]    boxas    containing at least 3 valid boxes in even and odd
 * \param[in]    sides    L_ADJUST_TOP, L_ADJUST_BOT, L_ADJUST_TOP_AND_BOT
 * \param[in]    delh     threshold on median height difference
 * \param[in]    op       L_ADJUST_CHOOSE_MIN, L_ADJUST_CHOOSE_MAX
 * \param[in]    factor   > 0.0, typically near 1.0
 * \param[in]    start    0 if pairing (0,1), etc; 1 if pairing (1,2), etc
 * \return  boxad adjusted, or a copy of boxas on error
 *
 * <pre>
 * Notes:
 *      (1) The basic idea is to reconcile differences in box height
 *          in the even and odd boxes, by moving the top and/or bottom
 *          edges in the even and odd boxes.  Choose the edge or edges
 *          to be moved, whether to adjust the boxes with the min
 *          or the max of the medians, and the threshold on the median
 *          difference between even and odd box heights for the operations
 *          to take place.  The same threshold is also used to
 *          determine if each individual box edge is to be adjusted.
 *      (2) Boxes are conditionally reset with either the same top (y)
 *          value or the same bottom value, or both.  The value is
 *          determined by the greater or lesser of the medians of the
 *          even and odd boxes, with the choice depending on the value
 *          of %op, which selects for either min or max median height.
 *          If the median difference between even and odd boxes is
 *          greater than %dely, then any individual box edge that differs
 *          from the selected median by more than %dely is set to
 *          the selected median times a factor typically near 1.0.
 *      (3) Note that if selecting for minimum height, you will choose
 *          the largest y-value for the top and the smallest y-value for
 *          the bottom of the box.
 *      (4) Typical input might be the output of boxaSmoothSequenceMedian(),
 *          where even and odd boxa have been independently regulated.
 *      (5) Require at least 3 valid even boxes and 3 valid odd boxes.
 *          Median values will be used for invalid boxes.
 *      (6) If the median height is not representative of the boxes
 *          in %boxas, this can make things much worse.  In that case,
 *          ignore the value of %op, and force pairwise equality of the
 *          heights, with pairwise maximal vertical extension.
 * </pre>
 */



Notes:
(1) The basic idea is to reconcile differences in box height
in the even and odd boxes, by moving the top and/or bottom
edges in the even and odd boxes.  Choose the edge or edges
to be moved, whether to adjust the boxes with the min
or the max of the medians, and the threshold on the median
difference between even and odd box heights for the operations
to take place.  The same threshold is also used to
determine if each individual box edge is to be adjusted.
(2) Boxes are conditionally reset with either the same top (y)
value or the same bottom value, or both.  The value is
determined by the greater or lesser of the medians of the
even and odd boxes, with the choice depending on the value
of %op, which selects for either min or max median height.
If the median difference between even and odd boxes is
greater than %dely, then any individual box edge that differs
from the selected median by more than %dely is set to
the selected median times a factor typically near 1.0.
(3) Note that if selecting for minimum height, you will choose
the largest y-value for the top and the smallest y-value for
the bottom of the box.
(4) Typical input might be the output of boxaSmoothSequenceMedian(),
where even and odd boxa have been independently regulated.
(5) Require at least 3 valid even boxes and 3 valid odd boxes.
Median values will be used for invalid boxes.
(6) If the median height is not representative of the boxes
in %boxas, this can make things much worse.  In that case,
ignore the value of %op, and force pairwise equality of the
heights, with pairwise maximal vertical extension.
Notes : ( 1 ) The basic idea is to reconcile differences in box height in the even and odd boxes by moving the top and / or bottom edges in the even and odd boxes . Choose the edge or edges to be moved whether to adjust the boxes with the min or the max of the medians and the threshold on the median difference between even and odd box heights for the operations to take place . The same threshold is also used to determine if each individual box edge is to be adjusted . ( 2 ) Boxes are conditionally reset with either the same top ( y ) value or the same bottom value or both . The value is determined by the greater or lesser of the medians of the even and odd boxes with the choice depending on the value of %op which selects for either min or max median height . If the median difference between even and odd boxes is greater than %dely then any individual box edge that differs from the selected median by more than %dely is set to the selected median times a factor typically near 1 . 0 . ( 3 ) Note that if selecting for minimum height you will choose the largest y - value for the top and the smallest y - value for the bottom of the box . ( 4 ) Typical input might be the output of boxaSmoothSequenceMedian () where even and odd boxa have been independently regulated . ( 5 ) Require at least 3 valid even boxes and 3 valid odd boxes . Median values will be used for invalid boxes . ( 6 ) If the median height is not representative of the boxes in %boxas this can make things much worse . In that case ignore the value of %op and force pairwise equality of the heights with pairwise maximal vertical extension .
BOXA *
boxaReconcileEvenOddHeight(BOXA      *boxas,
                           l_int32    sides,
                           l_int32    delh,
                           l_int32    op,
                           l_float32  factor,
                           l_int32    start)
{
l_int32    n, he, ho, hmed, doeven;
l_float32  del1, del2;
BOXA      *boxae, *boxao, *boxa1e, *boxa1o, *boxad;
    PROCNAME("boxaReconcileEvenOddHeight");
    if (!boxas)
        return (BOXA *)ERROR_PTR("boxas not defined", procName, NULL);
    if (sides != L_ADJUST_TOP && sides != L_ADJUST_BOT &&
        sides != L_ADJUST_TOP_AND_BOT) {
        L_WARNING("no action requested; returning copy\n", procName);
        return boxaCopy(boxas, L_COPY);
    }
    if ((n = boxaGetValidCount(boxas)) < 6) {
        L_WARNING("need at least 6 valid boxes; returning copy\n", procName);
        return boxaCopy(boxas, L_COPY);
    }
    if (factor <= 0.0) {
        L_WARNING("invalid factor; setting to 1.0\n", procName);
        factor = 1.0;
    }
    boxaSplitEvenOdd(boxas, 0, &boxae, &boxao);
    if (boxaGetValidCount(boxae) < 3 || boxaGetValidCount(boxao) < 3) {
        boxaDestroy(&boxae);
        boxaDestroy(&boxao);
        return boxaCopy(boxas, L_COPY);
    }
    boxaGetMedianVals(boxae, NULL, NULL, NULL, NULL, NULL, &he);
    boxaGetMedianVals(boxao, NULL, NULL, NULL, NULL, NULL, &ho);
    L_INFO("median he = %d, median ho = %d\n", procName, he, ho);
    if (L_ABS(he - ho) > delh) {
        if (op == L_ADJUST_CHOOSE_MIN) {
            doeven = (ho < he) ? TRUE : FALSE;
            hmed = (l_int32)(factor * L_MIN(he, ho));
            hmed = L_MIN(hmed, L_MAX(he, ho));  
        } else {  
            doeven = (ho > he) ? TRUE : FALSE;
            hmed = (l_int32)(factor * L_MAX(he, ho));
            hmed = L_MAX(hmed, L_MIN(he, ho));  
        }
        if (doeven) {
            boxa1e = boxaAdjustHeightToTarget(NULL, boxae, sides, hmed, delh);
            boxa1o = boxaCopy(boxao, L_COPY);
        } else {  
            boxa1e = boxaCopy(boxae, L_COPY);
            boxa1o = boxaAdjustHeightToTarget(NULL, boxao, sides, hmed, delh);
        }
    } else {
        boxa1e = boxaCopy(boxae, L_CLONE);
        boxa1o = boxaCopy(boxao, L_CLONE);
    }
    boxaDestroy(&boxae);
    boxaDestroy(&boxao);
    boxad = boxaMergeEvenOdd(boxa1e, boxa1o, 0);
    boxaTestEvenOddHeight(boxas, boxad, start, &del1, &del2);
    boxaDestroy(&boxa1e);
    boxaDestroy(&boxa1o);
    if (del2 < del1 + 10.)
        return boxad;
    L_INFO("Got worse: del2 = %f > del1 = %f\n", procName, del2, del1);
    boxaDestroy(&boxad);
    return boxaCopy(boxas, L_COPY);
}
BOXA * boxaReconcileEvenOddHeight ( BOXA * boxas , l_int32 sides , l_int32 delh , l_int32 op , l_float32 factor , l_int32 start ) { l_int32 n , he , ho , hmed , doeven ; l_float32 del1 , del2 ; BOXA * boxae , * boxao , * boxa1e , * boxa1o , * boxad ; PROCNAME ( " " ) ; if ( ! boxas ) return ( BOXA * ) ERROR_PTR ( " " , procName , NULL ) ; if ( sides != L_ADJUST_TOP && sides != L_ADJUST_BOT && sides != L_ADJUST_TOP_AND_BOT ) { L_WARNING ( " \n " , procName ) ; return boxaCopy ( boxas , L_COPY ) ; } if ( ( n = boxaGetValidCount ( boxas ) ) < 6 ) { L_WARNING ( " \n " , procName ) ; return boxaCopy ( boxas , L_COPY ) ; } if ( factor <= 0.0 ) { L_WARNING ( " \n " , procName ) ; factor = 1.0 ; } boxaSplitEvenOdd ( boxas , 0 , & boxae , & boxao ) ; if ( boxaGetValidCount ( boxae ) < 3 || boxaGetValidCount ( boxao ) < 3 ) { boxaDestroy ( & boxae ) ; boxaDestroy ( & boxao ) ; return boxaCopy ( boxas , L_COPY ) ; } boxaGetMedianVals ( boxae , NULL , NULL , NULL , NULL , NULL , & he ) ; boxaGetMedianVals ( boxao , NULL , NULL , NULL , NULL , NULL , & ho ) ; L_INFO ( " \n " , procName , he , ho ) ; if ( L_ABS ( he - ho ) > delh ) { if ( op == L_ADJUST_CHOOSE_MIN ) { doeven = ( ho < he ) ? TRUE : FALSE ; hmed = ( l_int32 ) ( factor * L_MIN ( he , ho ) ) ; hmed = L_MIN ( hmed , L_MAX ( he , ho ) ) ; } else { doeven = ( ho > he ) ? TRUE : FALSE ; hmed = ( l_int32 ) ( factor * L_MAX ( he , ho ) ) ; hmed = L_MAX ( hmed , L_MIN ( he , ho ) ) ; } if ( doeven ) { boxa1e = boxaAdjustHeightToTarget ( NULL , boxae , sides , hmed , delh ) ; boxa1o = boxaCopy ( boxao , L_COPY ) ; } else { boxa1e = boxaCopy ( boxae , L_COPY ) ; boxa1o = boxaAdjustHeightToTarget ( NULL , boxao , sides , hmed , delh ) ; } } else { boxa1e = boxaCopy ( boxae , L_CLONE ) ; boxa1o = boxaCopy ( boxao , L_CLONE ) ; } boxaDestroy ( & boxae ) ; boxaDestroy ( & boxao ) ; boxad = boxaMergeEvenOdd ( boxa1e , boxa1o , 0 ) ; boxaTestEvenOddHeight ( boxas , boxad , start , & del1 , & del2 ) ; boxaDestroy ( & boxa1e ) ; boxaDestroy ( & boxa1o ) ; if ( del2 < del1 + 10. ) return boxad ; L_INFO ( " \n " , procName , del2 , del1 ) ; boxaDestroy ( & boxad ) ; return boxaCopy ( boxas , L_COPY ) ; }
\brief   boxaReconcileEvenOddHeight()
 \param[in]    boxas    containing at least 3 valid boxes in even and odd
 \param[in]    sides    L_ADJUST_TOP, L_ADJUST_BOT, L_ADJUST_TOP_AND_BOT
 \param[in]    delh     threshold on median height difference
 \param[in]    op       L_ADJUST_CHOOSE_MIN, L_ADJUST_CHOOSE_MAX
 \param[in]    factor   > 0.0, typically near 1.0
 \param[in]    start    0 if pairing (0,1), etc; 1 if pairing (1,2), etc
 \return  boxad adjusted, or a copy of boxas on error
\ brief boxaReconcileEvenOddHeight () \ param [ in ] boxas containing at least 3 valid boxes in even and odd \ param [ in ] sides L_ADJUST_TOP L_ADJUST_BOT L_ADJUST_TOP_AND_BOT \ param [ in ] delh threshold on median height difference \ param [ in ] op L_ADJUST_CHOOSE_MIN L_ADJUST_CHOOSE_MAX \ param [ in ] factor > 0 . 0 typically near 1 . 0 \ param [ in ] start 0 if pairing ( 0 1 ) etc ; 1 if pairing ( 1 2 ) etc \ return boxad adjusted or a copy of boxas on error
/* Require at least 3 valid boxes of both types */ /* Get the median heights for each set */ /* If the difference in median height reaches the threshold %delh,
         * only adjust the side(s) of one of the sets.  If we choose
         * the minimum median height as the target, allow the target
         * to be scaled by a factor, typically near 1.0, of the
         * minimum median height.  And similarly if the target is
         * the maximum median height. */ /* don't make it bigger! */ /* max height */ /* don't make it smaller! */ /* !doeven */ /* It can happen that the median is not a good measure for an
         * entire book.  In that case, the reconciliation above can do
         * more harm than good.  Sanity check by comparing height and y
         * differences of adjacent even/odd boxes, before and after
         * reconciliation.  */ /* Using the median made it worse.  Skip reconciliation:
         * forcing all pairs of top and bottom values to have
         * maximum extent does not improve the situation either. */