Logo Search packages:      
Sourcecode: leptonlib version File versions  Download package

shear.c

/*====================================================================*
 -  Copyright (C) 2001 Leptonica.  All rights reserved.
 -  This software is distributed in the hope that it will be
 -  useful, but with NO WARRANTY OF ANY KIND.
 -  No author or distributor accepts responsibility to anyone for the
 -  consequences of using this software, or for whether it serves any
 -  particular purpose or works at all, unless he or she says so in
 -  writing.  Everyone is granted permission to copy, modify and
 -  redistribute this source code, for commercial or non-commercial
 -  purposes, with the following restrictions: (1) the origin of this
 -  source code must not be misrepresented; (2) modified versions must
 -  be plainly marked as such; and (3) this notice may not be removed
 -  or altered from any source or modified source distribution.
 *====================================================================*/


/*
 *  shear.c
 *
 *       About arbitrary lines
 *           PIX      *pixHShear()
 *           PIX      *pixVShear()
 *
 *       About special 'points': UL corner and center
 *           PIX      *pixHShearCorner()
 *           PIX      *pixVShearCorner()
 *           PIX      *pixHShearCenter()
 *           PIX      *pixVShearCenter()
 *
 *       In place about arbitrary lines
 *           l_int32   pixHShearIP()
 *           l_int32   pixVShearIP()
 *
 */


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>

#include "allheaders.h"

#ifndef  NO_CONSOLE_IO
#define  DEBUG     0
#endif  /* ~NO_CONSOLE_IO */


/*-------------------------------------------------------------*
 *                    About arbitrary lines                    *
 *-------------------------------------------------------------*/
/*!
 *  pixHShear()
 *
 *      Input:  pixd (<optional>, can be equal to pixs for in-place)
 *              pixs
 *              liney  (location of horizontal line, measured from origin)
 *              angle (in radians)
 *              incolor (L_BRING_IN_WHITE, L_BRING_IN_BLACK);
 *      Return: pixd
 *
 *  Action: horizontal shear about the line at y with (+) shear pushing
 *          increasingly leftward (-x) with increasing y (downward). 
 *
 *  Notes:
 *      (1) This shear leaves the horizontal line of pixels at y = liney
 *          invariant.  For a positive shear angle, pixels above this
 *          line are shoved to the right, and pixels below this line
 *          move to the left.
 *      (2) With positive shear angle, this can be used, along with
 *          pixVShear(), to perform a cw rotation, either with 2 shears
 *          (for small angles) or in the general case with 3 shears.
 *      (3) Changing the value of liney is equivalent to translating
 *          the result horizontally.
 *      (4) This brings in 'incolor' pixels from outside the image.
 */
PIX *
pixHShear(PIX       *pixd,
        PIX       *pixs,
        l_int32    liney,
        l_float32  radang,
        l_int32    incolor)
{
l_int32    sign, w, h, d;
l_int32    y, yincr, inityincr, hshift;
l_float32  tanangle, invangle;

    PROCNAME("pixHShear");

    if (!pixs)
      return (PIX *)ERROR_PTR("pixs not defined", procName, pixd);
    if (incolor != L_BRING_IN_WHITE && incolor != L_BRING_IN_BLACK)
      return (PIX *)ERROR_PTR("invalid incolor value", procName, pixd);

    if (pixd == pixs) {  /* in place */
      pixHShearIP(pixd, liney, radang, incolor);
      return pixd;
    }

    if (radang == 0.0 || tan(radang) == 0.0)
      return pixCopy(pixd, pixs);

    if (!pixd) {
      if ((pixd = pixCreateTemplate(pixs)) == NULL)
          return (PIX *)ERROR_PTR("pixd not made", procName, pixd);
    }

        /* Set incoming pixels (and the rest as well) */
    d = pixGetDepth(pixd);
    if ((d == 1 && incolor == L_BRING_IN_WHITE) ||
        (d > 1 && incolor == L_BRING_IN_BLACK))
        pixClearAll(pixd);
    else
        pixSetAll(pixd);

    sign = L_SIGN(radang);
    w = pixGetWidth(pixs);
    h = pixGetHeight(pixs);
    tanangle = tan(radang);
    invangle = L_ABS(1. / tanangle); 
    inityincr = (l_int32)(invangle / 2.);
    yincr = (l_int32)invangle;

    pixRasterop(pixd, 0, liney - inityincr, w, 2 * inityincr, PIX_SRC,
                pixs, 0, liney - inityincr);

    for (hshift = 1, y = liney + inityincr; y < h; hshift++) {
      yincr = (l_int32)(invangle * (hshift + 0.5) + 0.5) - (y - liney);
      if (h - y < yincr)  /* reduce for last one if req'd */
          yincr = h - y;
      pixRasterop(pixd, -sign*hshift, y, w, yincr, PIX_SRC, pixs, 0, y);
#if DEBUG
      fprintf(stderr, "y = %d, hshift = %d, yincr = %d\n", y, hshift, yincr);
#endif /* DEBUG */
      y += yincr;
    }

    for (hshift = -1, y = liney - inityincr; y > 0; hshift--) {
      yincr = (y - liney) - (l_int32)(invangle * (hshift - 0.5) + 0.5);
      if (y < yincr)  /* reduce for last one if req'd */
          yincr = y;
      pixRasterop(pixd, -sign*hshift, y - yincr, w, yincr, PIX_SRC,
          pixs, 0, y - yincr);
#if DEBUG
      fprintf(stderr, "y = %d, hshift = %d, yincr = %d\n",
                y - yincr, hshift, yincr);
#endif /* DEBUG */
      y -= yincr;
    }

    return pixd;
}
                      

/*!
 *  pixVShear()
 *
 *      Input:  pixd (<optional>, can be equal to pixs for in-place)
 *              pixs
 *              linex  (location of vertical line, measured from origin)
 *              angle (in radians)
 *              incolor (L_BRING_IN_WHITE, L_BRING_IN_BLACK);
 *      Return: pixd
 *
 *  Action: vertical shear about the line at x with (+) shear pushing
 *          increasingly downward (+y) with increasing x. 
 *
 *  Notes:
 *      (1) This shear leaves the vertical line of pixels at x = linex
 *          invariant.  For a positive shear angle, pixels to the right
 *          of this line are shoved downward, and pixels to the left
 *          of the line move upward.
 *      (2) With positive shear angle, this can be used, along with
 *          pixHShear(), to perform a cw rotation, either with 2 shears
 *          (for small angles) or in the general case with 3 shears.
 *      (3) Changing the value of linex is equivalent to translating
 *          the result vertically.
 *      (4) This brings in 'incolor' pixels from outside the image.
 */
PIX *
pixVShear(PIX       *pixd,
        PIX       *pixs,
        l_int32    linex,
        l_float32  radang,
        l_int32    incolor)
{
l_int32    sign, w, h, d;
l_int32    x, xincr, initxincr, vshift;
l_float32  tanangle, invangle;

    PROCNAME("pixVShear");

    if (!pixs)
      return (PIX *)ERROR_PTR("pixs not defined", procName, pixd);
    if (incolor != L_BRING_IN_WHITE && incolor != L_BRING_IN_BLACK)
      return (PIX *)ERROR_PTR("invalid incolor value", procName, pixd);

    if (pixd == pixs) {  /* in place */
      pixVShearIP(pixd, linex, radang, incolor);
      return pixd;
    }

    if (radang == 0.0 || tan(radang) == 0.0)
      return pixCopy(pixd, pixs);

    if (!pixd) {
      if ((pixd = pixCreateTemplate(pixs)) == NULL)
          return (PIX *)ERROR_PTR("pixd not made", procName, pixd);
    }

        /* Set incoming pixels (and the rest as well) */
    d = pixGetDepth(pixd);
    if ((d == 1 && incolor == L_BRING_IN_WHITE) ||
        (d > 1 && incolor == L_BRING_IN_BLACK))
        pixClearAll(pixd);
    else
        pixSetAll(pixd);

    sign = L_SIGN(radang);
    w = pixGetWidth(pixs);
    h = pixGetHeight(pixs);
    tanangle = tan(radang);
    invangle = L_ABS(1. / tanangle); 
    initxincr = (l_int32)(invangle / 2.);
    xincr = (l_int32)invangle;

    pixRasterop(pixd, linex - initxincr, 0, 2 * initxincr, h, PIX_SRC,
               pixs, linex - initxincr, 0);

    for (vshift = 1, x = linex + initxincr; x < w; vshift++) {
      xincr = (l_int32)(invangle * (vshift + 0.5) + 0.5) - (x - linex);
      if (w - x < xincr)  /* reduce for last one if req'd */
          xincr = w - x;
      pixRasterop(pixd, x, sign*vshift, xincr, h, PIX_SRC, pixs, x, 0);
#if DEBUG
      fprintf(stderr, "x = %d, vshift = %d, xincr = %d\n", x, vshift, xincr);
#endif /* DEBUG */
      x += xincr;
    }

    for (vshift = -1, x = linex - initxincr; x > 0; vshift--) {
      xincr = (x - linex) - (l_int32)(invangle * (vshift - 0.5) + 0.5);
      if (x < xincr)  /* reduce for last one if req'd */
          xincr = x;
      pixRasterop(pixd, x - xincr, sign*vshift, xincr, h, PIX_SRC,
          pixs, x - xincr, 0);
#if DEBUG
      fprintf(stderr, "x = %d, vshift = %d, xincr = %d\n",
              x - xincr, vshift, xincr);
#endif /* DEBUG */
      x -= xincr;
    }

    return pixd;
}
                      


/*-------------------------------------------------------------*
 *             Shears about UL corner and center               *
 *-------------------------------------------------------------*/
/*!
 *  pixHShearCorner()
 *
 *      Input:  pixd (<optional>)
 *              pixs
 *              angle (in radians)
 *              incolor (L_BRING_IN_WHITE, L_BRING_IN_BLACK);
 *      Return: pixd
 *
 *  Notes:
 *      (1) Horizontal shear about the UL corner, with (+) shear
 *          pushing increasingly leftward (-x) with increasing y. 
 *      (2) This brings in 'incolor' pixels from outside the image.
 */
PIX *
pixHShearCorner(PIX       *pixd,
              PIX       *pixs,
              l_float32  radang,
            l_int32    incolor)
{
    PROCNAME("pixHShearCorner");

    if (!pixs)
      return (PIX *)ERROR_PTR("pixs not defined", procName, pixd);

    return pixHShear(pixd, pixs, 0, radang, incolor);
}


/*!
 *  pixVShearCorner()
 *
 *      Input:  pixd (<optional>)
 *              pixs
 *              angle (in radians)
 *              incolor (L_BRING_IN_WHITE, L_BRING_IN_BLACK);
 *      Return: pixd
 *
 *  Notes:
 *      (1) Vertical shear about the UL corner, with (+) shear
 *          pushing increasingly downward (+y) with increasing x. 
 *      (2) This brings in 'incolor' pixels from outside the image.
 */
PIX *
pixVShearCorner(PIX       *pixd,
              PIX       *pixs,
              l_float32  radang,
            l_int32    incolor)
{
    PROCNAME("pixVShearCorner");

    if (!pixs)
      return (PIX *)ERROR_PTR("pixs not defined", procName, pixd);

    return pixVShear(pixd, pixs, 0, radang, incolor);
}
                      

/*!
 *  pixHShearCenter()
 *
 *      Input:  pixd (<optional>)
 *              pixs
 *              angle (in radians)
 *              incolor (L_BRING_IN_WHITE, L_BRING_IN_BLACK);
 *      Return: pixd
 *
 *  Notes:
 *      (1) Horizontal shear about the center, with (+) shear
 *          pushing increasingly leftward (-x) with increasing y. 
 *      (2) This brings in 'incolor' pixels from outside the image.
 */
PIX *
pixHShearCenter(PIX       *pixd,
              PIX       *pixs,
              l_float32  radang,
            l_int32    incolor)
{
    PROCNAME("pixHShearCenter");

    if (!pixs)
      return (PIX *)ERROR_PTR("pixs not defined", procName, pixd);

    return pixHShear(pixd, pixs, pixGetHeight(pixs) / 2, radang, incolor);
}


/*!
 *  pixVShearCenter()
 *
 *      Input:  pixd (<optional>)
 *              pixs
 *              angle (in radians)
 *              incolor (L_BRING_IN_WHITE, L_BRING_IN_BLACK);
 *      Return: pixd
 *
 *  Notes:
 *      (1) Vertical shear about the center, with (+) shear
 *          pushing increasingly downward (+y) with increasing x. 
 *      (2) This brings in 'incolor' pixels from outside the image.
 */
PIX *
pixVShearCenter(PIX       *pixd,
              PIX       *pixs,
              l_float32  radang,
            l_int32    incolor)
{
    PROCNAME("pixVShearCenter");

    if (!pixs)
      return (PIX *)ERROR_PTR("pixs not defined", procName, pixd);

    return pixVShear(pixd, pixs, pixGetWidth(pixs) / 2, radang, incolor);
}



/*-------------------------------------------------------------*
 *                In place about arbitrary lines               *
 *-------------------------------------------------------------*/
/*!
 *  pixHShearIP()
 *
 *      Input:  pixs
 *              liney  (location of horizontal line, measured from origin)
 *              angle (in radians)
 *              incolor (L_BRING_IN_WHITE, L_BRING_IN_BLACK);
 *      Return: 0 if OK; 1 on error
 *
 *  Notes:
 *      (1) This is an in-place version of pixHShear(); see comments there.
 *      (2) This brings in 'incolor' pixels from outside the image.
 *      (3) Does a horizontal full-band shear about the line with (+) shear
 *          pushing increasingly leftward (-x) with increasing y. 
 */
l_int32
pixHShearIP(PIX       *pixs,
          l_int32    liney,
          l_float32  radang,
          l_int32    incolor)
{
l_int32    sign, w, h;
l_int32    y, yincr, inityincr, hshift;
l_float32  tanangle, invangle;

    PROCNAME("pixHShearIP");

    if (!pixs)
      return ERROR_INT("pixs not defined", procName, 1);
    if (incolor != L_BRING_IN_WHITE && incolor != L_BRING_IN_BLACK)
      return ERROR_INT("invalid incolor value", procName, 1);

    if (radang == 0.0 || tan(radang) == 0.0)
      return 0;

    sign = L_SIGN(radang);
    w = pixGetWidth(pixs);
    h = pixGetHeight(pixs);
    tanangle = tan(radang);
    invangle = L_ABS(1. / tanangle); 
    inityincr = (l_int32)(invangle / 2.);
    yincr = (l_int32)invangle;

    pixRasteropHip(pixs, liney - inityincr, 2 * inityincr, 0, incolor);

    for (hshift = 1, y = liney + inityincr; y < h; hshift++) {
      yincr = (l_int32)(invangle * (hshift + 0.5) + 0.5) - (y - liney);
      if (h - y < yincr)  /* reduce for last one if req'd */
          yincr = h - y;
      pixRasteropHip(pixs, y, yincr, -sign*hshift, incolor);
      y += yincr;
    }

    for (hshift = -1, y = liney - inityincr; y > 0; hshift--) {
      yincr = (y - liney) - (l_int32)(invangle * (hshift - 0.5) + 0.5);
      if (y < yincr)  /* reduce for last one if req'd */
          yincr = y;
      pixRasteropHip(pixs, y - yincr, yincr, -sign*hshift, incolor);
      y -= yincr;
    }

    return 0;
}
                      

/*!
 *  pixVShearIP()
 *
 *      Input:  pixs
 *              linex  (location of vertical line, measured from origin)
 *              angle (in radians)
 *              incolor (L_BRING_IN_WHITE, L_BRING_IN_BLACK);
 *      Return: 0 if OK; 1 on error
 *
 *  Notes:
 *      (1) This is an in-place version of pixVShear(); see comments there.
 *      (2) This brings in 'incolor' pixels from outside the image.
 *      (3) Does a vertical full-band shear about the line with (+) shear
 *          pushing increasingly downward (+y) with increasing x. 
 */
l_int32
pixVShearIP(PIX       *pixs,
          l_int32    linex,
          l_float32  radang,
          l_int32    incolor)
{
l_int32    sign, w, h;
l_int32    x, xincr, initxincr, vshift;
l_float32  tanangle, invangle;

    PROCNAME("pixVShearIP");

    if (!pixs)
      return ERROR_INT("pixs not defined", procName, 1);
    if (incolor != L_BRING_IN_WHITE && incolor != L_BRING_IN_BLACK)
      return ERROR_INT("invalid incolor value", procName, 1);

    if (radang == 0.0 || tan(radang) == 0.0)
      return 0;

    sign = L_SIGN(radang);
    w = pixGetWidth(pixs);
    h = pixGetHeight(pixs);
    tanangle = tan(radang);
    invangle = L_ABS(1. / tanangle); 
    initxincr = (l_int32)(invangle / 2.);
    xincr = (l_int32)invangle;

    pixRasteropVip(pixs, linex - initxincr, 2 * initxincr, 0, incolor);

    for (vshift = 1, x = linex + initxincr; x < w; vshift++) {
      xincr = (l_int32)(invangle * (vshift + 0.5) + 0.5) - (x - linex);
      if (w - x < xincr)  /* reduce for last one if req'd */
          xincr = w - x;
      pixRasteropVip(pixs, x, xincr, sign*vshift, incolor);
      x += xincr;
    }

    for (vshift = -1, x = linex - initxincr; x > 0; vshift--) {
      xincr = (x - linex) - (l_int32)(invangle * (vshift - 0.5) + 0.5);
      if (x < xincr)  /* reduce for last one if req'd */
          xincr = x;
      pixRasteropVip(pixs, x - xincr, xincr, sign*vshift, incolor);
      x -= xincr;
    }

    return 0;
}


Generated by  Doxygen 1.6.0   Back to index