IPP Software Navigation Tools IPP Links Communication Pan-STARRS Links

Ignore:
Timestamp:
Jan 12, 2015, 12:35:53 PM (12 years ago)
Author:
eugene
Message:

merge changes from trunk

File:
1 edited

Legend:

Unmodified
Added
Removed
  • branches/eam_branches/ipp-pv3-20140717-merge/psLib/src/imageops/psImageMapFit.c

    r34153 r37827  
    1818
    1919#include <stdio.h>
     20#include <stdlib.h>
    2021#include "psError.h"
    2122#include "psAbort.h"
     
    3536#include "psImageStructManip.h"
    3637#include "psImageMap.h"
     38#include "psSparse.h"
    3739// #include "psImagePixelInterpolate.h"
    3840// #include "psImageUnbin.h"
     
    118120    psImageInit (A, 0.0);
    119121    psVectorInit (B, 0.0);
    120 
     122   
    121123    // we are looping over the Nx,Ny image map elements;
    122124    // the matrix equation contains Nx*Ny rows and columns
     
    262264            int I = n + Nx * m;
    263265            B->data.F32[I] = fi_rx_ry + fi_rx_py + fi_px_ry + fi_px_py;
    264 
     266           
    265267            // insert these values into their corresponding locations in A, B
    266268            // float Sum = 0.0;
     
    273275                    int J = (n + jn) + Nx * (m + jm);
    274276                    A->data.F32[J][I] = sA[jn][jm];
     277                   
    275278                    // fprintf (stderr, "A %d %d (%d %d : %d %d): %f\n", I, J, n, m, n + jn, m + jm, sA[jn][jm]);
    276279                    // Sum += sA[jn][jm];
     
    282285    }
    283286    // fprintf (stderr, "Total: %f\n", Total);
     287
     288    double MaxPivot = 0.0;
     289    for (int i = 0; i < Nx*Ny; i++) {
     290      MaxPivot = PS_MAX(MaxPivot, fabs(A->data.F32[i][i]));
     291      // fprintf (stderr, "piv, max: %f : %f\n", A->data.F32[i][i], MaxPivot);
     292    }
    284293
    285294    // test for empty diagonal elements (unconstained cells), mark, and set pivots to 1.0
    286295    psVector *Empty = psVectorAlloc (Nx*Ny, PS_TYPE_S8);
    287296    psVectorInit (Empty, 0);
     297    double MinPivot = 0.025*MaxPivot;
    288298    for (int i = 0; i < Nx*Ny; i++) {
    289         if (A->data.F32[i][i] == 0.0) {
     299      if (fabs(A->data.F32[i][i]) < MinPivot) {
    290300            Empty->data.S8[i] = 1;
    291301            for (int j = 0; j < Nx*Ny; j++) {
     
    320330        return true;
    321331    }
    322 
     332   
    323333    // set bad values to NaN
    324334    for (int i = 0; i < Nx*Ny; i++) {
     
    341351    psFree (B);
    342352    psFree (Empty);
    343 
    344353    *pGoodFit = true;
    345354    return true;
     
    402411        psS32 Nkeep = 0;
    403412        if (!psImageMapFit(pGoodFit, map, mask, maskValue, x, y, f, df)) {
     413            psError(PS_ERR_UNKNOWN, false, "Could not fit image map.\n");
     414            psFree(resid);
     415            if (!inMask) psFree (mask);
     416            return false;
     417        }
     418        if (!*pGoodFit) {
     419            psWarning ("bad fit to image map, try something else");
     420            psFree(resid);
     421            if (!inMask) psFree (mask);
     422            return true;
     423        }
     424
     425        psVector *fit = psImageMapEvalVector(map, mask, maskValue, x, y);
     426        if (fit == NULL) {
     427            psError(PS_ERR_UNKNOWN, false, "Failure in psImageMapEvalVector().\n");
     428            psFree(resid);
     429            if (!inMask) psFree (mask);
     430            return false;
     431        }
     432        for (int i = 0 ; i < f->n ; i++) {
     433            resid->data.F32[i] = (f->data.F32[i] - fit->data.F32[i]);
     434        }
     435
     436        if (!psVectorStats(stats, resid, NULL, mask, maskValue)) {
     437            psError(PS_ERR_UNKNOWN, false, "Failure to compute statistics on the resid vector.\n");
     438            psFree(resid);
     439            psFree(fit);
     440            if (!inMask) psFree (mask);
     441            return false;
     442        }
     443
     444        double meanValue = psStatsGetValue (stats, meanOption);
     445        double stdevValue = psStatsGetValue (stats, stdevOption);
     446
     447        psTrace("psLib.imageops", 5, "Mean is %f\n", meanValue);
     448        psTrace("psLib.imageops", 5, "Stdev is %f\n", stdevValue);
     449        psF32 minClipValue = -minClipSigma*stdevValue;
     450        psF32 maxClipValue = +maxClipSigma*stdevValue;
     451
     452        // set mask if pts are not valid
     453        // we are masking out any point which is out of range
     454        // recovery is not allowed with this scheme
     455        for (psS32 i = 0; i < resid->n; i++) {
     456            // XXX this prevents recovery of previously masked values
     457            if (mask->data.PS_TYPE_VECTOR_MASK_DATA[i] & maskValue) {
     458                continue;
     459            }
     460
     461            if ((resid->data.F32[i] - meanValue > maxClipValue) || (resid->data.F32[i] - meanValue < minClipValue)) {
     462                psTrace("psLib.imageops", 6, "Masking element %d  : %f vs %f : resid is %f\n", i, f->data.F32[i], fit->data.F32[i], resid->data.F32[i]);
     463                mask->data.PS_TYPE_VECTOR_MASK_DATA[i] |= 0x01;
     464                continue;
     465            }
     466            Nkeep++;
     467        }
     468
     469        // We should probably exit this loop if no new elements were masked since the fit won't
     470        // change.
     471        psTrace("psLib.imageops", 6, "keeping %d of %ld pts for fit\n", Nkeep, x->n);
     472        stats->clippedNvalues = Nkeep;
     473        psFree(fit);
     474    }
     475
     476    // Free local temporary variables
     477    psFree(resid);
     478    if (!inMask) psFree (mask);
     479    *pGoodFit = true; // XXX probably don't need to set this (set by psImageMapFit)
     480    return true;
     481}
     482
     483// CZW: 2014-10-09
     484// Sparse versions of MapFit and MapFitClip that assume the matrices are not filled.
     485bool psImageMapFitSparse(bool *pGoodFit, psImageMap *map, const psVector *mask, psVectorMaskType maskValue,
     486                   const psVector *x, const psVector *y, const psVector *f, const psVector *df)
     487{
     488    // XXX Add Asserts
     489
     490    *pGoodFit = false;
     491
     492    // dimensions of the output map image
     493    int Nx = map->binning->nXruff;
     494    int Ny = map->binning->nYruff;
     495
     496   
     497    // no spatial information, just calculate mean & stdev
     498    if ((Nx == 1) && (Ny == 1)) {
     499        psStatsInit(map->stats);
     500
     501        // the user has supplied one of various stats option pairs,
     502        psStatsOptions mean = psStatsMeanOption(map->stats->options);
     503        psStatsOptions stdev = psStatsStdevOption(map->stats->options);
     504        if (!psStatsSingleOption(mean)) {
     505            psError(PS_ERR_UNKNOWN, true, "no valid mean stats option selected");
     506            return false;
     507        }
     508        if (!psStatsSingleOption(stdev)) {
     509            psError(PS_ERR_UNKNOWN, true, "no valid stdev stats option selected");
     510            return false;
     511        }
     512
     513        // XXX does ROBUST_MEDIAN work with weight?
     514        if (!psVectorStats(map->stats, f, NULL, mask, maskValue)) {
     515            psError(PS_ERR_UNKNOWN, false, "failure to measure stats");
     516            return false;
     517        }
     518
     519        map->map->data.F32[0][0]   = psStatsGetValue(map->stats, mean);
     520        map->error->data.F32[0][0] = psStatsGetValue(map->stats, stdev);
     521        if (isfinite(map->map->data.F32[0][0]) && isfinite( map->error->data.F32[0][0])) {
     522            *pGoodFit = true;
     523        }
     524        return true;
     525    }
     526
     527    if (Nx == 1) {
     528        bool status;
     529        status = psImageMapFit1DinY (pGoodFit, map, mask, maskValue, x, y, f, df);
     530        return status;
     531    }
     532    if (Ny == 1) {
     533        bool status;
     534        status = psImageMapFit1DinX (pGoodFit, map, mask, maskValue, x, y, f, df);
     535        return status;
     536    }
     537
     538    // set up the redirection table so we can use sA[-1][-1], etc
     539    // XXX psKernel does this for you --- PAP.
     540    float SAm[3][3], *SAv[3], **sA;
     541
     542    for (int i = 0; i < 3; i++) {
     543        SAv[i] = SAm[i] + 1;
     544    }
     545    sA = SAv + 1;
     546
     547    // elements of the matrix equation Ax = B; we are solving for the vector x
     548    // psImage *A = psImageAlloc (Nx*Ny, Nx*Ny, PS_TYPE_F32);
     549    // psVector *B = psVectorAlloc (Nx*Ny, PS_TYPE_F32);
     550
     551    // psImageInit (A, 0.0);
     552    // psVectorInit (B, 0.0);
     553
     554    // CZW: call to psSparseAlloc
     555    // It should match old A, and each element of that should only touch four others.
     556    psSparse *Asparse = psSparseAlloc(Nx * Ny, 4 * Nx * Ny);
     557   
     558    // we are looping over the Nx,Ny image map elements;
     559    // the matrix equation contains Nx*Ny rows and columns
     560
     561    for (int n = 0; n < Nx; n++) {
     562        for (int m = 0; m < Ny; m++) {
     563            // define & init summing variables
     564            float rx_rx_ry_ry = 0;
     565            float rx_rx_dy_ry = 0;
     566            float dx_rx_ry_ry = 0;
     567            float dx_rx_dy_ry = 0;
     568            float fi_rx_ry    = 0;
     569            float rx_rx_py_py = 0;
     570            float rx_rx_qy_py = 0;
     571            float dx_rx_py_py = 0;
     572            float dx_rx_qy_py = 0;
     573            float fi_rx_py    = 0;
     574            float px_px_ry_ry = 0;
     575            float px_px_dy_ry = 0;
     576            float qx_px_ry_ry = 0;
     577            float qx_px_dy_ry = 0;
     578            float fi_px_ry    = 0;
     579            float px_px_py_py = 0;
     580            float px_px_qy_py = 0;
     581            float qx_px_py_py = 0;
     582            float qx_px_qy_py = 0;
     583            float fi_px_py    = 0;
     584
     585            // generate the sums for the fitting matrix element I,J
     586            // I = n + nX*m
     587            // J = (n + jn) + nX*(m + jm)
     588            for (int i = 0; i < x->n; i++) {
     589
     590                if (mask && (mask->data.PS_TYPE_VECTOR_MASK_DATA[i] & maskValue)) continue;
     591
     592                // base coordinate offset for this point (x,y) relative to this map element (n,m)
     593                float dx = psImageBinningGetRuffX (map->binning, x->data.F32[i]) - (n + 0.5);
     594                float dy = psImageBinningGetRuffY (map->binning, y->data.F32[i]) - (m + 0.5);
     595
     596                // edge cases to include:
     597                bool edgeX = false;
     598                edgeX |= ((n == 1) && (dx < -1.0));
     599                edgeX |= ((n == Nx - 2) && (dx > +1.0));
     600
     601                bool edgeY = false;
     602                edgeY |= ((m == 1) && (dy < -1.0));
     603                edgeY |= ((m == Ny - 2) && (dy > +1.0));
     604
     605                // skip points outside of 2x2 grid centered on n,m:
     606                if (!edgeX && (fabs(dx) > 1.0)) continue;
     607                if (!edgeY && (fabs(dy) > 1.0)) continue;
     608
     609                // related offset values
     610                float rx = 1.0 - dx;
     611                float ry = 1.0 - dy;
     612                float px = 1.0 + dx;
     613                float py = 1.0 + dy;
     614                float qx = -dx;
     615                float qy = -dy;
     616
     617                // data value & weight for this point
     618                float fi = f->data.F32[i];
     619                if (!isfinite(fi)) continue;
     620
     621                float wt = 1.0;
     622                if (df != NULL) {
     623                    if (df->data.F32[i] == 0.0) {
     624                        wt = 0.0;
     625                    } else {
     626                        if (!isfinite(df->data.F32[i])) continue;
     627                        wt = 1.0 / PS_SQR(df->data.F32[i]); // XXX test for dz == NULL or dz_i = 0
     628                    }
     629                }
     630
     631                // sum the appropriate elements for the different quadrants
     632
     633                int Qx = (dx >= 0) ? 1 : 0;
     634                if (n ==      0) Qx = 1;
     635                if (n == Nx - 1) Qx = 0;
     636
     637                int Qy = (dy >= 0) ? 1 : 0;
     638                if (m ==      0) Qy = 1;
     639                if (m == Ny - 1) Qy = 0;
     640
     641                assert (isfinite(fi));
     642                assert (isfinite(wt));
     643                assert (isfinite(rx));
     644                assert (isfinite(ry));
     645
     646                // points at offset 1,1
     647                if ((Qx == 1) && (Qy == 1)) {
     648                    rx_rx_ry_ry += rx*rx*ry*ry*wt;
     649                    rx_rx_dy_ry += rx*rx*dy*ry*wt;
     650                    dx_rx_ry_ry += dx*rx*ry*ry*wt;
     651                    dx_rx_dy_ry += dx*rx*dy*ry*wt;
     652                    fi_rx_ry    += fi*rx*ry*wt;
     653                }
     654                // points at offset 1,0
     655                if ((Qx == 1) && (Qy == 0)) {
     656                    rx_rx_py_py += rx*rx*py*py*wt;
     657                    rx_rx_qy_py += rx*rx*qy*py*wt;
     658                    dx_rx_py_py += dx*rx*py*py*wt;
     659                    dx_rx_qy_py += dx*rx*qy*py*wt;
     660                    fi_rx_py    += fi*rx*py*wt;
     661                }
     662                // points at offset 0,1
     663                if ((Qx == 0) && (Qy == 1)) {
     664                    px_px_ry_ry += px*px*ry*ry*wt;
     665                    px_px_dy_ry += px*px*dy*ry*wt;
     666                    qx_px_ry_ry += qx*px*ry*ry*wt;
     667                    qx_px_dy_ry += qx*px*dy*ry*wt;
     668                    fi_px_ry    += fi*px*ry*wt;
     669                }
     670                // points at offset 0,0
     671                if ((Qx == 0) && (Qy == 0)) {
     672                    px_px_py_py += px*px*py*py*wt;
     673                    px_px_qy_py += px*px*qy*py*wt;
     674                    qx_px_py_py += qx*px*py*py*wt;
     675                    qx_px_qy_py += qx*px*qy*py*wt;
     676                    fi_px_py    += fi*px*py*wt;
     677                }
     678            }
     679
     680            // the chi-square derivatives have elements of the form g(n+jn,m+jm)*A(jn,jm),
     681            // jn,jm = -1 to +1. Convert the sums above into the correct coefficients
     682            sA[-1][-1] = qx_px_qy_py;
     683            sA[-1][ 0] = qx_px_ry_ry + qx_px_py_py;
     684            sA[-1][+1] = qx_px_dy_ry;
     685            sA[ 0][-1] = rx_rx_qy_py + px_px_qy_py;
     686            sA[ 0][ 0] = rx_rx_ry_ry + px_px_ry_ry + rx_rx_py_py + px_px_py_py;
     687            sA[ 0][+1] = rx_rx_dy_ry + px_px_dy_ry;
     688            sA[+1][-1] = dx_rx_qy_py;
     689            sA[+1][ 0] = dx_rx_ry_ry + dx_rx_py_py;
     690            sA[+1][+1] = dx_rx_dy_ry;
     691
     692            // I[ 0][ 0] = index for this n,m element:
     693            int I = n + Nx * m;
     694            //            B->data.F32[I] = fi_rx_ry + fi_rx_py + fi_px_ry + fi_px_py;
     695            // CZW: call to psSparseVector Element
     696            if (fi_rx_ry + fi_rx_py + fi_px_ry + fi_px_py == 0.0) {
     697              psSparseVectorElement(Asparse, I, 1.0);
     698            }
     699            else {
     700              psSparseVectorElement(Asparse, I, fi_rx_ry + fi_rx_py + fi_px_ry + fi_px_py);
     701            }
     702           
     703            //      printf("ADDING: %d %g \n",I, fi_rx_ry + fi_rx_py + fi_px_ry + fi_px_py);
     704            // insert these values into their corresponding locations in A, B
     705            for (int jn = -1; jn <= +1; jn++) {
     706                if (n + jn <   0) continue;
     707                if (n + jn >= Nx) continue;
     708                for (int jm = -1; jm <= +1; jm++) {
     709                    if (m + jm <   0) continue;
     710                    if (m + jm >= Ny) continue;
     711                    int J = (n + jn) + Nx * (m + jm);
     712                    //              printf("A: %d %d %g\n",J,I,sA[jn][jm]);
     713                    // A->data.F32[J][I] = sA[jn][jm];
     714                    // CZW: call to psSparseMatrixElement
     715                    if (J < I) { continue; }
     716                    psSparseMatrixElement(Asparse,J,I,sA[jn][jm]); // Ensure J < I?
     717                   
     718                }
     719            }
     720        }
     721    }
     722
     723    // test for empty diagonal elements (unconstained cells), mark, and set pivots to 1.0
     724    // CZW: I'm not totally sure how to check these in the sparse context.
     725    // Iterate over all ii pairs, and manually check the structure?
     726#if (0)
     727    psVector *Empty = psVectorAlloc (Nx*Ny, PS_TYPE_S8);
     728    psVectorInit (Empty, 0);
     729    for (int i = 0; i < Nx*Ny; i++) {
     730        if (A->data.F32[i][i] == 0.0) {
     731            Empty->data.S8[i] = 1;
     732            for (int j = 0; j < Nx*Ny; j++) {
     733                A->data.F32[i][j] = 0.0;
     734                A->data.F32[j][i] = 0.0;
     735            }
     736            A->data.F32[i][i] = 1.0;
     737            B->data.F32[i] = 0.0;
     738        }
     739    }
     740#endif
     741
     742    // CZW: call to psSparseSolve
     743    psVector *solution = psVectorAlloc(Nx*Ny, PS_TYPE_F32);
     744    psSparseConstraint Constraint;
     745    Constraint.paramDelta = 1e-3;
     746    Constraint.paramMin   = -1e5;
     747    Constraint.paramMax   = 1e5;
     748    solution = psSparseSolve(solution, Constraint, Asparse, 1000);
     749    if (!solution) {
     750      psFree(solution);
     751      psFree(Asparse);
     752      return(false);
     753    }
     754
     755#if (0)
     756    // CZW: This is a continuation of the above information
     757    // set bad values to NaN
     758    for (int i = 0; i < Nx*Ny; i++) {
     759        if (Empty->data.S8[i]) {
     760            B->data.F32[i] = NAN;
     761            A->data.F32[i][i] = 0;
     762        }
     763    }
     764#endif
     765
     766    for (int n = 0; n < Nx; n++) {
     767        for (int m = 0; m < Ny; m++) {
     768            int I = n + Nx * m;
     769            map->map->data.F32[m][n] = solution->data.F32[I];
     770            map->error->data.F32[m][n] = NAN; // sqrt(A->data.F32[I][I]); // CZW: fix this to be a real error.
     771        }
     772    }
     773
     774    //    psFree (A);
     775    //    psFree (B);
     776    //    psFree (Empty);
     777    // CZW: free things
     778    psFree(solution);
     779    psFree(Asparse);
     780   
     781    *pGoodFit = true;
     782    return true;
     783}
     784
     785// measure residuals on each pass and clip outliers based on stats
     786bool psImageMapClipFitSparse(bool *pGoodFit, psImageMap *map, psStats *stats, psVector *inMask, psVectorMaskType maskValue,
     787                             const psVector *x, const psVector *y, const psVector *f, const psVector *df)
     788{
     789    // XXX add in full PS_ASSERTS
     790    psAssert(map, "impossible");
     791    psAssert(stats, "impossible");
     792    psAssert(x, "impossible");
     793    psAssert(y, "impossible");
     794    psAssert(f, "impossible");
     795
     796    *pGoodFit = false;
     797
     798    // the user supplies one of various stats option pairs,
     799    // determine the desired mean and stdev STATS options:
     800    psStatsOptions meanOption = psStatsMeanOption(stats->options);
     801    psStatsOptions stdevOption = psStatsStdevOption(stats->options);
     802    if (!psStatsSingleOption(meanOption)) {
     803        psError(PS_ERR_UNKNOWN, true, "no valid mean stats option selected");
     804        return false;
     805    }
     806    if (!psStatsSingleOption(stdevOption)) {
     807        psError(PS_ERR_UNKNOWN, true, "no valid stdev stats option selected");
     808        return false;
     809    }
     810
     811    // clipping range defined by min and max and/or clipSigma
     812    psF32 minClipSigma;
     813    psF32 maxClipSigma;
     814    if (isfinite(stats->max)) {
     815        maxClipSigma = fabs(stats->max);
     816    } else {
     817        maxClipSigma = fabs(stats->clipSigma);
     818    }
     819    if (isfinite(stats->min)) {
     820        minClipSigma = fabs(stats->min);
     821    } else {
     822        minClipSigma = fabs(stats->clipSigma);
     823    }
     824
     825    psVector *mask = inMask;
     826    if (!inMask) {
     827        mask = psVectorAlloc (x->n, PS_TYPE_VECTOR_MASK);
     828        psVectorInit (mask, 0);
     829    }
     830
     831    // vector to store residuals
     832    psVector *resid = psVectorAlloc(f->n, PS_TYPE_F32);
     833
     834    psTrace("psLib.imageops", 4, "stats->clipIter is %d\n", stats->clipIter);
     835    psTrace("psLib.imageops", 4, "(minClipSigma, maxClipSigma) is (%.2f, %.2f)\n", minClipSigma, maxClipSigma);
     836
     837    for (psS32 N = 0; N < stats->clipIter; N++) {
     838        psTrace("psLib.imageops", 6, "Loop iteration %d.  Calling psImageMapFit()\n", N);
     839        psS32 Nkeep = 0;
     840        if (!psImageMapFitSparse(pGoodFit, map, mask, maskValue, x, y, f, df)) {
    404841            psError(PS_ERR_UNKNOWN, false, "Could not fit image map.\n");
    405842            psFree(resid);
Note: See TracChangeset for help on using the changeset viewer.