Leptonica 1.68
C Image Processing Library

shear.c

Go to the documentation of this file.
00001 /*====================================================================*
00002  -  Copyright (C) 2001 Leptonica.  All rights reserved.
00003  -  This software is distributed in the hope that it will be
00004  -  useful, but with NO WARRANTY OF ANY KIND.
00005  -  No author or distributor accepts responsibility to anyone for the
00006  -  consequences of using this software, or for whether it serves any
00007  -  particular purpose or works at all, unless he or she says so in
00008  -  writing.  Everyone is granted permission to copy, modify and
00009  -  redistribute this source code, for commercial or non-commercial
00010  -  purposes, with the following restrictions: (1) the origin of this
00011  -  source code must not be misrepresented; (2) modified versions must
00012  -  be plainly marked as such; and (3) this notice may not be removed
00013  -  or altered from any source or modified source distribution.
00014  *====================================================================*/
00015 
00016 
00017 /*
00018  *  shear.c
00019  *
00020  *    About arbitrary lines
00021  *           PIX      *pixHShear()
00022  *           PIX      *pixVShear()
00023  *
00024  *    About special 'points': UL corner and center
00025  *           PIX      *pixHShearCorner()
00026  *           PIX      *pixVShearCorner()
00027  *           PIX      *pixHShearCenter()
00028  *           PIX      *pixVShearCenter()
00029  *
00030  *    In place about arbitrary lines
00031  *           l_int32   pixHShearIP()
00032  *           l_int32   pixVShearIP()
00033  *
00034  *    Linear interpolated shear about arbitrary lines
00035  *           PIX      *pixHShearLI()
00036  *           PIX      *pixVShearLI()
00037  *
00038  *    Static helper
00039  *      static l_float32  normalizeAngleForShear()
00040  */
00041 
00042 #include <stdio.h>
00043 #include <stdlib.h>
00044 #include <string.h>
00045 #include <math.h>
00046 #include "allheaders.h"
00047 
00048     /* Shear angle must not get too close to -pi/2 or pi/2 */
00049 static const l_float32   MIN_DIFF_FROM_HALF_PI = 0.04;
00050 
00051 static l_float32 normalizeAngleForShear(l_float32 radang, l_float32 mindif);
00052 
00053 
00054 #ifndef  NO_CONSOLE_IO
00055 #define  DEBUG     0
00056 #endif  /* ~NO_CONSOLE_IO */
00057 
00058 
00059 /*-------------------------------------------------------------*
00060  *                    About arbitrary lines                    *
00061  *-------------------------------------------------------------*/
00062 /*!
00063  *  pixHShear()
00064  *
00065  *      Input:  pixd (<optional>, this can be null, equal to pixs,
00066  *                    or different from pixs)
00067  *              pixs (no restrictions on depth)
00068  *              liney  (location of horizontal line, measured from origin)
00069  *              angle (in radians)
00070  *              incolor (L_BRING_IN_WHITE, L_BRING_IN_BLACK);
00071  *      Return: pixd, always
00072  *
00073  *  Notes:
00074  *      (1) There are 3 cases:
00075  *            (a) pixd == null (make a new pixd)
00076  *            (b) pixd == pixs (in-place)
00077  *            (c) pixd != pixs
00078  *      (2) For these three cases, use these patterns, respectively:
00079  *              pixd = pixHShear(NULL, pixs, ...);
00080  *              pixHShear(pixs, pixs, ...);
00081  *              pixHShear(pixd, pixs, ...);
00082  *      (3) This shear leaves the horizontal line of pixels at y = liney
00083  *          invariant.  For a positive shear angle, pixels above this
00084  *          line are shoved to the right, and pixels below this line
00085  *          move to the left.
00086  *      (4) With positive shear angle, this can be used, along with
00087  *          pixVShear(), to perform a cw rotation, either with 2 shears
00088  *          (for small angles) or in the general case with 3 shears.
00089  *      (5) Changing the value of liney is equivalent to translating
00090  *          the result horizontally.
00091  *      (6) This brings in 'incolor' pixels from outside the image.
00092  *      (7) For in-place operation, pixs cannot be colormapped,
00093  *          because the in-place operation only blits in 0 or 1 bits,
00094  *          not an arbitrary colormap index.
00095  *      (8) The angle is brought into the range [-pi, -pi].  It is
00096  *          not permitted to be within MIN_DIFF_FROM_HALF_PI radians
00097  *          from either -pi/2 or pi/2.
00098  */
00099 PIX *
00100 pixHShear(PIX       *pixd,
00101           PIX       *pixs,
00102           l_int32    liney,
00103           l_float32  radang,
00104           l_int32    incolor)
00105 {
00106 l_int32    sign, w, h;
00107 l_int32    y, yincr, inityincr, hshift;
00108 l_float32  tanangle, invangle;
00109 
00110     PROCNAME("pixHShear");
00111 
00112     if (!pixs)
00113         return (PIX *)ERROR_PTR("pixs not defined", procName, pixd);
00114     if (incolor != L_BRING_IN_WHITE && incolor != L_BRING_IN_BLACK)
00115         return (PIX *)ERROR_PTR("invalid incolor value", procName, pixd);
00116 
00117     if (pixd == pixs) {  /* in place */
00118         if (pixGetColormap(pixs) != NULL)
00119             return (PIX *)ERROR_PTR("pixs is colormapped", procName, pixd);
00120         pixHShearIP(pixd, liney, radang, incolor);
00121         return pixd;
00122     }
00123 
00124         /* Make sure pixd exists and is same size as pixs */
00125     if (!pixd) {
00126         if ((pixd = pixCreateTemplate(pixs)) == NULL)
00127             return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
00128     }
00129     else  /* pixd != pixs */
00130         pixResizeImageData(pixd, pixs);
00131 
00132         /* Normalize angle.  If no rotation, return a copy */
00133     radang = normalizeAngleForShear(radang, MIN_DIFF_FROM_HALF_PI);
00134     if (radang == 0.0 || tan(radang) == 0.0)
00135         return pixCopy(pixd, pixs);
00136 
00137         /* Initialize to value of incoming pixels */
00138     pixSetBlackOrWhite(pixd, incolor);
00139 
00140     pixGetDimensions(pixs, &w, &h, NULL);
00141     sign = L_SIGN(radang);
00142     tanangle = tan(radang);
00143     invangle = L_ABS(1. / tanangle); 
00144     inityincr = (l_int32)(invangle / 2.);
00145     yincr = (l_int32)invangle;
00146     pixRasterop(pixd, 0, liney - inityincr, w, 2 * inityincr, PIX_SRC,
00147                 pixs, 0, liney - inityincr);
00148 
00149     for (hshift = 1, y = liney + inityincr; y < h; hshift++) {
00150         yincr = (l_int32)(invangle * (hshift + 0.5) + 0.5) - (y - liney);
00151         if (h - y < yincr)  /* reduce for last one if req'd */
00152             yincr = h - y;
00153         pixRasterop(pixd, -sign*hshift, y, w, yincr, PIX_SRC, pixs, 0, y);
00154 #if DEBUG
00155         fprintf(stderr, "y = %d, hshift = %d, yincr = %d\n", y, hshift, yincr);
00156 #endif /* DEBUG */
00157         y += yincr;
00158     }
00159 
00160     for (hshift = -1, y = liney - inityincr; y > 0; hshift--) {
00161         yincr = (y - liney) - (l_int32)(invangle * (hshift - 0.5) + 0.5);
00162         if (y < yincr)  /* reduce for last one if req'd */
00163             yincr = y;
00164         pixRasterop(pixd, -sign*hshift, y - yincr, w, yincr, PIX_SRC,
00165             pixs, 0, y - yincr);
00166 #if DEBUG
00167         fprintf(stderr, "y = %d, hshift = %d, yincr = %d\n",
00168                 y - yincr, hshift, yincr);
00169 #endif /* DEBUG */
00170         y -= yincr;
00171     }
00172 
00173     return pixd;
00174 }
00175                         
00176 
00177 /*!
00178  *  pixVShear()
00179  *
00180  *      Input:  pixd (<optional>, this can be null, equal to pixs,
00181  *                    or different from pixs)
00182  *              pixs (no restrictions on depth)
00183  *              linex  (location of vertical line, measured from origin)
00184  *              angle (in radians; not too close to +-(pi / 2))
00185  *              incolor (L_BRING_IN_WHITE, L_BRING_IN_BLACK);
00186  *      Return: pixd, or null on error
00187  *
00188  *  Notes:
00189  *      (1) There are 3 cases:
00190  *            (a) pixd == null (make a new pixd)
00191  *            (b) pixd == pixs (in-place)
00192  *            (c) pixd != pixs
00193  *      (2) For these three cases, use these patterns, respectively:
00194  *              pixd = pixVShear(NULL, pixs, ...);
00195  *              pixVShear(pixs, pixs, ...);
00196  *              pixVShear(pixd, pixs, ...);
00197  *      (3) This shear leaves the vertical line of pixels at x = linex
00198  *          invariant.  For a positive shear angle, pixels to the right
00199  *          of this line are shoved downward, and pixels to the left
00200  *          of the line move upward.
00201  *      (4) With positive shear angle, this can be used, along with
00202  *          pixHShear(), to perform a cw rotation, either with 2 shears
00203  *          (for small angles) or in the general case with 3 shears.
00204  *      (5) Changing the value of linex is equivalent to translating
00205  *          the result vertically.
00206  *      (6) This brings in 'incolor' pixels from outside the image.
00207  *      (7) For in-place operation, pixs cannot be colormapped,
00208  *          because the in-place operation only blits in 0 or 1 bits,
00209  *          not an arbitrary colormap index.
00210  *      (8) The angle is brought into the range [-pi, -pi].  It is
00211  *          not permitted to be within MIN_DIFF_FROM_HALF_PI radians
00212  *          from either -pi/2 or pi/2.
00213  */
00214 PIX *
00215 pixVShear(PIX       *pixd,
00216           PIX       *pixs,
00217           l_int32    linex,
00218           l_float32  radang,
00219           l_int32    incolor)
00220 {
00221 l_int32    sign, w, h;
00222 l_int32    x, xincr, initxincr, vshift;
00223 l_float32  tanangle, invangle;
00224 
00225     PROCNAME("pixVShear");
00226 
00227     if (!pixs)
00228         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
00229     if (incolor != L_BRING_IN_WHITE && incolor != L_BRING_IN_BLACK)
00230         return (PIX *)ERROR_PTR("invalid incolor value", procName, NULL);
00231 
00232     if (pixd == pixs) {  /* in place */
00233         if (pixGetColormap(pixs) != NULL)
00234             return (PIX *)ERROR_PTR("pixs is colormapped", procName, pixd);
00235         pixVShearIP(pixd, linex, radang, incolor);
00236         return pixd;
00237     }
00238 
00239         /* Make sure pixd exists and is same size as pixs */
00240     if (!pixd) {
00241         if ((pixd = pixCreateTemplate(pixs)) == NULL)
00242             return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
00243     }
00244     else  /* pixd != pixs */
00245         pixResizeImageData(pixd, pixs);
00246 
00247         /* Normalize angle.  If no rotation, return a copy */
00248     radang = normalizeAngleForShear(radang, MIN_DIFF_FROM_HALF_PI);
00249     if (radang == 0.0 || tan(radang) == 0.0)
00250         return pixCopy(pixd, pixs);
00251 
00252         /* Initialize to value of incoming pixels */
00253     pixSetBlackOrWhite(pixd, incolor);
00254 
00255     pixGetDimensions(pixs, &w, &h, NULL);
00256     sign = L_SIGN(radang);
00257     tanangle = tan(radang);
00258     invangle = L_ABS(1. / tanangle); 
00259     initxincr = (l_int32)(invangle / 2.);
00260     xincr = (l_int32)invangle;
00261     pixRasterop(pixd, linex - initxincr, 0, 2 * initxincr, h, PIX_SRC,
00262                 pixs, linex - initxincr, 0);
00263 
00264     for (vshift = 1, x = linex + initxincr; x < w; vshift++) {
00265         xincr = (l_int32)(invangle * (vshift + 0.5) + 0.5) - (x - linex);
00266         if (w - x < xincr)  /* reduce for last one if req'd */
00267             xincr = w - x;
00268         pixRasterop(pixd, x, sign*vshift, xincr, h, PIX_SRC, pixs, x, 0);
00269 #if DEBUG
00270         fprintf(stderr, "x = %d, vshift = %d, xincr = %d\n", x, vshift, xincr);
00271 #endif /* DEBUG */
00272         x += xincr;
00273     }
00274 
00275     for (vshift = -1, x = linex - initxincr; x > 0; vshift--) {
00276         xincr = (x - linex) - (l_int32)(invangle * (vshift - 0.5) + 0.5);
00277         if (x < xincr)  /* reduce for last one if req'd */
00278             xincr = x;
00279         pixRasterop(pixd, x - xincr, sign*vshift, xincr, h, PIX_SRC,
00280             pixs, x - xincr, 0);
00281 #if DEBUG
00282         fprintf(stderr, "x = %d, vshift = %d, xincr = %d\n",
00283                 x - xincr, vshift, xincr);
00284 #endif /* DEBUG */
00285         x -= xincr;
00286     }
00287 
00288     return pixd;
00289 }
00290                         
00291 
00292 
00293 /*-------------------------------------------------------------*
00294  *             Shears about UL corner and center               *
00295  *-------------------------------------------------------------*/
00296 /*!
00297  *  pixHShearCorner()
00298  *
00299  *      Input:  pixd (<optional>, if not null, must be equal to pixs)
00300  *              pixs
00301  *              angle (in radians)
00302  *              incolor (L_BRING_IN_WHITE, L_BRING_IN_BLACK);
00303  *      Return: pixd, or null on error.
00304  *
00305  *  Notes:
00306  *      (1) See pixHShear() for usage.
00307  *      (2) This does a horizontal shear about the UL corner, with (+) shear
00308  *          pushing increasingly leftward (-x) with increasing y. 
00309  */
00310 PIX *
00311 pixHShearCorner(PIX       *pixd,
00312                 PIX       *pixs,
00313                 l_float32  radang,
00314                 l_int32    incolor)
00315 {
00316     PROCNAME("pixHShearCorner");
00317 
00318     if (!pixs)
00319         return (PIX *)ERROR_PTR("pixs not defined", procName, pixd);
00320 
00321     return pixHShear(pixd, pixs, 0, radang, incolor);
00322 }
00323 
00324 
00325 /*!
00326  *  pixVShearCorner()
00327  *
00328  *      Input:  pixd (<optional>, if not null, must be equal to pixs)
00329  *              pixs
00330  *              angle (in radians)
00331  *              incolor (L_BRING_IN_WHITE, L_BRING_IN_BLACK);
00332  *      Return: pixd, or null on error.
00333  *
00334  *  Notes:
00335  *      (1) See pixVShear() for usage.
00336  *      (2) This does a vertical shear about the UL corner, with (+) shear
00337  *          pushing increasingly downward (+y) with increasing x. 
00338  */
00339 PIX *
00340 pixVShearCorner(PIX       *pixd,
00341                 PIX       *pixs,
00342                 l_float32  radang,
00343                 l_int32    incolor)
00344 {
00345     PROCNAME("pixVShearCorner");
00346 
00347     if (!pixs)
00348         return (PIX *)ERROR_PTR("pixs not defined", procName, pixd);
00349 
00350     return pixVShear(pixd, pixs, 0, radang, incolor);
00351 }
00352                         
00353 
00354 /*!
00355  *  pixHShearCenter()
00356  *
00357  *      Input:  pixd (<optional>, if not null, must be equal to pixs)
00358  *              pixs
00359  *              angle (in radians)
00360  *              incolor (L_BRING_IN_WHITE, L_BRING_IN_BLACK);
00361  *      Return: pixd, or null on error.
00362  *
00363  *  Notes:
00364  *      (1) See pixHShear() for usage.
00365  *      (2) This does a horizontal shear about the center, with (+) shear
00366  *          pushing increasingly leftward (-x) with increasing y. 
00367  */
00368 PIX *
00369 pixHShearCenter(PIX       *pixd,
00370                 PIX       *pixs,
00371                 l_float32  radang,
00372                 l_int32    incolor)
00373 {
00374     PROCNAME("pixHShearCenter");
00375 
00376     if (!pixs)
00377         return (PIX *)ERROR_PTR("pixs not defined", procName, pixd);
00378 
00379     return pixHShear(pixd, pixs, pixGetHeight(pixs) / 2, radang, incolor);
00380 }
00381 
00382 
00383 /*!
00384  *  pixVShearCenter()
00385  *
00386  *      Input:  pixd (<optional>, if not null, must be equal to pixs)
00387  *              pixs
00388  *              angle (in radians)
00389  *              incolor (L_BRING_IN_WHITE, L_BRING_IN_BLACK);
00390  *      Return: pixd, or null on error.
00391  *
00392  *  Notes:
00393  *      (1) See pixVShear() for usage.
00394  *      (2) This does a vertical shear about the center, with (+) shear
00395  *          pushing increasingly downward (+y) with increasing x. 
00396  */
00397 PIX *
00398 pixVShearCenter(PIX       *pixd,
00399                 PIX       *pixs,
00400                 l_float32  radang,
00401                 l_int32    incolor)
00402 {
00403     PROCNAME("pixVShearCenter");
00404 
00405     if (!pixs)
00406         return (PIX *)ERROR_PTR("pixs not defined", procName, pixd);
00407 
00408     return pixVShear(pixd, pixs, pixGetWidth(pixs) / 2, radang, incolor);
00409 }
00410 
00411 
00412 
00413 /*--------------------------------------------------------------------------*
00414  *                       In place about arbitrary lines                     *
00415  *--------------------------------------------------------------------------*/
00416 /*!
00417  *  pixHShearIP()
00418  *
00419  *      Input:  pixs
00420  *              liney  (location of horizontal line, measured from origin)
00421  *              angle (in radians)
00422  *              incolor (L_BRING_IN_WHITE, L_BRING_IN_BLACK);
00423  *      Return: 0 if OK; 1 on error
00424  *
00425  *  Notes:
00426  *      (1) This is an in-place version of pixHShear(); see comments there.
00427  *      (2) This brings in 'incolor' pixels from outside the image.
00428  *      (3) pixs cannot be colormapped, because the in-place operation
00429  *          only blits in 0 or 1 bits, not an arbitrary colormap index.
00430  *      (4) Does a horizontal full-band shear about the line with (+) shear
00431  *          pushing increasingly leftward (-x) with increasing y. 
00432  */
00433 l_int32
00434 pixHShearIP(PIX       *pixs,
00435             l_int32    liney,
00436             l_float32  radang,
00437             l_int32    incolor)
00438 {
00439 l_int32    sign, w, h;
00440 l_int32    y, yincr, inityincr, hshift;
00441 l_float32  tanangle, invangle;
00442 
00443     PROCNAME("pixHShearIP");
00444 
00445     if (!pixs)
00446         return ERROR_INT("pixs not defined", procName, 1);
00447     if (incolor != L_BRING_IN_WHITE && incolor != L_BRING_IN_BLACK)
00448         return ERROR_INT("invalid incolor value", procName, 1);
00449     if (pixGetColormap(pixs) != NULL)
00450         return ERROR_INT("pixs is colormapped", procName, 1);
00451 
00452         /* Normalize angle */
00453     radang = normalizeAngleForShear(radang, MIN_DIFF_FROM_HALF_PI);
00454     if (radang == 0.0 || tan(radang) == 0.0)
00455         return 0;
00456 
00457     sign = L_SIGN(radang);
00458     pixGetDimensions(pixs, &w, &h, NULL);
00459     tanangle = tan(radang);
00460     invangle = L_ABS(1. / tanangle); 
00461     inityincr = (l_int32)(invangle / 2.);
00462     yincr = (l_int32)invangle;
00463 
00464     pixRasteropHip(pixs, liney - inityincr, 2 * inityincr, 0, incolor);
00465 
00466     for (hshift = 1, y = liney + inityincr; y < h; hshift++) {
00467         yincr = (l_int32)(invangle * (hshift + 0.5) + 0.5) - (y - liney);
00468         if (h - y < yincr)  /* reduce for last one if req'd */
00469             yincr = h - y;
00470         pixRasteropHip(pixs, y, yincr, -sign*hshift, incolor);
00471         y += yincr;
00472     }
00473 
00474     for (hshift = -1, y = liney - inityincr; y > 0; hshift--) {
00475         yincr = (y - liney) - (l_int32)(invangle * (hshift - 0.5) + 0.5);
00476         if (y < yincr)  /* reduce for last one if req'd */
00477             yincr = y;
00478         pixRasteropHip(pixs, y - yincr, yincr, -sign*hshift, incolor);
00479         y -= yincr;
00480     }
00481 
00482     return 0;
00483 }
00484                         
00485 
00486 /*!
00487  *  pixVShearIP()
00488  *
00489  *      Input:  pixs (all depths; not colormapped)
00490  *              linex  (location of vertical line, measured from origin)
00491  *              angle (in radians)
00492  *              incolor (L_BRING_IN_WHITE, L_BRING_IN_BLACK);
00493  *      Return: 0 if OK; 1 on error
00494  *
00495  *  Notes:
00496  *      (1) This is an in-place version of pixVShear(); see comments there.
00497  *      (2) This brings in 'incolor' pixels from outside the image.
00498  *      (3) pixs cannot be colormapped, because the in-place operation
00499  *          only blits in 0 or 1 bits, not an arbitrary colormap index.
00500  *      (4) Does a vertical full-band shear about the line with (+) shear
00501  *          pushing increasingly downward (+y) with increasing x. 
00502  */
00503 l_int32
00504 pixVShearIP(PIX       *pixs,
00505             l_int32    linex,
00506             l_float32  radang,
00507             l_int32    incolor)
00508 {
00509 l_int32    sign, w, h;
00510 l_int32    x, xincr, initxincr, vshift;
00511 l_float32  tanangle, invangle;
00512 
00513     PROCNAME("pixVShearIP");
00514 
00515     if (!pixs)
00516         return ERROR_INT("pixs not defined", procName, 1);
00517     if (incolor != L_BRING_IN_WHITE && incolor != L_BRING_IN_BLACK)
00518         return ERROR_INT("invalid incolor value", procName, 1);
00519     if (pixGetColormap(pixs) != NULL)
00520         return ERROR_INT("pixs is colormapped", procName, 1);
00521 
00522         /* Normalize angle */
00523     radang = normalizeAngleForShear(radang, MIN_DIFF_FROM_HALF_PI);
00524     if (radang == 0.0 || tan(radang) == 0.0)
00525         return 0;
00526 
00527     sign = L_SIGN(radang);
00528     pixGetDimensions(pixs, &w, &h, NULL);
00529     tanangle = tan(radang);
00530     invangle = L_ABS(1. / tanangle); 
00531     initxincr = (l_int32)(invangle / 2.);
00532     xincr = (l_int32)invangle;
00533 
00534     pixRasteropVip(pixs, linex - initxincr, 2 * initxincr, 0, incolor);
00535 
00536     for (vshift = 1, x = linex + initxincr; x < w; vshift++) {
00537         xincr = (l_int32)(invangle * (vshift + 0.5) + 0.5) - (x - linex);
00538         if (w - x < xincr)  /* reduce for last one if req'd */
00539             xincr = w - x;
00540         pixRasteropVip(pixs, x, xincr, sign*vshift, incolor);
00541         x += xincr;
00542     }
00543 
00544     for (vshift = -1, x = linex - initxincr; x > 0; vshift--) {
00545         xincr = (x - linex) - (l_int32)(invangle * (vshift - 0.5) + 0.5);
00546         if (x < xincr)  /* reduce for last one if req'd */
00547             xincr = x;
00548         pixRasteropVip(pixs, x - xincr, xincr, sign*vshift, incolor);
00549         x -= xincr;
00550     }
00551 
00552     return 0;
00553 }
00554 
00555 
00556 /*-------------------------------------------------------------------------*
00557  *              Linear interpolated shear about arbitrary lines            *
00558  *-------------------------------------------------------------------------*/
00559 /*!
00560  *  pixHShearLI()
00561  *
00562  *      Input:  pixs (8 bpp or 32 bpp, or colormapped)
00563  *              liney  (location of horizontal line, measured from origin)
00564  *              angle (in radians, in range (-pi/2 ... pi/2))
00565  *              incolor (L_BRING_IN_WHITE, L_BRING_IN_BLACK);
00566  *      Return: pixd (sheared), or null on error
00567  *
00568  *  Notes:
00569  *      (1) This does horizontal shear with linear interpolation for
00570  *          accurate results on 8 bpp gray, 32 bpp rgb, or cmapped images.
00571  *          It is relatively slow compared to the sampled version
00572  *          implemented by rasterop, but the result is much smoother.
00573  *      (2) This shear leaves the horizontal line of pixels at y = liney
00574  *          invariant.  For a positive shear angle, pixels above this
00575  *          line are shoved to the right, and pixels below this line
00576  *          move to the left.
00577  *      (3) Any colormap is removed.
00578  *      (4) The angle is brought into the range [-pi/2 + del, pi/2 - del],
00579  *          where del == MIN_DIFF_FROM_HALF_PI.
00580  */
00581 PIX *
00582 pixHShearLI(PIX       *pixs,
00583             l_int32    liney,
00584             l_float32  radang,
00585             l_int32    incolor)
00586 {
00587 l_int32    i, jd, x, xp, xf, w, h, d, wm, wpls, wpld, val, rval, gval, bval;
00588 l_uint32   word0, word1;
00589 l_uint32  *datas, *datad, *lines, *lined;
00590 l_float32  tanangle, xshift;
00591 PIX       *pix, *pixd;
00592 
00593     PROCNAME("pixHShearLI");
00594 
00595     if (!pixs)
00596         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
00597     pixGetDimensions(pixs, &w, &h, &d);
00598     if (d != 8 && d != 32 && !pixGetColormap(pixs))
00599         return (PIX *)ERROR_PTR("pixs not 8, 32 bpp, or cmap", procName, NULL);
00600     if (incolor != L_BRING_IN_WHITE && incolor != L_BRING_IN_BLACK)
00601         return (PIX *)ERROR_PTR("invalid incolor value", procName, NULL);
00602     if (liney < 0 || liney >= h)
00603         return (PIX *)ERROR_PTR("liney not in [0 ... h-1]", procName, NULL);
00604 
00605     if (pixGetColormap(pixs))
00606         pix = pixRemoveColormap(pixs, REMOVE_CMAP_BASED_ON_SRC);
00607     else
00608         pix = pixClone(pixs);
00609 
00610         /* Normalize angle.  If no rotation, return a copy */
00611     radang = normalizeAngleForShear(radang, MIN_DIFF_FROM_HALF_PI);
00612     if (radang == 0.0 || tan(radang) == 0.0) {
00613         pixDestroy(&pix);
00614         return pixCopy(NULL, pixs);
00615     }
00616 
00617         /* Initialize to value of incoming pixels */
00618     pixd = pixCreateTemplate(pix);
00619     pixSetBlackOrWhite(pixd, incolor);
00620 
00621         /* Standard linear interp: subdivide each pixel into 64 parts */
00622     d = pixGetDepth(pixd);  /* 8 or 32 */
00623     datas = pixGetData(pix);
00624     datad = pixGetData(pixd);
00625     wpls = pixGetWpl(pix);
00626     wpld = pixGetWpl(pixd);
00627     tanangle = tan(radang);
00628     for (i = 0; i < h; i++) {
00629         lines = datas + i * wpls;
00630         lined = datad + i * wpld;
00631         xshift = (liney - i) * tanangle;
00632         for (jd = 0; jd < w; jd++) {
00633             x = (l_int32)(64.0 * (-xshift + jd) + 0.5);
00634             xp = x / 64;
00635             xf = x & 63;
00636             wm = w - 1;
00637             if (xp < 0 || xp > wm) continue;
00638             if (d == 8) {
00639                 if (xp < wm)
00640                     val = ((63 - xf) * GET_DATA_BYTE(lines, xp) +
00641                            xf * GET_DATA_BYTE(lines, xp + 1) + 31) / 63;
00642                 else  /* xp == wm */
00643                     val = GET_DATA_BYTE(lines, xp);
00644                 SET_DATA_BYTE(lined, jd, val);
00645             }
00646             else {  /* d == 32 */
00647                 if (xp < wm) {
00648                     word0 = *(lines + xp);
00649                     word1 = *(lines + xp + 1);
00650                     rval = ((63 - xf) * ((word0 >> L_RED_SHIFT) & 0xff) +
00651                            xf * ((word1 >> L_RED_SHIFT) & 0xff) + 31) / 63;
00652                     gval = ((63 - xf) * ((word0 >> L_GREEN_SHIFT) & 0xff) +
00653                            xf * ((word1 >> L_GREEN_SHIFT) & 0xff) + 31) / 63;
00654                     bval = ((63 - xf) * ((word0 >> L_BLUE_SHIFT) & 0xff) +
00655                            xf * ((word1 >> L_BLUE_SHIFT) & 0xff) + 31) / 63;
00656                     composeRGBPixel(rval, gval, bval, lined + jd);
00657                 }
00658                 else  /* xp == wm */
00659                     lined[jd] = lines[xp];
00660             }
00661         }
00662     }
00663 
00664     pixDestroy(&pix);
00665     return pixd;
00666 }
00667 
00668 
00669 /*!
00670  *  pixVShearLI()
00671  *
00672  *      Input:  pixs (8 bpp or 32 bpp, or colormapped)
00673  *              linex  (location of vertical line, measured from origin)
00674  *              angle (in radians, in range (-pi/2 ... pi/2))
00675  *              incolor (L_BRING_IN_WHITE, L_BRING_IN_BLACK);
00676  *      Return: pixd (sheared), or null on error
00677  *
00678  *  Notes:
00679  *      (1) This does vertical shear with linear interpolation for
00680  *          accurate results on 8 bpp gray, 32 bpp rgb, or cmapped images.
00681  *          It is relatively slow compared to the sampled version
00682  *          implemented by rasterop, but the result is much smoother.
00683  *      (2) This shear leaves the vertical line of pixels at x = linex
00684  *          invariant.  For a positive shear angle, pixels to the right
00685  *          of this line are shoved downward, and pixels to the left
00686  *          of the line move upward.
00687  *      (3) Any colormap is removed.
00688  *      (4) The angle is brought into the range [-pi/2 + del, pi/2 - del],
00689  *          where del == MIN_DIFF_FROM_HALF_PI.
00690  */
00691 PIX *
00692 pixVShearLI(PIX       *pixs,
00693             l_int32    linex,
00694             l_float32  radang,
00695             l_int32    incolor)
00696 {
00697 l_int32    id, y, yp, yf, j, w, h, d, hm, wpls, wpld, val, rval, gval, bval;
00698 l_uint32   word0, word1;
00699 l_uint32  *datas, *datad, *lines, *lined;
00700 l_float32  tanangle, yshift;
00701 PIX       *pix, *pixd;
00702 
00703     PROCNAME("pixVShearLI");
00704 
00705     if (!pixs)
00706         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
00707     pixGetDimensions(pixs, &w, &h, &d);
00708     if (d != 8 && d != 32 && !pixGetColormap(pixs))
00709         return (PIX *)ERROR_PTR("pixs not 8, 32 bpp, or cmap", procName, NULL);
00710     if (incolor != L_BRING_IN_WHITE && incolor != L_BRING_IN_BLACK)
00711         return (PIX *)ERROR_PTR("invalid incolor value", procName, NULL);
00712     if (linex < 0 || linex >= w)
00713         return (PIX *)ERROR_PTR("linex not in [0 ... w-1]", procName, NULL);
00714 
00715     if (pixGetColormap(pixs))
00716         pix = pixRemoveColormap(pixs, REMOVE_CMAP_BASED_ON_SRC);
00717     else
00718         pix = pixClone(pixs);
00719 
00720         /* Normalize angle.  If no rotation, return a copy */
00721     radang = normalizeAngleForShear(radang, MIN_DIFF_FROM_HALF_PI);
00722     if (radang == 0.0 || tan(radang) == 0.0) {
00723         pixDestroy(&pix);
00724         return pixCopy(NULL, pixs);
00725     }
00726 
00727         /* Initialize to value of incoming pixels */
00728     pixd = pixCreateTemplate(pix);
00729     pixSetBlackOrWhite(pixd, incolor);
00730 
00731         /* Standard linear interp: subdivide each pixel into 64 parts */
00732     d = pixGetDepth(pixd);  /* 8 or 32 */
00733     datas = pixGetData(pix);
00734     datad = pixGetData(pixd);
00735     wpls = pixGetWpl(pix);
00736     wpld = pixGetWpl(pixd);
00737     tanangle = tan(radang);
00738     for (j = 0; j < w; j++) {
00739         yshift = (j - linex) * tanangle;
00740         for (id = 0; id < h; id++) {
00741             y = (l_int32)(64.0 * (-yshift + id) + 0.5);
00742             yp = y / 64;
00743             yf = y & 63;
00744             hm = h - 1;
00745             if (yp < 0 || yp > hm) continue;
00746             lines = datas + yp * wpls;
00747             lined = datad + id * wpld;
00748             if (d == 8) {
00749                 if (yp < hm)
00750                     val = ((63 - yf) * GET_DATA_BYTE(lines, j) +
00751                            yf * GET_DATA_BYTE(lines + wpls, j) + 31) / 63;
00752                 else  /* yp == hm */
00753                     val = GET_DATA_BYTE(lines, j);
00754                 SET_DATA_BYTE(lined, j, val);
00755             }
00756             else {  /* d == 32 */
00757                 if (yp < hm) {
00758                     word0 = *(lines + j);
00759                     word1 = *(lines + wpls + j);
00760                     rval = ((63 - yf) * ((word0 >> L_RED_SHIFT) & 0xff) +
00761                            yf * ((word1 >> L_RED_SHIFT) & 0xff) + 31) / 63;
00762                     gval = ((63 - yf) * ((word0 >> L_GREEN_SHIFT) & 0xff) +
00763                            yf * ((word1 >> L_GREEN_SHIFT) & 0xff) + 31) / 63;
00764                     bval = ((63 - yf) * ((word0 >> L_BLUE_SHIFT) & 0xff) +
00765                            yf * ((word1 >> L_BLUE_SHIFT) & 0xff) + 31) / 63;
00766                     composeRGBPixel(rval, gval, bval, lined + j);
00767                 }
00768                 else  /* yp == hm */
00769                     lined[j] = lines[j];
00770             }
00771         }
00772     }
00773 
00774     pixDestroy(&pix);
00775     return pixd;
00776 }
00777 
00778 
00779 /*-------------------------------------------------------------------------*
00780  *                           Angle normalization                           *
00781  *-------------------------------------------------------------------------*/
00782 static l_float32
00783 normalizeAngleForShear(l_float32  radang,
00784                        l_float32  mindif)
00785 {
00786 l_float32  pi2;
00787 
00788     PROCNAME("normalizeAngleForShear");
00789 
00790        /* Bring angle into range [-pi/2, pi/2] */
00791     pi2 = 3.14159265 / 2.0;
00792     if (radang < -pi2 || radang > pi2)
00793         radang = radang - (l_int32)(radang / pi2) * pi2;
00794 
00795        /* If angle is too close to pi/2 or -pi/2, move it */
00796     if (radang > pi2 - mindif) {
00797         L_WARNING("angle close to pi/2; shifting away", procName);
00798         radang = pi2 - mindif;
00799     }
00800     else if (radang < -pi2 + mindif) {
00801         L_WARNING("angle close to -pi/2; shifting away", procName);
00802         radang = -pi2 + mindif;
00803     }
00804 
00805     return radang;
00806 }
00807 
00808 
00809 
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines