Leptonica 1.68
C Image Processing Library

bilinear.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  *  bilinear.c
00019  *
00020  *      Bilinear (4 pt) image transformation using a sampled
00021  *      (to nearest integer) transform on each dest point
00022  *           PIX      *pixBilinearSampledPta()
00023  *           PIX      *pixBilinearSampled()
00024  *
00025  *      Bilinear (4 pt) image transformation using interpolation 
00026  *      (or area mapping) for anti-aliasing images that are
00027  *      2, 4, or 8 bpp gray, or colormapped, or 32 bpp RGB
00028  *           PIX      *pixBilinearPta()
00029  *           PIX      *pixBilinear()
00030  *           PIX      *pixBilinearPtaColor()
00031  *           PIX      *pixBilinearColor()
00032  *           PIX      *pixBilinearPtaGray()
00033  *           PIX      *pixBilinearGray()
00034  *
00035  *      Bilinear transform including alpha (blend) component and gamma xform
00036  *           PIX      *pixBilinearPtaWithAlpha()
00037  *           PIX      *pixBilinearPtaGammaXform()
00038  *
00039  *      Bilinear coordinate transformation
00040  *           l_int32   getBilinearXformCoeffs()
00041  *           l_int32   bilinearXformSampledPt()
00042  *           l_int32   bilinearXformPt()
00043  *
00044  *      A bilinear transform can be specified as a specific functional
00045  *      mapping between 4 points in the source and 4 points in the dest.
00046  *      It can be used as an approximation to a (nonlinear) projective
00047  *      transform, because for small warps it is very similar and
00048  *      it is more stable.  (Projective transforms have a division
00049  *      by a quantity that can get arbitrarily small.)
00050  *
00051  *      We give both a bilinear coordinate transformation and
00052  *      a bilinear image transformation.
00053  *
00054  *      For the former, we ask for the coordinate value (x',y')
00055  *      in the transformed space for any point (x,y) in the original
00056  *      space.  The coefficients of the transformation are found by
00057  *      solving 8 simultaneous equations for the 8 coordinates of
00058  *      the 4 points in src and dest.  The transformation can then
00059  *      be used to compute the associated image transform, by
00060  *      computing, for each dest pixel, the relevant pixel(s) in
00061  *      the source.  This can be done either by taking the closest
00062  *      src pixel to each transformed dest pixel ("sampling") or
00063  *      by doing an interpolation and averaging over 4 source 
00064  *      pixels with appropriate weightings ("interpolated").
00065  *
00066  *      A typical application would be to remove some of the 
00067  *      keystoning due to a projective transform in the imaging system.
00068  *
00069  *      The bilinear transform is given by specifying two equations:
00070  *
00071  *          x' = ax + by + cxy + d
00072  *          y' = ex + fy + gxy + h
00073  *
00074  *      where the eight coefficients have been computed from four
00075  *      sets of these equations, each for two corresponding data pts.
00076  *      In practice, for each point (x,y) in the dest image, this
00077  *      equation is used to compute the corresponding point (x',y')
00078  *      in the src.  That computed point in the src is then used
00079  *      to determine the dest value in one of two ways:
00080  *
00081  *       - sampling: take the value of the src pixel in which this
00082  *                   point falls
00083  *       - interpolation: take appropriate linear combinations of the
00084  *                        four src pixels that this dest pixel would
00085  *                        overlap, with the coefficients proportional
00086  *                        to the amount of overlap
00087  *
00088  *      For small warp, like rotation, area mapping in the
00089  *      interpolation is equivalent to linear interpolation.
00090  *
00091  *      Typical relative timing of transforms (sampled = 1.0):
00092  *      8 bpp:   sampled        1.0
00093  *               interpolated   1.6
00094  *      32 bpp:  sampled        1.0
00095  *               interpolated   1.8
00096  *      Additionally, the computation time/pixel is nearly the same
00097  *      for 8 bpp and 32 bpp, for both sampled and interpolated.
00098  */
00099 
00100 #include <stdio.h>
00101 #include <stdlib.h>
00102 #include <string.h>
00103 #include <math.h>
00104 #include "allheaders.h"
00105 
00106 extern l_float32  AlphaMaskBorderVals[2];
00107 
00108 
00109 /*-------------------------------------------------------------*
00110  *             Sampled bilinear image transformation           *
00111  *-------------------------------------------------------------*/
00112 /*!
00113  *  pixBilinearSampledPta()
00114  *
00115  *      Input:  pixs (all depths)
00116  *              ptad  (4 pts of final coordinate space)
00117  *              ptas  (4 pts of initial coordinate space)
00118  *              incolor (L_BRING_IN_WHITE, L_BRING_IN_BLACK)
00119  *      Return: pixd, or null on error
00120  *
00121  *  Notes:
00122  *      (1) Brings in either black or white pixels from the boundary.
00123  *      (2) Retains colormap, which you can do for a sampled transform..
00124  *      (3) No 3 of the 4 points may be collinear.
00125  *      (4) For 8 and 32 bpp pix, better quality is obtained by the
00126  *          somewhat slower pixBilinearPta().  See that
00127  *          function for relative timings between sampled and interpolated.
00128  */
00129 PIX *
00130 pixBilinearSampledPta(PIX     *pixs,
00131                       PTA     *ptad,
00132                       PTA     *ptas,
00133                       l_int32  incolor)
00134 {
00135 l_float32  *vc;
00136 PIX        *pixd;
00137 
00138     PROCNAME("pixBilinearSampledPta");
00139 
00140     if (!pixs)
00141         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
00142     if (!ptas)
00143         return (PIX *)ERROR_PTR("ptas not defined", procName, NULL);
00144     if (!ptad)
00145         return (PIX *)ERROR_PTR("ptad not defined", procName, NULL);
00146     if (incolor != L_BRING_IN_WHITE && incolor != L_BRING_IN_BLACK)
00147         return (PIX *)ERROR_PTR("invalid incolor", procName, NULL);
00148     if (ptaGetCount(ptas) != 4)
00149         return (PIX *)ERROR_PTR("ptas count not 4", procName, NULL);
00150     if (ptaGetCount(ptad) != 4)
00151         return (PIX *)ERROR_PTR("ptad count not 4", procName, NULL);
00152 
00153         /* Get backwards transform from dest to src, and apply it */
00154     getBilinearXformCoeffs(ptad, ptas, &vc);
00155     pixd = pixBilinearSampled(pixs, vc, incolor);
00156     FREE(vc);
00157 
00158     return pixd;
00159 }
00160 
00161 
00162 /*!
00163  *  pixBilinearSampled()
00164  *
00165  *      Input:  pixs (all depths)
00166  *              vc  (vector of 8 coefficients for bilinear transformation)
00167  *              incolor (L_BRING_IN_WHITE, L_BRING_IN_BLACK)
00168  *      Return: pixd, or null on error
00169  *
00170  *  Notes:
00171  *      (1) Brings in either black or white pixels from the boundary.
00172  *      (2) Retains colormap, which you can do for a sampled transform..
00173  *      (3) For 8 or 32 bpp, much better quality is obtained by the
00174  *          somewhat slower pixBilinear().  See that function
00175  *          for relative timings between sampled and interpolated.
00176  */
00177 PIX *
00178 pixBilinearSampled(PIX        *pixs,
00179                    l_float32  *vc,
00180                    l_int32     incolor)
00181 {
00182 l_int32     i, j, w, h, d, x, y, wpls, wpld, color, cmapindex;
00183 l_uint32    val;
00184 l_uint32   *datas, *datad, *lines, *lined;
00185 PIX        *pixd;
00186 PIXCMAP    *cmap;
00187 
00188     PROCNAME("pixBilinearSampled");
00189 
00190     if (!pixs)
00191         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
00192     if (!vc)
00193         return (PIX *)ERROR_PTR("vc not defined", procName, NULL);
00194     if (incolor != L_BRING_IN_WHITE && incolor != L_BRING_IN_BLACK)
00195         return (PIX *)ERROR_PTR("invalid incolor", procName, NULL);
00196     pixGetDimensions(pixs, &w, &h, &d);
00197     if (d != 1 && d != 2 && d != 4 && d != 8 && d != 32)
00198         return (PIX *)ERROR_PTR("depth not 1, 2, 4, 8 or 16", procName, NULL);
00199 
00200         /* Init all dest pixels to color to be brought in from outside */
00201     pixd = pixCreateTemplate(pixs);
00202     if ((cmap = pixGetColormap(pixs)) != NULL) {
00203         if (incolor == L_BRING_IN_WHITE)
00204             color = 1;
00205         else
00206             color = 0;
00207         pixcmapAddBlackOrWhite(cmap, color, &cmapindex);
00208         pixSetAllArbitrary(pixd, cmapindex);
00209     }
00210     else {
00211         if ((d == 1 && incolor == L_BRING_IN_WHITE) ||
00212             (d > 1 && incolor == L_BRING_IN_BLACK))
00213             pixClearAll(pixd);
00214         else
00215             pixSetAll(pixd);
00216     }
00217 
00218         /* Scan over the dest pixels */
00219     datas = pixGetData(pixs);
00220     wpls = pixGetWpl(pixs);
00221     datad = pixGetData(pixd);
00222     wpld = pixGetWpl(pixd);
00223     for (i = 0; i < h; i++) {
00224         lined = datad + i * wpld;
00225         for (j = 0; j < w; j++) {
00226             bilinearXformSampledPt(vc, j, i, &x, &y);
00227             if (x < 0 || y < 0 || x >=w || y >= h)
00228                 continue;
00229             lines = datas + y * wpls;
00230             if (d == 1) {
00231                 val = GET_DATA_BIT(lines, x);
00232                 SET_DATA_BIT_VAL(lined, j, val);
00233             }
00234             else if (d == 8) {
00235                 val = GET_DATA_BYTE(lines, x);
00236                 SET_DATA_BYTE(lined, j, val);
00237             }
00238             else if (d == 32) {
00239                 lined[j] = lines[x];
00240             }
00241             else if (d == 2) {
00242                 val = GET_DATA_DIBIT(lines, x);
00243                 SET_DATA_DIBIT(lined, j, val);
00244             }
00245             else if (d == 4) {
00246                 val = GET_DATA_QBIT(lines, x);
00247                 SET_DATA_QBIT(lined, j, val);
00248             }
00249         }
00250     }
00251 
00252     return pixd;
00253 }
00254 
00255 
00256 /*---------------------------------------------------------------------*
00257  *            Interpolated bilinear image transformation             *
00258  *---------------------------------------------------------------------*/
00259 /*!
00260  *  pixBilinearPta()
00261  *
00262  *      Input:  pixs (all depths; colormap ok)
00263  *              ptad  (4 pts of final coordinate space)
00264  *              ptas  (4 pts of initial coordinate space)
00265  *              incolor (L_BRING_IN_WHITE, L_BRING_IN_BLACK)
00266  *      Return: pixd, or null on error
00267  *
00268  *  Notes:
00269  *      (1) Brings in either black or white pixels from the boundary
00270  *      (2) Removes any existing colormap, if necessary, before transforming
00271  */
00272 PIX *
00273 pixBilinearPta(PIX     *pixs,
00274                PTA     *ptad,
00275                PTA     *ptas,
00276                l_int32  incolor)
00277 {
00278 l_int32   d;
00279 l_uint32  colorval;
00280 PIX      *pixt1, *pixt2, *pixd;
00281 
00282     PROCNAME("pixBilinearPta");
00283 
00284     if (!pixs)
00285         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
00286     if (!ptas)
00287         return (PIX *)ERROR_PTR("ptas not defined", procName, NULL);
00288     if (!ptad)
00289         return (PIX *)ERROR_PTR("ptad not defined", procName, NULL);
00290     if (incolor != L_BRING_IN_WHITE && incolor != L_BRING_IN_BLACK)
00291         return (PIX *)ERROR_PTR("invalid incolor", procName, NULL);
00292     if (ptaGetCount(ptas) != 4)
00293         return (PIX *)ERROR_PTR("ptas count not 4", procName, NULL);
00294     if (ptaGetCount(ptad) != 4)
00295         return (PIX *)ERROR_PTR("ptad count not 4", procName, NULL);
00296 
00297     if (pixGetDepth(pixs) == 1)
00298         return pixBilinearSampledPta(pixs, ptad, ptas, incolor);
00299 
00300         /* Remove cmap if it exists, and unpack to 8 bpp if necessary */
00301     pixt1 = pixRemoveColormap(pixs, REMOVE_CMAP_BASED_ON_SRC);
00302     d = pixGetDepth(pixt1);
00303     if (d < 8)
00304         pixt2 = pixConvertTo8(pixt1, FALSE);
00305     else
00306         pixt2 = pixClone(pixt1);
00307     d = pixGetDepth(pixt2);
00308 
00309         /* Compute actual color to bring in from edges */
00310     colorval = 0;
00311     if (incolor == L_BRING_IN_WHITE) {
00312         if (d == 8)
00313             colorval = 255;
00314         else  /* d == 32 */
00315             colorval = 0xffffff00;
00316     }
00317     
00318     if (d == 8)
00319         pixd = pixBilinearPtaGray(pixt2, ptad, ptas, colorval);
00320     else  /* d == 32 */
00321         pixd = pixBilinearPtaColor(pixt2, ptad, ptas, colorval);
00322     pixDestroy(&pixt1);
00323     pixDestroy(&pixt2);
00324     return pixd;
00325 }
00326 
00327 
00328 /*!
00329  *  pixBilinear()
00330  *
00331  *      Input:  pixs (all depths; colormap ok)
00332  *              vc  (vector of 8 coefficients for bilinear transformation)
00333  *              incolor (L_BRING_IN_WHITE, L_BRING_IN_BLACK)
00334  *      Return: pixd, or null on error
00335  *
00336  *  Notes:
00337  *      (1) Brings in either black or white pixels from the boundary
00338  *      (2) Removes any existing colormap, if necessary, before transforming
00339  */
00340 PIX *
00341 pixBilinear(PIX        *pixs,
00342             l_float32  *vc,
00343             l_int32     incolor)
00344 {
00345 l_int32   d;
00346 l_uint32  colorval;
00347 PIX      *pixt1, *pixt2, *pixd;
00348 
00349     PROCNAME("pixBilinear");
00350 
00351     if (!pixs)
00352         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
00353     if (!vc)
00354         return (PIX *)ERROR_PTR("vc not defined", procName, NULL);
00355 
00356     if (pixGetDepth(pixs) == 1)
00357         return pixBilinearSampled(pixs, vc, incolor);
00358 
00359         /* Remove cmap if it exists, and unpack to 8 bpp if necessary */
00360     pixt1 = pixRemoveColormap(pixs, REMOVE_CMAP_BASED_ON_SRC);
00361     d = pixGetDepth(pixt1);
00362     if (d < 8)
00363         pixt2 = pixConvertTo8(pixt1, FALSE);
00364     else
00365         pixt2 = pixClone(pixt1);
00366     d = pixGetDepth(pixt2);
00367 
00368         /* Compute actual color to bring in from edges */
00369     colorval = 0;
00370     if (incolor == L_BRING_IN_WHITE) {
00371         if (d == 8)
00372             colorval = 255;
00373         else  /* d == 32 */
00374             colorval = 0xffffff00;
00375     }
00376     
00377     if (d == 8)
00378         pixd = pixBilinearGray(pixt2, vc, colorval);
00379     else  /* d == 32 */
00380         pixd = pixBilinearColor(pixt2, vc, colorval);
00381     pixDestroy(&pixt1);
00382     pixDestroy(&pixt2);
00383     return pixd;
00384 }
00385 
00386 
00387 /*!
00388  *  pixBilinearPtaColor()
00389  *
00390  *      Input:  pixs (32 bpp)
00391  *              ptad  (4 pts of final coordinate space)
00392  *              ptas  (4 pts of initial coordinate space)
00393  *              colorval (e.g., 0 to bring in BLACK, 0xffffff00 for WHITE)
00394  *      Return: pixd, or null on error
00395  */
00396 PIX *
00397 pixBilinearPtaColor(PIX      *pixs,
00398                     PTA      *ptad,
00399                     PTA      *ptas,
00400                     l_uint32  colorval)
00401 {
00402 l_float32  *vc;
00403 PIX        *pixd;
00404 
00405     PROCNAME("pixBilinearPtaColor");
00406 
00407     if (!pixs)
00408         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
00409     if (!ptas)
00410         return (PIX *)ERROR_PTR("ptas not defined", procName, NULL);
00411     if (!ptad)
00412         return (PIX *)ERROR_PTR("ptad not defined", procName, NULL);
00413     if (pixGetDepth(pixs) != 32)
00414         return (PIX *)ERROR_PTR("pixs must be 32 bpp", procName, NULL);
00415     if (ptaGetCount(ptas) != 4)
00416         return (PIX *)ERROR_PTR("ptas count not 4", procName, NULL);
00417     if (ptaGetCount(ptad) != 4)
00418         return (PIX *)ERROR_PTR("ptad count not 4", procName, NULL);
00419 
00420         /* Get backwards transform from dest to src, and apply it */
00421     getBilinearXformCoeffs(ptad, ptas, &vc);
00422     pixd = pixBilinearColor(pixs, vc, colorval);
00423     FREE(vc);
00424 
00425     return pixd;
00426 }
00427 
00428 
00429 /*!
00430  *  pixBilinearColor()
00431  *
00432  *      Input:  pixs (32 bpp)
00433  *              vc  (vector of 8 coefficients for bilinear transformation)
00434  *              colorval (e.g., 0 to bring in BLACK, 0xffffff00 for WHITE)
00435  *      Return: pixd, or null on error
00436  */
00437 PIX *
00438 pixBilinearColor(PIX        *pixs,
00439                  l_float32  *vc,
00440                  l_uint32    colorval)
00441 {
00442 l_int32    i, j, w, h, d, wpls, wpld;
00443 l_uint32   val;
00444 l_uint32  *datas, *datad, *lined;
00445 l_float32  x, y;
00446 PIX       *pixd;
00447 
00448     PROCNAME("pixBilinearColor");
00449 
00450     if (!pixs)
00451         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
00452     pixGetDimensions(pixs, &w, &h, &d);
00453     if (d != 32)
00454         return (PIX *)ERROR_PTR("pixs must be 32 bpp", procName, NULL);
00455     if (!vc)
00456         return (PIX *)ERROR_PTR("vc not defined", procName, NULL);
00457 
00458     datas = pixGetData(pixs);
00459     wpls = pixGetWpl(pixs);
00460     pixd = pixCreateTemplate(pixs);
00461     pixSetAllArbitrary(pixd, colorval);
00462     datad = pixGetData(pixd);
00463     wpld = pixGetWpl(pixd);
00464 
00465         /* Iterate over destination pixels */
00466     for (i = 0; i < h; i++) {
00467         lined = datad + i * wpld;
00468         for (j = 0; j < w; j++) {
00469                 /* Compute float src pixel location corresponding to (i,j) */
00470             bilinearXformPt(vc, j, i, &x, &y);
00471             linearInterpolatePixelColor(datas, wpls, w, h, x, y, colorval,
00472                                         &val);
00473             *(lined + j) = val;
00474         }
00475     }
00476 
00477     return pixd;
00478 }
00479 
00480 
00481 /*!
00482  *  pixBilinearPtaGray()
00483  *
00484  *      Input:  pixs (8 bpp)
00485  *              ptad  (4 pts of final coordinate space)
00486  *              ptas  (4 pts of initial coordinate space)
00487  *              grayval (0 to bring in BLACK, 255 for WHITE)
00488  *      Return: pixd, or null on error
00489  */
00490 PIX *
00491 pixBilinearPtaGray(PIX     *pixs,
00492                    PTA     *ptad,
00493                    PTA     *ptas,
00494                    l_uint8  grayval)
00495 {
00496 l_float32  *vc;
00497 PIX        *pixd;
00498 
00499     PROCNAME("pixBilinearPtaGray");
00500 
00501     if (!pixs)
00502         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
00503     if (!ptas)
00504         return (PIX *)ERROR_PTR("ptas not defined", procName, NULL);
00505     if (!ptad)
00506         return (PIX *)ERROR_PTR("ptad not defined", procName, NULL);
00507     if (pixGetDepth(pixs) != 8)
00508         return (PIX *)ERROR_PTR("pixs must be 8 bpp", procName, NULL);
00509     if (ptaGetCount(ptas) != 4)
00510         return (PIX *)ERROR_PTR("ptas count not 4", procName, NULL);
00511     if (ptaGetCount(ptad) != 4)
00512         return (PIX *)ERROR_PTR("ptad count not 4", procName, NULL);
00513 
00514         /* Get backwards transform from dest to src, and apply it */
00515     getBilinearXformCoeffs(ptad, ptas, &vc);
00516     pixd = pixBilinearGray(pixs, vc, grayval);
00517     FREE(vc);
00518 
00519     return pixd;
00520 }
00521 
00522 
00523 /*!
00524  *  pixBilinearGray()
00525  *
00526  *      Input:  pixs (8 bpp)
00527  *              vc  (vector of 8 coefficients for bilinear transformation)
00528  *              grayval (0 to bring in BLACK, 255 for WHITE)
00529  *      Return: pixd, or null on error
00530  */
00531 PIX *
00532 pixBilinearGray(PIX        *pixs,
00533                 l_float32  *vc,
00534                 l_uint8     grayval)
00535 {
00536 l_int32    i, j, w, h, wpls, wpld, val;
00537 l_uint32  *datas, *datad, *lined;
00538 l_float32  x, y;
00539 PIX       *pixd;
00540 
00541     PROCNAME("pixBilinearGray");
00542 
00543     if (!pixs)
00544         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
00545     pixGetDimensions(pixs, &w, &h, NULL);
00546     if (pixGetDepth(pixs) != 8)
00547         return (PIX *)ERROR_PTR("pixs must be 8 bpp", procName, NULL);
00548     if (!vc)
00549         return (PIX *)ERROR_PTR("vc not defined", procName, NULL);
00550 
00551     datas = pixGetData(pixs);
00552     wpls = pixGetWpl(pixs);
00553     pixd = pixCreateTemplate(pixs);
00554     pixSetAllArbitrary(pixd, grayval);
00555     datad = pixGetData(pixd);
00556     wpld = pixGetWpl(pixd);
00557 
00558         /* Iterate over destination pixels */
00559     for (i = 0; i < h; i++) {
00560         lined = datad + i * wpld;
00561         for (j = 0; j < w; j++) {
00562                 /* Compute float src pixel location corresponding to (i,j) */
00563             bilinearXformPt(vc, j, i, &x, &y);
00564             linearInterpolatePixelGray(datas, wpls, w, h, x, y, grayval, &val);
00565             SET_DATA_BYTE(lined, j, val);
00566         }
00567     }
00568 
00569     return pixd;
00570 }
00571 
00572 
00573 /*-------------------------------------------------------------------------*
00574  *  Bilinear transform including alpha (blend) component and gamma xform   *
00575  *-------------------------------------------------------------------------*/
00576 /*!
00577  *  pixBilinearPtaWithAlpha()
00578  *
00579  *      Input:  pixs (32 bpp rgb)
00580  *              ptad  (4 pts of final coordinate space)
00581  *              ptas  (4 pts of initial coordinate space)
00582  *              pixg (<optional> 8 bpp, can be null)
00583  *              fract (between 0.0 and 1.0, with 0.0 fully transparent
00584  *                     and 1.0 fully opaque)
00585  *              border (of pixels added to capture transformed source pixels)
00586  *      Return: pixd, or null on error
00587  *
00588  *  Notes:
00589  *      (1) The alpha channel is transformed separately from pixs,
00590  *          and aligns with it, being fully transparent outside the
00591  *          boundary of the transformed pixs.  For pixels that are fully
00592  *          transparent, a blending function like pixBlendWithGrayMask()
00593  *          will give zero weight to corresponding pixels in pixs.
00594  *      (2) If pixg is NULL, it is generated as an alpha layer that is
00595  *          partially opaque, using @fract.  Otherwise, it is cropped
00596  *          to pixs if required and @fract is ignored.  The alpha channel
00597  *          in pixs is never used.
00598  *      (3) Colormaps are removed.
00599  *      (4) When pixs is transformed, it doesn't matter what color is brought
00600  *          in because the alpha channel will be transparent (0) there.
00601  *      (5) To avoid losing source pixels in the destination, it may be
00602  *          necessary to add a border to the source pix before doing
00603  *          the bilinear transformation.  This can be any non-negative number.
00604  *      (6) The input @ptad and @ptas are in a coordinate space before
00605  *          the border is added.  Internally, we compensate for this
00606  *          before doing the bilinear transform on the image after
00607  *          the border is added.
00608  *      (7) The default setting for the border values in the alpha channel
00609  *          is 0 (transparent) for the outermost ring of pixels and
00610  *          (0.5 * fract * 255) for the second ring.  When blended over
00611  *          a second image, this
00612  *          (a) shrinks the visible image to make a clean overlap edge
00613  *              with an image below, and
00614  *          (b) softens the edges by weakening the aliasing there.
00615  *          Use l_setAlphaMaskBorder() to change these values.
00616  */
00617 PIX *
00618 pixBilinearPtaWithAlpha(PIX       *pixs,
00619                         PTA       *ptad,
00620                         PTA       *ptas,
00621                         PIX       *pixg,
00622                         l_float32  fract,
00623                         l_int32    border)
00624 {
00625 l_int32  ws, hs, d;
00626 PIX     *pixd, *pixb1, *pixb2, *pixg2, *pixga;
00627 PTA     *ptad2, *ptas2;
00628 
00629     PROCNAME("pixBilinearPtaWithAlpha");
00630 
00631     if (!pixs)
00632         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
00633     pixGetDimensions(pixs, &ws, &hs, &d);
00634     if (d != 32 && pixGetColormap(pixs) == NULL)
00635         return (PIX *)ERROR_PTR("pixs not cmapped or 32 bpp", procName, NULL);
00636     if (pixg && pixGetDepth(pixg) != 8) {
00637         L_WARNING("pixg not 8 bpp; using @fract transparent alpha", procName);
00638         pixg = NULL;
00639     }
00640     if (!pixg && (fract < 0.0 || fract > 1.0)) {
00641         L_WARNING("invalid fract; using 1.0 (fully transparent)", procName);
00642         fract = 1.0;
00643     }
00644     if (!pixg && fract == 0.0)
00645         L_WARNING("fully opaque alpha; image cannot be blended", procName);
00646     if (!ptad)
00647         return (PIX *)ERROR_PTR("ptad not defined", procName, NULL);
00648     if (!ptas)
00649         return (PIX *)ERROR_PTR("ptas not defined", procName, NULL);
00650 
00651         /* Add border; the color doesn't matter */
00652     pixb1 = pixAddBorder(pixs, border, 0);
00653 
00654         /* Transform the ptr arrays to work on the bordered image */
00655     ptad2 = ptaTransform(ptad, border, border, 1.0, 1.0);
00656     ptas2 = ptaTransform(ptas, border, border, 1.0, 1.0);
00657 
00658         /* Do separate bilinear transform of rgb channels of pixs and of pixg */
00659     pixd = pixBilinearPtaColor(pixb1, ptad2, ptas2, 0);
00660     if (!pixg) {
00661         pixg2 = pixCreate(ws, hs, 8);
00662         if (fract == 1.0)
00663             pixSetAll(pixg2);
00664         else
00665             pixSetAllArbitrary(pixg2, (l_int32)(255.0 * fract));
00666     }
00667     else
00668         pixg2 = pixResizeToMatch(pixg, NULL, ws, hs);
00669     if (ws > 10 && hs > 10) {  /* see note 7 */
00670         pixSetBorderRingVal(pixg2, 1,
00671                             (l_int32)(255.0 * fract * AlphaMaskBorderVals[0]));
00672         pixSetBorderRingVal(pixg2, 2,
00673                             (l_int32)(255.0 * fract * AlphaMaskBorderVals[1]));
00674 
00675     }
00676     pixb2 = pixAddBorder(pixg2, border, 0);  /* must be black border */
00677     pixga = pixBilinearPtaGray(pixb2, ptad2, ptas2, 0);
00678     pixSetRGBComponent(pixd, pixga, L_ALPHA_CHANNEL);
00679 
00680     pixDestroy(&pixg2);
00681     pixDestroy(&pixb1);
00682     pixDestroy(&pixb2);
00683     pixDestroy(&pixga);
00684     ptaDestroy(&ptad2);
00685     ptaDestroy(&ptas2);
00686     return pixd;
00687 }
00688 
00689 
00690 /*!
00691  *  pixBilinearPtaGammaXform()
00692  *
00693  *      Input:  pixs (32 bpp rgb)
00694  *              gamma (gamma correction; must be > 0.0)
00695  *              ptad  (3 pts of final coordinate space)
00696  *              ptas  (3 pts of initial coordinate space)
00697  *              fract (between 0.0 and 1.0, with 1.0 fully transparent)
00698  *              border (of pixels to capture transformed source pixels)
00699  *      Return: pixd, or null on error
00700  *
00701  *  Notes:
00702  *      (1) This wraps a gamma/inverse-gamma photometric transform around
00703  *          pixBilinearPtaWithAlpha().
00704  *      (2) For usage, see notes in pixBilinearPtaWithAlpha() and
00705  *          pixGammaTRCWithAlpha().
00706  *      (3) The basic idea of a gamma/inverse-gamma transform is to remove
00707  *          any gamma correction before the bilinear transform, and restore
00708  *          it afterward.  The effects can be subtle, but important for
00709  *          some applications.  For example, using gamma > 1.0 will
00710  *          cause the dark areas to become somewhat lighter and slightly
00711  *          reduce aliasing effects when blending using the alpha channel.
00712  */
00713 PIX *
00714 pixBilinearPtaGammaXform(PIX       *pixs,
00715                          l_float32  gamma,
00716                          PTA       *ptad,
00717                          PTA       *ptas,
00718                          l_float32  fract,
00719                          l_int32    border)
00720 {
00721 PIX  *pixg, *pixd;
00722 
00723     PROCNAME("pixBilinearPtaGammaXform");
00724 
00725     if (!pixs || (pixGetDepth(pixs) != 32))
00726         return (PIX *)ERROR_PTR("pixs undefined or not 32 bpp", procName, NULL);
00727     if (fract == 0.0)
00728         L_WARNING("fully opaque alpha; image cannot be blended", procName);
00729     if (gamma <= 0.0)  {
00730         L_WARNING("gamma must be > 0.0; setting to 1.0", procName);
00731         gamma = 1.0;
00732     }
00733 
00734     pixg = pixGammaTRCWithAlpha(NULL, pixs, 1.0 / gamma, 0, 255);
00735     pixd = pixBilinearPtaWithAlpha(pixg, ptad, ptas, NULL, fract, border);
00736     pixGammaTRCWithAlpha(pixd, pixd, gamma, 0, 255);
00737     pixDestroy(&pixg);
00738     return  pixd;
00739 }
00740 
00741 
00742 /*-------------------------------------------------------------*
00743  *                Bilinear coordinate transformation           *
00744  *-------------------------------------------------------------*/
00745 /*!
00746  *  getBilinearXformCoeffs()
00747  *
00748  *      Input:  ptas  (source 4 points; unprimed)
00749  *              ptad  (transformed 4 points; primed)
00750  *              &vc   (<return> vector of coefficients of transform)
00751  *      Return: 0 if OK; 1 on error
00752  *
00753  *  We have a set of 8 equations, describing the bilinear
00754  *  transformation that takes 4 points (ptas) into 4 other
00755  *  points (ptad).  These equations are:
00756  *
00757  *          x1' = c[0]*x1 + c[1]*y1 + c[2]*x1*y1 + c[3]
00758  *          y1' = c[4]*x1 + c[5]*y1 + c[6]*x1*y1 + c[7]
00759  *          x2' = c[0]*x2 + c[1]*y2 + c[2]*x2*y2 + c[3]
00760  *          y2' = c[4]*x2 + c[5]*y2 + c[6]*x2*y2 + c[7]
00761  *          x3' = c[0]*x3 + c[1]*y3 + c[2]*x3*y3 + c[3]
00762  *          y3' = c[4]*x3 + c[5]*y3 + c[6]*x3*y3 + c[7]
00763  *          x4' = c[0]*x4 + c[1]*y4 + c[2]*x4*y4 + c[3]
00764  *          y4' = c[4]*x4 + c[5]*y4 + c[6]*x4*y4 + c[7]
00765  *    
00766  *  This can be represented as
00767  *
00768  *           AC = B
00769  *
00770  *  where B and C are column vectors
00771  *    
00772  *         B = [ x1' y1' x2' y2' x3' y3' x4' y4' ]
00773  *         C = [ c[0] c[1] c[2] c[3] c[4] c[5] c[6] c[7] ]
00774  *    
00775  *  and A is the 8x8 matrix
00776  *
00777  *             x1   y1   x1*y1   1   0    0      0     0
00778  *              0    0     0     0   x1   y1   x1*y1   1
00779  *             x2   y2   x2*y2   1   0    0      0     0
00780  *              0    0     0     0   x2   y2   x2*y2   1
00781  *             x3   y3   x3*y3   1   0    0      0     0
00782  *              0    0     0     0   x3   y3   x3*y3   1
00783  *             x4   y4   x4*y4   1   0    0      0     0
00784  *              0    0     0     0   x4   y4   x4*y4   1
00785  *
00786  *  These eight equations are solved here for the coefficients C.
00787  *
00788  *  These eight coefficients can then be used to find the mapping
00789  *  (x,y) --> (x',y'):
00790  *
00791  *           x' = c[0]x + c[1]y + c[2]xy + c[3]
00792  *           y' = c[4]x + c[5]y + c[6]xy + c[7]
00793  *
00794  *  that are implemented in bilinearXformSampledPt() and
00795  *  bilinearXFormPt().
00796  */
00797 l_int32
00798 getBilinearXformCoeffs(PTA         *ptas,
00799                        PTA         *ptad,
00800                        l_float32  **pvc)
00801 {
00802 l_int32     i;
00803 l_float32   x1, y1, x2, y2, x3, y3, x4, y4;
00804 l_float32  *b;   /* rhs vector of primed coords X'; coeffs returned in *pvc */
00805 l_float32  *a[8];  /* 8x8 matrix A  */
00806 
00807     PROCNAME("getBilinearXformCoeffs");
00808 
00809     if (!ptas)
00810         return ERROR_INT("ptas not defined", procName, 1);
00811     if (!ptad)
00812         return ERROR_INT("ptad not defined", procName, 1);
00813     if (!pvc)
00814         return ERROR_INT("&vc not defined", procName, 1);
00815         
00816     if ((b = (l_float32 *)CALLOC(8, sizeof(l_float32))) == NULL)
00817         return ERROR_INT("b not made", procName, 1);
00818     *pvc = b;
00819 
00820     ptaGetPt(ptas, 0, &x1, &y1);
00821     ptaGetPt(ptas, 1, &x2, &y2);
00822     ptaGetPt(ptas, 2, &x3, &y3);
00823     ptaGetPt(ptas, 3, &x4, &y4);
00824     ptaGetPt(ptad, 0, &b[0], &b[1]);
00825     ptaGetPt(ptad, 1, &b[2], &b[3]);
00826     ptaGetPt(ptad, 2, &b[4], &b[5]);
00827     ptaGetPt(ptad, 3, &b[6], &b[7]);
00828 
00829     for (i = 0; i < 8; i++) {
00830         if ((a[i] = (l_float32 *)CALLOC(8, sizeof(l_float32))) == NULL)
00831             return ERROR_INT("a[i] not made", procName, 1);
00832     }
00833 
00834     a[0][0] = x1;
00835     a[0][1] = y1;
00836     a[0][2] = x1 * y1;
00837     a[0][3] = 1.;
00838     a[1][4] = x1;
00839     a[1][5] = y1;
00840     a[1][6] = x1 * y1;
00841     a[1][7] = 1.;
00842     a[2][0] = x2;
00843     a[2][1] = y2;
00844     a[2][2] = x2 * y2;
00845     a[2][3] = 1.;
00846     a[3][4] = x2;
00847     a[3][5] = y2;
00848     a[3][6] = x2 * y2;
00849     a[3][7] = 1.;
00850     a[4][0] = x3;
00851     a[4][1] = y3;
00852     a[4][2] = x3 * y3;
00853     a[4][3] = 1.;
00854     a[5][4] = x3;
00855     a[5][5] = y3;
00856     a[5][6] = x3 * y3;
00857     a[5][7] = 1.;
00858     a[6][0] = x4;
00859     a[6][1] = y4;
00860     a[6][2] = x4 * y4;
00861     a[6][3] = 1.;
00862     a[7][4] = x4;
00863     a[7][5] = y4;
00864     a[7][6] = x4 * y4;
00865     a[7][7] = 1.;
00866 
00867     gaussjordan(a, b, 8);
00868 
00869     for (i = 0; i < 8; i++)
00870         FREE(a[i]);
00871 
00872     return 0;
00873 }
00874 
00875 
00876 /*!
00877  *  bilinearXformSampledPt()
00878  *
00879  *      Input:  vc (vector of 8 coefficients)
00880  *              (x, y)  (initial point)
00881  *              (&xp, &yp)   (<return> transformed point)
00882  *      Return: 0 if OK; 1 on error
00883  *
00884  *  Notes:
00885  *      (1) This finds the nearest pixel coordinates of the transformed point.
00886  *      (2) It does not check ptrs for returned data!
00887  */
00888 l_int32
00889 bilinearXformSampledPt(l_float32  *vc,
00890                        l_int32     x,
00891                        l_int32     y,
00892                        l_int32    *pxp,
00893                        l_int32    *pyp)
00894 {
00895 
00896     PROCNAME("bilinearXformSampledPt");
00897 
00898     if (!vc)
00899         return ERROR_INT("vc not defined", procName, 1);
00900 
00901     *pxp = (l_int32)(vc[0] * x + vc[1] * y + vc[2] * x * y + vc[3] + 0.5);
00902     *pyp = (l_int32)(vc[4] * x + vc[5] * y + vc[6] * x * y + vc[7] + 0.5);
00903     return 0;
00904 }
00905 
00906 
00907 /*!
00908  *  bilinearXformPt()
00909  *
00910  *      Input:  vc (vector of 8 coefficients)
00911  *              (x, y)  (initial point)
00912  *              (&xp, &yp)   (<return> transformed point)
00913  *      Return: 0 if OK; 1 on error
00914  *
00915  *  Notes:
00916  *      (1) This computes the floating point location of the transformed point.
00917  *      (2) It does not check ptrs for returned data!
00918  */
00919 l_int32
00920 bilinearXformPt(l_float32  *vc,
00921                 l_int32     x,
00922                 l_int32     y,
00923                 l_float32  *pxp,
00924                 l_float32  *pyp)
00925 {
00926     PROCNAME("bilinearXformPt");
00927 
00928     if (!vc)
00929         return ERROR_INT("vc not defined", procName, 1);
00930 
00931     *pxp = vc[0] * x + vc[1] * y + vc[2] * x * y + vc[3];
00932     *pyp = vc[4] * x + vc[5] * y + vc[6] * x * y + vc[7];
00933     return 0;
00934 }
00935 
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines