Leptonica  1.82.0
Image processing and image analysis suite
affine.c File Reference
#include <string.h>
#include <math.h>
#include "allheaders.h"

Go to the source code of this file.

Macros

#define DEBUG   0
 
#define SWAP(a, b)   {temp = (a); (a) = (b); (b) = temp;}
 

Functions

PIXpixAffineSampledPta (PIX *pixs, PTA *ptad, PTA *ptas, l_int32 incolor)
 
PIXpixAffineSampled (PIX *pixs, l_float32 *vc, l_int32 incolor)
 
PIXpixAffinePta (PIX *pixs, PTA *ptad, PTA *ptas, l_int32 incolor)
 
PIXpixAffine (PIX *pixs, l_float32 *vc, l_int32 incolor)
 
PIXpixAffinePtaColor (PIX *pixs, PTA *ptad, PTA *ptas, l_uint32 colorval)
 
PIXpixAffineColor (PIX *pixs, l_float32 *vc, l_uint32 colorval)
 
PIXpixAffinePtaGray (PIX *pixs, PTA *ptad, PTA *ptas, l_uint8 grayval)
 
PIXpixAffineGray (PIX *pixs, l_float32 *vc, l_uint8 grayval)
 
PIXpixAffinePtaWithAlpha (PIX *pixs, PTA *ptad, PTA *ptas, PIX *pixg, l_float32 fract, l_int32 border)
 
l_ok getAffineXformCoeffs (PTA *ptas, PTA *ptad, l_float32 **pvc)
 
l_ok affineInvertXform (l_float32 *vc, l_float32 **pvci)
 
l_ok affineXformSampledPt (l_float32 *vc, l_int32 x, l_int32 y, l_int32 *pxp, l_int32 *pyp)
 
l_ok affineXformPt (l_float32 *vc, l_int32 x, l_int32 y, l_float32 *pxp, l_float32 *pyp)
 
l_ok linearInterpolatePixelColor (l_uint32 *datas, l_int32 wpls, l_int32 w, l_int32 h, l_float32 x, l_float32 y, l_uint32 colorval, l_uint32 *pval)
 
l_ok linearInterpolatePixelGray (l_uint32 *datas, l_int32 wpls, l_int32 w, l_int32 h, l_float32 x, l_float32 y, l_int32 grayval, l_int32 *pval)
 
l_int32 gaussjordan (l_float32 **a, l_float32 *b, l_int32 n)
 
PIXpixAffineSequential (PIX *pixs, PTA *ptad, PTA *ptas, l_int32 bw, l_int32 bh)
 

Variables

l_float32 AlphaMaskBorderVals [2]
 

Detailed Description


     Affine (3 pt) image transformation using a sampled
     (to nearest integer) transform on each dest point
          PIX        *pixAffineSampledPta()
          PIX        *pixAffineSampled()

     Affine (3 pt) image transformation using interpolation
     (or area mapping) for anti-aliasing images that are
     2, 4, or 8 bpp gray, or colormapped, or 32 bpp RGB
          PIX        *pixAffinePta()
          PIX        *pixAffine()
          PIX        *pixAffinePtaColor()
          PIX        *pixAffineColor()
          PIX        *pixAffinePtaGray()
          PIX        *pixAffineGray()

     Affine transform including alpha (blend) component
          PIX        *pixAffinePtaWithAlpha()

     Affine coordinate transformation
          l_int32     getAffineXformCoeffs()
          l_int32     affineInvertXform()
          l_int32     affineXformSampledPt()
          l_int32     affineXformPt()

     Interpolation helper functions
          l_int32     linearInterpolatePixelGray()
          l_int32     linearInterpolatePixelColor()

     Gauss-jordan linear equation solver
          l_int32     gaussjordan()

     Affine image transformation using a sequence of
     shear/scale/translation operations
          PIX        *pixAffineSequential()

     One can define a coordinate space by the location of the origin,
     the orientation of x and y axes, and the unit scaling along
     each axis.  An affine transform is a general linear
     transformation from one coordinate space to another.

     For the general case, we can define the affine transform using
     two sets of three (noncollinear) points in a plane.  One set
     corresponds to the input (src) coordinate space; the other to the
     transformed (dest) coordinate space.  Each point in the
     src corresponds to one of the points in the dest.  With two
     sets of three points, we get a set of 6 equations in 6 unknowns
     that specifies the mapping between the coordinate spaces.
     The interface here allows you to specify either the corresponding
     sets of 3 points, or the transform itself (as a vector of 6
     coefficients).

     Given the transform as a vector of 6 coefficients, we can compute
     both a a pointwise affine coordinate transformation and an
     affine image transformation.

     To compute the coordinate transform, we need the coordinate
     value (x',y') in the transformed space for any point (x,y)
     in the original space.  To derive this transform from the
     three corresponding points, it is convenient to express the affine
     coordinate transformation using an LU decomposition of
     a set of six linear equations that express the six coordinates
     of the three points in the transformed space as a function of
     the six coordinates in the original space.  Once we have
     this transform matrix , we can transform an image by
     finding, for each destination pixel, the pixel (or pixels)
     in the source that give rise to it.

     This 'pointwise' transformation can be done either by sampling
     and picking a single pixel in the src to replicate into the dest,
     or by interpolating (or averaging) over four src pixels to
     determine the value of the dest pixel.  The first method is
     implemented by pixAffineSampled() and the second method by
     pixAffine().  The interpolated method can only be used for
     images with more than 1 bpp, but for these, the image quality
     is significantly better than the sampled method, due to
     the 'antialiasing' effect of weighting the src pixels.

     Interpolation works well when there is relatively little scaling,
     or if there is image expansion in general.  However, if there
     is significant image reduction, one should apply a low-pass
     filter before subsampling to avoid aliasing the high frequencies.

     A typical application might be to align two images, which
     may be scaled, rotated and translated versions of each other.
     Through some pre-processing, three corresponding points are
     located in each of the two images.  One of the images is
     then to be (affine) transformed to align with the other.
     As mentioned, the standard way to do this is to use three
     sets of points, compute the 6 transformation coefficients
     from these points that describe the linear transformation,

         x' = ax + by + c
         y' = dx + ey + f

     and use this in a pointwise manner to transform the image.

     N.B.  Be sure to see the comment in getAffineXformCoeffs(),
     regarding using the inverse of the affine transform for points
     to transform images.

     There is another way to do this transformation; namely,
     by doing a sequence of simple affine transforms, without
     computing directly the affine coordinate transformation.
     We have at our disposal (1) translations (using rasterop),
     (2) horizontal and vertical shear about any horizontal and vertical
     line, respectively, and (3) non-isotropic scaling by two
     arbitrary x and y scaling factors.  We also have rotation
     about an arbitrary point, but this is equivalent to a set
     of three shears so we do not need to use it.

     Why might we do this?  For binary images, it is usually
     more efficient to do such transformations by a sequence
     of word parallel operations.  Shear and translation can be
     done in-place and word parallel; arbitrary scaling is
     mostly pixel-wise.

     Suppose that we are transforming image 1 to correspond to image 2.
     We have a set of three points, describing the coordinate space
     embedded in image 1, and we need to transform image 1 until
     those three points exactly correspond to the new coordinate space
     defined by the second set of three points.  In our image
     matching application, the latter set of three points was
     found to be the corresponding points in image 2.

     The most elegant way I can think of to do such a sequential
     implementation is to imagine that we're going to transform
     BOTH images until they're aligned.  (We don't really want
     to transform both, because in fact we may only have one image
     that is undergoing a general affine transformation.)

     Choose the 3 corresponding points as follows:
        ~ The 1st point is an origin
        ~ The 2nd point gives the orientation and scaling of the
          "x" axis with respect to the origin
        ~ The 3rd point does likewise for the "y" axis.
     These "axes" must not be collinear; otherwise they are
     arbitrary (although some strange things will happen if
     the handedness sweeping through the minimum angle between
     the axes is opposite).

     An important constraint is that we have shear operations
     about an arbitrary horizontal or vertical line, but always
     parallel to the x or y axis.  If we continue to pretend that
     we have an unprimed coordinate space embedded in image 1 and
     a primed coordinate space embedded in image 2, we imagine
     (a) transforming image 1 by horizontal and vertical shears about
     point 1 to align points 3 and 2 along the y and x axes,
     respectively, and (b) transforming image 2 by horizontal and
     vertical shears about point 1' to align points 3' and 2' along
     the y and x axes.  Then we scale image 1 so that the distances
     from 1 to 2 and from 1 to 3 are equal to the distances in
     image 2 from 1' to 2' and from 1' to 3'.  This scaling operation
     leaves the true image origin, at (0,0) invariant, and will in
     general translate point 1.  The original points 1 and 1' will
     typically not coincide in any event, so we must translate
     the origin of image 1, at its current point 1, to the origin
     of image 2 at 1'.  The images should now be aligned.  But
     because we never really transformed image 2 (and image 2 may
     not even exist), we now perform  on image 1 the reverse of
     the shear transforms that we imagined doing on image 2;
     namely, the negative vertical shear followed by the negative
     horizontal shear.  Image 1 should now have its transformed
     unprimed coordinates aligned with the original primed
     coordinates.  In all this, it is only necessary to keep track
     of the shear angles and translations of points during the shears.
     What has been accomplished is a general affine transformation
     on image 1.

     Having described all this, if you are going to use an
     affine transformation in an application, this is what you
     need to know:

         (1) You should NEVER use the sequential method, because
             the image quality for 1 bpp text is much poorer
             (even though it is about 2x faster than the pointwise sampled
             method), and for images with depth greater than 1, it is
             nearly 20x slower than the pointwise sampled method
             and over 10x slower than the pointwise interpolated method!
             The sequential method is given here for purely
             pedagogical reasons.

         (2) For 1 bpp images, use the pointwise sampled function
             pixAffineSampled().  For all other images, the best
             quality results result from using the pointwise
             interpolated function pixAffinePta() or pixAffine();
             the cost is less than a doubling of the computation time
             with respect to the sampled function.  If you use
             interpolation on colormapped images, the colormap will
             be removed, resulting in either a grayscale or color
             image, depending on the values in the colormap.
             If you want to retain the colormap, use pixAffineSampled().

     Typical relative timing of pointwise transforms (sampled = 1.0):
     8 bpp:   sampled        1.0
              interpolated   1.6
     32 bpp:  sampled        1.0
              interpolated   1.8
     Additionally, the computation time/pixel is nearly the same
     for 8 bpp and 32 bpp, for both sampled and interpolated.

Definition in file affine.c.

Function Documentation

◆ affineInvertXform()

l_ok affineInvertXform ( l_float32 *  vc,
l_float32 **  pvci 
)

affineInvertXform()

Parameters
[in]vcvector of 6 coefficients
[out]pvciinverted transform
Returns
0 if OK; 1 on error
Notes:
     (1) The 6 affine transform coefficients are the first
         two rows of a 3x3 matrix where the last row has
         only a 1 in the third column.  We invert this
         using gaussjordan(), and select the first 2 rows
         as the coefficients of the inverse affine transform.
     (2) Alternatively, we can find the inverse transform
         coefficients by inverting the 2x2 submatrix,
         and treating the top 2 coefficients in the 3rd column as
         a RHS vector for that 2x2 submatrix.  Then the
         6 inverted transform coefficients are composed of
         the inverted 2x2 submatrix and the negative of the
         transformed RHS vector.  Why is this so?  We have
            Y = AX + R  (2 equations in 6 unknowns)
         Then
            X = A'Y - A'R
         Gauss-jordan solves
            AF = R
         and puts the solution for F, which is A'R,
         into the input R vector.

Definition at line 1023 of file affine.c.

References gaussjordan().

◆ affineXformPt()

l_ok affineXformPt ( l_float32 *  vc,
l_int32  x,
l_int32  y,
l_float32 *  pxp,
l_float32 *  pyp 
)

affineXformPt()

Parameters
[in]vcvector of 6 coefficients
[in]x,yinitial point
[out]pxp,pyptransformed point
Returns
0 if OK; 1 on error
Notes:
     (1) This computes the floating point location of the transformed point.
     (2) It does not check ptrs for returned data!

Definition at line 1138 of file affine.c.

Referenced by fpixAffine().

◆ affineXformSampledPt()

l_ok affineXformSampledPt ( l_float32 *  vc,
l_int32  x,
l_int32  y,
l_int32 *  pxp,
l_int32 *  pyp 
)

affineXformSampledPt()

Parameters
[in]vcvector of 6 coefficients
[in]x,yinitial point
[out]pxp,pyptransformed point
Returns
0 if OK; 1 on error
Notes:
     (1) This finds the nearest pixel coordinates of the transformed point.
     (2) It does not check ptrs for returned data!

Definition at line 1106 of file affine.c.

◆ gaussjordan()

l_int32 gaussjordan ( l_float32 **  a,
l_float32 *  b,
l_int32  n 
)

gaussjordan()

Parameters
[in]an x n matrix
[in]bn x 1 right-hand side column vector
[in]ndimension
Returns
0 if ok, 1 on error
Notes:
     (1) There are two side-effects:
         * The matrix a is transformed to its inverse A
         * The rhs vector b is transformed to the solution x
           of the linear equation ax = b
     (2) The inverse A can then be used to solve the same equation with
         different rhs vectors c by multiplication: x = Ac
     (3) Adapted from "Numerical Recipes in C, Second Edition", 1992,
         pp. 36-41 (gauss-jordan elimination)

Definition at line 1344 of file affine.c.

Referenced by affineInvertXform(), getAffineXformCoeffs(), getBilinearXformCoeffs(), getProjectiveXformCoeffs(), ptaGetCubicLSF(), ptaGetQuadraticLSF(), and ptaGetQuarticLSF().

◆ getAffineXformCoeffs()

l_ok getAffineXformCoeffs ( PTA ptas,
PTA ptad,
l_float32 **  pvc 
)

getAffineXformCoeffs()

Parameters
[in]ptassource 3 points; unprimed
[in]ptadtransformed 3 points; primed
[out]pvcvector of coefficients of transform
Returns
0 if OK; 1 on error
 We have a set of six equations, describing the affine
 transformation that takes 3 points ptas into 3 other
 points ptad.  These equations are:

         x1' = c[0]*x1 + c[1]*y1 + c[2]
         y1' = c[3]*x1 + c[4]*y1 + c[5]
         x2' = c[0]*x2 + c[1]*y2 + c[2]
         y2' = c[3]*x2 + c[4]*y2 + c[5]
         x3' = c[0]*x3 + c[1]*y3 + c[2]
         y3' = c[3]*x3 + c[4]*y3 + c[5]

 This can be represented as

         AC = B

 where B and C are column vectors

         B = [ x1' y1' x2' y2' x3' y3' ]
         C = [ c[0] c[1] c[2] c[3] c[4] c[5] c[6] ]

 and A is the 6x6 matrix

         x1   y1   1   0    0    0
          0    0   0   x1   y1   1
         x2   y2   1   0    0    0
          0    0   0   x2   y2   1
         x3   y3   1   0    0    0
          0    0   0   x3   y3   1

 These six equations are solved here for the coefficients C.

 These six coefficients can then be used to find the dest
 point x',y') corresponding to any src point (x,y, according
 to the equations

          x' = c[0]x + c[1]y + c[2]
          y' = c[3]x + c[4]y + c[5]

 that are implemented in affineXformPt.

 !!!!!!!!!!!!!!!!!!   Very important   !!!!!!!!!!!!!!!!!!!!!!

 When the affine transform is composed from a set of simple
 operations such as translation, scaling and rotation,
 it is built in a form to convert from the un-transformed src
 point to the transformed dest point.  However, when an
 affine transform is used on images, it is used in an inverted
 way: it converts from the transformed dest point to the
 un-transformed src point.  So, for example, if you transform
 a boxa using transform A, to transform an image in the same
 way you must use the inverse of A.

 For example, if you transform a boxa with a 3x3 affine matrix
 'mat', the analogous image transformation must use 'matinv':
boxad = boxaAffineTransform(boxas, mat);
affineInvertXform(mat, &matinv);
pixd = pixAffine(pixs, matinv, L_BRING_IN_WHITE);
l_ok affineInvertXform(l_float32 *vc, l_float32 **pvci)
affineInvertXform()
Definition: affine.c:1023
PIX * pixAffine(PIX *pixs, l_float32 *vc, l_int32 incolor)
pixAffine()
Definition: affine.c:495
BOXA * boxaAffineTransform(BOXA *boxas, l_float32 *mat)
boxaAffineTransform()
@ L_BRING_IN_WHITE
Definition: pix.h:869
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

Definition at line 933 of file affine.c.

References gaussjordan(), and ptaGetPt().

Referenced by fpixAffinePta(), and pixAffineSampledPta().

◆ linearInterpolatePixelColor()

l_ok linearInterpolatePixelColor ( l_uint32 *  datas,
l_int32  wpls,
l_int32  w,
l_int32  h,
l_float32  x,
l_float32  y,
l_uint32  colorval,
l_uint32 *  pval 
)

linearInterpolatePixelColor()

Parameters
[in]datasptr to beginning of image data
[in]wpls32-bit word/line for this data array
[in]w,hof image
[in]x,yfloating pt location for evaluation
[in]colorvalcolor brought in from the outside when the input x,y location is outside the image; in 0xrrggbb00 format)
[out]pvalinterpolated color value
Returns
0 if OK, 1 on error
Notes:
     (1) This is a standard linear interpolation function.  It is
         equivalent to area weighting on each component, and
         avoids "jaggies" when rendering sharp edges.

Definition at line 1179 of file affine.c.

References lept_stderr().

◆ linearInterpolatePixelGray()

l_ok linearInterpolatePixelGray ( l_uint32 *  datas,
l_int32  wpls,
l_int32  w,
l_int32  h,
l_float32  x,
l_float32  y,
l_int32  grayval,
l_int32 *  pval 
)

linearInterpolatePixelGray()

Parameters
[in]datasptr to beginning of image data
[in]wpls32-bit word/line for this data array
[in]w,hof image
[in]x,yfloating pt location for evaluation
[in]grayvalcolor brought in from the outside when the input x,y location is outside the image
[out]pvalinterpolated gray value
Returns
0 if OK, 1 on error
Notes:
     (1) This is a standard linear interpolation function.  It is
         equivalent to area weighting on each component, and
         avoids "jaggies" when rendering sharp edges.

Definition at line 1265 of file affine.c.

References GET_DATA_BYTE, and lept_stderr().

◆ pixAffine()

PIX* pixAffine ( PIX pixs,
l_float32 *  vc,
l_int32  incolor 
)

pixAffine()

Parameters
[in]pixsall depths; colormap ok
[in]vcvector of 6 coefficients for affine transformation
[in]incolorL_BRING_IN_WHITE, L_BRING_IN_BLACK
Returns
pixd, or NULL on error
Notes:
     (1) Brings in either black or white pixels from the boundary
     (2) Removes any existing colormap, if necessary, before transforming

Definition at line 495 of file affine.c.

◆ pixAffineColor()

PIX* pixAffineColor ( PIX pixs,
l_float32 *  vc,
l_uint32  colorval 
)

pixAffineColor()

Parameters
[in]pixs32 bpp
[in]vcvector of 6 coefficients for affine transformation
[in]colorvale.g.: 0 to bring in BLACK, 0xffffff00 for WHITE
Returns
pixd, or NULL on error

Definition at line 592 of file affine.c.

References pixGetData(), and pixGetDimensions().

◆ pixAffineGray()

PIX* pixAffineGray ( PIX pixs,
l_float32 *  vc,
l_uint8  grayval 
)

pixAffineGray()

Parameters
[in]pixs8 bpp
[in]vcvector of 6 coefficients for affine transformation
[in]grayvale.g.: 0 to bring in BLACK, 255 for WHITE
Returns
pixd, or NULL on error

Definition at line 696 of file affine.c.

References pixGetDimensions().

◆ pixAffinePta()

PIX* pixAffinePta ( PIX pixs,
PTA ptad,
PTA ptas,
l_int32  incolor 
)

pixAffinePta()

Parameters
[in]pixsall depths; colormap ok
[in]ptad3 pts of final coordinate space
[in]ptas3 pts of initial coordinate space
[in]incolorL_BRING_IN_WHITE, L_BRING_IN_BLACK
Returns
pixd, or NULL on error
Notes:
     (1) Brings in either black or white pixels from the boundary
     (2) Removes any existing colormap, if necessary, before transforming

Definition at line 425 of file affine.c.

References L_BRING_IN_BLACK, L_BRING_IN_WHITE, and ptaGetCount().

◆ pixAffinePtaColor()

PIX* pixAffinePtaColor ( PIX pixs,
PTA ptad,
PTA ptas,
l_uint32  colorval 
)

pixAffinePtaColor()

Parameters
[in]pixs32 bpp
[in]ptad3 pts of final coordinate space
[in]ptas3 pts of initial coordinate space
[in]colorvale.g.: 0 to bring in BLACK, 0xffffff00 for WHITE
Returns
pixd, or NULL on error

Definition at line 551 of file affine.c.

◆ pixAffinePtaGray()

PIX* pixAffinePtaGray ( PIX pixs,
PTA ptad,
PTA ptas,
l_uint8  grayval 
)

pixAffinePtaGray()

Parameters
[in]pixs8 bpp
[in]ptad3 pts of final coordinate space
[in]ptas3 pts of initial coordinate space
[in]grayvale.g.: 0 to bring in BLACK, 255 for WHITE
Returns
pixd, or NULL on error

Definition at line 654 of file affine.c.

◆ pixAffinePtaWithAlpha()

PIX* pixAffinePtaWithAlpha ( PIX pixs,
PTA ptad,
PTA ptas,
PIX pixg,
l_float32  fract,
l_int32  border 
)

pixAffinePtaWithAlpha()

Parameters
[in]pixs32 bpp rgb
[in]ptad3 pts of final coordinate space
[in]ptas3 pts of initial coordinate space
[in]pixg[optional] 8 bpp, can be null
[in]fractbetween 0.0 and 1.0, with 0.0 fully transparent and 1.0 fully opaque
[in]borderof pixels added to capture transformed source pixels
Returns
pixd, or NULL on error
Notes:
     (1) The alpha channel is transformed separately from pixs,
         and aligns with it, being fully transparent outside the
         boundary of the transformed pixs.  For pixels that are fully
         transparent, a blending function like pixBlendWithGrayMask()
         will give zero weight to corresponding pixels in pixs.
     (2) If pixg is NULL, it is generated as an alpha layer that is
         partially opaque, using fract.  Otherwise, it is cropped
         to pixs if required and fract is ignored.  The alpha channel
         in pixs is never used.
     (3) Colormaps are removed.
     (4) When pixs is transformed, it doesn't matter what color is brought
         in because the alpha channel will be transparent (0) there.
     (5) To avoid losing source pixels in the destination, it may be
         necessary to add a border to the source pix before doing
         the affine transformation.  This can be any non-negative number.
     (6) The input ptad and ptas are in a coordinate space before
         the border is added.  Internally, we compensate for this
         before doing the affine transform on the image after the border
         is added.
     (7) The default setting for the border values in the alpha channel
         is 0 (transparent) for the outermost ring of pixels and
         (0.5 * fract * 255) for the second ring.  When blended over
         a second image, this
         (a) shrinks the visible image to make a clean overlap edge
             with an image below, and
         (b) softens the edges by weakening the aliasing there.
         Use l_setAlphaMaskBorder() to change these values.

Definition at line 784 of file affine.c.

References pixGetDimensions().

◆ pixAffineSampled()

PIX* pixAffineSampled ( PIX pixs,
l_float32 *  vc,
l_int32  incolor 
)

pixAffineSampled()

Parameters
[in]pixsall depths
[in]vcvector of 6 coefficients for affine transformation
[in]incolorL_BRING_IN_WHITE, L_BRING_IN_BLACK
Returns
pixd, or NULL on error
Notes:
     (1) Brings in either black or white pixels from the boundary.
     (2) Retains colormap, which you can do for a sampled transform..
     (3) For 8 or 32 bpp, much better quality is obtained by the
         somewhat slower pixAffine().  See that function
         for relative timings between sampled and interpolated.

Definition at line 332 of file affine.c.

References L_BRING_IN_BLACK, L_BRING_IN_WHITE, pixCreateTemplate(), and pixGetDimensions().

Referenced by pixAffineSampledPta().

◆ pixAffineSampledPta()

PIX* pixAffineSampledPta ( PIX pixs,
PTA ptad,
PTA ptas,
l_int32  incolor 
)

pixAffineSampledPta()

Parameters
[in]pixsall depths
[in]ptad3 pts of final coordinate space
[in]ptas3 pts of initial coordinate space
[in]incolorL_BRING_IN_WHITE, L_BRING_IN_BLACK
Returns
pixd, or NULL on error
Notes:
     (1) Brings in either black or white pixels from the boundary.
     (2) Retains colormap, which you can do for a sampled transform..
     (3) The 3 points must not be collinear.
     (4) The order of the 3 points is arbitrary; however, to compare
         with the sequential transform they must be in these locations
         and in this order: origin, x-axis, y-axis.
     (5) For 1 bpp images, this has much better quality results
         than pixAffineSequential(), particularly for text.
         It is about 3x slower, but does not require additional
         border pixels.  The poor quality of pixAffineSequential()
         is due to repeated quantized transforms.  It is strongly
         recommended that pixAffineSampled() be used for 1 bpp images.
     (6) For 8 or 32 bpp, much better quality is obtained by the
         somewhat slower pixAffinePta().  See that function
         for relative timings between sampled and interpolated.
     (7) To repeat, use of the sequential transform,
         pixAffineSequential(), for any images, is discouraged.

Definition at line 282 of file affine.c.

References getAffineXformCoeffs(), L_BRING_IN_BLACK, L_BRING_IN_WHITE, pixAffineSampled(), and ptaGetCount().

◆ pixAffineSequential()

PIX* pixAffineSequential ( PIX pixs,
PTA ptad,
PTA ptas,
l_int32  bw,
l_int32  bh 
)

pixAffineSequential()

Parameters
[in]pixs
[in]ptad3 pts of final coordinate space
[in]ptas3 pts of initial coordinate space
[in]bwpixels of additional border width during computation
[in]bhpixels of additional border height during computation
Returns
pixd, or NULL on error
Notes:
     (1) The 3 pts must not be collinear.
     (2) The 3 pts must be given in this order:
          ~ origin
          ~ a location along the x-axis
          ~ a location along the y-axis.
     (3) You must guess how much border must be added so that no
         pixels are lost in the transformations from src to
         dest coordinate space.  (This can be calculated but it
         is a lot of work!)  For coordinate spaces that are nearly
         at right angles, on a 300 ppi scanned page, the addition
         of 1000 pixels on each side is usually sufficient.
     (4) This is here for pedagogical reasons.  It is about 3x faster
         on 1 bpp images than pixAffineSampled(), but the results
         on text are much inferior.

Definition at line 1468 of file affine.c.

References L_BRING_IN_WHITE, lept_stderr(), pixAddBorderGeneral(), pixClone(), pixCopy(), pixDestroy(), pixHShearIP(), pixRasteropIP(), pixRemoveBorderGeneral(), pixScale(), pixVShearIP(), ptaGetCount(), and ptaGetIPt().