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 /* 00018 * ptafunc1.c 00019 * 00020 * Pta and Ptaa rearrangements 00021 * PTA *ptaSubsample() 00022 * l_int32 ptaJoin() 00023 * PTA *ptaReverse() 00024 * PTA *ptaCyclicPerm() 00025 * PTA *ptaSort() 00026 * PTA *ptaRemoveDuplicates() 00027 * PTAA *ptaaSortByIndex() 00028 * 00029 * Geometric 00030 * BOX *ptaGetBoundingRegion() 00031 * l_int32 *ptaGetRange() 00032 * PTA *ptaGetInsideBox() 00033 * PTA *pixFindCornerPixels() 00034 * l_int32 ptaContainsPt() 00035 * l_int32 ptaTestIntersection() 00036 * PTA *ptaTransform() 00037 * 00038 * Least Squares Fit 00039 * l_int32 ptaGetLinearLSF() 00040 * l_int32 ptaGetQuadraticLSF() 00041 * l_int32 ptaGetCubicLSF() 00042 * l_int32 ptaGetQuarticLSF() 00043 * l_int32 applyLinearFit() 00044 * l_int32 applyQuadraticFit() 00045 * l_int32 applyCubicFit() 00046 * l_int32 applyQuarticFit() 00047 * 00048 * Interconversions with Pix 00049 * l_int32 pixPlotAlongPta() 00050 * PTA *ptaGetPixelsFromPix() 00051 * PIX *pixGenerateFromPta() 00052 * PTA *ptaGetBoundaryPixels() 00053 * PTAA *ptaaGetBoundaryPixels() 00054 * 00055 * Display Pta and Ptaa 00056 * PIX *pixDisplayPta() 00057 * PIX *pixDisplayPtaa() 00058 */ 00059 00060 #include <string.h> 00061 #include "allheaders.h" 00062 00063 /* Default spreading factor for hashing pts in a plane */ 00064 static const l_int32 DEFAULT_SPREADING_FACTOR = 7500; 00065 00066 00067 /*---------------------------------------------------------------------* 00068 * Pta rearrangements * 00069 *---------------------------------------------------------------------*/ 00070 /*! 00071 * ptaSubsample() 00072 * 00073 * Input: ptas 00074 * subfactor (subsample factor, >= 1) 00075 * Return: ptad (evenly sampled pt values from ptas, or null on error 00076 */ 00077 PTA * 00078 ptaSubsample(PTA *ptas, 00079 l_int32 subfactor) 00080 { 00081 l_int32 n, i; 00082 l_float32 x, y; 00083 PTA *ptad; 00084 00085 PROCNAME("pixSubsample"); 00086 00087 if (!ptas) 00088 return (PTA *)ERROR_PTR("ptas not defined", procName, NULL); 00089 if (subfactor < 1) 00090 return (PTA *)ERROR_PTR("subfactor < 1", procName, NULL); 00091 00092 ptad = ptaCreate(0); 00093 n = ptaGetCount(ptas); 00094 for (i = 0; i < n; i++) { 00095 if (i % subfactor != 0) continue; 00096 ptaGetPt(ptas, i, &x, &y); 00097 ptaAddPt(ptad, x, y); 00098 } 00099 00100 return ptad; 00101 } 00102 00103 00104 /*! 00105 * ptaJoin() 00106 * 00107 * Input: ptad (dest pta; add to this one) 00108 * ptas (source pta; add from this one) 00109 * istart (starting index in ptas) 00110 * iend (ending index in ptas; use 0 to cat all) 00111 * Return: 0 if OK, 1 on error 00112 * 00113 * Notes: 00114 * (1) istart < 0 is taken to mean 'read from the start' (istart = 0) 00115 * (2) iend <= 0 means 'read to the end' 00116 */ 00117 l_int32 00118 ptaJoin(PTA *ptad, 00119 PTA *ptas, 00120 l_int32 istart, 00121 l_int32 iend) 00122 { 00123 l_int32 ns, i, x, y; 00124 00125 PROCNAME("ptaJoin"); 00126 00127 if (!ptad) 00128 return ERROR_INT("ptad not defined", procName, 1); 00129 if (!ptas) 00130 return ERROR_INT("ptas not defined", procName, 1); 00131 ns = ptaGetCount(ptas); 00132 if (istart < 0) 00133 istart = 0; 00134 if (istart >= ns) 00135 return ERROR_INT("istart out of bounds", procName, 1); 00136 if (iend <= 0) 00137 iend = ns - 1; 00138 if (iend >= ns) 00139 return ERROR_INT("iend out of bounds", procName, 1); 00140 if (istart > iend) 00141 return ERROR_INT("istart > iend; no pts", procName, 1); 00142 00143 for (i = istart; i <= iend; i++) { 00144 ptaGetIPt(ptas, i, &x, &y); 00145 ptaAddPt(ptad, x, y); 00146 } 00147 00148 return 0; 00149 } 00150 00151 00152 /*! 00153 * ptaReverse() 00154 * 00155 * Input: ptas 00156 * type (0 for float values; 1 for integer values) 00157 * Return: ptad (reversed pta), or null on error 00158 */ 00159 PTA * 00160 ptaReverse(PTA *ptas, 00161 l_int32 type) 00162 { 00163 l_int32 n, i, ix, iy; 00164 l_float32 x, y; 00165 PTA *ptad; 00166 00167 PROCNAME("ptaReverse"); 00168 00169 if (!ptas) 00170 return (PTA *)ERROR_PTR("ptas not defined", procName, NULL); 00171 00172 n = ptaGetCount(ptas); 00173 if ((ptad = ptaCreate(n)) == NULL) 00174 return (PTA *)ERROR_PTR("ptad not made", procName, NULL); 00175 for (i = n - 1; i >= 0; i--) { 00176 if (type == 0) { 00177 ptaGetPt(ptas, i, &x, &y); 00178 ptaAddPt(ptad, x, y); 00179 } 00180 else { /* type == 1 */ 00181 ptaGetIPt(ptas, i, &ix, &iy); 00182 ptaAddPt(ptad, ix, iy); 00183 } 00184 } 00185 00186 return ptad; 00187 } 00188 00189 00190 /*! 00191 * ptaCyclicPerm() 00192 * 00193 * Input: ptas 00194 * xs, ys (start point; must be in ptas) 00195 * Return: ptad (cyclic permutation, starting and ending at (xs, ys), 00196 * or null on error 00197 * 00198 * Notes: 00199 * (1) Check to insure that (a) ptas is a closed path where 00200 * the first and last points are identical, and (b) the 00201 * resulting pta also starts and ends on the same point 00202 * (which in this case is (xs, ys). 00203 */ 00204 PTA * 00205 ptaCyclicPerm(PTA *ptas, 00206 l_int32 xs, 00207 l_int32 ys) 00208 { 00209 l_int32 n, i, x, y, j, index, state; 00210 l_int32 x1, y1, x2, y2; 00211 PTA *ptad; 00212 00213 PROCNAME("ptaCyclicPerm"); 00214 00215 if (!ptas) 00216 return (PTA *)ERROR_PTR("ptas not defined", procName, NULL); 00217 00218 n = ptaGetCount(ptas); 00219 00220 /* Verify input data */ 00221 ptaGetIPt(ptas, 0, &x1, &y1); 00222 ptaGetIPt(ptas, n - 1, &x2, &y2); 00223 if (x1 != x2 || y1 != y2) 00224 return (PTA *)ERROR_PTR("start and end pts not same", procName, NULL); 00225 state = L_NOT_FOUND; 00226 for (i = 0; i < n; i++) { 00227 ptaGetIPt(ptas, i, &x, &y); 00228 if (x == xs && y == ys) { 00229 state = L_FOUND; 00230 break; 00231 } 00232 } 00233 if (state == L_NOT_FOUND) 00234 return (PTA *)ERROR_PTR("start pt not in ptas", procName, NULL); 00235 00236 if ((ptad = ptaCreate(n)) == NULL) 00237 return (PTA *)ERROR_PTR("ptad not made", procName, NULL); 00238 for (j = 0; j < n - 1; j++) { 00239 if (i + j < n - 1) 00240 index = i + j; 00241 else 00242 index = (i + j + 1) % n; 00243 ptaGetIPt(ptas, index, &x, &y); 00244 ptaAddPt(ptad, x, y); 00245 } 00246 ptaAddPt(ptad, xs, ys); 00247 00248 return ptad; 00249 } 00250 00251 00252 /*! 00253 * ptaSort() 00254 * 00255 * Input: ptas 00256 * sorttype (L_SORT_BY_X, L_SORT_BY_Y) 00257 * sortorder (L_SORT_INCREASING, L_SORT_DECREASING) 00258 * &naindex (<optional return> index of sorted order into 00259 * original array) 00260 * Return: ptad (sorted version of ptas), or null on error 00261 */ 00262 PTA * 00263 ptaSort(PTA *ptas, 00264 l_int32 sorttype, 00265 l_int32 sortorder, 00266 NUMA **pnaindex) 00267 { 00268 l_int32 i, index, n; 00269 l_float32 x, y; 00270 PTA *ptad; 00271 NUMA *na, *naindex; 00272 00273 PROCNAME("ptaSort"); 00274 00275 if (!ptas) 00276 return (PTA *)ERROR_PTR("ptas not defined", procName, NULL); 00277 if (sorttype != L_SORT_BY_X && sorttype != L_SORT_BY_Y) 00278 return (PTA *)ERROR_PTR("invalid sort type", procName, NULL); 00279 if (sortorder != L_SORT_INCREASING && sortorder != L_SORT_DECREASING) 00280 return (PTA *)ERROR_PTR("invalid sort order", procName, NULL); 00281 00282 /* Build up numa of specific data */ 00283 n = ptaGetCount(ptas); 00284 if ((na = numaCreate(n)) == NULL) 00285 return (PTA *)ERROR_PTR("na not made", procName, NULL); 00286 for (i = 0; i < n; i++) { 00287 ptaGetPt(ptas, i, &x, &y); 00288 if (sorttype == L_SORT_BY_X) 00289 numaAddNumber(na, x); 00290 else 00291 numaAddNumber(na, y); 00292 } 00293 00294 /* Get the sort index for data array */ 00295 if ((naindex = numaGetSortIndex(na, sortorder)) == NULL) 00296 return (PTA *)ERROR_PTR("naindex not made", procName, NULL); 00297 00298 /* Build up sorted pta using sort index */ 00299 if ((ptad = ptaCreate(n)) == NULL) 00300 return (PTA *)ERROR_PTR("ptad not made", procName, NULL); 00301 for (i = 0; i < n; i++) { 00302 numaGetIValue(naindex, i, &index); 00303 ptaGetPt(ptas, index, &x, &y); 00304 ptaAddPt(ptad, x, y); 00305 } 00306 00307 if (pnaindex) 00308 *pnaindex = naindex; 00309 else 00310 numaDestroy(&naindex); 00311 numaDestroy(&na); 00312 return ptad; 00313 } 00314 00315 00316 /*! 00317 * ptaRemoveDuplicates() 00318 * 00319 * Input: ptas (assumed to be integer values) 00320 * factor (should be larger than the largest point value; 00321 * use 0 for default) 00322 * Return: ptad (with duplicates removed), or null on error 00323 */ 00324 PTA * 00325 ptaRemoveDuplicates(PTA *ptas, 00326 l_uint32 factor) 00327 { 00328 l_int32 nsize, i, j, k, index, n, nvals; 00329 l_int32 x, y, xk, yk; 00330 l_int32 *ia; 00331 PTA *ptad; 00332 NUMA *na; 00333 NUMAHASH *nahash; 00334 00335 PROCNAME("ptaRemoveDuplicates"); 00336 00337 if (!ptas) 00338 return (PTA *)ERROR_PTR("ptas not defined", procName, NULL); 00339 if (factor == 0) 00340 factor = DEFAULT_SPREADING_FACTOR; 00341 00342 /* Build up numaHash of indices, hashed by a key that is 00343 * a large linear combination of x and y values designed to 00344 * randomize the key. */ 00345 nsize = 5507; /* buckets in hash table; prime */ 00346 nahash = numaHashCreate(nsize, 2); 00347 n = ptaGetCount(ptas); 00348 for (i = 0; i < n; i++) { 00349 ptaGetIPt(ptas, i, &x, &y); 00350 numaHashAdd(nahash, factor * x + y, (l_float32)i); 00351 } 00352 00353 if ((ptad = ptaCreate(n)) == NULL) 00354 return (PTA *)ERROR_PTR("ptad not made", procName, NULL); 00355 for (i = 0; i < nsize; i++) { 00356 na = numaHashGetNuma(nahash, i); 00357 if (!na) continue; 00358 00359 nvals = numaGetCount(na); 00360 /* If more than 1 pt, compare exhaustively with double loop; 00361 * otherwise, just enter it. */ 00362 if (nvals > 1) { 00363 if ((ia = (l_int32 *)CALLOC(nvals, sizeof(l_int32))) == NULL) 00364 return (PTA *)ERROR_PTR("ia not made", procName, NULL); 00365 for (j = 0; j < nvals; j++) { 00366 if (ia[j] == 1) continue; 00367 numaGetIValue(na, j, &index); 00368 ptaGetIPt(ptas, index, &x, &y); 00369 ptaAddPt(ptad, x, y); 00370 for (k = j + 1; k < nvals; k++) { 00371 if (ia[k] == 1) continue; 00372 numaGetIValue(na, k, &index); 00373 ptaGetIPt(ptas, index, &xk, &yk); 00374 if (x == xk && y == yk) /* duplicate */ 00375 ia[k] = 1; 00376 } 00377 } 00378 FREE(ia); 00379 } 00380 else { 00381 numaGetIValue(na, 0, &index); 00382 ptaGetIPt(ptas, index, &x, &y); 00383 ptaAddPt(ptad, x, y); 00384 } 00385 numaDestroy(&na); /* the clone */ 00386 } 00387 00388 numaHashDestroy(&nahash); 00389 return ptad; 00390 } 00391 00392 00393 /*! 00394 * ptaaSortByIndex() 00395 * 00396 * Input: ptaas 00397 * naindex (na that maps from the new ptaa to the input ptaa) 00398 * Return: ptaad (sorted), or null on error 00399 */ 00400 PTAA * 00401 ptaaSortByIndex(PTAA *ptaas, 00402 NUMA *naindex) 00403 { 00404 l_int32 i, n, index; 00405 PTA *pta; 00406 PTAA *ptaad; 00407 00408 PROCNAME("ptaaSortByIndex"); 00409 00410 if (!ptaas) 00411 return (PTAA *)ERROR_PTR("ptaas not defined", procName, NULL); 00412 if (!naindex) 00413 return (PTAA *)ERROR_PTR("naindex not defined", procName, NULL); 00414 00415 n = ptaaGetCount(ptaas); 00416 if (numaGetCount(naindex) != n) 00417 return (PTAA *)ERROR_PTR("numa and ptaa sizes differ", procName, NULL); 00418 ptaad = ptaaCreate(n); 00419 for (i = 0; i < n; i++) { 00420 numaGetIValue(naindex, i, &index); 00421 pta = ptaaGetPta(ptaas, index, L_COPY); 00422 ptaaAddPta(ptaad, pta, L_INSERT); 00423 } 00424 00425 return ptaad; 00426 } 00427 00428 00429 00430 /*---------------------------------------------------------------------* 00431 * Geometric * 00432 *---------------------------------------------------------------------*/ 00433 /*! 00434 * ptaGetBoundingRegion() 00435 * 00436 * Input: pta 00437 * Return: box, or null on error 00438 * 00439 * Notes: 00440 * (1) This is used when the pta represents a set of points in 00441 * a two-dimensional image. It returns the box of minimum 00442 * size containing the pts in the pta. 00443 */ 00444 BOX * 00445 ptaGetBoundingRegion(PTA *pta) 00446 { 00447 l_int32 n, i, x, y, minx, maxx, miny, maxy; 00448 00449 PROCNAME("ptaGetBoundingRegion"); 00450 00451 if (!pta) 00452 return (BOX *)ERROR_PTR("pta not defined", procName, NULL); 00453 00454 minx = 10000000; 00455 miny = 10000000; 00456 maxx = -10000000; 00457 maxy = -10000000; 00458 n = ptaGetCount(pta); 00459 for (i = 0; i < n; i++) { 00460 ptaGetIPt(pta, i, &x, &y); 00461 if (x < minx) minx = x; 00462 if (x > maxx) maxx = x; 00463 if (y < miny) miny = y; 00464 if (y > maxy) maxy = y; 00465 } 00466 00467 return boxCreate(minx, miny, maxx - minx + 1, maxy - miny + 1); 00468 } 00469 00470 00471 /*! 00472 * ptaGetRange() 00473 * 00474 * Input: pta 00475 * &minx (<optional return> min value of x) 00476 * &maxx (<optional return> max value of x) 00477 * &miny (<optional return> min value of y) 00478 * &maxy (<optional return> max value of y) 00479 * Return: 0 if OK, 1 on error 00480 * 00481 * Notes: 00482 * (1) We can use pts to represent pairs of floating values, that 00483 * are not necessarily tied to a two-dimension region. For 00484 * example, the pts can represent a general function y(x). 00485 */ 00486 l_int32 00487 ptaGetRange(PTA *pta, 00488 l_float32 *pminx, 00489 l_float32 *pmaxx, 00490 l_float32 *pminy, 00491 l_float32 *pmaxy) 00492 { 00493 l_int32 n, i; 00494 l_float32 x, y, minx, maxx, miny, maxy; 00495 00496 PROCNAME("ptaGetRange"); 00497 00498 if (!pminx && !pmaxx && !pminy && !pmaxy) 00499 return ERROR_INT("no output requested", procName, 1); 00500 if (pminx) *pminx = 0; 00501 if (pmaxx) *pmaxx = 0; 00502 if (pminy) *pminy = 0; 00503 if (pmaxy) *pmaxy = 0; 00504 if (!pta) 00505 return ERROR_INT("pta not defined", procName, 1); 00506 if ((n = ptaGetCount(pta)) == 0) 00507 return ERROR_INT("no points in pta", procName, 1); 00508 00509 ptaGetPt(pta, 0, &x, &y); 00510 minx = x; 00511 maxx = x; 00512 miny = y; 00513 maxy = y; 00514 for (i = 1; i < n; i++) { 00515 ptaGetPt(pta, i, &x, &y); 00516 if (x < minx) minx = x; 00517 if (x > maxx) maxx = x; 00518 if (y < miny) miny = y; 00519 if (y > maxy) maxy = y; 00520 } 00521 if (pminx) *pminx = minx; 00522 if (pmaxx) *pmaxx = maxx; 00523 if (pminy) *pminy = miny; 00524 if (pmaxy) *pmaxy = maxy; 00525 return 0; 00526 } 00527 00528 00529 /*! 00530 * ptaGetInsideBox() 00531 * 00532 * Input: ptas (input pts) 00533 * box 00534 * Return: ptad (of pts in ptas that are inside the box), or null on error 00535 */ 00536 PTA * 00537 ptaGetInsideBox(PTA *ptas, 00538 BOX *box) 00539 { 00540 PTA *ptad; 00541 l_int32 n, i, contains; 00542 l_float32 x, y; 00543 00544 PROCNAME("ptaGetInsideBox"); 00545 00546 if (!ptas) 00547 return (PTA *)ERROR_PTR("ptas not defined", procName, NULL); 00548 if (!box) 00549 return (PTA *)ERROR_PTR("box not defined", procName, NULL); 00550 00551 n = ptaGetCount(ptas); 00552 ptad = ptaCreate(0); 00553 for (i = 0; i < n; i++) { 00554 ptaGetPt(ptas, i, &x, &y); 00555 boxContainsPt(box, x, y, &contains); 00556 if (contains) 00557 ptaAddPt(ptad, x, y); 00558 } 00559 00560 return ptad; 00561 } 00562 00563 00564 /*! 00565 * pixFindCornerPixels() 00566 * 00567 * Input: pixs (1 bpp) 00568 * Return: pta, or null on error 00569 * 00570 * Notes: 00571 * (1) Finds the 4 corner-most pixels, as defined by a search 00572 * inward from each corner, using a 45 degree line. 00573 */ 00574 PTA * 00575 pixFindCornerPixels(PIX *pixs) 00576 { 00577 l_int32 i, j, x, y, w, h, wpl, mindim, found; 00578 l_uint32 *data, *line; 00579 PTA *pta; 00580 00581 PROCNAME("pixFindCornerPixels"); 00582 00583 if (!pixs) 00584 return (PTA *)ERROR_PTR("pixs not defined", procName, NULL); 00585 if (pixGetDepth(pixs) != 1) 00586 return (PTA *)ERROR_PTR("pixs not 1 bpp", procName, NULL); 00587 00588 w = pixGetWidth(pixs); 00589 h = pixGetHeight(pixs); 00590 mindim = L_MIN(w, h); 00591 data = pixGetData(pixs); 00592 wpl = pixGetWpl(pixs); 00593 00594 if ((pta = ptaCreate(4)) == NULL) 00595 return (PTA *)ERROR_PTR("pta not made", procName, NULL); 00596 00597 for (found = FALSE, i = 0; i < mindim; i++) { 00598 for (j = 0; j <= i; j++) { 00599 y = i - j; 00600 line = data + y * wpl; 00601 if (GET_DATA_BIT(line, j)) { 00602 ptaAddPt(pta, j, y); 00603 found = TRUE; 00604 break; 00605 } 00606 } 00607 if (found == TRUE) 00608 break; 00609 } 00610 00611 for (found = FALSE, i = 0; i < mindim; i++) { 00612 for (j = 0; j <= i; j++) { 00613 y = i - j; 00614 line = data + y * wpl; 00615 x = w - 1 - j; 00616 if (GET_DATA_BIT(line, x)) { 00617 ptaAddPt(pta, x, y); 00618 found = TRUE; 00619 break; 00620 } 00621 } 00622 if (found == TRUE) 00623 break; 00624 } 00625 00626 for (found = FALSE, i = 0; i < mindim; i++) { 00627 for (j = 0; j <= i; j++) { 00628 y = h - 1 - i + j; 00629 line = data + y * wpl; 00630 if (GET_DATA_BIT(line, j)) { 00631 ptaAddPt(pta, j, y); 00632 found = TRUE; 00633 break; 00634 } 00635 } 00636 if (found == TRUE) 00637 break; 00638 } 00639 00640 for (found = FALSE, i = 0; i < mindim; i++) { 00641 for (j = 0; j <= i; j++) { 00642 y = h - 1 - i + j; 00643 line = data + y * wpl; 00644 x = w - 1 - j; 00645 if (GET_DATA_BIT(line, x)) { 00646 ptaAddPt(pta, x, y); 00647 found = TRUE; 00648 break; 00649 } 00650 } 00651 if (found == TRUE) 00652 break; 00653 } 00654 00655 return pta; 00656 } 00657 00658 00659 /*! 00660 * ptaContainsPt() 00661 * 00662 * Input: pta 00663 * x, y (point) 00664 * Return: 1 if contained, 0 otherwise or on error 00665 */ 00666 l_int32 00667 ptaContainsPt(PTA *pta, 00668 l_int32 x, 00669 l_int32 y) 00670 { 00671 l_int32 i, n, ix, iy; 00672 00673 PROCNAME("ptaContainsPt"); 00674 00675 if (!pta) 00676 return ERROR_INT("pta not defined", procName, 0); 00677 00678 n = ptaGetCount(pta); 00679 for (i = 0; i < n; i++) { 00680 ptaGetIPt(pta, i, &ix, &iy); 00681 if (x == ix && y == iy) 00682 return 1; 00683 } 00684 return 0; 00685 } 00686 00687 00688 /*! 00689 * ptaTestIntersection() 00690 * 00691 * Input: pta1, pta2 00692 * Return: bval which is 1 if they have any elements in common; 00693 * 0 otherwise or on error. 00694 */ 00695 l_int32 00696 ptaTestIntersection(PTA *pta1, 00697 PTA *pta2) 00698 { 00699 l_int32 i, j, n1, n2, x1, y1, x2, y2; 00700 00701 PROCNAME("ptaTestIntersection"); 00702 00703 if (!pta1) 00704 return ERROR_INT("pta1 not defined", procName, 0); 00705 if (!pta2) 00706 return ERROR_INT("pta2 not defined", procName, 0); 00707 00708 n1 = ptaGetCount(pta1); 00709 n2 = ptaGetCount(pta2); 00710 for (i = 0; i < n1; i++) { 00711 ptaGetIPt(pta1, i, &x1, &y1); 00712 for (j = 0; j < n2; j++) { 00713 ptaGetIPt(pta2, i, &x2, &y2); 00714 if (x1 == x2 && y1 == y2) 00715 return 1; 00716 } 00717 } 00718 00719 return 0; 00720 } 00721 00722 00723 /*! 00724 * ptaTransform() 00725 * 00726 * Input: pta 00727 * shiftx, shifty 00728 * scalex, scaley 00729 * Return: pta, or null on error 00730 * 00731 * Notes: 00732 * (1) Shift first, then scale. 00733 */ 00734 PTA * 00735 ptaTransform(PTA *ptas, 00736 l_int32 shiftx, 00737 l_int32 shifty, 00738 l_float32 scalex, 00739 l_float32 scaley) 00740 { 00741 l_int32 n, i, x, y; 00742 PTA *ptad; 00743 00744 PROCNAME("ptaTransform"); 00745 00746 if (!ptas) 00747 return (PTA *)ERROR_PTR("ptas not defined", procName, NULL); 00748 n = ptaGetCount(ptas); 00749 ptad = ptaCreate(n); 00750 for (i = 0; i < n; i++) { 00751 ptaGetIPt(ptas, i, &x, &y); 00752 x = (l_int32)(scalex * (x + shiftx) + 0.5); 00753 y = (l_int32)(scaley * (y + shifty) + 0.5); 00754 ptaAddPt(ptad, x, y); 00755 } 00756 00757 return ptad; 00758 } 00759 00760 00761 00762 /*---------------------------------------------------------------------* 00763 * Least Squares Fit * 00764 *---------------------------------------------------------------------*/ 00765 /*! 00766 * ptaGetLinearLSF() 00767 * 00768 * Input: pta 00769 * &a (<optional return> slope a of least square fit: y = ax + b) 00770 * &b (<optional return> intercept b of least square fit) 00771 * &nafit (<optional return> numa of least square fit) 00772 * Return: 0 if OK, 1 on error 00773 * 00774 * Notes: 00775 * (1) At least one of: &a and &b must not be null. 00776 * (2) If both &a and &b are defined, this returns a and b that minimize: 00777 * 00778 * sum (yi - axi -b)^2 00779 * i 00780 * 00781 * The method is simple: differentiate this expression w/rt a and b, 00782 * and solve the resulting two equations for a and b in terms of 00783 * various sums over the input data (xi, yi). 00784 * (3) We also allow two special cases, where either a = 0 or b = 0: 00785 * (a) If &a is given and &b = null, find the linear LSF that 00786 * goes through the origin (b = 0). 00787 * (b) If &b is given and &a = null, find the linear LSF with 00788 * zero slope (a = 0). 00789 * (4) If @nafit is defined, this returns an array of fitted values, 00790 * corresponding to the two implicit Numa arrays (nax and nay) in pta. 00791 * Thus, just as you can plot the data in pta as nay vs. nax, 00792 * you can plot the linear least square fit as nafit vs. nax. 00793 */ 00794 l_int32 00795 ptaGetLinearLSF(PTA *pta, 00796 l_float32 *pa, 00797 l_float32 *pb, 00798 NUMA **pnafit) 00799 { 00800 l_int32 n, i; 00801 l_float32 factor, sx, sy, sxx, sxy, val; 00802 l_float32 *xa, *ya; 00803 00804 PROCNAME("ptaGetLinearLSF"); 00805 00806 if (!pa && !pb) 00807 return ERROR_INT("&a and/or &b not defined", procName, 1); 00808 if (pa) *pa = 0.0; 00809 if (pb) *pb = 0.0; 00810 if (pnafit) *pnafit = NULL; 00811 if (!pta) 00812 return ERROR_INT("pta not defined", procName, 1); 00813 00814 if ((n = ptaGetCount(pta)) < 2) 00815 return ERROR_INT("less than 2 pts not found", procName, 1); 00816 xa = pta->x; /* not a copy */ 00817 ya = pta->y; /* not a copy */ 00818 00819 sx = sy = sxx = sxy = 0.; 00820 if (pa && pb) { 00821 for (i = 0; i < n; i++) { 00822 sx += xa[i]; 00823 sy += ya[i]; 00824 sxx += xa[i] * xa[i]; 00825 sxy += xa[i] * ya[i]; 00826 } 00827 factor = n * sxx - sx * sx; 00828 if (factor == 0.0) 00829 return ERROR_INT("no solution found", procName, 1); 00830 factor = 1. / factor; 00831 00832 *pa = factor * ((l_float32)n * sxy - sx * sy); 00833 *pb = factor * (sxx * sy - sx * sxy); 00834 } 00835 else if (pa) { /* line through origin */ 00836 for (i = 0; i < n; i++) { 00837 sxx += xa[i] * xa[i]; 00838 sxy += xa[i] * ya[i]; 00839 } 00840 if (sxx == 0.0) 00841 return ERROR_INT("no solution found", procName, 1); 00842 *pa = sxy / sxx; 00843 } 00844 else { /* a = 0; horizontal line */ 00845 for (i = 0; i < n; i++) 00846 sy += ya[i]; 00847 *pb = sy / (l_float32)n; 00848 } 00849 00850 if (pnafit) { 00851 *pnafit = numaCreate(n); 00852 for (i = 0; i < n; i++) { 00853 val = (*pa) * xa[i] + *pb; 00854 numaAddNumber(*pnafit, val); 00855 } 00856 } 00857 00858 return 0; 00859 } 00860 00861 00862 /*! 00863 * ptaGetQuadraticLSF() 00864 * 00865 * Input: pta 00866 * &a (<optional return> coeff a of LSF: y = ax^2 + bx + c) 00867 * &b (<optional return> coeff b of LSF: y = ax^2 + bx + c) 00868 * &c (<optional return> coeff c of LSF: y = ax^2 + bx + c) 00869 * &nafit (<optional return> numa of least square fit) 00870 * Return: 0 if OK, 1 on error 00871 * 00872 * Notes: 00873 * (1) This does a quadratic least square fit to the set of points 00874 * in @pta. That is, it finds coefficients a, b and c that minimize: 00875 * 00876 * sum (yi - a*xi*xi -b*xi -c)^2 00877 * i 00878 * 00879 * The method is simple: differentiate this expression w/rt 00880 * a, b and c, and solve the resulting three equations for these 00881 * coefficients in terms of various sums over the input data (xi, yi). 00882 * The three equations are in the form: 00883 * f[0][0]a + f[0][1]b + f[0][2]c = g[0] 00884 * f[1][0]a + f[1][1]b + f[1][2]c = g[1] 00885 * f[2][0]a + f[2][1]b + f[2][2]c = g[2] 00886 * (2) If @nafit is defined, this returns an array of fitted values, 00887 * corresponding to the two implicit Numa arrays (nax and nay) in pta. 00888 * Thus, just as you can plot the data in pta as nay vs. nax, 00889 * you can plot the linear least square fit as nafit vs. nax. 00890 */ 00891 l_int32 00892 ptaGetQuadraticLSF(PTA *pta, 00893 l_float32 *pa, 00894 l_float32 *pb, 00895 l_float32 *pc, 00896 NUMA **pnafit) 00897 { 00898 l_int32 n, i, ret; 00899 l_float32 x, y, sx, sy, sx2, sx3, sx4, sxy, sx2y; 00900 l_float32 *xa, *ya; 00901 l_float32 *f[3]; 00902 l_float32 g[3]; 00903 NUMA *nafit; 00904 00905 PROCNAME("ptaGetQuadraticLSF"); 00906 00907 if (!pa && !pb && !pc && !pnafit) 00908 return ERROR_INT("no output requested", procName, 1); 00909 if (pa) *pa = 0.0; 00910 if (pb) *pb = 0.0; 00911 if (pc) *pc = 0.0; 00912 if (pnafit) *pnafit = NULL; 00913 if (!pta) 00914 return ERROR_INT("pta not defined", procName, 1); 00915 00916 if ((n = ptaGetCount(pta)) < 3) 00917 return ERROR_INT("less than 3 pts not found", procName, 1); 00918 xa = pta->x; /* not a copy */ 00919 ya = pta->y; /* not a copy */ 00920 00921 sx = sy = sx2 = sx3 = sx4 = sxy = sx2y = 0.; 00922 for (i = 0; i < n; i++) { 00923 x = xa[i]; 00924 y = ya[i]; 00925 sx += x; 00926 sy += y; 00927 sx2 += x * x; 00928 sx3 += x * x * x; 00929 sx4 += x * x * x * x; 00930 sxy += x * y; 00931 sx2y += x * x * y; 00932 } 00933 00934 for (i = 0; i < 3; i++) 00935 f[i] = (l_float32 *)CALLOC(3, sizeof(l_float32)); 00936 f[0][0] = sx4; 00937 f[0][1] = sx3; 00938 f[0][2] = sx2; 00939 f[1][0] = sx3; 00940 f[1][1] = sx2; 00941 f[1][2] = sx; 00942 f[2][0] = sx2; 00943 f[2][1] = sx; 00944 f[2][2] = n; 00945 g[0] = sx2y; 00946 g[1] = sxy; 00947 g[2] = sy; 00948 00949 /* Solve for the unknowns, also putting f-inverse into f */ 00950 ret = gaussjordan(f, g, 3); 00951 for (i = 0; i < 3; i++) 00952 FREE(f[i]); 00953 if (ret) 00954 return ERROR_INT("quadratic solution failed", procName, 1); 00955 00956 if (pa) *pa = g[0]; 00957 if (pb) *pb = g[1]; 00958 if (pc) *pc = g[2]; 00959 if (pnafit) { 00960 nafit = numaCreate(n); 00961 *pnafit = nafit; 00962 for (i = 0; i < n; i++) { 00963 x = xa[i]; 00964 y = g[0] * x * x + g[1] * x + g[2]; 00965 numaAddNumber(nafit, y); 00966 } 00967 } 00968 00969 return 0; 00970 } 00971 00972 00973 /*! 00974 * ptaGetCubicLSF() 00975 * 00976 * Input: pta 00977 * &a (<optional return> coeff a of LSF: y = ax^3 + bx^2 + cx + d) 00978 * &b (<optional return> coeff b of LSF) 00979 * &c (<optional return> coeff c of LSF) 00980 * &d (<optional return> coeff d of LSF) 00981 * &nafit (<optional return> numa of least square fit) 00982 * Return: 0 if OK, 1 on error 00983 * 00984 * Notes: 00985 * (1) This does a cubic least square fit to the set of points 00986 * in @pta. That is, it finds coefficients a, b, c and d 00987 * that minimize: 00988 * 00989 * sum (yi - a*xi*xi*xi -b*xi*xi -c*xi - d)^2 00990 * i 00991 * 00992 * Differentiate this expression w/rt a, b, c and d, and solve 00993 * the resulting four equations for these coefficients in 00994 * terms of various sums over the input data (xi, yi). 00995 * The four equations are in the form: 00996 * f[0][0]a + f[0][1]b + f[0][2]c + f[0][3] = g[0] 00997 * f[1][0]a + f[1][1]b + f[1][2]c + f[1][3] = g[1] 00998 * f[2][0]a + f[2][1]b + f[2][2]c + f[2][3] = g[2] 00999 * f[3][0]a + f[3][1]b + f[3][2]c + f[3][3] = g[3] 01000 * (2) If @nafit is defined, this returns an array of fitted values, 01001 * corresponding to the two implicit Numa arrays (nax and nay) in pta. 01002 * Thus, just as you can plot the data in pta as nay vs. nax, 01003 * you can plot the linear least square fit as nafit vs. nax. 01004 */ 01005 l_int32 01006 ptaGetCubicLSF(PTA *pta, 01007 l_float32 *pa, 01008 l_float32 *pb, 01009 l_float32 *pc, 01010 l_float32 *pd, 01011 NUMA **pnafit) 01012 { 01013 l_int32 n, i, ret; 01014 l_float32 x, y, sx, sy, sx2, sx3, sx4, sx5, sx6, sxy, sx2y, sx3y; 01015 l_float32 *xa, *ya; 01016 l_float32 *f[4]; 01017 l_float32 g[4]; 01018 NUMA *nafit; 01019 01020 PROCNAME("ptaGetCubicLSF"); 01021 01022 if (!pa && !pb && !pc && !pd && !pnafit) 01023 return ERROR_INT("no output requested", procName, 1); 01024 if (pa) *pa = 0.0; 01025 if (pb) *pb = 0.0; 01026 if (pc) *pc = 0.0; 01027 if (pd) *pd = 0.0; 01028 if (pnafit) *pnafit = NULL; 01029 if (!pta) 01030 return ERROR_INT("pta not defined", procName, 1); 01031 01032 if ((n = ptaGetCount(pta)) < 4) 01033 return ERROR_INT("less than 4 pts not found", procName, 1); 01034 xa = pta->x; /* not a copy */ 01035 ya = pta->y; /* not a copy */ 01036 01037 sx = sy = sx2 = sx3 = sx4 = sx5 = sx6 = sxy = sx2y = sx3y = 0.; 01038 for (i = 0; i < n; i++) { 01039 x = xa[i]; 01040 y = ya[i]; 01041 sx += x; 01042 sy += y; 01043 sx2 += x * x; 01044 sx3 += x * x * x; 01045 sx4 += x * x * x * x; 01046 sx5 += x * x * x * x * x; 01047 sx6 += x * x * x * x * x * x; 01048 sxy += x * y; 01049 sx2y += x * x * y; 01050 sx3y += x * x * x * y; 01051 } 01052 01053 for (i = 0; i < 4; i++) 01054 f[i] = (l_float32 *)CALLOC(4, sizeof(l_float32)); 01055 f[0][0] = sx6; 01056 f[0][1] = sx5; 01057 f[0][2] = sx4; 01058 f[0][3] = sx3; 01059 f[1][0] = sx5; 01060 f[1][1] = sx4; 01061 f[1][2] = sx3; 01062 f[1][3] = sx2; 01063 f[2][0] = sx4; 01064 f[2][1] = sx3; 01065 f[2][2] = sx2; 01066 f[2][3] = sx; 01067 f[3][0] = sx3; 01068 f[3][1] = sx2; 01069 f[3][2] = sx; 01070 f[3][3] = n; 01071 g[0] = sx3y; 01072 g[1] = sx2y; 01073 g[2] = sxy; 01074 g[3] = sy; 01075 01076 /* Solve for the unknowns, also putting f-inverse into f */ 01077 ret = gaussjordan(f, g, 4); 01078 for (i = 0; i < 4; i++) 01079 FREE(f[i]); 01080 if (ret) 01081 return ERROR_INT("cubic solution failed", procName, 1); 01082 01083 if (pa) *pa = g[0]; 01084 if (pb) *pb = g[1]; 01085 if (pc) *pc = g[2]; 01086 if (pd) *pd = g[3]; 01087 if (pnafit) { 01088 nafit = numaCreate(n); 01089 *pnafit = nafit; 01090 for (i = 0; i < n; i++) { 01091 x = xa[i]; 01092 y = g[0] * x * x * x + g[1] * x * x + g[2] * x + g[3]; 01093 numaAddNumber(nafit, y); 01094 } 01095 } 01096 01097 return 0; 01098 } 01099 01100 01101 /*! 01102 * ptaGetQuarticLSF() 01103 * 01104 * Input: pta 01105 * &a (<optional return> coeff a of LSF: 01106 * y = ax^4 + bx^3 + cx^2 + dx + e) 01107 * &b (<optional return> coeff b of LSF) 01108 * &c (<optional return> coeff c of LSF) 01109 * &d (<optional return> coeff d of LSF) 01110 * &e (<optional return> coeff e of LSF) 01111 * &nafit (<optional return> numa of least square fit) 01112 * Return: 0 if OK, 1 on error 01113 * 01114 * Notes: 01115 * (1) This does a quartic least square fit to the set of points 01116 * in @pta. That is, it finds coefficients a, b, c, d and 3 01117 * that minimize: 01118 * 01119 * sum (yi - a*xi*xi*xi*xi -b*xi*xi*xi -c*xi*xi - d*xi - e)^2 01120 * i 01121 * 01122 * Differentiate this expression w/rt a, b, c, d and e, and solve 01123 * the resulting five equations for these coefficients in 01124 * terms of various sums over the input data (xi, yi). 01125 * The five equations are in the form: 01126 * f[0][0]a + f[0][1]b + f[0][2]c + f[0][3] + f[0][4] = g[0] 01127 * f[1][0]a + f[1][1]b + f[1][2]c + f[1][3] + f[1][4] = g[1] 01128 * f[2][0]a + f[2][1]b + f[2][2]c + f[2][3] + f[2][4] = g[2] 01129 * f[3][0]a + f[3][1]b + f[3][2]c + f[3][3] + f[3][4] = g[3] 01130 * f[4][0]a + f[4][1]b + f[4][2]c + f[4][3] + f[4][4] = g[4] 01131 * (2) If @nafit is defined, this returns an array of fitted values, 01132 * corresponding to the two implicit Numa arrays (nax and nay) in pta. 01133 * Thus, just as you can plot the data in pta as nay vs. nax, 01134 * you can plot the linear least square fit as nafit vs. nax. 01135 */ 01136 l_int32 01137 ptaGetQuarticLSF(PTA *pta, 01138 l_float32 *pa, 01139 l_float32 *pb, 01140 l_float32 *pc, 01141 l_float32 *pd, 01142 l_float32 *pe, 01143 NUMA **pnafit) 01144 { 01145 l_int32 n, i, ret; 01146 l_float32 x, y, sx, sy, sx2, sx3, sx4, sx5, sx6, sx7, sx8; 01147 l_float32 sxy, sx2y, sx3y, sx4y; 01148 l_float32 *xa, *ya; 01149 l_float32 *f[5]; 01150 l_float32 g[5]; 01151 NUMA *nafit; 01152 01153 PROCNAME("ptaGetQuarticLSF"); 01154 01155 if (!pa && !pb && !pc && !pd && !pe && !pnafit) 01156 return ERROR_INT("no output requested", procName, 1); 01157 if (pa) *pa = 0.0; 01158 if (pb) *pb = 0.0; 01159 if (pc) *pc = 0.0; 01160 if (pd) *pd = 0.0; 01161 if (pe) *pe = 0.0; 01162 if (pnafit) *pnafit = NULL; 01163 if (!pta) 01164 return ERROR_INT("pta not defined", procName, 1); 01165 01166 if ((n = ptaGetCount(pta)) < 5) 01167 return ERROR_INT("less than 5 pts not found", procName, 1); 01168 xa = pta->x; /* not a copy */ 01169 ya = pta->y; /* not a copy */ 01170 01171 sx = sy = sx2 = sx3 = sx4 = sx5 = sx6 = sx7 = sx8 = 0; 01172 sxy = sx2y = sx3y = sx4y = 0.; 01173 for (i = 0; i < n; i++) { 01174 x = xa[i]; 01175 y = ya[i]; 01176 sx += x; 01177 sy += y; 01178 sx2 += x * x; 01179 sx3 += x * x * x; 01180 sx4 += x * x * x * x; 01181 sx5 += x * x * x * x * x; 01182 sx6 += x * x * x * x * x * x; 01183 sx7 += x * x * x * x * x * x * x; 01184 sx8 += x * x * x * x * x * x * x * x; 01185 sxy += x * y; 01186 sx2y += x * x * y; 01187 sx3y += x * x * x * y; 01188 sx4y += x * x * x * x * y; 01189 } 01190 01191 for (i = 0; i < 5; i++) 01192 f[i] = (l_float32 *)CALLOC(5, sizeof(l_float32)); 01193 f[0][0] = sx8; 01194 f[0][1] = sx7; 01195 f[0][2] = sx6; 01196 f[0][3] = sx5; 01197 f[0][4] = sx4; 01198 f[1][0] = sx7; 01199 f[1][1] = sx6; 01200 f[1][2] = sx5; 01201 f[1][3] = sx4; 01202 f[1][4] = sx3; 01203 f[2][0] = sx6; 01204 f[2][1] = sx5; 01205 f[2][2] = sx4; 01206 f[2][3] = sx3; 01207 f[2][4] = sx2; 01208 f[3][0] = sx5; 01209 f[3][1] = sx4; 01210 f[3][2] = sx3; 01211 f[3][3] = sx2; 01212 f[3][4] = sx; 01213 f[4][0] = sx4; 01214 f[4][1] = sx3; 01215 f[4][2] = sx2; 01216 f[4][3] = sx; 01217 f[4][4] = n; 01218 g[0] = sx4y; 01219 g[1] = sx3y; 01220 g[2] = sx2y; 01221 g[3] = sxy; 01222 g[4] = sy; 01223 01224 /* Solve for the unknowns, also putting f-inverse into f */ 01225 ret = gaussjordan(f, g, 5); 01226 for (i = 0; i < 5; i++) 01227 FREE(f[i]); 01228 if (ret) 01229 return ERROR_INT("quartic solution failed", procName, 1); 01230 01231 if (pa) *pa = g[0]; 01232 if (pb) *pb = g[1]; 01233 if (pc) *pc = g[2]; 01234 if (pd) *pd = g[3]; 01235 if (pe) *pe = g[4]; 01236 if (pnafit) { 01237 nafit = numaCreate(n); 01238 *pnafit = nafit; 01239 for (i = 0; i < n; i++) { 01240 x = xa[i]; 01241 y = g[0] * x * x * x * x + g[1] * x * x * x + g[2] * x * x 01242 + g[3] * x + g[4]; 01243 numaAddNumber(nafit, y); 01244 } 01245 } 01246 01247 return 0; 01248 } 01249 01250 01251 /*! 01252 * applyLinearFit() 01253 * 01254 * Input: a, b (linear fit coefficients) 01255 * x 01256 * &y (<return> y = a * x + b) 01257 * Return: 0 if OK, 1 on error 01258 */ 01259 l_int32 01260 applyLinearFit(l_float32 a, 01261 l_float32 b, 01262 l_float32 x, 01263 l_float32 *py) 01264 { 01265 PROCNAME("applyLinearFit"); 01266 01267 if (!py) 01268 return ERROR_INT("&y not defined", procName, 1); 01269 01270 *py = a * x + b; 01271 return 0; 01272 } 01273 01274 01275 /*! 01276 * applyQuadraticFit() 01277 * 01278 * Input: a, b, c (quadratic fit coefficients) 01279 * x 01280 * &y (<return> y = a * x^2 + b * x + c) 01281 * Return: 0 if OK, 1 on error 01282 */ 01283 l_int32 01284 applyQuadraticFit(l_float32 a, 01285 l_float32 b, 01286 l_float32 c, 01287 l_float32 x, 01288 l_float32 *py) 01289 { 01290 PROCNAME("applyQuadraticFit"); 01291 01292 if (!py) 01293 return ERROR_INT("&y not defined", procName, 1); 01294 01295 *py = a * x * x + b * x + c; 01296 return 0; 01297 } 01298 01299 01300 /*! 01301 * applyCubicFit() 01302 * 01303 * Input: a, b, c, d (cubic fit coefficients) 01304 * x 01305 * &y (<return> y = a * x^3 + b * x^2 + c * x + d) 01306 * Return: 0 if OK, 1 on error 01307 */ 01308 l_int32 01309 applyCubicFit(l_float32 a, 01310 l_float32 b, 01311 l_float32 c, 01312 l_float32 d, 01313 l_float32 x, 01314 l_float32 *py) 01315 { 01316 PROCNAME("applyCubicFit"); 01317 01318 if (!py) 01319 return ERROR_INT("&y not defined", procName, 1); 01320 01321 *py = a * x * x * x + b * x * x + c * x + d; 01322 return 0; 01323 } 01324 01325 01326 /*! 01327 * applyQuarticFit() 01328 * 01329 * Input: a, b, c, d, e (quartic fit coefficients) 01330 * x 01331 * &y (<return> y = a * x^4 + b * x^3 + c * x^2 + d * x + e) 01332 * Return: 0 if OK, 1 on error 01333 */ 01334 l_int32 01335 applyQuarticFit(l_float32 a, 01336 l_float32 b, 01337 l_float32 c, 01338 l_float32 d, 01339 l_float32 e, 01340 l_float32 x, 01341 l_float32 *py) 01342 { 01343 l_float32 x2; 01344 01345 PROCNAME("applyQuarticFit"); 01346 01347 if (!py) 01348 return ERROR_INT("&y not defined", procName, 1); 01349 01350 x2 = x * x; 01351 *py = a * x2 * x2 + b * x2 * x + c * x2 + d * x + e; 01352 return 0; 01353 } 01354 01355 01356 /*---------------------------------------------------------------------* 01357 * Interconversions with Pix * 01358 *---------------------------------------------------------------------*/ 01359 /*! 01360 * pixPlotAlongPta() 01361 * 01362 * Input: pixs (any depth) 01363 * pta (set of points on which to plot) 01364 * outformat (GPLOT_PNG, GPLOT_PS, GPLOT_EPS, GPLOT_X11, 01365 * GPLOT_LATEX) 01366 * title (<optional> for plot; can be null) 01367 * Return: 0 if OK, 1 on error 01368 * 01369 * Notes: 01370 * (1) We remove any existing colormap and clip the pta to the input pixs. 01371 * (2) This is a debugging function, and does not remove temporary 01372 * plotting files that it generates. 01373 * (3) If the image is RGB, three separate plots are generated. 01374 */ 01375 l_int32 01376 pixPlotAlongPta(PIX *pixs, 01377 PTA *pta, 01378 l_int32 outformat, 01379 const char *title) 01380 { 01381 char buffer[128]; 01382 char *rtitle, *gtitle, *btitle; 01383 static l_int32 count = 0; /* require separate temp files for each call */ 01384 l_int32 i, x, y, d, w, h, npts, rval, gval, bval; 01385 l_uint32 val; 01386 NUMA *na, *nar, *nag, *nab; 01387 PIX *pixt; 01388 01389 PROCNAME("pixPlotAlongPta"); 01390 01391 if (!pixs) 01392 return ERROR_INT("pixs not defined", procName, 1); 01393 if (!pta) 01394 return ERROR_INT("pta not defined", procName, 1); 01395 if (outformat != GPLOT_PNG && outformat != GPLOT_PS && 01396 outformat != GPLOT_EPS && outformat != GPLOT_X11 && 01397 outformat != GPLOT_LATEX) { 01398 L_WARNING("outformat invalid; using GPLOT_PNG", procName); 01399 outformat = GPLOT_PNG; 01400 } 01401 01402 pixt = pixRemoveColormap(pixs, REMOVE_CMAP_BASED_ON_SRC); 01403 d = pixGetDepth(pixt); 01404 w = pixGetWidth(pixt); 01405 h = pixGetHeight(pixt); 01406 npts = ptaGetCount(pta); 01407 if (d == 32) { 01408 nar = numaCreate(npts); 01409 nag = numaCreate(npts); 01410 nab = numaCreate(npts); 01411 for (i = 0; i < npts; i++) { 01412 ptaGetIPt(pta, i, &x, &y); 01413 if (x < 0 || x >= w) 01414 continue; 01415 if (y < 0 || y >= h) 01416 continue; 01417 pixGetPixel(pixt, x, y, &val); 01418 rval = GET_DATA_BYTE(&val, COLOR_RED); 01419 gval = GET_DATA_BYTE(&val, COLOR_GREEN); 01420 bval = GET_DATA_BYTE(&val, COLOR_BLUE); 01421 numaAddNumber(nar, rval); 01422 numaAddNumber(nag, gval); 01423 numaAddNumber(nab, bval); 01424 } 01425 01426 sprintf(buffer, "/tmp/junkplot.%d", count++); 01427 rtitle = stringJoin("Red: ", title); 01428 gplotSimple1(nar, outformat, buffer, rtitle); 01429 sprintf(buffer, "/tmp/junkplot.%d", count++); 01430 gtitle = stringJoin("Green: ", title); 01431 gplotSimple1(nag, outformat, buffer, gtitle); 01432 sprintf(buffer, "/tmp/junkplot.%d", count++); 01433 btitle = stringJoin("Blue: ", title); 01434 gplotSimple1(nab, outformat, buffer, btitle); 01435 numaDestroy(&nar); 01436 numaDestroy(&nag); 01437 numaDestroy(&nab); 01438 FREE(rtitle); 01439 FREE(gtitle); 01440 FREE(btitle); 01441 } 01442 else { 01443 na = numaCreate(npts); 01444 for (i = 0; i < npts; i++) { 01445 ptaGetIPt(pta, i, &x, &y); 01446 if (x < 0 || x >= w) 01447 continue; 01448 if (y < 0 || y >= h) 01449 continue; 01450 pixGetPixel(pixt, x, y, &val); 01451 numaAddNumber(na, (l_float32)val); 01452 } 01453 01454 sprintf(buffer, "/tmp/junkplot.%d", count++); 01455 gplotSimple1(na, outformat, buffer, title); 01456 numaDestroy(&na); 01457 } 01458 pixDestroy(&pixt); 01459 return 0; 01460 } 01461 01462 01463 /*! 01464 * ptaGetPixelsFromPix() 01465 * 01466 * Input: pixs (1 bpp) 01467 * box (<optional> can be null) 01468 * Return: pta, or null on error 01469 * 01470 * Notes: 01471 * (1) Generates a pta of fg pixels in the pix, within the box. 01472 * If box == NULL, it uses the entire pix. 01473 */ 01474 PTA * 01475 ptaGetPixelsFromPix(PIX *pixs, 01476 BOX *box) 01477 { 01478 l_int32 i, j, w, h, wpl, xstart, xend, ystart, yend, bw, bh; 01479 l_uint32 *data, *line; 01480 PTA *pta; 01481 01482 PROCNAME("ptaGetPixelsFromPix"); 01483 01484 if (!pixs || (pixGetDepth(pixs) != 1)) 01485 return (PTA *)ERROR_PTR("pixs undefined or not 1 bpp", procName, NULL); 01486 01487 pixGetDimensions(pixs, &w, &h, NULL); 01488 data = pixGetData(pixs); 01489 wpl = pixGetWpl(pixs); 01490 xstart = ystart = 0; 01491 xend = w - 1; 01492 yend = h - 1; 01493 if (box) { 01494 boxGetGeometry(box, &xstart, &ystart, &bw, &bh); 01495 xend = xstart + bw - 1; 01496 yend = ystart + bh - 1; 01497 } 01498 01499 if ((pta = ptaCreate(0)) == NULL) 01500 return (PTA *)ERROR_PTR("pta not made", procName, NULL); 01501 for (i = ystart; i <= yend; i++) { 01502 line = data + i * wpl; 01503 for (j = xstart; j <= xend; j++) { 01504 if (GET_DATA_BIT(line, j)) 01505 ptaAddPt(pta, j, i); 01506 } 01507 } 01508 01509 return pta; 01510 } 01511 01512 01513 /*! 01514 * pixGenerateFromPta() 01515 * 01516 * Input: pta 01517 * w, h (of pix) 01518 * Return: pix (1 bpp), or null on error 01519 * 01520 * Notes: 01521 * (1) Points are rounded to nearest ints. 01522 * (2) Any points outside (w,h) are silently discarded. 01523 * (3) Output 1 bpp pix has values 1 for each point in the pta. 01524 */ 01525 PIX * 01526 pixGenerateFromPta(PTA *pta, 01527 l_int32 w, 01528 l_int32 h) 01529 { 01530 l_int32 n, i, x, y; 01531 PIX *pix; 01532 01533 PROCNAME("pixGenerateFromPta"); 01534 01535 if (!pta) 01536 return (PIX *)ERROR_PTR("pta not defined", procName, NULL); 01537 01538 if ((pix = pixCreate(w, h, 1)) == NULL) 01539 return (PIX *)ERROR_PTR("pix not made", procName, NULL); 01540 n = ptaGetCount(pta); 01541 for (i = 0; i < n; i++) { 01542 ptaGetIPt(pta, i, &x, &y); 01543 if (x < 0 || x >= w || y < 0 || y >= h) 01544 continue; 01545 pixSetPixel(pix, x, y, 1); 01546 } 01547 01548 return pix; 01549 } 01550 01551 01552 /*! 01553 * ptaGetBoundaryPixels() 01554 * 01555 * Input: pixs (1 bpp) 01556 * type (L_BOUNDARY_FG, L_BOUNDARY_BG) 01557 * Return: pta, or null on error 01558 * 01559 * Notes: 01560 * (1) This generates a pta of either fg or bg boundary pixels. 01561 */ 01562 PTA * 01563 ptaGetBoundaryPixels(PIX *pixs, 01564 l_int32 type) 01565 { 01566 PIX *pixt; 01567 PTA *pta; 01568 01569 PROCNAME("ptaGetBoundaryPixels"); 01570 01571 if (!pixs || (pixGetDepth(pixs) != 1)) 01572 return (PTA *)ERROR_PTR("pixs undefined or not 1 bpp", procName, NULL); 01573 if (type != L_BOUNDARY_FG && type != L_BOUNDARY_BG) 01574 return (PTA *)ERROR_PTR("invalid type", procName, NULL); 01575 01576 if (type == L_BOUNDARY_FG) 01577 pixt = pixMorphSequence(pixs, "e3.3", 0); 01578 else 01579 pixt = pixMorphSequence(pixs, "d3.3", 0); 01580 pixXor(pixt, pixt, pixs); 01581 pta = ptaGetPixelsFromPix(pixt, NULL); 01582 01583 pixDestroy(&pixt); 01584 return pta; 01585 } 01586 01587 01588 /*! 01589 * ptaaGetBoundaryPixels() 01590 * 01591 * Input: pixs (1 bpp) 01592 * type (L_BOUNDARY_FG, L_BOUNDARY_BG) 01593 * connectivity (4 or 8) 01594 * &boxa (<optional return> bounding boxes of the c.c.) 01595 * &pixa (<optional return> pixa of the c.c.) 01596 * Return: ptaa, or null on error 01597 * 01598 * Notes: 01599 * (1) This generates a ptaa of either fg or bg boundary pixels, 01600 * where each pta has the boundary pixels for a connected 01601 * component. 01602 * (2) We can't simply find all the boundary pixels and then select 01603 * those within the bounding box of each component, because 01604 * bounding boxes can overlap. It is necessary to extract and 01605 * dilate or erode each component separately. Note also that 01606 * special handling is required for bg pixels when the 01607 * component touches the pix boundary. 01608 */ 01609 PTAA * 01610 ptaaGetBoundaryPixels(PIX *pixs, 01611 l_int32 type, 01612 l_int32 connectivity, 01613 BOXA **pboxa, 01614 PIXA **ppixa) 01615 { 01616 l_int32 i, n, w, h, x, y, bw, bh, left, right, top, bot; 01617 BOXA *boxa; 01618 PIX *pixt1, *pixt2; 01619 PIXA *pixa; 01620 PTA *pta1, *pta2; 01621 PTAA *ptaa; 01622 01623 PROCNAME("ptaaGetBoundaryPixels"); 01624 01625 if (pboxa) *pboxa = NULL; 01626 if (ppixa) *ppixa = NULL; 01627 if (!pixs || (pixGetDepth(pixs) != 1)) 01628 return (PTAA *)ERROR_PTR("pixs undefined or not 1 bpp", procName, NULL); 01629 if (type != L_BOUNDARY_FG && type != L_BOUNDARY_BG) 01630 return (PTAA *)ERROR_PTR("invalid type", procName, NULL); 01631 if (connectivity != 4 && connectivity != 8) 01632 return (PTAA *)ERROR_PTR("connectivity not 4 or 8", procName, NULL); 01633 01634 pixGetDimensions(pixs, &w, &h, NULL); 01635 boxa = pixConnComp(pixs, &pixa, connectivity); 01636 n = boxaGetCount(boxa); 01637 ptaa = ptaaCreate(0); 01638 for (i = 0; i < n; i++) { 01639 pixt1 = pixaGetPix(pixa, i, L_CLONE); 01640 boxaGetBoxGeometry(boxa, i, &x, &y, &bw, &bh); 01641 left = right = top = bot = 0; 01642 if (type == L_BOUNDARY_BG) { 01643 if (x > 0) left = 1; 01644 if (y > 0) top = 1; 01645 if (x + bw < w) right = 1; 01646 if (y + bh < h) bot = 1; 01647 pixt2 = pixAddBorderGeneral(pixt1, left, right, top, bot, 0); 01648 } 01649 else 01650 pixt2 = pixClone(pixt1); 01651 pta1 = ptaGetBoundaryPixels(pixt2, type); 01652 pta2 = ptaTransform(pta1, x - left, y - top, 1.0, 1.0); 01653 ptaaAddPta(ptaa, pta2, L_INSERT); 01654 ptaDestroy(&pta1); 01655 pixDestroy(&pixt1); 01656 pixDestroy(&pixt2); 01657 } 01658 01659 if (pboxa) 01660 *pboxa = boxa; 01661 else 01662 boxaDestroy(&boxa); 01663 if (ppixa) 01664 *ppixa = pixa; 01665 else 01666 pixaDestroy(&pixa); 01667 return ptaa; 01668 } 01669 01670 01671 /*---------------------------------------------------------------------* 01672 * Display Pta and Ptaa * 01673 *---------------------------------------------------------------------*/ 01674 /*! 01675 * pixDisplayPta() 01676 * 01677 * Input: pixd (can be same as pixs or null; 32 bpp if in-place) 01678 * pixs (1, 2, 4, 8, 16 or 32 bpp) 01679 * pta (of path to be plotted) 01680 * Return: pixd (32 bpp RGB version of pixs, with path in green), 01681 * or null on error 01682 * 01683 * Notes: 01684 * (1) To write on an existing pixs, pixs must be 32 bpp and 01685 * call with pixd == pixs: 01686 * pixDisplayPta(pixs, pixs, pta); 01687 * To write on a new pix, set pixd == NULL and call: 01688 * pixd = pixDisplayPta(NULL, pixs, pta); 01689 */ 01690 PIX * 01691 pixDisplayPta(PIX *pixd, 01692 PIX *pixs, 01693 PTA *pta) 01694 { 01695 l_int32 i, n, x, y; 01696 l_uint32 rpixel, gpixel, bpixel; 01697 01698 PROCNAME("pixDisplayPta"); 01699 01700 if (!pixs) 01701 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL); 01702 if (!pta) 01703 return (PIX *)ERROR_PTR("pta not defined", procName, NULL); 01704 if (pixd && (pixd != pixs || pixGetDepth(pixd) != 32)) 01705 return (PIX *)ERROR_PTR("invalid pixd", procName, NULL); 01706 01707 if (!pixd) 01708 pixd = pixConvertTo32(pixs); 01709 composeRGBPixel(255, 0, 0, &rpixel); /* start point */ 01710 composeRGBPixel(0, 255, 0, &gpixel); 01711 composeRGBPixel(0, 0, 255, &bpixel); /* end point */ 01712 01713 n = ptaGetCount(pta); 01714 for (i = 0; i < n; i++) { 01715 ptaGetIPt(pta, i, &x, &y); 01716 if (i == 0) 01717 pixSetPixel(pixd, x, y, rpixel); 01718 else if (i < n - 1) 01719 pixSetPixel(pixd, x, y, gpixel); 01720 else 01721 pixSetPixel(pixd, x, y, bpixel); 01722 } 01723 01724 return pixd; 01725 } 01726 01727 01728 /*! 01729 * pixDisplayPtaa() 01730 * 01731 * Input: pixs (1, 2, 4, 8, 16 or 32 bpp) 01732 * ptaa (array of paths to be plotted) 01733 * Return: pixd (32 bpp RGB version of pixs, with paths plotted 01734 * in different colors), or null on error 01735 */ 01736 PIX * 01737 pixDisplayPtaa(PIX *pixs, 01738 PTAA *ptaa) 01739 { 01740 l_int32 i, j, npta, npt, x, y, rv, gv, bv; 01741 l_uint32 *pixela; 01742 NUMA *na1, *na2, *na3; 01743 PIX *pixd; 01744 PTA *pta; 01745 01746 PROCNAME("pixDisplayPtaa"); 01747 01748 if (!pixs) 01749 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL); 01750 if (!ptaa) 01751 return (PIX *)ERROR_PTR("ptaa not defined", procName, NULL); 01752 npta = ptaaGetCount(ptaa); 01753 if (npta == 0) 01754 return (PIX *)ERROR_PTR("no pta", procName, NULL); 01755 01756 if ((pixd = pixConvertTo32(pixs)) == NULL) 01757 return (PIX *)ERROR_PTR("pixd not made", procName, NULL); 01758 01759 /* Make a colormap for the paths */ 01760 if ((pixela = (l_uint32 *)CALLOC(npta, sizeof(l_uint32))) == NULL) 01761 return (PIX *)ERROR_PTR("calloc fail for pixela", procName, NULL); 01762 na1 = numaPseudorandomSequence(256, 14657); 01763 na2 = numaPseudorandomSequence(256, 34631); 01764 na3 = numaPseudorandomSequence(256, 54617); 01765 for (i = 0; i < npta; i++) { 01766 numaGetIValue(na1, i % 256, &rv); 01767 numaGetIValue(na2, i % 256, &gv); 01768 numaGetIValue(na3, i % 256, &bv); 01769 composeRGBPixel(rv, gv, bv, &pixela[i]); 01770 } 01771 numaDestroy(&na1); 01772 numaDestroy(&na2); 01773 numaDestroy(&na3); 01774 01775 for (i = 0; i < npta; i++) { 01776 pta = ptaaGetPta(ptaa, i, L_CLONE); 01777 npt = ptaGetCount(pta); 01778 for (j = 0; j < npt; j++) { 01779 ptaGetIPt(pta, j, &x, &y); 01780 pixSetPixel(pixd, x, y, pixela[i]); 01781 } 01782 ptaDestroy(&pta); 01783 } 01784 01785 FREE(pixela); 01786 return pixd; 01787 } 01788 01789