Leptonica 1.68
C Image Processing Library

affine.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  *  affine.c
00019  *
00020  *      Affine (3 pt) image transformation using a sampled
00021  *      (to nearest integer) transform on each dest point
00022  *           PIX        *pixAffineSampledPta()
00023  *           PIX        *pixAffineSampled()
00024  *
00025  *      Affine (3 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        *pixAffinePta()
00029  *           PIX        *pixAffine()
00030  *           PIX        *pixAffinePtaColor()
00031  *           PIX        *pixAffineColor()
00032  *           PIX        *pixAffinePtaGray()
00033  *           PIX        *pixAffineGray()
00034  *
00035  *      Affine transform including alpha (blend) component and gamma transform
00036  *           PIX        *pixAffinePtaWithAlpha()
00037  *           PIX        *pixAffinePtaGammaXform()
00038  *
00039  *      Affine coordinate transformation
00040  *           l_int32     getAffineXformCoeffs()
00041  *           l_int32     affineInvertXform()
00042  *           l_int32     affineXformSampledPt()
00043  *           l_int32     affineXformPt()
00044  *
00045  *      Interpolation helper functions
00046  *           l_int32     linearInterpolatePixelGray()
00047  *           l_int32     linearInterpolatePixelColor()
00048  *
00049  *      Gauss-jordan linear equation solver
00050  *           l_int32     gaussjordan()
00051  *
00052  *      Affine image transformation using a sequence of 
00053  *      shear/scale/translation operations
00054  *           PIX        *pixAffineSequential()
00055  *
00056  *      One can define a coordinate space by the location of the origin,
00057  *      the orientation of x and y axes, and the unit scaling along
00058  *      each axis.  An affine transform is a general linear
00059  *      transformation from one coordinate space to another.
00060  *
00061  *      For the general case, we can define the affine transform using
00062  *      two sets of three (noncollinear) points in a plane.  One set
00063  *      corresponds to the input (src) coordinate space; the other to the 
00064  *      transformed (dest) coordinate space.  Each point in the
00065  *      src corresponds to one of the points in the dest.  With two
00066  *      sets of three points, we get a set of 6 equations in 6 unknowns
00067  *      that specifies the mapping between the coordinate spaces.
00068  *      The interface here allows you to specify either the corresponding
00069  *      sets of 3 points, or the transform itself (as a vector of 6
00070  *      coefficients).
00071  *
00072  *      Given the transform as a vector of 6 coefficients, we can compute
00073  *      both a a pointwise affine coordinate transformation and an
00074  *      affine image transformation.
00075  *
00076  *      To compute the coordinate transform, we need the coordinate
00077  *      value (x',y') in the transformed space for any point (x,y)
00078  *      in the original space.  To derive this transform from the
00079  *      three corresponding points, it is convenient to express the affine
00080  *      coordinate transformation using an LU decomposition of
00081  *      a set of six linear equations that express the six coordinates
00082  *      of the three points in the transformed space as a function of
00083  *      the six coordinates in the original space.  Once we have
00084  *      this transform matrix , we can transform an image by
00085  *      finding, for each destination pixel, the pixel (or pixels)
00086  *      in the source that give rise to it.
00087  *
00088  *      This 'pointwise' transformation can be done either by sampling
00089  *      and picking a single pixel in the src to replicate into the dest,
00090  *      or by interpolating (or averaging) over four src pixels to
00091  *      determine the value of the dest pixel.  The first method is
00092  *      implemented by pixAffineSampled() and the second method by
00093  *      pixAffine().  The interpolated method can only be used for
00094  *      images with more than 1 bpp, but for these, the image quality
00095  *      is significantly better than the sampled method, due to
00096  *      the 'antialiasing' effect of weighting the src pixels.
00097  *
00098  *      Interpolation works well when there is relatively little scaling,
00099  *      or if there is image expansion in general.  However, if there
00100  *      is significant image reduction, one should apply a low-pass
00101  *      filter before subsampling to avoid aliasing the high frequencies.
00102  *
00103  *      A typical application might be to align two images, which
00104  *      may be scaled, rotated and translated versions of each other.
00105  *      Through some pre-processing, three corresponding points are
00106  *      located in each of the two images.  One of the images is
00107  *      then to be (affine) transformed to align with the other.
00108  *      As mentioned, the standard way to do this is to use three
00109  *      sets of points, compute the 6 transformation coefficients
00110  *      from these points that describe the linear transformation,
00111  *
00112  *          x' = ax + by + c
00113  *          y' = dx + ey + f
00114  *
00115  *      and use this in a pointwise manner to transform the image.
00116  *
00117  *      N.B.  Be sure to see the comment in getAffineXformCoeffs(),
00118  *      regarding using the inverse of the affine transform for points
00119  *      to transform images.
00120  *
00121  *      There is another way to do this transformation; namely,
00122  *      by doing a sequence of simple affine transforms, without
00123  *      computing directly the affine coordinate transformation.
00124  *      We have at our disposal (1) translations (using rasterop),
00125  *      (2) horizontal and vertical shear about any horizontal and vertical
00126  *      line, respectively, and (3) non-isotropic scaling by two
00127  *      arbitrary x and y scaling factors.  We also have rotation
00128  *      about an arbitrary point, but this is equivalent to a set 
00129  *      of three shears so we do not need to use it.
00130  *
00131  *      Why might we do this?  For binary images, it is usually
00132  *      more efficient to do such transformations by a sequence
00133  *      of word parallel operations.  Shear and translation can be
00134  *      done in-place and word parallel; arbitrary scaling is
00135  *      mostly pixel-wise.
00136  *
00137  *      Suppose that we are tranforming image 1 to correspond to image 2.
00138  *      We have a set of three points, describing the coordinate space
00139  *      embedded in image 1, and we need to transform image 1 until
00140  *      those three points exactly correspond to the new coordinate space
00141  *      defined by the second set of three points.  In our image
00142  *      matching application, the latter set of three points was
00143  *      found to be the corresponding points in image 2.
00144  *
00145  *      The most elegant way I can think of to do such a sequential
00146  *      implementation is to imagine that we're going to transform
00147  *      BOTH images until they're aligned.  (We don't really want
00148  *      to transform both, because in fact we may only have one image
00149  *      that is undergoing a general affine transformation.)
00150  *
00151  *      Choose the 3 corresponding points as follows:
00152  *         - The 1st point is an origin
00153  *         - The 2nd point gives the orientation and scaling of the
00154  *           "x" axis with respect to the origin
00155  *         - The 3rd point does likewise for the "y" axis.
00156  *      These "axes" must not be collinear; otherwise they are
00157  *      arbitrary (although some strange things will happen if
00158  *      the handedness sweeping through the minimum angle between
00159  *      the axes is opposite).
00160  *
00161  *      An important constraint is that we have shear operations
00162  *      about an arbitrary horizontal or vertical line, but always
00163  *      parallel to the x or y axis.  If we continue to pretend that
00164  *      we have an unprimed coordinate space embedded in image 1 and
00165  *      a primed coordinate space embedded in image 2, we imagine
00166  *      (a) transforming image 1 by horizontal and vertical shears about
00167  *      point 1 to align points 3 and 2 along the y and x axes,
00168  *      respectively, and (b) transforming image 2 by horizontal and
00169  *      vertical shears about point 1' to align points 3' and 2' along
00170  *      the y and x axes.  Then we scale image 1 so that the distances
00171  *      from 1 to 2 and from 1 to 3 are equal to the distances in
00172  *      image 2 from 1' to 2' and from 1' to 3'.  This scaling operation
00173  *      leaves the true image origin, at (0,0) invariant, and will in
00174  *      general translate point 1.  The original points 1 and 1' will
00175  *      typically not coincide in any event, so we must translate
00176  *      the origin of image 1, at its current point 1, to the origin
00177  *      of image 2 at 1'.  The images should now be aligned.  But
00178  *      because we never really transformed image 2 (and image 2 may
00179  *      not even exist), we now perform  on image 1 the reverse of
00180  *      the shear transforms that we imagined doing on image 2;
00181  *      namely, the negative vertical shear followed by the negative
00182  *      horizontal shear.  Image 1 should now have its transformed
00183  *      unprimed coordinates aligned with the original primed
00184  *      coordinates.  In all this, it is only necessary to keep track
00185  *      of the shear angles and translations of points during the shears.
00186  *      What has been accomplished is a general affine transformation
00187  *      on image 1.
00188  *
00189  *      Having described all this, if you are going to use an
00190  *      affine transformation in an application, this is what you
00191  *      need to know:
00192  *
00193  *          (1) You should NEVER use the sequential method, because
00194  *              the image quality for 1 bpp text is much poorer
00195  *              (even though it is about 2x faster than the pointwise sampled
00196  *              method), and for images with depth greater than 1, it is
00197  *              nearly 20x slower than the pointwise sampled method
00198  *              and over 10x slower than the pointwise interpolated method!
00199  *              The sequential method is given here for purely
00200  *              pedagogical reasons.
00201  *
00202  *          (2) For 1 bpp images, use the pointwise sampled function
00203  *              pixAffineSampled().  For all other images, the best
00204  *              quality results result from using the pointwise
00205  *              interpolated function pixAffinePta() or pixAffine();
00206  *              the cost is less than a doubling of the computation time
00207  *              with respect to the sampled function.  If you use 
00208  *              interpolation on colormapped images, the colormap will
00209  *              be removed, resulting in either a grayscale or color
00210  *              image, depending on the values in the colormap.
00211  *              If you want to retain the colormap, use pixAffineSampled().
00212  *
00213  *      Typical relative timing of pointwise transforms (sampled = 1.0):
00214  *      8 bpp:   sampled        1.0
00215  *               interpolated   1.6
00216  *      32 bpp:  sampled        1.0
00217  *               interpolated   1.8
00218  *      Additionally, the computation time/pixel is nearly the same
00219  *      for 8 bpp and 32 bpp, for both sampled and interpolated.
00220  */
00221 
00222 
00223 #include <stdio.h>
00224 #include <stdlib.h>
00225 #include <string.h>
00226 #include <math.h>
00227 #include "allheaders.h"
00228 
00229 extern l_float32  AlphaMaskBorderVals[2];
00230 
00231 #ifndef  NO_CONSOLE_IO
00232 #define  DEBUG     0
00233 #endif  /* ~NO_CONSOLE_IO */
00234 
00235 
00236 /*-------------------------------------------------------------*
00237  *               Sampled affine image transformation           *
00238  *-------------------------------------------------------------*/
00239 /*!
00240  *  pixAffineSampledPta()
00241  *
00242  *      Input:  pixs (all depths)
00243  *              ptad  (3 pts of final coordinate space)
00244  *              ptas  (3 pts of initial coordinate space)
00245  *              incolor (L_BRING_IN_WHITE, L_BRING_IN_BLACK)
00246  *      Return: pixd, or null on error
00247  *
00248  *  Notes:
00249  *      (1) Brings in either black or white pixels from the boundary.
00250  *      (2) Retains colormap, which you can do for a sampled transform..
00251  *      (3) The 3 points must not be collinear.
00252  *      (4) The order of the 3 points is arbitrary; however, to compare
00253  *          with the sequential transform they must be in these locations
00254  *          and in this order: origin, x-axis, y-axis.
00255  *      (5) For 1 bpp images, this has much better quality results
00256  *          than pixAffineSequential(), particularly for text.
00257  *          It is about 3x slower, but does not require additional
00258  *          border pixels.  The poor quality of pixAffineSequential()
00259  *          is due to repeated quantized transforms.  It is strongly
00260  *          recommended that pixAffineSampled() be used for 1 bpp images.
00261  *      (6) For 8 or 32 bpp, much better quality is obtained by the
00262  *          somewhat slower pixAffinePta().  See that function
00263  *          for relative timings between sampled and interpolated.
00264  *      (7) To repeat, use of the sequential transform,
00265  *          pixAffineSequential(), for any images, is discouraged.
00266  */
00267 PIX *
00268 pixAffineSampledPta(PIX     *pixs,
00269                     PTA     *ptad,
00270                     PTA     *ptas,
00271                     l_int32  incolor)
00272 {
00273 l_float32  *vc;
00274 PIX        *pixd;
00275 
00276     PROCNAME("pixAffineSampledPta");
00277 
00278     if (!pixs)
00279         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
00280     if (!ptas)
00281         return (PIX *)ERROR_PTR("ptas not defined", procName, NULL);
00282     if (!ptad)
00283         return (PIX *)ERROR_PTR("ptad not defined", procName, NULL);
00284     if (incolor != L_BRING_IN_WHITE && incolor != L_BRING_IN_BLACK)
00285         return (PIX *)ERROR_PTR("invalid incolor", procName, NULL);
00286     if (ptaGetCount(ptas) != 3)
00287         return (PIX *)ERROR_PTR("ptas count not 3", procName, NULL);
00288     if (ptaGetCount(ptad) != 3)
00289         return (PIX *)ERROR_PTR("ptad count not 3", procName, NULL);
00290 
00291         /* Get backwards transform from dest to src, and apply it */
00292     getAffineXformCoeffs(ptad, ptas, &vc);
00293     pixd = pixAffineSampled(pixs, vc, incolor);
00294     FREE(vc);
00295 
00296     return pixd;
00297 }
00298 
00299 
00300 /*!
00301  *  pixAffineSampled()
00302  *
00303  *      Input:  pixs (all depths)
00304  *              vc  (vector of 6 coefficients for affine transformation)
00305  *              incolor (L_BRING_IN_WHITE, L_BRING_IN_BLACK)
00306  *      Return: pixd, or null on error
00307  *
00308  *  Notes:
00309  *      (1) Brings in either black or white pixels from the boundary.
00310  *      (2) Retains colormap, which you can do for a sampled transform..
00311  *      (3) For 8 or 32 bpp, much better quality is obtained by the
00312  *          somewhat slower pixAffine().  See that function
00313  *          for relative timings between sampled and interpolated.
00314  */
00315 PIX *
00316 pixAffineSampled(PIX        *pixs,
00317                  l_float32  *vc,
00318                  l_int32     incolor)
00319 {
00320 l_int32     i, j, w, h, d, x, y, wpls, wpld, color, cmapindex;
00321 l_uint32    val;
00322 l_uint32   *datas, *datad, *lines, *lined;
00323 PIX        *pixd;
00324 PIXCMAP    *cmap;
00325 
00326     PROCNAME("pixAffineSampled");
00327 
00328     if (!pixs)
00329         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
00330     if (!vc)
00331         return (PIX *)ERROR_PTR("vc not defined", procName, NULL);
00332     if (incolor != L_BRING_IN_WHITE && incolor != L_BRING_IN_BLACK)
00333         return (PIX *)ERROR_PTR("invalid incolor", procName, NULL);
00334     pixGetDimensions(pixs, &w, &h, &d);
00335     if (d != 1 && d != 2 && d != 4 && d != 8 && d != 32)
00336         return (PIX *)ERROR_PTR("depth not 1, 2, 4, 8 or 16", procName, NULL);
00337 
00338         /* Init all dest pixels to color to be brought in from outside */
00339     pixd = pixCreateTemplate(pixs);
00340     if ((cmap = pixGetColormap(pixs)) != NULL) {
00341         if (incolor == L_BRING_IN_WHITE)
00342             color = 1;
00343         else
00344             color = 0;
00345         pixcmapAddBlackOrWhite(cmap, color, &cmapindex);
00346         pixSetAllArbitrary(pixd, cmapindex);
00347     }
00348     else {
00349         if ((d == 1 && incolor == L_BRING_IN_WHITE) ||
00350             (d > 1 && incolor == L_BRING_IN_BLACK))
00351             pixClearAll(pixd);
00352         else
00353             pixSetAll(pixd);
00354     }
00355 
00356         /* Scan over the dest pixels */
00357     datas = pixGetData(pixs);
00358     wpls = pixGetWpl(pixs);
00359     datad = pixGetData(pixd);
00360     wpld = pixGetWpl(pixd);
00361     for (i = 0; i < h; i++) {
00362         lined = datad + i * wpld;
00363         for (j = 0; j < w; j++) {
00364             affineXformSampledPt(vc, j, i, &x, &y);
00365             if (x < 0 || y < 0 || x >=w || y >= h)
00366                 continue;
00367             lines = datas + y * wpls;
00368             if (d == 1) {
00369                 val = GET_DATA_BIT(lines, x);
00370                 SET_DATA_BIT_VAL(lined, j, val);
00371             }
00372             else if (d == 8) {
00373                 val = GET_DATA_BYTE(lines, x);
00374                 SET_DATA_BYTE(lined, j, val);
00375             }
00376             else if (d == 32) {
00377                 lined[j] = lines[x];
00378             }
00379             else if (d == 2) {
00380                 val = GET_DATA_DIBIT(lines, x);
00381                 SET_DATA_DIBIT(lined, j, val);
00382             }
00383             else if (d == 4) {
00384                 val = GET_DATA_QBIT(lines, x);
00385                 SET_DATA_QBIT(lined, j, val);
00386             }
00387         }
00388     }
00389 
00390     return pixd;
00391 }
00392 
00393 
00394 /*---------------------------------------------------------------------*
00395  *               Interpolated affine image transformation              *
00396  *---------------------------------------------------------------------*/
00397 /*!
00398  *  pixAffinePta()
00399  *
00400  *      Input:  pixs (all depths; colormap ok)
00401  *              ptad  (3 pts of final coordinate space)
00402  *              ptas  (3 pts of initial coordinate space)
00403  *              incolor (L_BRING_IN_WHITE, L_BRING_IN_BLACK)
00404  *      Return: pixd, or null on error
00405  *
00406  *  Notes:
00407  *      (1) Brings in either black or white pixels from the boundary
00408  *      (2) Removes any existing colormap, if necessary, before transforming
00409  */
00410 PIX *
00411 pixAffinePta(PIX     *pixs,
00412              PTA     *ptad,
00413              PTA     *ptas,
00414              l_int32  incolor)
00415 {
00416 l_int32   d;
00417 l_uint32  colorval;
00418 PIX      *pixt1, *pixt2, *pixd;
00419 
00420     PROCNAME("pixAffinePta");
00421 
00422     if (!pixs)
00423         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
00424     if (!ptas)
00425         return (PIX *)ERROR_PTR("ptas not defined", procName, NULL);
00426     if (!ptad)
00427         return (PIX *)ERROR_PTR("ptad not defined", procName, NULL);
00428     if (incolor != L_BRING_IN_WHITE && incolor != L_BRING_IN_BLACK)
00429         return (PIX *)ERROR_PTR("invalid incolor", procName, NULL);
00430     if (ptaGetCount(ptas) != 3)
00431         return (PIX *)ERROR_PTR("ptas count not 3", procName, NULL);
00432     if (ptaGetCount(ptad) != 3)
00433         return (PIX *)ERROR_PTR("ptad count not 3", procName, NULL);
00434 
00435     if (pixGetDepth(pixs) == 1)
00436         return pixAffineSampledPta(pixs, ptad, ptas, incolor);
00437 
00438         /* Remove cmap if it exists, and unpack to 8 bpp if necessary */
00439     pixt1 = pixRemoveColormap(pixs, REMOVE_CMAP_BASED_ON_SRC);
00440     d = pixGetDepth(pixt1);
00441     if (d < 8)
00442         pixt2 = pixConvertTo8(pixt1, FALSE);
00443     else
00444         pixt2 = pixClone(pixt1);
00445     d = pixGetDepth(pixt2);
00446 
00447         /* Compute actual color to bring in from edges */
00448     colorval = 0;
00449     if (incolor == L_BRING_IN_WHITE) {
00450         if (d == 8)
00451             colorval = 255;
00452         else  /* d == 32 */
00453             colorval = 0xffffff00;
00454     }
00455     
00456     if (d == 8)
00457         pixd = pixAffinePtaGray(pixt2, ptad, ptas, colorval);
00458     else  /* d == 32 */
00459         pixd = pixAffinePtaColor(pixt2, ptad, ptas, colorval);
00460     pixDestroy(&pixt1);
00461     pixDestroy(&pixt2);
00462     return pixd;
00463 }
00464 
00465 
00466 /*!
00467  *  pixAffine()
00468  *
00469  *      Input:  pixs (all depths; colormap ok)
00470  *              vc  (vector of 6 coefficients for affine transformation)
00471  *              incolor (L_BRING_IN_WHITE, L_BRING_IN_BLACK)
00472  *      Return: pixd, or null on error
00473  *
00474  *  Notes:
00475  *      (1) Brings in either black or white pixels from the boundary
00476  *      (2) Removes any existing colormap, if necessary, before transforming
00477  */
00478 PIX *
00479 pixAffine(PIX        *pixs,
00480           l_float32  *vc,
00481           l_int32     incolor)
00482 {
00483 l_int32   d;
00484 l_uint32  colorval;
00485 PIX      *pixt1, *pixt2, *pixd;
00486 
00487     PROCNAME("pixAffine");
00488 
00489     if (!pixs)
00490         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
00491     if (!vc)
00492         return (PIX *)ERROR_PTR("vc not defined", procName, NULL);
00493 
00494     if (pixGetDepth(pixs) == 1)
00495         return pixAffineSampled(pixs, vc, incolor);
00496 
00497         /* Remove cmap if it exists, and unpack to 8 bpp if necessary */
00498     pixt1 = pixRemoveColormap(pixs, REMOVE_CMAP_BASED_ON_SRC);
00499     d = pixGetDepth(pixt1);
00500     if (d < 8)
00501         pixt2 = pixConvertTo8(pixt1, FALSE);
00502     else
00503         pixt2 = pixClone(pixt1);
00504     d = pixGetDepth(pixt2);
00505 
00506         /* Compute actual color to bring in from edges */
00507     colorval = 0;
00508     if (incolor == L_BRING_IN_WHITE) {
00509         if (d == 8)
00510             colorval = 255;
00511         else  /* d == 32 */
00512             colorval = 0xffffff00;
00513     }
00514     
00515     if (d == 8)
00516         pixd = pixAffineGray(pixt2, vc, colorval);
00517     else  /* d == 32 */
00518         pixd = pixAffineColor(pixt2, vc, colorval);
00519     pixDestroy(&pixt1);
00520     pixDestroy(&pixt2);
00521     return pixd;
00522 }
00523 
00524 
00525 /*!
00526  *  pixAffinePtaColor()
00527  *
00528  *      Input:  pixs (32 bpp)
00529  *              ptad  (3 pts of final coordinate space)
00530  *              ptas  (3 pts of initial coordinate space)
00531  *              colorval (e.g., 0 to bring in BLACK, 0xffffff00 for WHITE)
00532  *      Return: pixd, or null on error
00533  */
00534 PIX *
00535 pixAffinePtaColor(PIX      *pixs,
00536                   PTA      *ptad,
00537                   PTA      *ptas,
00538                   l_uint32  colorval)
00539 {
00540 l_float32  *vc;
00541 PIX        *pixd;
00542 
00543     PROCNAME("pixAffinePtaColor");
00544 
00545     if (!pixs)
00546         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
00547     if (!ptas)
00548         return (PIX *)ERROR_PTR("ptas not defined", procName, NULL);
00549     if (!ptad)
00550         return (PIX *)ERROR_PTR("ptad not defined", procName, NULL);
00551     if (pixGetDepth(pixs) != 32)
00552         return (PIX *)ERROR_PTR("pixs must be 32 bpp", procName, NULL);
00553     if (ptaGetCount(ptas) != 3)
00554         return (PIX *)ERROR_PTR("ptas count not 3", procName, NULL);
00555     if (ptaGetCount(ptad) != 3)
00556         return (PIX *)ERROR_PTR("ptad count not 3", procName, NULL);
00557 
00558         /* Get backwards transform from dest to src, and apply it */
00559     getAffineXformCoeffs(ptad, ptas, &vc);
00560     pixd = pixAffineColor(pixs, vc, colorval);
00561     FREE(vc);
00562 
00563     return pixd;
00564 }
00565 
00566 
00567 /*!
00568  *  pixAffineColor()
00569  *
00570  *      Input:  pixs (32 bpp)
00571  *              vc  (vector of 6 coefficients for affine transformation)
00572  *              colorval (e.g., 0 to bring in BLACK, 0xffffff00 for WHITE)
00573  *      Return: pixd, or null on error
00574  */
00575 PIX *
00576 pixAffineColor(PIX        *pixs,
00577                l_float32  *vc,
00578                l_uint32    colorval)
00579 {
00580 l_int32    i, j, w, h, d, wpls, wpld;
00581 l_uint32   val;
00582 l_uint32  *datas, *datad, *lined;
00583 l_float32  x, y;
00584 PIX       *pixd;
00585 
00586     PROCNAME("pixAffineColor");
00587 
00588     if (!pixs)
00589         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
00590     pixGetDimensions(pixs, &w, &h, &d);
00591     if (d != 32)
00592         return (PIX *)ERROR_PTR("pixs must be 32 bpp", procName, NULL);
00593     if (!vc)
00594         return (PIX *)ERROR_PTR("vc not defined", procName, NULL);
00595 
00596     datas = pixGetData(pixs);
00597     wpls = pixGetWpl(pixs);
00598     pixd = pixCreateTemplate(pixs);
00599     pixSetAllArbitrary(pixd, colorval);
00600     datad = pixGetData(pixd);
00601     wpld = pixGetWpl(pixd);
00602 
00603         /* Iterate over destination pixels */
00604     for (i = 0; i < h; i++) {
00605         lined = datad + i * wpld;
00606         for (j = 0; j < w; j++) {
00607                 /* Compute float src pixel location corresponding to (i,j) */
00608             affineXformPt(vc, j, i, &x, &y);
00609             linearInterpolatePixelColor(datas, wpls, w, h, x, y, colorval,
00610                                         &val);
00611             *(lined + j) = val;
00612         }
00613     }
00614 
00615     return pixd;
00616 }
00617 
00618 
00619 /*!
00620  *  pixAffinePtaGray()
00621  *
00622  *      Input:  pixs (8 bpp)
00623  *              ptad  (3 pts of final coordinate space)
00624  *              ptas  (3 pts of initial coordinate space)
00625  *              grayval (0 to bring in BLACK, 255 for WHITE)
00626  *      Return: pixd, or null on error
00627  */
00628 PIX *
00629 pixAffinePtaGray(PIX     *pixs,
00630                  PTA     *ptad,
00631                  PTA     *ptas,
00632                  l_uint8  grayval)
00633 {
00634 l_float32  *vc;
00635 PIX        *pixd;
00636 
00637     PROCNAME("pixAffinePtaGray");
00638 
00639     if (!pixs)
00640         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
00641     if (!ptas)
00642         return (PIX *)ERROR_PTR("ptas not defined", procName, NULL);
00643     if (!ptad)
00644         return (PIX *)ERROR_PTR("ptad not defined", procName, NULL);
00645     if (pixGetDepth(pixs) != 8)
00646         return (PIX *)ERROR_PTR("pixs must be 8 bpp", procName, NULL);
00647     if (ptaGetCount(ptas) != 3)
00648         return (PIX *)ERROR_PTR("ptas count not 3", procName, NULL);
00649     if (ptaGetCount(ptad) != 3)
00650         return (PIX *)ERROR_PTR("ptad count not 3", procName, NULL);
00651 
00652         /* Get backwards transform from dest to src, and apply it */
00653     getAffineXformCoeffs(ptad, ptas, &vc);
00654     pixd = pixAffineGray(pixs, vc, grayval);
00655     FREE(vc);
00656 
00657     return pixd;
00658 }
00659 
00660 
00661 
00662 /*!
00663  *  pixAffineGray()
00664  *
00665  *      Input:  pixs (8 bpp)
00666  *              vc  (vector of 6 coefficients for affine transformation)
00667  *              grayval (0 to bring in BLACK, 255 for WHITE)
00668  *      Return: pixd, or null on error
00669  */
00670 PIX *
00671 pixAffineGray(PIX        *pixs,
00672               l_float32  *vc,
00673               l_uint8     grayval)
00674 {
00675 l_int32    i, j, w, h, wpls, wpld, val;
00676 l_uint32  *datas, *datad, *lined;
00677 l_float32  x, y;
00678 PIX       *pixd;
00679 
00680     PROCNAME("pixAffineGray");
00681 
00682     if (!pixs)
00683         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
00684     pixGetDimensions(pixs, &w, &h, NULL);
00685     if (pixGetDepth(pixs) != 8)
00686         return (PIX *)ERROR_PTR("pixs must be 8 bpp", procName, NULL);
00687     if (!vc)
00688         return (PIX *)ERROR_PTR("vc not defined", procName, NULL);
00689 
00690     datas = pixGetData(pixs);
00691     wpls = pixGetWpl(pixs);
00692     pixd = pixCreateTemplate(pixs);
00693     pixSetAllArbitrary(pixd, grayval);
00694     datad = pixGetData(pixd);
00695     wpld = pixGetWpl(pixd);
00696 
00697         /* Iterate over destination pixels */
00698     for (i = 0; i < h; i++) {
00699         lined = datad + i * wpld;
00700         for (j = 0; j < w; j++) {
00701                 /* Compute float src pixel location corresponding to (i,j) */
00702             affineXformPt(vc, j, i, &x, &y);
00703             linearInterpolatePixelGray(datas, wpls, w, h, x, y, grayval, &val);
00704             SET_DATA_BYTE(lined, j, val);
00705         }
00706     }
00707 
00708     return pixd;
00709 }
00710 
00711 
00712 /*---------------------------------------------------------------------------*
00713  *   Affine transform including alpha (blend) component and gamma transform  *
00714  *---------------------------------------------------------------------------*/
00715 /*!
00716  *  pixAffinePtaWithAlpha()
00717  *
00718  *      Input:  pixs (32 bpp rgb)
00719  *              ptad  (3 pts of final coordinate space)
00720  *              ptas  (3 pts of initial coordinate space)
00721  *              pixg (<optional> 8 bpp, can be null)
00722  *              fract (between 0.0 and 1.0, with 0.0 fully transparent
00723  *                     and 1.0 fully opaque)
00724  *              border (of pixels added to capture transformed source pixels)
00725  *      Return: pixd, or null on error
00726  *
00727  *  Notes:
00728  *      (1) The alpha channel is transformed separately from pixs,
00729  *          and aligns with it, being fully transparent outside the
00730  *          boundary of the transformed pixs.  For pixels that are fully
00731  *          transparent, a blending function like pixBlendWithGrayMask()
00732  *          will give zero weight to corresponding pixels in pixs.
00733  *      (2) If pixg is NULL, it is generated as an alpha layer that is
00734  *          partially opaque, using @fract.  Otherwise, it is cropped
00735  *          to pixs if required and @fract is ignored.  The alpha channel
00736  *          in pixs is never used.
00737  *      (3) Colormaps are removed.
00738  *      (4) When pixs is transformed, it doesn't matter what color is brought
00739  *          in because the alpha channel will be transparent (0) there.
00740  *      (5) To avoid losing source pixels in the destination, it may be
00741  *          necessary to add a border to the source pix before doing
00742  *          the affine transformation.  This can be any non-negative number.
00743  *      (6) The input @ptad and @ptas are in a coordinate space before
00744  *          the border is added.  Internally, we compensate for this
00745  *          before doing the affine transform on the image after the border
00746  *          is added.
00747  *      (7) The default setting for the border values in the alpha channel
00748  *          is 0 (transparent) for the outermost ring of pixels and
00749  *          (0.5 * fract * 255) for the second ring.  When blended over
00750  *          a second image, this
00751  *          (a) shrinks the visible image to make a clean overlap edge
00752  *              with an image below, and
00753  *          (b) softens the edges by weakening the aliasing there.
00754  *          Use l_setAlphaMaskBorder() to change these values.
00755  */
00756 PIX *
00757 pixAffinePtaWithAlpha(PIX       *pixs,
00758                       PTA       *ptad,
00759                       PTA       *ptas,
00760                       PIX       *pixg,
00761                       l_float32  fract,
00762                       l_int32    border)
00763 {
00764 l_int32  ws, hs, d;
00765 PIX     *pixd, *pixb1, *pixb2, *pixg2, *pixga;
00766 PTA     *ptad2, *ptas2;
00767 
00768     PROCNAME("pixAffinePtaWithAlpha");
00769 
00770     if (!pixs)
00771         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
00772     pixGetDimensions(pixs, &ws, &hs, &d);
00773     if (d != 32 && pixGetColormap(pixs) == NULL)
00774         return (PIX *)ERROR_PTR("pixs not cmapped or 32 bpp", procName, NULL);
00775     if (pixg && pixGetDepth(pixg) != 8) {
00776         L_WARNING("pixg not 8 bpp; using @fract transparent alpha", procName);
00777         pixg = NULL;
00778     }
00779     if (!pixg && (fract < 0.0 || fract > 1.0)) {
00780         L_WARNING("invalid fract; using 1.0 (fully transparent)", procName);
00781         fract = 1.0;
00782     }
00783     if (!pixg && fract == 0.0)
00784         L_WARNING("fully opaque alpha; image will not be blended", procName);
00785     if (!ptad)
00786         return (PIX *)ERROR_PTR("ptad not defined", procName, NULL);
00787     if (!ptas)
00788         return (PIX *)ERROR_PTR("ptas not defined", procName, NULL);
00789 
00790         /* Add border; the color doesn't matter */
00791     pixb1 = pixAddBorder(pixs, border, 0);
00792 
00793         /* Transform the ptr arrays to work on the bordered image */
00794     ptad2 = ptaTransform(ptad, border, border, 1.0, 1.0);
00795     ptas2 = ptaTransform(ptas, border, border, 1.0, 1.0);
00796 
00797         /* Do separate affine transform of rgb channels of pixs and of pixg */
00798     pixd = pixAffinePtaColor(pixb1, ptad2, ptas2, 0);
00799     if (!pixg) {
00800         pixg2 = pixCreate(ws, hs, 8);
00801         if (fract == 1.0)
00802             pixSetAll(pixg2);
00803         else
00804             pixSetAllArbitrary(pixg2, (l_int32)(255.0 * fract));
00805     }
00806     else
00807         pixg2 = pixResizeToMatch(pixg, NULL, ws, hs);
00808     if (ws > 10 && hs > 10) {  /* see note 7 */
00809         pixSetBorderRingVal(pixg2, 1,
00810                             (l_int32)(255.0 * fract * AlphaMaskBorderVals[0]));
00811         pixSetBorderRingVal(pixg2, 2,
00812                             (l_int32)(255.0 * fract * AlphaMaskBorderVals[1]));
00813 
00814     }
00815     pixb2 = pixAddBorder(pixg2, border, 0);  /* must be black border */
00816     pixga = pixAffinePtaGray(pixb2, ptad2, ptas2, 0);
00817     pixSetRGBComponent(pixd, pixga, L_ALPHA_CHANNEL);
00818 
00819     pixDestroy(&pixg2);
00820     pixDestroy(&pixb1);
00821     pixDestroy(&pixb2);
00822     pixDestroy(&pixga);
00823     ptaDestroy(&ptad2);
00824     ptaDestroy(&ptas2);
00825     return pixd;
00826 }
00827 
00828 
00829 /*!
00830  *  pixAffinePtaGammaXform()
00831  *
00832  *      Input:  pixs (32 bpp rgb)
00833  *              gamma (gamma correction; must be > 0.0)
00834  *              ptad  (3 pts of final coordinate space)
00835  *              ptas  (3 pts of initial coordinate space)
00836  *              fract (between 0.0 and 1.0, with 1.0 fully transparent)
00837  *              border (of pixels to capture transformed source pixels)
00838  *      Return: pixd, or null on error
00839  *
00840  *  Notes:
00841  *      (1) This wraps a gamma/inverse-gamma photometric transform around
00842  *          pixAffinePtaWithAlpha().
00843  *      (2) For usage, see notes in pixAffinePtaWithAlpha() and
00844  *          pixGammaTRCWithAlpha().
00845  *      (3) The basic idea of a gamma/inverse-gamma transform is to remove
00846  *          any gamma correction before the affine transform, and restore
00847  *          it afterward.  The effects can be subtle, but important for
00848  *          some applications.  For example, using gamma > 1.0 will
00849  *          cause the dark areas to become somewhat lighter and slightly
00850  *          reduce aliasing effects when blending using the alpha channel.
00851  */
00852 PIX *
00853 pixAffinePtaGammaXform(PIX       *pixs,
00854                        l_float32  gamma,
00855                        PTA       *ptad,
00856                        PTA       *ptas,
00857                        l_float32  fract,
00858                        l_int32    border)
00859 {
00860 PIX  *pixg, *pixd;
00861 
00862     PROCNAME("pixAffinePtaGammaXform");
00863 
00864     if (!pixs || (pixGetDepth(pixs) != 32))
00865         return (PIX *)ERROR_PTR("pixs undefined or not 32 bpp", procName, NULL);
00866     if (fract == 0.0)
00867         L_WARNING("fully opaque alpha; image cannot be blended", procName);
00868     if (gamma <= 0.0)  {
00869         L_WARNING("gamma must be > 0.0; setting to 1.0", procName);
00870         gamma = 1.0;
00871     }
00872 
00873     pixg = pixGammaTRCWithAlpha(NULL, pixs, 1.0 / gamma, 0, 255);
00874     pixd = pixAffinePtaWithAlpha(pixg, ptad, ptas, NULL, fract, border);
00875     pixGammaTRCWithAlpha(pixd, pixd, gamma, 0, 255);
00876     pixDestroy(&pixg);
00877     return pixd;
00878 }
00879 
00880 
00881 /*-------------------------------------------------------------*
00882  *                 Affine coordinate transformation            *
00883  *-------------------------------------------------------------*/
00884 /*!
00885  *  getAffineXformCoeffs()
00886  *
00887  *      Input:  ptas  (source 3 points; unprimed)
00888  *              ptad  (transformed 3 points; primed)
00889  *              &vc   (<return> vector of coefficients of transform)
00890  *      Return: 0 if OK; 1 on error
00891  *
00892  *  We have a set of six equations, describing the affine
00893  *  transformation that takes 3 points (ptas) into 3 other
00894  *  points (ptad).  These equations are:
00895  *
00896  *          x1' = c[0]*x1 + c[1]*y1 + c[2]
00897  *          y1' = c[3]*x1 + c[4]*y1 + c[5]
00898  *          x2' = c[0]*x2 + c[1]*y2 + c[2]
00899  *          y2' = c[3]*x2 + c[4]*y2 + c[5]
00900  *          x3' = c[0]*x3 + c[1]*y3 + c[2]
00901  *          y3' = c[3]*x3 + c[4]*y3 + c[5]
00902  *    
00903  *  This can be represented as
00904  *
00905  *          AC = B
00906  *
00907  *  where B and C are column vectors
00908  *    
00909  *          B = [ x1' y1' x2' y2' x3' y3' ]
00910  *          C = [ c[0] c[1] c[2] c[3] c[4] c[5] c[6] ]
00911  *    
00912  *  and A is the 6x6 matrix
00913  *
00914  *          x1   y1   1   0    0    0
00915  *           0    0   0   x1   y1   1
00916  *          x2   y2   1   0    0    0
00917  *           0    0   0   x2   y2   1
00918  *          x3   y3   1   0    0    0
00919  *           0    0   0   x3   y3   1
00920  *
00921  *  These six equations are solved here for the coefficients C.
00922  *
00923  *  These six coefficients can then be used to find the dest
00924  *  point (x',y') corresponding to any src point (x,y), according
00925  *  to the equations
00926  *
00927  *           x' = c[0]x + c[1]y + c[2]
00928  *           y' = c[3]x + c[4]y + c[5]
00929  *
00930  *  that are implemented in affineXformPt().
00931  *
00932  *  !!!!!!!!!!!!!!!!!!   Very important   !!!!!!!!!!!!!!!!!!!!!!
00933  *
00934  *  When the affine transform is composed from a set of simple
00935  *  operations such as translation, scaling and rotation,
00936  *  it is built in a form to convert from the un-transformed src
00937  *  point to the transformed dest point.  However, when an
00938  *  affine transform is used on images, it is used in an inverted
00939  *  way: it converts from the transformed dest point to the
00940  *  un-transformed src point.  So, for example, if you transform
00941  *  a boxa using transform A, to transform an image in the same
00942  *  way you must use the inverse of A.
00943  *
00944  *  For example, if you transform a boxa with a 3x3 affine matrix
00945  *  'mat', the analogous image transformation must use 'matinv':
00946  *
00947  *     boxad = boxaAffineTransform(boxas, mat);
00948  *     affineInvertXform(mat, &matinv);
00949  *     pixd = pixAffine(pixs, matinv, L_BRING_IN_WHITE);
00950  *
00951  *  !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
00952  */
00953 l_int32
00954 getAffineXformCoeffs(PTA         *ptas,
00955                      PTA         *ptad,
00956                      l_float32  **pvc)
00957 {
00958 l_int32     i;
00959 l_float32   x1, y1, x2, y2, x3, y3;
00960 l_float32  *b;   /* rhs vector of primed coords X'; coeffs returned in *pvc */
00961 l_float32  *a[6];  /* 6x6 matrix A  */
00962 
00963     PROCNAME("getAffineXformCoeffs");
00964 
00965     if (!ptas)
00966         return ERROR_INT("ptas not defined", procName, 1);
00967     if (!ptad)
00968         return ERROR_INT("ptad not defined", procName, 1);
00969     if (!pvc)
00970         return ERROR_INT("&vc not defined", procName, 1);
00971         
00972     if ((b = (l_float32 *)CALLOC(6, sizeof(l_float32))) == NULL)
00973         return ERROR_INT("b not made", procName, 1);
00974     *pvc = b;
00975 
00976     ptaGetPt(ptas, 0, &x1, &y1);
00977     ptaGetPt(ptas, 1, &x2, &y2);
00978     ptaGetPt(ptas, 2, &x3, &y3);
00979     ptaGetPt(ptad, 0, &b[0], &b[1]);
00980     ptaGetPt(ptad, 1, &b[2], &b[3]);
00981     ptaGetPt(ptad, 2, &b[4], &b[5]);
00982 
00983     for (i = 0; i < 6; i++)
00984         if ((a[i] = (l_float32 *)CALLOC(6, sizeof(l_float32))) == NULL)
00985             return ERROR_INT("a[i] not made", procName, 1);
00986 
00987     a[0][0] = x1;
00988     a[0][1] = y1;
00989     a[0][2] = 1.;
00990     a[1][3] = x1;
00991     a[1][4] = y1;
00992     a[1][5] = 1.;
00993     a[2][0] = x2;
00994     a[2][1] = y2;
00995     a[2][2] = 1.;
00996     a[3][3] = x2;
00997     a[3][4] = y2;
00998     a[3][5] = 1.;
00999     a[4][0] = x3;
01000     a[4][1] = y3;
01001     a[4][2] = 1.;
01002     a[5][3] = x3;
01003     a[5][4] = y3;
01004     a[5][5] = 1.;
01005 
01006     gaussjordan(a, b, 6);
01007 
01008     for (i = 0; i < 6; i++)
01009         FREE(a[i]);
01010 
01011     return 0;
01012 }
01013 
01014 
01015 /*!
01016  *  affineInvertXform()
01017  *
01018  *      Input:  vc (vector of 6 coefficients)
01019  *              *vci (<return> inverted transform)
01020  *      Return: 0 if OK; 1 on error
01021  *
01022  *  Notes:
01023  *      (1) The 6 affine transform coefficients are the first
01024  *          two rows of a 3x3 matrix where the last row has
01025  *          only a 1 in the third column.  We invert this
01026  *          using gaussjordan(), and select the first 2 rows
01027  *          as the coefficients of the inverse affine transform.
01028  *      (2) Alternatively, we can find the inverse transform
01029  *          coefficients by inverting the 2x2 submatrix,
01030  *          and treating the top 2 coefficients in the 3rd column as
01031  *          a RHS vector for that 2x2 submatrix.  Then the
01032  *          6 inverted transform coefficients are composed of
01033  *          the inverted 2x2 submatrix and the negative of the
01034  *          transformed RHS vector.  Why is this so?  We have
01035  *             Y = AX + R  (2 equations in 6 unknowns)
01036  *          Then
01037  *             X = A'Y - A'R
01038  *          Gauss-jordan solves
01039  *             AF = R
01040  *          and puts the solution for F, which is A'R,
01041  *          into the input R vector.
01042  *
01043  */
01044 l_int32
01045 affineInvertXform(l_float32   *vc,
01046                   l_float32  **pvci)
01047 {
01048 l_int32     i;
01049 l_float32  *vci;
01050 l_float32  *a[3];
01051 l_float32   b[3] = {1.0, 1.0, 1.0};   /* anything; results ignored */
01052 
01053     PROCNAME("affineInvertXform");
01054 
01055     if (!pvci)
01056         return ERROR_INT("&vci not defined", procName, 1);
01057     *pvci = NULL;
01058     if (!vc)
01059         return ERROR_INT("vc not defined", procName, 1);
01060 
01061     for (i = 0; i < 3; i++)
01062         a[i] = (l_float32 *)CALLOC(3, sizeof(l_float32));
01063     a[0][0] = vc[0];
01064     a[0][1] = vc[1];
01065     a[0][2] = vc[2];
01066     a[1][0] = vc[3];
01067     a[1][1] = vc[4];
01068     a[1][2] = vc[5];
01069     a[2][2] = 1.0;
01070     gaussjordan(a, b, 3);  /* now matrix a contains the inverse */
01071     vci = (l_float32 *)CALLOC(6, sizeof(l_float32));
01072     *pvci = vci;
01073     vci[0] = a[0][0];
01074     vci[1] = a[0][1];
01075     vci[2] = a[0][2];
01076     vci[3] = a[1][0];
01077     vci[4] = a[1][1];
01078     vci[5] = a[1][2];
01079 
01080 #if 0
01081         /* Alternative version, inverting a 2x2 matrix */
01082     for (i = 0; i < 2; i++)
01083         a[i] = (l_float32 *)CALLOC(2, sizeof(l_float32));
01084     a[0][0] = vc[0];
01085     a[0][1] = vc[1];
01086     a[1][0] = vc[3];
01087     a[1][1] = vc[4];
01088     b[0] = vc[2];
01089     b[1] = vc[5];
01090     gaussjordan(a, b, 2);  /* now matrix a contains the inverse */
01091     vci = (l_float32 *)CALLOC(6, sizeof(l_float32));
01092     *pvci = vci;
01093     vci[0] = a[0][0];
01094     vci[1] = a[0][1];
01095     vci[2] = -b[0];   /* note sign */
01096     vci[3] = a[1][0];
01097     vci[4] = a[1][1];
01098     vci[5] = -b[1];   /* note sign */
01099 #endif
01100 
01101     return 0;
01102 }
01103 
01104 
01105 /*!
01106  *  affineXformSampledPt()
01107  *
01108  *      Input:  vc (vector of 6 coefficients)
01109  *              (x, y)  (initial point)
01110  *              (&xp, &yp)   (<return> transformed point)
01111  *      Return: 0 if OK; 1 on error
01112  *
01113  *  Notes:
01114  *      (1) This finds the nearest pixel coordinates of the transformed point.
01115  *      (2) It does not check ptrs for returned data!
01116  */
01117 l_int32
01118 affineXformSampledPt(l_float32  *vc,
01119                      l_int32     x,
01120                      l_int32     y,
01121                      l_int32    *pxp,
01122                      l_int32    *pyp)
01123 {
01124     PROCNAME("affineXformSampledPt");
01125 
01126     if (!vc)
01127         return ERROR_INT("vc not defined", procName, 1);
01128 
01129     *pxp = (l_int32)(vc[0] * x + vc[1] * y + vc[2] + 0.5);
01130     *pyp = (l_int32)(vc[3] * x + vc[4] * y + vc[5] + 0.5);
01131     return 0;
01132 }
01133 
01134 
01135 /*!
01136  *  affineXformPt()
01137  *
01138  *      Input:  vc (vector of 6 coefficients)
01139  *              (x, y)  (initial point)
01140  *              (&xp, &yp)   (<return> transformed point)
01141  *      Return: 0 if OK; 1 on error
01142  *
01143  *  Notes:
01144  *      (1) This computes the floating point location of the transformed point.
01145  *      (2) It does not check ptrs for returned data!
01146  */
01147 l_int32
01148 affineXformPt(l_float32  *vc,
01149               l_int32     x,
01150               l_int32     y,
01151               l_float32  *pxp,
01152               l_float32  *pyp)
01153 {
01154     PROCNAME("affineXformPt");
01155 
01156     if (!vc)
01157         return ERROR_INT("vc not defined", procName, 1);
01158 
01159     *pxp = vc[0] * x + vc[1] * y + vc[2];
01160     *pyp = vc[3] * x + vc[4] * y + vc[5];
01161     return 0;
01162 }
01163 
01164 
01165 /*-------------------------------------------------------------*
01166  *                 Interpolation helper functions              *
01167  *-------------------------------------------------------------*/
01168 /*!
01169  *  linearInterpolatePixelColor()
01170  *
01171  *      Input:  datas (ptr to beginning of image data)
01172  *              wpls (32-bit word/line for this data array)
01173  *              w, h (of image)
01174  *              x, y (floating pt location for evaluation)
01175  *              colorval (color brought in from the outside when the
01176  *                        input x,y location is outside the image;
01177  *                        in 0xrrggbb00 format))
01178  *              &val (<return> interpolated color value)
01179  *      Return: 0 if OK, 1 on error
01180  *
01181  *  Notes:
01182  *      (1) This is a standard linear interpolation function.  It is
01183  *          equivalent to area weighting on each component, and
01184  *          avoids "jaggies" when rendering sharp edges.
01185  */
01186 l_int32
01187 linearInterpolatePixelColor(l_uint32  *datas,
01188                             l_int32    wpls,
01189                             l_int32    w,
01190                             l_int32    h,
01191                             l_float32  x,
01192                             l_float32  y,
01193                             l_uint32   colorval,
01194                             l_uint32  *pval)
01195 {
01196 l_int32    xpm, ypm, xp, yp, xf, yf;
01197 l_int32    rval, gval, bval;
01198 l_uint32   word00, word01, word10, word11;
01199 l_uint32  *lines;
01200 
01201     PROCNAME("linearInterpolatePixelColor");
01202 
01203     if (!pval)
01204         return ERROR_INT("&val not defined", procName, 1);
01205     *pval = colorval;
01206     if (!datas)
01207         return ERROR_INT("datas not defined", procName, 1);
01208 
01209         /* Skip if off the edge */
01210     if (x < 0.0 || y < 0.0 || x > w - 2.0 || y > h - 2.0)
01211         return 0;
01212 
01213     xpm = (l_int32)(16.0 * x + 0.5);
01214     ypm = (l_int32)(16.0 * y + 0.5);
01215     xp = xpm >> 4;
01216     yp = ypm >> 4;
01217     xf = xpm & 0x0f;
01218     yf = ypm & 0x0f;
01219 
01220 #if  DEBUG
01221     if (xf < 0 || yf < 0)
01222         fprintf(stderr, "xp = %d, yp = %d, xf = %d, yf = %d\n", xp, yp, xf, yf);
01223 #endif  /* DEBUG */
01224 
01225         /* Do area weighting (eqiv. to linear interpolation) */
01226     lines = datas + yp * wpls;
01227     word00 = *(lines + xp);
01228     word10 = *(lines + xp + 1);
01229     word01 = *(lines + wpls + xp);
01230     word11 = *(lines + wpls + xp + 1);
01231     rval = ((16 - xf) * (16 - yf) * ((word00 >> L_RED_SHIFT) & 0xff) +
01232         xf * (16 - yf) * ((word10 >> L_RED_SHIFT) & 0xff) +
01233         (16 - xf) * yf * ((word01 >> L_RED_SHIFT) & 0xff) +
01234         xf * yf * ((word11 >> L_RED_SHIFT) & 0xff) + 128) / 256;
01235     gval = ((16 - xf) * (16 - yf) * ((word00 >> L_GREEN_SHIFT) & 0xff) +
01236         xf * (16 - yf) * ((word10 >> L_GREEN_SHIFT) & 0xff) +
01237         (16 - xf) * yf * ((word01 >> L_GREEN_SHIFT) & 0xff) +
01238         xf * yf * ((word11 >> L_GREEN_SHIFT) & 0xff) + 128) / 256;
01239     bval = ((16 - xf) * (16 - yf) * ((word00 >> L_BLUE_SHIFT) & 0xff) +
01240         xf * (16 - yf) * ((word10 >> L_BLUE_SHIFT) & 0xff) +
01241         (16 - xf) * yf * ((word01 >> L_BLUE_SHIFT) & 0xff) +
01242         xf * yf * ((word11 >> L_BLUE_SHIFT) & 0xff) + 128) / 256;
01243     *pval = (rval << L_RED_SHIFT) | (gval << L_GREEN_SHIFT) |
01244           (bval << L_BLUE_SHIFT);
01245     return 0;
01246 }
01247 
01248 
01249 /*!
01250  *  linearInterpolatePixelGray()
01251  *
01252  *      Input:  datas (ptr to beginning of image data)
01253  *              wpls (32-bit word/line for this data array)
01254  *              w, h (of image)
01255  *              x, y (floating pt location for evaluation)
01256  *              grayval (color brought in from the outside when the
01257  *                       input x,y location is outside the image)
01258  *              &val (<return> interpolated gray value)
01259  *      Return: 0 if OK, 1 on error
01260  *
01261  *  Notes:
01262  *      (1) This is a standard linear interpolation function.  It is
01263  *          equivalent to area weighting on each component, and
01264  *          avoids "jaggies" when rendering sharp edges.
01265  */
01266 l_int32
01267 linearInterpolatePixelGray(l_uint32  *datas,
01268                            l_int32    wpls,
01269                            l_int32    w,
01270                            l_int32    h,
01271                            l_float32  x,
01272                            l_float32  y,
01273                            l_int32    grayval,
01274                            l_int32   *pval)
01275 {
01276 l_int32    xpm, ypm, xp, yp, xf, yf, v00, v10, v01, v11;
01277 l_uint32  *lines;
01278 
01279     PROCNAME("linearInterpolatePixelGray");
01280 
01281     if (!pval)
01282         return ERROR_INT("&val not defined", procName, 1);
01283     *pval = grayval;
01284     if (!datas)
01285         return ERROR_INT("datas not defined", procName, 1);
01286 
01287         /* Skip if off the edge */
01288     if (x < 0.0 || y < 0.0 || x > w - 2.0 || y > h - 2.0)
01289         return 0;
01290 
01291     xpm = (l_int32)(16.0 * x + 0.5);
01292     ypm = (l_int32)(16.0 * y + 0.5);
01293     xp = xpm >> 4;
01294     yp = ypm >> 4;
01295     xf = xpm & 0x0f;
01296     yf = ypm & 0x0f;
01297 
01298 #if  DEBUG
01299     if (xf < 0 || yf < 0)
01300         fprintf(stderr, "xp = %d, yp = %d, xf = %d, yf = %d\n", xp, yp, xf, yf);
01301 #endif  /* DEBUG */
01302 
01303         /* Interpolate by area weighting. */
01304     lines = datas + yp * wpls;
01305     v00 = (16 - xf) * (16 - yf) * GET_DATA_BYTE(lines, xp);
01306     v10 = xf * (16 - yf) * GET_DATA_BYTE(lines, xp + 1);
01307     v01 = (16 - xf) * yf * GET_DATA_BYTE(lines + wpls, xp);
01308     v11 = xf * yf * GET_DATA_BYTE(lines + wpls, xp + 1);
01309     *pval = (v00 + v01 + v10 + v11 + 128) / 256;
01310     return 0;
01311 }
01312 
01313 
01314 
01315 /*-------------------------------------------------------------*
01316  *               Gauss-jordan linear equation solver           *
01317  *-------------------------------------------------------------*/
01318 #define  SWAP(a,b)   {temp = (a); (a) = (b); (b) = temp;}
01319 
01320 /*!
01321  *  gaussjordan()
01322  *
01323  *      Input:   a  (n x n matrix)
01324  *               b  (rhs column vector)
01325  *               n  (dimension)
01326  *      Return:  0 if ok, 1 on error
01327  *
01328  *      Note side effects:
01329  *            (1) the matrix a is transformed to its inverse
01330  *            (2) the vector b is transformed to the solution X to the
01331  *                linear equation AX = B
01332  *
01333  *      Adapted from "Numerical Recipes in C, Second Edition", 1992
01334  *      pp. 36-41 (gauss-jordan elimination)
01335  */
01336 l_int32
01337 gaussjordan(l_float32  **a,
01338             l_float32   *b,
01339             l_int32      n)
01340 {
01341 l_int32    i, icol, irow, j, k, l, ll;
01342 l_int32   *indexc, *indexr, *ipiv;
01343 l_float32  big, dum, pivinv, temp;
01344 
01345     PROCNAME("gaussjordan");
01346 
01347     if (!a)
01348         return ERROR_INT("a not defined", procName, 1);
01349     if (!b)
01350         return ERROR_INT("b not defined", procName, 1);
01351 
01352     if ((indexc = (l_int32 *)CALLOC(n, sizeof(l_int32))) == NULL)
01353         return ERROR_INT("indexc not made", procName, 1);
01354     if ((indexr = (l_int32 *)CALLOC(n, sizeof(l_int32))) == NULL)
01355         return ERROR_INT("indexr not made", procName, 1);
01356     if ((ipiv = (l_int32 *)CALLOC(n, sizeof(l_int32))) == NULL)
01357         return ERROR_INT("ipiv not made", procName, 1);
01358 
01359     for (i = 0; i < n; i++) {
01360         big = 0.0;
01361         for (j = 0; j < n; j++) {
01362             if (ipiv[j] != 1)
01363                 for (k = 0; k < n; k++) {
01364                     if (ipiv[k] == 0) {
01365                         if (fabs(a[j][k]) >= big) {
01366                             big = fabs(a[j][k]);
01367                             irow = j;
01368                             icol = k;
01369                         }
01370                     }
01371                     else if (ipiv[k] > 1)
01372                         return ERROR_INT("singular matrix", procName, 1);
01373                 }
01374         }
01375         ++(ipiv[icol]);
01376         
01377         if (irow != icol) {
01378             for (l = 0; l < n; l++)
01379                 SWAP(a[irow][l], a[icol][l]);
01380             SWAP(b[irow], b[icol]);
01381         }
01382 
01383         indexr[i] = irow;
01384         indexc[i] = icol;
01385         if (a[icol][icol] == 0.0)
01386             return ERROR_INT("singular matrix", procName, 1);
01387         pivinv = 1.0 / a[icol][icol];
01388         a[icol][icol] = 1.0;
01389         for (l = 0; l < n; l++)
01390             a[icol][l] *= pivinv;
01391         b[icol] *= pivinv;
01392 
01393         for (ll = 0; ll < n; ll++) 
01394             if (ll != icol) {
01395                 dum = a[ll][icol];
01396                 a[ll][icol] = 0.0;
01397                 for (l = 0; l < n; l++)
01398                     a[ll][l] -= a[icol][l] * dum;
01399                 b[ll] -= b[icol] * dum;
01400             }
01401     }
01402 
01403     for (l = n - 1; l >= 0; l--) {
01404         if (indexr[l] != indexc[l])
01405             for (k = 0; k < n; k++)
01406                 SWAP(a[k][indexr[l]], a[k][indexc[l]]);
01407     }
01408 
01409     FREE(indexr);
01410     FREE(indexc);
01411     FREE(ipiv);
01412     return 0;
01413 }
01414 
01415 
01416 /*-------------------------------------------------------------*
01417  *              Sequential affine image transformation         *
01418  *-------------------------------------------------------------*/
01419 /*!
01420  *  pixAffineSequential()
01421  *
01422  *      Input:  pixs
01423  *              ptad  (3 pts of final coordinate space)
01424  *              ptas  (3 pts of initial coordinate space)
01425  *              bw    (pixels of additional border width during computation)
01426  *              bh    (pixels of additional border height during computation)
01427  *      Return: pixd, or null on error
01428  *
01429  *  Notes:
01430  *      (1) The 3 pts must not be collinear.
01431  *      (2) The 3 pts must be given in this order:
01432  *           - origin
01433  *           - a location along the x-axis
01434  *           - a location along the y-axis.
01435  *      (3) You must guess how much border must be added so that no
01436  *          pixels are lost in the transformations from src to
01437  *          dest coordinate space.  (This can be calculated but it
01438  *          is a lot of work!)  For coordinate spaces that are nearly
01439  *          at right angles, on a 300 ppi scanned page, the addition
01440  *          of 1000 pixels on each side is usually sufficient.
01441  *      (4) This is here for pedagogical reasons.  It is about 3x faster
01442  *          on 1 bpp images than pixAffineSampled(), but the results
01443  *          on text are much inferior.
01444  */
01445 PIX *
01446 pixAffineSequential(PIX     *pixs,
01447                     PTA     *ptad,
01448                     PTA     *ptas,
01449                     l_int32  bw,
01450                     l_int32  bh)
01451 {
01452 l_int32    x1, y1, x2, y2, x3, y3;    /* ptas */
01453 l_int32    x1p, y1p, x2p, y2p, x3p, y3p;   /* ptad */
01454 l_int32    x1sc, y1sc;  /* scaled origin */
01455 l_float32  x2s, x2sp, scalex, scaley;
01456 l_float32  th3, th3p, ph2, ph2p;
01457 l_float32  rad2deg;
01458 PIX       *pixt1, *pixt2, *pixd;
01459 
01460     PROCNAME("pixAffineSequential");
01461 
01462     if (!pixs)
01463         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
01464     if (!ptas)
01465         return (PIX *)ERROR_PTR("ptas not defined", procName, NULL);
01466     if (!ptad)
01467         return (PIX *)ERROR_PTR("ptad not defined", procName, NULL);
01468 
01469     if (ptaGetCount(ptas) != 3)
01470         return (PIX *)ERROR_PTR("ptas count not 3", procName, NULL);
01471     if (ptaGetCount(ptad) != 3)
01472         return (PIX *)ERROR_PTR("ptad count not 3", procName, NULL);
01473     ptaGetIPt(ptas, 0, &x1, &y1);
01474     ptaGetIPt(ptas, 1, &x2, &y2);
01475     ptaGetIPt(ptas, 2, &x3, &y3);
01476     ptaGetIPt(ptad, 0, &x1p, &y1p);
01477     ptaGetIPt(ptad, 1, &x2p, &y2p);
01478     ptaGetIPt(ptad, 2, &x3p, &y3p);
01479 
01480     rad2deg = 180. / 3.1415926535;
01481 
01482     if (y1 == y3)
01483         return (PIX *)ERROR_PTR("y1 == y3!", procName, NULL);
01484     if (y1p == y3p)
01485         return (PIX *)ERROR_PTR("y1p == y3p!", procName, NULL);
01486         
01487     if (bw != 0 || bh != 0) {
01488             /* resize all points and add border to pixs */
01489         x1 = x1 + bw;
01490         y1 = y1 + bh;
01491         x2 = x2 + bw;
01492         y2 = y2 + bh;
01493         x3 = x3 + bw;
01494         y3 = y3 + bh;
01495         x1p = x1p + bw;
01496         y1p = y1p + bh;
01497         x2p = x2p + bw;
01498         y2p = y2p + bh;
01499         x3p = x3p + bw;
01500         y3p = y3p + bh;
01501 
01502         if ((pixt1 = pixAddBorderGeneral(pixs, bw, bw, bh, bh, 0)) == NULL)
01503             return (PIX *)ERROR_PTR("pixt1 not made", procName, NULL);
01504     }
01505     else
01506         pixt1 = pixCopy(NULL, pixs);
01507 
01508     /*-------------------------------------------------------------*
01509         The horizontal shear is done to move the 3rd point to the
01510         y axis.  This moves the 2nd point either towards or away
01511         from the y axis, depending on whether it is above or below
01512         the x axis.  That motion must be computed so that we know
01513         the angle of vertical shear to use to get the 2nd point
01514         on the x axis.  We must also know the x coordinate of the
01515         2nd point in order to compute how much scaling is required
01516         to match points on the axis.
01517      *-------------------------------------------------------------*/
01518 
01519         /* Shear angles required to put src points on x and y axes */
01520     th3 = atan2((l_float64)(x1 - x3), (l_float64)(y1 - y3));
01521     x2s = (l_float32)(x2 - ((l_float32)(y1 - y2) * (x3 - x1)) / (y1 - y3));
01522     if (x2s == (l_float32)x1)
01523         return (PIX *)ERROR_PTR("x2s == x1!", procName, NULL);
01524     ph2 = atan2((l_float64)(y1 - y2), (l_float64)(x2s - x1));
01525 
01526         /* Shear angles required to put dest points on x and y axes.
01527          * Use the negative of these values to instead move the
01528          * src points from the axes to the actual dest position.
01529          * These values are also needed to scale the image. */
01530     th3p = atan2((l_float64)(x1p - x3p), (l_float64)(y1p - y3p));
01531     x2sp = (l_float32)(x2p - ((l_float32)(y1p - y2p) * (x3p - x1p)) / (y1p - y3p));
01532     if (x2sp == (l_float32)x1p)
01533         return (PIX *)ERROR_PTR("x2sp == x1p!", procName, NULL);
01534     ph2p = atan2((l_float64)(y1p - y2p), (l_float64)(x2sp - x1p));
01535 
01536         /* Shear image to first put src point 3 on the y axis,
01537          * and then to put src point 2 on the x axis */
01538     pixHShearIP(pixt1, y1, th3, L_BRING_IN_WHITE);
01539     pixVShearIP(pixt1, x1, ph2, L_BRING_IN_WHITE);
01540 
01541         /* Scale image to match dest scale.  The dest scale
01542          * is calculated above from the angles th3p and ph2p
01543          * that would be required to move the dest points to
01544          * the x and y axes. */
01545     scalex = (l_float32)(x2sp - x1p) / (x2s - x1);
01546     scaley = (l_float32)(y3p - y1p) / (y3 - y1);
01547     if ((pixt2 = pixScale(pixt1, scalex, scaley)) == NULL)
01548         return (PIX *)ERROR_PTR("pixt2 not made", procName, NULL);
01549 
01550 #if  DEBUG
01551     fprintf(stderr, "th3 = %5.1f deg, ph2 = %5.1f deg\n",
01552             rad2deg * th3, rad2deg * ph2);
01553     fprintf(stderr, "th3' = %5.1f deg, ph2' = %5.1f deg\n",
01554             rad2deg * th3p, rad2deg * ph2p);
01555     fprintf(stderr, "scalex = %6.3f, scaley = %6.3f\n", scalex, scaley);
01556 #endif  /* DEBUG */
01557 
01558     /*-------------------------------------------------------------*
01559         Scaling moves the 1st src point, which is the origin. 
01560         It must now be moved again to coincide with the origin
01561         (1st point) of the dest.  After this is done, the 2nd
01562         and 3rd points must be sheared back to the original
01563         positions of the 2nd and 3rd dest points.  We use the
01564         negative of the angles that were previously computed
01565         for shearing those points in the dest image to x and y
01566         axes, and take the shears in reverse order as well.
01567      *-------------------------------------------------------------*/
01568         /* Shift image to match dest origin. */
01569     x1sc = (l_int32)(scalex * x1 + 0.5);   /* x comp of origin after scaling */
01570     y1sc = (l_int32)(scaley * y1 + 0.5);   /* y comp of origin after scaling */
01571     pixRasteropIP(pixt2, x1p - x1sc, y1p - y1sc, L_BRING_IN_WHITE);
01572 
01573         /* Shear image to take points 2 and 3 off the axis and
01574          * put them in the original dest position */
01575     pixVShearIP(pixt2, x1p, -ph2p, L_BRING_IN_WHITE);
01576     pixHShearIP(pixt2, y1p, -th3p, L_BRING_IN_WHITE);
01577 
01578     if (bw != 0 || bh != 0) {
01579         if ((pixd = pixRemoveBorderGeneral(pixt2, bw, bw, bh, bh)) == NULL)
01580             return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
01581     }
01582     else
01583         pixd = pixClone(pixt2);
01584 
01585     pixDestroy(&pixt1);
01586     pixDestroy(&pixt2);
01587     return pixd;
01588 }
01589 
01590 
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines