Changeset 14701 for trunk/psModules/src/imcombine/pmSubtraction.c
- Timestamp:
- Aug 29, 2007, 5:50:28 PM (19 years ago)
- File:
-
- 1 edited
-
trunk/psModules/src/imcombine/pmSubtraction.c (modified) (14 diffs)
Legend:
- Unmodified
- Added
- Removed
-
trunk/psModules/src/imcombine/pmSubtraction.c
r14648 r14701 4 4 * @author GLG, MHPCC 5 5 * 6 * @version $Revision: 1.4 8$ $Name: not supported by cvs2svn $7 * @date $Date: 2007-08- 23 23:43:12$6 * @version $Revision: 1.49 $ $Name: not supported by cvs2svn $ 7 * @date $Date: 2007-08-30 03:50:28 $ 8 8 * 9 9 * Copyright 2004-2007 Institute for Astronomy, University of Hawaii … … 17 17 #include <stdio.h> 18 18 #include <math.h> 19 #include <string.h> 19 20 #include <pslib.h> 20 21 … … 24 25 25 26 #include "pmSubtraction.h" 27 28 //#define TESTING 26 29 27 30 #define PIXEL_LIST_BUFFER 100 // Number of entries to add to pixel list at a time … … 216 219 } 217 220 218 // Generate the convolved pixel value 219 static inline double convolvePixel(const pmSubtractionKernels *kernels, // Kernel basis functions 220 int index, // Kernel basis function index 221 int x, int y, // Pixel around which to convolve 222 const psKernel *image // Image to convolve (a kernel for convenience) 223 ) 221 // Subtract the (0,0) element to preserve photometric scaling 222 static void convolveSub(psKernel *convolved, // Convolved image 223 const psKernel *image, // Image being convolved 224 int footprint // Size of region of interest 225 ) 226 { 227 // Can't use psBinaryOp because the images are of different size 228 for (int y = -footprint; y <= footprint; y++) { 229 for (int x = -footprint; x <= footprint; x++) { 230 convolved->kernel[y][x] -= image->kernel[y][x]; 231 } 232 } 233 return; 234 } 235 236 // Generate the convolution given some offset 237 static psKernel *convolveOffset(const psKernel *image, // Image to convolve (a kernel for convenience) 238 int u, int v, // Offset to apply 239 int footprint // Size of region of interest 240 ) 241 { 242 psKernel *convolved = psKernelAlloc(-footprint, footprint, -footprint, footprint); // Convolved image 243 int numBytes = (2 * footprint + 1) * PSELEMTYPE_SIZEOF(PS_TYPE_F32); // Number of bytes to copy 244 for (int y = -footprint; y <= footprint; y++) { 245 // Convolution with a delta function is just the value specified by the offset 246 memcpy(&convolved->kernel[y][-footprint], &image->kernel[y - v][-footprint - u], numBytes); 247 } 248 return convolved; 249 } 250 251 // Generate the convolution given a precalculated kernel 252 static psKernel *convolvePrecalc(const psKernel *image, // Image to convolve (a kernel for convenience) 253 const psKernel *kernel, // Kernel by which to convolve 254 int footprint // Size of region of interest 255 ) 256 { 257 psImage *conv = psImageConvolveFFT(image->image, kernel, 0.0); // Convolved image 258 int x0 = - image->xMin, y0 = - image->yMin; // Position of centre of convolved image 259 psKernel *convolved = psKernelAllocFromImage(conv, x0, y0); // Kernel version 260 psFree(conv); 261 return convolved; 262 } 263 264 // Generate the convolved reference image 265 static psKernel *convolveRef(const pmSubtractionKernels *kernels, // Kernel basis functions 266 int index, // Kernel basis function index 267 const psKernel *image, // Image to convolve (a kernel for convenience) 268 int footprint // Size of region of interest 269 ) 224 270 { 225 271 switch (kernels->type) { 226 272 case PM_SUBTRACTION_KERNEL_POIS: { 227 // Convolution with a delta function is just the value specified by the offset228 273 int u = kernels->u->data.S32[index]; // Offset in x 229 274 int v = kernels->v->data.S32[index]; // Offset in y 230 float value = image->kernel[y + v][x + u]; // Value of convolution275 psKernel *convolved = convolveOffset(image, u, v, footprint); // Convolved image 231 276 if (kernels->spatialOrder > 0 && index != kernels->subIndex) { 232 // The (0,0) element is subtracted from most kernels to preserve photometric scaling 233 value -= image->kernel[y][x]; 277 convolveSub(convolved, image, footprint); 234 278 } 235 return value;279 return convolved; 236 280 } 237 281 // Method for SPAM and FRIES is the same 238 282 case PM_SUBTRACTION_KERNEL_SPAM: 239 283 case PM_SUBTRACTION_KERNEL_FRIES: { 284 psKernel *convolved = psKernelAlloc(-footprint, footprint, 285 -footprint, footprint); // Convolved image 240 286 int uStart = kernels->u->data.S32[index]; 241 287 int uStop = kernels->uStop->data.S32[index]; 242 288 int vStart = kernels->v->data.S32[index]; 243 289 int vStop = kernels->vStop->data.S32[index]; 244 double sum = 0.0; 245 for (int v = vStart; v <= vStop; v++) { 246 for (int u = uStart; u <= uStop; u++) { 247 sum += image->kernel[y + v][x + u]; 290 float norm = 1.0 / (uStop - uStart + 1) * (vStop - vStart + 1); // Normalisation 291 for (int y = -footprint; y <= footprint; y++) { 292 for (int x = -footprint; x <= footprint; x++) { 293 double sum = 0.0; 294 for (int v = vStart; v <= vStop; v++) { 295 for (int u = uStart; u <= uStop; u++) { 296 sum += image->kernel[y - v][x - u]; 297 } 298 } 299 convolved->kernel[y][x] = norm * sum; 248 300 } 249 301 } 250 sum /= (uStop - uStart + 1) * (vStop - vStart + 1); // Normalising sum of kernel component to unity251 302 if (kernels->spatialOrder > 0 && index != kernels->subIndex) { 252 // The (0,0) element is subtracted from most kernels to preserve photometric scaling 253 sum -= image->kernel[y][x]; 303 convolveSub(convolved, image, footprint); 254 304 } 255 return sum;305 return convolved; 256 306 } 257 307 case PM_SUBTRACTION_KERNEL_GUNK: { 258 308 if (index < kernels->inner) { 259 // Using pre-calculated function 260 psKernel *kernel = kernels->preCalc->data[index]; // The convolution kernel 261 int size = kernels->size; // Kernel half-size 262 double sum = 0.0; // Accumulated sum from convolution 263 for (int v = -size; v <= size; v++) { 264 for (int u = -size; u <= size; u++) { 265 sum += kernel->kernel[v][u] * image->kernel[y + v][x + u]; 266 } 267 } 268 return sum; 309 // Photometric scaling is already built in to the precalculated kernel 310 return convolvePrecalc(image, kernels->preCalc->data[index], footprint); 269 311 } 270 312 // Using delta function 271 313 int u = kernels->u->data.S32[index]; // Offset in x 272 314 int v = kernels->v->data.S32[index]; // Offset in y 273 float value = image->kernel[y + v][x + u]; // Value of convolution 274 // The (0,0) delta function is subtracted from most kernels to preserve photometric scaling 315 psKernel *convolved = convolveOffset(image, u, v, footprint); // Convolved image 275 316 if (kernels->spatialOrder > 0 && index != kernels->subIndex) { 276 value -= image->kernel[y][x];317 convolveSub(convolved, image, footprint); 277 318 } 278 return value;319 return convolved; 279 320 } 280 321 case PM_SUBTRACTION_KERNEL_ISIS: { 281 psKernel *kernel = kernels->preCalc->data[index]; // The convolution kernel 282 int size = kernels->size; // Kernel half-size 283 double sum = 0.0; // Accumulated sum from convolution 284 for (int v = -size; v <= size; v++) { 285 for (int u = -size; u <= size; u++) { 286 sum += kernel->kernel[v][u] * image->kernel[y + v][x + u]; 287 // Photometric scaling is already built in to the precalculated kernel 288 } 289 } 290 return sum; 322 // Photometric scaling is already built in to the precalculated kernel 323 return convolvePrecalc(image, kernels->preCalc->data[index], footprint); 291 324 } 292 325 case PM_SUBTRACTION_KERNEL_RINGS: { 326 psKernel *convolved = psKernelAlloc(-footprint, footprint, 327 -footprint, footprint); // Convolved image 293 328 if (index == kernels->subIndex) { 294 return image->kernel[y][x]; 329 // Simply copying over the image 330 return convolveOffset(image, 0, 0, footprint); 295 331 } 332 296 333 psArray *preCalc = kernels->preCalc->data[index]; // Precalculated data 297 334 psVector *uCoords = preCalc->data[0]; // u coordinates … … 299 336 psVector *poly = preCalc->data[2]; // Polynomial values 300 337 int num = uCoords->n; // Number of pixels 301 double sum = 0.0; // Accumulated sum from convolution 302 for (int j = 0; j < num; j++) { 303 int u = uCoords->data.S32[j], v = vCoords->data.S32[j]; // Kernel coordinates 304 sum += image->kernel[y + v][x + u] * poly->data.F32[j]; 338 for (int y = -footprint; y <= footprint; y++) { 339 for (int x = -footprint; x <= footprint; x++) { 340 double sum = 0.0; // Accumulated sum from convolution 341 for (int j = 0; j < num; j++) { 342 int u = uCoords->data.S32[j], v = vCoords->data.S32[j]; // Kernel coordinates 343 sum += image->kernel[y - v][x - u] * poly->data.F32[j]; 344 } 345 convolved->kernel[y][x] = sum; 346 // Photometric scaling is built into the kernel --- no subtraction! 347 } 305 348 } 306 // Photometric scaling is built into the kernel --- no subtraction! 307 return sum; 349 return convolved; 308 350 } 309 351 default: 310 352 psAbort("Should never get here."); 311 353 } 312 return N AN;354 return NULL; 313 355 } 314 356 … … 460 502 int numParams = numKernels * numSpatial + numBackground; 461 503 int bgIndex = numParams - numBackground; // Index in matrix for the background 462 psVector *convolutions = psVectorAlloc(numKernels * numSpatial, PS_TYPE_F64); // Convolutions463 504 464 505 // We iterate over each stamp, allocate the matrix and vectors if … … 466 507 for (int i = 0; i < stamps->n; i++) { 467 508 pmSubtractionStamp *stamp = stamps->data[i]; // Stamp of interest 468 if (stamp->status == PM_SUBTRACTION_STAMP_CALCULATE) { 469 psImage *stampMatrix = stamp->matrix; // Least-squares matrix for this stamp 470 psVector *stampVector = stamp->vector; // Least-squares vector for this stamp 471 472 if (!stampMatrix) { 473 stamp->matrix = stampMatrix = psImageAlloc(numParams, numParams, PS_TYPE_F64); 474 } 475 assert(stampMatrix->type.type == PS_TYPE_F64); 476 assert(stampMatrix->numCols == numParams && stampMatrix->numRows == numParams); 477 psImageInit(stampMatrix, 0.0); 478 479 if (!stampVector) { 480 stamp->vector = stampVector = psVectorAlloc(numParams, PS_TYPE_F64); 481 } 482 assert(stampVector->type.type == PS_TYPE_F64); 483 assert(stampVector->n == numParams); 484 psVectorInit(stampVector, 0.0); 485 486 // Spatial polynomial terms 487 psImage *polyValues = spatialPolyValues(spatialOrder, stamp->xNorm, stamp->yNorm); 488 489 psKernel *reference = stamp->reference; // Reference postage stamp 490 psKernel *input = stamp->input; // Input postage stamp 491 psKernel *weight = stamp->weight; // Weight map postage stamp 492 493 for (int y = - footprint; y <= footprint; y++) { 494 for (int x = - footprint; x <= footprint; x++) { 495 float invNoise2 = 1.0 / weight->kernel[y][x]; // Inverse square noise 496 497 // Generate the convolutions 498 for (int j = 0; j < numKernels; j++) { 499 double value = convolvePixel(kernels, j, x, y, reference); // Value from convolution 500 // Generate the pseudo-convolutions from the spatial polynomial terms 501 for (int yOrder = 0, index = j; yOrder <= spatialOrder; yOrder++) { 502 for (int xOrder = 0; xOrder <= spatialOrder - yOrder; 503 xOrder++, index += numKernels) { 504 convolutions->data.F64[index] = value * polyValues->data.F64[yOrder][xOrder]; 509 if (stamp->status != PM_SUBTRACTION_STAMP_CALCULATE) { 510 continue; 511 } 512 513 psImage *stampMatrix = stamp->matrix; // Least-squares matrix for this stamp 514 psVector *stampVector = stamp->vector; // Least-squares vector for this stamp 515 516 if (!stampMatrix) { 517 stamp->matrix = stampMatrix = psImageAlloc(numParams, numParams, PS_TYPE_F64); 518 } 519 assert(stampMatrix->type.type == PS_TYPE_F64); 520 assert(stampMatrix->numCols == numParams && stampMatrix->numRows == numParams); 521 psImageInit(stampMatrix, 0.0); 522 523 if (!stampVector) { 524 stamp->vector = stampVector = psVectorAlloc(numParams, PS_TYPE_F64); 525 } 526 assert(stampVector->type.type == PS_TYPE_F64); 527 assert(stampVector->n == numParams); 528 psVectorInit(stampVector, 0.0); 529 530 psKernel *reference = stamp->reference; // Reference postage stamp 531 psKernel *input = stamp->input; // Input postage stamp 532 psKernel *weight = stamp->weight; // Weight map postage stamp 533 534 // Generate convolutions of the reference 535 psArray *convolutions = stamp->convolutions; // Convolutions of the reference for each kernel 536 if (!convolutions) { 537 stamp->convolutions = convolutions = psArrayAlloc(numKernels); 538 } 539 for (int j = 0; j < numKernels; j++) { 540 if (convolutions->data[j]) { 541 psFree(convolutions->data[j]); 542 } 543 convolutions->data[j] = convolveRef(kernels, j, reference, footprint); 544 #ifdef TESTING 545 { 546 psKernel *conv = convolutions->data[j]; // Convolution of interest 547 psString filename = NULL; 548 psStringAppend(&filename, "conv_%03d_%03d.fits", i, j); 549 psFits *fits = psFitsOpen(filename, "w"); 550 psFree(filename); 551 psFitsWriteImage(fits, NULL, conv->image, 0, NULL); 552 psFitsClose(fits); 553 } 554 #endif 555 } 556 557 psImage *polyValues = spatialPolyValues(spatialOrder, stamp->xNorm, stamp->yNorm); // Polynomial terms 558 559 // Generate least-squares vector and matrix 560 for (int j = 0; j < numKernels; j++) { 561 psKernel *jConv = convolutions->data[j]; // Convolution for j-th element 562 563 // Generate upper diagonals of matrix 564 for (int k = 0; k < numKernels; k++) { 565 psKernel *kConv = convolutions->data[k]; // Convolution for k-th element 566 double sumCC = 0.0; // Sum of the convolution products 567 for (int y = - footprint; y <= footprint; y++) { 568 for (int x = - footprint; x <= footprint; x++) { 569 sumCC += jConv->kernel[y][x] * kConv->kernel[y][x] / weight->kernel[y][x]; 570 } 571 } 572 // Generate the pseudo-convolutions from the spatial polynomial terms 573 for (int jyOrder = 0, jIndex = j; jyOrder <= spatialOrder; jyOrder++) { 574 for (int jxOrder = 0; jxOrder <= spatialOrder - jyOrder; 575 jxOrder++, jIndex += numKernels) { 576 for (int kyOrder = 0, kIndex = k; kyOrder <= spatialOrder; kyOrder++) { 577 for (int kxOrder = 0; kxOrder <= spatialOrder - kyOrder; 578 kxOrder++, kIndex += numKernels) { 579 stampMatrix->data.F64[jIndex][kIndex] = sumCC * 580 polyValues->data.F64[jyOrder][jxOrder] * 581 polyValues->data.F64[kyOrder][kxOrder]; 505 582 } 506 583 } 507 584 } 508 509 // Generate the least-squares matrix and vector 510 // Upper diagonal only 511 for (int i = 0; i < bgIndex; i++) { 512 for (int j = i; j < bgIndex; j++) { 513 stampMatrix->data.F64[i][j] += convolutions->data.F64[i] * 514 convolutions->data.F64[j] * invNoise2; 585 } 586 } 587 588 // Vector and background term for matrix 589 double sumC = 0.0; // Sum of the convolution 590 double sumIC = 0.0; // Sum of the convolution/input product 591 for (int y = - footprint; y <= footprint; y++) { 592 for (int x = - footprint; x <= footprint; x++) { 593 double convProduct = jConv->kernel[y][x] / weight->kernel[y][x]; // Convolution / noise^2 594 sumC += convProduct; 595 sumIC += input->kernel[y][x] * convProduct; 596 } 597 } 598 for (int jyOrder = 0, jIndex = j; jyOrder <= spatialOrder; jyOrder++) { 599 for (int jxOrder = 0; jxOrder <= spatialOrder - jyOrder; 600 jxOrder++, jIndex += numKernels) { 601 stampVector->data.F64[jIndex] = sumIC * polyValues->data.F64[jyOrder][jxOrder]; 602 stampMatrix->data.F64[jIndex][bgIndex] = sumC * polyValues->data.F64[jyOrder][jxOrder]; 603 stampMatrix->data.F64[bgIndex][jIndex] = sumC * polyValues->data.F64[jyOrder][jxOrder]; 604 } 605 } 606 607 } 608 psFree(polyValues); 609 610 // Background only terms 611 double sum1 = 0.0; // Sum of the weighting 612 double sumI = 0.0; // Sum of the input 613 for (int y = - footprint; y <= footprint; y++) { 614 for (int x = - footprint; x <= footprint; x++) { 615 double invNoise2 = 1.0 / weight->kernel[y][x]; // Inverse noise, squared 616 sum1 += invNoise2; 617 sumI += input->kernel[y][x] * invNoise2; 618 } 619 } 620 stampMatrix->data.F64[bgIndex][bgIndex] = sum1; 621 stampVector->data.F64[bgIndex] = sumI; 622 623 // Fill in lower diagonals of symmetric matrix, while checking for bad values 624 // Note, there are two symmetries going on here --- the matrix is C_i C_j P_i P_j 625 bool bad = false; // Are there bad values? 626 #if 0 627 for (int j = 0; j < numKernels; j++) { 628 for (int jSpatial = 0, jIndex = j; jSpatial < numSpatial; jSpatial++, jIndex += numKernels) { 629 for (int k = 0; k < j; k++) { 630 for (int kSpatial = 0, kIndex = k; kSpatial < numSpatial; 631 kSpatial++, kIndex += numKernels) { 632 double value = stampMatrix->data.F64[kIndex][jIndex]; // Value of matrix 633 stampMatrix->data.F64[jIndex][kIndex] = value; 634 if (!isfinite(value)) { 635 bad = true; 515 636 } 516 stampVector->data.F64[i] += input->kernel[y][x] * convolutions->data.F64[i] *517 invNoise2;518 519 // Background term520 stampMatrix->data.F64[i][bgIndex] += convolutions->data.F64[i] * invNoise2;521 637 } 522 // Background only terms 523 stampMatrix->data.F64[bgIndex][bgIndex] += invNoise2; 524 stampVector->data.F64[bgIndex] += input->kernel[y][x] * invNoise2; 525 } 526 } 527 psFree(polyValues); 528 529 // Fill in lower diagonal of symmetric matrix, while checking for bad values 530 bool bad = false; // Are there bad values? 531 for (int i = 0; i < bgIndex; i++) { 532 for (int j = 0; j < i; j++) { 533 stampMatrix->data.F64[i][j] = stampMatrix->data.F64[j][i]; 534 if (!isfinite(stampMatrix->data.F64[j][i])) { 535 bad = true; 536 } 537 } 538 stampMatrix->data.F64[bgIndex][i] = stampMatrix->data.F64[i][bgIndex]; 539 if (!isfinite(stampMatrix->data.F64[i][bgIndex]) || 540 !isfinite(stampMatrix->data.F64[i][i]) || 541 !isfinite(stampVector->data.F64[i])) { 638 } 639 640 stampMatrix->data.F64[bgIndex][jIndex] = stampMatrix->data.F64[jIndex][bgIndex]; 641 if (!isfinite(stampMatrix->data.F64[jIndex][bgIndex]) || 642 !isfinite(stampMatrix->data.F64[jIndex][jIndex]) || 643 !isfinite(stampVector->data.F64[jIndex])) { 542 644 bad = true; 543 645 } 544 646 } 545 if (!isfinite(stampVector->data.F64[bgIndex])) { 546 bad = true; 547 } 548 549 if (bad) { 550 stamp->status = PM_SUBTRACTION_STAMP_REJECTED; 551 psTrace("psModules.imcombine", 3, "Rejecting stamp %d (%d,%d) because of bad equation\n", 552 i, (int)(stamp->x + 0.5), (int)(stamp->y + 0.5)); 553 } else { 554 stamp->status = PM_SUBTRACTION_STAMP_USED; 555 } 556 557 if (psTraceGetLevel("psModules.imcombine.equation") >= 10) { 558 psString matrixName = NULL; 559 psStringAppend(&matrixName, "matrix%d.fits", i); 560 psFits *matrixFile = psFitsOpen(matrixName, "w"); 561 psFree(matrixName); 562 psFitsWriteImage(matrixFile, NULL, stampMatrix, 0, NULL); 563 psFitsClose(matrixFile); 564 } 565 566 } 567 } 568 569 psFree(convolutions); 647 } 648 #endif 649 if (!isfinite(stampVector->data.F64[bgIndex])) { 650 bad = true; 651 } 652 653 if (bad) { 654 stamp->status = PM_SUBTRACTION_STAMP_REJECTED; 655 psTrace("psModules.imcombine", 3, "Rejecting stamp %d (%d,%d) because of bad equation\n", 656 i, (int)(stamp->x + 0.5), (int)(stamp->y + 0.5)); 657 } else { 658 stamp->status = PM_SUBTRACTION_STAMP_USED; 659 } 660 661 if (psTraceGetLevel("psModules.imcombine.equation") >= 10) { 662 psString matrixName = NULL; 663 psStringAppend(&matrixName, "matrix%d.fits", i); 664 psFits *matrixFile = psFitsOpen(matrixName, "w"); 665 psFree(matrixName); 666 psFitsWriteImage(matrixFile, NULL, stampMatrix, 0, NULL); 667 psFitsClose(matrixFile); 668 } 669 } 570 670 571 671 return true; … … 665 765 double totalSquareDev = 0.0; // Total square deviation from zero 666 766 int numStamps = 0; // Number of used stamps 767 int numKernels = kernels->num; // Number of kernels 768 int spatialOrder = kernels->spatialOrder; // Order of kernel spatial variations 769 double devNorm = 1.0 / PS_SQR(2 * footprint + 1); // Normalisation for deviations 667 770 { 668 psStats *stats = psStatsAlloc(PS_STAT_SAMPLE_MEAN); // Statistics669 psKernel *convolution = psKernelAlloc(-footprint, footprint, -footprint, footprint); // Convolution670 psKernel *kernelImage = NULL; // The kernel, with which to convolve the stamps671 771 float background = solution->data.F64[solution->n-1]; // The difference in background 672 int size = kernels->size; // Half-size of the kernel673 772 674 773 for (int i = 0; i < stamps->n; i++) { … … 681 780 stamp->yNorm); // Polynomial terms 682 781 683 psKernel *reference = stamp->reference; // Reference postage stamp 684 685 kernelImage = solvedKernel(kernelImage, solution, kernels, polyValues, false); 782 psKernel *input = stamp->input; // Input postage stamp 783 psKernel *weight = stamp->weight; // Weight postage stamp 784 psArray *convolutions = stamp->convolutions; // Convolutions of reference image for each kernel 785 #ifdef TESTING 786 psKernel *residual = psKernelAlloc(-footprint, footprint, -footprint, footprint); 787 #endif 788 float deviation = 0.0; // Deviation for this stamp 686 789 for (int y = - footprint; y <= footprint; y++) { 687 790 for (int x = - footprint; x <= footprint; x++) { 688 convolution->kernel[y][x] = background; 689 for (int v = -size; v <= size; v++) { 690 for (int u = -size; u <= size; u++) { 691 convolution->kernel[y][x] += kernelImage->kernel[v][u] * 692 reference->kernel[y + v][x + u]; 791 float conv = background; // The value of the convolution 792 for (int j = 0; j < numKernels; j++) { 793 psKernel *convolution = convolutions->data[j]; // Convolution of reference 794 double polynomial = 0.0; // Value of the polynomial 795 for (int yOrder = 0, index = j; yOrder <= spatialOrder; yOrder++) { 796 for (int xOrder = 0; xOrder <= spatialOrder - yOrder; 797 xOrder++, index += numKernels) { 798 polynomial += solution->data.F64[index] * 799 polyValues->data.F64[yOrder][xOrder]; 800 } 693 801 } 802 conv += convolution->kernel[y][x] * polynomial; 694 803 } 804 float diff = input->kernel[y][x] - conv; 805 deviation += PS_SQR(diff) / weight->kernel[y][x]; 806 #ifdef TESTING 807 residual->kernel[y][x] = diff; 808 #endif 695 809 } 696 810 } 697 811 psFree(polyValues); 698 812 699 psImage *convolvedStamp = convolution->image; // Image of the convolution 700 psImage *input = stamp->input->image; // Input image postage stamp 701 psImage *weight = stamp->weight->image; // Weight image postage stamp 702 703 // Region of interest 704 psRegion inRegion = psRegionSet(input->col0 + size, input->col0 + size + 2 * footprint + 1, 705 input->row0 + size, input->row0 + size + 2 * footprint + 1); 706 psRegion wtRegion = (input == weight ? inRegion : 707 psRegionSet(weight->col0 + size, weight->col0 + size + 2 * footprint + 1, 708 weight->row0 + size, weight->row0 + size + 2 * footprint + 1)); 709 710 psImage *inStamp = psImageSubset(stamp->input->image, inRegion); // Image of stamp 711 psImage *wtStamp = psImageSubset(stamp->weight->image, wtRegion); // Image of stamp 712 assert(convolvedStamp->numCols == inStamp->numCols && 713 convolvedStamp->numRows == inStamp->numRows); 714 assert(convolvedStamp->numCols == wtStamp->numCols && 715 convolvedStamp->numRows == wtStamp->numRows); 716 (void)psBinaryOp(convolvedStamp, inStamp, "-", convolvedStamp); 717 (void)psBinaryOp(convolvedStamp, convolvedStamp, "*", convolvedStamp); 718 (void)psBinaryOp(convolvedStamp, convolvedStamp, "/", wtStamp); 719 psFree(inStamp); 720 psFree(wtStamp); 721 if (!psImageStats(stats, convolvedStamp, NULL, 0)) { 722 psError(PS_ERR_UNKNOWN, false, 723 "Unable to calculate statistics on normalised residual image of stamp."); 724 psFree(deviations); 725 psFree(convolution); 726 psFree(stats); 727 return -1; 728 } 729 deviations->data.F32[i] = sqrt(stats->sampleMean / 2.0); 730 psTrace("psModules.imcombine", 1, "Deviation for stamp %d (%d,%d): %f\n", 731 i, (int)(stamp->x + 0.5), (int)(stamp->y + 0.5), deviations->data.F32[i]); 813 deviations->data.F32[i] = devNorm * deviation; 814 psTrace("psModules.imcombine", 5, "Deviation for stamp %d (%d,%d): %f\n", 815 i, (int)stamp->x, (int)stamp->y, deviations->data.F32[i]); 732 816 totalSquareDev += PS_SQR(deviations->data.F32[i]); 733 817 numStamps++; 734 } 735 736 psFree(kernelImage); 737 psFree(convolution); 738 psFree(stats); 818 819 #ifdef TESTING 820 { 821 psString filename = NULL; 822 psStringAppend(&filename, "resid_%03d.fits", i); 823 psFits *fits = psFitsOpen(filename, "w"); 824 psFree(filename); 825 psFitsWriteImage(fits, NULL, residual->image, 0, NULL); 826 psFitsClose(fits); 827 } 828 psFree(residual); 829 #endif 830 831 } 739 832 } 740 833 … … 823 916 } 824 917 918 // Convolve an image using FFT 919 static void convolveFFT(psImage *target,// Place the result in here 920 const psImage *image, // Image to convolve 921 const psKernel *kernel, // Kernel by which to convolve 922 psRegion region,// Region of interest 923 float background, // Background to add 924 int size // Size of (square) kernel 925 ) 926 { 927 psRegion border = psRegionSet(region.x0 - size, region.x1 + size, 928 region.y0 - size, region.y1 + size); // Add a border 929 930 // Casting away const so psImageSubset can add the child 931 psImage *subImage = psImageSubset((psImage*)image, border); // Subimage to convolve 932 psImage *convolved = psImageConvolveFFT(subImage, kernel, 0.0); // Convolution 933 psFree(subImage); 934 935 // Now, we have to chop off the borders, and stick it in where it belongs 936 psImage *subConv = psImageSubset(convolved, psRegionSet(size, -size, 937 size, -size)); // Cut off the edges 938 psImage *subTarget = psImageSubset(target, region); // Target for this subregion 939 if (background != 0.0) { 940 psBinaryOp(subTarget, subConv, "+", psScalarAlloc(background, PS_TYPE_F32)); 941 } else { 942 int numBytes = subTarget->numCols * PSELEMTYPE_SIZEOF(PS_TYPE_F32); // Number of bytes to copy 943 for (int y = 0; y < subTarget->numRows; y++) { 944 memcpy(subTarget->data.F32[y], subConv->data.F32[y], numBytes); 945 } 946 } 947 psFree(subConv); 948 psFree(convolved); 949 psFree(subTarget); 950 return; 951 } 952 953 // Convolve an image directly 954 static void convolveDirect(psImage *target, // Put the result here 955 const psImage *image, // Image to convolve 956 const psKernel *kernel, // Kernel by which to convolve 957 psRegion region,// Region of interest 958 float background, // Background to add 959 int size // Size of (square) kernel 960 ) 961 { 962 for (int y = region.y0; y < region.y1; y++) { 963 for (int x = region.x0; x < region.x1; x++) { 964 target->data.F32[y][x] = background; 965 for (int v = -size; v <= size; v++) { 966 for (int u = -size; u <= size; u++) { 967 target->data.F32[y][x] += kernel->kernel[v][u] * 968 image->data.F32[y - v][x - u]; 969 } 970 } 971 } 972 } 973 return; 974 } 825 975 826 976 bool pmSubtractionConvolve(psImage **outImage, psImage **outWeight, psImage **outMask, 827 977 const psImage *inImage, const psImage *inWeight, const psImage *subMask, 828 978 psMaskType blank, const psRegion *region, const psVector *solution, 829 const pmSubtractionKernels *kernels )979 const pmSubtractionKernels *kernels, bool useFFT) 830 980 { 831 981 PS_ASSERT_IMAGE_NON_NULL(inImage, false); … … 927 1077 928 1078 for (int j = yMin; j < yMax; j += fullSize) { 1079 int ySubMax = PS_MIN(j + fullSize, yMax); // Range for subregion of interest 929 1080 for (int i = xMin; i < xMax; i += fullSize) { 1081 int xSubMax = PS_MIN(i + fullSize, xMax); // Range for subregion of interest 930 1082 931 1083 // Only generate polynomial values every kernel footprint, since we have already assumed … … 935 1087 2.0 * (float)(i + size + 1 - numCols/2.0) / (float)numCols, 936 1088 2.0 * (float)(j + size + 1 - numRows/2.0) / (float)numRows); 1089 937 1090 kernelImage = solvedKernel(kernelImage, solution, kernels, polyValues, false); 938 1091 if (inWeight) { … … 940 1093 } 941 1094 942 for (int y = j; y < PS_MIN(j + fullSize, yMax); y++) { 943 for (int x = i; x < PS_MIN(i + fullSize, xMax); x++) { 944 // Check and propagate the kernel footprint, if required 1095 1096 if (useFFT) { 1097 // Use Fast Fourier Transform to do the convolution 1098 // This provides a big speed-up for large kernels 1099 convolveFFT(convImage, inImage, kernelImage, psRegionSet(i, xSubMax, j, ySubMax), 1100 background, size); 1101 if (inWeight) { 1102 convolveFFT(convWeight, inWeight, kernelWeight, psRegionSet(i, xSubMax, j, ySubMax), 1103 0.0, size); 1104 } 1105 } else { 1106 convolveDirect(convImage, inImage, kernelImage, psRegionSet(i, xSubMax, j, ySubMax), 1107 background, size); 1108 if (inWeight) { 1109 convolveDirect(convWeight, inWeight, kernelWeight, psRegionSet(i, xSubMax, j, ySubMax), 1110 0.0, size); 1111 } 1112 } 1113 1114 // Propagate the mask 1115 for (int y = j; y < ySubMax; y++) { 1116 for (int x = i; x < xSubMax; x++) { 945 1117 if (subMask && (subMask->data.PS_TYPE_MASK_DATA[y][x] & 946 1118 (PM_SUBTRACTION_MASK_INPUT | PM_SUBTRACTION_MASK_CONVOLVE))) { … … 950 1122 convWeight->data.F32[y][x] = NAN; 951 1123 } 952 } else {953 // Convolve the image954 convImage->data.F32[y][x] = background;955 for (int v = -size; v <= size; v++) {956 for (int u = -size; u <= size; u++) {957 convImage->data.F32[y][x] += kernelImage->kernel[v][u] *958 inImage->data.F32[y + v][x + u];959 }960 }961 962 // Convolve the weight (variance) map963 if (inWeight) {964 for (int v = -size; v <= size; v++) {965 for (int u = -size; u <= size; u++) {966 convWeight->data.F32[y][x] += kernelWeight->kernel[v][u] *967 inWeight->data.F32[y + v][x + u];968 }969 }970 }971 1124 } 972 1125 } 973 1126 } 1127 974 1128 } 975 1129 }
Note:
See TracChangeset
for help on using the changeset viewer.
