Leptonica 1.68
C Image Processing Library
|
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