Leptonica 1.68
C Image Processing Library

warper.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  *  warper.c
00018  *
00019  *      High-level captcha interface
00020  *          PIX               *pixSimpleCaptcha()
00021  *
00022  *      Random sinusoidal warping
00023  *          PIX               *pixRandomHarmonicWarp()
00024  *
00025  *      Helper functions
00026  *          static l_float64  *generateRandomNumberArray()
00027  *          static l_int32     applyWarpTransform()
00028  *
00029  *      Version using a LUT for sin
00030  *          PIX               *pixRandomHarmonicWarpLUT()
00031  *          static l_int32     applyWarpTransformLUT()
00032  *          static l_int32     makeSinLUT()
00033  *          static l_float32   getSinFromLUT()
00034  *
00035  *      Stereoscopic warping
00036  *          PIX               *pixWarpStereoscopic()
00037  *
00038  *      Linear and quadratic horizontal stretching
00039  *          PIX               *pixStretchHorizontal()
00040  *          PIX               *pixStretchHorizontalSampled()
00041  *          PIX               *pixStretchHorizontalLI()
00042  *
00043  *      Quadratic vertical shear
00044  *          PIX               *pixQuadraticVShear()
00045  *          PIX               *pixQuadraticVShearSampled()
00046  *          PIX               *pixQuadraticVShearLI()
00047  *
00048  *      Stereo from a pair of images
00049  *          PIX               *pixStereoFromPair()
00050  */
00051 
00052 #include <stdio.h>
00053 #include <stdlib.h>
00054 #include <math.h>
00055 #include "allheaders.h"
00056 
00057 static l_float64 *generateRandomNumberArray(l_int32 size);
00058 static l_int32 applyWarpTransform(l_float32 xmag, l_float32 ymag,
00059                                 l_float32 xfreq, l_float32 yfreq,
00060                                 l_float64 *randa, l_int32 nx, l_int32 ny,
00061                                 l_int32 xp, l_int32 yp,
00062                                 l_float32 *px, l_float32 *py);
00063 
00064 #define  USE_SIN_TABLE    0
00065 
00066     /* Suggested input to pixStereoFromPair().  These are weighting
00067      * factors for input to the red channel from the left image. */
00068 static const l_float32  L_DEFAULT_RED_WEIGHT   = 0.0;
00069 static const l_float32  L_DEFAULT_GREEN_WEIGHT = 0.7;
00070 static const l_float32  L_DEFAULT_BLUE_WEIGHT  = 0.3;
00071 
00072 
00073 /*----------------------------------------------------------------------*
00074  *                High-level example captcha interface                  *
00075  *----------------------------------------------------------------------*/
00076 /*!
00077  *  pixSimpleCaptcha()
00078  *
00079  *      Input:  pixs (8 bpp; no colormap)
00080  *              border (added white pixels on each side)
00081  *              nterms (number of x and y harmonic terms)
00082  *              seed (of random number generator)
00083  *              color (for colorizing; in 0xrrggbb00 format; use 0 for black)
00084  *              cmapflag (1 for colormap output; 0 for rgb)
00085  *      Return: pixd (8 bpp cmap or 32 bpp rgb), or null on error
00086  *
00087  *  Notes:
00088  *      (1) This uses typical default values for generating captchas.
00089  *          The magnitudes of the harmonic warp are typically to be
00090  *          smaller when more terms are used, even though the phases
00091  *          are random.  See, for example, prog/warptest.c.
00092  */
00093 PIX *
00094 pixSimpleCaptcha(PIX      *pixs,
00095                  l_int32   border,
00096                  l_int32   nterms,
00097                  l_uint32  seed,
00098                  l_uint32  color,
00099                  l_int32   cmapflag)
00100 {
00101 l_int32    k;
00102 l_float32  xmag[] = {7.0, 5.0, 4.0, 3.0};
00103 l_float32  ymag[] = {10.0, 8.0, 6.0, 5.0};
00104 l_float32  xfreq[] = {0.12, 0.10, 0.10, 0.11};
00105 l_float32  yfreq[] = {0.15, 0.13, 0.13, 0.11};
00106 PIX       *pixg, *pixgb, *pixw, *pixd;
00107 
00108     PROCNAME("pixSimpleCaptcha");
00109 
00110     if (!pixs)
00111         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
00112     if (nterms < 1 || nterms > 4)
00113         return (PIX *)ERROR_PTR("nterms must be in {1,2,3,4}", procName, NULL);
00114 
00115     k = nterms - 1;
00116     pixg = pixConvertTo8(pixs, 0);
00117     pixgb = pixAddBorder(pixg, border, 255);
00118     pixw = pixRandomHarmonicWarp(pixgb, xmag[k], ymag[k], xfreq[k], yfreq[k],
00119                                  nterms, nterms, seed, 255);
00120     pixd = pixColorizeGray(pixw, color, cmapflag);
00121 
00122     pixDestroy(&pixg);
00123     pixDestroy(&pixgb);
00124     pixDestroy(&pixw);
00125     return pixd;
00126 }
00127 
00128 
00129 /*----------------------------------------------------------------------*
00130  *                     Random sinusoidal warping                        *
00131  *----------------------------------------------------------------------*/
00132 /*!
00133  *  pixRandomHarmonicWarp()
00134  *
00135  *      Input:  pixs (8 bpp; no colormap)
00136  *              xmag, ymag (maximum magnitude of x and y distortion)
00137  *              xfreq, yfreq (maximum magnitude of x and y frequency)
00138  *              nx, ny (number of x and y harmonic terms)
00139  *              seed (of random number generator)
00140  *              grayval (color brought in from the outside;
00141  *                       0 for black, 255 for white)
00142  *      Return: pixd (8 bpp; no colormap), or null on error
00143  *
00144  *  Notes:
00145  *      (1) To generate the warped image p(x',y'), set up the transforms
00146  *          that are in getWarpTransform().  For each (x',y') in the
00147  *          dest, the warp function computes the originating location
00148  *          (x, y) in the src.  The differences (x - x') and (y - y')
00149  *          are given as a sum of products of sinusoidal terms.  Each
00150  *          term is multiplied by a maximum amplitude (in pixels), and the
00151  *          angle is determined by a frequency and phase, and depends
00152  *          on the (x', y') value of the dest.  Random numbers with
00153  *          a variable input seed are used to allow the warping to be
00154  *          unpredictable.  A linear interpolation is used to find
00155  *          the value for the source at (x, y); this value is written
00156  *          into the dest.
00157  *      (2) This can be used to generate 'captcha's, which are somewhat
00158  *          randomly distorted images of text.  A typical set of parameters
00159  *          for a captcha are:
00160  *                    xmag = 4.0     ymag = 6.0
00161  *                    xfreq = 0.10   yfreq = 0.13
00162  *                    nx = 3         ny = 3
00163  *          Other examples can be found in prog/warptest.c.
00164  */
00165 PIX *
00166 pixRandomHarmonicWarp(PIX       *pixs,
00167                       l_float32  xmag,
00168                       l_float32  ymag,
00169                       l_float32  xfreq,
00170                       l_float32  yfreq,
00171                       l_int32    nx,
00172                       l_int32    ny,
00173                       l_uint32   seed,
00174                       l_int32    grayval)
00175 {
00176 l_int32     w, h, d, i, j, wpls, wpld, val;
00177 l_uint32   *datas, *datad, *lined;
00178 l_float32   x, y;
00179 l_float64  *randa;
00180 PIX        *pixd;
00181 
00182     PROCNAME("pixRandomHarmonicWarp");
00183 
00184     if (!pixs)
00185         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
00186     pixGetDimensions(pixs, &w, &h, &d);
00187     if (d != 8)
00188         return (PIX *)ERROR_PTR("pixs not 8 bpp", procName, NULL);
00189 
00190         /* Compute filter output at each location.  We iterate over
00191          * the destination pixels.  For each dest pixel, use the
00192          * warp function to compute the four source pixels that
00193          * contribute, at the location (x, y).  Each source pixel
00194          * is divided into 16 x 16 subpixels to get an approximate value. */
00195     srand(seed);
00196     randa = generateRandomNumberArray(5 * (nx + ny));
00197     pixd = pixCreateTemplate(pixs);
00198     datas = pixGetData(pixs);
00199     wpls = pixGetWpl(pixs);
00200     datad = pixGetData(pixd);
00201     wpld = pixGetWpl(pixd);
00202 
00203     for (i = 0; i < h; i++) {
00204         lined = datad + i * wpld;
00205         for (j = 0; j < w; j++) {
00206             applyWarpTransform(xmag, ymag, xfreq, yfreq, randa, nx, ny,
00207                                j, i, &x, &y);
00208             linearInterpolatePixelGray(datas, wpls, w, h, x, y, grayval, &val);
00209             SET_DATA_BYTE(lined, j, val);
00210         }
00211     }
00212 
00213     FREE(randa);
00214     return pixd;
00215 }
00216 
00217 
00218 /*----------------------------------------------------------------------*
00219  *                         Static helper functions                      *
00220  *----------------------------------------------------------------------*/
00221 static l_float64 *
00222 generateRandomNumberArray(l_int32  size)
00223 {
00224 l_int32     i;
00225 l_float64  *randa;
00226 
00227     PROCNAME("generateRandomNumberArray");
00228 
00229     if ((randa = (l_float64 *)CALLOC(size, sizeof(l_float64))) == NULL)
00230         return (l_float64 *)ERROR_PTR("calloc fail for randa", procName, NULL);
00231 
00232         /* Return random values between 0.5 and 1.0 */
00233     for (i = 0; i < size; i++)
00234         randa[i] = 0.5 * (1.0 + (l_float64)rand() / (l_float64)RAND_MAX);
00235     return randa;
00236 }
00237 
00238 
00239 /*!
00240  *  applyWarpTransform()
00241  *
00242  *  Notes:
00243  *      (1) Uses the internal sin function.
00244  */
00245 static l_int32
00246 applyWarpTransform(l_float32   xmag,
00247                    l_float32   ymag,
00248                    l_float32   xfreq,
00249                    l_float32   yfreq,
00250                    l_float64  *randa,
00251                    l_int32     nx,
00252                    l_int32     ny,
00253                    l_int32     xp,
00254                    l_int32     yp,
00255                    l_float32  *px,
00256                    l_float32  *py)
00257 {
00258 l_int32    i;
00259 l_float64  twopi, x, y, anglex, angley;
00260 
00261     twopi = 6.283185;
00262     for (i = 0, x = xp; i < nx; i++) {
00263         anglex = xfreq * randa[3 * i + 1] * xp + twopi * randa[3 * i + 2];
00264         angley = yfreq * randa[3 * i + 3] * yp + twopi * randa[3 * i + 4];
00265         x += xmag * randa[3 * i] * sin(anglex) * sin(angley);
00266     }
00267     for (i = nx, y = yp; i < nx + ny; i++) {
00268         angley = yfreq * randa[3 * i + 1] * yp + twopi * randa[3 * i + 2];
00269         anglex = xfreq * randa[3 * i + 3] * xp + twopi * randa[3 * i + 4];
00270         y += ymag * randa[3 * i] * sin(angley) * sin(anglex);
00271     }
00272 
00273     *px = (l_float32)x;
00274     *py = (l_float32)y;
00275     return 0;
00276 }
00277 
00278 
00279 #if  USE_SIN_TABLE
00280 /*----------------------------------------------------------------------*
00281  *                       Version using a LUT for sin                    *
00282  *----------------------------------------------------------------------*/
00283 static l_int32 applyWarpTransformLUT(l_float32 xmag, l_float32 ymag,
00284                                 l_float32 xfreq, l_float32 yfreq,
00285                                 l_float64 *randa, l_int32 nx, l_int32 ny,
00286                                 l_int32 xp, l_int32 yp, l_float32 *lut,
00287                                 l_int32 npts, l_float32 *px, l_float32 *py);
00288 static l_int32 makeSinLUT(l_int32 npts, NUMA **pna);
00289 static l_float32 getSinFromLUT(l_float32 *tab, l_int32 npts,
00290                                l_float32 radang);
00291 
00292 /*!
00293  *  pixRandomHarmonicWarpLUT()
00294  *
00295  *      Input:  pixs (8 bpp; no colormap)
00296  *              xmag, ymag (maximum magnitude of x and y distortion)
00297  *              xfreq, yfreq (maximum magnitude of x and y frequency)
00298  *              nx, ny (number of x and y harmonic terms)
00299  *              seed (of random number generator)
00300  *              grayval (color brought in from the outside;
00301  *                       0 for black, 255 for white)
00302  *      Return: pixd (8 bpp; no colormap), or null on error
00303  *
00304  *  Notes:
00305  *      (1) See notes and inline comments in pixRandomHarmonicWarp().
00306  *          This version uses a LUT for the sin function.  It is not
00307  *          appreciably faster than using the built-in sin function,
00308  *          and is here for comparison only.
00309  */
00310 PIX *
00311 pixRandomHarmonicWarpLUT(PIX       *pixs,
00312                          l_float32  xmag,
00313                          l_float32  ymag,
00314                          l_float32  xfreq,
00315                          l_float32  yfreq,
00316                          l_int32    nx,
00317                          l_int32    ny,
00318                          l_uint32   seed,
00319                          l_int32    grayval)
00320 {
00321 l_int32     w, h, d, i, j, wpls, wpld, val, npts;
00322 l_uint32   *datas, *datad, *lined;
00323 l_float32   x, y;
00324 l_float32  *lut;
00325 l_float64  *randa;
00326 NUMA       *na;
00327 PIX        *pixd;
00328 
00329     PROCNAME("pixRandomHarmonicWarp");
00330 
00331     if (!pixs)
00332         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
00333     pixGetDimensions(pixs, &w, &h, &d);
00334     if (d != 8)
00335         return (PIX *)ERROR_PTR("pixs not 8 bpp", procName, NULL);
00336 
00337         /* Compute filter output at each location.  We iterate over
00338          * the destination pixels.  For each dest pixel, use the
00339          * warp function to compute the four source pixels that
00340          * contribute, at the location (x, y).  Each source pixel
00341          * is divided into 16 x 16 subpixels to get an approximate value. */
00342     srand(seed);
00343     randa = generateRandomNumberArray(5 * (nx + ny));
00344     pixd = pixCreateTemplate(pixs);
00345     datas = pixGetData(pixs);
00346     wpls = pixGetWpl(pixs);
00347     datad = pixGetData(pixd);
00348     wpld = pixGetWpl(pixd);
00349 
00350     npts = 100;
00351     makeSinLUT(npts, &na);
00352     lut = numaGetFArray(na, L_NOCOPY);
00353     for (i = 0; i < h; i++) {
00354         lined = datad + i * wpld;
00355         for (j = 0; j < w; j++) {
00356             applyWarpTransformLUT(xmag, ymag, xfreq, yfreq, randa, nx, ny,
00357                                   j, i, lut, npts, &x, &y);
00358             linearInterpolatePixelGray(datas, wpls, w, h, x, y, grayval, &val);
00359             SET_DATA_BYTE(lined, j, val);
00360         }
00361     }
00362 
00363     numaDestroy(&na);
00364     FREE(randa);
00365     return pixd;
00366 }
00367 
00368 
00369 /*!
00370  *  applyWarpTransformLUT()
00371  *
00372  *  Notes:
00373  *      (1) Uses an LUT for computing sin(theta).  There is little speed
00374  *          advantage to using the LUT.
00375  */
00376 static l_int32
00377 applyWarpTransformLUT(l_float32   xmag,
00378                       l_float32   ymag,
00379                       l_float32   xfreq,
00380                       l_float32   yfreq,
00381                       l_float64  *randa,
00382                       l_int32     nx,
00383                       l_int32     ny,
00384                       l_int32     xp,
00385                       l_int32     yp,
00386                       l_float32  *lut,
00387                       l_int32     npts,
00388                       l_float32  *px,
00389                       l_float32  *py)
00390 {
00391 l_int32    i;
00392 l_float64  twopi, x, y, anglex, angley, sanglex, sangley;
00393 
00394     twopi = 6.283185;
00395     for (i = 0, x = xp; i < nx; i++) {
00396         anglex = xfreq * randa[3 * i + 1] * xp + twopi * randa[3 * i + 2];
00397         angley = yfreq * randa[3 * i + 3] * yp + twopi * randa[3 * i + 4];
00398         sanglex = getSinFromLUT(lut, npts, anglex);
00399         sangley = getSinFromLUT(lut, npts, angley);
00400         x += xmag * randa[3 * i] * sanglex * sangley;
00401     }
00402     for (i = nx, y = yp; i < nx + ny; i++) {
00403         angley = yfreq * randa[3 * i + 1] * yp + twopi * randa[3 * i + 2];
00404         anglex = xfreq * randa[3 * i + 3] * xp + twopi * randa[3 * i + 4];
00405         sanglex = getSinFromLUT(lut, npts, anglex);
00406         sangley = getSinFromLUT(lut, npts, angley);
00407         y += ymag * randa[3 * i] * sangley * sanglex;
00408     }
00409 
00410     *px = (l_float32)x;
00411     *py = (l_float32)y;
00412     return 0;
00413 }
00414 
00415 
00416 static l_int32
00417 makeSinLUT(l_int32  npts,
00418            NUMA   **pna)
00419 {
00420 l_int32    i, n;
00421 l_float32  delx, fval;
00422 NUMA      *na;
00423 
00424     PROCNAME("makeSinLUT");
00425 
00426     if (!pna)
00427         return ERROR_INT("&na not defined", procName, 1);
00428     *pna = NULL;
00429     if (npts < 2)
00430         return ERROR_INT("npts < 2", procName, 1);
00431     n = 2 * npts + 1;
00432     na = numaCreate(n);
00433     *pna = na;
00434     delx = 3.14159265 / (l_float32)npts;
00435     numaSetXParameters(na, 0.0, delx);
00436     for (i = 0; i < n / 2; i++)
00437          numaAddNumber(na, (l_float32)sin((l_float64)i * delx));
00438     for (i = 0; i < n / 2; i++) {
00439          numaGetFValue(na, i, &fval);
00440          numaAddNumber(na, -fval);
00441     }
00442     numaAddNumber(na, 0);
00443 
00444     return 0;
00445 }
00446 
00447 
00448 static l_float32
00449 getSinFromLUT(l_float32  *tab,
00450               l_int32     npts,
00451               l_float32   radang)
00452 {
00453 l_int32    index;
00454 l_float32  twopi, invtwopi, findex, diff;
00455 
00456         /* Restrict radang to [0, 2pi] */
00457     twopi = 6.283185;
00458     invtwopi = 0.1591549;
00459     if (radang < 0.0)
00460         radang += twopi * (1.0 - (l_int32)(-radang * invtwopi));
00461     else if (radang > 0.0)
00462         radang -= twopi * (l_int32)(radang * invtwopi);
00463 
00464         /* Interpolate */
00465     findex = (2.0 * (l_float32)npts) * (radang * invtwopi);
00466     index = (l_int32)findex;
00467     if (index == 2 * npts)
00468         return tab[index];
00469     diff = findex - index;
00470     return (1.0 - diff) * tab[index] + diff * tab[index + 1];
00471 }
00472 #endif  /* USE_SIN_TABLE */
00473 
00474 
00475 
00476 /*---------------------------------------------------------------------------*
00477  *                          Stereoscopic warping                             *
00478  *---------------------------------------------------------------------------*/
00479 /*!
00480  *  pixWarpStereoscopic()
00481  *
00482  *      Input:  pixs (any depth, colormap ok)
00483  *              zbend (horizontal separation in pixels of red and cyan
00484  *                    at the left and right sides, that gives rise to
00485  *                    quadratic curvature out of the image plane)
00486  *              zshiftt (uniform pixel translation difference between
00487  *                      red and cyan, that pushes the top of the image
00488  *                      plane away from the viewer (zshiftt > 0) or 
00489  *                      towards the viewer (zshiftt < 0))
00490  *              zshiftb (uniform pixel translation difference between
00491  *                      red and cyan, that pushes the bottom of the image
00492  *                      plane away from the viewer (zshiftb > 0) or 
00493  *                      towards the viewer (zshiftb < 0))
00494  *              ybendt (multiplicative parameter for in-plane vertical
00495  *                      displacement at the left or right edge at the top:
00496  *                        y = ybendt * (2x/w - 1)^2 )
00497  *              ybendb (same as ybendt, except at the left or right edge
00498  *                      at the bottom)
00499  *              redleft (1 if the red filter is on the left; 0 otherwise)
00500  *      Return: pixd (32 bpp), or null on error
00501  *
00502  *  Notes:
00503  *      (1) This function splits out the red channel, mucks around with
00504  *          it, then recombines with the unmolested cyan channel.
00505  *      (2) By using a quadratically increasing shift of the red
00506  *          pixels horizontally and away from the vertical centerline,
00507  *          the image appears to bend quadratically out of the image
00508  *          plane, symmetrically with respect to the vertical center
00509  *          line.  A positive value of @zbend causes the plane to be
00510  *          curved away from the viewer.  We use linearly interpolated
00511  *          stretching to avoid the appearance of kinks in the curve.
00512  *      (3) The parameters @zshiftt and @zshiftb tilt the image plane
00513  *          about a horizontal line through the center, and at the
00514  *          same time move that line either in toward the viewer or away.
00515  *          This is implemented by a combination of horizontal shear
00516  *          about the center line (for the tilt) and horizontal
00517  *          translation (to move the entire plane in or out).
00518  *          A positive value of @zshiftt moves the top of the plane
00519  *          away from the viewer, and a positive value of @zshiftb
00520  *          moves the bottom of the plane away.  We use linear interpolated
00521  *          shear to avoid visible vertical steps in the tilted image.
00522  *      (4) The image can be bent in the plane and about the vertical
00523  *          centerline.  The centerline does not shift, and the
00524  *          parameter @ybend gives the relative shift at left and right
00525  *          edges, with a downward shift for positive values of @ybend.
00526  *      (6) When writing out a steroscopic (red/cyan) image in jpeg,
00527  *          first call l_jpegSetNoChromaSampling() to get sufficient
00528  *          resolution in the red channel.
00529  *      (7) Typical values are:
00530  *             zbend = 20
00531  *             zshiftt = 15
00532  *             zshiftb = -15
00533  *             ybendt = 30
00534  *             ybendb = 0
00535  *          If the disparity z-values are too large, it is difficult for
00536  *          the brain to register the two images.
00537  *      (8) This function has been cleverly reimplemented by Jeff Breidenbach.
00538  *          The original implementation used two 32 bpp rgb images,
00539  *          and merged them at the end.  The result is somewhat faded,
00540  *          and has a parameter "thresh" that controls the amount of
00541  *          color in the result.  (The present implementation avoids these
00542  *          two problems, skipping both the colorization and the alpha
00543  *          blending at the end, and is about 3x faster)
00544  *          The basic operations with 32 bpp are as follows:
00545  *               // Immediate conversion to 32 bpp
00546  *            Pix *pixt1 = pixConvertTo32(pixs);
00547  *               // Do vertical shear
00548  *            Pix *pixr = pixQuadraticVerticalShear(pixt1, L_WARP_TO_RIGHT,
00549  *                                                  ybendt, ybendb,
00550  *                                                  L_BRING_IN_WHITE);
00551  *               // Colorize two versions, toward red and cyan
00552  *            Pix *pixc = pixCopy(NULL, pixr);
00553  *            l_int32 thresh = 150;  // if higher, get less original color
00554  *            pixColorGray(pixr, NULL, L_PAINT_DARK, thresh, 255, 0, 0);
00555  *            pixColorGray(pixc, NULL, L_PAINT_DARK, thresh, 0, 255, 255);
00556  *               // Shift the red pixels; e.g., by stretching
00557  *            Pix *pixrs = pixStretchHorizontal(pixr, L_WARP_TO_RIGHT,
00558  *                                              L_QUADRATIC_WARP, zbend,
00559  *                                              L_INTERPOLATED,
00560  *                                              L_BRING_IN_WHITE);
00561  *               // Blend the shifted red and unshifted cyan 50:50
00562  *            Pix *pixg = pixCreate(w, h, 8);
00563  *            pixSetAllArbitrary(pixg, 128);
00564  *            pixd = pixBlendWithGrayMask(pixrs, pixc, pixg, 0, 0);
00565  */
00566 PIX *
00567 pixWarpStereoscopic(PIX     *pixs,
00568                     l_int32  zbend,
00569                     l_int32  zshiftt,
00570                     l_int32  zshiftb,
00571                     l_int32  ybendt,
00572                     l_int32  ybendb,
00573                     l_int32  redleft)
00574 {
00575 l_int32    w, h, zshift;
00576 l_float32  angle;
00577 BOX       *boxleft, *boxright;
00578 PIX       *pixt, *pixt2, *pixt3;
00579 PIX       *pixr, *pixg, *pixb;
00580 PIX       *pixv1, *pixv2, *pixv3, *pixv4;
00581 PIX       *pixr1, *pixr2, *pixr3, *pixr4, *pixrs, *pixrss;
00582 PIX       *pixd;
00583 
00584     PROCNAME("pixWarpStereoscopic");
00585 
00586     if (!pixs)
00587         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
00588 
00589         /* Convert to the output depth, 32 bpp. */
00590     pixt = pixConvertTo32(pixs);
00591 
00592         /* If requested, do a quad vertical shearing, pushing pixels up
00593          * or down, depending on their distance from the centerline. */
00594     pixGetDimensions(pixs, &w, &h, NULL);
00595     boxleft = boxCreate(0, 0, w / 2, h);
00596     boxright = boxCreate(w / 2, 0, w - w / 2, h);
00597     if (ybendt != 0 || ybendb != 0) {
00598         pixv1 = pixClipRectangle(pixt, boxleft, NULL);
00599         pixv2 = pixClipRectangle(pixt, boxright, NULL);
00600         pixv3 = pixQuadraticVShear(pixv1, L_WARP_TO_LEFT, ybendt,
00601                                           ybendb, L_INTERPOLATED,
00602                                           L_BRING_IN_WHITE);
00603         pixv4 = pixQuadraticVShear(pixv2, L_WARP_TO_RIGHT, ybendt,
00604                                           ybendb, L_INTERPOLATED,
00605                                           L_BRING_IN_WHITE);
00606         pixt2 = pixCreate(w, h, 32);
00607         pixRasterop(pixt2, 0, 0, w / 2, h, PIX_SRC, pixv3, 0, 0);
00608         pixRasterop(pixt2, w / 2, 0, w - w / 2, h, PIX_SRC, pixv4, 0, 0);
00609         pixDestroy(&pixv1);
00610         pixDestroy(&pixv2);
00611         pixDestroy(&pixv3);
00612         pixDestroy(&pixv4);
00613     }
00614     else
00615         pixt2 = pixClone(pixt);
00616 
00617         /* Split out the 3 components */
00618     pixr = pixGetRGBComponent(pixt2, COLOR_RED);
00619     pixg = pixGetRGBComponent(pixt2, COLOR_GREEN);
00620     pixb = pixGetRGBComponent(pixt2, COLOR_BLUE);
00621     pixDestroy(&pixt);
00622     pixDestroy(&pixt2);
00623 
00624         /* The direction of the stereo disparity below is set
00625          * for the red filter to be over the left eye.  If the red
00626          * filter is over the right eye, invert the horizontal shifts. */
00627     if (redleft) {
00628         zbend = -zbend;
00629         zshiftt = -zshiftt;
00630         zshiftb = -zshiftb;
00631     }
00632 
00633         /* Shift the red pixels horizontally by an amount that
00634          * increases quadratically from the centerline. */
00635     if (zbend == 0)
00636         pixrs = pixClone(pixr);
00637     else {
00638         pixr1 = pixClipRectangle(pixr, boxleft, NULL);
00639         pixr2 = pixClipRectangle(pixr, boxright, NULL);
00640         pixr3 = pixStretchHorizontal(pixr1, L_WARP_TO_LEFT, L_QUADRATIC_WARP,
00641                                      zbend, L_INTERPOLATED, L_BRING_IN_WHITE);
00642         pixr4 = pixStretchHorizontal(pixr2, L_WARP_TO_RIGHT, L_QUADRATIC_WARP,
00643                                      zbend, L_INTERPOLATED, L_BRING_IN_WHITE);
00644         pixrs = pixCreate(w, h, 8);
00645         pixRasterop(pixrs, 0, 0, w / 2, h, PIX_SRC, pixr3, 0, 0);
00646         pixRasterop(pixrs, w / 2, 0, w - w / 2, h, PIX_SRC, pixr4, 0, 0);
00647         pixDestroy(&pixr1);
00648         pixDestroy(&pixr2);
00649         pixDestroy(&pixr3);
00650         pixDestroy(&pixr4);
00651     }
00652 
00653         /* Perform a combination of horizontal shift and shear of
00654          * red pixels.  The causes the plane of the image to tilt and
00655          * also move forward or backward. */
00656     if (zshiftt == 0 && zshiftb == 0)
00657         pixrss = pixClone(pixrs);
00658     else if (zshiftt == zshiftb)
00659         pixrss = pixTranslate(NULL, pixrs, zshiftt, 0, L_BRING_IN_WHITE);
00660     else {
00661         angle = (l_float32)(zshiftb - zshiftt) / (l_float32)pixGetHeight(pixrs);
00662         zshift = (zshiftt + zshiftb) / 2;
00663         pixt3 = pixTranslate(NULL, pixrs, zshift, 0, L_BRING_IN_WHITE);
00664         pixrss = pixHShearLI(pixt3, h / 2, angle, L_BRING_IN_WHITE);
00665         pixDestroy(&pixt3);
00666     }
00667 
00668         /* Combine the unchanged cyan (g,b) image with the shifted red */
00669     pixd = pixCreateRGBImage(pixrss, pixg, pixb);
00670 
00671     boxDestroy(&boxleft);
00672     boxDestroy(&boxright);
00673     pixDestroy(&pixrs);
00674     pixDestroy(&pixrss);
00675     pixDestroy(&pixr);
00676     pixDestroy(&pixg);
00677     pixDestroy(&pixb);
00678     return pixd;
00679 }
00680 
00681 
00682 /*----------------------------------------------------------------------*
00683  *              Linear and quadratic horizontal stretching              *
00684  *----------------------------------------------------------------------*/
00685 /*!
00686  *  pixStretchHorizontal()
00687  *
00688  *      Input:  pixs (1, 8 or 32 bpp)
00689  *              dir (L_WARP_TO_LEFT or L_WARP_TO_RIGHT)
00690  *              type (L_LINEAR_WARP or L_QUADRATIC_WARP)
00691  *              hmax (horizontal displacement at edge)
00692  *              operation (L_SAMPLED or L_INTERPOLATED)
00693  *              incolor (L_BRING_IN_WHITE or L_BRING_IN_BLACK)
00694  *      Return: pixd (stretched/compressed), or null on error
00695  *
00696  *  Notes:
00697  *      (1) If @hmax > 0, this is an increase in the coordinate value of
00698  *          pixels in pixd, relative to the same pixel in pixs.
00699  *      (2) If @dir == L_WARP_TO_LEFT, the pixels on the right edge of
00700  *          the image are not moved. So, for example, if @hmax > 0
00701  *          and @dir == L_WARP_TO_LEFT, the pixels in pixd are
00702  *          contracted toward the right edge of the image, relative
00703  *          to those in pixs.
00704  *      (3) If @type == L_LINEAR_WARP, the pixel positions are moved
00705  *          to the left or right by an amount that varies linearly with
00706  *          the horizontal location.
00707  *      (4) If @operation == L_SAMPLED, the dest pixels are taken from
00708  *          the nearest src pixel.  Otherwise, we use linear interpolation
00709  *          between pairs of sampled pixels.
00710  */
00711 PIX *
00712 pixStretchHorizontal(PIX     *pixs,
00713                      l_int32  dir,
00714                      l_int32  type,
00715                      l_int32  hmax,
00716                      l_int32  operation,
00717                      l_int32  incolor)
00718 {
00719 l_int32  d;
00720 
00721     PROCNAME("pixStretchHorizontal");
00722 
00723     if (!pixs)
00724         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
00725     d = pixGetDepth(pixs);
00726     if (d != 1 && d != 8 && d != 32)
00727         return (PIX *)ERROR_PTR("pixs not 1, 8 or 32 bpp", procName, NULL);
00728     if (dir != L_WARP_TO_LEFT && dir != L_WARP_TO_RIGHT)
00729         return (PIX *)ERROR_PTR("invalid direction", procName, NULL);
00730     if (type != L_LINEAR_WARP && type != L_QUADRATIC_WARP)
00731         return (PIX *)ERROR_PTR("invalid type", procName, NULL);
00732     if (operation != L_SAMPLED && operation != L_INTERPOLATED)
00733         return (PIX *)ERROR_PTR("invalid operation", procName, NULL);
00734     if (incolor != L_BRING_IN_WHITE && incolor != L_BRING_IN_BLACK)
00735         return (PIX *)ERROR_PTR("invalid incolor", procName, NULL);
00736     if (d == 1 && operation == L_INTERPOLATED) {
00737         L_WARNING("Using sampling for 1 bpp", procName);
00738         operation = L_INTERPOLATED;
00739     }
00740 
00741     if (operation == L_SAMPLED)
00742         return pixStretchHorizontalSampled(pixs, dir, type, hmax, incolor);
00743     else
00744         return pixStretchHorizontalLI(pixs, dir, type, hmax, incolor);
00745 }
00746 
00747 
00748 /*!
00749  *  pixStretchHorizontalSampled()
00750  *
00751  *      Input:  pixs (1, 8 or 32 bpp)
00752  *              dir (L_WARP_TO_LEFT or L_WARP_TO_RIGHT)
00753  *              type (L_LINEAR_WARP or L_QUADRATIC_WARP)
00754  *              hmax (horizontal displacement at edge)
00755  *              incolor (L_BRING_IN_WHITE or L_BRING_IN_BLACK)
00756  *      Return: pixd (stretched/compressed), or null on error
00757  *
00758  *  Notes:
00759  *      (1) See pixStretchHorizontal() for details.
00760  */
00761 PIX *
00762 pixStretchHorizontalSampled(PIX     *pixs,
00763                             l_int32  dir,
00764                             l_int32  type,
00765                             l_int32  hmax,
00766                             l_int32  incolor)
00767 {
00768 l_int32    i, j, jd, w, wm, h, d, wpls, wpld, val;
00769 l_uint32  *datas, *datad, *lines, *lined;
00770 PIX       *pixd;
00771 
00772     PROCNAME("pixStretchHorizontalSampled");
00773 
00774     if (!pixs)
00775         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
00776     pixGetDimensions(pixs, &w, &h, &d);
00777     if (d != 1 && d != 8 && d != 32)
00778         return (PIX *)ERROR_PTR("pixs not 1, 8 or 32 bpp", procName, NULL);
00779     if (dir != L_WARP_TO_LEFT && dir != L_WARP_TO_RIGHT)
00780         return (PIX *)ERROR_PTR("invalid direction", procName, NULL);
00781     if (type != L_LINEAR_WARP && type != L_QUADRATIC_WARP)
00782         return (PIX *)ERROR_PTR("invalid type", procName, NULL);
00783     if (incolor != L_BRING_IN_WHITE && incolor != L_BRING_IN_BLACK)
00784         return (PIX *)ERROR_PTR("invalid incolor", procName, NULL);
00785 
00786     pixd = pixCreateTemplate(pixs);
00787     pixSetBlackOrWhite(pixd, L_BRING_IN_WHITE);
00788     datas = pixGetData(pixs);
00789     datad = pixGetData(pixd);
00790     wpls = pixGetWpl(pixs);
00791     wpld = pixGetWpl(pixd);
00792     wm = w - 1;
00793     for (jd = 0; jd < w; jd++) {
00794         if (dir == L_WARP_TO_LEFT) {
00795             if (type == L_LINEAR_WARP)
00796                 j = jd - (hmax * (wm - jd)) / wm;
00797             else  /* L_QUADRATIC_WARP */
00798                 j = jd - (hmax * (wm - jd) * (wm - jd)) / (wm * wm);
00799         }
00800         else if (dir == L_WARP_TO_RIGHT) {
00801             if (type == L_LINEAR_WARP)
00802                 j = jd - (hmax * jd) / wm;
00803             else  /* L_QUADRATIC_WARP */
00804                 j = jd - (hmax * jd * jd) / (wm * wm);
00805         }
00806         if (j < 0 || j > w - 1) continue;
00807 
00808         switch (d)
00809         {
00810         case 1:
00811             for (i = 0; i < h; i++) {
00812                 lines = datas + i * wpls;
00813                 lined = datad + i * wpld;
00814                 val = GET_DATA_BIT(lines, j);
00815                 if (val)
00816                     SET_DATA_BIT(lined, jd);
00817             }
00818             break;
00819         case 8:
00820             for (i = 0; i < h; i++) {
00821                 lines = datas + i * wpls;
00822                 lined = datad + i * wpld;
00823                 val = GET_DATA_BYTE(lines, j);
00824                 SET_DATA_BYTE(lined, jd, val);
00825             }
00826             break;
00827         case 32:
00828             for (i = 0; i < h; i++) {
00829                 lines = datas + i * wpls;
00830                 lined = datad + i * wpld;
00831                 lined[jd] = lines[j];
00832             }
00833             break;
00834         default:
00835             L_ERROR_INT("invalid depth: %d", procName, d);
00836             pixDestroy(&pixd);
00837             return NULL;
00838         }
00839     }
00840 
00841     return pixd;
00842 }
00843 
00844 
00845 /*!
00846  *  pixStretchHorizontalLI()
00847  *
00848  *      Input:  pixs (1, 8 or 32 bpp)
00849  *              dir (L_WARP_TO_LEFT or L_WARP_TO_RIGHT)
00850  *              type (L_LINEAR_WARP or L_QUADRATIC_WARP)
00851  *              hmax (horizontal displacement at edge)
00852  *              incolor (L_BRING_IN_WHITE or L_BRING_IN_BLACK)
00853  *      Return: pixd (stretched/compressed), or null on error
00854  *
00855  *  Notes:
00856  *      (1) See pixStretchHorizontal() for details.
00857  */
00858 PIX *
00859 pixStretchHorizontalLI(PIX     *pixs,
00860                        l_int32  dir,
00861                        l_int32  type,
00862                        l_int32  hmax,
00863                        l_int32  incolor)
00864 {
00865 l_int32    i, j, jd, jp, jf, w, wm, h, d, wpls, wpld, val, rval, gval, bval;
00866 l_uint32   word0, word1;
00867 l_uint32  *datas, *datad, *lines, *lined;
00868 PIX       *pixd;
00869 
00870     PROCNAME("pixStretchHorizontalLI");
00871 
00872     if (!pixs)
00873         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
00874     pixGetDimensions(pixs, &w, &h, &d);
00875     if (d != 8 && d != 32)
00876         return (PIX *)ERROR_PTR("pixs not 8 or 32 bpp", procName, NULL);
00877     if (dir != L_WARP_TO_LEFT && dir != L_WARP_TO_RIGHT)
00878         return (PIX *)ERROR_PTR("invalid direction", procName, NULL);
00879     if (type != L_LINEAR_WARP && type != L_QUADRATIC_WARP)
00880         return (PIX *)ERROR_PTR("invalid type", procName, NULL);
00881     if (incolor != L_BRING_IN_WHITE && incolor != L_BRING_IN_BLACK)
00882         return (PIX *)ERROR_PTR("invalid incolor", procName, NULL);
00883 
00884         /* Standard linear interpolation, subdividing each pixel into 64 */
00885     pixd = pixCreateTemplate(pixs);
00886     pixSetBlackOrWhite(pixd, L_BRING_IN_WHITE);
00887     datas = pixGetData(pixs);
00888     datad = pixGetData(pixd);
00889     wpls = pixGetWpl(pixs);
00890     wpld = pixGetWpl(pixd);
00891     wm = w - 1;
00892     for (jd = 0; jd < w; jd++) {
00893         if (dir == L_WARP_TO_LEFT) {
00894             if (type == L_LINEAR_WARP)
00895                 j = 64 * jd - 64 * (hmax * (wm - jd)) / wm;
00896             else  /* L_QUADRATIC_WARP */
00897                 j = 64 * jd - 64 * (hmax * (wm - jd) * (wm - jd)) / (wm * wm);
00898         }
00899         else if (dir == L_WARP_TO_RIGHT) {
00900             if (type == L_LINEAR_WARP)
00901                 j = 64 * jd - 64 * (hmax * jd) / wm;
00902             else  /* L_QUADRATIC_WARP */
00903                 j = 64 * jd - 64 * (hmax * jd * jd) / (wm * wm);
00904         }
00905         jp = j / 64;
00906         jf = j & 0x3f;
00907         if (jp < 0 || jp > wm) continue;
00908 
00909         switch (d)
00910         {
00911         case 8:
00912             if (jp < wm) {
00913                 for (i = 0; i < h; i++) {
00914                     lines = datas + i * wpls;
00915                     lined = datad + i * wpld;
00916                     val = ((63 - jf) * GET_DATA_BYTE(lines, jp) +
00917                            jf * GET_DATA_BYTE(lines, jp + 1) + 31) / 63;
00918                     SET_DATA_BYTE(lined, jd, val);
00919                 }
00920             }
00921             else {  /* jp == wm */
00922                 for (i = 0; i < h; i++) {
00923                     lines = datas + i * wpls;
00924                     lined = datad + i * wpld;
00925                     val = GET_DATA_BYTE(lines, jp);
00926                     SET_DATA_BYTE(lined, jd, val);
00927                 }
00928             }
00929             break;
00930         case 32:
00931             if (jp < wm) {
00932                 for (i = 0; i < h; i++) {
00933                     lines = datas + i * wpls;
00934                     lined = datad + i * wpld;
00935                     word0 = *(lines + jp);
00936                     word1 = *(lines + jp + 1);
00937                     rval = ((63 - jf) * ((word0 >> L_RED_SHIFT) & 0xff) +
00938                            jf * ((word1 >> L_RED_SHIFT) & 0xff) + 31) / 63;
00939                     gval = ((63 - jf) * ((word0 >> L_GREEN_SHIFT) & 0xff) +
00940                            jf * ((word1 >> L_GREEN_SHIFT) & 0xff) + 31) / 63;
00941                     bval = ((63 - jf) * ((word0 >> L_BLUE_SHIFT) & 0xff) +
00942                            jf * ((word1 >> L_BLUE_SHIFT) & 0xff) + 31) / 63;
00943                     composeRGBPixel(rval, gval, bval, lined + jd);
00944                 }
00945             }
00946             else {  /* jp == wm */
00947                 for (i = 0; i < h; i++) {
00948                     lines = datas + i * wpls;
00949                     lined = datad + i * wpld;
00950                     lined[jd] = lines[jp];
00951                 }
00952             }
00953             break;
00954         default:
00955             L_ERROR_INT("invalid depth: %d", procName, d);
00956             pixDestroy(&pixd);
00957             return NULL;
00958         }
00959     }
00960 
00961     return pixd;
00962 }
00963 
00964 
00965 /*----------------------------------------------------------------------*
00966  *                       Quadratic vertical shear                       *
00967  *----------------------------------------------------------------------*/
00968 /*!
00969  *  pixQuadraticVShear()
00970  *
00971  *      Input:  pixs (1, 8 or 32 bpp)
00972  *              dir (L_WARP_TO_LEFT or L_WARP_TO_RIGHT)
00973  *              vmaxt (max vertical displacement at edge and at top)
00974  *              vmaxb (max vertical displacement at edge and at bottom)
00975  *              operation (L_SAMPLED or L_INTERPOLATED)
00976  *              incolor (L_BRING_IN_WHITE or L_BRING_IN_BLACK)
00977  *      Return: pixd (stretched), or null on error
00978  *
00979  *  Notes:
00980  *      (1) This gives a quadratic bending, upward or downward, as you
00981  *          move to the left or right.
00982  *      (2) If @dir == L_WARP_TO_LEFT, the right edge is unchanged, and
00983  *          the left edge pixels are moved maximally up or down.
00984  *      (3) Parameters @vmaxt and @vmaxb control the maximum amount of
00985  *          vertical pixel shear at the top and bottom, respectively.
00986  *          If @vmaxt > 0, the vertical displacement of pixels at the
00987  *          top is downward.  Likewise, if @vmaxb > 0, the vertical
00988  *          displacement of pixels at the bottom is downward.
00989  *      (4) If @operation == L_SAMPLED, the dest pixels are taken from
00990  *          the nearest src pixel.  Otherwise, we use linear interpolation
00991  *          between pairs of sampled pixels.
00992  *      (5) This is for quadratic shear.  For uniform (linear) shear,
00993  *          use the standard shear operators.
00994  */
00995 PIX *
00996 pixQuadraticVShear(PIX     *pixs,
00997                    l_int32  dir,
00998                    l_int32  vmaxt,
00999                    l_int32  vmaxb,
01000                    l_int32  operation,
01001                    l_int32  incolor)
01002 {
01003 l_int32    w, h, d;
01004 
01005     PROCNAME("pixQuadraticVShear");
01006 
01007     if (!pixs)
01008         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
01009     pixGetDimensions(pixs, &w, &h, &d);
01010     if (d != 1 && d != 8 && d != 32)
01011         return (PIX *)ERROR_PTR("pixs not 1, 8 or 32 bpp", procName, NULL);
01012     if (dir != L_WARP_TO_LEFT && dir != L_WARP_TO_RIGHT)
01013         return (PIX *)ERROR_PTR("invalid direction", procName, NULL);
01014     if (operation != L_SAMPLED && operation != L_INTERPOLATED)
01015         return (PIX *)ERROR_PTR("invalid operation", procName, NULL);
01016     if (incolor != L_BRING_IN_WHITE && incolor != L_BRING_IN_BLACK)
01017         return (PIX *)ERROR_PTR("invalid incolor", procName, NULL);
01018 
01019     if (vmaxt == 0 && vmaxb == 0)
01020         return pixCopy(NULL, pixs);
01021 
01022     if (operation == L_INTERPOLATED && d == 1) {
01023         L_WARNING("no interpolation for 1 bpp; using sampling", procName);
01024         operation = L_SAMPLED;
01025     }
01026 
01027     if (operation == L_SAMPLED)
01028         return pixQuadraticVShearSampled(pixs, dir, vmaxt, vmaxb, incolor);
01029     else  /* operation == L_INTERPOLATED */
01030         return pixQuadraticVShearLI(pixs, dir, vmaxt, vmaxb, incolor);
01031 }
01032 
01033 
01034 /*!
01035  *  pixQuadraticVShearSampled()
01036  *
01037  *      Input:  pixs (1, 8 or 32 bpp)
01038  *              dir (L_WARP_TO_LEFT or L_WARP_TO_RIGHT)
01039  *              vmaxt (max vertical displacement at edge and at top)
01040  *              vmaxb (max vertical displacement at edge and at bottom)
01041  *              incolor (L_BRING_IN_WHITE or L_BRING_IN_BLACK)
01042  *      Return: pixd (stretched), or null on error
01043  *
01044  *  Notes:
01045  *      (1) See pixQuadraticVShear() for details.
01046  */
01047 PIX *
01048 pixQuadraticVShearSampled(PIX     *pixs,
01049                           l_int32  dir,
01050                           l_int32  vmaxt,
01051                           l_int32  vmaxb,
01052                           l_int32  incolor)
01053 {
01054 l_int32    i, j, id, w, h, d, wm, hm, wpls, wpld, val;
01055 l_uint32  *datas, *datad, *lines, *lined;
01056 l_float32  delrowt, delrowb, denom1, denom2, dely;
01057 PIX       *pixd;
01058 
01059     PROCNAME("pixQuadraticVShearSampled");
01060 
01061     if (!pixs)
01062         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
01063     pixGetDimensions(pixs, &w, &h, &d);
01064     if (d != 1 && d != 8 && d != 32)
01065         return (PIX *)ERROR_PTR("pixs not 1, 8 or 32 bpp", procName, NULL);
01066     if (dir != L_WARP_TO_LEFT && dir != L_WARP_TO_RIGHT)
01067         return (PIX *)ERROR_PTR("invalid direction", procName, NULL);
01068     if (incolor != L_BRING_IN_WHITE && incolor != L_BRING_IN_BLACK)
01069         return (PIX *)ERROR_PTR("invalid incolor", procName, NULL);
01070 
01071     if (vmaxt == 0 && vmaxb == 0)
01072         return pixCopy(NULL, pixs);
01073 
01074     pixd = pixCreateTemplate(pixs);
01075     pixSetBlackOrWhite(pixd, L_BRING_IN_WHITE);
01076     datas = pixGetData(pixs);
01077     datad = pixGetData(pixd);
01078     wpls = pixGetWpl(pixs);
01079     wpld = pixGetWpl(pixd);
01080     wm = w - 1;
01081     hm = h - 1;
01082     denom1 = 1. / (l_float32)h;
01083     denom2 = 1. / (l_float32)(wm * wm);
01084     for (j = 0; j < w; j++) {
01085         if (dir == L_WARP_TO_LEFT) {
01086             delrowt = (l_float32)(vmaxt * (wm - j) * (wm - j)) * denom2;
01087             delrowb = (l_float32)(vmaxb * (wm - j) * (wm - j)) * denom2;
01088         }
01089         else if (dir == L_WARP_TO_RIGHT) {
01090             delrowt = (l_float32)(vmaxt * j * j) * denom2;
01091             delrowb = (l_float32)(vmaxb * j * j) * denom2;
01092         }
01093         switch (d)
01094         {
01095         case 1:
01096             for (id = 0; id < h; id++) {
01097                 dely = (delrowt * (hm - id) + delrowb * id) * denom1;
01098                 i = id - (l_int32)(dely + 0.5);
01099                 if (i < 0 || i > hm) continue;
01100                 lines = datas + i * wpls;
01101                 lined = datad + id * wpld;
01102                 val = GET_DATA_BIT(lines, j);
01103                 if (val)
01104                     SET_DATA_BIT(lined, j);
01105             }
01106             break;
01107         case 8:
01108             for (id = 0; id < h; id++) {
01109                 dely = (delrowt * (hm - id) + delrowb * id) * denom1;
01110                 i = id - (l_int32)(dely + 0.5);
01111                 if (i < 0 || i > hm) continue;
01112                 lines = datas + i * wpls;
01113                 lined = datad + id * wpld;
01114                 val = GET_DATA_BYTE(lines, j);
01115                 SET_DATA_BYTE(lined, j, val);
01116             }
01117             break;
01118         case 32:
01119             for (id = 0; id < h; id++) {
01120                 dely = (delrowt * (hm - id) + delrowb * id) * denom1;
01121                 i = id - (l_int32)(dely + 0.5);
01122                 if (i < 0 || i > hm) continue;
01123                 lines = datas + i * wpls;
01124                 lined = datad + id * wpld;
01125                 lined[j] = lines[j];
01126             }
01127             break;
01128         default:
01129             L_ERROR_INT("invalid depth: %d", procName, d);
01130             pixDestroy(&pixd);
01131             return NULL;
01132         }
01133     }
01134 
01135     return pixd;
01136 }
01137 
01138 
01139 /*!
01140  *  pixQuadraticVShearLI()
01141  *
01142  *      Input:  pixs (8 or 32 bpp, or colormapped)
01143  *              dir (L_WARP_TO_LEFT or L_WARP_TO_RIGHT)
01144  *              vmaxt (max vertical displacement at edge and at top)
01145  *              vmaxb (max vertical displacement at edge and at bottom)
01146  *              incolor (L_BRING_IN_WHITE or L_BRING_IN_BLACK)
01147  *      Return: pixd (stretched), or null on error
01148  *
01149  *  Notes:
01150  *      (1) See pixQuadraticVShear() for details.
01151  */
01152 PIX *
01153 pixQuadraticVShearLI(PIX     *pixs,
01154                      l_int32  dir,
01155                      l_int32  vmaxt,
01156                      l_int32  vmaxb,
01157                      l_int32  incolor)
01158 {
01159 l_int32    i, j, id, yp, yf, w, h, d, wm, hm, wpls, wpld;
01160 l_int32    val, rval, gval, bval;
01161 l_uint32   word0, word1;
01162 l_uint32  *datas, *datad, *lines, *lined;
01163 l_float32  delrowt, delrowb, denom1, denom2, dely;
01164 PIX       *pix, *pixd;
01165 PIXCMAP   *cmap;
01166 
01167     PROCNAME("pixQuadraticVShearLI");
01168 
01169     if (!pixs)
01170         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
01171     pixGetDimensions(pixs, &w, &h, &d);
01172     if (d == 1)
01173         return (PIX *)ERROR_PTR("pixs is 1 bpp", procName, NULL);
01174     cmap = pixGetColormap(pixs);
01175     if (d != 8 && d != 32 && !cmap)
01176         return (PIX *)ERROR_PTR("pixs not 8, 32 bpp, or cmap", procName, NULL);
01177     if (dir != L_WARP_TO_LEFT && dir != L_WARP_TO_RIGHT)
01178         return (PIX *)ERROR_PTR("invalid direction", procName, NULL);
01179     if (incolor != L_BRING_IN_WHITE && incolor != L_BRING_IN_BLACK)
01180         return (PIX *)ERROR_PTR("invalid incolor", procName, NULL);
01181 
01182     if (vmaxt == 0 && vmaxb == 0)
01183         return pixCopy(NULL, pixs);
01184 
01185         /* Remove any existing colormap */
01186     if (cmap)
01187         pix = pixRemoveColormap(pixs, REMOVE_CMAP_BASED_ON_SRC);
01188     else
01189         pix = pixClone(pixs);
01190     d = pixGetDepth(pix);
01191     if (d != 8 && d != 32) {
01192         pixDestroy(&pix);
01193         return (PIX *)ERROR_PTR("invalid depth", procName, NULL);
01194     }
01195 
01196         /* Standard linear interp: subdivide each pixel into 64 parts */
01197     pixd = pixCreateTemplate(pix);
01198     pixSetBlackOrWhite(pixd, L_BRING_IN_WHITE);
01199     datas = pixGetData(pix);
01200     datad = pixGetData(pixd);
01201     wpls = pixGetWpl(pix);
01202     wpld = pixGetWpl(pixd);
01203     wm = w - 1;
01204     hm = h - 1;
01205     denom1 = 1.0 / (l_float32)h;
01206     denom2 = 1.0 / (l_float32)(wm * wm);
01207     for (j = 0; j < w; j++) {
01208         if (dir == L_WARP_TO_LEFT) {
01209             delrowt = (l_float32)(vmaxt * (wm - j) * (wm - j)) * denom2;
01210             delrowb = (l_float32)(vmaxb * (wm - j) * (wm - j)) * denom2;
01211         }
01212         else if (dir == L_WARP_TO_RIGHT) {
01213             delrowt = (l_float32)(vmaxt * j * j) * denom2;
01214             delrowb = (l_float32)(vmaxb * j * j) * denom2;
01215         }
01216         switch (d)
01217         {
01218         case 8:
01219             for (id = 0; id < h; id++) {
01220                 dely = (delrowt * (hm - id) + delrowb * id) * denom1;
01221                 i = 64 * id - (l_int32)(64.0 * dely);
01222                 yp = i / 64;
01223                 yf = i & 63;
01224                 if (yp < 0 || yp > hm) continue;
01225                 lines = datas + yp * wpls;
01226                 lined = datad + id * wpld;
01227                 if (yp < hm)
01228                     val = ((63 - yf) * GET_DATA_BYTE(lines, j) +
01229                            yf * GET_DATA_BYTE(lines + wpls, j) + 31) / 63;
01230                 else  /* yp == hm */
01231                     val = GET_DATA_BYTE(lines, j);
01232                 SET_DATA_BYTE(lined, j, val);
01233             }
01234             break;
01235         case 32:
01236             for (id = 0; id < h; id++) {
01237                 dely = (delrowt * (hm - id) + delrowb * id) * denom1;
01238                 i = 64 * id - (l_int32)(64.0 * dely);
01239                 yp = i / 64;
01240                 yf = i & 63;
01241                 if (yp < 0 || yp > hm) continue;
01242                 lines = datas + yp * wpls;
01243                 lined = datad + id * wpld;
01244                 if (yp < hm) {
01245                     word0 = *(lines + j);
01246                     word1 = *(lines + wpls + j);
01247                     rval = ((63 - yf) * ((word0 >> L_RED_SHIFT) & 0xff) +
01248                            yf * ((word1 >> L_RED_SHIFT) & 0xff) + 31) / 63;
01249                     gval = ((63 - yf) * ((word0 >> L_GREEN_SHIFT) & 0xff) +
01250                            yf * ((word1 >> L_GREEN_SHIFT) & 0xff) + 31) / 63;
01251                     bval = ((63 - yf) * ((word0 >> L_BLUE_SHIFT) & 0xff) +
01252                            yf * ((word1 >> L_BLUE_SHIFT) & 0xff) + 31) / 63;
01253                     composeRGBPixel(rval, gval, bval, lined + j);
01254                 }
01255                 else {  /* yp == hm */
01256                     lined[j] = lines[j];
01257                 }
01258             }
01259             break;
01260         default:
01261             L_ERROR_INT("invalid depth: %d", procName, d);
01262             pixDestroy(&pix);
01263             pixDestroy(&pixd);
01264             return NULL;
01265         }
01266     }
01267 
01268     pixDestroy(&pix);
01269     return pixd;
01270 }
01271 
01272 
01273 /*----------------------------------------------------------------------*
01274  *                     Stereo from a pair of images                     *
01275  *----------------------------------------------------------------------*/
01276 /*!
01277  *  pixStereoFromPair()
01278  *
01279  *      Input:  pix1 (32 bpp rgb)
01280  *              pix2 (32 bpp rgb)
01281  *              rwt, gwt, bwt (weighting factors used for each component in
01282                                pix1 to determine the output red channel)
01283  *      Return: pixd (stereo enhanced), or null on error
01284  *
01285  *  Notes:
01286  *      (1) pix1 and pix2 are a pair of stereo images, ideally taken
01287  *          concurrently in the same plane, with some lateral translation.
01288  *      (2) The output red channel is determined from @pix1.
01289  *          The output green and blue channels are taken from the green
01290  *          and blue channels, respectively, of @pix2.
01291  *      (3) The weights determine how much of each component in @pix1
01292  *          goes into the output red channel.  The sum of weights
01293  *          must be 1.0.  If it's not, we scale the weights to
01294  *          satisfy this criterion.
01295  *      (4) The most general pixel mapping allowed here is:
01296  *            rval = rwt * r1 + gwt * g1 + bwt * b1  (from pix1)
01297  *            gval = g2   (from pix2)
01298  *            bval = b2   (from pix2)
01299  *      (5) The simplest method is to use rwt = 1.0, gwt = 0.0, bwt = 0.0,
01300  *          but this causes unpleasant visual artifacts with red in the image.
01301  *          Use of green and blue from @pix1 in the red channel,
01302  *          instead of red, tends to fix that problem.
01303  */
01304 PIX *
01305 pixStereoFromPair(PIX       *pix1,
01306                   PIX       *pix2,
01307                   l_float32  rwt,
01308                   l_float32  gwt,
01309                   l_float32  bwt)
01310 {
01311 l_int32    i, j, w, h, wpl1, wpl2, rval, gval, bval;
01312 l_uint32   word1, word2;
01313 l_uint32  *data1, *data2, *datad, *line1, *line2, *lined;
01314 l_float32  sum;
01315 PIX       *pixd;
01316 
01317     PROCNAME("pixStereoFromPair");
01318 
01319     if (!pix1 || !pix2)
01320         return (PIX *)ERROR_PTR("pix1, pix2 not both defined", procName, NULL);
01321     if (pixGetDepth(pix1) != 32 || pixGetDepth(pix2) != 32)
01322         return (PIX *)ERROR_PTR("pix1, pix2 not both 32 bpp", procName, NULL);
01323 
01324         /* Make sure the sum of weights is 1.0; otherwise, you can get
01325          * overflow in the gray value. */
01326     if (rwt == 0.0 && gwt == 0.0 && bwt == 0.0) {
01327         rwt = L_DEFAULT_RED_WEIGHT;
01328         gwt = L_DEFAULT_GREEN_WEIGHT;
01329         bwt = L_DEFAULT_BLUE_WEIGHT;
01330     }
01331     sum = rwt + gwt + bwt;
01332     if (L_ABS(sum - 1.0) > 0.0001) {  /* maintain ratios with sum == 1.0 */
01333         L_WARNING("weights don't sum to 1; maintaining ratios", procName);
01334         rwt = rwt / sum;
01335         gwt = gwt / sum;
01336         bwt = bwt / sum;
01337     }
01338 
01339     pixGetDimensions(pix1, &w, &h, NULL);
01340     pixd = pixCreateTemplate(pix1);
01341     data1 = pixGetData(pix1);
01342     data2 = pixGetData(pix2);
01343     datad = pixGetData(pixd);
01344     wpl1 = pixGetWpl(pix1);
01345     wpl2 = pixGetWpl(pix2);
01346     for (i = 0; i < h; i++) {
01347         line1 = data1 + i * wpl1;
01348         line2 = data2 + i * wpl2;
01349         lined = datad + i * wpl1;  /* wpl1 works for pixd */
01350         for (j = 0; j < w; j++) {
01351             word1 = *(line1 + j);
01352             word2 = *(line2 + j);
01353             rval = (l_int32)(rwt * ((word1 >> L_RED_SHIFT) & 0xff) +
01354                              gwt * ((word1 >> L_GREEN_SHIFT) & 0xff) +
01355                              bwt * ((word1 >> L_BLUE_SHIFT) & 0xff) + 0.5);
01356             gval = (word2 >> L_GREEN_SHIFT) & 0xff;
01357             bval = (word2 >> L_BLUE_SHIFT) & 0xff;
01358             composeRGBPixel(rval, gval, bval, lined + j);
01359         }
01360     }
01361 
01362     return pixd;
01363 }
01364 
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines