Changeset 26893 for trunk/psModules/src/imcombine
- Timestamp:
- Feb 10, 2010, 7:34:39 PM (16 years ago)
- Location:
- trunk/psModules/src/imcombine
- Files:
-
- 25 edited
- 4 copied
-
Makefile.am (modified) (2 diffs)
-
pmImageCombine.c (modified) (5 diffs)
-
pmPSFEnvelope.c (modified) (3 diffs)
-
pmPSFEnvelope.h (modified) (1 diff)
-
pmStackReject.c (modified) (3 diffs)
-
pmSubtraction.c (modified) (31 diffs)
-
pmSubtraction.h (modified) (3 diffs)
-
pmSubtractionAnalysis.c (modified) (3 diffs)
-
pmSubtractionAnalysis.h (modified) (1 diff)
-
pmSubtractionDeconvolve.c (copied) (copied from branches/eam_branches/20091201/psModules/src/imcombine/pmSubtractionDeconvolve.c )
-
pmSubtractionDeconvolve.h (copied) (copied from branches/eam_branches/20091201/psModules/src/imcombine/pmSubtractionDeconvolve.h )
-
pmSubtractionEquation.c (modified) (51 diffs)
-
pmSubtractionEquation.h (modified) (2 diffs)
-
pmSubtractionHermitian.c (copied) (copied from branches/eam_branches/20091201/psModules/src/imcombine/pmSubtractionHermitian.c )
-
pmSubtractionHermitian.h (copied) (copied from branches/eam_branches/20091201/psModules/src/imcombine/pmSubtractionHermitian.h )
-
pmSubtractionIO.c (modified) (4 diffs)
-
pmSubtractionKernels.c (modified) (30 diffs)
-
pmSubtractionKernels.h (modified) (15 diffs)
-
pmSubtractionMask.c (modified) (3 diffs)
-
pmSubtractionMask.h (modified) (1 diff)
-
pmSubtractionMatch.c (modified) (25 diffs)
-
pmSubtractionMatch.h (modified) (3 diffs)
-
pmSubtractionParams.c (modified) (4 diffs)
-
pmSubtractionParams.h (modified) (1 diff)
-
pmSubtractionStamps.c (modified) (31 diffs)
-
pmSubtractionStamps.h (modified) (7 diffs)
-
pmSubtractionThreads.c (modified) (1 diff)
-
pmSubtractionVisual.c (modified) (14 diffs)
-
pmSubtractionVisual.h (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
-
trunk/psModules/src/imcombine/Makefile.am
r23242 r26893 13 13 pmSubtractionIO.c \ 14 14 pmSubtractionKernels.c \ 15 pmSubtractionHermitian.c \ 16 pmSubtractionDeconvolve.c \ 15 17 pmSubtractionMask.c \ 16 18 pmSubtractionMatch.c \ … … 32 34 pmSubtractionIO.h \ 33 35 pmSubtractionKernels.h \ 36 pmSubtractionHermitian.h \ 37 pmSubtractionDeconvolve.h \ 34 38 pmSubtractionMask.h \ 35 39 pmSubtractionMatch.h \ -
trunk/psModules/src/imcombine/pmImageCombine.c
r23989 r26893 118 118 psImage *mask = masks->data[i]; // Mask of interest 119 119 pixelMasks->data.PS_TYPE_VECTOR_MASK_DATA[i] = (mask->data.PS_TYPE_IMAGE_MASK_DATA[y][x] & maskVal); 120 } 121 // Set the pixel error data, if necessary120 } 121 // Set the pixel error data, if necessary 122 122 if (errors) { 123 123 psImage *error = errors->data[i]; // Error image of interest … … 132 132 // Combine all the pixels, using the specified stat. 133 133 if (!psVectorStats(stats, pixelData, pixelErrors, pixelMasks, 0xff)) { 134 psError(PS_ERR_UNKNOWN, false, "failure to measure stats");135 return false;136 }137 if (isnan(stats->sampleMean)) {134 psError(PS_ERR_UNKNOWN, false, "failure to measure stats"); 135 return false; 136 } 137 if (isnan(stats->sampleMean)) { 138 138 combine->data.F32[y][x] = NAN; 139 139 psFree(buffer); … … 141 141 } 142 142 float combinedPixel = stats->sampleMean; // Value of the combination 143 143 144 144 if (iter == 0) { 145 145 // Save the value produced with no rejection, since it may be useful later … … 369 369 psStats *stats = psStatsAlloc(PS_STAT_SAMPLE_MEDIAN); 370 370 if (!psVectorStats(stats, pixels, NULL, mask, 1)) { 371 psError(PS_ERR_UNKNOWN, false, "failure to measure stats");371 psError(PS_ERR_UNKNOWN, false, "failure to measure stats"); 372 372 } 373 373 float median = stats->sampleMedian; … … 640 640 (psPlaneTransform * )outToIn->data[otherImg], 641 641 outCoords); 642 psS32 xPix = (int)(inCoords->x +0.5);643 psS32 yPix = (int)(inCoords->y +0.5);642 psS32 xPix = (int)(inCoords->x - 0.5); 643 psS32 yPix = (int)(inCoords->y - 0.5); 644 644 if ((xPix >= 0) && (xPix <= ((psImage*)(images->data[otherImg]))->numCols - 1) && 645 645 (yPix >= 0) && (yPix <= ((psImage*)(images->data[otherImg]))->numRows - 1)) { -
trunk/psModules/src/imcombine/pmPSFEnvelope.c
r25754 r26893 65 65 int radius, // Radius of each PSF 66 66 const char *modelName,// Name of PSF model to use 67 int xOrder, int yOrder // Order for PSF variation fit 67 int xOrder, int yOrder, // Order for PSF variation fit 68 psImageMaskType maskVal 68 69 ) 69 70 { … … 154 155 pmModelClassSetLimits(PM_MODEL_LIMITS_IGNORE); 155 156 pmModel *model = pmModelFromPSFforXY(psf, numCols / 2.0, numRows / 2.0, PEAK_FLUX); // Test model 156 model->modelSetLimits(PM_MODEL_LIMITS_STRICT); 157 for (int j = 0; j < model->params->n && goodPSF; j++) { 158 if (!model->modelLimits(PS_MINIMIZE_PARAM_MIN, j, model->params->data.F32, NULL) || 159 !model->modelLimits(PS_MINIMIZE_PARAM_MAX, j, model->params->data.F32, NULL)) { 160 goodPSF = false; 157 if (!model) { 158 goodPSF = false; 159 } else { 160 model->modelSetLimits(PM_MODEL_LIMITS_STRICT); 161 for (int j = 0; j < model->params->n && goodPSF; j++) { 162 if (!model->modelLimits(PS_MINIMIZE_PARAM_MIN, j, model->params->data.F32, NULL) || 163 !model->modelLimits(PS_MINIMIZE_PARAM_MAX, j, model->params->data.F32, NULL)) { 164 goodPSF = false; 165 } 161 166 } 162 }163 psFree(model);167 psFree(model); 168 } 164 169 if (!goodPSF) { 165 170 psWarning("PSF %d is bad --- not including in envelope calculation.", i); … … 360 365 361 366 // measure the source moments: tophat windowing, no pixel S/N cutoff 362 if (!pmSourceMoments(source, maxRadius, 0.0, 1.0)) { 367 // XXX probably should be passing the maskVal to this function so we can pass it along here... 368 if (!pmSourceMoments(source, maxRadius, 0.0, 1.0, maskVal)) { 363 369 // Can't do anything about it; limp along as best we can 364 370 psErrorClear(); -
trunk/psModules/src/imcombine/pmPSFEnvelope.h
r15837 r26893 17 17 int radius, // Radius of each PSF 18 18 const char *modelName, // Name of PSF model to use 19 int xOrder, int yOrder // Order for PSF variation 19 int xOrder, int yOrder, // Order for PSF variation 20 psImageMaskType maskVal 20 21 ); 21 22 -
trunk/psModules/src/imcombine/pmStackReject.c
r25468 r26893 35 35 { 36 36 int size = kernels->size; // Half-size of convolution kernel 37 psImage *polyValues = p_pmSubtractionPolynomialFromCoords(NULL, kernels, numCols, numRows, 38 xMin + size + 1, yMin + size + 1); // Polynomial 37 int x = PS_MIN(xMin + size + 1, kernels->xMax); // x coordinate of interest 38 int y = PS_MIN(yMin + size + 1, kernels->yMax); // y coordinate of interest 39 40 psImage *polyValues = p_pmSubtractionPolynomialFromCoords(NULL, kernels, x, y); // Polynomial 39 41 int box = p_pmSubtractionBadRadius(NULL, kernels, polyValues, false, poorFrac); // Radius of bad box 40 42 psTrace("psModules.imcombine", 10, "Growing by %d", box); … … 150 152 pmReadout *inRO = pmReadoutAlloc(NULL); // Readout with input image 151 153 inRO->image = image; 154 convRO->image = psImageAlloc(image->numCols, image->numRows, PS_TYPE_F32); 152 155 for (int i = 0; i < numRegions; i++) { 153 156 psRegion *region = subRegions->data[i]; // Region of interest 154 157 pmSubtractionKernels *kernels = subKernels->data[i]; // Kernel of interest 155 if (!pmSubtractionConvolve(NULL, convRO, NULL, inRO, NULL, stride, 0, 0, 1.0, 0.0, 158 if (!pmSubtractionConvolve(NULL, convRO, NULL, inRO, NULL, stride, 0, 0, 1.0, 0.0, 0.0, 156 159 region, kernels, false, true)) { 157 160 psError(PS_ERR_UNKNOWN, false, "Unable to convolve mask image in region %d.", i); … … 165 168 166 169 // Image of the kernel at the centre of the region 167 float xNorm = (region->x0 + 0.5 * (region->x1 - region->x0) - kernels->numCols/2.0) / 168 (float)kernels->numCols; 169 float yNorm = (region->y0 + 0.5 * (region->y1 - region->y0) - kernels->numRows/2.0) / 170 (float)kernels->numRows; 171 psImage *kernel = pmSubtractionKernelImage(kernels, xNorm, yNorm, false); 170 psImage *kernel = pmSubtractionKernelImage(kernels, 0.5, 0.5, false); 172 171 if (!kernel) { 173 172 psError(PS_ERR_UNKNOWN, false, "Unable to generate kernel image."); -
trunk/psModules/src/imcombine/pmSubtraction.c
r26584 r26893 21 21 #include "pmSubtractionStamps.h" 22 22 #include "pmSubtractionEquation.h" 23 #include "pmSubtractionVisual.h" 23 24 #include "pmSubtractionThreads.h" 24 25 … … 63 64 } 64 65 65 // Contribute to an image of the solved kernel component for ISIS66 static void solvedKernel ISIS(psKernel *kernel, // Kernel, updated67 const pmSubtractionKernels *kernels, // Kernel basis functions68 float value, // Normalisation value for basis function69 int index // Index of basis function of interest66 // Contribute to an image of the solved kernel component using the preCalculated image 67 static void solvedKernelPreCalc(psKernel *kernel, // Kernel, updated 68 const pmSubtractionKernels *kernels, // Kernel basis functions 69 float value, // Normalisation value for basis function 70 int index // Index of basis function of interest 70 71 ) 71 72 { 72 73 int size = kernels->size; // Kernel half-size 73 p sArray*preCalc = kernels->preCalc->data[index]; // Precalculated values74 pmSubtractionKernelPreCalc *preCalc = kernels->preCalc->data[index]; // Precalculated values 74 75 #if 0 75 psVector *xKernel = preCalc->data[0]; // Kernel in x76 psVector *yKernel = preCalc->data[1]; // Kernel in y77 76 // Iterating over the kernel 78 77 for (int y = 0, v = -size; v <= size; y++, v++) { 79 float yValue = value * yKernel->data.F32[y];78 float yValue = value * preCalc->yKernel->data.F32[y]; 80 79 for (int x = 0, u = -size; u <= size; x++, u++) { 81 kernel->kernel[v][u] += yValue * xKernel->data.F32[x];80 kernel->kernel[v][u] += yValue * preCalc->xKernel->data.F32[x]; 82 81 } 83 82 } … … 87 86 } 88 87 #else 89 psKernel *k = preCalc->data[2]; // Kernel image90 88 for (int v = -size; v <= size; v++) { 91 89 for (int u = -size; u <= size; u++) { 92 kernel->kernel[v][u] += value * k->kernel[v][u];90 kernel->kernel[v][u] += value * preCalc->kernel->kernel[v][u]; 93 91 } 94 92 } … … 119 117 for (int i = 0; i < numKernels; i++) { 120 118 double value = p_pmSubtractionSolutionCoeff(kernels, polyValues, i, wantDual); // Polynomial value 119 if (wantDual) { 120 // The model is built with the dual convolution terms added, so to produce zero residual the 121 // equation results in negative coefficients which we must undo. 122 value *= -1.0; 123 } 121 124 122 125 switch (kernels->type) { … … 149 152 case PM_SUBTRACTION_KERNEL_GUNK: { 150 153 if (i < kernels->inner) { 151 solvedKernel ISIS(kernel, kernels, value, i);154 solvedKernelPreCalc(kernel, kernels, value, i); 152 155 } else { 153 156 // Using delta function … … 159 162 break; 160 163 } 161 case PM_SUBTRACTION_KERNEL_ISIS: { 162 solvedKernelISIS(kernel, kernels, value, i); 164 case PM_SUBTRACTION_KERNEL_ISIS: 165 case PM_SUBTRACTION_KERNEL_ISIS_RADIAL: 166 case PM_SUBTRACTION_KERNEL_HERM: 167 case PM_SUBTRACTION_KERNEL_DECONV_HERM: { 168 solvedKernelPreCalc(kernel, kernels, value, i); 163 169 break; 164 170 } 165 171 case PM_SUBTRACTION_KERNEL_RINGS: { 166 psArray *preCalc = kernels->preCalc->data[i]; // Precalculated data 167 psVector *uCoords = preCalc->data[0]; // u coordinates 168 psVector *vCoords = preCalc->data[1]; // v coordinates 169 psVector *poly = preCalc->data[2]; // Polynomial values 170 int num = uCoords->n; // Number of pixels 172 pmSubtractionKernelPreCalc *preCalc = kernels->preCalc->data[i]; // Precalculated kernels 173 int num = preCalc->uCoords->n; // Number of pixels 171 174 172 175 for (int j = 0; j < num; j++) { 173 int u = uCoords->data.S32[j], v = vCoords->data.S32[j]; // Kernel coordinates 174 kernel->kernel[v][u] += poly->data.F32[j] * value; 176 int u = preCalc->uCoords->data.S32[j]; 177 int v = preCalc->vCoords->data.S32[j]; // Kernel coordinates 178 kernel->kernel[v][u] += preCalc->poly->data.F32[j] * value; 175 179 } 176 180 // Photometric scaling is built into the kernel --- no subtraction! … … 419 423 *target |= maskBad; 420 424 } else if (*source & subConvPoor) { 425 *target &= ~maskBad; 421 426 *target |= maskPoor; 427 } else { 428 *target &= ~maskBad & ~maskPoor; 422 429 } 423 430 } … … 454 461 #endif 455 462 456 // Convolve a stamp using a n ISISkernel basis function457 static psKernel *convolveStamp ISIS(const psKernel *image, // Image to convolve458 const pmSubtractionKernels *kernels, // Kernel basis functions459 int index, // Index of basis function of interest460 int footprint // Half-size of stamp463 // Convolve a stamp using a pre-calculated kernel basis function 464 static psKernel *convolveStampPreCalc(const psKernel *image, // Image to convolve 465 const pmSubtractionKernels *kernels, // Kernel basis functions 466 int index, // Index of basis function of interest 467 int footprint // Half-size of stamp 461 468 ) 462 469 { 463 p sArray*preCalc = kernels->preCalc->data[index]; // Precalculated data470 pmSubtractionKernelPreCalc *preCalc = kernels->preCalc->data[index]; // Precalculated data 464 471 #if 0 465 472 // Convolving using separable convolution 466 psVector *xKernel = preCalc->data[0]; // Kernel in x467 psVector *yKernel = preCalc->data[1]; // Kernel in y468 473 int size = kernels->size; // Size of kernel 469 474 … … 477 482 float value = 0.0; // Value of convolved pixel 478 483 int uMin = x - size, uMax = x + size; // Range for u 479 psF32 *xKernelData = & xKernel->data.F32[xKernel->n - 1]; // Kernel values484 psF32 *xKernelData = &preCalc->xKernel->data.F32[xKernel->n - 1]; // Kernel values 480 485 psF32 *imageData = &image->kernel[y][uMin]; // Image values 481 486 for (int u = uMin; u <= uMax; u++, xKernelData--, imageData++) { … … 492 497 float value = 0.0; // Value of convolved pixel 493 498 int vMin = y - size, vMax = y + size; // Range for v 494 psF32 *yKernelData = & yKernel->data.F32[yKernel->n - 1]; // Kernel values499 psF32 *yKernelData = &preCalc->yKernel->data.F32[yKernel->n - 1]; // Kernel values 495 500 psF32 *imageData = &temp->kernel[x][vMin]; // Image values; NOTE: wrong way! 496 501 for (int v = vMin; v <= vMax; v++, yKernelData--, imageData++) { … … 509 514 #else 510 515 // Convolving using precalculated kernel 511 return p_pmSubtractionConvolveStampPrecalc(image, preCalc-> data[2]);516 return p_pmSubtractionConvolveStampPrecalc(image, preCalc->kernel); 512 517 #endif 513 518 } … … 525 530 int x0 = - image->xMin, y0 = - image->yMin; // Position of centre of convolved image 526 531 psKernel *convolved = psKernelAllocFromImage(conv, x0, y0); // Kernel version 532 533 // pmSubtractionVisualShowSubtraction(image->image, kernel->image, conv); 534 527 535 psFree(conv); 528 536 return convolved; … … 569 577 } 570 578 579 void p_pmSubtractionPolynomialNormCoords(float *xOut, float *yOut, float xIn, float yIn, 580 int xMin, int xMax, int yMin, int yMax) 581 { 582 float xNormSize = xMax - xMin, yNormSize = yMax - yMin; // Size to use for normalisation 583 *xOut = 2.0 * (float)(xIn - xMin - xNormSize/2.0) / xNormSize; 584 *yOut = 2.0 * (float)(yIn - yMin - yNormSize/2.0) / yNormSize; 585 return; 586 } 587 571 588 psImage *p_pmSubtractionPolynomialFromCoords(psImage *output, const pmSubtractionKernels *kernels, 572 int numCols, int numRows, intx, int y)589 int x, int y) 573 590 { 574 591 assert(kernels); 575 assert(numCols > 0 && numRows > 0); 576 577 // Size to use when calculating normalised coordinates (different from actual size when convolving 578 // subimage) 579 int xNormSize = (kernels->numCols > 0 ? kernels->numCols : numCols); 580 int yNormSize = (kernels->numRows > 0 ? kernels->numRows : numRows); 581 582 // Normalised coordinates 583 float yNorm = 2.0 * (float)(y - yNormSize/2.0) / (float)yNormSize; 584 float xNorm = 2.0 * (float)(x - xNormSize/2.0) / (float)xNormSize; 585 592 593 float xNorm, yNorm; // Normalised coordinates 594 p_pmSubtractionPolynomialNormCoords(&xNorm, &yNorm, x, y, 595 kernels->xMin, kernels->xMax, kernels->yMin, kernels->yMax); 586 596 return p_pmSubtractionPolynomial(output, kernels->spatialOrder, xNorm, yNorm); 587 597 } … … 664 674 if (index < kernels->inner) { 665 675 // Photometric scaling is already built in to the precalculated kernel 666 return convolveStamp ISIS(image, kernels, index, footprint);676 return convolveStampPreCalc(image, kernels, index, footprint); 667 677 } 668 678 // Using delta function … … 673 683 return convolved; 674 684 } 675 case PM_SUBTRACTION_KERNEL_ISIS: { 676 return convolveStampISIS(image, kernels, index, footprint); 677 } 685 case PM_SUBTRACTION_KERNEL_ISIS: 686 case PM_SUBTRACTION_KERNEL_ISIS_RADIAL: 687 case PM_SUBTRACTION_KERNEL_HERM: 688 case PM_SUBTRACTION_KERNEL_DECONV_HERM: { 689 return convolveStampPreCalc(image, kernels, index, footprint); 690 } 678 691 case PM_SUBTRACTION_KERNEL_RINGS: { 679 psKernel *convolved = psKernelAlloc(-footprint, footprint, 680 -footprint, footprint); // Convolved image 681 psArray *preCalc = kernels->preCalc->data[index]; // Precalculated data 682 psVector *uCoords = preCalc->data[0]; // u coordinates 683 psVector *vCoords = preCalc->data[1]; // v coordinates 684 psVector *poly = preCalc->data[2]; // Polynomial values 685 int num = uCoords->n; // Number of pixels 686 psS32 *uData = uCoords->data.S32, *vData = vCoords->data.S32; // Dereference u,v coordinates 687 psF32 *polyData = poly->data.F32; // Dereference polynomial values 692 psKernel *convolved = psKernelAlloc(-footprint, footprint, -footprint, footprint); // Convolved image 693 pmSubtractionKernelPreCalc *preCalc = kernels->preCalc->data[index]; // Precalculated data 694 695 int num = preCalc->uCoords->n; // Number of pixels 696 psS32 *uData = preCalc->uCoords->data.S32; // Dereference v coordinate 697 psS32 *vData = preCalc->vCoords->data.S32; // Dereference u coordinate 698 psF32 *polyData = preCalc->poly->data.F32; // Dereference polynomial values 688 699 psF32 **imageData = image->kernel; // Dereference image 689 700 psF32 **convData = convolved->kernel; // Dereference convolved image … … 765 776 766 777 767 768 769 778 int pmSubtractionRejectStamps(pmSubtractionKernels *kernels, pmSubtractionStampList *stamps, 770 779 const psVector *deviations, psImage *subMask, float sigmaRej) … … 860 869 int numGood = 0; // Number of good stamps 861 870 double newMean = 0.0; // New mean 871 psString log = NULL; // Log message 872 psStringAppend(&log, "Rejecting stamps, mean = %f, threshold = %f\n", mean, limit); 862 873 for (int i = 0; i < stamps->num; i++) { 863 874 pmSubtractionStamp *stamp = stamps->stamps->data[i]; // Stamp of interest … … 872 883 // Mask out the stamp in the image so you it's not found again 873 884 psTrace("psModules.imcombine", 3, "Rejecting stamp %d (%d,%d)\n", i, 874 (int)(stamp->x + 0.5), (int)(stamp->y + 0.5)); 885 (int)(stamp->x - 0.5), (int)(stamp->y - 0.5)); 886 psStringAppend(&log, "Stamp %d (%d,%d): %f\n", i, 887 (int)(stamp->x - 0.5), (int)(stamp->y - 0.5), 888 fabsf(deviations->data.F32[i] - mean)); 875 889 numRejected++; 876 890 for (int y = stamp->y - footprint; y <= stamp->y + footprint; y++) { … … 895 909 psFree(stamp->weight); 896 910 stamp->image1 = stamp->image2 = stamp->weight = NULL; 897 psFree(stamp->matrix1); 898 psFree(stamp->matrix2); 899 psFree(stamp->matrixX); 900 stamp->matrix1 = stamp->matrix2 = stamp->matrixX = NULL; 901 psFree(stamp->vector1); 902 psFree(stamp->vector2); 903 stamp->vector1 = stamp->vector2 = NULL; 911 psFree(stamp->matrix); 912 stamp->matrix = NULL; 913 psFree(stamp->vector); 914 stamp->vector = NULL; 904 915 } else { 905 916 numGood++; … … 910 921 } 911 922 newMean /= numGood; 923 924 if (numRejected == 0) { 925 psStringAppend(&log, "<none>\n"); 926 } 927 psLogMsg("psModules.imcombine", PS_LOG_DETAIL, "%s", log); 928 psFree(log); 912 929 913 930 if (ds9) { … … 995 1012 psVector *backup = psVectorCopy(NULL, solution, PS_TYPE_F64); // Backup version 996 1013 997 int num = wantDual ? solution->n - 1 : solution->n;// Number of kernel basis functions1014 int num = kernels->num; // Number of kernel basis functions 998 1015 999 1016 psImage *polyValues = p_pmSubtractionPolynomial(NULL, kernels->spatialOrder, x, y); // Solved polynomial … … 1060 1077 // Only generate polynomial values every kernel footprint, since we have already assumed 1061 1078 // (with the stamps) that it does not vary rapidly on this scale. 1062 psImage *polyValues = p_pmSubtractionPolynomialFromCoords(NULL, kernels, numCols, numRows, 1063 xMin + x0 + size + 1, 1064 yMin + y0 + size + 1); 1079 psImage *polyValues = p_pmSubtractionPolynomialFromCoords(NULL, kernels, xMin + x0 + size + 1, 1080 yMin + y0 + size + 1); // Polynomial 1065 1081 float background = doBG ? p_pmSubtractionSolutionBackground(kernels, polyValues) : 0.0; // Background term 1066 1082 … … 1137 1153 bool pmSubtractionConvolve(pmReadout *out1, pmReadout *out2, const pmReadout *ro1, const pmReadout *ro2, 1138 1154 psImage *subMask, int stride, psImageMaskType maskBad, psImageMaskType maskPoor, 1139 float poorFrac, float kernelError, const psRegion *region,1155 float poorFrac, float kernelError, float covarFrac, const psRegion *region, 1140 1156 const pmSubtractionKernels *kernels, bool doBG, bool useFFT) 1141 1157 { … … 1146 1162 PM_ASSERT_READOUT_NON_NULL(ro1, false); 1147 1163 PM_ASSERT_READOUT_IMAGE(ro1, false); 1164 PM_ASSERT_READOUT_IMAGE(out1, false); 1148 1165 numCols = ro1->image->numCols; 1149 1166 numRows = ro1->image->numRows; … … 1155 1172 PM_ASSERT_READOUT_NON_NULL(ro2, false); 1156 1173 PM_ASSERT_READOUT_IMAGE(ro2, false); 1174 PM_ASSERT_READOUT_IMAGE(out2, false); 1157 1175 if (numCols == 0 && numRows == 0) { 1158 1176 numCols = ro2->image->numCols; … … 1177 1195 PS_ASSERT_FLOAT_LARGER_THAN_OR_EQUAL(kernelError, 0.0, false); 1178 1196 PS_ASSERT_FLOAT_LESS_THAN_OR_EQUAL(kernelError, 1.0, false); 1197 PS_ASSERT_FLOAT_LARGER_THAN_OR_EQUAL(covarFrac, 0.0, false); 1198 PS_ASSERT_FLOAT_LESS_THAN(covarFrac, 1.0, false); 1179 1199 if (region && psRegionIsNaN(*region)) { 1180 1200 psString string = psRegionToString(*region); … … 1188 1208 bool threaded = pmSubtractionThreaded(); // Running threaded? 1189 1209 1190 // Outputs1191 if (kernels->mode == PM_SUBTRACTION_MODE_1 || kernels->mode == PM_SUBTRACTION_MODE_DUAL) {1192 if (!out1->image) {1193 out1->image = psImageAlloc(numCols, numRows, PS_TYPE_F32);1194 }1195 if (ro1->variance) {1196 if (!out1->variance) {1197 out1->variance = psImageAlloc(numCols, numRows, PS_TYPE_F32);1198 }1199 psImageInit(out1->variance, 0.0);1200 }1201 }1202 if (kernels->mode == PM_SUBTRACTION_MODE_2 || kernels->mode == PM_SUBTRACTION_MODE_DUAL) {1203 if (!out2->image) {1204 out2->image = psImageAlloc(numCols, numRows, PS_TYPE_F32);1205 }1206 if (ro2->variance) {1207 if (!out2->variance) {1208 out2->variance = psImageAlloc(numCols, numRows, PS_TYPE_F32);1209 }1210 psImageInit(out2->variance, 0.0);1211 }1212 }1213 1210 psImage *convMask = NULL; // Convolved mask image (common to inputs 1 and 2) 1214 1211 if (subMask) { 1215 1212 if (kernels->mode == PM_SUBTRACTION_MODE_1 || kernels->mode == PM_SUBTRACTION_MODE_DUAL) { 1216 if (!out1->mask) {1217 out1->mask = psImageAlloc(numCols, numRows, PS_TYPE_IMAGE_MASK);1218 }1219 psImageInit(out1->mask, 0);1220 1213 convMask = out1->mask; 1221 1214 } 1222 1215 if (kernels->mode == PM_SUBTRACTION_MODE_2 || kernels->mode == PM_SUBTRACTION_MODE_DUAL) { 1223 if (!out2->mask) {1224 out2->mask = psImageAlloc(numCols, numRows, PS_TYPE_IMAGE_MASK);1225 }1226 psImageInit(out2->mask, 0);1227 1216 if (!convMask) { 1228 1217 convMask = out2->mask; … … 1244 1233 1245 1234 // Get region for convolution: [xMin:xMax,yMin:yMax] 1246 int xMin = size, xMax = numCols- size;1247 int yMin = size, yMax = numRows- size;1235 int xMin = kernels->xMin + size, xMax = kernels->xMax - size; 1236 int yMin = kernels->yMin + size, yMax = kernels->yMax - size; 1248 1237 if (region) { 1249 1238 xMin = PS_MAX(region->x0, xMin); … … 1336 1325 1337 1326 // Calculate covariances 1338 // This can take a while, so we only do it for a single instance 1339 // XXX psImageCovarianceCalculate could be multithreaded 1327 // This can be fairly involved, so we only do it for a single instance 1328 // Enable threads for covariance calculation, since we're not threading on top of it. 1329 oldThreads = psImageCovarianceSetThreads(true); 1340 1330 if (kernels->mode == PM_SUBTRACTION_MODE_1 || kernels->mode == PM_SUBTRACTION_MODE_DUAL) { 1341 1331 psKernel *kernel = pmSubtractionKernel(kernels, 0.0, 0.0, false); // Convolution kernel 1332 psKernelTruncate(kernel, covarFrac); 1342 1333 out1->covariance = psImageCovarianceCalculate(kernel, ro1->covariance); 1343 1334 psFree(kernel); … … 1346 1337 psKernel *kernel = pmSubtractionKernel(kernels, 0.0, 0.0, 1347 1338 kernels->mode == PM_SUBTRACTION_MODE_DUAL); // Conv. kernel 1339 psKernelTruncate(kernel, covarFrac); 1348 1340 out2->covariance = psImageCovarianceCalculate(kernel, ro2->covariance); 1349 1341 psFree(kernel); 1350 1342 } 1343 psImageCovarianceSetThreads(oldThreads); 1351 1344 1352 1345 // Copy anything that wasn't convolved … … 1388 1381 } 1389 1382 1390 1391 1383 psLogMsg("psModules.imcombine", PS_LOG_INFO, "Convolve image: %f sec", 1392 1384 psTimerClear("pmSubtractionConvolve")); -
trunk/psModules/src/imcombine/pmSubtraction.h
r25279 r26893 113 113 psImageMaskType maskPoor, ///< Mask value to give poor pixels 114 114 float poorFrac, ///< Fraction for "poor" 115 float sysError, ///< Relative systematic error 115 float kernelError, ///< Relative systematic error in kernel 116 float covarFrac, ///< Truncation fraction for kernel before covariance calculation 116 117 const psRegion *region, ///< Region to convolve (or NULL) 117 118 const pmSubtractionKernels *kernels, ///< Kernel parameters … … 127 128 ); 128 129 130 /// Return normalised coordinates 131 void p_pmSubtractionPolynomialNormCoords( 132 float *xOut, float *yOut, ///< Normalised coordinates, returned 133 float xIn, float yIn, ///< Input coordinates 134 int xMin, int xMax, int yMin, int yMax ///< Bounds of validity 135 ); 136 129 137 /// Given (normalised) coordinates (x,y), generate a matrix where the elements (i,j) are x^i * y^j 130 138 psImage *p_pmSubtractionPolynomial(psImage *output, ///< Output matrix, or NULL … … 138 146 psImage *p_pmSubtractionPolynomialFromCoords(psImage *output, ///< Output matrix, or NULL 139 147 const pmSubtractionKernels *kernels, ///< Kernel parameters 140 int numCols, int numRows, ///< Size of image of interest141 148 int x, int y ///< Position of interest 142 149 ); -
trunk/psModules/src/imcombine/pmSubtractionAnalysis.c
r25999 r26893 117 117 } 118 118 119 // sample difference images 120 { 121 psMetadataAddArray(analysis, PS_LIST_TAIL, "SUBTRACTION.SAMPLE.STAMP.SET", PS_META_DUPLICATE_OK, "Sample Difference Stamps", kernels->sampleStamps); 122 } 119 123 120 124 #ifdef TESTING … … 269 273 // Difference in background 270 274 { 271 psImage *polyValues = p_pmSubtractionPolynomialFromCoords(NULL, kernels, numCols, numRows, 272 numCols / 2.0, numRows / 2.0); // Polynomial 275 psImage *polyValues = p_pmSubtractionPolynomial(NULL, kernels->spatialOrder, 0.0, 0.0); // Polynomial 273 276 float bg = p_pmSubtractionSolutionBackground(kernels, polyValues); // Background difference 274 277 … … 295 298 psMetadataAddF32(header, PS_LIST_TAIL, PM_SUBTRACTION_ANALYSIS_DEV_RMS, 0, "RMS stamp deviation", 296 299 kernels->rms); 300 301 psMetadataAddF32(analysis, PS_LIST_TAIL, PM_SUBTRACTION_ANALYSIS_FSIGMA_RES_MEAN, 0, "Mean Fractional Sigma of Residuals", kernels->fSigResMean); 302 psMetadataAddF32(analysis, PS_LIST_TAIL, PM_SUBTRACTION_ANALYSIS_FSIGMA_RES_STDEV, 0, "Mean Fractional Sigma of Residuals", kernels->fSigResStdev); 303 psMetadataAddF32(analysis, PS_LIST_TAIL, PM_SUBTRACTION_ANALYSIS_FMIN_RES_MEAN, 0, "Mean Fractional Sigma of Residuals", kernels->fSigResMean); 304 psMetadataAddF32(analysis, PS_LIST_TAIL, PM_SUBTRACTION_ANALYSIS_FMIN_RES_STDEV, 0, "Mean Fractional Sigma of Residuals", kernels->fSigResStdev); 305 psMetadataAddF32(analysis, PS_LIST_TAIL, PM_SUBTRACTION_ANALYSIS_FMAX_RES_MEAN, 0, "Mean Fractional Sigma of Residuals", kernels->fSigResMean); 306 psMetadataAddF32(analysis, PS_LIST_TAIL, PM_SUBTRACTION_ANALYSIS_FMAX_RES_STDEV, 0, "Mean Fractional Sigma of Residuals", kernels->fSigResStdev); 307 308 psMetadataAddF32(header, PS_LIST_TAIL, PM_SUBTRACTION_ANALYSIS_FSIGMA_RES_MEAN, 0, "Mean Fractional Sigma of Residuals", kernels->fSigResMean); 309 psMetadataAddF32(header, PS_LIST_TAIL, PM_SUBTRACTION_ANALYSIS_FSIGMA_RES_STDEV, 0, "Mean Fractional Sigma of Residuals", kernels->fSigResStdev); 310 psMetadataAddF32(header, PS_LIST_TAIL, PM_SUBTRACTION_ANALYSIS_FMIN_RES_MEAN, 0, "Mean Fractional Sigma of Residuals", kernels->fSigResMean); 311 psMetadataAddF32(header, PS_LIST_TAIL, PM_SUBTRACTION_ANALYSIS_FMIN_RES_STDEV, 0, "Mean Fractional Sigma of Residuals", kernels->fSigResStdev); 312 psMetadataAddF32(header, PS_LIST_TAIL, PM_SUBTRACTION_ANALYSIS_FMAX_RES_MEAN, 0, "Mean Fractional Sigma of Residuals", kernels->fSigResMean); 313 psMetadataAddF32(header, PS_LIST_TAIL, PM_SUBTRACTION_ANALYSIS_FMAX_RES_STDEV, 0, "Mean Fractional Sigma of Residuals", kernels->fSigResStdev); 297 314 } 298 315 -
trunk/psModules/src/imcombine/pmSubtractionAnalysis.h
r25060 r26893 24 24 #define PM_SUBTRACTION_ANALYSIS_DECONV_MAX "SUBTRACTION.DECONV.MAX" // Maximum deconvolution fraction 25 25 26 #define PM_SUBTRACTION_ANALYSIS_FSIGMA_RES_MEAN "SUBTRACTION.RES.FSIGMA.MEAN" // RMS stamp deviation 27 #define PM_SUBTRACTION_ANALYSIS_FSIGMA_RES_STDEV "SUBTRACTION.RES.FSIGMA.STDEV" // RMS stamp deviation 28 #define PM_SUBTRACTION_ANALYSIS_FMIN_RES_MEAN "SUBTRACTION.RES.FMIN.MEAN" // RMS stamp deviation 29 #define PM_SUBTRACTION_ANALYSIS_FMIN_RES_STDEV "SUBTRACTION.RES.FMIN.STDEV" // RMS stamp deviation 30 #define PM_SUBTRACTION_ANALYSIS_FMAX_RES_MEAN "SUBTRACTION.RES.FMAX.MEAN" // RMS stamp deviation 31 #define PM_SUBTRACTION_ANALYSIS_FMAX_RES_STDEV "SUBTRACTION.RES.FMAX.STDEV" // RMS stamp deviation 32 26 33 // Derive QA information about the subtraction 27 34 bool pmSubtractionAnalysis( -
trunk/psModules/src/imcombine/pmSubtractionEquation.c
r26035 r26893 17 17 //#define TESTING // TESTING output for debugging; may not work with threads! 18 18 19 #define USE_WEIGHT // Include weight (1/variance) in equation? 19 //#define USE_WEIGHT // Include weight (1/variance) in equation? 20 //#define USE_WINDOW // Include weight (1/variance) in equation? 20 21 21 22 … … 27 28 static bool calculateMatrixVector(psImage *matrix, // Least-squares matrix, updated 28 29 psVector *vector, // Least-squares vector, updated 30 double *norm, // Normalisation, updated 29 31 const psKernel *input, // Input image (target) 30 32 const psKernel *reference, // Reference image (convolution source) 31 33 const psKernel *weight, // Weight image 34 const psKernel *window, // Window image 32 35 const psArray *convolutions, // Convolutions for each kernel 33 36 const pmSubtractionKernels *kernels, // Kernels 34 37 const psImage *polyValues, // Spatial polynomial values 35 int footprint // (Half-)Size of stamp 38 int footprint, // (Half-)Size of stamp 39 int normWindow, // Window (half-)size for normalisation measurement 40 const pmSubtractionEquationCalculationMode mode 36 41 ) 37 42 { … … 51 56 52 57 // Evaluate polynomial-polynomial terms 58 // XXX we can skip this if we are not calculating kernel coeffs 53 59 for (int iyOrder = 0, iIndex = 0; iyOrder <= spatialOrder; iyOrder++) { 54 60 for (int ixOrder = 0; ixOrder <= spatialOrder - iyOrder; ixOrder++, iIndex++) { … … 64 70 } 65 71 72 // initialize the matrix and vector for NOP on all coeffs. we only fill in the coeffs we 73 // choose to calculate 74 psImageInit(matrix, 0.0); 75 psVectorInit(vector, 1.0); 76 for (int i = 0; i < matrix->numCols; i++) { 77 matrix->data.F64[i][i] = 1.0; 78 } 79 80 // the order of the elements in the matrix and vector is: 81 // [kernel 0, x^0 y^0][kernel 1 x^0 y^0]...[kernel N, x^0 y^0] 82 // [kernel 0, x^1 y^0][kernel 1 x^1 y^0]...[kernel N, x^1 y^0] 83 // [kernel 0, x^n y^m][kernel 1 x^n y^m]...[kernel N, x^n y^m] 84 // normalization 85 // bg 0, bg 1, bg 2 (only 0 is currently used?) 66 86 67 87 for (int i = 0; i < numKernels; i++) { … … 74 94 for (int x = - footprint; x <= footprint; x++) { 75 95 double cc = iConv->kernel[y][x] * jConv->kernel[y][x]; 76 #ifdef USE_WEIGHT 77 cc *= weight->kernel[y][x]; 78 #endif 96 if (weight) { 97 cc *= weight->kernel[y][x]; 98 } 99 if (window) { 100 cc *= window->kernel[y][x]; 101 } 79 102 sumCC += cc; 80 103 } 81 104 } 82 105 83 // Spatial variation 84 for (int iTerm = 0, iIndex = i; iTerm < numPoly; iTerm++, iIndex += numKernels) { 85 for (int jTerm = 0, jIndex = j; jTerm < numPoly; jTerm++, jIndex += numKernels) { 86 double value = sumCC * poly2[iTerm][jTerm]; 87 matrix->data.F64[iIndex][jIndex] = value; 88 matrix->data.F64[jIndex][iIndex] = value; 106 // Spatial variation of kernel coeffs 107 if (mode & PM_SUBTRACTION_EQUATION_KERNELS) { 108 for (int iTerm = 0, iIndex = i; iTerm < numPoly; iTerm++, iIndex += numKernels) { 109 for (int jTerm = 0, jIndex = j; jTerm < numPoly; jTerm++, jIndex += numKernels) { 110 double value = sumCC * poly2[iTerm][jTerm]; 111 matrix->data.F64[iIndex][jIndex] = value; 112 matrix->data.F64[jIndex][iIndex] = value; 113 } 89 114 } 90 115 } … … 102 127 double rc = ref * conv; 103 128 double c = conv; 104 #ifdef USE_WEIGHT 105 float wtVal = weight->kernel[y][x]; 106 ic *= wtVal; 107 rc *= wtVal; 108 c *= wtVal; 109 #endif 129 if (weight) { 130 float wtVal = weight->kernel[y][x]; 131 ic *= wtVal; 132 rc *= wtVal; 133 c *= wtVal; 134 } 135 if (window) { 136 float winVal = window->kernel[y][x]; 137 ic *= winVal; 138 rc *= winVal; 139 c *= winVal; 140 } 110 141 sumIC += ic; 111 142 sumRC += rc; … … 117 148 double normTerm = sumRC * poly[iTerm]; 118 149 double bgTerm = sumC * poly[iTerm]; 119 matrix->data.F64[iIndex][normIndex] = normTerm; 120 matrix->data.F64[normIndex][iIndex] = normTerm; 121 matrix->data.F64[iIndex][bgIndex] = bgTerm; 122 matrix->data.F64[bgIndex][iIndex] = bgTerm; 123 vector->data.F64[iIndex] = sumIC * poly[iTerm]; 150 if ((mode & PM_SUBTRACTION_EQUATION_NORM) && (mode & PM_SUBTRACTION_EQUATION_KERNELS)) { 151 matrix->data.F64[iIndex][normIndex] = normTerm; 152 matrix->data.F64[normIndex][iIndex] = normTerm; 153 } 154 if ((mode & PM_SUBTRACTION_EQUATION_BG) && (mode & PM_SUBTRACTION_EQUATION_KERNELS)) { 155 matrix->data.F64[iIndex][bgIndex] = bgTerm; 156 matrix->data.F64[bgIndex][iIndex] = bgTerm; 157 } 158 if (mode & PM_SUBTRACTION_EQUATION_KERNELS) { 159 vector->data.F64[iIndex] = sumIC * poly[iTerm]; 160 if (!(mode & PM_SUBTRACTION_EQUATION_NORM)) { 161 // subtract norm * sumRC * poly[iTerm] 162 psAssert (kernels->solution1, "programming error: define solution first!"); 163 int normIndex = PM_SUBTRACTION_INDEX_NORM(kernels); // Index for normalisation 164 double norm = fabs(kernels->solution1->data.F64[normIndex]); // Normalisation 165 vector->data.F64[iIndex] -= norm * normTerm; 166 } 167 } 124 168 } 125 169 } … … 130 174 double sumR = 0.0; // Sum of the reference 131 175 double sumI = 0.0; // Sum of the input 176 double normI1 = 0.0, normI2 = 0.0; // Sum of I_1 and I_2 within the normalisation window 132 177 for (int y = - footprint; y <= footprint; y++) { 133 178 for (int x = - footprint; x <= footprint; x++) { … … 137 182 double rr = PS_SQR(ref); 138 183 double one = 1.0; 139 #ifdef USE_WEIGHT 140 float wtVal = weight->kernel[y][x]; 141 rr *= wtVal; 142 ir *= wtVal; 143 in *= wtVal; 144 ref *= wtVal; 145 one *= wtVal; 146 #endif 184 185 if (PS_SQR(x) + PS_SQR(y) <= PS_SQR(normWindow)) { 186 normI1 += ref; 187 normI2 += in; 188 } 189 190 if (weight) { 191 float wtVal = weight->kernel[y][x]; 192 rr *= wtVal; 193 ir *= wtVal; 194 in *= wtVal; 195 ref *= wtVal; 196 one *= wtVal; 197 } 198 if (window) { 199 float winVal = window->kernel[y][x]; 200 rr *= winVal; 201 ir *= winVal; 202 in *= winVal; 203 ref *= winVal; 204 one *= winVal; 205 } 147 206 sumRR += rr; 148 207 sumIR += ir; … … 152 211 } 153 212 } 154 matrix->data.F64[normIndex][normIndex] = sumRR; 155 matrix->data.F64[bgIndex][bgIndex] = sum1; 156 matrix->data.F64[normIndex][bgIndex] = matrix->data.F64[bgIndex][normIndex] = sumR; 157 vector->data.F64[normIndex] = sumIR; 158 vector->data.F64[bgIndex] = sumI; 213 214 *norm = normI2 / normI1; 215 216 if (mode & PM_SUBTRACTION_EQUATION_NORM) { 217 matrix->data.F64[normIndex][normIndex] = sumRR; 218 vector->data.F64[normIndex] = sumIR; 219 // subtract sum over kernels * kernel solution 220 } 221 if (mode & PM_SUBTRACTION_EQUATION_BG) { 222 matrix->data.F64[bgIndex][bgIndex] = sum1; 223 vector->data.F64[bgIndex] = sumI; 224 } 225 if ((mode & PM_SUBTRACTION_EQUATION_NORM) && (mode & PM_SUBTRACTION_EQUATION_BG)) { 226 matrix->data.F64[normIndex][bgIndex] = sumR; 227 matrix->data.F64[bgIndex][normIndex] = sumR; 228 } 229 230 // check for any NAN values in the result, skip if found: 231 for (int iy = 0; iy < matrix->numRows; iy++) { 232 for (int ix = 0; ix < matrix->numCols; ix++) { 233 if (!isfinite(matrix->data.F64[iy][ix])) { 234 fprintf (stderr, "WARNING: NAN in matrix\n"); 235 return false; 236 } 237 } 238 } 239 for (int ix = 0; ix < vector->n; ix++) { 240 if (!isfinite(vector->data.F64[ix])) { 241 fprintf (stderr, "WARNING: NAN in vector\n"); 242 return false; 243 } 244 } 159 245 160 246 return true; 161 247 } 162 248 249 163 250 // Calculate the least-squares matrix and vector for dual convolution 164 static bool calculateDualMatrixVector(psImage *matrix1, // Least-squares matrix, updated 165 psVector *vector1, // Least-squares vector, updated 166 psImage *matrix2, // Least-squares matrix, updated 167 psVector *vector2, // Least-squares vector, updated 168 psImage *matrixX, // Cross-matrix 251 static bool calculateDualMatrixVector(psImage *matrix, // Least-squares matrix, updated 252 psVector *vector, // Least-squares vector, updated 253 double *norm, // Normalisation, updated 169 254 const psKernel *image1, // Image 1 170 255 const psKernel *image2, // Image 2 171 256 const psKernel *weight, // Weight image 257 const psKernel *window, // Window image 172 258 const psArray *convolutions1, // Convolutions of image 1 for each kernel 173 259 const psArray *convolutions2, // Convolutions of image 2 for each kernel 174 260 const pmSubtractionKernels *kernels, // Kernels 175 261 const psImage *polyValues, // Spatial polynomial values 176 int footprint // (Half-)Size of stamp 262 int footprint, // (Half-)Size of stamp 263 int normWindow, // Window (half-)size for normalisation measurement 264 const pmSubtractionEquationCalculationMode mode 177 265 ) 178 266 { 179 // A_ij = A_i A_j180 // B_ij = B_i B_j181 // C_ij = A_i B_j182 // d_i = A_i I_2183 // e_i = B_i I_2184 185 // A_i = I_1 * k_i186 // B_i = I_2 * k_i187 188 // Background: A_i = 1.0189 // Normalisation: A_i = I_1190 191 267 int numKernels = kernels->num; // Number of kernels 192 268 int normIndex = PM_SUBTRACTION_INDEX_NORM(kernels); // Index for normalisation … … 196 272 double poly[numPoly]; // Polynomial terms 197 273 double poly2[numPoly][numPoly]; // Polynomial-polynomial values 274 275 int numBackground = PM_SUBTRACTION_POLYTERMS(kernels->bgOrder); // Number of background terms 276 int numParams = numKernels * numPoly + 1 + numBackground; // Number of regular parameters 277 int numParams2 = numKernels * numPoly; // Number of additional parameters for dual 278 int numDual = numParams + numParams2; // Total number of parameters for dual 279 280 psAssert(matrix && 281 matrix->type.type == PS_TYPE_F64 && 282 matrix->numCols == numDual && 283 matrix->numRows == numDual, 284 "Least-squares matrix is bad."); 285 psAssert(vector && 286 vector->type.type == PS_TYPE_F64 && 287 vector->n == numDual, 288 "Least-squares vector is bad."); 198 289 199 290 // Evaluate polynomial-polynomial terms … … 212 303 213 304 305 // initialize the matrix and vector for NOP on all coeffs. we only fill in the coeffs we 306 // choose to calculate 307 psImageInit(matrix, 0.0); 308 psVectorInit(vector, 1.0); 309 for (int i = 0; i < matrix->numCols; i++) { 310 matrix->data.F64[i][i] = 1.0; 311 } 312 214 313 for (int i = 0; i < numKernels; i++) { 215 314 psKernel *iConv1 = convolutions1->data[i]; // Convolution 1 for index i … … 219 318 psKernel *jConv2 = convolutions2->data[j]; // Convolution 2 for index j 220 319 221 double sumAA = 0.0; // Sum of convolution products for matrix A222 double sumBB = 0.0; // Sum of convolution products for matrix B223 double sumAB = 0.0; // Sum of convolution products for matrix C320 double sumAA = 0.0; // Sum of convolution products between image 1 321 double sumBB = 0.0; // Sum of convolution products between image 2 322 double sumAB = 0.0; // Sum of convolution products across images 1 and 2 224 323 for (int y = - footprint; y <= footprint; y++) { 225 324 for (int x = - footprint; x <= footprint; x++) { … … 227 326 double bb = iConv2->kernel[y][x] * jConv2->kernel[y][x]; 228 327 double ab = iConv1->kernel[y][x] * jConv2->kernel[y][x]; 229 #ifdef USE_WEIGHT 230 float wtVal = weight->kernel[y][x]; 231 aa *= wtVal; 232 bb *= wtVal; 233 ab *= wtVal; 234 #endif 328 if (weight) { 329 float wtVal = weight->kernel[y][x]; 330 aa *= wtVal; 331 bb *= wtVal; 332 ab *= wtVal; 333 } 334 if (window) { 335 float wtVal = window->kernel[y][x]; 336 aa *= wtVal; 337 bb *= wtVal; 338 ab *= wtVal; 339 } 235 340 sumAA += aa; 236 341 sumBB += bb; … … 239 344 } 240 345 241 // Spatial variation 242 for (int iTerm = 0, iIndex = i; iTerm < numPoly; iTerm++, iIndex += numKernels) { 243 for (int jTerm = 0, jIndex = j; jTerm < numPoly; jTerm++, jIndex += numKernels) { 244 double aa = sumAA * poly2[iTerm][jTerm]; 245 double bb = sumBB * poly2[iTerm][jTerm]; 246 double ab = sumAB * poly2[iTerm][jTerm]; 247 matrix1->data.F64[iIndex][jIndex] = aa; 248 matrix1->data.F64[jIndex][iIndex] = aa; 249 matrix2->data.F64[iIndex][jIndex] = bb; 250 matrix2->data.F64[jIndex][iIndex] = bb; 251 matrixX->data.F64[iIndex][jIndex] = ab; 346 // Spatial variation of kernel coeffs 347 if (mode & PM_SUBTRACTION_EQUATION_KERNELS) { 348 for (int iTerm = 0, iIndex = i; iTerm < numPoly; iTerm++, iIndex += numKernels) { 349 for (int jTerm = 0, jIndex = j; jTerm < numPoly; jTerm++, jIndex += numKernels) { 350 double aa = sumAA * poly2[iTerm][jTerm]; 351 double bb = sumBB * poly2[iTerm][jTerm]; 352 double ab = sumAB * poly2[iTerm][jTerm]; 353 354 matrix->data.F64[iIndex][jIndex] = aa; 355 matrix->data.F64[jIndex][iIndex] = aa; 356 357 matrix->data.F64[iIndex + numParams][jIndex + numParams] = bb; 358 matrix->data.F64[jIndex + numParams][iIndex + numParams] = bb; 359 360 matrix->data.F64[iIndex][jIndex + numParams] = ab; 361 matrix->data.F64[jIndex + numParams][iIndex] = ab; 362 } 252 363 } 253 364 } … … 259 370 for (int x = - footprint; x <= footprint; x++) { 260 371 double ab = iConv1->kernel[y][x] * jConv2->kernel[y][x]; 261 #ifdef USE_WEIGHT 262 ab *= weight->kernel[y][x]; 263 #endif 372 if (weight) { 373 ab *= weight->kernel[y][x]; 374 } 375 if (window) { 376 ab *= window->kernel[y][x]; 377 } 264 378 sumAB += ab; 265 379 } 266 380 } 267 381 268 // Spatial variation 269 for (int iTerm = 0, iIndex = i; iTerm < numPoly; iTerm++, iIndex += numKernels) { 270 for (int jTerm = 0, jIndex = j; jTerm < numPoly; jTerm++, jIndex += numKernels) { 271 double ab = sumAB * poly2[iTerm][jTerm]; 272 matrixX->data.F64[iIndex][jIndex] = ab; 273 } 274 } 275 } 276 277 double sumAI2 = 0.0; // Sum of A.I_2 products (for vector 1) 278 double sumBI2 = 0.0; // Sum of B.I_2 products (for vector 2) 279 double sumAI1 = 0.0; // Sum of A.I_1 products (for matrix 1, normalisation) 280 double sumA = 0.0; // Sum of A (for matrix 1, background) 281 double sumBI1 = 0.0; // Sum of B.I_1 products (for matrix X, normalisation) 282 double sumB = 0.0; // Sum of B products (for matrix X, background) 283 double sumI2 = 0.0; // Sum of I_2 (for vector 1, background) 284 double sumI1I2 = 0.0; // Sum of I_1.I_2 (for vector 1, normalisation) 382 // Spatial variation of kernel coeffs 383 if (mode & PM_SUBTRACTION_EQUATION_KERNELS) { 384 for (int iTerm = 0, iIndex = i; iTerm < numPoly; iTerm++, iIndex += numKernels) { 385 for (int jTerm = 0, jIndex = j; jTerm < numPoly; jTerm++, jIndex += numKernels) { 386 double ab = sumAB * poly2[iTerm][jTerm]; 387 matrix->data.F64[iIndex][jIndex + numParams] = ab; 388 matrix->data.F64[jIndex + numParams][iIndex] = ab; 389 } 390 } 391 } 392 } 393 394 double sumAI2 = 0.0; // Sum of A.I_2 products (for vector) 395 double sumBI2 = 0.0; // Sum of B.I_2 products (for vector) 396 double sumAI1 = 0.0; // Sum of A.I_1 products (for matrix, normalisation) 397 double sumA = 0.0; // Sum of A (for matrix, background) 398 double sumBI1 = 0.0; // Sum of B.I_1 products (for matrix, normalisation) 399 double sumB = 0.0; // Sum of B products (for matrix, background) 400 double sumI2 = 0.0; // Sum of I_2 (for vector, background) 285 401 for (int y = - footprint; y <= footprint; y++) { 286 402 for (int x = - footprint; x <= footprint; x++) { 287 floata = iConv1->kernel[y][x];288 floatb = iConv2->kernel[y][x];403 double a = iConv1->kernel[y][x]; 404 double b = iConv2->kernel[y][x]; 289 405 float i1 = image1->kernel[y][x]; 290 406 float i2 = image2->kernel[y][x]; … … 294 410 double ai1 = a * i1; 295 411 double bi1 = b * i1; 296 double i1i2 = i1 * i2; 297 298 #ifdef USE_WEIGHT 299 float wtVal = weight->kernel[y][x]; 300 ai2 *= wtVal; 301 bi2 *= wtVal; 302 ai1 *= wtVal; 303 bi1 *= wtVal; 304 i1i2 *= wtVal; 305 a *= wtVal; 306 b *= wtVal; 307 i2 *= wtVal; 308 #endif 309 412 413 if (weight) { 414 float wtVal = weight->kernel[y][x]; 415 ai2 *= wtVal; 416 bi2 *= wtVal; 417 ai1 *= wtVal; 418 bi1 *= wtVal; 419 a *= wtVal; 420 b *= wtVal; 421 i2 *= wtVal; 422 } 423 if (window) { 424 float wtVal = window->kernel[y][x]; 425 ai2 *= wtVal; 426 bi2 *= wtVal; 427 ai1 *= wtVal; 428 bi1 *= wtVal; 429 a *= wtVal; 430 b *= wtVal; 431 i2 *= wtVal; 432 } 310 433 sumAI2 += ai2; 311 434 sumBI2 += bi2; … … 315 438 sumB += b; 316 439 sumI2 += i2; 317 sumI1I2 += i1i2;318 440 } 319 441 } … … 323 445 double bi2 = sumBI2 * poly[iTerm]; 324 446 double ai1 = sumAI1 * poly[iTerm]; 325 double a = sumA * poly[iTerm];447 double a = sumA * poly[iTerm]; 326 448 double bi1 = sumBI1 * poly[iTerm]; 327 double b = sumB * poly[iTerm]; 328 329 matrix1->data.F64[iIndex][normIndex] = ai1; 330 matrix1->data.F64[normIndex][iIndex] = ai1; 331 matrix1->data.F64[iIndex][bgIndex] = a; 332 matrix1->data.F64[bgIndex][iIndex] = a; 333 vector1->data.F64[iIndex] = ai2; 334 vector2->data.F64[iIndex] = bi2; 335 matrixX->data.F64[iIndex][normIndex] = bi1; 336 matrixX->data.F64[iIndex][bgIndex] = b; 337 } 338 } 339 340 double sumI1 = 0.0; // Sum of I_1 (for matrix 1, background-normalisation) 341 double sumI1I1 = 0.0; // Sum of I_1^2 (for matrix 1, normalisation-normalisation) 342 double sum1 = 0.0; // Sum of 1 (for matrix 1, background-background) 343 double sumI2 = 0.0; // Sum of I_2 (for vector 1, background) 344 double sumI1I2 = 0.0; // Sum of I_1.I_2 (for vector 1, normalisation) 449 double b = sumB * poly[iTerm]; 450 451 if ((mode & PM_SUBTRACTION_EQUATION_NORM) && (mode & PM_SUBTRACTION_EQUATION_KERNELS)) { 452 matrix->data.F64[iIndex][normIndex] = ai1; 453 matrix->data.F64[normIndex][iIndex] = ai1; 454 matrix->data.F64[iIndex + numParams][normIndex] = bi1; 455 matrix->data.F64[normIndex][iIndex + numParams] = bi1; 456 } 457 if ((mode & PM_SUBTRACTION_EQUATION_BG) && (mode & PM_SUBTRACTION_EQUATION_KERNELS)) { 458 matrix->data.F64[iIndex][bgIndex] = a; 459 matrix->data.F64[bgIndex][iIndex] = a; 460 matrix->data.F64[iIndex + numParams][bgIndex] = b; 461 matrix->data.F64[bgIndex][iIndex + numParams] = b; 462 } 463 if (mode & PM_SUBTRACTION_EQUATION_KERNELS) { 464 vector->data.F64[iIndex] = ai2; 465 vector->data.F64[iIndex + numParams] = bi2; 466 if (!(mode & PM_SUBTRACTION_EQUATION_NORM)) { 467 // subtract norm * sumRC * poly[iTerm] 468 psAssert (kernels->solution1, "programming error: define solution first!"); 469 int normIndex = PM_SUBTRACTION_INDEX_NORM(kernels); // Index for normalisation 470 double norm = fabs(kernels->solution1->data.F64[normIndex]); // Normalisation 471 vector->data.F64[iIndex] -= norm * ai1; 472 vector->data.F64[iIndex + numParams] -= norm * bi1; 473 } 474 } 475 } 476 } 477 478 double sumI1 = 0.0; // Sum of I_1 (for matrix, background-normalisation) 479 double sumI1I1 = 0.0; // Sum of I_1^2 (for matrix, normalisation-normalisation) 480 double sum1 = 0.0; // Sum of 1 (for matrix, background-background) 481 double sumI2 = 0.0; // Sum of I_2 (for vector, background) 482 double sumI1I2 = 0.0; // Sum of I_1.I_2 (for vector, normalisation) 483 double normI1 = 0.0, normI2 = 0.0; // Sum of I_1 and I_2 within the normalisation window 345 484 for (int y = - footprint; y <= footprint; y++) { 346 485 for (int x = - footprint; x <= footprint; x++) { 347 floati1 = image1->kernel[y][x];348 floati2 = image2->kernel[y][x];486 double i1 = image1->kernel[y][x]; 487 double i2 = image2->kernel[y][x]; 349 488 350 489 double i1i1 = i1 * i1; … … 352 491 double i1i2 = i1 * i2; 353 492 354 #ifdef USE_WEIGHT 355 float wtVal = weight->kernel[y][x]; 356 i1 *= wtVal; 357 i1i1 *= wtVal; 358 one *= wtVal; 359 i2 *= wtVal; 360 i1i2 *= wtVal; 361 #endif 362 493 if (PS_SQR(x) + PS_SQR(y) <= PS_SQR(normWindow)) { 494 normI1 += i1; 495 normI2 += i2; 496 } 497 498 if (weight) { 499 float wtVal = weight->kernel[y][x]; 500 i1 *= wtVal; 501 i1i1 *= wtVal; 502 one *= wtVal; 503 i2 *= wtVal; 504 i1i2 *= wtVal; 505 } 506 if (window) { 507 float wtVal = window->kernel[y][x]; 508 i1 *= wtVal; 509 i1i1 *= wtVal; 510 one *= wtVal; 511 i2 *= wtVal; 512 i1i2 *= wtVal; 513 } 363 514 sumI1 += i1; 364 515 sumI1I1 += i1i1; … … 368 519 } 369 520 } 370 matrix1->data.F64[bgIndex][normIndex] = sumI1; 371 matrix1->data.F64[normIndex][bgIndex] = sumI1; 372 matrix1->data.F64[normIndex][normIndex] = sumI1I1; 373 matrix1->data.F64[bgIndex][bgIndex] = sum1; 374 vector1->data.F64[bgIndex] = sumI2; 375 vector1->data.F64[normIndex] = sumI1I2; 521 522 *norm = normI2 / normI1; 523 524 if (mode & PM_SUBTRACTION_EQUATION_NORM) { 525 matrix->data.F64[normIndex][normIndex] = sumI1I1; 526 vector->data.F64[normIndex] = sumI1I2; 527 } 528 if (mode & PM_SUBTRACTION_EQUATION_BG) { 529 matrix->data.F64[bgIndex][bgIndex] = sum1; 530 vector->data.F64[bgIndex] = sumI2; 531 } 532 if ((mode & PM_SUBTRACTION_EQUATION_NORM) && (mode & PM_SUBTRACTION_EQUATION_BG)) { 533 matrix->data.F64[bgIndex][normIndex] = sumI1; 534 matrix->data.F64[normIndex][bgIndex] = sumI1; 535 } 536 537 // check for any NAN values in the result, skip if found: 538 for (int iy = 0; iy < matrix->numRows; iy++) { 539 for (int ix = 0; ix < matrix->numCols; ix++) { 540 if (!isfinite(matrix->data.F64[iy][ix])) { 541 fprintf (stderr, "WARNING: NAN in matrix\n"); 542 return false; 543 } 544 } 545 } 546 for (int ix = 0; ix < vector->n; ix++) { 547 if (!isfinite(vector->data.F64[ix])) { 548 fprintf (stderr, "WARNING: NAN in vector\n"); 549 return false; 550 } 551 } 552 376 553 377 554 return true; 378 555 } 379 556 380 // Merge dual matrices and vectors into single matrix equation 381 // Have: Aa = Ct.b + d 382 // Have: Ca = Bb + e 383 // Set: F = ( A -Ct ; C -B ) 384 // Set: g = ( a ; b ) 385 // Set: h = ( d ; e ) 386 // So that we combine the above two equations: Fg = h 387 static bool calculateEquationDual(psImage **outMatrix, 388 psVector **outVector, 389 const psImage *sumMatrix1, 390 const psImage *sumMatrix2, 391 const psImage *sumMatrixX, 392 const psVector *sumVector1, 393 const psVector *sumVector2 394 ) 395 { 396 psAssert(sumMatrix1 && sumMatrix2 && sumMatrixX, "Require input matrices"); 397 psAssert(sumVector1 && sumVector2, "Require input vectors"); 398 int num1 = sumVector1->n; // Number of parameters in first set 399 int num2 = sumVector2->n; // Number of parameters in second set 400 int num = num1 + num2; // Number of parameters in new set 401 402 psAssert(sumMatrix1->type.type == PS_TYPE_F64 && 403 sumMatrix2->type.type == PS_TYPE_F64 && 404 sumMatrixX->type.type == PS_TYPE_F64 && 405 sumVector1->type.type == PS_TYPE_F64 && 406 sumVector2->type.type == PS_TYPE_F64, 407 "Require input type is F64"); 408 409 psAssert(outMatrix, "Require output matrix"); 410 psAssert(outVector, "Require output vector"); 411 if (!*outMatrix) { 412 *outMatrix = psImageAlloc(num, num, PS_TYPE_F64); 413 } 414 if (!*outVector) { 415 *outVector = psVectorAlloc(num, PS_TYPE_F64); 416 } 417 psImage *matrix = *outMatrix; 418 psVector *vector = *outVector; 419 420 psAssert(sumMatrix1->numCols == num1 && sumMatrix1->numRows == num1, "Require size NxN"); 421 psAssert(sumMatrix2->numCols == num2 && sumMatrix2->numRows == num2, "Require size MxM"); 422 psAssert(sumMatrixX->numCols == num1 && sumMatrixX->numRows == num2, "Require size MxN"); 423 424 memcpy(vector->data.F64, sumVector1->data.F64, num1 * PSELEMTYPE_SIZEOF(PS_TYPE_F64)); 425 memcpy(&vector->data.F64[num1], sumVector2->data.F64, num2 * PSELEMTYPE_SIZEOF(PS_TYPE_F64)); 426 427 for (int i = 0; i < num1; i++) { 428 memcpy(matrix->data.F64[i], sumMatrix1->data.F64[i], num1 * PSELEMTYPE_SIZEOF(PS_TYPE_F64)); 429 for (int j = 0, k = num1; j < num2; j++, k++) { 430 matrix->data.F64[i][k] = - sumMatrixX->data.F64[j][i]; 431 } 432 } 433 for (int i1 = 0, i2 = num1; i1 < num2; i1++, i2++) { 434 memcpy(matrix->data.F64[i2], sumMatrixX->data.F64[i1], num1 * PSELEMTYPE_SIZEOF(PS_TYPE_F64)); 435 for (int j = 0, k = num1; j < num2; j++, k++) { 436 matrix->data.F64[i2][k] = - sumMatrix2->data.F64[i1][j]; 437 } 438 } 439 440 return true; 441 } 442 443 557 #if 1 444 558 // Add in penalty term to least-squares vector 445 staticbool calculatePenalty(psImage *matrix, // Matrix to which to add in penalty term559 bool calculatePenalty(psImage *matrix, // Matrix to which to add in penalty term 446 560 psVector *vector, // Vector to which to add in penalty term 447 561 const pmSubtractionKernels *kernels, // Kernel parameters … … 456 570 int spatialOrder = kernels->spatialOrder; // Order of spatial variations 457 571 int numKernels = kernels->num; // Number of kernel components 572 int numSpatial = PM_SUBTRACTION_POLYTERMS(spatialOrder); // Number of spatial variations 573 int numParams = numKernels * numSpatial; // Number of kernel parameters 574 575 // order is : 576 // [p_0,x_0,y_0 p_1,x_0,y_0, p_2,x_0,y_0] 577 // [p_0,x_1,y_0 p_1,x_1,y_0, p_2,x_1,y_0] 578 // [p_0,x_0,y_1 p_1,x_0,y_1, p_2,x_0,y_1] 579 // [norm] 580 // [bg] 581 // [q_0,x_0,y_0 q_1,x_0,y_0, q_2,x_0,y_0] 582 // [q_0,x_1,y_0 q_1,x_1,y_0, q_2,x_1,y_0] 583 // [q_0,x_0,y_1 q_1,x_0,y_1, q_2,x_0,y_1] 584 458 585 for (int i = 0; i < numKernels; i++) { 459 586 for (int yOrder = 0, index = i; yOrder <= spatialOrder; yOrder++) { 460 587 for (int xOrder = 0; xOrder <= spatialOrder - yOrder; xOrder++, index += numKernels) { 461 588 // Contribution to chi^2: a_i^2 P_i 462 matrix->data.F64[index][index] -= norm * penalties->data.F32[i]; 589 psAssert(isfinite(penalties->data.F32[i]), "Invalid penalty"); 590 matrix->data.F64[index][index] += norm * penalties->data.F32[i]; 591 if (kernels->mode == PM_SUBTRACTION_MODE_DUAL) { 592 matrix->data.F64[index + numParams + 2][index + numParams + 2] += norm * penalties->data.F32[i]; 593 // matrix[i][i] is ~ (k_i * I_1)(k_i * I_1) 594 // penalties scale with second moments 595 // 596 } 463 597 } 464 598 } … … 467 601 return true; 468 602 } 603 # endif 469 604 470 605 ////////////////////////////////////////////////////////////////////////////////////////////////////////////// … … 476 611 // Calculate the value of a polynomial, specified by coefficients and polynomial values 477 612 double p_pmSubtractionCalculatePolynomial(const psVector *coeff, // Coefficients 478 const psImage *polyValues, // Polynomial values479 int order, // Order of polynomials480 int index, // Index at which to begin481 int step // Step between subsequent indices482 )613 const psImage *polyValues, // Polynomial values 614 int order, // Order of polynomials 615 int index, // Index at which to begin 616 int step // Step between subsequent indices 617 ) 483 618 { 484 619 double sum = 0.0; // Value of the polynomial sum … … 495 630 496 631 double p_pmSubtractionSolutionCoeff(const pmSubtractionKernels *kernels, const psImage *polyValues, 497 int index, bool wantDual)632 int index, bool wantDual) 498 633 { 499 634 #if 0 … … 548 683 const pmSubtractionKernels *kernels = job->args->data[1]; // Kernels 549 684 int index = PS_SCALAR_VALUE(job->args->data[2], S32); // Stamp index 550 551 return pmSubtractionCalculateEquationStamp(stamps, kernels, index); 685 pmSubtractionEquationCalculationMode mode = PS_SCALAR_VALUE(job->args->data[3], S32); // calculation model 686 687 return pmSubtractionCalculateEquationStamp(stamps, kernels, index, mode); 552 688 } 553 689 554 690 bool pmSubtractionCalculateEquationStamp(pmSubtractionStampList *stamps, const pmSubtractionKernels *kernels, 555 int index )691 int index, const pmSubtractionEquationCalculationMode mode) 556 692 { 557 693 PM_ASSERT_SUBTRACTION_STAMP_LIST_NON_NULL(stamps, false); … … 566 702 int numBackground = PM_SUBTRACTION_POLYTERMS(kernels->bgOrder); // Number of background terms 567 703 704 // numKernels is the number of unique kernel images (one for each Gaussian modified by a specific polynomial). 705 // = \sum_i^N_Gaussians [(order + 1) * (order + 2) / 2], eg for 1 Gauss and 1st order, numKernels = 3 706 568 707 // Total number of parameters to solve for: coefficient of each kernel basis function, multipled by the 569 708 // number of coefficients for the spatial polynomial, normalisation and a constant background offset. 570 709 int numParams = numKernels * numSpatial + 1 + numBackground; 710 if (kernels->mode == PM_SUBTRACTION_MODE_DUAL) { 711 // An additional image is convolved 712 numParams += numKernels * numSpatial; 713 } 571 714 572 715 pmSubtractionStamp *stamp = stamps->stamps->data[index]; // Stamp of interest 573 716 psAssert(stamp->status == PM_SUBTRACTION_STAMP_CALCULATE, "We only operate on stamps with this state."); 574 717 575 // Generate convolutions 718 // Generate convolutions: these are generated once and saved 576 719 if (!pmSubtractionConvolveStamp(stamp, kernels, footprint)) { 577 720 psError(PS_ERR_UNKNOWN, false, "Unable to convolve stamp %d.", index); … … 603 746 #endif 604 747 748 // XXX visualize the set of convolved stamps 749 605 750 psImage *polyValues = p_pmSubtractionPolynomial(NULL, spatialOrder, 606 751 stamp->xNorm, stamp->yNorm); // Polynomial terms 607 752 608 bool new = stamp->vector 1? false : true; // Is this a new run?753 bool new = stamp->vector ? false : true; // Is this a new run? 609 754 if (new) { 610 stamp->matrix 1= psImageAlloc(numParams, numParams, PS_TYPE_F64);611 stamp->vector 1= psVectorAlloc(numParams, PS_TYPE_F64);755 stamp->matrix = psImageAlloc(numParams, numParams, PS_TYPE_F64); 756 stamp->vector = psVectorAlloc(numParams, PS_TYPE_F64); 612 757 } 613 758 #ifdef TESTING 614 psImageInit(stamp->matrix 1, NAN);615 psVectorInit(stamp->vector 1, NAN);759 psImageInit(stamp->matrix, NAN); 760 psVectorInit(stamp->vector, NAN); 616 761 #endif 617 762 618 763 bool status; // Status of least-squares matrix/vector calculation 764 765 psKernel *weight = NULL; 766 psKernel *window = NULL; 767 768 #ifdef USE_WEIGHT 769 weight = stamp->weight; 770 #endif 771 #ifdef USE_WINDOW 772 window = stamps->window; 773 #endif 774 619 775 switch (kernels->mode) { 620 776 case PM_SUBTRACTION_MODE_1: 621 status = calculateMatrixVector(stamp->matrix 1, stamp->vector1, stamp->image2, stamp->image1,622 stamp->weight, stamp->convolutions1, kernels, polyValues,623 footprint);777 status = calculateMatrixVector(stamp->matrix, stamp->vector, &stamp->norm, stamp->image2, stamp->image1, 778 weight, window, stamp->convolutions1, kernels, 779 polyValues, footprint, stamps->normWindow, mode); 624 780 break; 625 781 case PM_SUBTRACTION_MODE_2: 626 status = calculateMatrixVector(stamp->matrix 1, stamp->vector1, stamp->image1, stamp->image2,627 stamp->weight, stamp->convolutions2, kernels, polyValues,628 footprint);782 status = calculateMatrixVector(stamp->matrix, stamp->vector, &stamp->norm, stamp->image1, stamp->image2, 783 weight, window, stamp->convolutions2, kernels, 784 polyValues, footprint, stamps->normWindow, mode); 629 785 break; 630 786 case PM_SUBTRACTION_MODE_DUAL: 631 if (new) { 632 stamp->matrix2 = psImageAlloc(numKernels * numSpatial, numKernels * numSpatial, PS_TYPE_F64); 633 stamp->matrixX = psImageAlloc(numParams, numKernels * numSpatial, PS_TYPE_F64); 634 stamp->vector2 = psVectorAlloc(numKernels * numSpatial, PS_TYPE_F64); 635 } 636 #ifdef TESTING 637 psImageInit(stamp->matrix2, NAN); 638 psImageInit(stamp->matrixX, NAN); 639 psVectorInit(stamp->vector2, NAN); 640 #endif 641 status = calculateDualMatrixVector(stamp->matrix1, stamp->vector1, stamp->matrix2, stamp->vector2, 642 stamp->matrixX, stamp->image1, stamp->image2, stamp->weight, 643 stamp->convolutions1, stamp->convolutions2, kernels, polyValues, 644 footprint); 787 status = calculateDualMatrixVector(stamp->matrix, stamp->vector, &stamp->norm, 788 stamp->image1, stamp->image2, 789 weight, window, stamp->convolutions1, stamp->convolutions2, 790 kernels, polyValues, footprint, stamps->normWindow, mode); 645 791 break; 646 792 default: … … 651 797 stamp->status = PM_SUBTRACTION_STAMP_REJECTED; 652 798 psWarning("Rejecting stamp %d (%d,%d) because of bad equation", 653 index, (int)(stamp->x + 0.5), (int)(stamp->y +0.5));799 index, (int)(stamp->x - 0.5), (int)(stamp->y - 0.5)); 654 800 } else { 655 801 stamp->status = PM_SUBTRACTION_STAMP_USED; … … 659 805 { 660 806 psString matrixName = NULL; 661 psStringAppend(&matrixName, "matrix 1_%d.fits", index);807 psStringAppend(&matrixName, "matrix_%d.fits", index); 662 808 psFits *matrixFile = psFitsOpen(matrixName, "w"); 663 809 psFree(matrixName); 664 psFitsWriteImage(matrixFile, NULL, stamp->matrix 1, 0, NULL);810 psFitsWriteImage(matrixFile, NULL, stamp->matrix, 0, NULL); 665 811 psFitsClose(matrixFile); 666 812 667 813 matrixName = NULL; 668 psStringAppend(&matrixName, "vector 1_%d.fits", index);669 psImage *dummy = psImageAlloc(stamp->vector 1->n, 1, PS_TYPE_F64);670 memcpy(dummy->data.F64[0], stamp->vector 1->data.F64,671 PSELEMTYPE_SIZEOF(PS_TYPE_F64) * stamp->vector 1->n);814 psStringAppend(&matrixName, "vector_%d.fits", index); 815 psImage *dummy = psImageAlloc(stamp->vector->n, 1, PS_TYPE_F64); 816 memcpy(dummy->data.F64[0], stamp->vector->data.F64, 817 PSELEMTYPE_SIZEOF(PS_TYPE_F64) * stamp->vector->n); 672 818 matrixFile = psFitsOpen(matrixName, "w"); 673 819 psFree(matrixName); … … 675 821 psFree(dummy); 676 822 psFitsClose(matrixFile); 677 678 if (stamp->vector2) {679 matrixName = NULL;680 psStringAppend(&matrixName, "vector2_%d.fits", index);681 dummy = psImageAlloc(stamp->vector2->n, 1, PS_TYPE_F64);682 memcpy(dummy->data.F64[0], stamp->vector2->data.F64,683 PSELEMTYPE_SIZEOF(PS_TYPE_F64) * stamp->vector2->n);684 matrixFile = psFitsOpen(matrixName, "w");685 psFree(matrixName);686 psFitsWriteImage(matrixFile, NULL, dummy, 0, NULL);687 psFree(dummy);688 psFitsClose(matrixFile);689 }690 691 if (kernels->mode == PM_SUBTRACTION_MODE_DUAL) {692 matrixName = NULL;693 psStringAppend(&matrixName, "matrix2_%d.fits", index);694 matrixFile = psFitsOpen(matrixName, "w");695 psFree(matrixName);696 psFitsWriteImage(matrixFile, NULL, stamp->matrix2, 0, NULL);697 psFitsClose(matrixFile);698 699 matrixName = NULL;700 psStringAppend(&matrixName, "matrixX_%d.fits", index);701 matrixFile = psFitsOpen(matrixName, "w");702 psFree(matrixName);703 psFitsWriteImage(matrixFile, NULL, stamp->matrixX, 0, NULL);704 psFitsClose(matrixFile);705 }706 823 } 707 824 #endif … … 712 829 } 713 830 714 bool pmSubtractionCalculateEquation(pmSubtractionStampList *stamps, const pmSubtractionKernels *kernels) 831 bool pmSubtractionCalculateEquation(pmSubtractionStampList *stamps, const pmSubtractionKernels *kernels, 832 const pmSubtractionEquationCalculationMode mode) 715 833 { 716 834 PM_ASSERT_SUBTRACTION_STAMP_LIST_NON_NULL(stamps, false); … … 727 845 } 728 846 847 if ((stamp->x <= 0.0) && (stamp->y <= 0.0)) { 848 psAbort ("bad stamp"); 849 } 850 if (!isfinite(stamp->x) && !isfinite(stamp->y)) { 851 psAbort ("bad stamp"); 852 } 853 729 854 if (pmSubtractionThreaded()) { 730 855 psThreadJob *job = psThreadJobAlloc("PSMODULES_SUBTRACTION_CALCULATE_EQUATION"); … … 732 857 psArrayAdd(job->args, 1, (pmSubtractionKernels*)kernels); // Casting away const to put on array 733 858 PS_ARRAY_ADD_SCALAR(job->args, i, PS_TYPE_S32); 859 PS_ARRAY_ADD_SCALAR(job->args, mode, PS_TYPE_S32); 734 860 if (!psThreadJobAddPending(job)) { 735 861 psFree(job); … … 738 864 psFree(job); 739 865 } else { 740 pmSubtractionCalculateEquationStamp(stamps, kernels, i );866 pmSubtractionCalculateEquationStamp(stamps, kernels, i, mode); 741 867 } 742 868 } … … 748 874 749 875 pmSubtractionVisualPlotLeastSquares(stamps); 876 pmSubtractionVisualShowKernels((pmSubtractionKernels *)kernels); 877 pmSubtractionVisualShowBasis(stamps); 750 878 751 879 psLogMsg("psModules.imcombine", PS_LOG_INFO, "Calculate equation: %f sec", … … 756 884 } 757 885 758 bool pmSubtractionSolveEquation(pmSubtractionKernels *kernels, const pmSubtractionStampList *stamps) 886 // private functions used on pmSubtractionSolveEquation 887 bool psVectorWriteFile (char *filename, const psVector *vector); 888 bool psFitsWriteImageSimple (char *filename, psImage *image, psMetadata *header); 889 890 psImage *p_pmSubSolve_wUt (psVector *w, psImage *U); 891 psImage *p_pmSubSolve_VwUt (psImage *V, psImage *wUt); 892 893 bool p_pmSubSolve_SetWeights (psVector *wApply, psVector *w, psVector *wMask); 894 895 bool p_pmSubSolve_UtB (psVector **UtB, psImage *U, psVector *B); 896 bool p_pmSubSolve_wUtB (psVector **wUtB, psVector *w, psVector *UtB); 897 bool p_pmSubSolve_VwUtB (psVector **VwUtB, psImage *V, psVector *wUtB); 898 899 bool p_pmSubSolve_Ax (psVector **B, psImage *A, psVector *x); 900 bool p_pmSubSolve_VdV (double *value, psVector *x, psVector *y); 901 bool p_pmSubSolve_y2 (double *y2, pmSubtractionKernels *kernels, const pmSubtractionStampList *stamps); 902 903 psImage *p_pmSubSolve_Xvar (psImage *V, psVector *w); 904 905 double p_pmSubSolve_ChiSquare (pmSubtractionKernels *kernels, const pmSubtractionStampList *stamps); 906 907 bool pmSubtractionSolveEquation(pmSubtractionKernels *kernels, 908 const pmSubtractionStampList *stamps, 909 const pmSubtractionEquationCalculationMode mode) 759 910 { 760 911 PM_ASSERT_SUBTRACTION_KERNELS_NON_NULL(kernels, false); … … 762 913 763 914 // Check inputs 764 int numParams = -1; // Number of parameters 765 int numParams2 = 0; // Number of parameters for part solution (DUAL mode) 915 int numKernels = kernels->num; // Number of kernel basis functions 916 int numSpatial = PM_SUBTRACTION_POLYTERMS(kernels->spatialOrder); // Number of spatial variations 917 int numBackground = PM_SUBTRACTION_POLYTERMS(kernels->bgOrder); // Number of background terms 918 int numParams = numKernels * numSpatial + 1 + numBackground; // Number of parameters being solved for 919 int numSolution1 = numParams, numSolution2 = 0; // Number of parameters for each solution 920 if (kernels->mode == PM_SUBTRACTION_MODE_DUAL) { 921 // An additional image is convolved 922 numSolution2 = numKernels * numSpatial; 923 numParams += numSolution2; 924 } 925 766 926 for (int i = 0; i < stamps->num; i++) { 767 927 pmSubtractionStamp *stamp = stamps->stamps->data[i]; // Stamp of interest … … 771 931 } 772 932 773 PS_ASSERT_VECTOR_NON_NULL(stamp->vector1, false); 774 if (numParams == -1) { 775 numParams = stamp->vector1->n; 776 } 777 PS_ASSERT_VECTOR_SIZE(stamp->vector1, (long)numParams, false); 778 PS_ASSERT_VECTOR_TYPE(stamp->vector1, PS_TYPE_F64, false); 779 PS_ASSERT_IMAGE_NON_NULL(stamp->matrix1, false); 780 PS_ASSERT_IMAGE_SIZE(stamp->matrix1, numParams, numParams, false); 781 PS_ASSERT_IMAGE_TYPE(stamp->matrix1, PS_TYPE_F64, false); 782 783 if (kernels->mode == PM_SUBTRACTION_MODE_DUAL) { 784 PS_ASSERT_IMAGE_NON_NULL(stamp->matrix2, false); 785 PS_ASSERT_IMAGE_NON_NULL(stamp->matrixX, false); 786 if (numParams2 == 0) { 787 numParams2 = stamp->matrix2->numCols; 788 } 789 PS_ASSERT_IMAGE_SIZE(stamp->matrix2, numParams2, numParams2, false); 790 PS_ASSERT_IMAGE_SIZE(stamp->matrixX, numParams, numParams2, false); 791 PS_ASSERT_IMAGE_TYPE(stamp->matrix2, PS_TYPE_F64, false); 792 PS_ASSERT_IMAGE_TYPE(stamp->matrixX, PS_TYPE_F64, false); 793 PS_ASSERT_VECTOR_NON_NULL(stamp->vector2, false); 794 PS_ASSERT_VECTOR_SIZE(stamp->vector2, (long)numParams2, false); 795 PS_ASSERT_VECTOR_TYPE(stamp->vector2, PS_TYPE_F64, false); 796 } 797 } 798 if (numParams == -1) { 799 psError(PS_ERR_BAD_PARAMETER_VALUE, true, "No suitable stamps found."); 800 return NULL; 933 PS_ASSERT_VECTOR_NON_NULL(stamp->vector, false); 934 PS_ASSERT_VECTOR_SIZE(stamp->vector, (long)numParams, false); 935 PS_ASSERT_VECTOR_TYPE(stamp->vector, PS_TYPE_F64, false); 936 PS_ASSERT_IMAGE_NON_NULL(stamp->matrix, false); 937 PS_ASSERT_IMAGE_SIZE(stamp->matrix, numParams, numParams, false); 938 PS_ASSERT_IMAGE_TYPE(stamp->matrix, PS_TYPE_F64, false); 801 939 } 802 940 … … 814 952 psVectorInit(sumVector, 0.0); 815 953 psImageInit(sumMatrix, 0.0); 954 955 psVector *norms = psVectorAllocEmpty(stamps->num, PS_TYPE_F64); // Normalisations 956 816 957 int numStamps = 0; // Number of good stamps 817 958 for (int i = 0; i < stamps->num; i++) { 818 959 pmSubtractionStamp *stamp = stamps->stamps->data[i]; // Stamp of interest 819 820 960 if (stamp->status == PM_SUBTRACTION_STAMP_USED) { 821 822 #ifdef TESTING 823 // XXX double-check for NAN in data: 824 for (int iy = 0; iy < stamp->matrix1->numRows; iy++) { 825 for (int ix = 0; ix < stamp->matrix1->numCols; ix++) { 826 if (!isfinite(stamp->matrix1->data.F64[iy][ix])) { 827 fprintf (stderr, "WARNING: NAN in matrix1\n"); 828 } 829 } 830 } 831 for (int ix = 0; ix < stamp->vector1->n; ix++) { 832 if (!isfinite(stamp->vector1->data.F64[ix])) { 833 fprintf (stderr, "WARNING: NAN in vector1\n"); 834 } 835 } 836 #endif 837 838 (void)psBinaryOp(sumMatrix, sumMatrix, "+", stamp->matrix1); 839 (void)psBinaryOp(sumVector, sumVector, "+", stamp->vector1); 961 (void)psBinaryOp(sumMatrix, sumMatrix, "+", stamp->matrix); 962 (void)psBinaryOp(sumVector, sumVector, "+", stamp->vector); 963 psVectorAppend(norms, stamp->norm); 840 964 pmSubtractionStampPrint(ds9, stamp->x, stamp->y, stamps->footprint, "green"); 841 965 numStamps++; … … 845 969 } 846 970 847 #ifdef TESTING848 for (int ix = 0; ix < sumVector->n; ix++) {849 if (!isfinite(sumVector->data.F64[ix])) {850 fprintf (stderr, "WARNING: NAN in vector1\n");851 }852 }853 #endif854 855 971 #if 0 856 972 int bgIndex = PM_SUBTRACTION_INDEX_BG(kernels); // Index for background … … 858 974 #endif 859 975 860 #ifdef TESTING 861 for (int ix = 0; ix < sumVector->n; ix++) { 862 if (!isfinite(sumVector->data.F64[ix])) { 863 fprintf (stderr, "WARNING: NAN in vector1\n"); 864 } 865 } 976 psVector *solution = NULL; // Solution to equation! 977 solution = psVectorAlloc(numParams, PS_TYPE_F64); 978 psVectorInit(solution, 0); 979 980 #if 0 981 // Regular, straight-forward solution 982 solution = psMatrixSolveSVD(solution, sumMatrix, sumVector, NAN); 983 #else 866 984 { 867 psImage *inverse = psMatrixInvert(NULL, sumMatrix, NULL); 868 psFits *fits = psFitsOpen("matrixInv.fits", "w"); 869 psFitsWriteImage(fits, NULL, inverse, 0, NULL); 870 psFitsClose(fits); 871 psFree(inverse); 872 } 873 { 874 psImage *X = psMatrixInvert(NULL, sumMatrix, NULL); 875 psImage *Xt = psMatrixTranspose(NULL, X); 876 psImage *XtX = psMatrixMultiply(NULL, Xt, X); 877 psFits *fits = psFitsOpen("matrixErr.fits", "w"); 878 psFitsWriteImage(fits, NULL, XtX, 0, NULL); 879 psFitsClose(fits); 880 psFree(X); 881 psFree(Xt); 882 psFree(XtX); 883 } 884 #endif 885 886 psVector *permutation = NULL; // Permutation vector, required for LU decomposition 887 psImage *luMatrix = psMatrixLUDecomposition(NULL, &permutation, sumMatrix); 985 // Solve normalisation and background separately 986 int normIndex = PM_SUBTRACTION_INDEX_NORM(kernels); // Index for normalisation 987 int bgIndex = PM_SUBTRACTION_INDEX_BG(kernels); // Index for background 988 989 psStats *stats = psStatsAlloc(PS_STAT_ROBUST_MEDIAN); // Statistics for norm 990 if (!psVectorStats(stats, norms, NULL, NULL, 0)) { 991 psError(PS_ERR_UNKNOWN, false, "Unable to determine median normalisation"); 992 psFree(stats); 993 psFree(sumMatrix); 994 psFree(sumVector); 995 psFree(norms); 996 return false; 997 } 998 999 double normValue = stats->robustMedian; 1000 // double bgValue = 0.0; 1001 1002 psFree(stats); 1003 1004 fprintf(stderr, "Norm: %lf\n", normValue); 1005 1006 // Solve kernel components 1007 for (int i = 0; i < numSolution1; i++) { 1008 sumVector->data.F64[i] -= normValue * sumMatrix->data.F64[normIndex][i]; 1009 1010 sumMatrix->data.F64[i][normIndex] = 0.0; 1011 sumMatrix->data.F64[normIndex][i] = 0.0; 1012 } 1013 sumVector->data.F64[bgIndex] -= normValue * sumMatrix->data.F64[normIndex][bgIndex]; 1014 sumMatrix->data.F64[bgIndex][normIndex] = 0.0; 1015 sumMatrix->data.F64[normIndex][bgIndex] = 0.0; 1016 1017 sumMatrix->data.F64[normIndex][normIndex] = 1.0; 1018 sumVector->data.F64[normIndex] = 0.0; 1019 1020 solution = psMatrixSolveSVD(solution, sumMatrix, sumVector, NAN); 1021 1022 solution->data.F64[normIndex] = normValue; 1023 } 1024 # endif 1025 1026 if (!kernels->solution1) { 1027 kernels->solution1 = psVectorAlloc(sumVector->n, PS_TYPE_F64); 1028 psVectorInit(kernels->solution1, 0.0); 1029 } 1030 1031 // only update the solutions that we chose to calculate: 1032 if (mode & PM_SUBTRACTION_EQUATION_NORM) { 1033 int normIndex = PM_SUBTRACTION_INDEX_NORM(kernels); // Index for normalisation 1034 kernels->solution1->data.F64[normIndex] = solution->data.F64[normIndex]; 1035 } 1036 if (mode & PM_SUBTRACTION_EQUATION_BG) { 1037 int bgIndex = PM_SUBTRACTION_INDEX_BG(kernels); // Index in matrix for background 1038 kernels->solution1->data.F64[bgIndex] = solution->data.F64[bgIndex]; 1039 } 1040 if (mode & PM_SUBTRACTION_EQUATION_KERNELS) { 1041 int numKernels = kernels->num; 1042 int spatialOrder = kernels->spatialOrder; // Order of spatial variation 1043 int numPoly = PM_SUBTRACTION_POLYTERMS(spatialOrder); // Number of polynomial terms 1044 for (int i = 0; i < numKernels * numPoly; i++) { 1045 kernels->solution1->data.F64[i] = solution->data.F64[i]; 1046 } 1047 } 1048 1049 psFree(solution); 1050 psFree(sumVector); 888 1051 psFree(sumMatrix); 889 if (!luMatrix) {890 psError(PS_ERR_UNKNOWN, true, "LU Decomposition of least-squares matrix failed.\n");891 psFree(sumVector);892 psFree(luMatrix);893 psFree(permutation);894 return NULL;895 }896 kernels->solution1 = psMatrixLUSolution(kernels->solution1, luMatrix, sumVector, permutation);897 1052 898 1053 #ifdef TESTING … … 900 1055 for (int ix = 0; ix < kernels->solution1->n; ix++) { 901 1056 if (!isfinite(kernels->solution1->data.F64[ix])) { 902 fprintf (stderr, "WARNING: NAN in vector1\n"); 903 } 904 } 905 #endif 906 907 psFree(sumVector); 908 psFree(luMatrix); 909 psFree(permutation); 910 if (!kernels->solution1) { 911 psError(PS_ERR_UNKNOWN, true, "Failed to solve the least-squares system.\n"); 912 return NULL; 913 } 1057 fprintf (stderr, "WARNING: NAN in vector\n"); 1058 } 1059 } 1060 #endif 1061 914 1062 } else { 915 1063 // Dual convolution solution 916 1064 917 1065 // Accumulation of stamp matrices/vectors 918 psImage *sumMatrix1 = psImageAlloc(numParams, numParams, PS_TYPE_F64); 919 psImage *sumMatrix2 = psImageAlloc(numParams2, numParams2, PS_TYPE_F64); 920 psImage *sumMatrixX = psImageAlloc(numParams, numParams2, PS_TYPE_F64); 921 psVector *sumVector1 = psVectorAlloc(numParams, PS_TYPE_F64); 922 psVector *sumVector2 = psVectorAlloc(numParams, PS_TYPE_F64); 923 psImageInit(sumMatrix1, 0.0); 924 psImageInit(sumMatrix2, 0.0); 925 psImageInit(sumMatrixX, 0.0); 926 psVectorInit(sumVector1, 0.0); 927 psVectorInit(sumVector2, 0.0); 1066 psImage *sumMatrix = psImageAlloc(numParams, numParams, PS_TYPE_F64); 1067 psVector *sumVector = psVectorAlloc(numParams, PS_TYPE_F64); 1068 psImageInit(sumMatrix, 0.0); 1069 psVectorInit(sumVector, 0.0); 1070 1071 psVector *norms = psVectorAllocEmpty(stamps->num, PS_TYPE_F64); // Normalisations 928 1072 929 1073 int numStamps = 0; // Number of good stamps … … 931 1075 pmSubtractionStamp *stamp = stamps->stamps->data[i]; // Stamp of interest 932 1076 if (stamp->status == PM_SUBTRACTION_STAMP_USED) { 933 (void)psBinaryOp(sumMatrix 1, sumMatrix1, "+", stamp->matrix1);934 (void)psBinaryOp(sum Matrix2, sumMatrix2, "+", stamp->matrix2);935 (void)psBinaryOp(sumMatrixX, sumMatrixX, "+", stamp->matrixX); 936 (void)psBinaryOp(sumVector1, sumVector1, "+", stamp->vector1);937 (void)psBinaryOp(sumVector2, sumVector2, "+", stamp->vector2); 1077 (void)psBinaryOp(sumMatrix, sumMatrix, "+", stamp->matrix); 1078 (void)psBinaryOp(sumVector, sumVector, "+", stamp->vector); 1079 1080 psVectorAppend(norms, stamp->norm); 1081 938 1082 pmSubtractionStampPrint(ds9, stamp->x, stamp->y, stamps->footprint, "green"); 939 1083 numStamps++; … … 941 1085 } 942 1086 943 int bgIndex = PM_SUBTRACTION_INDEX_BG(kernels); // Index for background944 calculatePenalty(sumMatrix1, sumVector1, kernels, sumMatrix1->data.F64[bgIndex][bgIndex]);945 calculatePenalty(sumMatrix2, sumVector2, kernels, -sumMatrix1->data.F64[bgIndex][bgIndex]);946 947 psImage *sumMatrix = NULL; // Combined matrix948 psVector *sumVector = NULL; // Combined vector949 calculateEquationDual(&sumMatrix, &sumVector, sumMatrix1, sumMatrix2,950 sumMatrixX, sumVector1, sumVector2);951 952 1087 #ifdef TESTING 1088 psFitsWriteImageSimple ("sumMatrix.fits", sumMatrix, NULL); 1089 psVectorWriteFile("sumVector.dat", sumVector); 1090 #endif 1091 1092 #if 1 1093 // int bgIndex = PM_SUBTRACTION_INDEX_BG(kernels); // Index for background 1094 // calculatePenalty(sumMatrix, sumVector, kernels, sumMatrix->data.F64[bgIndex][bgIndex]); 1095 1096 int normIndex = PM_SUBTRACTION_INDEX_NORM(kernels); // Index for normalisation 1097 calculatePenalty(sumMatrix, sumVector, kernels, sumMatrix->data.F64[normIndex][normIndex] / 1000.0); 1098 #endif 1099 1100 psVector *solution = NULL; // Solution to equation! 1101 solution = psVectorAlloc(numParams, PS_TYPE_F64); 1102 psVectorInit(solution, 0); 1103 1104 #if 0 1105 // Regular, straight-forward solution 1106 solution = psMatrixSolveSVD(solution, sumMatrix, sumVector, NAN); 1107 #else 953 1108 { 954 psFits *fits = psFitsOpen("sumMatrix.fits", "w"); 955 psFitsWriteImage(fits, NULL, sumMatrix, 0, NULL); 956 psFitsClose(fits); 957 } 958 { 959 psImage *image = psImageAlloc(1, numParams + numParams2, PS_TYPE_F64); 960 psFits *fits = psFitsOpen("sumVector.fits", "w"); 961 for (int i = 0; i < numParams + numParams2; i++) { 962 image->data.F64[0][i] = sumVector->data.F64[i]; 963 } 964 psFitsWriteImage(fits, NULL, image, 0, NULL); 965 psFree(image); 966 psFitsClose(fits); 967 } 968 #endif 969 970 psVector *solution = NULL; // Solution to equation! 971 { 972 solution = psMatrixSolveSVD(solution, sumMatrix, sumVector); 973 if (!solution) { 974 psError(PS_ERR_UNKNOWN, false, "SVD solution of least-squares equation failed.\n"); 1109 // Solve normalisation and background separately 1110 int normIndex = PM_SUBTRACTION_INDEX_NORM(kernels); // Index for normalisation 1111 int bgIndex = PM_SUBTRACTION_INDEX_BG(kernels); // Index for background 1112 1113 #if 0 1114 psImage *normMatrix = psImageAlloc(2, 2, PS_TYPE_F64); 1115 psVector *normVector = psVectorAlloc(2, PS_TYPE_F64); 1116 1117 normMatrix->data.F64[0][0] = sumMatrix->data.F64[normIndex][normIndex]; 1118 normMatrix->data.F64[1][1] = sumMatrix->data.F64[bgIndex][bgIndex]; 1119 normMatrix->data.F64[0][1] = normMatrix->data.F64[1][0] = sumMatrix->data.F64[normIndex][bgIndex]; 1120 1121 normVector->data.F64[0] = sumVector->data.F64[normIndex]; 1122 normVector->data.F64[1] = sumVector->data.F64[bgIndex]; 1123 1124 psVector *normSolution = psMatrixSolveSVD(NULL, normMatrix, normVector, NAN); 1125 1126 double normValue = normSolution->data.F64[0]; 1127 double bgValue = normSolution->data.F64[1]; 1128 1129 psFree(normMatrix); 1130 psFree(normVector); 1131 psFree(normSolution); 1132 #endif 1133 1134 psStats *stats = psStatsAlloc(PS_STAT_ROBUST_MEDIAN); // Statistics for norm 1135 if (!psVectorStats(stats, norms, NULL, NULL, 0)) { 1136 psError(PS_ERR_UNKNOWN, false, "Unable to determine median normalisation"); 1137 psFree(stats); 975 1138 psFree(sumMatrix); 976 1139 psFree(sumVector); 977 return NULL; 978 } 979 980 int numSpatial = PM_SUBTRACTION_POLYTERMS(kernels->spatialOrder); // Number of spatial variations 981 int numKernels = kernels->num; // Number of kernel basis functions 982 983 // Remove a kernel basis for image 1 from the equation 984 #define MASK_BASIS_1(INDEX) \ 985 { \ 986 for (int j = 0, index = INDEX; j < numSpatial; j++, index += numKernels) { \ 987 for (int k = 0; k < numParams2; k++) { \ 988 sumMatrix1->data.F64[k][index] = 0.0; \ 989 sumMatrix1->data.F64[index][k] = 0.0; \ 990 sumMatrixX->data.F64[k][index] = 0.0; \ 991 } \ 992 sumMatrix1->data.F64[bgIndex][index] = 0.0; \ 993 sumMatrix1->data.F64[index][bgIndex] = 0.0; \ 994 sumMatrix1->data.F64[normIndex][index] = 0.0; \ 995 sumMatrix1->data.F64[index][normIndex] = 0.0; \ 996 sumMatrix1->data.F64[index][index] = 1.0; \ 997 sumVector1->data.F64[index] = 0.0; \ 998 } \ 999 } 1000 1001 // Remove a kernel basis for image 2 from the equation 1002 #define MASK_BASIS_2(INDEX) \ 1003 { \ 1004 for (int j = 0, index = INDEX; j < numSpatial; j++, index += numKernels) { \ 1005 for (int k = 0; k < numParams2; k++) { \ 1006 sumMatrix2->data.F64[k][index] = 0.0; \ 1007 sumMatrix2->data.F64[index][k] = 0.0; \ 1008 sumMatrixX->data.F64[index][k] = 0.0; \ 1009 } \ 1010 sumMatrix2->data.F64[index][index] = 1.0; \ 1011 sumMatrixX->data.F64[index][normIndex] = 0.0; \ 1012 sumMatrixX->data.F64[index][bgIndex] = 0.0; \ 1013 sumVector2->data.F64[index] = 0.0; \ 1014 } \ 1015 } 1016 1017 #define TOL 1.0e-5 1018 int normIndex = PM_SUBTRACTION_INDEX_NORM(kernels); // Index for normalisation 1019 double norm = fabs(solution->data.F64[normIndex]); // Normalisation 1020 double thresh = norm * TOL; // Threshold for low parameters 1021 for (int i = 0; i < numKernels; i++) { 1022 // Getting 0th order parameter value. In the presence of spatial variation, the actual value 1023 // of the parameter will vary over the image. We are in effect getting the value in the 1024 // centre of the image. If we use different polynomial functions (e.g., Chebyshev), we may 1025 // have to change this to properly determine the value of the parameter at the centre. 1026 double param1 = solution->data.F64[i], 1027 param2 = solution->data.F64[numParams + i]; // Parameters of interest 1028 bool mask1 = false, mask2 = false; // Masked the parameter? 1029 if (fabs(param1) < thresh) { 1030 psTrace("psModules.imcombine", 7, "Parameter %d: 1 below threshold\n", i); 1031 MASK_BASIS_1(i); 1032 mask1 = true; 1033 } 1034 if (fabs(param2) < thresh) { 1035 psTrace("psModules.imcombine", 7, "Parameter %d: 2 below threshold\n", i); 1036 MASK_BASIS_2(i); 1037 mask2 = true; 1038 } 1039 1040 if (!mask1 && !mask2) { 1041 if (fabs(param1) < fabs(param2)) { 1042 psTrace("psModules.imcombine", 7, "Parameter %d: 1 < 2\n", i); 1043 MASK_BASIS_1(i); 1044 } else { 1045 psTrace("psModules.imcombine", 7, "Parameter %d: 2 < 1\n", i); 1046 MASK_BASIS_2(i); 1047 } 1048 } 1049 } 1050 } 1051 1052 calculateEquationDual(&sumMatrix, &sumVector, sumMatrix1, sumMatrix2, 1053 sumMatrixX, sumVector1, sumVector2); 1140 psFree(norms); 1141 return false; 1142 } 1143 1144 double normValue = stats->robustMedian; 1145 1146 psFree(stats); 1147 1148 fprintf(stderr, "Norm: %lf\n", normValue); 1149 1150 // Solve kernel components 1151 for (int i = 0; i < numSolution2; i++) { 1152 sumVector->data.F64[i] -= normValue * sumMatrix->data.F64[normIndex][i]; 1153 sumVector->data.F64[i + numSolution1] -= normValue * sumMatrix->data.F64[normIndex][i + numSolution1]; 1154 1155 sumMatrix->data.F64[i][normIndex] = 0.0; 1156 sumMatrix->data.F64[normIndex][i] = 0.0; 1157 1158 sumMatrix->data.F64[i + numSolution1][normIndex] = 0.0; 1159 sumMatrix->data.F64[normIndex][i + numSolution1] = 0.0; 1160 } 1161 sumVector->data.F64[bgIndex] -= normValue * sumMatrix->data.F64[normIndex][bgIndex]; 1162 sumMatrix->data.F64[bgIndex][normIndex] = 0.0; 1163 sumMatrix->data.F64[normIndex][bgIndex] = 0.0; 1164 1165 sumMatrix->data.F64[normIndex][normIndex] = 1.0; 1166 1167 sumVector->data.F64[normIndex] = 0.0; 1168 1169 solution = psMatrixSolveSVD(solution, sumMatrix, sumVector, NAN); 1170 1171 solution->data.F64[normIndex] = normValue; 1172 } 1173 #endif 1174 1054 1175 1055 1176 #ifdef TESTING 1056 { 1057 psFits *fits = psFitsOpen("sumMatrixFix.fits", "w"); 1058 psFitsWriteImage(fits, NULL, sumMatrix, 0, NULL); 1059 psFitsClose(fits); 1060 } 1061 { 1062 psImage *image = psImageAlloc(1, numParams + numParams2, PS_TYPE_F64); 1063 psFits *fits = psFitsOpen("sumVectorFix.fits", "w"); 1064 for (int i = 0; i < numParams + numParams2; i++) { 1065 image->data.F64[0][i] = sumVector->data.F64[i]; 1066 } 1067 psFitsWriteImage(fits, NULL, image, 0, NULL); 1068 psFree(image); 1069 psFitsClose(fits); 1070 } 1071 #endif 1072 1073 solution = psMatrixSolveSVD(solution, sumMatrix, sumVector); 1074 if (!solution) { 1075 psError(PS_ERR_UNKNOWN, false, "SVD solution of least-squares equation failed.\n"); 1076 psFree(sumMatrix); 1077 psFree(sumVector); 1078 return NULL; 1079 } 1080 1081 psFree(sumMatrix1); 1082 psFree(sumMatrix2); 1083 psFree(sumMatrixX); 1084 psFree(sumVector1); 1085 psFree(sumVector2); 1177 for (int i = 0; i < solution->n; i++) { 1178 fprintf(stderr, "Dual solution %d: %lf\n", i, solution->data.F64[i]); 1179 } 1180 #endif 1086 1181 1087 1182 psFree(sumMatrix); 1088 1183 psFree(sumVector); 1089 1184 1090 #ifdef TESTING 1091 { 1092 psImage *image = psImageAlloc(1, numParams + numParams2, PS_TYPE_F64); 1093 psFits *fits = psFitsOpen("solnVector.fits", "w"); 1094 for (int i = 0; i < numParams + numParams2; i++) { 1095 image->data.F64[0][i] = solution->data.F64[i]; 1096 } 1097 psFitsWriteImage(fits, NULL, image, 0, NULL); 1098 psFree(image); 1099 psFitsClose(fits); 1100 } 1101 #endif 1185 psFree(norms); 1102 1186 1103 1187 if (!kernels->solution1) { 1104 kernels->solution1 = psVectorAlloc(numParams, PS_TYPE_F64); 1188 kernels->solution1 = psVectorAlloc(numSolution1, PS_TYPE_F64); 1189 psVectorInit (kernels->solution1, 0.0); 1105 1190 } 1106 1191 if (!kernels->solution2) { 1107 kernels->solution2 = psVectorAlloc(numParams2, PS_TYPE_F64); 1108 } 1109 1110 memcpy(kernels->solution1->data.F64, solution->data.F64, numParams * PSELEMTYPE_SIZEOF(PS_TYPE_F64)); 1111 memcpy(kernels->solution2->data.F64, &solution->data.F64[numParams], 1112 numParams2 * PSELEMTYPE_SIZEOF(PS_TYPE_F64)); 1192 kernels->solution2 = psVectorAlloc(numSolution2, PS_TYPE_F64); 1193 psVectorInit (kernels->solution2, 0.0); 1194 } 1195 1196 // only update the solutions that we chose to calculate: 1197 if (mode & PM_SUBTRACTION_EQUATION_NORM) { 1198 int normIndex = PM_SUBTRACTION_INDEX_NORM(kernels); // Index for normalisation 1199 kernels->solution1->data.F64[normIndex] = solution->data.F64[normIndex]; 1200 } 1201 if (mode & PM_SUBTRACTION_EQUATION_BG) { 1202 int bgIndex = PM_SUBTRACTION_INDEX_BG(kernels); // Index in matrix for background 1203 kernels->solution1->data.F64[bgIndex] = solution->data.F64[bgIndex]; 1204 } 1205 if (mode & PM_SUBTRACTION_EQUATION_KERNELS) { 1206 int numKernels = kernels->num; 1207 for (int i = 0; i < numKernels * numSpatial; i++) { 1208 // XXX fprintf (stderr, "keep\n"); 1209 kernels->solution1->data.F64[i] = solution->data.F64[i]; 1210 kernels->solution2->data.F64[i] = solution->data.F64[i + numSolution1]; 1211 } 1212 } 1213 1214 1215 memcpy(kernels->solution1->data.F64, solution->data.F64, 1216 numSolution1 * PSELEMTYPE_SIZEOF(PS_TYPE_F64)); 1217 memcpy(kernels->solution2->data.F64, &solution->data.F64[numSolution1], 1218 numSolution2 * PSELEMTYPE_SIZEOF(PS_TYPE_F64)); 1113 1219 1114 1220 psFree(solution); … … 1131 1237 } 1132 1238 1133 pmSubtractionVisualPlotLeastSquares((pmSubtractionStampList *) stamps); //casting away const1239 // pmSubtractionVisualPlotLeastSquares((pmSubtractionStampList *) stamps); //casting away const 1134 1240 return true; 1135 1241 } 1136 1242 1243 bool pmSubtractionResidualStats(psVector *fSigRes, psVector *fMaxRes, psVector *fMinRes, psKernel *target, psKernel *source, psKernel *residual, double norm, int footprint) { 1244 1245 // XXX measure some useful stats on the residuals 1246 float sum = 0.0; 1247 float peak = 0.0; 1248 for (int y = - footprint; y <= footprint; y++) { 1249 for (int x = - footprint; x <= footprint; x++) { 1250 sum += 0.5*(target->kernel[y][x] + source->kernel[y][x] * norm); 1251 peak = PS_MAX(peak, 0.5*(target->kernel[y][x] + source->kernel[y][x] * norm)); 1252 } 1253 } 1254 1255 // only count pixels with more than X% of the source flux 1256 // calculate stdev(dflux) 1257 float dflux1 = 0.0; 1258 float dflux2 = 0.0; 1259 int npix = 0; 1260 1261 float dmax = 0.0; 1262 float dmin = 0.0; 1263 1264 for (int y = - footprint; y <= footprint; y++) { 1265 for (int x = - footprint; x <= footprint; x++) { 1266 float dflux = 0.5*(target->kernel[y][x] + source->kernel[y][x] * norm); 1267 if (dflux < 0.02*sum) continue; 1268 dflux1 += residual->kernel[y][x]; 1269 dflux2 += PS_SQR(residual->kernel[y][x]); 1270 dmax = PS_MAX(residual->kernel[y][x], dmax); 1271 dmin = PS_MIN(residual->kernel[y][x], dmin); 1272 npix ++; 1273 } 1274 } 1275 float sigma = sqrt(dflux2 / npix - PS_SQR(dflux1/npix)); 1276 if (!isfinite(sum)) return false; 1277 if (!isfinite(dmax)) return false; 1278 if (!isfinite(dmin)) return false; 1279 if (!isfinite(peak)) return false; 1280 1281 // fprintf (stderr, "sum: %f, peak: %f, sigma: %f, fsigma: %f, fmax: %f, fmin: %f\n", sum, peak, sigma, sigma/sum, dmax/peak, dmin/peak); 1282 psVectorAppend(fSigRes, sigma/sum); 1283 psVectorAppend(fMaxRes, dmax/peak); 1284 psVectorAppend(fMinRes, dmin/peak); 1285 return true; 1286 } 1287 1137 1288 psVector *pmSubtractionCalculateDeviations(pmSubtractionStampList *stamps, 1138 constpmSubtractionKernels *kernels)1289 pmSubtractionKernels *kernels) 1139 1290 { 1140 1291 PM_ASSERT_SUBTRACTION_STAMP_LIST_NON_NULL(stamps, NULL); … … 1151 1302 psKernel *residual = psKernelAlloc(-footprint, footprint, -footprint, footprint); // Residual image 1152 1303 1304 // set up holding images for the visualization 1305 pmSubtractionVisualShowFitInit (stamps); 1306 1307 psVector *fSigRes = psVectorAllocEmpty(stamps->num, PS_TYPE_F32); 1308 psVector *fMinRes = psVectorAllocEmpty(stamps->num, PS_TYPE_F32); 1309 psVector *fMaxRes = psVectorAllocEmpty(stamps->num, PS_TYPE_F32); 1310 1311 // we want to save the residual images for the 9 brightest stamps. 1312 // identify the 9 brightest stamps 1313 psVector *keepStamps = psVectorAlloc(stamps->num, PS_TYPE_S32); 1314 psVectorInit (keepStamps, 0); 1315 { 1316 psVector *flux = psVectorAlloc(stamps->num, PS_TYPE_F32); 1317 psVectorInit (flux, 0.0); 1318 1319 for (int i = 0; i < stamps->num; i++) { 1320 pmSubtractionStamp *stamp = stamps->stamps->data[i]; 1321 if (!isfinite(stamp->flux)) continue; 1322 flux->data.F32[i] = stamp->flux; 1323 } 1324 1325 psVector *index = psVectorSortIndex(NULL, flux); 1326 for (int i = 0; (i < stamps->num) && (i < 9); i++) { 1327 int n = stamps->num - i - 1; 1328 keepStamps->data.S32[index->data.S32[n]] = 1; 1329 fprintf (stderr, "keeping %d (%d of %d)\n", index->data.S32[n], n, 9); 1330 } 1331 psFree (flux); 1332 psFree (index); 1333 1334 // this function is called multiple times in the iteration, but 1335 // we only know after the interation is done if we will try again. 1336 // therefore we must save the sample each time, and blow away the old one 1337 // if it exists. 1338 psFree (kernels->sampleStamps); 1339 kernels->sampleStamps = psArrayAllocEmpty(9); 1340 } 1341 1342 psString log = psStringCopy("Deviations:\n"); // Log message with deviations 1153 1343 for (int i = 0; i < stamps->num; i++) { 1154 1344 pmSubtractionStamp *stamp = stamps->stamps->data[i]; // The stamp of interest … … 1210 1400 for (int y = - footprint; y <= footprint; y++) { 1211 1401 for (int x = - footprint; x <= footprint; x++) { 1212 residual->kernel[y][x] -= convolution->kernel[y][x] * coefficient;1402 residual->kernel[y][x] += convolution->kernel[y][x] * coefficient; 1213 1403 } 1214 1404 } 1215 1405 } 1406 1407 // XXX visualize the target, source, convolution and residual 1408 pmSubtractionVisualShowFitAddStamp (target, source, residual, background, norm, i); 1409 1216 1410 for (int y = - footprint; y <= footprint; y++) { 1217 1411 for (int x = - footprint; x <= footprint; x++) { 1218 residual->kernel[y][x] += target->kernel[y][x] - background - source->kernel[y][x] * norm; 1219 } 1220 } 1412 residual->kernel[y][x] += background + source->kernel[y][x] * norm - target->kernel[y][x]; 1413 } 1414 } 1415 1416 if (keepStamps->data.S32[i]) { 1417 psImage *sample = psImageCopy(NULL, residual->image, PS_TYPE_F32); 1418 psArrayAdd (kernels->sampleStamps, 9, sample); 1419 psFree (sample); 1420 } 1421 1422 pmSubtractionResidualStats(fSigRes, fMaxRes, fMinRes, target, source, residual, norm, footprint); 1423 1221 1424 } else { 1222 1425 // Dual convolution … … 1234 1437 for (int y = - footprint; y <= footprint; y++) { 1235 1438 for (int x = - footprint; x <= footprint; x++) { 1236 residual->kernel[y][x] += conv2->kernel[y][x] * coeff2 -conv1->kernel[y][x] * coeff1;1439 residual->kernel[y][x] += conv2->kernel[y][x] * coeff2 + conv1->kernel[y][x] * coeff1; 1237 1440 } 1238 1441 } 1239 1442 } 1443 1444 // XXX visualize the target, source, convolution and residual 1445 pmSubtractionVisualShowFitAddStamp (image2, image1, residual, background, norm, i); 1446 1240 1447 for (int y = - footprint; y <= footprint; y++) { 1241 1448 for (int x = - footprint; x <= footprint; x++) { 1242 residual->kernel[y][x] += image2->kernel[y][x] - background - image1->kernel[y][x] * norm; 1243 } 1244 } 1449 residual->kernel[y][x] += background + image1->kernel[y][x] * norm - image2->kernel[y][x]; 1450 } 1451 } 1452 if (keepStamps->data.S32[i]) { 1453 psImage *sample = psImageCopy(NULL, residual->image, PS_TYPE_F32); 1454 psArrayAdd (kernels->sampleStamps, 9, sample); 1455 psFree (sample); 1456 } 1457 1458 pmSubtractionResidualStats(fSigRes, fMaxRes, fMinRes, image1, image2, residual, norm, footprint); 1245 1459 } 1246 1460 … … 1257 1471 deviations->data.F32[i] = devNorm * deviation; 1258 1472 psTrace("psModules.imcombine", 5, "Deviation for stamp %d (%d,%d): %f\n", 1259 i, (int)(stamp->x + 0.5), (int)(stamp->y + 0.5), deviations->data.F32[i]); 1473 i, (int)(stamp->x - 0.5), (int)(stamp->y - 0.5), deviations->data.F32[i]); 1474 psStringAppend(&log, "Stamp %d (%d,%d): %f\n", 1475 i, (int)(stamp->x - 0.5), (int)(stamp->y - 0.5), deviations->data.F32[i]); 1260 1476 if (!isfinite(deviations->data.F32[i])) { 1261 1477 stamp->status = PM_SUBTRACTION_STAMP_REJECTED; 1262 1478 psTrace("psModules.imcombine", 5, 1263 1479 "Rejecting stamp %d (%d,%d) because of non-finite deviation\n", 1264 i, (int)(stamp->x + 0.5), (int)(stamp->y +0.5));1480 i, (int)(stamp->x - 0.5), (int)(stamp->y - 0.5)); 1265 1481 continue; 1266 1482 } … … 1302 1518 1303 1519 } 1520 1521 psLogMsg("psModules.imcombine", PS_LOG_DETAIL, "%s", log); 1522 psFree(log); 1523 1524 // calculate and report the normalization and background for the image center 1525 { 1526 polyValues = p_pmSubtractionPolynomial(polyValues, kernels->spatialOrder, 0.0, 0.0); 1527 double norm = p_pmSubtractionSolutionNorm(kernels); // Normalisation 1528 double background = p_pmSubtractionSolutionBackground(kernels, polyValues);// Difference in background 1529 psLogMsg("psModules.imcombine", PS_LOG_INFO, "normalization: %f, background: %f", norm, background); 1530 1531 pmSubtractionVisualShowFit(norm); 1532 pmSubtractionVisualPlotFit(kernels); 1533 1534 psStats *stats = psStatsAlloc(PS_STAT_ROBUST_MEDIAN | PS_STAT_ROBUST_STDEV); 1535 psVectorStats (stats, fSigRes, NULL, NULL, 0); 1536 kernels->fSigResMean = stats->robustMedian; 1537 kernels->fSigResStdev = stats->robustStdev; 1538 1539 psStatsInit (stats); 1540 psVectorStats (stats, fMaxRes, NULL, NULL, 0); 1541 kernels->fMaxResMean = stats->robustMedian; 1542 kernels->fMaxResStdev = stats->robustStdev; 1543 1544 psStatsInit (stats); 1545 psVectorStats (stats, fMinRes, NULL, NULL, 0); 1546 kernels->fMinResMean = stats->robustMedian; 1547 kernels->fMinResStdev = stats->robustStdev; 1548 1549 // XXX save these values somewhere 1550 psLogMsg("psModules.imcombine", PS_LOG_INFO, "fSigma: %f +/- %f, fMaxRes: %f +/- %f, fMinRes: %f +/- %f", 1551 kernels->fSigResMean, kernels->fSigResStdev, 1552 kernels->fMaxResMean, kernels->fMaxResStdev, 1553 kernels->fMinResMean, kernels->fMinResStdev); 1554 1555 psFree (fSigRes); 1556 psFree (fMaxRes); 1557 psFree (fMinRes); 1558 psFree (stats); 1559 } 1560 1304 1561 psFree(residual); 1305 1562 psFree(polyValues); 1306 1563 1564 1307 1565 return deviations; 1308 1566 } 1567 1568 // we are supplied U, not Ut; w represents a diagonal matrix (also, we apply 1/w instead of w) 1569 psImage *p_pmSubSolve_wUt (psVector *w, psImage *U) { 1570 1571 psAssert (w->n == U->numCols, "w and U dimensions do not match"); 1572 1573 // wUt has dimensions transposed relative to Ut. 1574 psImage *wUt = psImageAlloc (U->numRows, U->numCols, PS_TYPE_F64); 1575 psImageInit (wUt, 0.0); 1576 1577 for (int i = 0; i < wUt->numCols; i++) { 1578 for (int j = 0; j < wUt->numRows; j++) { 1579 if (!isfinite(w->data.F64[j])) continue; 1580 if (w->data.F64[j] == 0.0) continue; 1581 wUt->data.F64[j][i] = U->data.F64[i][j] / w->data.F64[j]; 1582 } 1583 } 1584 return wUt; 1585 } 1586 1587 // XXX this is just standard matrix multiplication: use psMatrixMultiply? 1588 psImage *p_pmSubSolve_VwUt (psImage *V, psImage *wUt) { 1589 1590 psAssert (V->numCols == wUt->numRows, "matrix dimensions do not match"); 1591 1592 psImage *Ainv = psImageAlloc (wUt->numCols, V->numRows, PS_TYPE_F64); 1593 1594 for (int i = 0; i < Ainv->numCols; i++) { 1595 for (int j = 0; j < Ainv->numRows; j++) { 1596 double sum = 0.0; 1597 for (int k = 0; k < V->numCols; k++) { 1598 sum += V->data.F64[j][k] * wUt->data.F64[k][i]; 1599 } 1600 Ainv->data.F64[j][i] = sum; 1601 } 1602 } 1603 return Ainv; 1604 } 1605 1606 // we are supplied U, not Ut 1607 bool p_pmSubSolve_UtB (psVector **UtB, psImage *U, psVector *B) { 1608 1609 psAssert (U->numRows == B->n, "U and B dimensions do not match"); 1610 1611 UtB[0] = psVectorRecycle (UtB[0], U->numCols, PS_TYPE_F64); 1612 1613 for (int i = 0; i < U->numCols; i++) { 1614 double sum = 0.0; 1615 for (int j = 0; j < U->numRows; j++) { 1616 sum += B->data.F64[j] * U->data.F64[j][i]; 1617 } 1618 UtB[0]->data.F64[i] = sum; 1619 } 1620 return true; 1621 } 1622 1623 // w is diagonal 1624 bool p_pmSubSolve_wUtB (psVector **wUtB, psVector *w, psVector *UtB) { 1625 1626 psAssert (w->n == UtB->n, "w and UtB dimensions do not match"); 1627 1628 // wUt has dimensions transposed relative to Ut. 1629 wUtB[0] = psVectorRecycle (wUtB[0], w->n, PS_TYPE_F64); 1630 psVectorInit (wUtB[0], 0.0); 1631 1632 for (int i = 0; i < w->n; i++) { 1633 if (!isfinite(w->data.F64[i])) continue; 1634 if (w->data.F64[i] == 0.0) continue; 1635 wUtB[0]->data.F64[i] = UtB->data.F64[i] / w->data.F64[i]; 1636 } 1637 return true; 1638 } 1639 1640 // this is basically matrix * vector 1641 bool p_pmSubSolve_VwUtB (psVector **VwUtB, psImage *V, psVector *wUtB) { 1642 1643 psAssert (V->numCols == wUtB->n, "V and wUtB dimensions do not match"); 1644 1645 VwUtB[0] = psVectorRecycle (*VwUtB, V->numRows, PS_TYPE_F64); 1646 1647 for (int j = 0; j < V->numRows; j++) { 1648 double sum = 0.0; 1649 for (int i = 0; i < V->numCols; i++) { 1650 sum += V->data.F64[j][i] * wUtB->data.F64[i]; 1651 } 1652 VwUtB[0]->data.F64[j] = sum; 1653 } 1654 return true; 1655 } 1656 1657 // this is basically matrix * vector 1658 bool p_pmSubSolve_Ax (psVector **B, psImage *A, psVector *x) { 1659 1660 psAssert (A->numCols == x->n, "A and x dimensions do not match"); 1661 1662 B[0] = psVectorRecycle (*B, A->numRows, PS_TYPE_F64); 1663 1664 for (int j = 0; j < A->numRows; j++) { 1665 double sum = 0.0; 1666 for (int i = 0; i < A->numCols; i++) { 1667 sum += A->data.F64[j][i] * x->data.F64[i]; 1668 } 1669 B[0]->data.F64[j] = sum; 1670 } 1671 return true; 1672 } 1673 1674 // this is basically Vector * vector 1675 bool p_pmSubSolve_VdV (double *value, psVector *x, psVector *y) { 1676 1677 psAssert (x->n == y->n, "x and y dimensions do not match"); 1678 1679 double sum = 0.0; 1680 for (int i = 0; i < x->n; i++) { 1681 sum += x->data.F64[i] * y->data.F64[i]; 1682 } 1683 *value = sum; 1684 return true; 1685 } 1686 1687 bool p_pmSubSolve_y2 (double *y2, pmSubtractionKernels *kernels, const pmSubtractionStampList *stamps) { 1688 1689 int footprint = stamps->footprint; // Half-size of stamps 1690 1691 double sum = 0.0; 1692 for (int i = 0; i < stamps->num; i++) { 1693 1694 pmSubtractionStamp *stamp = stamps->stamps->data[i]; 1695 if (stamp->status != PM_SUBTRACTION_STAMP_USED) continue; 1696 1697 psKernel *weight = NULL; 1698 psKernel *window = NULL; 1699 psKernel *input = NULL; 1700 1701 #ifdef USE_WEIGHT 1702 weight = stamp->weight; 1703 #endif 1704 #ifdef USE_WINDOW 1705 window = stamps->window; 1706 #endif 1707 1708 switch (kernels->mode) { 1709 // MODE_1 : convolve image 1 to match image 2 (and vice versa) 1710 case PM_SUBTRACTION_MODE_1: 1711 input = stamp->image2; 1712 break; 1713 case PM_SUBTRACTION_MODE_2: 1714 input = stamp->image1; 1715 break; 1716 default: 1717 psAbort ("programming error"); 1718 } 1719 1720 for (int y = - footprint; y <= footprint; y++) { 1721 for (int x = - footprint; x <= footprint; x++) { 1722 double in = input->kernel[y][x]; 1723 double value = in*in; 1724 if (weight) { 1725 float wtVal = weight->kernel[y][x]; 1726 value *= wtVal; 1727 } 1728 if (window) { 1729 float winVal = window->kernel[y][x]; 1730 value *= winVal; 1731 } 1732 sum += value; 1733 } 1734 } 1735 } 1736 *y2 = sum; 1737 return true; 1738 } 1739 1740 double p_pmSubSolve_ChiSquare (pmSubtractionKernels *kernels, const pmSubtractionStampList *stamps) { 1741 1742 int footprint = stamps->footprint; // Half-size of stamps 1743 int numKernels = kernels->num; // Number of kernels 1744 1745 double sum = 0.0; 1746 1747 psKernel *residual = psKernelAlloc(-footprint, footprint, -footprint, footprint); // Residual image 1748 psImageInit(residual->image, 0.0); 1749 1750 psImage *polyValues = NULL; // Polynomial values 1751 1752 for (int i = 0; i < stamps->num; i++) { 1753 1754 pmSubtractionStamp *stamp = stamps->stamps->data[i]; 1755 if (stamp->status != PM_SUBTRACTION_STAMP_USED) continue; 1756 1757 psKernel *weight = NULL; 1758 psKernel *window = NULL; 1759 psKernel *target = NULL; 1760 psKernel *source = NULL; 1761 1762 psArray *convolutions = NULL; 1763 1764 #ifdef USE_WEIGHT 1765 weight = stamp->weight; 1766 #endif 1767 #ifdef USE_WINDOW 1768 window = stamps->window; 1769 #endif 1770 1771 switch (kernels->mode) { 1772 // MODE_1 : convolve image 1 to match image 2 (and vice versa) 1773 case PM_SUBTRACTION_MODE_1: 1774 target = stamp->image2; 1775 source = stamp->image1; 1776 convolutions = stamp->convolutions1; 1777 break; 1778 case PM_SUBTRACTION_MODE_2: 1779 target = stamp->image1; 1780 source = stamp->image2; 1781 convolutions = stamp->convolutions2; 1782 break; 1783 default: 1784 psAbort ("programming error"); 1785 } 1786 1787 // Calculate coefficients of the kernel basis functions 1788 polyValues = p_pmSubtractionPolynomial(polyValues, kernels->spatialOrder, stamp->xNorm, stamp->yNorm); 1789 double norm = p_pmSubtractionSolutionNorm(kernels); // Normalisation 1790 double background = p_pmSubtractionSolutionBackground(kernels, polyValues);// Difference in background 1791 1792 psImageInit(residual->image, 0.0); 1793 for (int j = 0; j < numKernels; j++) { 1794 psKernel *convolution = convolutions->data[j]; // Convolution 1795 double coefficient = p_pmSubtractionSolutionCoeff(kernels, polyValues, j, false); // Coefficient 1796 for (int y = - footprint; y <= footprint; y++) { 1797 for (int x = - footprint; x <= footprint; x++) { 1798 residual->kernel[y][x] -= convolution->kernel[y][x] * coefficient; 1799 } 1800 } 1801 } 1802 1803 for (int y = - footprint; y <= footprint; y++) { 1804 for (int x = - footprint; x <= footprint; x++) { 1805 double resid = target->kernel[y][x] - background - source->kernel[y][x] * norm + residual->kernel[y][x]; 1806 double value = PS_SQR(resid); 1807 if (weight) { 1808 float wtVal = weight->kernel[y][x]; 1809 value *= wtVal; 1810 } 1811 if (window) { 1812 float winVal = window->kernel[y][x]; 1813 value *= winVal; 1814 } 1815 sum += value; 1816 } 1817 } 1818 } 1819 psFree (polyValues); 1820 psFree (residual); 1821 1822 return sum; 1823 } 1824 1825 bool p_pmSubSolve_SetWeights (psVector *wApply, psVector *w, psVector *wMask) { 1826 1827 for (int i = 0; i < w->n; i++) { 1828 wApply->data.F64[i] = wMask->data.U8[i] ? 0.0 : w->data.F64[i]; 1829 } 1830 return true; 1831 } 1832 1833 // we are supplied V and w; w represents a diagonal matrix (also, we apply 1/w instead of w) 1834 psImage *p_pmSubSolve_Xvar (psImage *V, psVector *w) { 1835 1836 psAssert (w->n == V->numCols, "w and U dimensions do not match"); 1837 1838 psImage *Vn = psImageAlloc (V->numCols, V->numRows, PS_TYPE_F64); 1839 psImageInit (Vn, 0.0); 1840 1841 // generate Vn = V * w^{-1} 1842 for (int j = 0; j < Vn->numRows; j++) { 1843 for (int i = 0; i < Vn->numCols; i++) { 1844 if (!isfinite(w->data.F64[i])) continue; 1845 if (w->data.F64[i] == 0.0) continue; 1846 Vn->data.F64[j][i] = V->data.F64[j][i] / w->data.F64[i]; 1847 } 1848 } 1849 1850 psImage *Xvar = psImageAlloc (V->numCols, V->numRows, PS_TYPE_F64); 1851 psImageInit (Xvar, 0.0); 1852 1853 // generate Xvar = Vn * Vn^T 1854 for (int j = 0; j < Vn->numRows; j++) { 1855 for (int i = 0; i < Vn->numCols; i++) { 1856 double sum = 0.0; 1857 for (int k = 0; k < Vn->numCols; k++) { 1858 sum += Vn->data.F64[k][i]*Vn->data.F64[k][j]; 1859 } 1860 Xvar->data.F64[j][i] = sum; 1861 } 1862 } 1863 return Xvar; 1864 } 1865 1866 // I get confused by the index values between the image vs matrix usage: In terms 1867 // of the elements of an image A(x,y) = A->data.F64[y][x] = A_x,y, a matrix 1868 // multiplication is: A_k,j * B_i,k = C_i,j 1869 1870 1871 bool psFitsWriteImageSimple (char *filename, psImage *image, psMetadata *header) { 1872 1873 psFits *fits = psFitsOpen(filename, "w"); 1874 psFitsWriteImage(fits, header, image, 0, NULL); 1875 psFitsClose(fits); 1876 1877 return true; 1878 } 1879 1880 bool psVectorWriteFile (char *filename, const psVector *vector) { 1881 1882 FILE *f = fopen (filename, "w"); 1883 int fd = fileno(f); 1884 p_psVectorPrint (fd, vector, "unnamed"); 1885 fclose (f); 1886 1887 return true; 1888 } 1889 1890 1891 # if 0 1892 1893 #ifdef TESTING 1894 psFitsWriteImageSimple("A.fits", sumMatrix, NULL); 1895 psVectorWriteFile ("B.dat", sumVector); 1896 #endif 1897 1898 # define SVD_ANALYSIS 0 1899 # define COEFF_SIG 0.0 1900 # define SVD_TOL 0.0 1901 1902 // Use SVD to determine the kernel coeffs (and validate) 1903 if (SVD_ANALYSIS) { 1904 1905 // We have sumVector and sumMatrix. we are trying to solve the following equation: 1906 // sumMatrix * x = sumVector. 1907 1908 // we can use any standard matrix inversion to solve this. However, the basis 1909 // functions in general have substantial correlation, so that the solution may be 1910 // somewhat poorly determined or unstable. If not numerically ill-conditioned, the 1911 // system of equations may be statistically ill-conditioned. Noise in the image 1912 // will drive insignificant, but correlated, terms in the solution. To avoid these 1913 // problems, we can use SVD to identify numerically unconstrained values and to 1914 // avoid statistically badly determined value. 1915 1916 // A = sumMatrix, B = sumVector 1917 // SVD: A = U w V^T -> A^{-1} = V (1/w) U^T 1918 // x = V (1/w) (U^T B) 1919 // \sigma_x = sqrt(diag(A^{-1})) 1920 // solve for x and A^{-1} to get x & dx 1921 // identify the elements of (1/w) that are nan (1/0.0) -> set to 0.0 1922 // identify the elements of x that are insignificant (x / dx < 1.0? < 0.5?) -> set to 0.0 1923 1924 // If I use the SVD trick to re-condition the matrix, I need to break out the 1925 // kernel and normalization terms from the background term. 1926 // XXX is this true? or was this due to an error in the analysis? 1927 1928 int bgIndex = PM_SUBTRACTION_INDEX_BG(kernels); // Index in matrix for background 1929 1930 // now pull out the kernel elements into their own square matrix 1931 psImage *kernelMatrix = psImageAlloc (sumMatrix->numCols - 1, sumMatrix->numRows - 1, PS_TYPE_F64); 1932 psVector *kernelVector = psVectorAlloc (sumMatrix->numCols - 1, PS_TYPE_F64); 1933 1934 for (int ix = 0, kx = 0; ix < sumMatrix->numCols; ix++) { 1935 if (ix == bgIndex) continue; 1936 for (int iy = 0, ky = 0; iy < sumMatrix->numRows; iy++) { 1937 if (iy == bgIndex) continue; 1938 kernelMatrix->data.F64[ky][kx] = sumMatrix->data.F64[iy][ix]; 1939 ky++; 1940 } 1941 kernelVector->data.F64[kx] = sumVector->data.F64[ix]; 1942 kx++; 1943 } 1944 1945 psImage *U = NULL; 1946 psImage *V = NULL; 1947 psVector *w = NULL; 1948 if (!psMatrixSVD (&U, &w, &V, kernelMatrix)) { 1949 psError(PS_ERR_UNKNOWN, false, "failed to perform SVD on sumMatrix\n"); 1950 return NULL; 1951 } 1952 1953 // calculate A_inverse: 1954 // Ainv = V * w * U^T 1955 psImage *wUt = p_pmSubSolve_wUt (w, U); 1956 psImage *Ainv = p_pmSubSolve_VwUt (V, wUt); 1957 psImage *Xvar = NULL; 1958 psFree (wUt); 1959 1960 # ifdef TESTING 1961 // kernel terms: 1962 for (int i = 0; i < w->n; i++) { 1963 fprintf (stderr, "w: %f\n", w->data.F64[i]); 1964 } 1965 # endif 1966 // loop over w adding in more and more of the values until chisquare is no longer 1967 // dropping significantly. 1968 // XXX this does not seem to work very well: we seem to need all terms even for 1969 // simple cases... 1970 1971 psVector *Xsvd = NULL; 1972 { 1973 psVector *Ax = NULL; 1974 psVector *UtB = NULL; 1975 psVector *wUtB = NULL; 1976 1977 psVector *wApply = psVectorAlloc(w->n, PS_TYPE_F64); 1978 psVector *wMask = psVectorAlloc(w->n, PS_TYPE_U8); 1979 psVectorInit (wMask, 1); // start by masking everything 1980 1981 double chiSquareLast = NAN; 1982 int maxWeight = 0; 1983 1984 double Axx, Bx, y2; 1985 1986 // XXX this is an attempt to exclude insignificant modes. 1987 // it was not successful with the ISIS kernel set: removing even 1988 // the least significant mode leaves additional ringing / noise 1989 // because the terms are so coupled. 1990 for (int k = 0; false && (k < w->n); k++) { 1991 1992 // unmask the k-th weight 1993 wMask->data.U8[k] = 0; 1994 p_pmSubSolve_SetWeights(wApply, w, wMask); 1995 1996 // solve for x: 1997 // x = V * w * (U^T * B) 1998 p_pmSubSolve_UtB (&UtB, U, kernelVector); 1999 p_pmSubSolve_wUtB (&wUtB, wApply, UtB); 2000 p_pmSubSolve_VwUtB (&Xsvd, V, wUtB); 2001 2002 // chi-square for this system of equations: 2003 // chi-square = sum over terms of: (Ax - B)*x - b*x - y^2 2004 // y^2 = \sum_stamps \sum_pixels input->kernel[y][x]^2 2005 p_pmSubSolve_Ax (&Ax, kernelMatrix, Xsvd); 2006 p_pmSubSolve_VdV (&Axx, Ax, Xsvd); 2007 p_pmSubSolve_VdV (&Bx, kernelVector, Xsvd); 2008 p_pmSubSolve_y2 (&y2, kernels, stamps); 2009 2010 // apparently, this works (compare with the brute force value below 2011 double chiSquare = Axx - 2.0*Bx + y2; 2012 double deltaChi = (k == 0) ? chiSquare : chiSquareLast - chiSquare; 2013 chiSquareLast = chiSquare; 2014 2015 // fprintf (stderr, "chi square = %f, delta: %f\n", chiSquare, deltaChi); 2016 if (k && !maxWeight && (deltaChi < 1.0)) { 2017 maxWeight = k; 2018 } 2019 } 2020 2021 // keep all terms or we get extra ringing 2022 maxWeight = w->n; 2023 psVectorInit (wMask, 1); 2024 for (int k = 0; k < maxWeight; k++) { 2025 wMask->data.U8[k] = 0; 2026 } 2027 p_pmSubSolve_SetWeights(wApply, w, wMask); 2028 2029 // solve for x: 2030 // x = V * w * (U^T * B) 2031 p_pmSubSolve_UtB (&UtB, U, kernelVector); 2032 p_pmSubSolve_wUtB (&wUtB, wApply, UtB); 2033 p_pmSubSolve_VwUtB (&Xsvd, V, wUtB); 2034 2035 // chi-square for this system of equations: 2036 // chi-square = sum over terms of: (Ax - B)*x - b*x - y^2 2037 // y^2 = \sum_stamps \sum_pixels input->kernel[y][x]^2 2038 p_pmSubSolve_Ax (&Ax, kernelMatrix, Xsvd); 2039 p_pmSubSolve_VdV (&Axx, Ax, Xsvd); 2040 p_pmSubSolve_VdV (&Bx, kernelVector, Xsvd); 2041 p_pmSubSolve_y2 (&y2, kernels, stamps); 2042 2043 // apparently, this works (compare with the brute force value below 2044 double chiSquare = Axx - 2.0*Bx + y2; 2045 psLogMsg ("psModules.imcombine", PS_LOG_INFO, "model kernel with %d terms; chi square = %f\n", maxWeight, chiSquare); 2046 2047 // re-calculate A^{-1} to get new variances: 2048 // Ainv = V * w * U^T 2049 // XXX since we keep all terms, this is identical to Ainv 2050 psImage *wUt = p_pmSubSolve_wUt (wApply, U); 2051 Xvar = p_pmSubSolve_VwUt (V, wUt); 2052 psFree (wUt); 2053 2054 psFree (Ax); 2055 psFree (UtB); 2056 psFree (wUtB); 2057 psFree (wApply); 2058 psFree (wMask); 2059 } 2060 2061 // copy the kernel solutions to the full solution vector: 2062 solution = psVectorAlloc(sumVector->n, PS_TYPE_F64); 2063 solutionErr = psVectorAlloc(sumVector->n, PS_TYPE_F64); 2064 2065 for (int ix = 0, kx = 0; ix < sumVector->n; ix++) { 2066 if (ix == bgIndex) { 2067 solution->data.F64[ix] = 0; 2068 solutionErr->data.F64[ix] = 0.001; 2069 continue; 2070 } 2071 solutionErr->data.F64[ix] = sqrt(Ainv->data.F64[kx][kx]); 2072 solution->data.F64[ix] = Xsvd->data.F64[kx]; 2073 kx++; 2074 } 2075 2076 psFree (kernelMatrix); 2077 psFree (kernelVector); 2078 2079 psFree (U); 2080 psFree (V); 2081 psFree (w); 2082 2083 psFree (Ainv); 2084 psFree (Xsvd); 2085 } else { 2086 psVector *permutation = NULL; // Permutation vector, required for LU decomposition 2087 psImage *luMatrix = psMatrixLUDecomposition(NULL, &permutation, sumMatrix); 2088 if (!luMatrix) { 2089 psError(PS_ERR_UNKNOWN, true, "LU Decomposition of least-squares matrix failed.\n"); 2090 psFree(solution); 2091 psFree(sumVector); 2092 psFree(sumMatrix); 2093 psFree(luMatrix); 2094 psFree(permutation); 2095 return NULL; 2096 } 2097 2098 solution = psMatrixLUSolution(NULL, luMatrix, sumVector, permutation); 2099 psFree(luMatrix); 2100 psFree(permutation); 2101 if (!solution) { 2102 psError(PS_ERR_UNKNOWN, true, "Failed to solve the least-squares system.\n"); 2103 psFree(solution); 2104 psFree(sumVector); 2105 psFree(sumMatrix); 2106 return NULL; 2107 } 2108 2109 // XXX LUD does not provide A^{-1}? fake the error for now 2110 solutionErr = psVectorAlloc(sumVector->n, PS_TYPE_F64); 2111 for (int ix = 0; ix < sumVector->n; ix++) { 2112 solutionErr->data.F64[ix] = 0.1*solution->data.F64[ix]; 2113 } 2114 } 2115 2116 if (!kernels->solution1) { 2117 kernels->solution1 = psVectorAlloc (sumVector->n, PS_TYPE_F64); 2118 psVectorInit (kernels->solution1, 0.0); 2119 } 2120 2121 // only update the solutions that we chose to calculate: 2122 if (mode & PM_SUBTRACTION_EQUATION_NORM) { 2123 int normIndex = PM_SUBTRACTION_INDEX_NORM(kernels); // Index for normalisation 2124 kernels->solution1->data.F64[normIndex] = solution->data.F64[normIndex]; 2125 } 2126 if (mode & PM_SUBTRACTION_EQUATION_BG) { 2127 int bgIndex = PM_SUBTRACTION_INDEX_BG(kernels); // Index in matrix for background 2128 kernels->solution1->data.F64[bgIndex] = solution->data.F64[bgIndex]; 2129 } 2130 if (mode & PM_SUBTRACTION_EQUATION_KERNELS) { 2131 int numKernels = kernels->num; 2132 int spatialOrder = kernels->spatialOrder; // Order of spatial variation 2133 int numPoly = PM_SUBTRACTION_POLYTERMS(spatialOrder); // Number of polynomial terms 2134 for (int i = 0; i < numKernels * numPoly; i++) { 2135 // XXX fprintf (stderr, "%f +/- %f (%f) -> ", solution->data.F64[i], solutionErr->data.F64[i], fabs(solution->data.F64[i]/solutionErr->data.F64[i])); 2136 if (fabs(solution->data.F64[i] / solutionErr->data.F64[i]) < COEFF_SIG) { 2137 // XXX fprintf (stderr, "drop\n"); 2138 kernels->solution1->data.F64[i] = 0.0; 2139 } else { 2140 // XXX fprintf (stderr, "keep\n"); 2141 kernels->solution1->data.F64[i] = solution->data.F64[i]; 2142 } 2143 } 2144 } 2145 // double chiSquare = p_pmSubSolve_ChiSquare (kernels, stamps); 2146 // fprintf (stderr, "chi square Brute = %f\n", chiSquare); 2147 2148 psFree(solution); 2149 psFree(sumVector); 2150 psFree(sumMatrix); 2151 # endif 2152 2153 #ifdef TESTING 2154 // XXX double-check for NAN in data: 2155 for (int iy = 0; iy < stamp->matrix->numRows; iy++) { 2156 for (int ix = 0; ix < stamp->matrix->numCols; ix++) { 2157 if (!isfinite(stamp->matrix->data.F64[iy][ix])) { 2158 fprintf (stderr, "WARNING: NAN in matrix\n"); 2159 } 2160 } 2161 } 2162 for (int ix = 0; ix < stamp->vector->n; ix++) { 2163 if (!isfinite(stamp->vector->data.F64[ix])) { 2164 fprintf (stderr, "WARNING: NAN in vector\n"); 2165 } 2166 } 2167 #endif 2168 2169 #ifdef TESTING 2170 for (int ix = 0; ix < sumVector->n; ix++) { 2171 if (!isfinite(sumVector->data.F64[ix])) { 2172 fprintf (stderr, "WARNING: NAN in vector\n"); 2173 } 2174 } 2175 #endif 2176 2177 #ifdef TESTING 2178 for (int ix = 0; ix < sumVector->n; ix++) { 2179 if (!isfinite(sumVector->data.F64[ix])) { 2180 fprintf (stderr, "WARNING: NAN in vector\n"); 2181 } 2182 } 2183 { 2184 psImage *inverse = psMatrixInvert(NULL, sumMatrix, NULL); 2185 psFitsWriteImageSimple("matrixInv.fits", inverse, NULL); 2186 psFree(inverse); 2187 } 2188 { 2189 psImage *X = psMatrixInvert(NULL, sumMatrix, NULL); 2190 psImage *Xt = psMatrixTranspose(NULL, X); 2191 psImage *XtX = psMatrixMultiply(NULL, Xt, X); 2192 psFitsWriteImageSimple("matrixErr.fits", XtX, NULL); 2193 psFree(X); 2194 psFree(Xt); 2195 psFree(XtX); 2196 } 2197 #endif 2198 -
trunk/psModules/src/imcombine/pmSubtractionEquation.h
r19299 r26893 4 4 #include "pmSubtractionStamps.h" 5 5 #include "pmSubtractionKernels.h" 6 7 typedef enum { 8 PM_SUBTRACTION_EQUATION_NONE = 0x00, 9 PM_SUBTRACTION_EQUATION_NORM = 0x01, 10 PM_SUBTRACTION_EQUATION_BG = 0x02, 11 PM_SUBTRACTION_EQUATION_KERNELS = 0x04, 12 PM_SUBTRACTION_EQUATION_ALL = 0x07, // value should be NORM | BG | KERNELS 13 } pmSubtractionEquationCalculationMode; 6 14 7 15 /// Execute a thread job to calculate the least-squares equation for a stamp … … 12 20 bool pmSubtractionCalculateEquationStamp(pmSubtractionStampList *stamps, ///< Stamps 13 21 const pmSubtractionKernels *kernels, ///< Kernel parameters 14 int index ///< Index of stamp 15 ); 22 int index, ///< Index of stamp 23 const pmSubtractionEquationCalculationMode mode 24 ); 16 25 17 26 /// Calculate the least-squares equation to match the image quality 18 27 bool pmSubtractionCalculateEquation(pmSubtractionStampList *stamps, ///< Stamps 19 const pmSubtractionKernels *kernels ///< Kernel parameters 20 ); 28 const pmSubtractionKernels *kernels, ///< Kernel parameters 29 const pmSubtractionEquationCalculationMode mode 30 ); 21 31 22 32 /// Solve the least-squares equation to match the image quality 23 33 bool pmSubtractionSolveEquation(pmSubtractionKernels *kernels, ///< Kernel parameters 24 const pmSubtractionStampList *stamps ///< Stamps 34 const pmSubtractionStampList *stamps, ///< Stamps 35 const pmSubtractionEquationCalculationMode mode 25 36 ); 26 37 27 38 /// Calculate deviations 28 39 psVector *pmSubtractionCalculateDeviations(pmSubtractionStampList *stamps, ///< Stamps 29 constpmSubtractionKernels *kernels ///< Kernel parameters40 pmSubtractionKernels *kernels ///< Kernel parameters 30 41 ); 31 42 -
trunk/psModules/src/imcombine/pmSubtractionIO.c
r23378 r26893 80 80 while ((item = psMetadataGetAndIncrement(iter))) { 81 81 assert(item->type == PS_DATA_UNKNOWN); 82 // Set the normalisation dimensions, since these will be otherwise unavailable when reading the83 // images by scans.84 82 pmSubtractionKernels *kernel = item->data.V; // Kernel used in subtraction 85 kernel->numCols = ro->image->numCols;86 kernel->numRows = ro->image->numRows;87 88 83 kernels = psArrayAdd(kernels, ARRAY_BUFFER, kernel); 89 84 } … … 126 121 kernel->bgOrder); 127 122 psMetadataAddS32(row, PS_LIST_TAIL, NAME_MODE, 0, "Matching mode (enum)", kernel->mode); 128 psMetadataAddS32(row, PS_LIST_TAIL, NAME_COLS, 0, "Number of columns", kernel->numCols);129 psMetadataAddS32(row, PS_LIST_TAIL, NAME_ROWS, 0, "Number of rows", kernel->numRows);130 123 if (kernel->mode == PM_SUBTRACTION_MODE_1 || kernel->mode == PM_SUBTRACTION_MODE_2) { 131 124 psMetadataAddVector(row, PS_LIST_TAIL, NAME_SOL1, 0, "Solution vector 1", kernel->solution1); … … 318 311 319 312 TABLE_LOOKUP(int, S32, bg, NAME_BG); 320 TABLE_LOOKUP(int, S32, numCols, NAME_COLS);321 TABLE_LOOKUP(int, S32, numRows, NAME_ROWS);322 313 323 314 TABLE_LOOKUP(float, F32, mean, NAME_MEAN); … … 325 316 TABLE_LOOKUP(int, S32, numStamps, NAME_NUMSTAMPS); 326 317 327 pmSubtractionKernels *kernels = pmSubtractionKernelsFromDescription(description, bg, mode); 328 kernels->numCols = numCols; 329 kernels->numRows = numRows; 318 pmSubtractionKernels *kernels = pmSubtractionKernelsFromDescription(description, bg, *region, mode); 330 319 kernels->mean = mean; 331 320 kernels->rms = rms; -
trunk/psModules/src/imcombine/pmSubtractionKernels.c
r26156 r26893 10 10 #include "pmSubtraction.h" 11 11 #include "pmSubtractionKernels.h" 12 #include "pmSubtractionHermitian.h" 13 #include "pmSubtractionDeconvolve.h" 14 #include "pmSubtractionVisual.h" 12 15 13 16 #define RINGS_BUFFER 10 // Buffer size for RINGS data 14 15 17 16 18 // Free function for pmSubtractionKernels … … 27 29 psFree(kernels->solution1); 28 30 psFree(kernels->solution2); 31 psFree(kernels->sampleStamps); 32 } 33 34 // Free function for pmSubtractionPreCalcKernel 35 static void pmSubtractionKernelPreCalcFree(pmSubtractionKernelPreCalc *kernel) 36 { 37 psFree(kernel->xKernel); 38 psFree(kernel->yKernel); 39 psFree(kernel->kernel); 40 41 psFree(kernel->uCoords); 42 psFree(kernel->vCoords); 43 psFree(kernel->poly); 29 44 } 30 45 … … 45 60 46 61 // Generate 1D convolution kernel for ISIS 47 static psVector *subtractionKernelISIS(float sigma, // Gaussian width62 psVector *pmSubtractionKernelISIS(float sigma, // Gaussian width 48 63 int order, // Polynomial order 49 64 int size // Kernel half-size … … 57 72 for (int i = 0, x = -size; x <= size; i++, x++) { 58 73 kernel->data.F32[i] = norm * power(x, order) * expf(expNorm * PS_SQR(x)); 74 } 75 76 return kernel; 77 } 78 79 // Generate 1D convolution kernel for HERM (normalized for 2D) 80 psVector *pmSubtractionKernelHERM(float sigma, // Gaussian width 81 int order, // Polynomial order 82 int size // Kernel half-size 83 ) 84 { 85 int fullSize = 2 * size + 1; // Full size of kernel 86 psVector *kernel = psVectorAlloc(fullSize, PS_TYPE_F32); // Kernel to return 87 88 // for now, we are only allowing equal orders and sigmas in X and Y 89 float nf = exp(lgamma(order + 1)); 90 float norm = 1.0 / sqrt(nf*sigma*sqrt(M_2_PI)); 91 92 for (int i = 0, x = -size; x <= size; i++, x++) { 93 float xf = x / sigma; 94 float z = -0.25*xf*xf; 95 kernel->data.F32[i] = norm * p_pmSubtractionHermitianPolynomial(xf, order) * exp(z); 96 } 97 98 return kernel; 99 } 100 101 // Generate 1D convolution kernel for HERM (normalized for 2D) 102 psKernel *pmSubtractionKernelHERM_RADIAL(float sigma, // Gaussian width 103 int order, // Polynomial order 104 int size // Kernel half-size 105 ) 106 { 107 psKernel *kernel = psKernelAlloc(-size, size, -size, size); // 2D Kernel 108 109 // for now, we are only allowing equal orders and sigmas in X and Y 110 float nf = exp(lgamma(order + 1)); 111 float norm = 1.0 / sqrt(nf*sigma*sqrt(M_2_PI)); 112 113 // generate 2D radial hermitian 114 for (int v = -size; v <= size; v++) { 115 for (int u = -size; u <= size; u++) { 116 float r = hypot(u, v) / sigma; 117 float z = -0.25*r*r; 118 kernel->kernel[v][u] = norm * p_pmSubtractionHermitianPolynomial(r, order) * exp(z); 119 } 59 120 } 60 121 … … 96 157 kernels->preCalc->data[index] = NULL; 97 158 kernels->penalties->data.F32[index] = kernels->penalty * PS_SQR(PS_SQR(u) + PS_SQR(v)); 98 159 psAssert (isfinite(kernels->penalties->data.F32[index]), "invalid penalty"); 99 160 psTrace("psModules.imcombine", 7, "Kernel %d: %d %d\n", index, u, v); 100 161 } … … 110 171 } 111 172 173 bool pmSubtractionKernelPreCalcNormalize(pmSubtractionKernels *kernels, pmSubtractionKernelPreCalc *preCalc, 174 int index, int size, int uOrder, int vOrder, float fwhm, 175 bool AlardLuptonStyle, bool forceZeroNull) 176 { 177 // we have 4 cases here: 178 // 1) for odd functions, normalize the kernel by the maximum swing / Npix 179 // 2) for even functions, normalize the kernel to unity 180 // 3) for alard-lupton style normalization, subtract 1 from the 0,0 pixel for all even functions 181 // 4) for deconvolved hermitians, subtract 1 from the 0,0 pixel for the 0,0 function(s) 182 183 // Calculate moments 184 double penalty = 0.0; // Moment, for penalty 185 double sum = 0.0, sum2 = 0.0; // Sum of kernel component 186 float min = INFINITY, max = -INFINITY; // Minimum and maximum kernel value 187 for (int v = -size; v <= size; v++) { 188 for (int u = -size; u <= size; u++) { 189 double value = preCalc->kernel->kernel[v][u]; 190 double value2 = PS_SQR(value); 191 sum += value; 192 sum2 += value2; 193 penalty += value2 * PS_SQR((PS_SQR(u) + PS_SQR(v))); 194 min = PS_MIN(value, min); 195 max = PS_MAX(value, max); 196 } 197 } 198 199 #if 0 200 fprintf(stderr, "%d raw: %lf, null: %f, min: %lf, max: %lf, moment: %lf\n", index, sum, preCalc->kernel->kernel[0][0], min, max, penalty); 201 #endif 202 203 bool zeroNull = false; // Zero out using the null position? 204 float scale2D = NAN; // Scaling for 2-D kernels 205 206 if (AlardLuptonStyle) { 207 if (uOrder % 2 == 0 && vOrder % 2 == 0) { 208 // Even functions: normalise to unit sum and subtract null pixel so that sum is zero 209 scale2D = 1.0 / fabs(sum); 210 zeroNull = true; 211 } else { 212 // Odd functions: choose normalisation so that parameters have about the same strength as for even 213 // functions, no subtraction of null pixel because the sum is already (near) zero 214 scale2D = 1.0 / sqrt(sum2); 215 zeroNull = false; 216 } 217 } 218 219 if (!AlardLuptonStyle && (uOrder == 0 && vOrder == 0)) { 220 zeroNull = true; 221 } 222 if (forceZeroNull) { 223 // Force rescaling and subtraction of null pixel even though the order doesn't indicate it's even 224 scale2D = 1.0 / fabs(sum); 225 zeroNull = true; 226 } 227 if (!forceZeroNull && ((uOrder % 2) || (vOrder % 2))) { 228 // Odd function 229 scale2D = 1.0 / sqrt(sum2); 230 } 231 232 float scale1D = sqrtf(scale2D); // Scaling for 1-D kernels 233 if (preCalc->xKernel) { 234 psBinaryOp(preCalc->xKernel, preCalc->xKernel, "*", psScalarAlloc(scale1D, PS_TYPE_F32)); 235 } 236 if (preCalc->yKernel) { 237 psBinaryOp(preCalc->yKernel, preCalc->yKernel, "*", psScalarAlloc(scale1D, PS_TYPE_F32)); 238 } 239 240 psBinaryOp(preCalc->kernel->image, preCalc->kernel->image, "*", psScalarAlloc(scale2D, PS_TYPE_F32)); 241 penalty *= 1.0 / sum2; 242 243 if (zeroNull) { 244 preCalc->kernel->kernel[0][0] -= 1.0; 245 } 246 247 #if 0 248 { 249 double sum = 0.0; // Sum of kernel component 250 float min = INFINITY, max = -INFINITY; // Minimum and maximum kernel value 251 for (int v = -size; v <= size; v++) { 252 for (int u = -size; u <= size; u++) { 253 sum += preCalc->kernel->kernel[v][u]; 254 min = PS_MIN(preCalc->kernel->kernel[v][u], min); 255 max = PS_MAX(preCalc->kernel->kernel[v][u], max); 256 } 257 } 258 fprintf(stderr, "%d mod: %lf, null: %f, min: %lf, max: %lf, scale: %f\n", index, sum, preCalc->kernel->kernel[0][0], min, max, scale2D); 259 } 260 #endif 261 262 kernels->widths->data.F32[index] = fwhm; 263 kernels->u->data.S32[index] = uOrder; 264 kernels->v->data.S32[index] = vOrder; 265 if (kernels->preCalc->data[index]) { 266 psFree(kernels->preCalc->data[index]); 267 } 268 kernels->preCalc->data[index] = preCalc; 269 kernels->penalties->data.F32[index] = kernels->penalty * penalty; 270 psAssert (isfinite(kernels->penalties->data.F32[index]), "invalid penalty"); 271 psTrace("psModules.imcombine", 7, "Kernel %d: %f %d %d %f\n", index, fwhm, uOrder, vOrder, penalty); 272 273 return true; 274 } 275 112 276 pmSubtractionKernels *p_pmSubtractionKernelsRawISIS(int size, int spatialOrder, 113 const psVector *fwhms , const psVector *orders,114 float penalty, p mSubtractionMode mode)115 { 116 PS_ASSERT_VECTOR_NON_NULL(fwhms , NULL);117 PS_ASSERT_VECTOR_TYPE(fwhms , PS_TYPE_F32, NULL);118 PS_ASSERT_VECTOR_NON_NULL(orders , NULL);119 PS_ASSERT_VECTOR_TYPE(orders , PS_TYPE_S32, NULL);120 PS_ASSERT_VECTORS_SIZE_EQUAL(fwhms , orders, NULL);277 const psVector *fwhmsIN, const psVector *ordersIN, 278 float penalty, psRegion bounds, pmSubtractionMode mode) 279 { 280 PS_ASSERT_VECTOR_NON_NULL(fwhmsIN, NULL); 281 PS_ASSERT_VECTOR_TYPE(fwhmsIN, PS_TYPE_F32, NULL); 282 PS_ASSERT_VECTOR_NON_NULL(ordersIN, NULL); 283 PS_ASSERT_VECTOR_TYPE(ordersIN, PS_TYPE_S32, NULL); 284 PS_ASSERT_VECTORS_SIZE_EQUAL(fwhmsIN, ordersIN, NULL); 121 285 PS_ASSERT_INT_POSITIVE(size, NULL); 122 286 PS_ASSERT_INT_NONNEGATIVE(spatialOrder, NULL); 287 288 // check the requested fwhm values: any values <= 0.0 should be dropped 289 psVector *fwhms = psVectorAllocEmpty (fwhmsIN->n, PS_TYPE_F32); 290 psVector *orders = psVectorAllocEmpty (ordersIN->n, PS_TYPE_S32); 291 for (int i = 0; i < fwhmsIN->n; i++) { 292 if (fwhmsIN->data.F32[i] <= FLT_EPSILON) continue; 293 psVectorAppend(fwhms, fwhmsIN->data.F32[i]); 294 psVectorAppend(orders, ordersIN->data.S32[i]); 295 } 123 296 124 297 int numGaussians = fwhms->n; // Number of Gaussians … … 133 306 134 307 pmSubtractionKernels *kernels = pmSubtractionKernelsAlloc(num, PM_SUBTRACTION_KERNEL_ISIS, size, 135 spatialOrder, penalty, mode); // The kernels308 spatialOrder, penalty, bounds, mode); // Kernels 136 309 psStringAppend(&kernels->description, "ISIS(%d,%s,%d,%.2e)", size, params, spatialOrder, penalty); 137 310 … … 141 314 142 315 // Set the kernel parameters 143 int fullSize = 2 * size + 1; // Full size of kernels144 316 for (int i = 0, index = 0; i < numGaussians; i++) { 145 317 float sigma = fwhms->data.F32[i] / (2.0 * sqrtf(2.0 * logf(2.0))); // Gaussian sigma … … 147 319 for (int uOrder = 0; uOrder <= orders->data.S32[i]; uOrder++) { 148 320 for (int vOrder = 0; vOrder <= orders->data.S32[i] - uOrder; vOrder++, index++) { 149 psArray *preCalc = psArrayAlloc(3); // Array to hold precalculated values 150 psVector *xKernel = preCalc->data[0] = subtractionKernelISIS(sigma, uOrder, size); // x Kernel 151 psVector *yKernel = preCalc->data[1] = subtractionKernelISIS(sigma, vOrder, size); // y Kernel 152 psKernel *kernel = preCalc->data[2] = psKernelAlloc(-size, size, -size, size); // Kernel 153 154 // Calculate moments 155 double moment = 0.0; // Moment, for penalty 156 for (int v = -size, y = 0; v <= size; v++, y++) { 157 for (int u = -size, x = 0; u <= size; u++, x++) { 158 double value = xKernel->data.F32[x] * yKernel->data.F32[y]; // Value of kernel 159 kernel->kernel[v][u] = value; 160 moment += value * PS_SQR((PS_SQR(u) + PS_SQR(v))); 161 } 321 322 pmSubtractionKernelPreCalc *preCalc = pmSubtractionKernelPreCalcAlloc(PM_SUBTRACTION_KERNEL_ISIS, uOrder, vOrder, size, sigma); // structure to hold precalculated values 323 pmSubtractionKernelPreCalcNormalize (kernels, preCalc, index, size, uOrder, vOrder, fwhms->data.F32[i], true, false); 324 // pmSubtractionKernelPreCalcNormalize (kernels, preCalc, index, size, uOrder, vOrder, fwhms->data.F32[i], false, false); 325 } 326 } 327 } 328 329 return kernels; 330 } 331 332 pmSubtractionKernels *pmSubtractionKernelsISIS_RADIAL(int size, int spatialOrder, 333 const psVector *fwhmsIN, const psVector *ordersIN, 334 float penalty, psRegion bounds, pmSubtractionMode mode) 335 { 336 PS_ASSERT_VECTOR_NON_NULL(fwhmsIN, NULL); 337 PS_ASSERT_VECTOR_TYPE(fwhmsIN, PS_TYPE_F32, NULL); 338 PS_ASSERT_VECTOR_NON_NULL(ordersIN, NULL); 339 PS_ASSERT_VECTOR_TYPE(ordersIN, PS_TYPE_S32, NULL); 340 PS_ASSERT_VECTORS_SIZE_EQUAL(fwhmsIN, ordersIN, NULL); 341 PS_ASSERT_INT_POSITIVE(size, NULL); 342 PS_ASSERT_INT_NONNEGATIVE(spatialOrder, NULL); 343 344 // check the requested fwhm values: any values <= 0.0 should be dropped 345 psVector *fwhms = psVectorAllocEmpty (fwhmsIN->n, PS_TYPE_F32); 346 psVector *orders = psVectorAllocEmpty (ordersIN->n, PS_TYPE_S32); 347 for (int i = 0; i < fwhmsIN->n; i++) { 348 if (fwhmsIN->data.F32[i] <= FLT_EPSILON) continue; 349 psVectorAppend(fwhms, fwhmsIN->data.F32[i]); 350 psVectorAppend(orders, ordersIN->data.S32[i]); 351 } 352 353 int numGaussians = fwhms->n; // Number of Gaussians 354 355 int num = 0; // Number of basis functions 356 psString params = NULL; // List of parameters 357 for (int i = 0; i < numGaussians; i++) { 358 int gaussOrder = orders->data.S32[i]; // Polynomial order to apply to Gaussian 359 psStringAppend(¶ms, "(%.1f,%d)", fwhms->data.F32[i], orders->data.S32[i]); 360 num += (gaussOrder + 1) * (gaussOrder + 2) / 2; 361 num += (11 - gaussOrder - 1); // include all higher order radial terms 362 } 363 364 pmSubtractionKernels *kernels = pmSubtractionKernelsAlloc(num, PM_SUBTRACTION_KERNEL_ISIS_RADIAL, size, 365 spatialOrder, penalty, bounds, mode); // Kernels 366 psStringAppend(&kernels->description, "ISIS_RADIAL(%d,%s,%d,%.2e)", size, params, spatialOrder, penalty); 367 368 psLogMsg("psModules.imcombine", PS_LOG_INFO, "ISIS_RADIAL kernel: %s,%d --> %d elements", params, spatialOrder, num); 369 psFree(params); 370 371 // Set the kernel parameters 372 for (int i = 0, index = 0; i < numGaussians; i++) { 373 float sigma = fwhms->data.F32[i] / (2.0 * sqrtf(2.0 * logf(2.0))); // Gaussian sigma 374 // Iterate over (u,v) order 375 for (int uOrder = 0; uOrder <= orders->data.S32[i]; uOrder++) { 376 for (int vOrder = 0; vOrder <= orders->data.S32[i] - uOrder; vOrder++, index++) { 377 pmSubtractionKernelPreCalc *preCalc = pmSubtractionKernelPreCalcAlloc(PM_SUBTRACTION_KERNEL_ISIS, uOrder, vOrder, size, sigma); // structure to hold precalculated values 378 pmSubtractionKernelPreCalcNormalize (kernels, preCalc, index, size, uOrder, vOrder, fwhms->data.F32[i], true, false); 379 } 380 } 381 for (int order = orders->data.S32[i] + 1; order < 11; order ++, index ++) { 382 // XXX modify size for hermitians to account for sqrt(2) in Hermitian definition (relative to ISIS Gaussian) 383 pmSubtractionKernelPreCalc *preCalc = pmSubtractionKernelPreCalcAlloc(PM_SUBTRACTION_KERNEL_ISIS_RADIAL, order, order, size, sigma / sqrt(2.0)); // structure to hold precalculated values 384 pmSubtractionKernelPreCalcNormalize (kernels, preCalc, index, size, order, order, fwhms->data.F32[i], true, true); 385 } 386 } 387 return kernels; 388 } 389 390 pmSubtractionKernels *pmSubtractionKernelsHERM(int size, int spatialOrder, 391 const psVector *fwhmsIN, const psVector *ordersIN, 392 float penalty, psRegion bounds, pmSubtractionMode mode) 393 { 394 PS_ASSERT_VECTOR_NON_NULL(fwhmsIN, NULL); 395 PS_ASSERT_VECTOR_TYPE(fwhmsIN, PS_TYPE_F32, NULL); 396 PS_ASSERT_VECTOR_NON_NULL(ordersIN, NULL); 397 PS_ASSERT_VECTOR_TYPE(ordersIN, PS_TYPE_S32, NULL); 398 PS_ASSERT_VECTORS_SIZE_EQUAL(fwhmsIN, ordersIN, NULL); 399 PS_ASSERT_INT_POSITIVE(size, NULL); 400 PS_ASSERT_INT_NONNEGATIVE(spatialOrder, NULL); 401 402 // check the requested fwhm values: any values <= 0.0 should be dropped 403 psVector *fwhms = psVectorAllocEmpty (fwhmsIN->n, PS_TYPE_F32); 404 psVector *orders = psVectorAllocEmpty (ordersIN->n, PS_TYPE_S32); 405 for (int i = 0; i < fwhmsIN->n; i++) { 406 if (fwhmsIN->data.F32[i] <= FLT_EPSILON) continue; 407 psVectorAppend(fwhms, fwhmsIN->data.F32[i]); 408 psVectorAppend(orders, ordersIN->data.S32[i]); 409 } 410 411 int numGaussians = fwhms->n; // Number of Gaussians 412 413 int num = 0; // Number of basis functions 414 psString params = NULL; // List of parameters 415 for (int i = 0; i < numGaussians; i++) { 416 int gaussOrder = orders->data.S32[i]; // Polynomial order to apply to Gaussian 417 psStringAppend(¶ms, "(%.1f,%d)", fwhms->data.F32[i], orders->data.S32[i]); 418 num += (gaussOrder + 1) * (gaussOrder + 2) / 2; 419 } 420 421 pmSubtractionKernels *kernels = pmSubtractionKernelsAlloc(num, PM_SUBTRACTION_KERNEL_HERM, size, 422 spatialOrder, penalty, bounds, mode); // Kernels 423 psStringAppend(&kernels->description, "HERM(%d,%s,%d,%.2e)", size, params, spatialOrder, penalty); 424 425 psLogMsg("psModules.imcombine", PS_LOG_INFO, "HERM kernel: %s,%d --> %d elements", 426 params, spatialOrder, num); 427 psFree(params); 428 429 // Set the kernel parameters 430 for (int i = 0, index = 0; i < numGaussians; i++) { 431 float sigma = fwhms->data.F32[i] / (2.0 * sqrtf(2.0 * logf(2.0))); // Gaussian sigma 432 // Iterate over (u,v) order 433 for (int uOrder = 0; uOrder <= orders->data.S32[i]; uOrder++) { 434 for (int vOrder = 0; vOrder <= orders->data.S32[i] - uOrder; vOrder++, index++) { 435 pmSubtractionKernelPreCalc *preCalc = pmSubtractionKernelPreCalcAlloc(PM_SUBTRACTION_KERNEL_HERM, uOrder, vOrder, size, sigma); // structure to hold precalculated values 436 pmSubtractionKernelPreCalcNormalize (kernels, preCalc, index, size, uOrder, vOrder, fwhms->data.F32[i], true, false); 437 } 438 } 439 } 440 441 return kernels; 442 } 443 444 pmSubtractionKernels *pmSubtractionKernelsDECONV_HERM(int size, int spatialOrder, 445 const psVector *fwhmsIN, const psVector *ordersIN, 446 float penalty, psRegion bounds, pmSubtractionMode mode) 447 { 448 PS_ASSERT_VECTOR_NON_NULL(fwhmsIN, NULL); 449 PS_ASSERT_VECTOR_TYPE(fwhmsIN, PS_TYPE_F32, NULL); 450 PS_ASSERT_VECTOR_NON_NULL(ordersIN, NULL); 451 PS_ASSERT_VECTOR_TYPE(ordersIN, PS_TYPE_S32, NULL); 452 PS_ASSERT_VECTORS_SIZE_EQUAL(fwhmsIN, ordersIN, NULL); 453 PS_ASSERT_INT_POSITIVE(size, NULL); 454 PS_ASSERT_INT_NONNEGATIVE(spatialOrder, NULL); 455 456 // check the requested fwhm values: any values <= 0.0 should be dropped 457 psVector *fwhms = psVectorAllocEmpty (fwhmsIN->n, PS_TYPE_F32); 458 psVector *orders = psVectorAllocEmpty (ordersIN->n, PS_TYPE_S32); 459 for (int i = 0; i < fwhmsIN->n; i++) { 460 if (fwhmsIN->data.F32[i] <= FLT_EPSILON) continue; 461 psVectorAppend(fwhms, fwhmsIN->data.F32[i]); 462 psVectorAppend(orders, ordersIN->data.S32[i]); 463 } 464 465 int numGaussians = fwhms->n; // Number of Gaussians 466 467 int num = 0; // Number of basis functions 468 psString params = NULL; // List of parameters 469 for (int i = 0; i < numGaussians; i++) { 470 int gaussOrder = orders->data.S32[i]; // Polynomial order to apply to Gaussian 471 psStringAppend(¶ms, "(%.1f,%d)", fwhms->data.F32[i], orders->data.S32[i]); 472 num += PS_SQR(gaussOrder + 1); 473 } 474 475 pmSubtractionKernels *kernels = pmSubtractionKernelsAlloc(num, PM_SUBTRACTION_KERNEL_DECONV_HERM, size, 476 spatialOrder, penalty, bounds, mode); // Kernels 477 psStringAppend(&kernels->description, "DECONV_HERM(%d,%s,%d,%.2e)", size, params, spatialOrder, penalty); 478 479 psLogMsg("psModules.imcombine", PS_LOG_INFO, "DECONVOLVED HERM kernel: %s,%d --> %d elements", params, spatialOrder, num); 480 psFree(params); 481 482 // XXXXX hard-wired reference sigma for now of 1.7 pix (== 4.0 pix fwhm == 1.0 arcsec in simtest) 483 // generate the Gaussian deconvolution kernel 484 # define DECONV_SIGMA 1.6 485 psKernel *kernelGauss = pmSubtractionDeconvolveGauss (size, DECONV_SIGMA); 486 487 # if 1 488 psArray *deconKernels = psArrayAllocEmpty(100); 489 # endif 490 491 // Set the kernel parameters 492 for (int i = 0, index = 0; i < numGaussians; i++) { 493 float sigma = fwhms->data.F32[i] / (2.0 * sqrtf(2.0 * logf(2.0))); // Gaussian sigma 494 // Iterate over (u,v) order 495 for (int uOrder = 0; uOrder <= orders->data.S32[i]; uOrder++) { 496 for (int vOrder = 0; vOrder <= orders->data.S32[i]; vOrder++, index++) { 497 498 pmSubtractionKernelPreCalc *preCalc = pmSubtractionKernelPreCalcAlloc(PM_SUBTRACTION_KERNEL_HERM, uOrder, vOrder, size, sigma); // structure to hold precalculated values 499 500 // save the generated 2D kernel as the target, deconvolve it by Gaussian, replacing the generated 2D kernel 501 psKernel *kernelTarget = preCalc->kernel; 502 preCalc->kernel = pmSubtractionDeconvolveKernel(kernelTarget, kernelGauss); // Kernel 503 504 // XXX do we use Alard-Lupton normalization (last param true) or not? 505 pmSubtractionKernelPreCalcNormalize (kernels, preCalc, index, size, uOrder, vOrder, fwhms->data.F32[i], true, false); 506 507 // XXXX test demo that deconvolved kernel is valid 508 # if 1 509 psImage *kernelConv = psImageConvolveFFT(NULL, preCalc->kernel->image, NULL, 0, kernelGauss); 510 psArrayAdd (deconKernels, 100, kernelConv); 511 psFree (kernelConv); 512 513 if (!uOrder && !vOrder){ 514 pmSubtractionVisualShowSubtraction (kernelTarget->image, preCalc->kernel->image, kernelConv); 162 515 } 163 164 // Normalise sum of kernel component to unity for even functions 165 if (uOrder % 2 == 0 && vOrder % 2 == 0) { 166 double sum = 0.0; // Sum of kernel component 167 for (int v = 0; v < fullSize; v++) { 168 for (int u = 0; u < fullSize; u++) { 169 sum += xKernel->data.F32[u] * yKernel->data.F32[v]; 170 } 171 } 172 sum = 1.0 / sqrt(sum); 173 psBinaryOp(xKernel, xKernel, "*", psScalarAlloc(sum, PS_TYPE_F32)); 174 psBinaryOp(yKernel, yKernel, "*", psScalarAlloc(sum, PS_TYPE_F32)); 175 psBinaryOp(kernel->image, kernel->image, "*", psScalarAlloc(PS_SQR(sum), PS_TYPE_F32)); 176 kernel->kernel[0][0] -= 1.0; 177 moment *= PS_SQR(sum); 516 # endif 517 } 518 } 519 } 520 521 # if 1 522 psImage *dot = psImageAlloc(deconKernels->n, deconKernels->n, PS_TYPE_F32); 523 for (int i = 0; i < deconKernels->n; i++) { 524 for (int j = 0; j <= i; j++) { 525 psImage *t1 = deconKernels->data[i]; 526 psImage *t2 = deconKernels->data[j]; 527 528 double sum = 0.0; 529 for (int iy = 0; iy < t1->numRows; iy++) { 530 for (int ix = 0; ix < t1->numCols; ix++) { 531 sum += t1->data.F32[iy][ix] * t2->data.F32[iy][ix]; 178 532 } 179 180 181 #if 0182 double sum = 0.0; // Sum of kernel component183 for (int v = -size; v <= size; v++) {184 for (int u = -size; u <= size; u++) {185 sum += kernel->kernel[v][u];186 }187 }188 fprintf(stderr, "%d sum: %lf\n", index, sum);189 #endif190 191 kernels->widths->data.F32[index] = fwhms->data.F32[i];192 kernels->u->data.S32[index] = uOrder;193 kernels->v->data.S32[index] = vOrder;194 if (kernels->preCalc->data[index]) {195 psFree(kernels->preCalc->data[index]);196 }197 kernels->preCalc->data[index] = preCalc;198 kernels->penalties->data.F32[index] = kernels->penalty * fabsf(moment);199 200 psTrace("psModules.imcombine", 7, "Kernel %d: %f %d %d %f\n", index,201 fwhms->data.F32[i], uOrder, vOrder, fabsf(moment));202 533 } 203 } 204 } 534 dot->data.F32[j][i] = sum; 535 dot->data.F32[i][j] = sum; 536 } 537 } 538 pmSubtractionVisualShowSubtraction (dot, NULL, NULL); 539 psFree (dot); 540 psFree (deconKernels); 541 # endif 205 542 206 543 return kernels; … … 212 549 213 550 pmSubtractionKernels *pmSubtractionKernelsAlloc(int numBasisFunctions, pmSubtractionKernelsType type, 214 int size, int spatialOrder, float penalty, 551 int size, int spatialOrder, float penalty, psRegion bounds, 215 552 pmSubtractionMode mode) 216 553 { … … 224 561 kernels->v = psVectorAlloc(numBasisFunctions, PS_TYPE_S32); 225 562 kernels->widths = psVectorAlloc(numBasisFunctions, PS_TYPE_F32); 563 kernels->uStop = NULL; 564 kernels->vStop = NULL; 565 kernels->xMin = bounds.x0; 566 kernels->xMax = bounds.x1; 567 kernels->yMin = bounds.y0; 568 kernels->yMax = bounds.y1; 226 569 kernels->preCalc = psArrayAlloc(numBasisFunctions); 227 570 kernels->penalty = penalty; 228 571 kernels->penalties = psVectorAlloc(numBasisFunctions, PS_TYPE_F32); 229 kernels->uStop = NULL;230 kernels->vStop = NULL;231 572 kernels->size = size; 232 573 kernels->inner = 0; … … 234 575 kernels->bgOrder = 0; 235 576 kernels->mode = mode; 236 kernels->numCols = 0;237 kernels->numRows = 0;238 577 kernels->solution1 = NULL; 239 578 kernels->solution2 = NULL; 579 kernels->mean = NAN; 580 kernels->rms = NAN; 581 kernels->numStamps = 0; 582 kernels->sampleStamps = NULL; 583 584 kernels->fSigResMean = NAN; 585 kernels->fSigResStdev = NAN; 586 kernels->fMaxResMean = NAN; 587 kernels->fMaxResStdev = NAN; 588 kernels->fMinResMean = NAN; 589 kernels->fMinResStdev = NAN; 240 590 241 591 return kernels; 242 592 } 243 593 244 pmSubtractionKernels *pmSubtractionKernelsPOIS(int size, int spatialOrder, float penalty, 594 pmSubtractionKernelPreCalc *pmSubtractionKernelPreCalcAlloc(pmSubtractionKernelsType type, int uOrder, int vOrder, int size, float sigma) { 595 596 pmSubtractionKernelPreCalc *preCalc = psAlloc(sizeof(pmSubtractionKernelPreCalc)); // Kernels, to return 597 psMemSetDeallocator(preCalc, (psFreeFunc)pmSubtractionKernelPreCalcFree); 598 599 // 1D kernel realizations: 600 switch (type) { 601 case PM_SUBTRACTION_KERNEL_ISIS: 602 preCalc->xKernel = pmSubtractionKernelISIS(sigma, uOrder, size); 603 preCalc->yKernel = pmSubtractionKernelISIS(sigma, vOrder, size); 604 preCalc->uCoords = NULL; 605 preCalc->vCoords = NULL; 606 preCalc->poly = NULL; 607 break; 608 case PM_SUBTRACTION_KERNEL_HERM: 609 preCalc->xKernel = pmSubtractionKernelHERM(sigma, uOrder, size); 610 preCalc->yKernel = pmSubtractionKernelHERM(sigma, vOrder, size); 611 preCalc->uCoords = NULL; 612 preCalc->vCoords = NULL; 613 preCalc->poly = NULL; 614 break; 615 case PM_SUBTRACTION_KERNEL_RINGS: 616 // the RINGS kernel uses the uCoords, vCoords, and poly elements of the structure 617 // we allocate these vectors here, but leave the kernel generation to the main function 618 preCalc->xKernel = NULL; 619 preCalc->yKernel = NULL; 620 preCalc->kernel = NULL; 621 preCalc->uCoords = psVectorAllocEmpty(size, PS_TYPE_S32); // u coords 622 preCalc->vCoords = psVectorAllocEmpty(size, PS_TYPE_S32); // v coords 623 preCalc->poly = psVectorAllocEmpty(size, PS_TYPE_F32); // Polynomial 624 return preCalc; 625 case PM_SUBTRACTION_KERNEL_ISIS_RADIAL: 626 preCalc->kernel = pmSubtractionKernelHERM_RADIAL(sigma, uOrder, size); 627 preCalc->xKernel = NULL; 628 preCalc->yKernel = NULL; 629 preCalc->uCoords = NULL; 630 preCalc->vCoords = NULL; 631 preCalc->poly = NULL; 632 return preCalc; 633 default: 634 psAbort("programming error: invalid type for PreCalc kernel"); 635 } 636 637 preCalc->kernel = psKernelAlloc(-size, size, -size, size); // 2D Kernel 638 639 // generate 2D kernel from 1D realizations 640 for (int v = -size, y = 0; v <= size; v++, y++) { 641 for (int u = -size, x = 0; u <= size; u++, x++) { 642 preCalc->kernel->kernel[v][u] = preCalc->xKernel->data.F32[x] * preCalc->yKernel->data.F32[y]; // Value of kernel 643 } 644 } 645 646 return preCalc; 647 } 648 649 pmSubtractionKernels *pmSubtractionKernelsPOIS(int size, int spatialOrder, float penalty, psRegion bounds, 245 650 pmSubtractionMode mode) 246 651 { … … 251 656 252 657 pmSubtractionKernels *kernels = pmSubtractionKernelsAlloc(0, PM_SUBTRACTION_KERNEL_POIS, size, 253 spatialOrder, penalty, mode); // The kernels658 spatialOrder, penalty, bounds, mode); // Kernels 254 659 psStringAppend(&kernels->description, "POIS(%d,%d,%.2e)", size, spatialOrder, penalty); 255 660 psLogMsg("psModules.imcombine", PS_LOG_INFO, "POIS kernel: %d,%d --> %d elements", … … 266 671 pmSubtractionKernels *pmSubtractionKernelsISIS(int size, int spatialOrder, 267 672 const psVector *fwhms, const psVector *orders, 268 float penalty, p mSubtractionMode mode)673 float penalty, psRegion bounds, pmSubtractionMode mode) 269 674 { 270 675 pmSubtractionKernels *kernels = p_pmSubtractionKernelsRawISIS(size, spatialOrder, fwhms, orders, 271 penalty, mode); // Kernels676 penalty, bounds, mode); // Kernels 272 677 if (!kernels) { 273 678 return NULL; … … 278 683 279 684 pmSubtractionKernels *pmSubtractionKernelsSPAM(int size, int spatialOrder, int inner, int binning, 280 float penalty, p mSubtractionMode mode)685 float penalty, psRegion bounds, pmSubtractionMode mode) 281 686 { 282 687 PS_ASSERT_INT_POSITIVE(size, NULL); … … 299 704 300 705 pmSubtractionKernels *kernels = pmSubtractionKernelsAlloc(num, PM_SUBTRACTION_KERNEL_SPAM, size, 301 spatialOrder, penalty, mode); // The kernels706 spatialOrder, penalty, bounds, mode); // Kernels 302 707 kernels->inner = inner; 303 708 psStringAppend(&kernels->description, "SPAM(%d,%d,%d,%d,%.2e)", size, inner, binning, spatialOrder, … … 370 775 371 776 pmSubtractionKernels *pmSubtractionKernelsFRIES(int size, int spatialOrder, int inner, float penalty, 372 p mSubtractionMode mode)777 psRegion bounds, pmSubtractionMode mode) 373 778 { 374 779 PS_ASSERT_INT_POSITIVE(size, NULL); … … 397 802 398 803 pmSubtractionKernels *kernels = pmSubtractionKernelsAlloc(num, PM_SUBTRACTION_KERNEL_FRIES, size, 399 spatialOrder, penalty, mode); // The kernels804 spatialOrder, penalty, bounds, mode); // Kernels 400 805 kernels->inner = inner; 401 806 psStringAppend(&kernels->description, "FRIES(%d,%d,%d,%.2e)", size, inner, spatialOrder, penalty); … … 463 868 } 464 869 465 // Grid United with Normal Kernel 870 // Grid United with Normal Kernel [description: GUNK=ISIS(...)+POIS(...)] 466 871 pmSubtractionKernels *pmSubtractionKernelsGUNK(int size, int spatialOrder, const psVector *fwhms, 467 872 const psVector *orders, int inner, float penalty, 468 p mSubtractionMode mode)873 psRegion bounds, pmSubtractionMode mode) 469 874 { 470 875 PS_ASSERT_INT_POSITIVE(size, NULL); … … 479 884 480 885 pmSubtractionKernels *kernels = p_pmSubtractionKernelsRawISIS(size, spatialOrder, fwhms, orders, 481 penalty, mode); // Kernels886 penalty, bounds, mode); // Kernels 482 887 kernels->type = PM_SUBTRACTION_KERNEL_GUNK; 483 888 psStringPrepend(&kernels->description, "GUNK="); … … 495 900 // RINGS --- just what it says 496 901 pmSubtractionKernels *pmSubtractionKernelsRINGS(int size, int spatialOrder, int inner, int ringsOrder, 497 float penalty, p mSubtractionMode mode)902 float penalty, psRegion bounds, pmSubtractionMode mode) 498 903 { 499 904 PS_ASSERT_INT_POSITIVE(size, NULL); … … 526 931 527 932 pmSubtractionKernels *kernels = pmSubtractionKernelsAlloc(num, PM_SUBTRACTION_KERNEL_RINGS, size, 528 spatialOrder, penalty, mode); // The kernels933 spatialOrder, penalty, bounds, mode); // Kernels 529 934 kernels->inner = inner; 530 935 psStringAppend(&kernels->description, "RINGS(%d,%d,%d,%d,%.2e)", size, inner, ringsOrder, spatialOrder, … … 566 971 for (int vOrder = 0; vOrder <= (i == 0 ? 0 : ringsOrder - uOrder); vOrder++, index++) { 567 972 568 psArray *data = psArrayAlloc(3); // Container for data 569 psVector *uCoords = data->data[0] = psVectorAllocEmpty(RINGS_BUFFER, PS_TYPE_S32); // u coords 570 psVector *vCoords = data->data[1] = psVectorAllocEmpty(RINGS_BUFFER, PS_TYPE_S32); // v coords 571 psVector *poly = data->data[2] = psVectorAllocEmpty(RINGS_BUFFER, PS_TYPE_F32); // Polynomial 973 pmSubtractionKernelPreCalc *preCalc = pmSubtractionKernelPreCalcAlloc (PM_SUBTRACTION_KERNEL_RINGS, 0, 0, RINGS_BUFFER, 0.0); 572 974 double moment = 0.0; // Moment, for penalty 573 975 574 976 if (i == 0) { 575 977 // Central pixel is easy 576 uCoords->data.S32[0] = vCoords->data.S32[0] = 0; 577 poly->data.F32[0] = 1.0; 578 uCoords->n = vCoords->n = poly->n = 1; 978 preCalc->uCoords->data.S32[0] = 0; 979 preCalc->vCoords->data.S32[0] = 0; 980 preCalc->poly->data.F32[0] = 1.0; 981 preCalc->uCoords->n = 1; 982 preCalc->vCoords->n = 1; 983 preCalc->poly->n = 1; 579 984 radiusLast = 0; 580 985 moment = 0.0; … … 594 999 float polyVal = uPoly * vPoly; // Value of polynomial 595 1000 if (polyVal != 0) { // No point adding it otherwise 596 uCoords->data.S32[j] = u;597 vCoords->data.S32[j] = v;598 p oly->data.F32[j] = polyVal;1001 preCalc->uCoords->data.S32[j] = u; 1002 preCalc->vCoords->data.S32[j] = v; 1003 preCalc->poly->data.F32[j] = polyVal; 599 1004 norm += polyVal; 600 moment += polyVal* PS_SQR(PS_SQR(u) + PS_SQR(v));601 602 psVectorExtend( uCoords, RINGS_BUFFER, 1);603 psVectorExtend( vCoords, RINGS_BUFFER, 1);604 psVectorExtend(p oly, RINGS_BUFFER, 1);1005 moment += PS_SQR(polyVal) * PS_SQR(PS_SQR(u) + PS_SQR(v)); 1006 1007 psVectorExtend(preCalc->uCoords, RINGS_BUFFER, 1); 1008 psVectorExtend(preCalc->vCoords, RINGS_BUFFER, 1); 1009 psVectorExtend(preCalc->poly, RINGS_BUFFER, 1); 605 1010 psTrace("psModules.imcombine", 9, "u = %d, v = %d, poly = %f\n", 606 u, v, p oly->data.F32[j]);1011 u, v, preCalc->poly->data.F32[j]); 607 1012 j++; 608 1013 } … … 612 1017 // Normalise kernel component to unit sum 613 1018 if (uOrder % 2 == 0 && vOrder % 2 == 0) { 614 psBinaryOp(p oly,poly, "*", psScalarAlloc(1.0 / norm, PS_TYPE_F32));1019 psBinaryOp(preCalc->poly, preCalc->poly, "*", psScalarAlloc(1.0 / norm, PS_TYPE_F32)); 615 1020 // Add subtraction of 0,0 component to preserve photometric scaling 616 uCoords->data.S32[j] = 0;617 vCoords->data.S32[j] = 0;618 p oly->data.F32[j] = -1.0;619 psVectorExtend( uCoords, RINGS_BUFFER, 1);620 psVectorExtend( vCoords, RINGS_BUFFER, 1);621 psVectorExtend(p oly, RINGS_BUFFER, 1);1021 preCalc->uCoords->data.S32[j] = 0; 1022 preCalc->vCoords->data.S32[j] = 0; 1023 preCalc->poly->data.F32[j] = -1.0; 1024 psVectorExtend(preCalc->uCoords, RINGS_BUFFER, 1); 1025 psVectorExtend(preCalc->vCoords, RINGS_BUFFER, 1); 1026 psVectorExtend(preCalc->poly, RINGS_BUFFER, 1); 622 1027 } else { 623 1028 norm = powf(size, uOrder) * powf(size, vOrder); 624 psBinaryOp(p oly,poly, "*", psScalarAlloc(1.0 / norm, PS_TYPE_F32));1029 psBinaryOp(preCalc->poly, preCalc->poly, "*", psScalarAlloc(1.0 / norm, PS_TYPE_F32)); 625 1030 } 626 moment /= norm;1031 moment /= PS_SQR(norm); 627 1032 } 628 1033 629 psTrace("psModules.imcombine", 8, "%ld pixels in kernel\n", uCoords->n);630 631 kernels->preCalc->data[index] = data;1034 psTrace("psModules.imcombine", 8, "%ld pixels in kernel\n", preCalc->uCoords->n); 1035 1036 kernels->preCalc->data[index] = preCalc; 632 1037 kernels->u->data.S32[index] = uOrder; 633 1038 kernels->v->data.S32[index] = vOrder; 634 1039 kernels->penalties->data.F32[index] = kernels->penalty * fabsf(moment); 1040 if (!isfinite(kernels->penalties->data.F32[index])) { 1041 psAbort ("invalid penalty"); 1042 } 635 1043 636 1044 psTrace("psModules.imcombine", 7, "Kernel %d: %d %d %d\n", index, … … 645 1053 pmSubtractionKernels *pmSubtractionKernelsGenerate(pmSubtractionKernelsType type, int size, int spatialOrder, 646 1054 const psVector *fwhms, const psVector *orders, int inner, 647 int binning, int ringsOrder, float penalty, 1055 int binning, int ringsOrder, float penalty, psRegion bounds, 648 1056 pmSubtractionMode mode) 649 1057 { 650 1058 switch (type) { 651 1059 case PM_SUBTRACTION_KERNEL_POIS: 652 return pmSubtractionKernelsPOIS(size, spatialOrder, penalty, mode);1060 return pmSubtractionKernelsPOIS(size, spatialOrder, penalty, bounds, mode); 653 1061 case PM_SUBTRACTION_KERNEL_ISIS: 654 return pmSubtractionKernelsISIS(size, spatialOrder, fwhms, orders, penalty, mode); 1062 return pmSubtractionKernelsISIS(size, spatialOrder, fwhms, orders, penalty, bounds, mode); 1063 case PM_SUBTRACTION_KERNEL_ISIS_RADIAL: 1064 return pmSubtractionKernelsISIS_RADIAL(size, spatialOrder, fwhms, orders, penalty, bounds, mode); 1065 case PM_SUBTRACTION_KERNEL_HERM: 1066 return pmSubtractionKernelsHERM(size, spatialOrder, fwhms, orders, penalty, bounds, mode); 1067 case PM_SUBTRACTION_KERNEL_DECONV_HERM: 1068 return pmSubtractionKernelsDECONV_HERM(size, spatialOrder, fwhms, orders, penalty, bounds, mode); 655 1069 case PM_SUBTRACTION_KERNEL_SPAM: 656 return pmSubtractionKernelsSPAM(size, spatialOrder, inner, binning, penalty, mode);1070 return pmSubtractionKernelsSPAM(size, spatialOrder, inner, binning, penalty, bounds, mode); 657 1071 case PM_SUBTRACTION_KERNEL_FRIES: 658 return pmSubtractionKernelsFRIES(size, spatialOrder, inner, penalty, mode);1072 return pmSubtractionKernelsFRIES(size, spatialOrder, inner, penalty, bounds, mode); 659 1073 case PM_SUBTRACTION_KERNEL_GUNK: 660 return pmSubtractionKernelsGUNK(size, spatialOrder, fwhms, orders, inner, penalty, mode);1074 return pmSubtractionKernelsGUNK(size, spatialOrder, fwhms, orders, inner, penalty, bounds, mode); 661 1075 case PM_SUBTRACTION_KERNEL_RINGS: 662 return pmSubtractionKernelsRINGS(size, spatialOrder, inner, ringsOrder, penalty, mode);1076 return pmSubtractionKernelsRINGS(size, spatialOrder, inner, ringsOrder, penalty, bounds, mode); 663 1077 default: 664 1078 psError(PS_ERR_BAD_PARAMETER_VALUE, true, "Unknown kernel type: %x", type); … … 696 1110 697 1111 pmSubtractionKernels *pmSubtractionKernelsFromDescription(const char *description, int bgOrder, 698 p mSubtractionMode mode)1112 psRegion bounds, pmSubtractionMode mode) 699 1113 { 700 1114 PS_ASSERT_STRING_NON_EMPTY(description, NULL); … … 715 1129 float penalty = 0.0; // Penalty for wideness 716 1130 717 if (strncmp(description, "ISIS", 4) == 0) { 718 // XXX Support for GUNK 719 if (strstr(description, "+POIS")) { 720 type = PM_SUBTRACTION_KERNEL_GUNK; 721 psAbort("Deciphering GUNK kernels (%s) is not currently supported.", description); 722 } else { 723 type = PM_SUBTRACTION_KERNEL_ISIS; 724 char *ptr = (char*)description + 5; // Eat "ISIS(" 725 PARSE_STRING_NUMBER(size, ptr, ',', parseStringInt); 726 727 // Count the number of Gaussians 728 int numGauss = 0; 729 for (char *string = ptr; string; string = strchr(string + 1, '(')) { 730 numGauss++; 731 } 732 733 fwhms = psVectorAlloc(numGauss, PS_TYPE_F32); 734 orders = psVectorAlloc(numGauss, PS_TYPE_S32); 735 736 for (int i = 0; i < numGauss; i++) { 737 ptr++; // Eat the '(' 738 PARSE_STRING_NUMBER(fwhms->data.F32[i], ptr, ',', parseStringFloat); // Eat "1.234," 739 PARSE_STRING_NUMBER(orders->data.S32[i], ptr, ')', parseStringInt); // Eat "3)" 740 } 741 742 ptr++; // Eat ',' 743 PARSE_STRING_NUMBER(spatialOrder, ptr, ',', parseStringInt); 744 penalty = parseStringFloat(ptr); 745 } 746 } else if (strncmp(description, "RINGS", 5) == 0) { 747 type = PM_SUBTRACTION_KERNEL_RINGS; 748 char *ptr = (char*)description + 6; 1131 // currently known descriptions: 1132 // ISIS(...), ISIS_RADIAL(...), HERM(...), DECONV_HERM(...), POIS(...), SPAM(...), 1133 // FRIES(...), GUNK=ISIS(...)+POIS(...), RINGS(...), 1134 // the descriptive name is the set of characters before the ( 1135 1136 type = pmSubtractionKernelsTypeFromString (description); 1137 char *ptr = strchr(description, '(') + 1; 1138 psAssert (ptr, "description is missing kernel parameters"); 1139 1140 switch (type) { 1141 case PM_SUBTRACTION_KERNEL_ISIS: 1142 case PM_SUBTRACTION_KERNEL_ISIS_RADIAL: 1143 case PM_SUBTRACTION_KERNEL_HERM: 1144 case PM_SUBTRACTION_KERNEL_DECONV_HERM: 1145 PARSE_STRING_NUMBER(size, ptr, ',', parseStringInt); 1146 1147 // Count the number of Gaussians 1148 int numGauss = 0; 1149 for (char *string = ptr; string; string = strchr(string + 1, '(')) { 1150 numGauss++; 1151 } 1152 1153 fwhms = psVectorAlloc(numGauss, PS_TYPE_F32); 1154 orders = psVectorAlloc(numGauss, PS_TYPE_S32); 1155 1156 for (int i = 0; i < numGauss; i++) { 1157 ptr++; // Eat the '(' 1158 PARSE_STRING_NUMBER(fwhms->data.F32[i], ptr, ',', parseStringFloat); // Eat "1.234," 1159 PARSE_STRING_NUMBER(orders->data.S32[i], ptr, ')', parseStringInt); // Eat "3)" 1160 } 1161 1162 ptr++; // Eat ',' 1163 PARSE_STRING_NUMBER(spatialOrder, ptr, ',', parseStringInt); 1164 penalty = parseStringFloat(ptr); 1165 break; 1166 case PM_SUBTRACTION_KERNEL_RINGS: 749 1167 PARSE_STRING_NUMBER(size, ptr, ',', parseStringInt); 750 1168 PARSE_STRING_NUMBER(inner, ptr, ',', parseStringInt); … … 752 1170 PARSE_STRING_NUMBER(spatialOrder, ptr, ',', parseStringInt); 753 1171 PARSE_STRING_NUMBER(penalty, ptr, ')', parseStringInt); 754 } else { 755 psAbort("Deciphering kernels other than ISIS and RINGS is not currently supported."); 756 } 757 758 759 return pmSubtractionKernelsGenerate(type, size, spatialOrder, fwhms, orders, 760 inner, binning, ringsOrder, penalty, mode); 761 } 762 763 1172 break; 1173 default: 1174 psAbort("Deciphering kernels other than ISIS, HERM, DECONV_HERM or RINGS is not currently supported."); 1175 } 1176 1177 return pmSubtractionKernelsGenerate(type, size, spatialOrder, fwhms, orders, inner, binning, 1178 ringsOrder, penalty, bounds, mode); 1179 } 1180 1181 1182 // the input string can either be just the name or the description string. Currently known 1183 // descriptions: ISIS(...), ISIS_RADIAL(...), HERM(...), DECONV_HERM(...), POIS(...), 1184 // SPAM(...), FRIES(...), GUNK=ISIS(...)+POIS(...), RINGS(...), 764 1185 pmSubtractionKernelsType pmSubtractionKernelsTypeFromString(const char *type) 765 1186 { 766 if (strcasecmp(type, "POIS") == 0) { 1187 // for a bare name (ISIS, HERM), use the full string length. 1188 // otherwise, use the length up to the first '(' 1189 int nameLength = strlen(type); 1190 char *ptr = strchr(type, '('); 1191 if (ptr) { 1192 nameLength = ptr - type; 1193 } 1194 1195 if (strncasecmp(type, "POIS", nameLength) == 0) { 767 1196 return PM_SUBTRACTION_KERNEL_POIS; 768 1197 } 769 if (str casecmp(type, "ISIS") == 0) {1198 if (strncasecmp(type, "ISIS", nameLength) == 0) { 770 1199 return PM_SUBTRACTION_KERNEL_ISIS; 771 1200 } 772 if (strcasecmp(type, "SPAM") == 0) { 1201 if (strncasecmp(type, "ISIS_RADIAL", nameLength) == 0) { 1202 return PM_SUBTRACTION_KERNEL_ISIS_RADIAL; 1203 } 1204 if (strncasecmp(type, "HERM", nameLength) == 0) { 1205 return PM_SUBTRACTION_KERNEL_HERM; 1206 } 1207 if (strncasecmp(type, "DECONV_HERM", nameLength) == 0) { 1208 return PM_SUBTRACTION_KERNEL_DECONV_HERM; 1209 } 1210 if (strncasecmp(type, "SPAM", nameLength) == 0) { 773 1211 return PM_SUBTRACTION_KERNEL_SPAM; 774 1212 } 775 if (str casecmp(type, "FRIES") == 0) {1213 if (strncasecmp(type, "FRIES", nameLength) == 0) { 776 1214 return PM_SUBTRACTION_KERNEL_FRIES; 777 1215 } 778 if (str casecmp(type, "GUNK") == 0) {1216 if (strncasecmp(type, "GUNK", nameLength) == 0) { 779 1217 return PM_SUBTRACTION_KERNEL_GUNK; 780 1218 } 781 if (strcasecmp(type, "RINGS") == 0) { 1219 // note that GUNK has a somewhat different description 1220 if (strncasecmp(type, "GUNK=ISIS", nameLength) == 0) { 1221 return PM_SUBTRACTION_KERNEL_GUNK; 1222 } 1223 if (strncasecmp(type, "RINGS", nameLength) == 0) { 782 1224 return PM_SUBTRACTION_KERNEL_RINGS; 783 1225 } … … 810 1252 out->bgOrder = in->bgOrder; 811 1253 out->mode = in->mode; 812 out->numCols = in->numCols; 813 out->numRows = in->numRows; 1254 out->xMin = in->xMin; 1255 out->xMax = in->xMax; 1256 out->yMin = in->yMin; 1257 out->yMax = in->yMax; 814 1258 out->solution1 = in->solution1 ? psVectorCopy(NULL, in->solution1, PS_TYPE_F64) : NULL; 815 1259 out->solution2 = in->solution2 ? psVectorCopy(NULL, in->solution2, PS_TYPE_F64) : NULL; 1260 out->sampleStamps = psMemIncrRefCounter(in->sampleStamps); 816 1261 817 1262 return out; -
trunk/psModules/src/imcombine/pmSubtractionKernels.h
r26157 r26893 10 10 PM_SUBTRACTION_KERNEL_POIS, ///< Pan-STARRS Optimal Image Subtraction --- delta functions 11 11 PM_SUBTRACTION_KERNEL_ISIS, ///< Traditional kernel --- gaussians modified by polynomials 12 PM_SUBTRACTION_KERNEL_ISIS_RADIAL, ///< ISIS + higher-order radial Hermitians 13 PM_SUBTRACTION_KERNEL_HERM, ///< Hermitian polynomial kernels 14 PM_SUBTRACTION_KERNEL_DECONV_HERM, ///< Deconvolved Hermitian polynomial kernels 12 15 PM_SUBTRACTION_KERNEL_SPAM, ///< Summed Pixels for Advanced Matching --- summed delta functions 13 16 PM_SUBTRACTION_KERNEL_FRIES, ///< Fibonacci Radius Increases Excellence of Subtraction … … 29 32 pmSubtractionKernelsType type; ///< Type of kernels --- allowing the use of multiple kernels 30 33 psString description; ///< Description of the kernel parameters 34 int xMin, xMax, yMin, yMax; ///< Bounds of image (for normalisation) 31 35 long num; ///< Number of kernel components (not including the spatial ones) 32 psVector *u, *v; ///< Offset (for POIS) or polynomial order (for ISIS )33 psVector *widths; ///< Gaussian FWHMs (ISIS )36 psVector *u, *v; ///< Offset (for POIS) or polynomial order (for ISIS, HERM or DECONV_HERM) 37 psVector *widths; ///< Gaussian FWHMs (ISIS, HERM or DECONV_HERM) 34 38 psVector *uStop, *vStop; ///< Width of kernel element (SPAM,FRIES only) 35 psArray *preCalc; ///< Array of images containing pre-calculated kernel (for ISIS )39 psArray *preCalc; ///< Array of images containing pre-calculated kernel (for ISIS, HERM or DECONV_HERM) 36 40 float penalty; ///< Penalty for wideness 37 41 psVector *penalties; ///< Penalty for each kernel component … … 41 45 int bgOrder; ///< The order for the background fitting 42 46 pmSubtractionMode mode; ///< Mode for subtraction 43 int numCols, numRows; ///< Size of image (for normalisation), or zero to use image provided44 47 psVector *solution1, *solution2; ///< Solution for the PSF matching 45 48 // Quality information 46 49 float mean, rms; ///< Mean and RMS of chi^2 from stamps 47 50 int numStamps; ///< Number of good stamps 51 float fSigResMean; ///< mean fractional stdev of residuals 52 float fSigResStdev; ///< stdev of fractional stdev of residuals 53 float fMaxResMean; ///< mean fractional positive swing in residuals 54 float fMaxResStdev; ///< stdev of fractional positive swing in residuals 55 float fMinResMean; ///< mean fractional negative swing in residuals 56 float fMinResStdev; ///< stdev of fractional negative swing in residuals 57 psArray *sampleStamps; ///< array of brightest set of stamps for output visualizations 48 58 } pmSubtractionKernels; 59 60 // pmSubtractionKernels->preCalc is an array of pmSubtractionKernelPreCalc structures 61 typedef struct { 62 psVector *uCoords; // used by RINGS 63 psVector *vCoords; // used by RINGS 64 psVector *poly; // used by RINGS 65 66 psVector *xKernel; // used by ISIS, HERM, DECONV_HERM 67 psVector *yKernel; // used by ISIS, HERM, DECONV_HERM 68 psKernel *kernel; // used by ISIS, HERM, DECONV_HERM 69 } pmSubtractionKernelPreCalc; 49 70 50 71 // Assertion to check pmSubtractionKernels … … 64 85 PS_ASSERT_VECTOR_SIZE((KERNELS)->widths, (KERNELS)->num, RETURNVALUE); \ 65 86 } \ 87 if ((KERNELS)->type == PM_SUBTRACTION_KERNEL_ISIS_RADIAL) { \ 88 PS_ASSERT_VECTOR_NON_NULL((KERNELS)->widths, RETURNVALUE); \ 89 PS_ASSERT_VECTOR_TYPE((KERNELS)->widths, PS_TYPE_F32, RETURNVALUE); \ 90 PS_ASSERT_VECTOR_SIZE((KERNELS)->widths, (KERNELS)->num, RETURNVALUE); \ 91 } \ 92 if ((KERNELS)->type == PM_SUBTRACTION_KERNEL_HERM) { \ 93 PS_ASSERT_VECTOR_NON_NULL((KERNELS)->widths, RETURNVALUE); \ 94 PS_ASSERT_VECTOR_TYPE((KERNELS)->widths, PS_TYPE_F32, RETURNVALUE); \ 95 PS_ASSERT_VECTOR_SIZE((KERNELS)->widths, (KERNELS)->num, RETURNVALUE); \ 96 } \ 97 if ((KERNELS)->type == PM_SUBTRACTION_KERNEL_DECONV_HERM) { \ 98 PS_ASSERT_VECTOR_NON_NULL((KERNELS)->widths, RETURNVALUE); \ 99 PS_ASSERT_VECTOR_TYPE((KERNELS)->widths, PS_TYPE_F32, RETURNVALUE); \ 100 PS_ASSERT_VECTOR_SIZE((KERNELS)->widths, (KERNELS)->num, RETURNVALUE); \ 101 } \ 66 102 if ((KERNELS)->uStop || (KERNELS)->vStop) { \ 67 103 PS_ASSERT_VECTOR_NON_NULL((KERNELS)->uStop, RETURNVALUE); \ … … 99 135 } 100 136 137 // Generate 1D convolution kernel for ISIS 138 psVector *pmSubtractionKernelISIS(float sigma, // Gaussian width 139 int order, // Polynomial order 140 int size // Kernel half-size 141 ); 142 143 // Generate 1D convolution kernel for HERM (normalized for 2D) 144 psVector *pmSubtractionKernelHERM(float sigma, // Gaussian width 145 int order, // Polynomial order 146 int size // Kernel half-size 147 ); 148 101 149 /// Generate a delta-function grid for subtraction kernels (like the POIS kernel) 102 150 bool p_pmSubtractionKernelsAddGrid(pmSubtractionKernels *kernels, ///< The subtraction kernels to append to … … 114 162 int spatialOrder, ///< Order of spatial variations 115 163 float penalty, ///< Penalty for wideness 164 psRegion bounds, ///< Bounds for validity 116 165 pmSubtractionMode mode ///< Mode for subtraction 117 166 ); 167 168 /// Allocator for pre-calculated kernel data structure 169 pmSubtractionKernelPreCalc *pmSubtractionKernelPreCalcAlloc( 170 pmSubtractionKernelsType type, ///< type of kernel to allocate (not all can be pre-calculated) 171 int uOrder, ///< order in x-direction 172 int vOrder, ///< order in x-direction 173 int size, ///< Half-size of the kernel 174 float sigma ///< sigma of gaussian kernel 175 ); 176 118 177 119 178 /// Generate POIS kernels … … 121 180 int spatialOrder, ///< Order of spatial variations 122 181 float penalty, ///< Penalty for wideness 182 psRegion bounds, ///< Bounds for validity 123 183 pmSubtractionMode mode ///< Mode for subtraction 124 184 ); … … 130 190 const psVector *orders, ///< Polynomial order of gaussians 131 191 float penalty, ///< Penalty for wideness 192 psRegion bounds, ///< Bounds for validity 132 193 pmSubtractionMode mode ///< Mode for subtraction 133 194 ); … … 139 200 const psVector *orders, ///< Polynomial order of gaussians 140 201 float penalty, ///< Penalty for wideness 202 psRegion bounds, ///< Bounds for validity 141 203 pmSubtractionMode mode ///< Mode for subtraction 142 204 ); 205 206 /// Generate ISIS + RADIAL_HERM kernels 207 pmSubtractionKernels *pmSubtractionKernelsISIS_RADIAL(int size, ///< Half-size of the kernel 208 int spatialOrder, ///< Order of spatial variations 209 const psVector *fwhms, ///< Gaussian FWHMs 210 const psVector *orders, ///< Polynomial order of gaussians 211 float penalty, ///< Penalty for wideness 212 psRegion bounds, ///< Bounds for validity 213 pmSubtractionMode mode ///< Mode for subtraction 214 ); 215 216 /// Generate HERM kernels 217 pmSubtractionKernels *pmSubtractionKernelsHERM(int size, ///< Half-size of the kernel 218 int spatialOrder, ///< Order of spatial variations 219 const psVector *fwhms, ///< Gaussian FWHMs 220 const psVector *orders, ///< order of hermitian polynomials 221 float penalty, ///< Penalty for wideness 222 psRegion bounds, ///< Bounds for validity 223 pmSubtractionMode mode ///< Mode for subtraction 224 ); 225 226 /// Generate DECONV_HERM kernels 227 pmSubtractionKernels *pmSubtractionKernelsDECONV_HERM(int size, ///< Half-size of the kernel 228 int spatialOrder, ///< Order of spatial variations 229 const psVector *fwhms, ///< Gaussian FWHMs 230 const psVector *orders, ///< order of hermitian polynomials 231 float penalty, ///< Penalty for wideness 232 psRegion bounds, ///< Bounds for validity 233 pmSubtractionMode mode ///< Mode for subtraction 234 ); 143 235 144 236 /// Generate SPAM kernels … … 148 240 int binning, ///< Kernel binning factor 149 241 float penalty, ///< Penalty for wideness 242 psRegion bounds, ///< Bounds for validity 150 243 pmSubtractionMode mode ///< Mode for subtraction 151 244 ); … … 156 249 int inner, ///< Inner radius to preserve unbinned 157 250 float penalty, ///< Penalty for wideness 251 psRegion bounds, ///< Bounds for validity 158 252 pmSubtractionMode mode ///< Mode for subtraction 159 253 ); … … 166 260 int inner, ///< Inner radius containing grid of delta functions 167 261 float penalty, ///< Penalty for wideness 262 psRegion bounds, ///< Bounds for validity 168 263 pmSubtractionMode mode ///< Mode for subtraction 169 264 ); … … 175 270 int ringsOrder, ///< Polynomial order 176 271 float penalty, ///< Penalty for wideness 272 psRegion bounds, ///< Bounds for validity 177 273 pmSubtractionMode mode ///< Mode for subtraction 178 274 ); … … 189 285 int ringsOrder, ///< Polynomial order for RINGS 190 286 float penalty, ///< Penalty for wideness 287 psRegion bounds, ///< Bounds for validity 191 288 pmSubtractionMode mode ///< Mode for subtraction 192 289 ); … … 196 293 const char *description, ///< Description of kernel 197 294 int bgOrder, ///< Polynomial order for background fitting 295 psRegion bounds, ///< Bounds for validity 198 296 pmSubtractionMode mode ///< Mode for subtraction 199 297 ); -
trunk/psModules/src/imcombine/pmSubtractionMask.c
r24257 r26893 38 38 ////////////////////////////////////////////////////////////////////////////////////////////////////////////// 39 39 40 psImage *pmSubtractionMask(const psImage *mask1, const psImage *mask2, psImageMaskType maskVal, 41 int size, int footprint, float badFrac, pmSubtractionMode mode) 42 { 43 PS_ASSERT_IMAGE_NON_NULL(mask1, NULL); 44 PS_ASSERT_IMAGE_TYPE(mask1, PS_TYPE_IMAGE_MASK, NULL); 45 if (mask2) { 46 PS_ASSERT_IMAGE_NON_NULL(mask2, NULL); 47 PS_ASSERT_IMAGE_TYPE(mask2, PS_TYPE_IMAGE_MASK, NULL); 48 PS_ASSERT_IMAGES_SIZE_EQUAL(mask2, mask1, NULL); 49 } 40 psImage *pmSubtractionMask(psRegion *bounds, const pmReadout *ro1, const pmReadout *ro2, 41 psImageMaskType maskVal, int size, int footprint, float badFrac, 42 pmSubtractionMode mode) 43 { 44 PM_ASSERT_READOUT_NON_NULL(ro1, NULL); 45 PM_ASSERT_READOUT_IMAGE(ro1, NULL); 46 PM_ASSERT_READOUT_MASK(ro1, NULL); 47 PM_ASSERT_READOUT_NON_NULL(ro2, NULL); 48 PM_ASSERT_READOUT_IMAGE(ro2, NULL); 49 PM_ASSERT_READOUT_MASK(ro2, NULL); 50 PS_ASSERT_IMAGES_SIZE_EQUAL(ro1->image, ro2->image, NULL); 50 51 PS_ASSERT_INT_NONNEGATIVE(size, NULL); 51 52 PS_ASSERT_INT_NONNEGATIVE(footprint, NULL); … … 55 56 } 56 57 57 int numCols = mask1->numCols, numRows = mask1->numRows; // Size of the images58 int numCols = ro1->image->numCols, numRows = ro1->image->numRows; // Size of the images 58 59 59 60 // Dereference inputs for convenience 60 psImageMaskType **data1 = mask1->data.PS_TYPE_IMAGE_MASK_DATA; 61 psImageMaskType **data2 = NULL; 62 if (mask2) { 63 data2 = mask2->data.PS_TYPE_IMAGE_MASK_DATA; 64 } 61 psF32 **imageData1 = ro1->image->data.F32, **imageData2 = ro2->image->data.F32; 62 psImageMaskType **maskData1 = ro1->mask->data.PS_TYPE_IMAGE_MASK_DATA, 63 **maskData2 = ro2->mask->data.PS_TYPE_IMAGE_MASK_DATA; 65 64 66 65 // First, a pass through to determine the fraction of bad pixels 67 if (isfinite(badFrac) && badFrac != 1.0) { 66 if (bounds || (isfinite(badFrac) && badFrac != 1.0)) { 67 int xMin = numCols, xMax = 0, yMin = numRows, yMax = 0; // Bounds of good pixels 68 68 int numBad = 0; // Number of bad pixels 69 69 for (int y = 0; y < numRows; y++) { 70 70 for (int x = 0; x < numCols; x++) { 71 if ( data1[y][x] & maskVal) {71 if ((maskData1[y][x] & maskVal) || !isfinite(imageData1[y][x])) { 72 72 numBad++; 73 73 continue; 74 74 } 75 if ( data2 && data2[y][x] & maskVal) {75 if ((maskData2[y][x] & maskVal) || !isfinite(imageData2[y][x])) { 76 76 numBad++; 77 continue; 77 78 } 78 } 79 } 80 if (numBad > badFrac * numCols * numRows) { 79 xMin = PS_MIN(xMin, x); 80 xMax = PS_MAX(xMax, x); 81 yMin = PS_MIN(yMin, y); 82 yMax = PS_MAX(yMax, y); 83 } 84 } 85 if (bounds) { 86 bounds->x0 = xMin; 87 bounds->x1 = xMax; 88 bounds->y0 = yMin; 89 bounds->y1 = yMax; 90 } 91 if (isfinite(badFrac) && badFrac != 1.0 && numBad > badFrac * numCols * numRows) { 81 92 psError(PM_ERR_SMALL_AREA, true, 82 93 "Fraction of bad pixels (%d/%d=%f) exceeds limit (%f)\n", … … 117 128 for (int y = 0; y < numRows; y++) { 118 129 for (int x = 0; x < numCols; x++) { 119 if ( data1[y][x] & maskVal) {130 if (maskData1[y][x] & maskVal) { 120 131 maskData[y][x] |= PM_SUBTRACTION_MASK_BAD_1; 121 132 } 122 if ( data2 && data2[y][x] & maskVal) {133 if (maskData2[y][x] & maskVal) { 123 134 maskData[y][x] |= PM_SUBTRACTION_MASK_BAD_2; 124 135 } -
trunk/psModules/src/imcombine/pmSubtractionMask.h
r23851 r26893 5 5 6 6 /// Generate a mask for use in the subtraction process 7 psImage *pmSubtractionMask(const psImage *refMask, ///< Mask for the reference image (will be convolved) 8 const psImage *inMask, ///< Mask for the input image, or NULL 9 psImageMaskType maskVal, ///< Value to mask out 10 int size, ///< Half-size of the kernel (pmSubtractionKernels.size) 11 int footprint, ///< Half-size of the kernel footprint 12 float badFrac, ///< Maximum fraction of bad input pixels to accept 13 pmSubtractionMode mode ///< Subtraction mode 7 psImage *pmSubtractionMask( 8 psRegion *bounds, ///< Bounds of valid pixels (or NULL), returned 9 const pmReadout *ro1, ///< Readout 1 10 const pmReadout *ro2, ///< Readout 2 11 psImageMaskType maskVal, ///< Value to mask out 12 int size, ///< Half-size of the kernel (pmSubtractionKernels.size) 13 int footprint, ///< Half-size of the kernel footprint 14 float badFrac, ///< Maximum fraction of bad input pixels to accept 15 pmSubtractionMode mode ///< Subtraction mode 14 16 ); 15 17 -
trunk/psModules/src/imcombine/pmSubtractionMatch.c
r26035 r26893 28 28 static bool useFFT = true; // Do convolutions using FFT 29 29 30 # define SEPARATE 0 31 # if (SEPARATE) 32 # define SUBMODE PM_SUBTRACTION_EQUATION_NORM 33 # else 34 # define SUBMODE PM_SUBTRACTION_EQUATION_ALL 35 # endif 30 36 31 37 //#define TESTING … … 64 70 const psImage *subMask, // Mask for subtraction, or NULL 65 71 psImage *variance, // Variance map 66 const psRegion *region, // Region of interest , or NULL72 const psRegion *region, // Region of interest 67 73 float thresh1, // Threshold for stamp finding on readout 1 68 74 float thresh2, // Threshold for stamp finding on readout 2 69 75 float stampSpacing, // Spacing between stamps 76 float normFrac, // Fraction of flux in window for normalisation window 70 77 float sysError, // Relative systematic error in images 78 float skyError, // Relative systematic error in images 71 79 int size, // Kernel half-size 72 80 int footprint, // Convolution footprint for stamps … … 74 82 ) 75 83 { 84 PS_ASSERT_PTR_NON_NULL(stamps, false); 85 PM_ASSERT_READOUT_NON_NULL(ro1, false); 86 PM_ASSERT_READOUT_NON_NULL(ro2, false); 87 PS_ASSERT_IMAGE_NON_NULL(subMask, false); 88 PS_ASSERT_IMAGE_NON_NULL(variance, false); 89 PS_ASSERT_PTR_NON_NULL(region, false); 90 76 91 psTrace("psModules.imcombine", 3, "Finding stamps...\n"); 77 92 … … 79 94 80 95 *stamps = pmSubtractionStampsFind(*stamps, image1, image2, subMask, region, thresh1, thresh2, 81 size, footprint, stampSpacing, sysError, mode);96 size, footprint, stampSpacing, normFrac, sysError, skyError, mode); 82 97 if (!*stamps) { 83 98 psError(psErrorCodeLast(), false, "Unable to find stamps."); … … 88 103 89 104 psTrace("psModules.imcombine", 3, "Extracting stamps...\n"); 90 if (!pmSubtractionStampsExtract(*stamps, ro1->image, ro2 ? ro2->image : NULL, variance, size)) {105 if (!pmSubtractionStampsExtract(*stamps, ro1->image, ro2->image, variance, size, *region)) { 91 106 psError(PS_ERR_UNKNOWN, false, "Unable to extract stamps."); 92 107 return false; … … 102 117 const pmReadout *ro1, const pmReadout *ro2, // Input images 103 118 int stride, // Size for convolution patches 119 float normFrac, // Fraction of window for normalisation window 104 120 float sysError, // Systematic error in images 121 float skyError, // Systematic error in images 105 122 float kernelError, // Systematic error in kernel 123 float covarFrac, // Fraction for kernel truncation before covariance 106 124 psImageMaskType maskVal, // Value to mask for input 107 125 psImageMaskType maskBad, // Mask for output bad pixels … … 149 167 PS_ASSERT_IMAGES_SIZE_EQUAL(ro1->image, ro2->image, false); 150 168 PS_ASSERT_INT_NONNEGATIVE(stride, false); 169 if (isfinite(normFrac)) { 170 PS_ASSERT_FLOAT_LARGER_THAN(normFrac, 0.0, false); 171 PS_ASSERT_FLOAT_LESS_THAN(normFrac, 1.0, false); 172 } 151 173 if (isfinite(sysError)) { 152 174 PS_ASSERT_FLOAT_LARGER_THAN_OR_EQUAL(sysError, 0.0, false); 153 175 PS_ASSERT_FLOAT_LESS_THAN(sysError, 1.0, false); 154 176 } 177 if (isfinite(sysError)) { 178 PS_ASSERT_FLOAT_LARGER_THAN_OR_EQUAL(skyError, 0.0, false); 179 } 155 180 if (isfinite(kernelError)) { 156 181 PS_ASSERT_FLOAT_LARGER_THAN_OR_EQUAL(kernelError, 0.0, false); 157 182 PS_ASSERT_FLOAT_LESS_THAN(kernelError, 1.0, false); 158 183 } 184 PS_ASSERT_FLOAT_LARGER_THAN_OR_EQUAL(covarFrac, 0.0, false); 185 PS_ASSERT_FLOAT_LESS_THAN(covarFrac, 1.0, false); 159 186 // Don't care about maskVal 160 187 // Don't care about maskBad … … 198 225 } 199 226 227 bool pmSubtractionMaskInvalid (const pmReadout *readout, psImageMaskType maskVal) { 228 229 if (!readout) return true; 230 231 psImage *image = readout->image; 232 psImage *mask = readout->mask; 233 psImage *variance = readout->variance; 234 for (int y = 0; y < image->numRows; y++) { 235 for (int x = 0; x < image->numCols; x++) { 236 if (mask->data.PS_TYPE_IMAGE_MASK_DATA[y][x] & maskVal) continue; 237 bool valid = false; 238 valid = isfinite(image->data.F32[y][x]); 239 if (variance) { 240 valid &= isfinite(variance->data.F32[y][x]); 241 } 242 if (valid) continue; 243 mask->data.PS_TYPE_IMAGE_MASK_DATA[y][x] = maskVal; 244 } 245 } 246 247 return true; 248 } 200 249 201 250 bool pmSubtractionMatchPrecalc(pmReadout *conv1, pmReadout *conv2, const pmReadout *ro1, const pmReadout *ro2, 202 psMetadata *analysis, int stride, float kernelError, 251 psMetadata *analysis, int stride, float kernelError, float covarFrac, 203 252 psImageMaskType maskVal, psImageMaskType maskBad, psImageMaskType maskPoor, 204 253 float poorFrac, float badFrac) … … 270 319 } 271 320 272 if (!subtractionMatchCheck(conv1, conv2, ro1, ro2, stride, NAN, kernelError,321 if (!subtractionMatchCheck(conv1, conv2, ro1, ro2, stride, NAN, NAN, NAN, kernelError, covarFrac, 273 322 maskVal, maskBad, maskPoor, poorFrac, badFrac, mode)) { 274 323 psFree(kernels); … … 277 326 } 278 327 279 psImage *subMask = pmSubtractionMask(ro1->mask, ro2 ? ro2->mask : NULL, maskVal, size, 0, 328 pmSubtractionMaskInvalid(ro1, maskVal); 329 pmSubtractionMaskInvalid(ro2, maskVal); 330 331 psRegion bounds = psRegionSet(NAN, NAN, NAN, NAN); // Bounds of valid pixels 332 333 psImage *subMask = pmSubtractionMask(&bounds, ro1, ro2, maskVal, size, 0, 280 334 badFrac, mode); // Subtraction mask 281 335 if (!subMask) { … … 306 360 307 361 if (!pmSubtractionConvolve(conv1, conv2, ro1, ro2, subMask, stride, maskBad, maskPoor, poorFrac, 308 kernelError, region, kernel, true, useFFT)) {362 kernelError, covarFrac, region, kernel, true, useFFT)) { 309 363 psError(PS_ERR_UNKNOWN, false, "Unable to convolve image."); 310 364 psFree(outAnalysis); … … 336 390 int inner, int ringsOrder, int binning, float penalty, 337 391 bool optimum, const psVector *optFWHMs, int optOrder, float optThreshold, 338 int iter, float rej, float sysError, float kernelError, psImageMaskType maskVal,339 psImageMaskType maskBad, psImageMaskType maskPoor, float poorFrac,340 float badFrac, pmSubtractionMode subMode)392 int iter, float rej, float normFrac, float sysError, float skyError, 393 float kernelError, float covarFrac, psImageMaskType maskVal, psImageMaskType maskBad, 394 psImageMaskType maskPoor, float poorFrac, float badFrac, pmSubtractionMode subMode) 341 395 { 342 if (!subtractionMatchCheck(conv1, conv2, ro1, ro2, stride, sysError, kernelError,343 maskVal, maskBad, maskPoor, poorFrac, badFrac, subMode)) {396 if (!subtractionMatchCheck(conv1, conv2, ro1, ro2, stride, normFrac, sysError, skyError, kernelError, 397 covarFrac, maskVal, maskBad, maskPoor, poorFrac, badFrac, subMode)) { 344 398 return false; 345 399 } … … 399 453 // Putting important variable declarations here, since they are freed after a "goto" if there is an error. 400 454 psImage *subMask = NULL; // Mask for subtraction 401 psRegion *region = NULL;// Iso-kernel region455 psRegion *region = psRegionAlloc(NAN, NAN, NAN, NAN); // Iso-kernel region 402 456 psString regionString = NULL; // String for region 403 457 pmSubtractionStampList *stamps = NULL; // Stamps for matching PSF … … 412 466 memCheck("start"); 413 467 414 subMask = pmSubtractionMask(ro1->mask, ro2 ? ro2->mask : NULL, maskVal, size, footprint, 415 badFrac, subMode); 468 pmSubtractionMaskInvalid(ro1, maskVal); 469 pmSubtractionMaskInvalid(ro2, maskVal); 470 471 psRegion bounds = psRegionSet(NAN, NAN, NAN, NAN); // Bounds of valid pixels 472 473 subMask = pmSubtractionMask(&bounds, ro1, ro2, maskVal, size, footprint, badFrac, subMode); 416 474 if (!subMask) { 417 475 psError(psErrorCodeLast(), false, "Unable to generate subtraction mask."); … … 423 481 // Get region of interest 424 482 int xRegions = 1, yRegions = 1; // Number of iso-kernel regions 425 float xRegionSize = 0, yRegionSize = 0; // Size of iso-kernel regions483 float xRegionSize = NAN, yRegionSize = NAN; // Size of iso-kernel regions 426 484 if (isfinite(regionSize) && regionSize != 0.0) { 427 xRegions = numCols / regionSize + 1; 428 yRegions = numRows / regionSize + 1; 429 xRegionSize = (float)numCols / (float)xRegions; 430 yRegionSize = (float)numRows / (float)yRegions; 431 region = psRegionAlloc(NAN, NAN, NAN, NAN); 432 } 433 485 xRegions = (bounds.x1 - bounds.x0) / regionSize + 1; 486 yRegions = (bounds.y1 - bounds.y0) / regionSize + 1; 487 xRegionSize = (float)(bounds.x1 - bounds.x0) / (float)xRegions; 488 yRegionSize = (float)(bounds.y1 - bounds.y0) / (float)yRegions; 489 } else { 490 xRegionSize = bounds.x1 - bounds.x0; 491 yRegionSize = bounds.y1 - bounds.y0; 492 } 493 494 // General background subtraction and measurement of stamp threshold 434 495 float stampThresh1 = NAN, stampThresh2 = NAN; // Stamp thresholds for images 435 496 { 436 psStats *bg = psStatsAlloc(PS_STAT_ROBUST_MEDIAN | PS_STAT_ROBUST_STDEV); // Statistics for backgroun 497 psStats *bg = psStatsAlloc(PS_STAT_ROBUST_MEDIAN | PS_STAT_ROBUST_STDEV); // Statistics for background 437 498 if (ro1) { 499 psStatsInit(bg); 438 500 if (!psImageBackground(bg, NULL, ro1->image, ro1->mask, maskVal, rng)) { 439 501 psError(PS_ERR_UNKNOWN, false, "Unable to measure background statistics."); … … 441 503 goto MATCH_ERROR; 442 504 } 443 stampThresh1 = bg->robustMedian + threshold * bg->robustStdev; 505 stampThresh1 = threshold * bg->robustStdev; 506 psBinaryOp(ro1->image, ro1->image, "-", psScalarAlloc((float)bg->robustMedian, PS_TYPE_F32)); 444 507 } 445 508 if (ro2) { 509 psStatsInit(bg); 446 510 if (!psImageBackground(bg, NULL, ro2->image, ro2->mask, maskVal, rng)) { 447 511 psError(PS_ERR_UNKNOWN, false, "Unable to measure background statistics."); … … 449 513 goto MATCH_ERROR; 450 514 } 451 stampThresh2 = bg->robustMedian + threshold * bg->robustStdev; 452 } 515 stampThresh2 = threshold * bg->robustStdev; 516 psBinaryOp(ro2->image, ro2->image, "-", psScalarAlloc((float)bg->robustMedian, PS_TYPE_F32)); 517 } 453 518 psFree(bg); 454 519 } 520 521 // Just in case the iso-kernel region doesn't cover the entire image... 522 if (subMode == PM_SUBTRACTION_MODE_1 || subMode == PM_SUBTRACTION_MODE_UNSURE || 523 subMode == PM_SUBTRACTION_MODE_DUAL) { 524 if (!conv1->image) { 525 conv1->image = psImageAlloc(numCols, numRows, PS_TYPE_F32); 526 } 527 psImageInit(conv1->image, NAN); 528 if (ro1->variance) { 529 if (!conv1->variance) { 530 conv1->variance = psImageAlloc(numCols, numRows, PS_TYPE_F32); 531 } 532 psImageInit(conv1->variance, NAN); 533 } 534 if (subMask) { 535 if (!conv1->mask) { 536 conv1->mask = psImageAlloc(numCols, numRows, PS_TYPE_IMAGE_MASK); 537 } 538 psImageInit(conv1->mask, maskBad); 539 } 540 } 541 if (subMode == PM_SUBTRACTION_MODE_2 || subMode == PM_SUBTRACTION_MODE_UNSURE || 542 subMode == PM_SUBTRACTION_MODE_DUAL) { 543 if (!conv2->image) { 544 conv2->image = psImageAlloc(numCols, numRows, PS_TYPE_F32); 545 } 546 psImageInit(conv2->image, NAN); 547 if (ro2->variance) { 548 if (!conv2->variance) { 549 conv2->variance = psImageAlloc(numCols, numRows, PS_TYPE_F32); 550 } 551 psImageInit(conv2->variance, NAN); 552 } 553 if (subMask) { 554 if (!conv2->mask) { 555 conv2->mask = psImageAlloc(numCols, numRows, PS_TYPE_IMAGE_MASK); 556 } 557 psImageInit(conv2->mask, maskBad); 558 } 559 } 560 455 561 456 562 // Iterate over iso-kernel regions … … 459 565 psTrace("psModules.imcombine", 1, "Subtracting region %d of %d...\n", 460 566 j * xRegions + i + 1, xRegions * yRegions); 461 if (region) {462 *region = psRegionSet((int)(i * xRegionSize),(int)((i + 1) * xRegionSize),463 (int)(j * yRegionSize), (int)((j + 1) * yRegionSize));464 psFree(regionString);465 regionString = psRegionToString(*region);466 psTrace("psModules.imcombine", 3, "Iso-kernel region: %s out of %d,%d\n",467 regionString, numCols, numRows);468 }567 *region = psRegionSet(bounds.x0 + (int)(i * xRegionSize), 568 bounds.x0 + (int)((i + 1) * xRegionSize), 569 bounds.y0 + (int)(j * yRegionSize), 570 bounds.y0 + (int)((j + 1) * yRegionSize)); 571 psFree(regionString); 572 regionString = psRegionToString(*region); 573 psLogMsg("psModules.imcombine", PS_LOG_DETAIL, "Iso-kernel region: %s out of %d,%d\n", 574 regionString, numCols, numRows); 469 575 470 576 if (stampsName && strlen(stampsName) > 0) { 471 577 stamps = pmSubtractionStampsSetFromFile(stampsName, ro1->image, subMask, region, size, 472 footprint, stampSpacing, sysError, subMode); 578 footprint, stampSpacing, normFrac, 579 sysError, skyError, subMode); 473 580 } else if (sources) { 474 581 stamps = pmSubtractionStampsSetFromSources(sources, ro1->image, subMask, region, size, 475 footprint, stampSpacing, sysError, subMode); 582 footprint, stampSpacing, normFrac, 583 sysError, skyError, subMode); 476 584 } 477 585 478 586 // We get the stamps here; we will also attempt to get stamps at the first iteration, but it 479 587 // doesn't matter. 480 if (!subtractionGetStamps(&stamps, ro1, ro2, subMask, variance, NULL, stampThresh1, stampThresh2,481 stampSpacing, sysError, size, footprint, subMode)) {588 if (!subtractionGetStamps(&stamps, ro1, ro2, subMask, variance, region, stampThresh1, stampThresh2, 589 stampSpacing, normFrac, sysError, skyError, size, footprint, subMode)) { 482 590 goto MATCH_ERROR; 483 591 } 484 592 593 594 // generate the window function from the set of stamps 595 if (!pmSubtractionStampsGetWindow(stamps, size)) { 596 psError(PS_ERR_UNKNOWN, false, "Unable to get stamp window."); 597 goto MATCH_ERROR; 598 } 485 599 486 600 // Define kernel basis functions 487 601 if (optimum && (type == PM_SUBTRACTION_KERNEL_ISIS || type == PM_SUBTRACTION_KERNEL_GUNK)) { 488 kernels = pmSubtractionKernelsOptimumISIS(type, size, inner, spatialOrder, optFWHMs, optOrder, 489 stamps, footprint, optThreshold, penalty, subMode); 602 kernels = pmSubtractionKernelsOptimumISIS(type, size, inner, spatialOrder, 603 optFWHMs, optOrder, stamps, footprint, 604 optThreshold, penalty, bounds, subMode); 490 605 if (!kernels) { 491 606 psErrorClear(); … … 496 611 // Not an ISIS/GUNK kernel, or the optimum kernel search failed 497 612 kernels = pmSubtractionKernelsGenerate(type, size, spatialOrder, isisWidths, isisOrders, 498 inner, binning, ringsOrder, penalty, subMode); 613 inner, binning, ringsOrder, penalty, bounds, subMode); 614 // pmSubtractionVisualShowKernels(kernels); 499 615 } 500 616 … … 545 661 546 662 if (!subtractionGetStamps(&stamps, ro1, ro2, subMask, variance, region, 547 stampThresh1, stampThresh2, stampSpacing, sysError, 548 size, footprint, subMode)) { 549 goto MATCH_ERROR; 550 } 551 552 psTrace("psModules.imcombine", 3, "Calculating equation...\n"); 553 if (!pmSubtractionCalculateEquation(stamps, kernels)) { 663 stampThresh1, stampThresh2, stampSpacing, normFrac, 664 sysError, skyError, size, footprint, subMode)) { 665 goto MATCH_ERROR; 666 } 667 668 // generate the window function from the set of stamps 669 if (!pmSubtractionStampsGetWindow(stamps, size)) { 670 psError(PS_ERR_UNKNOWN, false, "Unable to get stamps window."); 671 goto MATCH_ERROR; 672 } 673 674 // XXX step 1: calculate normalization 675 psTrace("psModules.imcombine", 3, "Calculating equation for normalization...\n"); 676 if (!pmSubtractionCalculateEquation(stamps, kernels, SUBMODE)) { 554 677 psError(PS_ERR_UNKNOWN, false, "Unable to calculate least-squares equation."); 555 678 goto MATCH_ERROR; 556 679 } 557 680 681 psTrace("psModules.imcombine", 3, "Solving equation for normalization...\n"); 682 if (!pmSubtractionSolveEquation(kernels, stamps, SUBMODE)) { 683 psError(PS_ERR_UNKNOWN, false, "Unable to calculate least-squares equation."); 684 goto MATCH_ERROR; 685 } 686 memCheck(" solve equation"); 687 688 # if (SEPARATE) 689 // set USED -> CALCULATE 690 pmSubtractionStampsResetStatus (stamps); 691 692 // XXX step 2: calculate kernel parameters 693 psTrace("psModules.imcombine", 3, "Calculating equation for kernels...\n"); 694 if (!pmSubtractionCalculateEquation(stamps, kernels, PM_SUBTRACTION_EQUATION_KERNELS)) { 695 psError(PS_ERR_UNKNOWN, false, "Unable to calculate least-squares equation."); 696 goto MATCH_ERROR; 697 } 558 698 memCheck(" calculate equation"); 559 699 560 psTrace("psModules.imcombine", 3, "Solving equation...\n"); 561 562 if (!pmSubtractionSolveEquation(kernels, stamps)) { 700 psTrace("psModules.imcombine", 3, "Solving equation for kernels...\n"); 701 if (!pmSubtractionSolveEquation(kernels, stamps, PM_SUBTRACTION_EQUATION_KERNELS)) { 563 702 psError(PS_ERR_UNKNOWN, false, "Unable to calculate least-squares equation."); 564 703 goto MATCH_ERROR; 565 704 } 566 567 705 memCheck(" solve equation"); 568 706 # endif 569 707 psVector *deviations = pmSubtractionCalculateDeviations(stamps, kernels); // Stamp deviations 570 708 if (!deviations) { … … 587 725 } 588 726 727 // if we hit the max number of iterations and we have rejected stamps, re-solve 589 728 if (numRejected > 0) { 590 psTrace("psModules.imcombine", 3, "Solving equation...\n"); 591 if (!pmSubtractionSolveEquation(kernels, stamps)) { 729 // XXX step 1: calculate normalization 730 psTrace("psModules.imcombine", 3, "Calculating equation for normalization...\n"); 731 if (!pmSubtractionCalculateEquation(stamps, kernels, SUBMODE)) { 592 732 psError(PS_ERR_UNKNOWN, false, "Unable to calculate least-squares equation."); 593 733 goto MATCH_ERROR; 594 734 } 735 736 // solve normalization 737 psTrace("psModules.imcombine", 3, "Solving equation for kernels...\n"); 738 if (!pmSubtractionSolveEquation(kernels, stamps, SUBMODE)) { 739 psError(PS_ERR_UNKNOWN, false, "Unable to calculate least-squares equation."); 740 goto MATCH_ERROR; 741 } 742 743 # if (SEPARATE) 744 // set USED -> CALCULATE 745 pmSubtractionStampsResetStatus (stamps); 746 747 // XXX step 2: calculate kernel parameters 748 psTrace("psModules.imcombine", 3, "Calculating equation for normalization...\n"); 749 if (!pmSubtractionCalculateEquation(stamps, kernels, PM_SUBTRACTION_EQUATION_KERNELS)) { 750 psError(PS_ERR_UNKNOWN, false, "Unable to calculate least-squares equation."); 751 goto MATCH_ERROR; 752 } 753 754 // solve kernel parameters 755 psTrace("psModules.imcombine", 3, "Solving equation for kernels...\n"); 756 if (!pmSubtractionSolveEquation(kernels, stamps, PM_SUBTRACTION_EQUATION_KERNELS)) { 757 psError(PS_ERR_UNKNOWN, false, "Unable to calculate least-squares equation."); 758 goto MATCH_ERROR; 759 } 760 memCheck(" solve equation"); 761 # endif 595 762 psVector *deviations = pmSubtractionCalculateDeviations(stamps, kernels); // Stamp deviations 596 763 if (!deviations) { … … 615 782 psTrace("psModules.imcombine", 2, "Convolving...\n"); 616 783 if (!pmSubtractionConvolve(conv1, conv2, ro1, ro2, subMask, stride, maskBad, maskPoor, poorFrac, 617 kernelError, region, kernels, true, useFFT)) {784 kernelError, covarFrac, region, kernels, true, useFFT)) { 618 785 psError(PS_ERR_UNKNOWN, false, "Unable to convolve image."); 619 786 goto MATCH_ERROR; … … 897 1064 assert(kernels); 898 1065 899 psTrace("psModules.imcombine", 3, "Calculating %s equation...\n", description);900 if (!pmSubtractionCalculateEquation(stamps, kernels )) {1066 psTrace("psModules.imcombine", 3, "Calculating %s normalization equation...\n", description); 1067 if (!pmSubtractionCalculateEquation(stamps, kernels, SUBMODE)) { 901 1068 psError(PS_ERR_UNKNOWN, false, "Unable to calculate least-squares equation."); 902 1069 return false; 903 1070 } 904 1071 905 psTrace("psModules.imcombine", 3, "Solving %s equation...\n", description);906 if (!pmSubtractionSolveEquation(kernels, stamps )) {1072 psTrace("psModules.imcombine", 3, "Solving %s normalization equation...\n", description); 1073 if (!pmSubtractionSolveEquation(kernels, stamps, SUBMODE)) { 907 1074 psError(PS_ERR_UNKNOWN, false, "Unable to calculate least-squares equation."); 908 1075 return false; 909 1076 } 1077 1078 # if (SEPARATE) 1079 // set USED -> CALCULATE 1080 pmSubtractionStampsResetStatus (stamps); 1081 1082 psTrace("psModules.imcombine", 3, "Calculating %s kernel coeffs equation...\n", description); 1083 if (!pmSubtractionCalculateEquation(stamps, kernels, PM_SUBTRACTION_EQUATION_KERNELS)) { 1084 psError(PS_ERR_UNKNOWN, false, "Unable to calculate least-squares equation."); 1085 return false; 1086 } 1087 1088 psTrace("psModules.imcombine", 3, "Solving %s kernel coeffs equation...\n", description); 1089 if (!pmSubtractionSolveEquation(kernels, stamps, PM_SUBTRACTION_EQUATION_KERNELS)) { 1090 psError(PS_ERR_UNKNOWN, false, "Unable to calculate least-squares equation."); 1091 return false; 1092 } 1093 # endif 910 1094 911 1095 psTrace("psModules.imcombine", 3, "Calculate %s deviations...\n", description); … … 927 1111 if (numRejected > 0) { 928 1112 // Allow re-fit with reduced stamps set 929 psTrace("psModules.imcombine", 3, " Resolving %sequation...\n", description);930 if (!pmSubtraction SolveEquation(kernels, stamps)) {1113 psTrace("psModules.imcombine", 3, "Calculating %s normalization equation...\n", description); 1114 if (!pmSubtractionCalculateEquation(stamps, kernels, PM_SUBTRACTION_EQUATION_ALL)) { 931 1115 psError(PS_ERR_UNKNOWN, false, "Unable to calculate least-squares equation."); 932 1116 return false; 933 1117 } 1118 1119 psTrace("psModules.imcombine", 3, "Resolving %s equation...\n", description); 1120 if (!pmSubtractionSolveEquation(kernels, stamps, PM_SUBTRACTION_EQUATION_ALL)) { 1121 psError(PS_ERR_UNKNOWN, false, "Unable to calculate least-squares equation."); 1122 return false; 1123 } 934 1124 psTrace("psModules.imcombine", 3, "Recalculate %s deviations...\n", description); 1125 1126 # if (SEPARATE) 1127 // set USED -> CALCULATE 1128 pmSubtractionStampsResetStatus (stamps); 1129 1130 psTrace("psModules.imcombine", 3, "Calculating %s normalization equation...\n", description); 1131 if (!pmSubtractionCalculateEquation(stamps, kernels, PM_SUBTRACTION_EQUATION_KERNELS)) { 1132 psError(PS_ERR_UNKNOWN, false, "Unable to calculate least-squares equation."); 1133 return false; 1134 } 1135 1136 psTrace("psModules.imcombine", 3, "Resolving %s equation...\n", description); 1137 if (!pmSubtractionSolveEquation(kernels, stamps, PM_SUBTRACTION_EQUATION_KERNELS)) { 1138 psError(PS_ERR_UNKNOWN, false, "Unable to calculate least-squares equation."); 1139 return false; 1140 } 1141 psTrace("psModules.imcombine", 3, "Recalculate %s deviations...\n", description); 1142 # endif 1143 935 1144 psVector *deviations = pmSubtractionCalculateDeviations(stamps, kernels); // Stamp deviations 936 1145 if (!deviations) { … … 1019 1228 } 1020 1229 1230 1231 bool pmSubtractionParamsScale(int *kernelSize, int *stampSize, psVector *widths, 1232 float fwhm1, float fwhm2, float scaleRef, float scaleMin, float scaleMax) 1233 { 1234 PS_ASSERT_PTR_NON_NULL(kernelSize, false); 1235 PS_ASSERT_PTR_NON_NULL(stampSize, false); 1236 PS_ASSERT_VECTOR_NON_NULL(widths, false); 1237 PS_ASSERT_VECTOR_TYPE(widths, PS_TYPE_F32, false); 1238 PS_ASSERT_FLOAT_LARGER_THAN(fwhm1, 0.0, false); 1239 PS_ASSERT_FLOAT_LARGER_THAN(fwhm2, 0.0, false); 1240 PS_ASSERT_FLOAT_LARGER_THAN(scaleRef, 0.0, false); 1241 PS_ASSERT_FLOAT_LARGER_THAN(scaleMin, 0.0, false); 1242 PS_ASSERT_FLOAT_LARGER_THAN(scaleMax, 0.0, false); 1243 PS_ASSERT_FLOAT_LARGER_THAN(scaleMax, scaleMin, false); 1244 1245 // float diff = sqrtf(PS_SQR(PS_MAX(fwhm1, fwhm2)) - PS_SQR(PS_MIN(fwhm1, fwhm2))); // Difference 1246 float scale = PS_MAX(fwhm1, fwhm2) / scaleRef; // Scaling factor 1247 1248 if (isfinite(scaleMin) && scale < scaleMin) { 1249 scale = scaleMin; 1250 } 1251 if (isfinite(scaleMax) && scale > scaleMax) { 1252 scale = scaleMax; 1253 } 1254 1255 for (int i = 0; i < widths->n; i++) { 1256 widths->data.F32[i] *= scale; 1257 } 1258 *kernelSize = *kernelSize * scale + 0.5; 1259 *stampSize = *stampSize * scale + 0.5; 1260 1261 psLogMsg("psModules.imcombine", PS_LOG_INFO, 1262 "Scaling kernel parameters by %f: %d %d", scale, *kernelSize, *stampSize); 1263 1264 return true; 1265 } -
trunk/psModules/src/imcombine/pmSubtractionMatch.h
r26035 r26893 39 39 int iter, ///< Rejection iterations 40 40 float rej, ///< Rejection threshold 41 float normFrac, ///< Fraction of flux in window for normalisation window 41 42 float sysError, ///< Relative systematic error in images 43 float skyError, ///< Relative systematic error in images 42 44 float kernelError, ///< Relative systematic error in kernel 45 float covarFrac, ///< Fraction for kernel truncation before covariance calculation 43 46 psImageMaskType maskVal, ///< Value to mask for input 44 47 psImageMaskType maskBad, ///< Mask for output bad pixels … … 57 60 int stride, ///< Size for convolution patches 58 61 float kernelError, ///< Relative systematic error in kernel 62 float covarFrac, ///< Fraction for kernel truncation before covariance calc. 59 63 psImageMaskType maskVal, ///< Value to mask for input 60 64 psImageMaskType maskBad, ///< Mask for output bad pixels … … 94 98 ); 95 99 100 101 /// Scale subtraction parameters according to the FWHMs of the inputs 102 bool pmSubtractionParamsScale( 103 int *kernelSize, ///< Half-size of the kernel 104 int *stampSize, ///< Half-size of the stamp (footprint) 105 psVector *widths, ///< ISIS widths 106 float fwhm1, float fwhm2, ///< FWHMs for inputs 107 float scaleRef, ///< Reference width for scaling 108 float scaleMin, ///< Minimum scaling ratio, or NAN 109 float scaleMax ///< Maximum scaling ratio, or NAN 110 ); 111 112 96 113 #endif -
trunk/psModules/src/imcombine/pmSubtractionParams.c
r26035 r26893 204 204 int spatialOrder, const psVector *fwhms, int maxOrder, 205 205 const pmSubtractionStampList *stamps, int footprint, 206 float tolerance, float penalty, pmSubtractionMode mode) 206 float tolerance, float penalty, psRegion bounds, 207 pmSubtractionMode mode) 207 208 { 208 209 if (type != PM_SUBTRACTION_KERNEL_ISIS && type != PM_SUBTRACTION_KERNEL_GUNK) { … … 232 233 psVectorInit(orders, maxOrder); 233 234 pmSubtractionKernels *kernels = p_pmSubtractionKernelsRawISIS(size, spatialOrder, fwhms, orders, 234 penalty, mode); // Kernels235 penalty, bounds, mode); // Kernels 235 236 psFree(orders); 236 237 psFree(kernels->description); … … 482 483 // Maintain photometric scaling 483 484 if (type == PM_SUBTRACTION_KERNEL_ISIS) { 484 psKernel *subtract = kernels->preCalc->data[0]; // Kernel to subtract from the rest 485 486 // XXX in r26035, this code was just wrong. we had: 487 488 // psKernel *subtract = kernels->preCalc->data[0] 489 490 // but, kernels->preCalc was an array of psArray, not an array of kernels. It is now 491 // an array of pmSubtractionKernelPreCalc. 492 493 pmSubtractionKernelPreCalc *subtract = kernels->preCalc->data[0]; // Kernel to subtract from the rest 494 485 495 for (int i = 1; i < newSize; i++) { 486 496 if (kernels->u->data.S32[i] % 2 == 0 && kernels->v->data.S32[i] % 2 == 0) { 487 p sKernel *kernel= kernels->preCalc->data[i]; // Kernel of interest488 psBinaryOp( kernel->image, kernel->image, "-", subtract->image);497 pmSubtractionKernelPreCalc *preCalc = kernels->preCalc->data[i]; // Kernel of interest 498 psBinaryOp(preCalc->kernel->image, preCalc->kernel->image, "-", subtract->kernel->image); 489 499 } 490 500 } … … 495 505 for (int i = 0; i < newSize; i++) { 496 506 if (kernels->u->data.S32[i] % 2 == 0 && kernels->v->data.S32[i] % 2 == 0) { 497 p sKernel *kernel= kernels->preCalc->data[i]; // Kernel of interest498 kernel->kernel[0][0] -= 1.0;507 pmSubtractionKernelPreCalc *preCalc = kernels->preCalc->data[i]; // Kernel of interest 508 preCalc->kernel->kernel[0][0] -= 1.0; 499 509 } 500 510 } -
trunk/psModules/src/imcombine/pmSubtractionParams.h
r18287 r26893 17 17 float tolerance, ///< Maximum difference in chi^2 18 18 float penalty, ///< Penalty for wideness 19 pmSubtractionMode mode // Mode for subtraction 19 psRegion bounds, ///< Bounds of validity 20 pmSubtractionMode mode ///< Mode for subtraction 20 21 ); 21 22 -
trunk/psModules/src/imcombine/pmSubtractionStamps.c
r26046 r26893 46 46 psFree(list->y); 47 47 psFree(list->flux); 48 psFree(list->window); 48 49 } 49 50 … … 57 58 psFree(stamp->convolutions1); 58 59 psFree(stamp->convolutions2); 59 60 psFree(stamp->matrix1); 61 psFree(stamp->matrix2); 62 psFree(stamp->matrixX); 63 psFree(stamp->vector1); 64 psFree(stamp->vector2); 65 60 psFree(stamp->matrix); 61 psFree(stamp->vector); 66 62 } 67 63 … … 80 76 81 77 // Search a region for a suitable stamp 82 bool stampSearch( int *xStamp, int *yStamp, // Coordinates of stamp, to return78 bool stampSearch(float *xStamp, float *yStamp, // Coordinates of stamp, to return 83 79 float *fluxStamp, // Flux of stamp, to return 84 80 const psImage *image1, const psImage *image2, // Images to search … … 93 89 *fluxStamp = -INFINITY; // Flux of best stamp 94 90 91 // fprintf (stderr, "xMin, xMax: %d, %d -> ", xMin, xMax); 92 95 93 // Ensure we're not going to go outside the bounds of the image 96 94 xMin = PS_MAX(border, xMin); … … 99 97 yMax = PS_MIN(numRows - border - 1, yMax); 100 98 99 if (xMax < xMin) return false; 100 if (yMax < yMin) return false; 101 102 psAssert (xMin <= xMax, "x mismatch?"); 103 psAssert (yMin <= yMax, "y mismatch?"); 104 101 105 for (int y = yMin; y <= yMax; y++) { 102 106 for (int x = xMin; x <= xMax; x++) { … … 115 119 ((image1) ? image1->data.F32[y][x] : image2->data.F32[y][x]); // Flux at pixel 116 120 if (flux > *fluxStamp) { 117 *xStamp = x ;118 *yStamp = y ;121 *xStamp = x + 0.5; 122 *yStamp = y + 0.5; 119 123 *fluxStamp = flux; 120 124 found = true; … … 180 184 181 185 pmSubtractionStampList *pmSubtractionStampListAlloc(int numCols, int numRows, const psRegion *region, 182 int footprint, float spacing, float sysErr) 186 int footprint, float spacing, float normFrac, 187 float sysErr, float skyErr) 183 188 { 184 189 pmSubtractionStampList *list = psAlloc(sizeof(pmSubtractionStampList)); // Stamp list to return … … 220 225 list->y = NULL; 221 226 list->flux = NULL; 227 list->window = NULL; 228 list->normFrac = normFrac; 229 list->normWindow = 0; 222 230 list->footprint = footprint; 223 231 list->sysErr = sysErr; 232 list->skyErr = skyErr; 224 233 225 234 return list; … … 239 248 out->y = NULL; 240 249 out->flux = NULL; 250 out->window = psMemIncrRefCounter(in->window); 241 251 out->footprint = in->footprint; 252 out->normWindow = in->normWindow; 242 253 243 254 for (int i = 0; i < num; i++) { … … 280 291 } 281 292 282 outStamp->matrix1 = inStamp->matrix1 ? psImageCopy(NULL, inStamp->matrix1, PS_TYPE_F64) : NULL; 283 outStamp->matrix2 = inStamp->matrix2 ? psImageCopy(NULL, inStamp->matrix2, PS_TYPE_F64) : NULL; 284 outStamp->matrixX = inStamp->matrixX ? psImageCopy(NULL, inStamp->matrixX, PS_TYPE_F64) : NULL; 285 outStamp->vector1 = inStamp->vector1 ? psVectorCopy(NULL, inStamp->vector1, PS_TYPE_F64) : NULL; 286 outStamp->vector2 = inStamp->vector2 ? psVectorCopy(NULL, inStamp->vector2, PS_TYPE_F64) : NULL; 293 outStamp->matrix = inStamp->matrix ? psImageCopy(NULL, inStamp->matrix, PS_TYPE_F64) : NULL; 294 outStamp->vector = inStamp->vector ? psVectorCopy(NULL, inStamp->vector, PS_TYPE_F64) : NULL; 287 295 288 296 out->stamps->data[i] = outStamp; … … 310 318 stamp->convolutions2 = NULL; 311 319 312 stamp->matrix1 = NULL; 313 stamp->matrix2 = NULL; 314 stamp->matrixX = NULL; 315 stamp->vector1 = NULL; 316 stamp->vector2 = NULL; 320 stamp->matrix = NULL; 321 stamp->vector = NULL; 322 stamp->norm = NAN; 317 323 318 324 return stamp; … … 323 329 const psImage *image2, const psImage *subMask, 324 330 const psRegion *region, float thresh1, float thresh2, 325 int size, int footprint, float spacing, float sysErr,326 pmSubtractionMode mode)331 int size, int footprint, float spacing, float normFrac, 332 float sysErr, float skyErr, pmSubtractionMode mode) 327 333 { 328 334 if (!image1 && !image2) { … … 380 386 381 387 if (!stamps) { 382 stamps = pmSubtractionStampListAlloc(numCols, numRows, region, footprint, spacing, sysErr); 388 stamps = pmSubtractionStampListAlloc(numCols, numRows, region, footprint, spacing, 389 normFrac, sysErr, skyErr); 383 390 } 384 391 … … 402 409 numSearch++; 403 410 404 int xStamp = 0, yStamp =0; // Coordinates of stamp411 float xStamp = 0.0, yStamp = 0.0; // Coordinates of stamp 405 412 float fluxStamp = -INFINITY; // Flux of stamp 406 413 bool goodStamp = false; // Found a good stamp? … … 414 421 // Take stamps off the top of the (sorted) list 415 422 for (int j = xList->n - 1; j >= 0 && !goodStamp; j--) { 416 int xCentre = xList->data.F32[j] + 0.5, yCentre = yList->data.F32[j] + 0.5;// Stamp centre417 418 423 // Chop off the top of the list 419 424 xList->n = j; … … 421 426 fluxList->n = j; 422 427 428 #if 0 423 429 // Fish around a bit to see if we can find a pixel that isn't masked 430 // This is not a good idea if we're using the window feature 424 431 psTrace("psModules.imcombine", 7, "Searching for stamp %d around %d,%d\n", 425 432 i, xCentre, yCentre); 426 433 427 434 // Search bounds 435 int xCentre = xList->data.F32[j] - 0.5, yCentre = yList->data.F32[j] - 0.5;// Stamp centre 428 436 int search = footprint - size; // Search radius 429 437 int xMin = PS_MAX(border, xCentre - search); … … 434 442 goodStamp = stampSearch(&xStamp, &yStamp, &fluxStamp, image1, image2, thresh1, thresh2, 435 443 subMask, xMin, xMax, yMin, yMax, numCols, numRows, border); 444 // fprintf (stderr, "find: %d %d ==> %5.1f %5.1f (\n", xCentre, yCentre, xStamp, yStamp); 445 #else 446 // Only search the exact centre pixel 447 goodStamp = stampSearch(&xStamp, &yStamp, &fluxStamp, image1, image2, thresh1, thresh2, 448 subMask, xList->data.F32[j], xList->data.F32[j], 449 yList->data.F32[j], yList->data.F32[j], numCols, numRows, border); 450 #endif 451 if (0 && goodStamp) { 452 fprintf (stderr, "find: %6.1f < %6.1f < %6.1f, %6.1f < %6.1f %6.1f\n", 453 region->x0 + size, xStamp, region->x1 - size, 454 region->y0 + size, yStamp, region->y1 - size); 455 } 436 456 } 437 457 } else { … … 488 508 const psImage *image, const psImage *subMask, 489 509 const psRegion *region, int size, int footprint, 490 float spacing, float sysErr, pmSubtractionMode mode) 510 float spacing, float normFrac, float sysErr, float skyErr, 511 pmSubtractionMode mode) 491 512 492 513 { … … 509 530 pmSubtractionStampList *stamps = pmSubtractionStampListAlloc(subMask->numCols, subMask->numRows, 510 531 region, footprint, spacing, 511 sysErr); // Stamp list532 normFrac, sysErr, skyErr); // Stamp list 512 533 int numStamps = stamps->num; // Number of stamps 513 534 … … 531 552 for (int i = 0; i < numStars; i++) { 532 553 float xStamp = x->data.F32[i], yStamp = y->data.F32[i]; // Coordinates of stamp 533 int xPix = xStamp + 0.5, yPix = yStamp +0.5; // Pixel coordinate of stamp554 int xPix = xStamp - 0.5, yPix = yStamp - 0.5; // Pixel coordinate of stamp 534 555 if (!checkStampRegion(xPix, yPix, region)) { 535 556 // It's not in the big region … … 539 560 continue; 540 561 } 562 563 // fprintf (stderr, "stamp: %5.1f %5.1f == %d %d\n", xStamp, yStamp, xPix, yPix); 541 564 542 565 bool found = false; … … 607 630 608 631 632 bool pmSubtractionStampsGetWindow(pmSubtractionStampList *stamps, int kernelSize) 633 { 634 PM_ASSERT_SUBTRACTION_STAMP_LIST_NON_NULL(stamps, false); 635 PS_ASSERT_INT_NONNEGATIVE(kernelSize, false); 636 637 int size = stamps->footprint; // Size of postage stamps 638 639 psFree (stamps->window); 640 stamps->window = psKernelAlloc(-size, size, -size, size); 641 psImageInit(stamps->window->image, 0.0); 642 643 // generate normalizations for each stamp 644 psVector *norm1 = psVectorAlloc(stamps->num, PS_TYPE_F32); 645 psVector *norm2 = psVectorAlloc(stamps->num, PS_TYPE_F32); 646 for (int i = 0; i < stamps->num; i++) { 647 pmSubtractionStamp *stamp = stamps->stamps->data[i]; // Stamp of interest 648 if (!stamp) continue; 649 if (!stamp->image1) continue; 650 if (!stamp->image2) continue; 651 652 float sum1 = 0.0; 653 float sum2 = 0.0; 654 for (int y = -size; y <= size; y++) { 655 for (int x = -size; x <= size; x++) { 656 sum1 += stamp->image1->kernel[y][x]; 657 sum2 += stamp->image2->kernel[y][x]; 658 } 659 } 660 norm1->data.F32[i] = sum1; 661 norm2->data.F32[i] = sum2; 662 } 663 664 // storage vector for flux data 665 psStats *stats = psStatsAlloc (PS_STAT_ROBUST_MEDIAN | PS_STAT_ROBUST_STDEV); 666 psVector *flux1 = psVectorAllocEmpty(2*stamps->num, PS_TYPE_F32); 667 psVector *flux2 = psVectorAllocEmpty(2*stamps->num, PS_TYPE_F32); 668 669 // generate the window pixels 670 double sum = 0.0; // Sum inside the window 671 float maxValue = 0.0; // Maximum value, for normalisation 672 for (int y = -size; y <= size; y++) { 673 for (int x = -size; x <= size; x++) { 674 675 flux1->n = 0; 676 flux2->n = 0; 677 for (int i = 0; i < stamps->num; i++) { 678 pmSubtractionStamp *stamp = stamps->stamps->data[i]; // Stamp of interest 679 if (!stamp) continue; 680 if (!stamp->image1) continue; 681 if (!stamp->image2) continue; 682 683 psVectorAppend(flux1, stamp->image1->kernel[y][x] / norm1->data.F32[i]); 684 psVectorAppend(flux2, stamp->image2->kernel[y][x] / norm2->data.F32[i]); 685 } 686 687 psStatsInit (stats); 688 if (!psVectorStats (stats, flux1, NULL, NULL, 0)) { 689 psAbort ("failed to generate stats"); 690 } 691 float f1 = stats->robustMedian; 692 psStatsInit (stats); 693 if (!psVectorStats (stats, flux2, NULL, NULL, 0)) { 694 psAbort ("failed to generate stats"); 695 } 696 float f2 = stats->robustMedian; 697 698 stamps->window->kernel[y][x] = f1 + f2; 699 if (PS_SQR(x) + PS_SQR(y) <= PS_SQR(size)) { 700 sum += stamps->window->kernel[y][x]; 701 } 702 maxValue = PS_MAX(maxValue, stamps->window->kernel[y][x]); 703 } 704 } 705 706 psTrace("psModules.imcombine", 3, "Window total: %f, threshold: %f\n", 707 sum, (1.0 - stamps->normFrac) * sum); 708 bool done = false; 709 for (int radius = 1; radius <= size && !done; radius++) { 710 double within = 0.0; 711 for (int y = -radius; y <= radius; y++) { 712 for (int x = -radius; x <= radius; x++) { 713 if (PS_SQR(x) + PS_SQR(y) <= PS_SQR(radius)) { 714 within += stamps->window->kernel[y][x]; 715 } 716 } 717 } 718 psTrace("psModules.imcombine", 5, "Radius %d: %f\n", radius, within); 719 if (within > (1.0 - stamps->normFrac) * sum) { 720 stamps->normWindow = radius; 721 done = true; 722 } 723 } 724 725 psTrace("psModules.imcombine", 3, "Normalisation window radius set to %d\n", stamps->normWindow); 726 if (stamps->normWindow == 0 || stamps->normWindow >= size) { 727 psError(PS_ERR_UNKNOWN, true, "Unable to determine normalisation window size."); 728 return false; 729 } 730 731 // re-normalize so chisquare values are sensible 732 for (int y = -size; y <= size; y++) { 733 for (int x = -size; x <= size; x++) { 734 stamps->window->kernel[y][x] /= maxValue; 735 } 736 } 737 738 #if 0 739 { 740 psFits *fits = psFitsOpen ("window.fits", "w"); 741 psFitsWriteImage (fits, NULL, stamps->window->image, 0, NULL); 742 psFitsClose (fits); 743 } 744 #endif 745 746 psFree (stats); 747 psFree (flux1); 748 psFree(flux2); 749 psFree (norm1); 750 psFree (norm2); 751 return true; 752 } 753 609 754 bool pmSubtractionStampsExtract(pmSubtractionStampList *stamps, psImage *image1, psImage *image2, 610 psImage *variance, int kernelSize )755 psImage *variance, int kernelSize, psRegion bounds) 611 756 { 612 757 PM_ASSERT_SUBTRACTION_STAMP_LIST_NON_NULL(stamps, false); … … 625 770 } 626 771 627 int numCols = image1->numCols, numRows = image1->numRows; // Size of images628 772 int size = kernelSize + stamps->footprint; // Size of postage stamps 629 773 … … 634 778 } 635 779 636 if (isnan(stamp->xNorm)) { 637 stamp->xNorm = 2.0 * (stamp->x - (float)numCols/2.0) / (float)numCols; 638 } 639 if (isnan(stamp->yNorm)) { 640 stamp->yNorm = 2.0 * (stamp->y - (float)numRows/2.0) / (float)numRows; 641 } 642 643 int x = stamp->x + 0.5, y = stamp->y + 0.5; // Stamp coordinates 644 if (x < size || x > numCols - size || y < size || y > numRows - size) { 645 psError(PS_ERR_UNKNOWN, false, "Stamp %d (%d,%d) is within the image border.\n", i, x, y); 780 p_pmSubtractionPolynomialNormCoords(&stamp->xNorm, &stamp->yNorm, stamp->x, stamp->y, 781 bounds.x0, bounds.x1, bounds.y0, bounds.y1); 782 783 int x = stamp->x - 0.5, y = stamp->y - 0.5; // Stamp coordinates 784 // fprintf (stderr, "stamp: %5.1f %5.1f == %d %d (size: %d)\n", stamp->x, stamp->y, x, y, size); 785 786 if (x < bounds.x0 + size || x > bounds.x1 - size || y < bounds.y0 + size || y > bounds.y1 - size) { 787 psError(PS_ERR_UNKNOWN, false, "Stamp %d (%d,%d) is within the region border.\n", i, x, y); 646 788 return false; 647 789 } … … 668 810 psImage *varSub = psImageSubset(variance, region); // Subimage with stamp 669 811 psKernel *var = psKernelAllocFromImage(varSub, size, size); // Variance postage stamp 670 if (isfinite(stamps->sysErr) && stamps->sysErr > 0) { 812 813 if ((isfinite(stamps->skyErr) && (stamps->skyErr > 0)) || 814 (isfinite(stamps->sysErr) && (stamps->sysErr > 0))) { 671 815 float sysErr = 0.25 * PS_SQR(stamps->sysErr); // Systematic error 816 float skyErr = stamps->skyErr; 672 817 psKernel *image1 = stamp->image1, *image2 = stamp->image2; // Input images 673 818 for (int y = -size; y <= size; y++) { 674 819 for (int x = -size; x <= size; x++) { 675 820 float additional = image1->kernel[y][x] + image2->kernel[y][x]; 676 weight->kernel[y][x] = 1.0 / ( var->kernel[y][x] + sysErr * PS_SQR(additional));821 weight->kernel[y][x] = 1.0 / (skyErr + var->kernel[y][x] + sysErr * PS_SQR(additional)); 677 822 } 678 823 } … … 698 843 pmSubtractionStampList *pmSubtractionStampsSetFromSources(const psArray *sources, const psImage *image, 699 844 const psImage *subMask, const psRegion *region, 700 int size, int footprint, float spacing, float sysErr, 845 int size, int footprint, float spacing, 846 float normFrac, float sysErr, float skyErr, 701 847 pmSubtractionMode mode) 702 848 { … … 722 868 y->data.F32[numOut] = source->peak->yf; 723 869 } 870 // fprintf (stderr, "stamp: %5.1f %5.1f\n", x->data.F32[numOut], y->data.F32[numOut]); 724 871 numOut++; 725 872 } … … 728 875 729 876 pmSubtractionStampList *stamps = pmSubtractionStampsSet(x, y, image, subMask, region, size, 730 footprint, spacing, sysErr, mode); // Stamps 877 footprint, spacing, normFrac, 878 sysErr, skyErr, mode); // Stamps 731 879 psFree(x); 732 880 psFree(y); … … 742 890 pmSubtractionStampList *pmSubtractionStampsSetFromFile(const char *filename, const psImage *image, 743 891 const psImage *subMask, const psRegion *region, 744 int size, int footprint, float spacing, float sysErr,745 pmSubtractionMode mode)892 int size, int footprint, float spacing, float normFrac, 893 float sysErr, float skyErr, pmSubtractionMode mode) 746 894 { 747 895 PS_ASSERT_STRING_NON_EMPTY(filename, NULL); … … 760 908 761 909 pmSubtractionStampList *stamps = pmSubtractionStampsSet(x, y, image, subMask, region, size, footprint, 762 spacing, sysErr, mode);910 spacing, normFrac, sysErr, skyErr, mode); 763 911 psFree(data); 764 912 … … 766 914 767 915 } 916 917 918 bool pmSubtractionStampsResetStatus (pmSubtractionStampList *stamps) { 919 920 for (int i = 0; i < stamps->num; i++) { 921 pmSubtractionStamp *stamp = stamps->stamps->data[i]; // Stamp of interest 922 if (!stamp) continue; 923 if (stamp->status != PM_SUBTRACTION_STAMP_USED) continue; 924 stamp->status = PM_SUBTRACTION_STAMP_CALCULATE; 925 } 926 return true; 927 } 928 -
trunk/psModules/src/imcombine/pmSubtractionStamps.h
r26035 r26893 24 24 psArray *flux; ///< Fluxes for possible stamps (or NULL) 25 25 int footprint; ///< Half-size of stamps 26 psKernel *window; ///< window function generated from ensemble of stamps 27 float normFrac; ///< Fraction of flux in window for normalisation window 28 int normWindow; ///< Size of window for measuring normalisation 26 29 float sysErr; ///< Systematic error 30 float skyErr; ///< increase effective readnoise 27 31 } pmSubtractionStampList; 28 32 29 33 /// Allocate a list of stamps 30 pmSubtractionStampList *pmSubtractionStampListAlloc(int numCols, // Number of columns in image 31 int numRows, // Number of rows in image 32 const psRegion *region, // Region for stamps, or NULL 33 int footprint, // Half-size of stamps 34 float spacing, // Rough average spacing between stamps 35 float sysErr // Relative systematic error or NAN 34 pmSubtractionStampList *pmSubtractionStampListAlloc( 35 int numCols, // Number of columns in image 36 int numRows, // Number of rows in image 37 const psRegion *region, // Region for stamps, or NULL 38 int footprint, // Half-size of stamps 39 float spacing, // Rough average spacing between stamps 40 float normFrac, // Fraction of flux in window for normalisation window 41 float sysErr, // Relative systematic error or NAN 42 float skyErr // Relative systematic error or NAN 36 43 ); 37 44 … … 73 80 psArray *convolutions1; ///< Convolutions of image 1 for each kernel component, or NULL 74 81 psArray *convolutions2; ///< Convolutions of image 2 for each kernel component, or NULL 75 psImage *matrix 1, *matrix2; ///< Least-squares matrices for each image, or NULL76 ps Image *matrixX; ///< Cross-matrix (for mode DUAL), or NULL77 psVector *vector1, *vector2; ///< Least-squares vectors for each image, or NULL82 psImage *matrix; ///< Least-squares matrix, or NULL 83 psVector *vector; ///< Least-squares vector, or NULL 84 double norm; ///< Normalisation difference 78 85 pmSubtractionStampStatus status; ///< Status of stamp 79 86 } pmSubtractionStamp; … … 83 90 84 91 /// Find stamps on an image 85 pmSubtractionStampList *pmSubtractionStampsFind(pmSubtractionStampList *stamps, ///< Output stamps, or NULL 86 const psImage *image1, ///< Image for which to find stamps 87 const psImage *image2, ///< Image for which to find stamps 88 const psImage *mask, ///< Mask, or NULL 89 const psRegion *region, ///< Region to search, or NULL 90 float thresh1, ///< Threshold for stamps in image 1 91 float thresh2, ///< Threshold for stamps in image 2 92 int size, ///< Kernel half-size 93 int footprint, ///< Half-size for stamps 94 float spacing, ///< Rough spacing for stamps 95 float sysErr, ///< Relative systematic error in images 96 pmSubtractionMode mode ///< Mode for subtraction 92 pmSubtractionStampList *pmSubtractionStampsFind( 93 pmSubtractionStampList *stamps, ///< Output stamps, or NULL 94 const psImage *image1, ///< Image for which to find stamps 95 const psImage *image2, ///< Image for which to find stamps 96 const psImage *mask, ///< Mask, or NULL 97 const psRegion *region, ///< Region to search, or NULL 98 float thresh1, ///< Threshold for stamps in image 1 99 float thresh2, ///< Threshold for stamps in image 2 100 int size, ///< Kernel half-size 101 int footprint, ///< Half-size for stamps 102 float spacing, ///< Rough spacing for stamps 103 float normFrac, // Fraction of flux in window for normalisation window 104 float sysErr, ///< Relative systematic error in images 105 float skyErr, ///< Relative systematic error in images 106 pmSubtractionMode mode ///< Mode for subtraction 97 107 ); 98 108 99 109 /// Set stamps based on a list of x,y 100 pmSubtractionStampList *pmSubtractionStampsSet(const psVector *x, ///< x coordinates for each stamp 101 const psVector *y, ///< y coordinates for each stamp 102 const psImage *image, ///< Image for flux of stamp 103 const psImage *mask, ///< Mask, or NULL 104 const psRegion *region, ///< Region to search, or NULL 105 int size, ///< Kernel half-size 106 int footprint, ///< Half-size for stamps 107 float spacing, ///< Rough spacing for stamps 108 float sysErr, ///< Systematic error in images 109 pmSubtractionMode mode ///< Mode for subtraction 110 pmSubtractionStampList *pmSubtractionStampsSet( 111 const psVector *x, ///< x coordinates for each stamp 112 const psVector *y, ///< y coordinates for each stamp 113 const psImage *image, ///< Image for flux of stamp 114 const psImage *mask, ///< Mask, or NULL 115 const psRegion *region, ///< Region to search, or NULL 116 int size, ///< Kernel half-size 117 int footprint, ///< Half-size for stamps 118 float spacing, ///< Rough spacing for stamps 119 float normFrac, // Fraction of flux in window for normalisation window 120 float sysErr, ///< Systematic error in images 121 float skyErr, ///< Systematic error in images 122 pmSubtractionMode mode ///< Mode for subtraction 110 123 ); 111 124 … … 119 132 int footprint, ///< Half-size for stamps 120 133 float spacing, ///< Rough spacing for stamps 134 float normFrac, // Fraction of flux in window for normalisation window 121 135 float sysErr, ///< Systematic error in images 136 float skyErr, ///< Systematic error in images 122 137 pmSubtractionMode mode ///< Mode for subtraction 123 138 ); … … 132 147 int footprint, ///< Half-size for stamps 133 148 float spacing, ///< Rough spacing for stamps 149 float normFrac, // Fraction of flux in window for normalisation window 134 150 float sysErr, ///< Systematic error in images 151 float skyErr, ///< Systematic error in images 135 152 pmSubtractionMode mode ///< Mode for subtraction 153 ); 154 155 /// Calculate the window and normalisation window from the stamps 156 bool pmSubtractionStampsGetWindow( 157 pmSubtractionStampList *stamps, ///< List of stamps 158 int kernelSize ///< Half-size of kernel 136 159 ); 137 160 … … 141 164 psImage *image2, ///< Input image (or NULL) 142 165 psImage *variance, ///< Variance map 143 int kernelSize ///< Kernel half-size 166 int kernelSize, ///< Kernel half-size 167 psRegion bounds ///< Bounds of validity 144 168 ); 145 169 … … 168 192 ); 169 193 194 195 bool pmSubtractionStampsResetStatus (pmSubtractionStampList *stamps); 196 170 197 #endif -
trunk/psModules/src/imcombine/pmSubtractionThreads.c
r21363 r26893 69 69 70 70 { 71 psThreadTask *task = psThreadTaskAlloc("PSMODULES_SUBTRACTION_CALCULATE_EQUATION", 3);71 psThreadTask *task = psThreadTaskAlloc("PSMODULES_SUBTRACTION_CALCULATE_EQUATION", 4); 72 72 task->function = &pmSubtractionCalculateEquationThread; 73 73 psThreadTaskAdd(task); -
trunk/psModules/src/imcombine/pmSubtractionVisual.c
r23487 r26893 16 16 17 17 #include "pmKapaPlots.h" 18 #include "pmSubtraction.h" 18 19 #include "pmSubtractionStamps.h" 20 #include "pmSubtractionEquation.h" 19 21 20 22 #include "pmVisual.h" … … 32 34 static bool plotLeastSquares = true; 33 35 static bool plotImage = true; 36 34 37 // variables to store plotting window indices 35 static int kapa = -1;38 static int kapa1 = -1; 36 39 static int kapa2 = -1; 40 static int kapa3 = -1; 37 41 38 42 /** function prototypes*/ … … 46 50 bool pmSubtractionVisualClose(void) 47 51 { 48 if(kapa != -1) 49 KiiClose(kapa); 50 if(kapa2 != -1) 51 KiiClose(kapa2); 52 if(kapa1 != -1) KiiClose(kapa1); 53 if(kapa2 != -1) KiiClose(kapa2); 52 54 return true; 53 55 } … … 60 62 bool pmSubtractionVisualPlotConvKernels(psImage *convKernels) { 61 63 if (!pmVisualIsVisual() || !plotConvKernels) return true; 62 if (!pmVisualInitWindow(&kapa , "ppSub:Images")) {63 return false; 64 } 65 pmVisualScaleImage(kapa , convKernels, "Convolution_Kernels", 0, true);64 if (!pmVisualInitWindow(&kapa1, "ppSub:Images")) { 65 return false; 66 } 67 pmVisualScaleImage(kapa1, convKernels, "Convolution_Kernels", 0, true); 66 68 pmVisualAskUser(&plotConvKernels); 67 69 return true; … … 74 76 bool pmSubtractionVisualPlotStamps(pmSubtractionStampList *stamps, pmReadout *ro) { 75 77 if (!pmVisualIsVisual() || !plotStamps) return true; 76 if (!pmVisualInitWindow (&kapa , "ppSub:Images")) {78 if (!pmVisualInitWindow (&kapa1, "ppSub:Images")) { 77 79 return false; 78 80 } … … 134 136 stampNum++; 135 137 } 136 pmVisualScaleImage(kapa , canvas, "Subtraction_Stamps", 0, true);138 pmVisualScaleImage(kapa1, canvas, "Subtraction_Stamps", 0, true); 137 139 138 140 pmVisualAskUser(&plotStamps); … … 144 146 145 147 if (!pmVisualIsVisual() || !plotLeastSquares) return true; 146 if (!pmVisualInitWindow (&kapa , "PPSub:Images")) {148 if (!pmVisualInitWindow (&kapa1, "PPSub:Images")) { 147 149 return false; 148 150 } … … 157 159 if (stamp == NULL) continue; 158 160 159 psImage *im = stamp->matrix1; 160 if (im == NULL) im = stamp->matrix2; 161 if (im == NULL) im = stamp->matrixX; 161 psImage *im = stamp->matrix; 162 162 if (im == NULL) continue; 163 163 … … 187 187 if (stamp == NULL) continue; 188 188 189 psImage *im = stamp->matrix1; 190 if (im == NULL) im = stamp->matrix2; 191 if (im == NULL) im = stamp->matrixX; 189 psImage *im = stamp->matrix; 192 190 if (im == NULL) continue; 193 191 … … 197 195 198 196 psImage *canvas32 = pmVisualImageToFloat(canvas); 199 pmVisualScaleImage(kapa , canvas32, "Least_Squares", 0, true);197 pmVisualScaleImage(kapa1, canvas32, "Least_Squares", 0, true); 200 198 201 199 pmVisualAskUser(&plotLeastSquares); … … 207 205 bool pmSubtractionVisualShowSubtraction(psImage *image, psImage *ref, psImage *sub) { 208 206 if (!pmVisualIsVisual() || !plotImage) return true; 209 if (!pmVisualInitWindow (&kapa, "PPSub:Images")) { 210 return false; 211 } 212 213 pmVisualScaleImage(kapa, image, "Image", 0, true); 214 pmVisualScaleImage(kapa, ref, "Reference", 1, true); 215 pmVisualScaleImage(kapa, sub, "Subtraction", 2, true); 207 if (!pmVisualInitWindow (&kapa1, "PPSub:Images")) { 208 return false; 209 } 210 211 pmVisualScaleImage(kapa1, image, "Image", 0, true); 212 pmVisualScaleImage(kapa1, ref, "Reference", 1, true); 213 pmVisualScaleImage(kapa1, sub, "Subtraction", 2, true); 214 pmVisualAskUser(&plotImage); 215 return true; 216 } 217 218 bool pmSubtractionVisualShowKernels(pmSubtractionKernels *kernels) { 219 220 if (!pmVisualIsVisual()) return true; 221 if (!pmVisualInitWindow (&kapa1, "PPSub:Images")) { 222 return false; 223 } 224 225 // get the kernel sizes 226 int footprint = kernels->size; 227 228 // output image is a grid of NXsub by NYsub sub-images 229 int NXsub = sqrt(kernels->num); 230 int NYsub = kernels->num / NXsub; 231 if (kernels->num % NXsub) NYsub++; 232 233 int NXpix = NXsub * (2*footprint + 1 + 3); 234 int NYpix = NYsub * (2*footprint + 1 + 3); 235 236 psImage *output = psImageAlloc(NXpix, NYpix, PS_TYPE_F32); 237 psImageInit (output, 0.0); 238 239 for (int i = 0; i < kernels->num; i++) { 240 pmSubtractionKernelPreCalc *preCalc = kernels->preCalc->data[i]; 241 psKernel *kernel = preCalc->kernel; 242 243 int xSub = i % NXsub; 244 int ySub = i / NXsub; 245 246 int xPix = xSub * (2*footprint + 1 + 3) + footprint; 247 int yPix = ySub * (2*footprint + 1 + 3) + footprint; 248 249 double sum = 0.0; 250 for (int y = -footprint; y <= footprint; y++) { 251 for (int x = -footprint; x <= footprint; x++) { 252 output->data.F32[y + yPix][x + xPix] = kernel->kernel[y][x]; 253 sum += kernel->kernel[y][x]; 254 } 255 } 256 fprintf (stderr, "kernel %d, sum %f\n", i, sum); 257 } 258 259 pmVisualScaleImage(kapa1, output, "Image", 0, true); 260 pmVisualAskUser(&plotImage); 261 return true; 262 } 263 264 bool pmSubtractionVisualShowBasis(pmSubtractionStampList *stamps) { 265 266 if (!pmVisualIsVisual()) return true; 267 if (!pmVisualInitWindow (&kapa2, "ppSub:StampMasterImage")) { 268 return false; 269 } 270 271 // get the kernel sizes 272 int footprint = stamps->footprint; 273 274 // choose the brightest stamp 275 pmSubtractionStamp *maxStamp = NULL; 276 float maxFlux = NAN; 277 for (int i = 0; i < stamps->num; i++) { 278 pmSubtractionStamp *stamp = stamps->stamps->data[i]; 279 if (!isfinite(stamp->flux)) continue; 280 if (!stamp->convolutions1 && !stamp->convolutions2) continue; 281 if (!maxStamp) { 282 maxFlux = stamp->flux; 283 maxStamp = stamp; 284 continue; 285 } 286 if (stamp->flux > maxFlux) { 287 maxFlux = stamp->flux; 288 maxStamp = stamp; 289 } 290 } 291 292 if (!isfinite(maxStamp->flux)) { 293 fprintf (stderr, "no valid stamps?\n"); 294 } 295 296 int nKernels = 0; 297 298 if (maxStamp->convolutions1) { 299 // output image is a grid of NXsub by NYsub sub-images 300 nKernels = maxStamp->convolutions1->n; 301 int NXsub = sqrt(nKernels); 302 int NYsub = nKernels / NXsub; 303 if (nKernels % NXsub) NYsub++; 304 305 int NXpix = NXsub * (2*footprint + 1 + 3); 306 int NYpix = NYsub * (2*footprint + 1 + 3); 307 308 psImage *output = psImageAlloc(NXpix, NYpix, PS_TYPE_F32); 309 psImageInit (output, 0.0); 310 311 for (int i = 0; i < nKernels; i++) { 312 psKernel *kernel = maxStamp->convolutions1->data[i]; 313 314 int xSub = i % NXsub; 315 int ySub = i / NXsub; 316 317 int xPix = xSub * (2*footprint + 1 + 3) + footprint; 318 int yPix = ySub * (2*footprint + 1 + 3) + footprint; 319 320 double sum = 0.0; 321 for (int y = -footprint; y <= footprint; y++) { 322 for (int x = -footprint; x <= footprint; x++) { 323 output->data.F32[y + yPix][x + xPix] = kernel->kernel[y][x]; 324 sum += kernel->kernel[y][x]; 325 } 326 } 327 fprintf (stderr, "kernel %d, sum %f\n", i, sum); 328 } 329 pmVisualScaleImage(kapa2, output, "Image", 0, true); 330 } 331 332 if (maxStamp->convolutions2) { 333 // output image is a grid of NXsub by NYsub sub-images 334 nKernels = maxStamp->convolutions2->n; 335 int NXsub = sqrt(nKernels); 336 int NYsub = nKernels / NXsub; 337 if (nKernels % NXsub) NYsub++; 338 339 int NXpix = NXsub * (2*footprint + 1 + 3); 340 int NYpix = NYsub * (2*footprint + 1 + 3); 341 342 psImage *output = psImageAlloc(NXpix, NYpix, PS_TYPE_F32); 343 psImageInit (output, 0.0); 344 345 for (int i = 0; i < nKernels; i++) { 346 psKernel *kernel = maxStamp->convolutions2->data[i]; 347 348 int xSub = i % NXsub; 349 int ySub = i / NXsub; 350 351 int xPix = xSub * (2*footprint + 1 + 3) + footprint; 352 int yPix = ySub * (2*footprint + 1 + 3) + footprint; 353 354 double sum = 0.0; 355 for (int y = -footprint; y <= footprint; y++) { 356 for (int x = -footprint; x <= footprint; x++) { 357 output->data.F32[y + yPix][x + xPix] = kernel->kernel[y][x]; 358 sum += kernel->kernel[y][x]; 359 } 360 } 361 fprintf (stderr, "kernel %d, sum %f\n", i, sum); 362 } 363 pmVisualScaleImage(kapa2, output, "Image", 1, true); 364 } 365 216 366 pmVisualAskUser(&plotImage); 217 367 return true; … … 240 390 241 391 overlay[Noverlay].type = KII_OVERLAY_BOX; 392 if ((stamp->x < 1.0) && (stamp->y < 1.0)) { 393 // fprintf (stderr, "stamp zero: %f %f\n", stamp->x, stamp->y); 394 continue; 395 } 396 if (!isfinite(stamp->x) && !isfinite(stamp->y)) { 397 // fprintf (stderr, "stamp nan: %f %f\n", stamp->x, stamp->y); 398 continue; 399 } 242 400 overlay[Noverlay].x = stamp->x; 243 401 overlay[Noverlay].y = stamp->y; … … 255 413 } 256 414 415 static int footprint = 0; 416 static int NX = 0; 417 static int NY = 0; 418 static psImage *sourceImage = NULL; 419 static psImage *targetImage = NULL; 420 static psImage *residualImage = NULL; 421 static psImage *fresidualImage = NULL; 422 static psImage *differenceImage = NULL; 423 static psImage *convolutionImage = NULL; 424 425 bool pmSubtractionVisualShowFitInit(pmSubtractionStampList *stamps) { 426 427 if (!pmVisualIsVisual()) return true; 428 429 // generate 4 storage images large enough to hold the N stamps: 430 431 footprint = stamps->footprint; 432 433 float NXf = sqrt(stamps->num); 434 NX = (int) NXf == NXf ? NXf : NXf + 1.0; 435 436 float NYf = stamps->num / NX; 437 NY = (int) NYf == NY ? NYf : NYf + 1.0; 438 439 int NXpix = (2*footprint + 1) * NX; 440 NXpix += (NX > 1) ? 3 * NX : 0; 441 442 int NYpix = (2*footprint + 1) * NY; 443 NYpix += (NY > 1) ? 3 * NY : 0; 444 445 sourceImage = psImageAlloc (NXpix, NYpix, PS_TYPE_F32); 446 targetImage = psImageAlloc (NXpix, NYpix, PS_TYPE_F32); 447 residualImage = psImageAlloc (NXpix, NYpix, PS_TYPE_F32); 448 fresidualImage = psImageAlloc (NXpix, NYpix, PS_TYPE_F32); 449 differenceImage = psImageAlloc (NXpix, NYpix, PS_TYPE_F32); 450 convolutionImage = psImageAlloc (NXpix, NYpix, PS_TYPE_F32); 451 452 psImageInit (sourceImage, 0.0); 453 psImageInit (targetImage, 0.0); 454 psImageInit (residualImage, 0.0); 455 psImageInit (fresidualImage, 0.0); 456 psImageInit (differenceImage, 0.0); 457 psImageInit (convolutionImage, 0.0); 458 459 return true; 460 } 461 462 bool pmSubtractionVisualShowFitAddStamp(psKernel *target, psKernel *source, psKernel *convolution, double background, double norm, int index) { 463 464 if (!pmVisualIsVisual()) return true; 465 466 double sum; 467 468 int NXoff = index % NX; 469 int NYoff = index / NX; 470 471 int NXpix = NXoff * (2*footprint + 1 + 3) + footprint; 472 int NYpix = NYoff * (2*footprint + 1 + 3) + footprint; 473 474 // insert the (target) kernel into the (target) image: 475 sum = 0.0; 476 for (int y = -footprint; y <= footprint; y++) { 477 for (int x = -footprint; x <= footprint; x++) { 478 targetImage->data.F32[y + NYpix][x + NXpix] = target->kernel[y][x]; 479 sum += targetImage->data.F32[y + NYpix][x + NXpix]; 480 } 481 } 482 targetImage->data.F32[footprint + 1 + NYpix][NXpix] = sum; 483 484 // insert the (source) kernel into the (source) image: 485 sum = 0.0; 486 for (int y = -footprint; y <= footprint; y++) { 487 for (int x = -footprint; x <= footprint; x++) { 488 sourceImage->data.F32[y + NYpix][x + NXpix] = source->kernel[y][x]; 489 sum += sourceImage->data.F32[y + NYpix][x + NXpix]; 490 } 491 } 492 sourceImage->data.F32[footprint + 1 + NYpix][NXpix] = sum; 493 494 // insert the (convolution) kernel into the (convolution) image: 495 sum = 0.0; 496 for (int y = -footprint; y <= footprint; y++) { 497 for (int x = -footprint; x <= footprint; x++) { 498 convolutionImage->data.F32[y + NYpix][x + NXpix] = -convolution->kernel[y][x]; 499 sum += convolutionImage->data.F32[y + NYpix][x + NXpix]; 500 } 501 } 502 convolutionImage->data.F32[footprint + 1 + NYpix][NXpix] = sum; 503 504 // insert the (difference) kernel into the (difference) image: 505 sum = 0.0; 506 for (int y = -footprint; y <= footprint; y++) { 507 for (int x = -footprint; x <= footprint; x++) { 508 differenceImage->data.F32[y + NYpix][x + NXpix] = target->kernel[y][x] - background - source->kernel[y][x] * norm; 509 sum += differenceImage->data.F32[y + NYpix][x + NXpix]; 510 } 511 } 512 differenceImage->data.F32[footprint + 1 + NYpix][NXpix] = sum; 513 514 // insert the (residual) kernel into the (residual) image: 515 sum = 0.0; 516 for (int y = -footprint; y <= footprint; y++) { 517 for (int x = -footprint; x <= footprint; x++) { 518 residualImage->data.F32[y + NYpix][x + NXpix] = target->kernel[y][x] - background - source->kernel[y][x] * norm - convolution->kernel[y][x]; 519 sum += residualImage->data.F32[y + NYpix][x + NXpix]; 520 } 521 } 522 residualImage->data.F32[footprint + 1 + NYpix][NXpix] = sum; 523 524 // insert the (fresidual) kernel into the (fresidual) image: 525 for (int y = -footprint; y <= footprint; y++) { 526 for (int x = -footprint; x <= footprint; x++) { 527 fresidualImage->data.F32[y + NYpix][x + NXpix] = residualImage->data.F32[y + NYpix][x + NXpix] / sqrt(PS_MAX(target->kernel[y][x], 100.0)); 528 } 529 } 530 return true; 531 } 532 533 bool pmSubtractionVisualShowFit(double norm) { 534 535 // for testing, dump the residual image and exit 536 if (0) { 537 psMetadata *header = psMetadataAlloc(); 538 psMetadataAddF32 (header, PS_LIST_TAIL, "NORM", 0, "Normalization", norm); 539 psFits *fits = psFitsOpen("resid.fits", "w"); 540 psFitsWriteImage(fits, header, residualImage, 0, NULL); 541 psFitsClose(fits); 542 // exit (0); 543 } 544 545 if (!pmVisualIsVisual()) return true; 546 if (!pmVisualInitWindow(&kapa1, "ppSub:Images")) return false; 547 if (!pmVisualInitWindow(&kapa2, "ppSub:Misc")) return false; 548 549 KiiEraseOverlay (kapa1, "red"); 550 KiiEraseOverlay (kapa2, "red"); 551 552 pmVisualScaleImage(kapa1, targetImage, "Target Stamps", 0, true); 553 pmVisualScaleImage(kapa1, sourceImage, "Source Stamps", 1, true); 554 pmVisualScaleImage(kapa1, convolutionImage, "Convolution Stamps", 2, true); 555 KiiCenter (kapa1, 0.5*targetImage->numCols, 0.5*targetImage->numRows, 1); 556 557 pmVisualScaleImage(kapa2, fresidualImage, "Frac Residual Stamps", 2, true); 558 pmVisualScaleImage(kapa2, differenceImage, "Difference Stamps", 0, true); 559 560 if (1) { 561 KiiImage image; 562 KapaImageData data; 563 Coords coords; 564 strcpy (coords.ctype, "RA---TAN"); 565 566 image.data2d = residualImage->data.F32; 567 image.Nx = residualImage->numCols; 568 image.Ny = residualImage->numRows; 569 strcpy (data.name, "Residual Stamps"); 570 strcpy (data.file, "Residual Stamps"); 571 572 data.zero = -300.0; 573 data.range = +600.0; 574 data.logflux = 0; 575 576 KiiSetChannel (kapa2, 1); 577 KiiNewPicture2D (kapa2, &image, &data, &coords); 578 } else { 579 pmVisualScaleImage(kapa2, residualImage, "Residual Stamps", 1, true); 580 } 581 582 KiiCenter (kapa2, 0.5*residualImage->numCols, 0.5*residualImage->numRows, 1); 583 584 pmVisualAskUser(NULL); 585 586 psFree(targetImage); 587 psFree(sourceImage); 588 psFree(convolutionImage); 589 psFree(differenceImage); 590 psFree(residualImage); 591 psFree(fresidualImage); 592 593 targetImage = NULL; 594 sourceImage = NULL; 595 convolutionImage = NULL; 596 differenceImage = NULL; 597 residualImage = NULL; 598 fresidualImage = NULL; 599 600 return true; 601 } 602 603 bool pmSubtractionVisualPlotFit(const pmSubtractionKernels *kernels) { 604 605 Graphdata graphdata; 606 607 if (!pmVisualIsVisual()) return true; 608 if (!pmVisualInitWindow(&kapa3, "ppSub:plots")) return false; 609 610 KapaClearSections (kapa3); 611 KapaInitGraph (&graphdata); 612 613 psVector *x = psVectorAllocEmpty (kernels->num, PS_TYPE_F32); 614 psVector *y = psVectorAllocEmpty (kernels->num, PS_TYPE_F32); 615 616 graphdata.xmin = -1.0; 617 graphdata.xmax = kernels->num + 1.0; 618 graphdata.ymin = +32.0; 619 graphdata.ymax = -32.0; 620 621 psImage *polyValues = p_pmSubtractionPolynomial(NULL, kernels->spatialOrder, 0.0, 0.0); 622 623 // construct the plot vectors 624 for (int i = 0; i < kernels->num; i++) { 625 x->data.F32[i] = i; 626 y->data.F32[i] = p_pmSubtractionSolutionCoeff(kernels, polyValues, i, false); 627 graphdata.ymin = PS_MIN(graphdata.ymin, y->data.F32[i]); 628 graphdata.ymax = PS_MAX(graphdata.ymax, y->data.F32[i]); 629 } 630 x->n = y->n = kernels->num; 631 632 float range; 633 range = graphdata.xmax - graphdata.xmin; 634 graphdata.xmax += 0.05*range; 635 graphdata.xmin -= 0.05*range; 636 range = graphdata.ymax - graphdata.ymin; 637 graphdata.ymax += 0.05*range; 638 graphdata.ymin -= 0.05*range; 639 640 KapaSetLimits (kapa3, &graphdata); 641 642 KapaSetFont (kapa3, "helvetica", 14); 643 KapaBox (kapa3, &graphdata); 644 KapaSendLabel (kapa3, "kernel number", KAPA_LABEL_XM); 645 KapaSendLabel (kapa3, "coeff", KAPA_LABEL_YM); 646 647 graphdata.color = KapaColorByName ("black"); 648 graphdata.ptype = 2; 649 graphdata.size = 0.5; 650 graphdata.style = 2; 651 652 KapaPrepPlot (kapa3, x->n, &graphdata); 653 KapaPlotVector (kapa3, x->n, x->data.F32, "x"); 654 KapaPlotVector (kapa3, x->n, y->data.F32, "y"); 655 656 psFree (x); 657 psFree (y); 658 659 pmVisualAskUser(NULL); 660 return true; 661 } 662 257 663 #else 258 664 bool pmSubtractionVisualClose(void) {return true;} … … 261 667 bool pmSubtractionVisualPlotLeastSquares(pmSubtractionStampList *stamps) {return true;} 262 668 bool pmSubtractionVisualShowSubtraction(psImage *image, psImage *ref, psImage *sub) {return true;} 669 bool pmSubtractionVisualShowFitInit(pmSubtractionStampList *stamps) {return true;} 670 bool pmSubtractionVisualShowFitAddStamp(psKernel *target, psKernel *source, psKernel *convolution, double background, double norm, int index) {return true;} 671 bool pmSubtractionVisualShowFit() {return true;} 672 bool pmSubtractionVisualPlotFit(const pmSubtractionKernels *kernels); 263 673 #endif -
trunk/psModules/src/imcombine/pmSubtractionVisual.h
r23487 r26893 7 7 bool pmSubtractionVisualPlotLeastSquares(pmSubtractionStampList *stamps); 8 8 bool pmSubtractionVisualShowSubtraction(psImage *image, psImage *ref, psImage *sub); 9 bool pmSubtractionVisualShowFitInit(pmSubtractionStampList *stamps); 10 bool pmSubtractionVisualShowFitAddStamp(psKernel *target, psKernel *source, psKernel *convolution, double background, double norm, int index); 11 bool pmSubtractionVisualShowFit(double norm); 12 bool pmSubtractionVisualPlotFit(const pmSubtractionKernels *kernels); 13 bool pmSubtractionVisualShowKernels(pmSubtractionKernels *kernels); 14 bool pmSubtractionVisualShowBasis(pmSubtractionStampList *stamps); 9 15 10 16 #endif
Note:
See TracChangeset
for help on using the changeset viewer.
