Leptonica 1.68
C Image Processing Library

ptafunc1.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 /*
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 
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines