Leptonica  1.54
Файл src/affine.c
#include <string.h>
#include <math.h>
#include "allheaders.h"

Макросы

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

Функции

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_int32 getAffineXformCoeffs (PTA *ptas, PTA *ptad, l_float32 **pvc)
l_int32 affineInvertXform (l_float32 *vc, l_float32 **pvci)
l_int32 affineXformSampledPt (l_float32 *vc, l_int32 x, l_int32 y, l_int32 *pxp, l_int32 *pyp)
l_int32 affineXformPt (l_float32 *vc, l_int32 x, l_int32 y, l_float32 *pxp, l_float32 *pyp)
l_int32 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_int32 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)

Переменные

l_float32 AlphaMaskBorderVals [2]

Макросы

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

Функции

l_int32 affineInvertXform ( l_float32 vc,
l_float32 **  pvci 
)

affineInvertXform()

Input: vc (vector of 6 coefficients) *vci (<return> inverted transform) Return: 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.

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

affineXformPt()

Input: vc (vector of 6 coefficients) (x, y) (initial point) (&xp, &yp) (<return> transformed point) Return: 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!

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

affineXformSampledPt()

Input: vc (vector of 6 coefficients) (x, y) (initial point) (&xp, &yp) (<return> transformed point) Return: 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!

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

gaussjordan()

Input: a (n x n matrix) b (n x 1 right-hand side column vector) n (dimension) Return: 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)

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

getAffineXformCoeffs()

Input: ptas (source 3 points; unprimed) ptad (transformed 3 points; primed) &vc (<return> vector of coefficients of transform) Return: 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_int32 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()

Input: datas (ptr to beginning of image data) wpls (32-bit word/line for this data array) w, h (of image) x, y (floating pt location for evaluation) colorval (color brought in from the outside when the input x,y location is outside the image; in 0xrrggbb00 format)) &val (<return> interpolated color value) Return: 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.

l_int32 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()

Input: datas (ptr to beginning of image data) wpls (32-bit word/line for this data array) w, h (of image) x, y (floating pt location for evaluation) grayval (color brought in from the outside when the input x,y location is outside the image) &val (<return> interpolated gray value) Return: 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.

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

pixAffine()

Input: pixs (all depths; colormap ok) vc (vector of 6 coefficients for affine transformation) incolor (L_BRING_IN_WHITE, L_BRING_IN_BLACK) Return: 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

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

pixAffineColor()

Input: pixs (32 bpp) vc (vector of 6 coefficients for affine transformation) colorval (e.g., 0 to bring in BLACK, 0xffffff00 for WHITE) Return: pixd, or null on error

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

pixAffineGray()

Input: pixs (8 bpp) vc (vector of 6 coefficients for affine transformation) grayval (0 to bring in BLACK, 255 for WHITE) Return: pixd, or null on error

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

pixAffinePta()

Input: pixs (all depths; colormap ok) ptad (3 pts of final coordinate space) ptas (3 pts of initial coordinate space) incolor (L_BRING_IN_WHITE, L_BRING_IN_BLACK) Return: 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

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

pixAffinePtaColor()

Input: pixs (32 bpp) ptad (3 pts of final coordinate space) ptas (3 pts of initial coordinate space) colorval (e.g., 0 to bring in BLACK, 0xffffff00 for WHITE) Return: pixd, or null on error

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

pixAffinePtaGray()

Input: pixs (8 bpp) ptad (3 pts of final coordinate space) ptas (3 pts of initial coordinate space) grayval (0 to bring in BLACK, 255 for WHITE) Return: pixd, or null on error

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

pixAffinePtaWithAlpha()

Input: pixs (32 bpp rgb) ptad (3 pts of final coordinate space) ptas (3 pts of initial coordinate space) pixg (<optional> 8 bpp, can be null) fract (between 0.0 and 1.0, with 0.0 fully transparent and 1.0 fully opaque) border (of pixels added to capture transformed source pixels) Return: 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 . Otherwise, it is cropped to pixs if required and 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 and 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.

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

pixAffineSampled()

Input: pixs (all depths) vc (vector of 6 coefficients for affine transformation) incolor (L_BRING_IN_WHITE, L_BRING_IN_BLACK) Return: 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.

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

pixAffineSampledPta()

Input: pixs (all depths) ptad (3 pts of final coordinate space) ptas (3 pts of initial coordinate space) incolor (L_BRING_IN_WHITE, L_BRING_IN_BLACK) Return: 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.

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

pixAffineSequential()

Input: pixs ptad (3 pts of final coordinate space) ptas (3 pts of initial coordinate space) bw (pixels of additional border width during computation) bh (pixels of additional border height during computation) Return: 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.

Переменные