- Timestamp:
- Jan 12, 2015, 12:35:53 PM (12 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
branches/eam_branches/ipp-pv3-20140717-merge/psLib/src/imageops/psImageMapFit.c
r34153 r37827 18 18 19 19 #include <stdio.h> 20 #include <stdlib.h> 20 21 #include "psError.h" 21 22 #include "psAbort.h" … … 35 36 #include "psImageStructManip.h" 36 37 #include "psImageMap.h" 38 #include "psSparse.h" 37 39 // #include "psImagePixelInterpolate.h" 38 40 // #include "psImageUnbin.h" … … 118 120 psImageInit (A, 0.0); 119 121 psVectorInit (B, 0.0); 120 122 121 123 // we are looping over the Nx,Ny image map elements; 122 124 // the matrix equation contains Nx*Ny rows and columns … … 262 264 int I = n + Nx * m; 263 265 B->data.F32[I] = fi_rx_ry + fi_rx_py + fi_px_ry + fi_px_py; 264 266 265 267 // insert these values into their corresponding locations in A, B 266 268 // float Sum = 0.0; … … 273 275 int J = (n + jn) + Nx * (m + jm); 274 276 A->data.F32[J][I] = sA[jn][jm]; 277 275 278 // fprintf (stderr, "A %d %d (%d %d : %d %d): %f\n", I, J, n, m, n + jn, m + jm, sA[jn][jm]); 276 279 // Sum += sA[jn][jm]; … … 282 285 } 283 286 // 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 } 284 293 285 294 // test for empty diagonal elements (unconstained cells), mark, and set pivots to 1.0 286 295 psVector *Empty = psVectorAlloc (Nx*Ny, PS_TYPE_S8); 287 296 psVectorInit (Empty, 0); 297 double MinPivot = 0.025*MaxPivot; 288 298 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) { 290 300 Empty->data.S8[i] = 1; 291 301 for (int j = 0; j < Nx*Ny; j++) { … … 320 330 return true; 321 331 } 322 332 323 333 // set bad values to NaN 324 334 for (int i = 0; i < Nx*Ny; i++) { … … 341 351 psFree (B); 342 352 psFree (Empty); 343 344 353 *pGoodFit = true; 345 354 return true; … … 402 411 psS32 Nkeep = 0; 403 412 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. 485 bool 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 786 bool 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)) { 404 841 psError(PS_ERR_UNKNOWN, false, "Could not fit image map.\n"); 405 842 psFree(resid);
Note:
See TracChangeset
for help on using the changeset viewer.
