Leptonica 1.68
C Image Processing Library

affinecompose.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  *  affinecompose.c
00018  *
00019  *      Composable coordinate transforms
00020  *           l_float32   *createMatrix2dTranslate()
00021  *           l_float32   *createMatrixScale()
00022  *           l_float32   *createMatrixRotate()
00023  *
00024  *      Special coordinate transforms on pta
00025  *           PTA         *ptaTranslate()
00026  *           PTA         *ptaScale()
00027  *           PTA         *ptaRotate()
00028  *
00029  *      Special coordinate transforms on boxa
00030  *           BOXA        *boxaTranslate()
00031  *           BOXA        *boxaScale()
00032  *           BOXA        *boxaRotate()
00033  *
00034  *      General coordinate transform on pta and boxa
00035  *           PTA         *ptaAffineTransform()
00036  *           BOXA        *boxaAffineTransform()
00037  *
00038  *      Matrix operations
00039  *           l_int32      l_productMatVec()
00040  *           l_int32      l_productMat2()
00041  *           l_int32      l_productMat3()
00042  *           l_int32      l_productMat4()
00043  */
00044 
00045 #include <stdio.h>
00046 #include <stdlib.h>
00047 #include <math.h>
00048 #include "allheaders.h"
00049 
00050 
00051 /*-------------------------------------------------------------*
00052  *                Composable coordinate transforms             *
00053  *-------------------------------------------------------------*/
00054 /*!
00055  *  createMatrix2dTranslate()
00056  *
00057  *      Input:  transx  (x component of translation wrt. the origin)
00058  *              transy  (y component of translation wrt. the origin)
00059  *      Return: 3x3 transform matrix, or null on error
00060  *
00061  *  Notes;
00062  *      (1) The translation is equivalent to:
00063  *             v' = Av
00064  *          where v and v' are 1x3 column vectors in the form
00065  *             v = [x, y, 1]^    (^ denotes transpose)
00066  *          and the affine tranlation matrix is
00067  *             A = [ 1   0   tx
00068  *                   0   1   ty
00069  *                   0   0    1  ]
00070  *
00071  *      (2) We consider translation as with respect to a fixed origin.
00072  *          In a clipping operation, the origin moves and the points
00073  *          are fixed, and you use (-tx, -ty) where (tx, ty) is the
00074  *          translation vector of the origin.
00075  */
00076 l_float32 *
00077 createMatrix2dTranslate(l_float32  transx,
00078                         l_float32  transy)
00079 {
00080 l_float32  *mat;
00081 
00082     PROCNAME("createMatrix2dTranslate");
00083 
00084     if ((mat = (l_float32 *)CALLOC(9, sizeof(l_float32))) == NULL)
00085         return (l_float32 *)ERROR_PTR("mat not made", procName, NULL);
00086 
00087     mat[0] = mat[4] = mat[8] = 1;
00088     mat[2] = transx;
00089     mat[5] = transy;
00090     return mat;
00091 }
00092 
00093 
00094 /*!
00095  *  createMatrix2dScale()
00096  *
00097  *      Input:  scalex  (horizontal scale factor)
00098  *              scaley  (vertical scale factor)
00099  *      Return: 3x3 transform matrix, or null on error
00100  *
00101  *  Notes;
00102  *      (1) The scaling is equivalent to:
00103  *             v' = Av
00104  *          where v and v' are 1x3 column vectors in the form
00105  *             v = [x, y, 1]^    (^ denotes transpose)
00106  *          and the affine scaling matrix is
00107  *             A = [ sx  0    0 
00108  *                   0   sy   0 
00109  *                   0   0    1  ]
00110  *
00111  *      (2) We consider scaling as with respect to a fixed origin.
00112  *          In other words, the origin is the only point that doesn't
00113  *          move in the scaling transform.
00114  */
00115 l_float32 *
00116 createMatrix2dScale(l_float32  scalex,
00117                     l_float32  scaley)
00118 {
00119 l_float32  *mat;
00120 
00121     PROCNAME("createMatrix2dScale");
00122 
00123     if ((mat = (l_float32 *)CALLOC(9, sizeof(l_float32))) == NULL)
00124         return (l_float32 *)ERROR_PTR("mat not made", procName, NULL);
00125 
00126     mat[0] = scalex;
00127     mat[4] = scaley;
00128     mat[8] = 1;
00129     return mat;
00130 }
00131 
00132 
00133 /*!
00134  *  createMatrix2dRotate()
00135  *
00136  *      Input:  xc, yc  (location of center of rotation)
00137  *              angle  (rotation in radians; clockwise is positive)
00138  *      Return: 3x3 transform matrix, or null on error
00139  *
00140  *  Notes;
00141  *      (1) The rotation is equivalent to:
00142  *             v' = Av
00143  *          where v and v' are 1x3 column vectors in the form
00144  *             v = [x, y, 1]^    (^ denotes transpose)
00145  *          and the affine rotation matrix is
00146  *             A = [ cosa   -sina    xc*(1-cosa) + yc*sina
00147  *                   sina    cosa    yc*(1-cosa) - xc*sina
00148  *                     0       0                 1         ]
00149  *
00150  *          If the rotation is about the origin, (xc, yc) = (0, 0) and
00151  *          this simplifies to
00152  *             A = [ cosa   -sina    0
00153  *                   sina    cosa    0
00154  *                     0       0     1 ]
00155  *
00156  *          These relations follow from the following equations, which
00157  *          you can convince yourself are correct as follows.  Draw a
00158  *          circle centered on (xc,yc) and passing through (x,y), with
00159  *          (x',y') on the arc at an angle 'a' clockwise from (x,y).
00160  *          [ Hint: cos(a + b) = cosa * cosb - sina * sinb
00161  *                  sin(a + b) = sina * cosb + cosa * sinb ]
00162  *
00163  *            x' - xc =  (x - xc) * cosa - (y - yc) * sina
00164  *            y' - yc =  (x - xc) * sina + (y - yc) * cosa
00165  */
00166 l_float32 *
00167 createMatrix2dRotate(l_float32  xc,
00168                      l_float32  yc,
00169                      l_float32  angle)
00170 {
00171 l_float32   sina, cosa;
00172 l_float32  *mat;
00173 
00174     PROCNAME("createMatrix2dRotate");
00175 
00176     if ((mat = (l_float32 *)CALLOC(9, sizeof(l_float32))) == NULL)
00177         return (l_float32 *)ERROR_PTR("mat not made", procName, NULL);
00178 
00179     sina = sin(angle);
00180     cosa = cos(angle);
00181     mat[0] = mat[4] = cosa;
00182     mat[1] = -sina;
00183     mat[2] = xc * (1.0 - cosa) + yc * sina;
00184     mat[3] = sina;
00185     mat[5] = yc * (1.0 - cosa) - xc * sina;
00186     mat[8] = 1;
00187     return mat;
00188 }
00189 
00190 
00191 
00192 /*-------------------------------------------------------------*
00193  *            Special coordinate transforms on pta             *
00194  *-------------------------------------------------------------*/
00195 /*!
00196  *  ptaTranslate()
00197  *
00198  *      Input:  ptas (for initial points)
00199  *              transx  (x component of translation wrt. the origin)
00200  *              transy  (y component of translation wrt. the origin)
00201  *      Return: ptad  (translated points), or null on error
00202  *
00203  *  Notes;
00204  *      (1) See createMatrix2dTranslate() for details of transform.
00205  */
00206 PTA *
00207 ptaTranslate(PTA       *ptas,
00208              l_float32  transx,
00209              l_float32  transy)
00210 {
00211 l_int32    i, npts;
00212 l_float32  x, y;
00213 PTA       *ptad;
00214 
00215     PROCNAME("ptaTranslate");
00216 
00217     if (!ptas)
00218         return (PTA *)ERROR_PTR("ptas not defined", procName, NULL);
00219 
00220     npts = ptaGetCount(ptas);
00221     if ((ptad = ptaCreate(npts)) == NULL)
00222         return (PTA *)ERROR_PTR("ptad not made", procName, NULL);
00223     for (i = 0; i < npts; i++) {
00224         ptaGetPt(ptas, i, &x, &y);
00225         ptaAddPt(ptad, x + transx, y + transy);
00226     }
00227 
00228     return ptad;
00229 }
00230 
00231 
00232 /*!
00233  *  ptaScale()
00234  *
00235  *      Input:  ptas (for initial points)
00236  *              scalex  (horizontal scale factor)
00237  *              scaley  (vertical scale factor)
00238  *      Return: 0 if OK; 1 on error
00239  *
00240  *  Notes;
00241  *      (1) See createMatrix2dScale() for details of transform.
00242  */
00243 PTA *
00244 ptaScale(PTA       *ptas,
00245          l_float32  scalex,
00246          l_float32  scaley)
00247 {
00248 l_int32    i, npts;
00249 l_float32  x, y;
00250 PTA       *ptad;
00251 
00252     PROCNAME("ptaScale");
00253 
00254     if (!ptas)
00255         return (PTA *)ERROR_PTR("ptas not defined", procName, NULL);
00256 
00257     npts = ptaGetCount(ptas);
00258     if ((ptad = ptaCreate(npts)) == NULL)
00259         return (PTA *)ERROR_PTR("ptad not made", procName, NULL);
00260     for (i = 0; i < npts; i++) {
00261         ptaGetPt(ptas, i, &x, &y);
00262         ptaAddPt(ptad, scalex * x, scaley * y);
00263     }
00264 
00265     return ptad;
00266 }
00267 
00268 
00269 /*!
00270  *  ptaRotate()
00271  *
00272  *      Input:  ptas (for initial points)
00273  *              (xc, yc)  (location of center of rotation)
00274  *              angle  (rotation in radians; clockwise is positive)
00275  *              (&ptad)  (<return> new locations)
00276  *      Return: 0 if OK; 1 on error
00277  *
00278  *  Notes;
00279  *      (1) See createMatrix2dScale() for details of transform.
00280  */
00281 PTA *
00282 ptaRotate(PTA       *ptas,
00283           l_float32  xc,
00284           l_float32  yc,
00285           l_float32  angle)
00286 {
00287 l_int32    i, npts;
00288 l_float32  x, y, xp, yp, sina, cosa;
00289 PTA       *ptad;
00290 
00291     PROCNAME("ptaRotate");
00292 
00293     if (!ptas)
00294         return (PTA *)ERROR_PTR("ptas not defined", procName, NULL);
00295 
00296     npts = ptaGetCount(ptas);
00297     if ((ptad = ptaCreate(npts)) == NULL)
00298         return (PTA *)ERROR_PTR("ptad not made", procName, NULL);
00299     sina = sin(angle);
00300     cosa = cos(angle);
00301     for (i = 0; i < npts; i++) {
00302         ptaGetPt(ptas, i, &x, &y);
00303         xp = xc + (x - xc) * cosa - (y - yc) * sina;
00304         yp = yc + (x - xc) * sina + (y - yc) * cosa;
00305         ptaAddPt(ptad, xp, yp);
00306     }
00307 
00308     return ptad;
00309 }
00310 
00311 
00312 /*-------------------------------------------------------------*
00313  *            Special coordinate transforms on boxa            *
00314  *-------------------------------------------------------------*/
00315 /*!
00316  *  boxaTranslate()
00317  *
00318  *      Input:  boxas
00319  *              transx  (x component of translation wrt. the origin)
00320  *              transy  (y component of translation wrt. the origin)
00321  *      Return: boxad  (translated boxas), or null on error
00322  *
00323  *  Notes;
00324  *      (1) See createMatrix2dTranslate() for details of transform.
00325  */
00326 BOXA *
00327 boxaTranslate(BOXA       *boxas,
00328               l_float32  transx,
00329               l_float32  transy)
00330 {
00331 PTA   *ptas, *ptad;
00332 BOXA  *boxad;
00333 
00334     PROCNAME("boxaTranslate");
00335 
00336     if (!boxas)
00337         return (BOXA *)ERROR_PTR("boxas not defined", procName, NULL);
00338 
00339     ptas = boxaConvertToPta(boxas, 4);
00340     ptad = ptaTranslate(ptas, transx, transy);
00341     boxad = ptaConvertToBoxa(ptad, 4);
00342     ptaDestroy(&ptas);
00343     ptaDestroy(&ptad);
00344     return boxad;
00345 }
00346 
00347 
00348 /*!
00349  *  boxaScale()
00350  *
00351  *      Input:  boxas
00352  *              scalex  (horizontal scale factor)
00353  *              scaley  (vertical scale factor)
00354  *      Return: boxad  (scaled boxas), or null on error
00355  *
00356  *  Notes;
00357  *      (1) See createMatrix2dScale() for details of transform.
00358  */
00359 BOXA *
00360 boxaScale(BOXA      *boxas,
00361           l_float32  scalex,
00362           l_float32  scaley)
00363 {
00364 PTA   *ptas, *ptad;
00365 BOXA  *boxad;
00366 
00367     PROCNAME("boxaScale");
00368 
00369     if (!boxas)
00370         return (BOXA *)ERROR_PTR("boxas not defined", procName, NULL);
00371 
00372     ptas = boxaConvertToPta(boxas, 4);
00373     ptad = ptaScale(ptas, scalex, scaley);
00374     boxad = ptaConvertToBoxa(ptad, 4);
00375     ptaDestroy(&ptas);
00376     ptaDestroy(&ptad);
00377     return boxad;
00378 }
00379 
00380 
00381 /*!
00382  *  boxaRotate()
00383  *
00384  *      Input:  boxas
00385  *              (xc, yc)  (location of center of rotation)
00386  *              angle  (rotation in radians; clockwise is positive)
00387  *      Return: boxad  (scaled boxas), or null on error
00388  *
00389  *  Notes;
00390  *      (1) See createMatrix2dRotate() for details of transform.
00391  */
00392 BOXA *
00393 boxaRotate(BOXA      *boxas,
00394            l_float32  xc,
00395            l_float32  yc,
00396            l_float32  angle)
00397 {
00398 PTA   *ptas, *ptad;
00399 BOXA  *boxad;
00400 
00401     PROCNAME("boxaRotate");
00402 
00403     if (!boxas)
00404         return (BOXA *)ERROR_PTR("boxas not defined", procName, NULL);
00405 
00406     ptas = boxaConvertToPta(boxas, 4);
00407     ptad = ptaRotate(ptas, xc, yc, angle);
00408     boxad = ptaConvertToBoxa(ptad, 4);
00409     ptaDestroy(&ptas);
00410     ptaDestroy(&ptad);
00411     return boxad;
00412 }
00413 
00414 
00415 /*-------------------------------------------------------------*
00416  *            General affine coordinate transform              *
00417  *-------------------------------------------------------------*/
00418 /*!
00419  *  ptaAffineTransform()
00420  *
00421  *      Input:  ptas (for initial points)
00422  *              mat  (3x3 transform matrix; canonical form)
00423  *      Return: ptad  (transformed points), or null on error
00424  */
00425 PTA *
00426 ptaAffineTransform(PTA        *ptas,
00427                    l_float32  *mat)
00428 {
00429 l_int32    i, npts;
00430 l_float32  vecs[3], vecd[3];
00431 PTA       *ptad;
00432 
00433     PROCNAME("ptaAffineTransform");
00434 
00435     if (!ptas)
00436         return (PTA *)ERROR_PTR("ptas not defined", procName, NULL);
00437     if (!mat)
00438         return (PTA *)ERROR_PTR("transform not defined", procName, NULL);
00439 
00440     vecs[2] = 1;
00441     npts = ptaGetCount(ptas);
00442     if ((ptad = ptaCreate(npts)) == NULL)
00443         return (PTA *)ERROR_PTR("ptad not made", procName, NULL);
00444     for (i = 0; i < npts; i++) {
00445         ptaGetPt(ptas, i, &vecs[0], &vecs[1]);
00446         l_productMatVec(mat, vecs, vecd, 3);
00447         ptaAddPt(ptad, vecd[0], vecd[1]);
00448     }
00449 
00450     return ptad;
00451 }
00452 
00453 
00454 /*!
00455  *  boxaAffineTransform()
00456  *
00457  *      Input:  boxas
00458  *              mat  (3x3 transform matrix; canonical form)
00459  *      Return: boxad  (transformed boxas), or null on error
00460  */
00461 BOXA *
00462 boxaAffineTransform(BOXA       *boxas,
00463                     l_float32  *mat)
00464 {
00465 PTA   *ptas, *ptad;
00466 BOXA  *boxad;
00467 
00468     PROCNAME("boxaAffineTransform");
00469 
00470     if (!boxas)
00471         return (BOXA *)ERROR_PTR("boxas not defined", procName, NULL);
00472     if (!mat)
00473         return (BOXA *)ERROR_PTR("transform not defined", procName, NULL);
00474 
00475     ptas = boxaConvertToPta(boxas, 4);
00476     ptad = ptaAffineTransform(ptas, mat);
00477     boxad = ptaConvertToBoxa(ptad, 4);
00478     ptaDestroy(&ptas);
00479     ptaDestroy(&ptad);
00480     return boxad;
00481 }
00482 
00483 
00484 /*-------------------------------------------------------------*
00485  *                      Matrix operations                      *
00486  *-------------------------------------------------------------*/
00487 /*!
00488  *  l_productMatVec()
00489  *
00490  *      Input:  mat  (square matrix, as a 1-dimensional @size^2 array)
00491  *              vecs (input column vector of length @size)
00492  *              vecd (result column vector)
00493  *              size (matrix is @size x @size; vectors are length @size)
00494  *      Return: 0 if OK, 1 on error
00495  */
00496 l_int32
00497 l_productMatVec(l_float32  *mat,
00498                 l_float32  *vecs,
00499                 l_float32  *vecd,
00500                 l_int32     size)
00501 {
00502 l_int32  i, j;
00503 
00504     PROCNAME("l_productMatVec");
00505 
00506     if (!mat)
00507         return ERROR_INT("matrix not defined", procName, 1);
00508     if (!vecs)
00509         return ERROR_INT("input vector not defined", procName, 1);
00510     if (!vecd)
00511         return ERROR_INT("result vector not defined", procName, 1);
00512 
00513     for (i = 0; i < size; i++) {
00514         vecd[i] = 0;
00515         for (j = 0; j < size; j++) {
00516             vecd[i] += mat[size * i + j] * vecs[j];
00517         }
00518     }
00519     return 0;
00520 }
00521 
00522 
00523 /*!
00524  *  l_productMat2()
00525  *
00526  *      Input:  mat1  (square matrix, as a 1-dimensional size^2 array)
00527  *              mat2  (square matrix, as a 1-dimensional size^2 array)
00528  *              matd  (square matrix; product stored here)
00529  *              size (of matrices)
00530  *      Return: 0 if OK, 1 on error
00531  */
00532 l_int32
00533 l_productMat2(l_float32  *mat1,
00534               l_float32  *mat2,
00535               l_float32  *matd,
00536               l_int32     size)
00537 {
00538 l_int32  i, j, k, index;
00539 
00540     PROCNAME("l_productMat2");
00541 
00542     if (!mat1)
00543         return ERROR_INT("matrix 1 not defined", procName, 1);
00544     if (!mat2)
00545         return ERROR_INT("matrix 2 not defined", procName, 1);
00546     if (!matd)
00547         return ERROR_INT("result matrix not defined", procName, 1);
00548 
00549     for (i = 0; i < size; i++) {
00550         for (j = 0; j < size; j++) {
00551             index = size * i + j;
00552             matd[index] = 0;
00553             for (k = 0; k < size; k++)
00554                  matd[index] += mat1[size * i + k] * mat2[size * k + j];
00555         }
00556     }
00557     return 0;
00558 }
00559 
00560 
00561 /*!
00562  *  l_productMat3()
00563  *
00564  *      Input:  mat1  (square matrix, as a 1-dimensional size^2 array)
00565  *              mat2  (square matrix, as a 1-dimensional size^2 array)
00566  *              mat3  (square matrix, as a 1-dimensional size^2 array)
00567  *              matd  (square matrix; product stored here)
00568  *              size  (of matrices)
00569  *      Return: 0 if OK, 1 on error
00570  */
00571 l_int32
00572 l_productMat3(l_float32  *mat1,
00573               l_float32  *mat2,
00574               l_float32  *mat3,
00575               l_float32  *matd,
00576               l_int32     size)
00577 {
00578 l_float32  *matt;
00579 
00580     PROCNAME("l_productMat3");
00581 
00582     if (!mat1)
00583         return ERROR_INT("matrix 1 not defined", procName, 1);
00584     if (!mat2)
00585         return ERROR_INT("matrix 2 not defined", procName, 1);
00586     if (!mat3)
00587         return ERROR_INT("matrix 3 not defined", procName, 1);
00588     if (!matd)
00589         return ERROR_INT("result matrix not defined", procName, 1);
00590 
00591     if ((matt = (l_float32 *)CALLOC(size * size, sizeof(l_float32))) == NULL)
00592         return ERROR_INT("matt not made", procName, 1);
00593     l_productMat2(mat1, mat2, matt, size);
00594     l_productMat2(matt, mat3, matd, size);
00595     FREE(matt);
00596     return 0;
00597 }
00598 
00599 
00600 /*!
00601  *  l_productMat4()
00602  *
00603  *      Input:  mat1  (square matrix, as a 1-dimensional size^2 array)
00604  *              mat2  (square matrix, as a 1-dimensional size^2 array)
00605  *              mat3  (square matrix, as a 1-dimensional size^2 array)
00606  *              mat4  (square matrix, as a 1-dimensional size^2 array)
00607  *              matd  (square matrix; product stored here)
00608  *              size  (of matrices)
00609  *      Return: 0 if OK, 1 on error
00610  */
00611 l_int32
00612 l_productMat4(l_float32  *mat1,
00613               l_float32  *mat2,
00614               l_float32  *mat3,
00615               l_float32  *mat4,
00616               l_float32  *matd,
00617               l_int32     size)
00618 {
00619 l_float32  *matt;
00620 
00621     PROCNAME("l_productMat4");
00622 
00623     if (!mat1)
00624         return ERROR_INT("matrix 1 not defined", procName, 1);
00625     if (!mat2)
00626         return ERROR_INT("matrix 2 not defined", procName, 1);
00627     if (!mat3)
00628         return ERROR_INT("matrix 3 not defined", procName, 1);
00629     if (!matd)
00630         return ERROR_INT("result matrix not defined", procName, 1);
00631 
00632     if ((matt = (l_float32 *)CALLOC(size * size, sizeof(l_float32))) == NULL)
00633         return ERROR_INT("matt not made", procName, 1);
00634     l_productMat3(mat1, mat2, mat3, matt, size);
00635     l_productMat2(matt, mat4, matd, size);
00636     FREE(matt);
00637     return 0;
00638 }
00639 
00640 
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines