Changeset 15443
- Timestamp:
- Nov 2, 2007, 4:28:24 PM (19 years ago)
- Location:
- trunk/psModules/src/imcombine
- Files:
-
- 10 edited
-
pmStackReject.c (modified) (3 diffs)
-
pmSubtraction.c (modified) (25 diffs)
-
pmSubtraction.h (modified) (7 diffs)
-
pmSubtractionKernels.h (modified) (1 diff)
-
pmSubtractionMatch.c (modified) (17 diffs)
-
pmSubtractionMatch.h (modified) (3 diffs)
-
pmSubtractionParams.c (modified) (19 diffs)
-
pmSubtractionParams.h (modified) (1 diff)
-
pmSubtractionStamps.c (modified) (21 diffs)
-
pmSubtractionStamps.h (modified) (5 diffs)
Legend:
- Unmodified
- Added
- Removed
-
trunk/psModules/src/imcombine/pmStackReject.c
r14701 r15443 52 52 53 53 // Convolve the image with the kernel --- we're basically applying a matched filter and then thresholding 54 psImage *convolved = NULL; // Convolved image 54 pmReadout *convRO = pmReadoutAlloc(NULL); // Readout with convolved image 55 pmReadout *inRO = pmReadoutAlloc(NULL); // Readout with input image 56 inRO->image = image; 55 57 for (int i = 0; i < numRegions; i++) { 56 58 psRegion *region = regions->data[i]; // Region of interest 57 59 psVector *solution = solutions->data[i]; // Solution of interest 58 if (!pmSubtractionConvolve( &convolved, NULL, NULL, image, NULL, NULL, 0,59 region, solution, kernels, true)) {60 if (!pmSubtractionConvolve(convRO, inRO, NULL, NULL, 0, region, solution, kernels, true, 61 PM_SUBTRACTION_MODE_1)) { 60 62 psError(PS_ERR_UNKNOWN, false, "Unable to convolve mask image in region %d.", i); 61 psFree(conv olved);62 psFree(i mage);63 psFree(convRO); 64 psFree(inRO); 63 65 return NULL; 64 66 } … … 73 75 if (!kernel) { 74 76 psError(PS_ERR_UNKNOWN, false, "Unable to generate kernel image."); 75 psFree(conv olved);76 psFree(i mage);77 psFree(convRO); 78 psFree(inRO); 77 79 return NULL; 78 80 } … … 85 87 psFree(kernel); 86 88 87 psImage *subConv = psImageSubset(conv olved, *region); // Sub-image of convolved image89 psImage *subConv = psImageSubset(convRO->image, *region); // Sub-image of convolved image 88 90 psBinaryOp(subConv, subConv, "*", psScalarAlloc(1.0 / sum, PS_TYPE_F32)); 89 91 } 90 psFree(image); 92 psFree(inRO); 93 psImage *convolved = psMemIncrRefCounter(convRO->image); 94 psFree(convRO); 91 95 92 96 // Threshold the convolved image -
trunk/psModules/src/imcombine/pmSubtraction.c
r15427 r15443 4 4 * @author GLG, MHPCC 5 5 * 6 * @version $Revision: 1.7 1$ $Name: not supported by cvs2svn $7 * @date $Date: 2007-11-0 1 01:11:03$6 * @version $Revision: 1.72 $ $Name: not supported by cvs2svn $ 7 * @date $Date: 2007-11-03 02:28:24 $ 8 8 * 9 9 * Copyright 2004-2007 Institute for Astronomy, University of Hawaii … … 76 76 77 77 // Generate the kernel to apply to the variance from the normal kernel 78 static psKernel *varianceKernel(psKernel *normalKernel // Normal kernel 78 static psKernel *varianceKernel(psKernel *out, // Output kernel 79 psKernel *normalKernel // Normal kernel 79 80 ) 80 81 { … … 83 84 int yMin = normalKernel->yMin, yMax = normalKernel->yMax; 84 85 85 psKernel *kernel = psKernelAlloc(xMin, xMax, yMin, yMax); // Kernel to return 86 if (!out) { 87 out = psKernelAlloc(xMin, xMax, yMin, yMax); 88 } 86 89 87 90 // Take the square of the normal kernel … … 93 96 sumNormal += value; 94 97 sumVariance += value2; 95 kernel->kernel[v][u] = value2;98 out->kernel[v][u] = value2; 96 99 } 97 100 } … … 99 102 // Normalise so that the sum of the variance kernel is the square of the sum of the normal kernel 100 103 // This is required to keep the relative scaling between the image and the weight map 101 psBinaryOp(kernel->image, kernel->image, "*", 102 psScalarAlloc(PS_SQR(sumNormal) / sumVariance, PS_TYPE_F32)); 103 104 return kernel; 104 psBinaryOp(out->image, out->image, "*", psScalarAlloc(PS_SQR(sumNormal) / sumVariance, PS_TYPE_F32)); 105 106 return out; 105 107 } 106 108 … … 264 266 } 265 267 266 // Generate the convolved reference image 267 static psKernel *convolveRef(const pmSubtractionKernels *kernels, // Kernel basis functions 268 int index, // Kernel basis function index 269 const psKernel *image, // Image to convolve (a kernel for convenience) 270 int footprint // Size of region of interest 271 ) 268 269 // Convolve an image using FFT 270 static void convolveFFT(psImage *target,// Place the result in here 271 const psImage *image, // Image to convolve 272 const psImage *mask, // Mask image 273 psMaskType maskVal, // Value to mask 274 const psKernel *kernel, // Kernel by which to convolve 275 psRegion region,// Region of interest 276 float background, // Background to add 277 int size // Size of (square) kernel 278 ) 279 { 280 psRegion border = psRegionSet(region.x0 - size, region.x1 + size, 281 region.y0 - size, region.y1 + size); // Add a border 282 283 // Casting away const so psImageSubset can add the child 284 psImage *subImage = psImageSubset((psImage*)image, border); // Subimage to convolve 285 psImage *subMask = mask ? psImageSubset((psImage*)mask, border) : NULL; // Subimage mask 286 psImage *convolved = psImageConvolveFFT(subImage, subMask, maskVal, kernel, 0.0); // Convolution 287 psFree(subImage); 288 psFree(subMask); 289 290 // Now, we have to chop off the borders, and stick it in where it belongs 291 psImage *subConv = psImageSubset(convolved, psRegionSet(size, -size, size, -size)); // Cut off the edges 292 psImage *subTarget = psImageSubset(target, region); // Target for this subregion 293 if (background != 0.0) { 294 psBinaryOp(subTarget, subConv, "+", psScalarAlloc(background, PS_TYPE_F32)); 295 } else { 296 int numBytes = subTarget->numCols * PSELEMTYPE_SIZEOF(PS_TYPE_F32); // Number of bytes to copy 297 for (int y = 0; y < subTarget->numRows; y++) { 298 memcpy(subTarget->data.F32[y], subConv->data.F32[y], numBytes); 299 } 300 } 301 psFree(subConv); 302 psFree(convolved); 303 psFree(subTarget); 304 return; 305 } 306 307 // Convolve an image directly 308 static void convolveDirect(psImage *target, // Put the result here 309 const psImage *image, // Image to convolve 310 const psKernel *kernel, // Kernel by which to convolve 311 psRegion region,// Region of interest 312 float background, // Background to add 313 int size // Size of (square) kernel 314 ) 315 { 316 for (int y = region.y0; y < region.y1; y++) { 317 for (int x = region.x0; x < region.x1; x++) { 318 target->data.F32[y][x] = background; 319 for (int v = -size; v <= size; v++) { 320 for (int u = -size; u <= size; u++) { 321 target->data.F32[y][x] += kernel->kernel[v][u] * 322 image->data.F32[y - v][x - u]; 323 } 324 } 325 } 326 } 327 return; 328 } 329 330 // Mark a pixel as blank in the image, mask and weight 331 static inline void markBlank(psImage *image, // Image to mark as blank 332 psImage *mask, // Mask to mark as blank (or NULL) 333 psImage *weight, // Weight map to mark as blank (or NULL) 334 int x, int y, // Coordinates to mark blank 335 psMaskType blank // Blank mask value 336 ) 337 { 338 image->data.F32[y][x] = NAN; 339 if (mask) { 340 mask->data.PS_TYPE_MASK_DATA[y][x] |= blank; 341 } 342 if (weight) { 343 weight->data.F32[y][x] = NAN; 344 } 345 return; 346 } 347 348 ////////////////////////////////////////////////////////////////////////////////////////////////////////////// 349 // Semi-public functions 350 ////////////////////////////////////////////////////////////////////////////////////////////////////////////// 351 352 // Generate the convolution given a precalculated kernel 353 psKernel *p_pmSubtractionConvolveStampPrecalc(const psKernel *image, const psKernel *kernel) 354 { 355 PS_ASSERT_KERNEL_NON_NULL(image, NULL); 356 PS_ASSERT_KERNEL_NON_NULL(kernel, NULL); 357 358 psImage *conv = psImageConvolveFFT(image->image, NULL, 0, kernel, 0.0); // Convolved image 359 int x0 = - image->xMin, y0 = - image->yMin; // Position of centre of convolved image 360 psKernel *convolved = psKernelAllocFromImage(conv, x0, y0); // Kernel version 361 psFree(conv); 362 return convolved; 363 } 364 365 366 ////////////////////////////////////////////////////////////////////////////////////////////////////////////// 367 // Public functions 368 ////////////////////////////////////////////////////////////////////////////////////////////////////////////// 369 370 psImage *pmSubtractionMask(const psImage *mask1, const psImage *mask2, psMaskType maskVal, 371 int size, int footprint, float badFrac, bool useFFT) 372 { 373 PS_ASSERT_IMAGE_NON_NULL(mask1, NULL); 374 PS_ASSERT_IMAGE_TYPE(mask1, PS_TYPE_MASK, NULL); 375 if (mask2) { 376 PS_ASSERT_IMAGE_NON_NULL(mask2, NULL); 377 PS_ASSERT_IMAGE_TYPE(mask2, PS_TYPE_MASK, NULL); 378 PS_ASSERT_IMAGES_SIZE_EQUAL(mask2, mask1, NULL); 379 } 380 PS_ASSERT_INT_NONNEGATIVE(size, NULL); 381 PS_ASSERT_INT_NONNEGATIVE(footprint, NULL); 382 if (isfinite(badFrac)) { 383 PS_ASSERT_FLOAT_LARGER_THAN(badFrac, 0.0, NULL); 384 PS_ASSERT_FLOAT_LESS_THAN_OR_EQUAL(badFrac, 1.0, NULL); 385 } 386 387 int numCols = mask1->numCols, numRows = mask1->numRows; // Size of the images 388 389 // Dereference inputs for convenience 390 psMaskType **data1 = mask1->data.PS_TYPE_MASK_DATA; 391 psMaskType **data2 = NULL; 392 if (mask2) { 393 data2 = mask2->data.PS_TYPE_MASK_DATA; 394 } 395 396 // First, a pass through to determine the fraction of bad pixels 397 if (isfinite(badFrac) && badFrac != 1.0) { 398 int numBad = 0; // Number of bad pixels 399 for (int y = 0; y < numRows; y++) { 400 for (int x = 0; x < numCols; x++) { 401 if (data1[y][x] & maskVal) { 402 numBad++; 403 continue; 404 } 405 if (data2 && data2[y][x] & maskVal) { 406 numBad++; 407 } 408 } 409 } 410 if (numBad > badFrac * numCols * numRows) { 411 psError(PS_ERR_BAD_PARAMETER_VALUE, true, 412 "Fraction of bad pixels (%d/%d=%f) exceeds limit (%f)\n", 413 numBad, numCols * numRows, (float)numBad/(float)(numCols * numRows), badFrac); 414 return NULL; 415 } 416 } 417 418 // Worried about the masks for bad pixels and bad stamps colliding, so make our own mask 419 psImage *mask = psImageAlloc(numCols, numRows, PS_TYPE_MASK); // The global mask 420 psImageInit(mask, 0); 421 psMaskType **maskData = mask->data.PS_TYPE_MASK_DATA; // Dereference for convenience 422 423 // Block out a border around the edge of the image 424 425 // Bottom stripe 426 for (int y = 0; y < PS_MIN(size + footprint, numRows); y++) { 427 for (int x = 0; x < numCols; x++) { 428 maskData[y][x] |= PM_SUBTRACTION_MASK_BORDER; 429 } 430 } 431 // Either side 432 for (int y = PS_MIN(size + footprint, numRows); y < numRows - size - footprint; y++) { 433 for (int x = 0; x < PS_MIN(size + footprint, numCols); x++) { 434 maskData[y][x] |= PM_SUBTRACTION_MASK_BORDER; 435 } 436 for (int x = PS_MAX(numCols - size - footprint, 0); x < numCols; x++) { 437 maskData[y][x] |= PM_SUBTRACTION_MASK_BORDER; 438 } 439 } 440 // Top stripe 441 for (int y = PS_MAX(numRows - size - footprint, 0); y < numRows; y++) { 442 for (int x = 0; x < numCols; x++) { 443 maskData[y][x] |= PM_SUBTRACTION_MASK_BORDER; 444 } 445 } 446 447 // XXX Could do something smarter here --- we will get images that are predominantly masked (where the 448 // skycell isn't overlapped by a large fraction by the observation), so that convolving around every bad 449 // pixel is wasting time. As a first cut, I've put in a check on the fraction of bad pixels, but we could 450 // imagine looking for the edge of big regions and convolving just at the edge. As a second cut, allow 451 // use of FFT convolution. 452 453 for (int y = 0; y < numRows; y++) { 454 for (int x = 0; x < numCols; x++) { 455 if (data1[y][x] & maskVal) { 456 maskData[y][x] |= PM_SUBTRACTION_MASK_BAD_1; 457 } 458 if (data2 && data2[y][x] & maskVal) { 459 maskData[y][x] |= PM_SUBTRACTION_MASK_BAD_2; 460 } 461 } 462 } 463 464 // Block out the entire stamp footprint around bad input pixels. 465 466 // We want to block out with the CONVOLVE mask anything that would be bad if we convolved with a bad 467 // reference pixel (within 'size'). Then we want to block out with the FOOTPRINT mask everything within a 468 // footprint's distance of those (within 'footprint'). 469 470 if (useFFT) { 471 if (!psImageConvolveMaskFFT(mask, mask, PM_SUBTRACTION_MASK_BAD_1 | PM_SUBTRACTION_MASK_BAD_2, 472 PM_SUBTRACTION_MASK_CONVOLVE_1 | PM_SUBTRACTION_MASK_FOOTPRINT_1, 473 -size, size, -size, size, 0.5)) { 474 psError(PS_ERR_UNKNOWN, false, "Unable to convolve bad pixels from mask 1."); 475 psFree(mask); 476 return NULL; 477 } 478 if (!psImageConvolveMaskFFT(mask, mask, PM_SUBTRACTION_MASK_BAD_2, 479 PM_SUBTRACTION_MASK_CONVOLVE_2 | PM_SUBTRACTION_MASK_FOOTPRINT_2, 480 -size, size, -size, size, 0.5)) { 481 psError(PS_ERR_UNKNOWN, false, "Unable to convolve bad pixels from mask 2."); 482 psFree(mask); 483 return NULL; 484 } 485 if (!psImageConvolveMaskFFT(mask, mask, PM_SUBTRACTION_MASK_CONVOLVE_1, 486 PM_SUBTRACTION_MASK_FOOTPRINT_1, 487 -footprint, footprint, -footprint, footprint, 0.5)) { 488 psError(PS_ERR_UNKNOWN, false, "Unable to reconvolve bad pixels from mask 1."); 489 psFree(mask); 490 return NULL; 491 } 492 if (!psImageConvolveMaskFFT(mask, mask, PM_SUBTRACTION_MASK_CONVOLVE_2, 493 PM_SUBTRACTION_MASK_FOOTPRINT_2, 494 -footprint, footprint, -footprint, footprint, 0.5)) { 495 psError(PS_ERR_UNKNOWN, false, "Unable to reconvolve bad pixels from mask 2."); 496 psFree(mask); 497 return NULL; 498 } 499 } else { 500 if (!psImageConvolveMaskDirect(mask, mask, PM_SUBTRACTION_MASK_BAD_1, 501 PM_SUBTRACTION_MASK_CONVOLVE_1 | PM_SUBTRACTION_MASK_FOOTPRINT_1, 502 -size, size, -size, size)) { 503 psError(PS_ERR_UNKNOWN, false, "Unable to convolve bad pixels from mask 1."); 504 psFree(mask); 505 return NULL; 506 } 507 if (!psImageConvolveMaskDirect(mask, mask, PM_SUBTRACTION_MASK_BAD_2, 508 PM_SUBTRACTION_MASK_CONVOLVE_2 | PM_SUBTRACTION_MASK_FOOTPRINT_2, 509 -size, size, -size, size)) { 510 psError(PS_ERR_UNKNOWN, false, "Unable to convolve bad pixels from mask 2."); 511 psFree(mask); 512 return NULL; 513 } 514 if (!psImageConvolveMaskDirect(mask, mask, PM_SUBTRACTION_MASK_CONVOLVE_1, 515 PM_SUBTRACTION_MASK_FOOTPRINT_1, 516 -footprint, footprint, -footprint, footprint)) { 517 psError(PS_ERR_UNKNOWN, false, "Unable to reconvolve bad pixels from mask 1."); 518 psFree(mask); 519 return NULL; 520 } 521 if (!psImageConvolveMaskDirect(mask, mask, PM_SUBTRACTION_MASK_CONVOLVE_2, 522 PM_SUBTRACTION_MASK_FOOTPRINT_2, 523 -footprint, footprint, -footprint, footprint)) { 524 psError(PS_ERR_UNKNOWN, false, "Unable to reconvolve bad pixels from mask 2."); 525 psFree(mask); 526 return NULL; 527 } 528 } 529 530 return mask; 531 } 532 533 // Convolve a stamp by a single kernel basis function 534 static psKernel *convolveStampSingle(const pmSubtractionKernels *kernels, // Kernel basis functions 535 int index, // Kernel basis function index 536 const psKernel *image, // Image to convolve (a kernel for convenience) 537 int footprint // Size of region of interest 538 ) 272 539 { 273 540 switch (kernels->type) { … … 326 593 } 327 594 case PM_SUBTRACTION_KERNEL_RINGS: { 328 psKernel *convolved = psKernelAlloc(-footprint, footprint,329 -footprint, footprint); // Convolved image330 595 if (index == kernels->subIndex) { 331 596 // Simply copying over the image 332 597 return convolveOffset(image, 0, 0, footprint); 333 598 } 334 599 psKernel *convolved = psKernelAlloc(-footprint, footprint, 600 -footprint, footprint); // Convolved image 335 601 psArray *preCalc = kernels->preCalc->data[index]; // Precalculated data 336 602 psVector *uCoords = preCalc->data[0]; // u coordinates … … 357 623 } 358 624 359 // Convolve an image using FFT 360 static void convolveFFT(psImage *target,// Place the result in here 361 const psImage *image, // Image to convolve 362 const psImage *mask, // Mask image 363 const psKernel *kernel, // Kernel by which to convolve 364 psRegion region,// Region of interest 365 float background, // Background to add 366 int size // Size of (square) kernel 367 ) 368 { 369 psRegion border = psRegionSet(region.x0 - size, region.x1 + size, 370 region.y0 - size, region.y1 + size); // Add a border 371 372 // Casting away const so psImageSubset can add the child 373 psImage *subImage = psImageSubset((psImage*)image, border); // Subimage to convolve 374 psImage *subMask = mask ? psImageSubset((psImage*)mask, border) : NULL; // Subimage mask 375 psImage *convolved = psImageConvolveFFT(subImage, subMask, PM_SUBTRACTION_MASK_REF, 376 kernel, 0.0); // Convolution 377 psFree(subImage); 378 psFree(subMask); 379 380 // Now, we have to chop off the borders, and stick it in where it belongs 381 psImage *subConv = psImageSubset(convolved, psRegionSet(size, -size, size, -size)); // Cut off the edges 382 psImage *subTarget = psImageSubset(target, region); // Target for this subregion 383 if (background != 0.0) { 384 psBinaryOp(subTarget, subConv, "+", psScalarAlloc(background, PS_TYPE_F32)); 385 } else { 386 int numBytes = subTarget->numCols * PSELEMTYPE_SIZEOF(PS_TYPE_F32); // Number of bytes to copy 387 for (int y = 0; y < subTarget->numRows; y++) { 388 memcpy(subTarget->data.F32[y], subConv->data.F32[y], numBytes); 389 } 390 } 391 psFree(subConv); 392 psFree(convolved); 393 psFree(subTarget); 394 return; 395 } 396 397 // Convolve an image directly 398 static void convolveDirect(psImage *target, // Put the result here 399 const psImage *image, // Image to convolve 400 const psKernel *kernel, // Kernel by which to convolve 401 psRegion region,// Region of interest 402 float background, // Background to add 403 int size // Size of (square) kernel 404 ) 405 { 406 for (int y = region.y0; y < region.y1; y++) { 407 for (int x = region.x0; x < region.x1; x++) { 408 target->data.F32[y][x] = background; 409 for (int v = -size; v <= size; v++) { 410 for (int u = -size; u <= size; u++) { 411 target->data.F32[y][x] += kernel->kernel[v][u] * 412 image->data.F32[y - v][x - u]; 413 } 414 } 415 } 416 } 417 return; 418 } 419 420 // Mark a pixel as blank in the image, mask and weight 421 static inline void markBlank(psImage *image, // Image to mark as blank 422 psImage *mask, // Mask to mark as blank (or NULL) 423 psImage *weight, // Weight map to mark as blank (or NULL) 424 int x, int y, // Coordinates to mark blank 425 psMaskType blank // Blank mask value 625 // Convolve the stamp by each of the kernel basis functions 626 static psArray *convolveStamp(psArray *convolutions, // The convolutions 627 const psKernel *image, // Image to convolve 628 const pmSubtractionKernels *kernels, // Kernel basis functions 629 int footprint // Stamp half-size 426 630 ) 427 631 { 428 image->data.F32[y][x] = NAN; 429 if (mask) { 430 mask->data.PS_TYPE_MASK_DATA[y][x] |= blank; 431 } 432 if (weight) { 433 weight->data.F32[y][x] = NAN; 434 } 435 return; 436 } 437 438 ////////////////////////////////////////////////////////////////////////////////////////////////////////////// 439 // Semi-public functions 440 ////////////////////////////////////////////////////////////////////////////////////////////////////////////// 441 442 // Generate the convolution given a precalculated kernel 443 psKernel *p_pmSubtractionConvolveStampPrecalc(const psKernel *image, const psKernel *kernel) 444 { 445 PS_ASSERT_KERNEL_NON_NULL(image, NULL); 446 PS_ASSERT_KERNEL_NON_NULL(kernel, NULL); 447 448 psImage *conv = psImageConvolveFFT(image->image, NULL, 0, kernel, 0.0); // Convolved image 449 int x0 = - image->xMin, y0 = - image->yMin; // Position of centre of convolved image 450 psKernel *convolved = psKernelAllocFromImage(conv, x0, y0); // Kernel version 451 psFree(conv); 452 return convolved; 453 } 454 455 456 ////////////////////////////////////////////////////////////////////////////////////////////////////////////// 457 // Public functions 458 ////////////////////////////////////////////////////////////////////////////////////////////////////////////// 459 460 psImage *pmSubtractionMask(const psImage *refMask, const psImage *inMask, psMaskType maskVal, 461 int size, int footprint, float badFrac, bool useFFT) 462 { 463 PS_ASSERT_IMAGE_NON_NULL(refMask, NULL); 464 PS_ASSERT_IMAGE_TYPE(refMask, PS_TYPE_MASK, NULL); 465 if (inMask) { 466 PS_ASSERT_IMAGE_NON_NULL(inMask, NULL); 467 PS_ASSERT_IMAGE_TYPE(inMask, PS_TYPE_MASK, NULL); 468 PS_ASSERT_IMAGES_SIZE_EQUAL(inMask, refMask, NULL); 469 } 470 PS_ASSERT_INT_NONNEGATIVE(size, NULL); 471 PS_ASSERT_INT_NONNEGATIVE(footprint, NULL); 472 if (isfinite(badFrac)) { 473 PS_ASSERT_FLOAT_LARGER_THAN(badFrac, 0.0, NULL); 474 PS_ASSERT_FLOAT_LESS_THAN_OR_EQUAL(badFrac, 1.0, NULL); 475 } 476 477 // Size of the images 478 int numCols = refMask->numCols; 479 int numRows = refMask->numRows; 480 481 // Dereference inputs for convenience 482 psMaskType **inData = NULL; 483 if (inMask) { 484 inData = inMask->data.PS_TYPE_MASK_DATA; 485 } 486 psMaskType **refData = refMask->data.PS_TYPE_MASK_DATA; 487 488 // First, a pass through to determine the fraction of bad pixels 489 if (isfinite(badFrac) && badFrac != 1.0) { 490 int numBad = 0; // Number of bad pixels 491 for (int y = 0; y < numRows; y++) { 492 for (int x = 0; x < numCols; x++) { 493 if (inData && inData[y][x] & maskVal) { 494 numBad++; 495 continue; 496 } 497 if (refData[y][x] & maskVal) { 498 numBad++; 499 } 500 } 501 } 502 if (numBad > badFrac * numCols * numRows) { 503 psError(PS_ERR_BAD_PARAMETER_VALUE, true, 504 "Fraction of bad pixels (%d/%d=%f) exceeds limit (%f)\n", 505 numBad, numCols * numRows, (float)numBad/(float)(numCols * numRows), badFrac); 506 return NULL; 507 } 508 } 509 510 // Worried about the masks for bad pixels and bad stamps colliding, so make our own mask 511 psImage *mask = psImageAlloc(numCols, numRows, PS_TYPE_MASK); // The global mask 512 psImageInit(mask, 0); 513 psMaskType **maskData = mask->data.PS_TYPE_MASK_DATA; // Dereference for convenience 514 515 // Block out a border around the edge of the image 516 517 // Bottom stripe 518 for (int y = 0; y < PS_MIN(size + footprint, numRows); y++) { 519 for (int x = 0; x < numCols; x++) { 520 maskData[y][x] |= PM_SUBTRACTION_MASK_BORDER; 521 } 522 } 523 // Either side 524 for (int y = PS_MIN(size + footprint, numRows); y < numRows - size - footprint; y++) { 525 for (int x = 0; x < PS_MIN(size + footprint, numCols); x++) { 526 maskData[y][x] |= PM_SUBTRACTION_MASK_BORDER; 527 } 528 for (int x = PS_MAX(numCols - size - footprint, 0); x < numCols; x++) { 529 maskData[y][x] |= PM_SUBTRACTION_MASK_BORDER; 530 } 531 } 532 // Top stripe 533 for (int y = PS_MAX(numRows - size - footprint, 0); y < numRows; y++) { 534 for (int x = 0; x < numCols; x++) { 535 maskData[y][x] |= PM_SUBTRACTION_MASK_BORDER; 536 } 537 } 538 539 // XXX Could do something smarter here --- we will get images that are predominantly masked (where the 540 // skycell isn't overlapped by a large fraction by the observation), so that convolving around every bad 541 // pixel is wasting time. As a first cut, I've put in a check on the fraction of bad pixels, but we could 542 // imagine looking for the edge of big regions and convolving just at the edge. As a second cut, allow 543 // use of FFT convolution. 544 545 for (int y = 0; y < numRows; y++) { 546 for (int x = 0; x < numCols; x++) { 547 if (inData && inData[y][x] & maskVal) { 548 maskData[y][x] |= PM_SUBTRACTION_MASK_INPUT; 549 } 550 if (refData[y][x] & maskVal) { 551 maskData[y][x] |= PM_SUBTRACTION_MASK_REF; 552 } 553 } 554 } 555 556 // Block out the entire stamp footprint around bad input pixels. 557 558 // We want to block out with the CONVOLVE mask anything that would be bad if we convolved with a bad 559 // reference pixel (within 'size'). Then we want to block out with the FOOTPRINT mask everything within a 560 // footprint's distance of those (within 'footprint'). 561 562 if (useFFT) { 563 if (!psImageConvolveMaskFFT(mask, mask, PM_SUBTRACTION_MASK_INPUT, PM_SUBTRACTION_MASK_FOOTPRINT, 564 -footprint, footprint, -footprint, footprint, 0.5)) { 565 psError(PS_ERR_UNKNOWN, false, "Unable to convolve bad input pixels."); 566 psFree(mask); 567 return NULL; 568 } 569 if (!psImageConvolveMaskFFT(mask, mask, PM_SUBTRACTION_MASK_REF, PM_SUBTRACTION_MASK_CONVOLVE, 570 -size, size, -size, size, 0.5)) { 571 psError(PS_ERR_UNKNOWN, false, "Unable to convolve bad reference pixels."); 572 psFree(mask); 573 return NULL; 574 } 575 if (!psImageConvolveMaskFFT(mask, mask, PM_SUBTRACTION_MASK_CONVOLVE, PM_SUBTRACTION_MASK_FOOTPRINT, 576 -footprint, footprint, -footprint, footprint, 0.5)) { 577 psError(PS_ERR_UNKNOWN, false, "Unable to reconvolve bad reference pixels."); 578 psFree(mask); 579 return NULL; 580 } 581 } else { 582 if (!psImageConvolveMaskDirect(mask, mask, PM_SUBTRACTION_MASK_INPUT, PM_SUBTRACTION_MASK_FOOTPRINT, 583 -footprint, footprint, -footprint, footprint)) { 584 psError(PS_ERR_UNKNOWN, false, "Unable to convolve bad input pixels."); 585 psFree(mask); 586 return NULL; 587 } 588 if (!psImageConvolveMaskDirect(mask, mask, PM_SUBTRACTION_MASK_REF, PM_SUBTRACTION_MASK_CONVOLVE, 589 -size, size, -size, size)) { 590 psError(PS_ERR_UNKNOWN, false, "Unable to convolve bad reference pixels."); 591 psFree(mask); 592 return NULL; 593 } 594 if (!psImageConvolveMaskDirect(mask, mask, PM_SUBTRACTION_MASK_CONVOLVE, 595 PM_SUBTRACTION_MASK_FOOTPRINT, 596 -footprint, footprint, -footprint, footprint)) { 597 psError(PS_ERR_UNKNOWN, false, "Unable to reconvolve bad reference pixels."); 598 psFree(mask); 599 return NULL; 600 } 601 } 602 603 return mask; 604 } 605 606 bool pmSubtractionConvolveStamp(pmSubtractionStamp *stamp, const pmSubtractionKernels *kernels, int footprint) 632 assert(image); 633 assert(kernels); 634 assert(footprint >= 0); 635 636 if (convolutions) { 637 // Already done 638 return convolutions; 639 } 640 641 int numKernels = kernels->num; // Number of kernels 642 convolutions = psArrayAlloc(numKernels); 643 644 for (int i = 0; i < numKernels; i++) { 645 convolutions->data[i] = convolveStampSingle(kernels, i, image, footprint); 646 } 647 648 return convolutions; 649 } 650 651 652 bool pmSubtractionConvolveStamp(pmSubtractionStamp *stamp, const pmSubtractionKernels *kernels, int footprint, 653 pmSubtractionMode mode) 607 654 { 608 655 PS_ASSERT_PTR_NON_NULL(stamp, false); 609 PS_ASSERT_KERNEL_NON_NULL(stamp->reference, false);610 656 PS_ASSERT_PTR_NON_NULL(kernels, false); 611 657 PS_ASSERT_VECTORS_SIZE_EQUAL(kernels->u, kernels->v, false); … … 617 663 } 618 664 619 if (stamp->convolutions) { 620 // Already done 621 return true; 622 } 623 624 stamp->convolutions = psArrayAlloc(kernels->num); 625 psKernel *reference = stamp->reference; // Reference postage stamp 626 627 for (int i = 0; i < kernels->num; i++) { 628 stamp->convolutions->data[i] = convolveRef(kernels, i, reference, footprint); 665 switch (mode) { 666 case PM_SUBTRACTION_MODE_TARGET: 667 case PM_SUBTRACTION_MODE_1: 668 stamp->convolutions1 = convolveStamp(stamp->convolutions1, stamp->image1, kernels, footprint); 669 break; 670 case PM_SUBTRACTION_MODE_2: 671 stamp->convolutions2 = convolveStamp(stamp->convolutions2, stamp->image2, kernels, footprint); 672 break; 673 case PM_SUBTRACTION_MODE_UNSURE: 674 case PM_SUBTRACTION_MODE_DUAL: 675 stamp->convolutions1 = convolveStamp(stamp->convolutions1, stamp->image1, kernels, footprint); 676 stamp->convolutions2 = convolveStamp(stamp->convolutions2, stamp->image2, kernels, footprint); 677 break; 678 default: 679 psAbort("Unsupported subtraction mode: %x", mode); 629 680 } 630 681 … … 634 685 635 686 bool pmSubtractionCalculateEquation(pmSubtractionStampList *stamps, const pmSubtractionKernels *kernels, 636 int footprint )687 int footprint, pmSubtractionMode mode) 637 688 { 638 689 PM_ASSERT_SUBTRACTION_STAMP_LIST_NON_NULL(stamps, false); … … 676 727 psVectorInit(stampVector, 0.0); 677 728 678 psKernel *input = stamp->input; // Input postage stamp 679 psKernel *weight = stamp->weight; // Weight map postage stamp 680 681 // Generate convolutions of the reference 682 if (!pmSubtractionConvolveStamp(stamp, kernels, footprint)) { 729 // Generate convolutions 730 if (!pmSubtractionConvolveStamp(stamp, kernels, footprint, mode)) { 683 731 psError(PS_ERR_UNKNOWN, false, "Unable to convolve stamp %d.", i); 684 732 return NULL; 685 733 } 686 734 687 psArray *convolutions = stamp->convolutions; // Convolutions of the reference for each kernel 735 psKernel *weight = stamp->weight; // Weight map postage stamp 736 psKernel *target; // Target postage stamp 737 psArray *convolutions; // Convolutions for each kernel 738 739 switch (mode) { 740 case PM_SUBTRACTION_MODE_TARGET: 741 case PM_SUBTRACTION_MODE_1: 742 target = stamp->image2; 743 convolutions = stamp->convolutions1; 744 break; 745 case PM_SUBTRACTION_MODE_2: 746 target = stamp->image1; 747 convolutions = stamp->convolutions2; 748 break; 749 default: 750 psAbort("Unsupported subtraction mode: %x", mode); 751 } 752 688 753 psImage *polyValues = spatialPolyValues(spatialOrder, stamp->xNorm, stamp->yNorm); // Polynomial terms 689 754 … … 739 804 // Vector and background term for matrix 740 805 double sumC = 0.0; // Sum of the convolution 741 double sum IC = 0.0; // Sum of the convolution/input product806 double sumTC = 0.0; // Sum of the convolution/target product 742 807 for (int y = - footprint; y <= footprint; y++) { 743 808 for (int x = - footprint; x <= footprint; x++) { 744 809 double convProduct = jConv->kernel[y][x] / weight->kernel[y][x]; // Convolution / noise^2 745 810 sumC += convProduct; 746 sum IC += input->kernel[y][x] * convProduct;811 sumTC += target->kernel[y][x] * convProduct; 747 812 } 748 813 } … … 752 817 continue; 753 818 } 754 if (!isfinite(sum IC)) {819 if (!isfinite(sumTC)) { 755 820 psStringAppend(&badString, "\nBad sumIC detected at %d", j); 756 821 bad = true; … … 761 826 for (int jxOrder = 0; jxOrder <= spatialOrder - jyOrder; 762 827 jxOrder++, jIndex += numKernels) { 763 stampVector->data.F64[jIndex] = sum IC * polyValues->data.F64[jyOrder][jxOrder];828 stampVector->data.F64[jIndex] = sumTC * polyValues->data.F64[jyOrder][jxOrder]; 764 829 765 830 double convPoly = sumC * polyValues->data.F64[jyOrder][jxOrder]; // Value … … 774 839 // Background only terms 775 840 double sum1 = 0.0; // Sum of the weighting 776 double sum I = 0.0; // Sum of the input841 double sumT = 0.0; // Sum of the target 777 842 for (int y = - footprint; y <= footprint; y++) { 778 843 for (int x = - footprint; x <= footprint; x++) { 779 844 double invNoise2 = 1.0 / weight->kernel[y][x]; // Inverse noise, squared 780 845 sum1 += invNoise2; 781 sum I += input->kernel[y][x] * invNoise2;846 sumT += target->kernel[y][x] * invNoise2; 782 847 } 783 848 } … … 785 850 psStringAppend(&badString, "\nBad sum1 detected"); 786 851 bad = true; 787 } else if (!isfinite(sum I)) {852 } else if (!isfinite(sumT)) { 788 853 psStringAppend(&badString, "\nBad sumI detected"); 789 854 bad = true; … … 791 856 792 857 stampMatrix->data.F64[bgIndex][bgIndex] = sum1; 793 stampVector->data.F64[bgIndex] = sum I;858 stampVector->data.F64[bgIndex] = sumT; 794 859 795 860 if (bad) { … … 890 955 } 891 956 892 893 int pmSubtractionRejectStamps(pmSubtractionStampList *stamps, psImage *subMask, const psVector *solution, 894 int footprint, float sigmaRej, const pmSubtractionKernels *kernels) 957 psVector *pmSubtractionCalculateDeviations(pmSubtractionStampList *stamps, const psVector *solution, 958 int footprint, const pmSubtractionKernels *kernels, 959 pmSubtractionMode mode) 960 { 961 PM_ASSERT_SUBTRACTION_STAMP_LIST_NON_NULL(stamps, NULL); 962 PS_ASSERT_VECTOR_NON_NULL(solution, NULL); 963 PS_ASSERT_VECTOR_TYPE(solution, PS_TYPE_F64, NULL); 964 PS_ASSERT_PTR_NON_NULL(kernels, NULL); 965 PS_ASSERT_VECTOR_SIZE(solution, kernels->num * polyTerms(kernels->spatialOrder) + 966 polyTerms(kernels->bgOrder), NULL); 967 PS_ASSERT_VECTOR_SIZE(kernels->u, kernels->num, NULL); 968 PS_ASSERT_VECTORS_SIZE_EQUAL(kernels->u, kernels->v, NULL); 969 970 psVector *deviations = psVectorAlloc(stamps->num, PS_TYPE_F32); // Mean deviation for stamps 971 double devNorm = 1.0 / PS_SQR(2 * footprint + 1); // Normalisation for deviations 972 int numKernels = kernels->num; // Number of kernels 973 int spatialOrder = kernels->spatialOrder; // Order of kernel spatial variations 974 float background = solution->data.F64[solution->n-1]; // The difference in background 975 976 psVector *coeff = psVectorAlloc(numKernels, PS_TYPE_F64); // Coefficients for the kernel basis functions 977 978 for (int i = 0; i < stamps->num; i++) { 979 pmSubtractionStamp *stamp = stamps->stamps->data[i]; // The stamp of interest 980 if (stamp->status != PM_SUBTRACTION_STAMP_USED) { 981 deviations->data.F32[i] = NAN; 982 continue; 983 } 984 985 // Calculate coefficients of the kernel basis functions 986 psImage *polyValues = spatialPolyValues(kernels->spatialOrder, 987 stamp->xNorm, stamp->yNorm); // Polynomial terms 988 for (int j = 0; j < numKernels; j++) { 989 double polynomial = 0.0; // Value of the polynomial 990 for (int yOrder = 0, index = j; yOrder <= spatialOrder; yOrder++) { 991 for (int xOrder = 0; xOrder <= spatialOrder - yOrder; xOrder++, index += numKernels) { 992 polynomial += solution->data.F64[index] * polyValues->data.F64[yOrder][xOrder]; 993 } 994 } 995 coeff->data.F64[j] = polynomial; 996 } 997 psFree(polyValues); 998 999 // Calculate residuals 1000 psKernel *weight = stamp->weight; // Weight postage stamp 1001 psKernel *target; // Target postage stamp 1002 psArray *convolutions; // Convolution postage stamps for each kernel basis function 1003 switch (mode) { 1004 case PM_SUBTRACTION_MODE_TARGET: 1005 case PM_SUBTRACTION_MODE_1: 1006 target = stamp->image2; 1007 convolutions = stamp->convolutions1; 1008 break; 1009 case PM_SUBTRACTION_MODE_2: 1010 target = stamp->image1; 1011 convolutions = stamp->convolutions2; 1012 break; 1013 default: 1014 psAbort("Unsupported subtraction mode: %x", mode); 1015 } 1016 1017 #ifdef TESTING 1018 psKernel *residual = psKernelAlloc(-footprint, footprint, -footprint, footprint); 1019 #endif 1020 float deviation = 0.0; // Deviation for this stamp 1021 for (int y = - footprint; y <= footprint; y++) { 1022 for (int x = - footprint; x <= footprint; x++) { 1023 float conv = background; // The value of the convolution 1024 for (int j = 0; j < numKernels; j++) { 1025 psKernel *convolution = convolutions->data[j]; // Convolution 1026 conv += convolution->kernel[y][x] * coeff->data.F64[j]; 1027 } 1028 float diff = target->kernel[y][x] - conv; 1029 deviation += PS_SQR(diff) / weight->kernel[y][x]; 1030 #ifdef TESTING 1031 residual->kernel[y][x] = diff; 1032 #endif 1033 } 1034 } 1035 1036 deviations->data.F32[i] = sqrtf(devNorm * deviation); 1037 psTrace("psModules.imcombine", 5, "Deviation for stamp %d (%d,%d): %f\n", 1038 i, (int)(stamp->x + 0.5), (int)(stamp->y + 0.5), deviations->data.F32[i]); 1039 if (!isfinite(deviations->data.F32[i])) { 1040 stamp->status = PM_SUBTRACTION_STAMP_REJECTED; 1041 psTrace("psModules.imcombine", 5, 1042 "Rejecting stamp %d (%d,%d) because of non-finite deviation\n", 1043 i, (int)(stamp->x + 0.5), (int)(stamp->y + 0.5)); 1044 continue; 1045 } 1046 1047 #ifdef TESTING 1048 { 1049 psString filename = NULL; 1050 psStringAppend(&filename, "resid_%03d.fits", i); 1051 psFits *fits = psFitsOpen(filename, "w"); 1052 psFree(filename); 1053 psFitsWriteImage(fits, NULL, residual->image, 0, NULL); 1054 psFitsClose(fits); 1055 } 1056 psFree(residual); 1057 #endif 1058 1059 } 1060 psFree(coeff); 1061 1062 return deviations; 1063 } 1064 1065 1066 int pmSubtractionRejectStamps(pmSubtractionStampList *stamps, const psVector *deviations, 1067 psImage *subMask, float sigmaRej, int footprint) 895 1068 { 896 1069 PM_ASSERT_SUBTRACTION_STAMP_LIST_NON_NULL(stamps, -1); 1070 PS_ASSERT_VECTOR_NON_NULL(deviations, -1); 1071 PS_ASSERT_VECTOR_TYPE(deviations, PS_TYPE_F32, -1); 897 1072 PS_ASSERT_IMAGE_NON_EMPTY(subMask, -1); 898 1073 PS_ASSERT_IMAGE_TYPE(subMask, PS_TYPE_MASK, -1); 899 PS_ASSERT_VECTOR_NON_NULL(solution, -1); 900 PS_ASSERT_VECTOR_TYPE(solution, PS_TYPE_F64, -1); 901 PS_ASSERT_PTR_NON_NULL(kernels, -1); 902 PS_ASSERT_VECTOR_SIZE(solution, kernels->num * polyTerms(kernels->spatialOrder) + 903 polyTerms(kernels->bgOrder), -1); 904 PS_ASSERT_VECTOR_SIZE(kernels->u, kernels->num, -1); 905 PS_ASSERT_VECTORS_SIZE_EQUAL(kernels->u, kernels->v, -1); 906 907 // Measure deviations 908 psVector *deviations = psVectorAlloc(stamps->num, PS_TYPE_F32); // Mean deviation for stamps 1074 909 1075 double totalSquareDev = 0.0; // Total square deviation from zero 910 1076 int numStamps = 0; // Number of used stamps 911 int numKernels = kernels->num; // Number of kernels 912 int spatialOrder = kernels->spatialOrder; // Order of kernel spatial variations 913 double devNorm = 1.0 / PS_SQR(2 * footprint + 1); // Normalisation for deviations 914 { 915 float background = solution->data.F64[solution->n-1]; // The difference in background 916 917 for (int i = 0; i < stamps->num; i++) { 918 pmSubtractionStamp *stamp = stamps->stamps->data[i]; // The stamp of interest 919 if (stamp->status != PM_SUBTRACTION_STAMP_USED) { 920 continue; 921 } 922 923 psImage *polyValues = spatialPolyValues(kernels->spatialOrder, stamp->xNorm, 924 stamp->yNorm); // Polynomial terms 925 926 psKernel *input = stamp->input; // Input postage stamp 927 psKernel *weight = stamp->weight; // Weight postage stamp 928 psArray *convolutions = stamp->convolutions; // Convolutions of reference image for each kernel 929 #ifdef TESTING 930 psKernel *residual = psKernelAlloc(-footprint, footprint, -footprint, footprint); 931 #endif 932 float deviation = 0.0; // Deviation for this stamp 933 for (int y = - footprint; y <= footprint; y++) { 934 for (int x = - footprint; x <= footprint; x++) { 935 float conv = background; // The value of the convolution 936 for (int j = 0; j < numKernels; j++) { 937 psKernel *convolution = convolutions->data[j]; // Convolution of reference 938 939 // XXX Precalculate these values, so that we're not calculating the same thing for 940 // every pixel. 941 double polynomial = 0.0; // Value of the polynomial 942 for (int yOrder = 0, index = j; yOrder <= spatialOrder; yOrder++) { 943 for (int xOrder = 0; xOrder <= spatialOrder - yOrder; 944 xOrder++, index += numKernels) { 945 polynomial += solution->data.F64[index] * 946 polyValues->data.F64[yOrder][xOrder]; 947 } 948 } 949 conv += convolution->kernel[y][x] * polynomial; 950 } 951 float diff = input->kernel[y][x] - conv; 952 deviation += PS_SQR(diff) / weight->kernel[y][x]; 953 #ifdef TESTING 954 residual->kernel[y][x] = diff; 955 #endif 956 } 957 } 958 psFree(polyValues); 959 960 deviations->data.F32[i] = devNorm * deviation; 961 if (!isfinite(deviations->data.F32[i])) { 962 stamp->status = PM_SUBTRACTION_STAMP_REJECTED; 963 psTrace("psModules.imcombine", 5, 964 "Rejecting stamp %d (%d,%d) because of non-finite deviation\n", 965 i, (int)(stamp->x + 0.5), (int)(stamp->y + 0.5)); 966 continue; 967 } 968 psTrace("psModules.imcombine", 5, "Deviation for stamp %d (%d,%d): %f\n", 969 i, (int)(stamp->x + 0.5), (int)(stamp->y + 0.5), deviations->data.F32[i]); 970 totalSquareDev += PS_SQR(deviations->data.F32[i]); 971 numStamps++; 972 973 #ifdef TESTING 974 { 975 psString filename = NULL; 976 psStringAppend(&filename, "resid_%03d.fits", i); 977 psFits *fits = psFitsOpen(filename, "w"); 978 psFree(filename); 979 psFitsWriteImage(fits, NULL, residual->image, 0, NULL); 980 psFitsClose(fits); 981 } 982 psFree(residual); 983 #endif 984 985 } 1077 for (int i = 0; i < stamps->num; i++) { 1078 pmSubtractionStamp *stamp = stamps->stamps->data[i]; // Stamp of interest 1079 if (stamp->status != PM_SUBTRACTION_STAMP_USED) { 1080 continue; 1081 } 1082 totalSquareDev += PS_SQR(deviations->data.F32[i]); 1083 numStamps++; 986 1084 } 987 1085 988 1086 if (numStamps == 0) { 989 1087 psError(PS_ERR_UNKNOWN, true, "No good stamps found."); 990 psFree(deviations);991 1088 return -1; 992 1089 } 993 1090 994 1091 if (!isfinite(sigmaRej) || sigmaRej <= 0.0) { 1092 // User just wanted to calculate and record the RMS for posterity 995 1093 psLogMsg("psModules.imcombine", PS_LOG_INFO, "RMS deviation: %f", sqrt(totalSquareDev / numStamps)); 996 psFree(deviations);997 1094 return 0; 998 1095 } 1096 1097 float limit = sigmaRej * sqrt(totalSquareDev / (double)numStamps); // Limit on maximum deviation 1098 psTrace("psModules.imcombine", 1, "Deviation limit: %f\n", limit); 999 1099 1000 1100 int numRejected = 0; // Number of stamps rejected 1001 1101 int numGood = 0; // Number of good stamps 1002 1102 double newSquareDev = 0.0; // New square deviation 1003 1004 float limit = sigmaRej * sqrt(totalSquareDev / numStamps); // Limit on maximum deviation1005 psTrace("psModules.imcombine", 1, "Deviation limit: %f\n", limit);1006 1007 1103 for (int i = 0; i < stamps->num; i++) { 1008 1104 pmSubtractionStamp *stamp = stamps->stamps->data[i]; // Stamp of interest … … 1024 1120 stamp->status = PM_SUBTRACTION_STAMP_REJECTED; 1025 1121 // Recalculate convolutions 1026 psFree(stamp->convolutions); 1027 stamp->convolutions = NULL; 1122 psFree(stamp->convolutions1); 1123 psFree(stamp->convolutions2); 1124 stamp->convolutions1 = stamp->convolutions2 = NULL; 1125 psFree(stamp->image1); 1126 psFree(stamp->image2); 1127 psFree(stamp->weight); 1128 stamp->image1 = stamp->image2 = stamp->weight = NULL; 1028 1129 } else { 1029 1130 numGood++; … … 1033 1134 } 1034 1135 1035 psLogMsg("psModules.imcombine", PS_LOG_INFO, "%d good stamps; %d rejected.\nRMS deviation: %f --> %f\n", 1036 numGood, numRejected, sqrt(totalSquareDev / numStamps), sqrt(newSquareDev / numGood)); 1037 1038 psFree(deviations); 1136 if (numRejected > 0) { 1137 psLogMsg("psModules.imcombine", PS_LOG_INFO, 1138 "%d good stamps; %d rejected.\nRMS deviation: %f --> %f\n", 1139 numGood, numRejected, sqrt(totalSquareDev / numStamps), 1140 sqrt(newSquareDev / (double)numGood)); 1141 } else { 1142 psLogMsg("psModules.imcombine", PS_LOG_INFO, 1143 "%d good stamps; 0 rejected.\nRMS deviation: %f\n", 1144 numGood, sqrt(totalSquareDev / numStamps)); 1145 } 1039 1146 1040 1147 return numRejected; … … 1096 1203 } 1097 1204 1098 bool pmSubtractionConvolve(psImage **outImage, psImage **outWeight, psImage **outMask, 1099 const psImage *inImage, const psImage *inWeight, const psImage *subMask, 1100 psMaskType blank, const psRegion *region, const psVector *solution, 1101 const pmSubtractionKernels *kernels, bool useFFT) 1102 { 1103 PS_ASSERT_IMAGE_NON_NULL(inImage, false); 1104 PS_ASSERT_IMAGE_TYPE(inImage, PS_TYPE_F32, false); 1205 bool pmSubtractionConvolve(pmReadout *out, const pmReadout *ro1, const pmReadout *ro2, 1206 const psImage *subMask, psMaskType blank, const psRegion *region, 1207 const psVector *solution, const pmSubtractionKernels *kernels, 1208 pmSubtractionMode mode, bool useFFT) 1209 { 1210 PS_ASSERT_PTR_NON_NULL(out, false); 1211 PS_ASSERT_PTR_NON_NULL(ro1, false); 1212 PS_ASSERT_IMAGE_NON_NULL(ro1->image, false); 1213 PS_ASSERT_IMAGE_TYPE(ro1->image, PS_TYPE_F32, false); 1214 if (ro1->weight) { 1215 PS_ASSERT_IMAGE_NON_NULL(ro1->weight, false); 1216 PS_ASSERT_IMAGE_TYPE(ro1->weight, PS_TYPE_F32, false); 1217 PS_ASSERT_IMAGES_SIZE_EQUAL(ro1->weight, ro1->image, false); 1218 } 1219 PS_ASSERT_PTR_NON_NULL(ro2, false); 1220 PS_ASSERT_IMAGE_NON_NULL(ro2->image, false); 1221 PS_ASSERT_IMAGE_TYPE(ro2->image, PS_TYPE_F32, false); 1222 if (ro2->weight) { 1223 PS_ASSERT_IMAGE_NON_NULL(ro2->weight, false); 1224 PS_ASSERT_IMAGE_TYPE(ro2->weight, PS_TYPE_F32, false); 1225 PS_ASSERT_IMAGES_SIZE_EQUAL(ro2->weight, ro1->image, false); 1226 } 1105 1227 if (subMask) { 1106 1228 PS_ASSERT_IMAGE_NON_NULL(subMask, false); 1107 1229 PS_ASSERT_IMAGE_TYPE(subMask, PS_TYPE_MASK, false); 1108 PS_ASSERT_IMAGES_SIZE_EQUAL(subMask, inImage, false); 1109 } 1110 if (inWeight) { 1111 PS_ASSERT_IMAGE_NON_NULL(inWeight, false); 1112 PS_ASSERT_IMAGE_TYPE(inWeight, PS_TYPE_F32, false); 1113 PS_ASSERT_IMAGES_SIZE_EQUAL(inWeight, inImage, false); 1114 } 1115 PS_ASSERT_PTR_NON_NULL(outImage, false); 1116 if (*outImage) { 1117 PS_ASSERT_IMAGE_NON_NULL(*outImage, false); 1118 PS_ASSERT_IMAGES_SIZE_EQUAL(*outImage, inImage, false); 1119 PS_ASSERT_IMAGE_TYPE(*outImage, PS_TYPE_F32, false); 1120 } 1121 if (outMask && *outMask) { 1122 PS_ASSERT_IMAGE_NON_NULL(*outMask, false); 1123 PS_ASSERT_IMAGES_SIZE_EQUAL(*outMask, inImage, false); 1124 PS_ASSERT_IMAGE_TYPE(*outMask, PS_TYPE_MASK, false); 1230 PS_ASSERT_IMAGES_SIZE_EQUAL(subMask, ro1->image, false); 1231 } 1232 if (out->image) { 1233 PS_ASSERT_IMAGE_NON_NULL(out->image, false); 1234 PS_ASSERT_IMAGES_SIZE_EQUAL(out->image, ro1->image, false); 1235 PS_ASSERT_IMAGE_TYPE(out->image, PS_TYPE_F32, false); 1236 } 1237 if (out->mask) { 1238 PS_ASSERT_IMAGE_NON_NULL(out->mask, false); 1239 PS_ASSERT_IMAGES_SIZE_EQUAL(out->mask, ro1->image, false); 1240 PS_ASSERT_IMAGE_TYPE(out->mask, PS_TYPE_MASK, false); 1125 1241 PS_ASSERT_IMAGE_NON_NULL(subMask, false); 1126 1242 } 1127 if (outWeight && *outWeight) { 1128 PS_ASSERT_IMAGE_NON_NULL(*outWeight, false); 1129 PS_ASSERT_IMAGES_SIZE_EQUAL(*outWeight, inImage, false); 1130 PS_ASSERT_IMAGE_TYPE(*outWeight, PS_TYPE_F32, false); 1131 PS_ASSERT_IMAGE_NON_NULL(inWeight, false); 1243 if (out->weight) { 1244 PS_ASSERT_IMAGE_NON_NULL(out->weight, false); 1245 PS_ASSERT_IMAGES_SIZE_EQUAL(out->weight, ro1->image, false); 1246 PS_ASSERT_IMAGE_TYPE(out->weight, PS_TYPE_F32, false); 1132 1247 } 1133 1248 PS_ASSERT_VECTOR_NON_NULL(solution, false); … … 1145 1260 return false; 1146 1261 } 1147 if (region->x0 < 0 || region->x1 > inImage->numCols ||1148 region->y0 < 0 || region->y1 > inImage->numRows) {1262 if (region->x0 < 0 || region->x1 > ro1->image->numCols || 1263 region->y0 < 0 || region->y1 > ro1->image->numRows) { 1149 1264 psString string = psRegionToString(*region); 1150 1265 psError(PS_ERR_BAD_PARAMETER_VALUE, true, "Input region (%s) does not fit in image (%dx%d)", 1151 string, inImage->numCols, inImage->numRows);1266 string, ro1->image->numCols, ro1->image->numRows); 1152 1267 psFree(string); 1153 1268 return false; … … 1155 1270 } 1156 1271 1272 psImage *image, *weight; // Image and weight map to convolve 1273 switch (mode) { 1274 case PM_SUBTRACTION_MODE_TARGET: 1275 case PM_SUBTRACTION_MODE_1: 1276 image = ro1->image; 1277 weight = ro1->weight; 1278 break; 1279 case PM_SUBTRACTION_MODE_2: 1280 image = ro2->image; 1281 weight = ro2->image; 1282 break; 1283 default: 1284 psAbort("Unsupported subtraction mode: %x", mode); 1285 } 1286 1157 1287 int numBackground = polyTerms(kernels->bgOrder); // Number of background terms 1158 1288 float background = solution->data.F64[solution->n - numBackground]; // The difference in background 1159 int numCols = inImage->numCols, numRows = inImage->numRows; // Image dimensions1160 1161 psImage *convImage = *outImage;// Convolved image1289 int numCols = ro1->image->numCols, numRows = ro1->image->numRows; // Image dimensions 1290 1291 psImage *convImage = out->image; // Convolved image 1162 1292 if (!convImage) { 1163 *outImage = psImageAlloc(numCols, numRows, PS_TYPE_F32);1164 convImage = *outImage;1293 out->image = psImageAlloc(numCols, numRows, PS_TYPE_F32); 1294 convImage = out->image; 1165 1295 } 1166 1296 psImage *convMask = NULL; // Convolved mask image 1167 if ( outMask &&subMask) {1168 if (! *outMask) {1169 *outMask = psImageAlloc(numCols, numRows, PS_TYPE_MASK);1170 } 1171 convMask = *outMask;1297 if (subMask) { 1298 if (!out->mask) { 1299 out->mask = psImageAlloc(numCols, numRows, PS_TYPE_MASK); 1300 } 1301 convMask = out->mask; 1172 1302 psImageInit(convMask, 0); 1173 1303 } 1174 1304 psImage *convWeight = NULL; // Convolved weight (variance) image 1175 if ( outWeight && inWeight) {1176 if (! *outWeight) {1177 *outWeight = psImageAlloc(numCols, numRows, PS_TYPE_F32);1178 } 1179 convWeight = *outWeight;1305 if (weight) { 1306 if (!out->weight) { 1307 out->weight = psImageAlloc(numCols, numRows, PS_TYPE_F32); 1308 } 1309 convWeight = out->weight; 1180 1310 psImageInit(convWeight, 0.0); 1181 1311 } … … 1198 1328 } 1199 1329 1330 psMaskType maskSource, maskTarget; // Mask values for source and target 1331 switch (mode) { 1332 case PM_SUBTRACTION_MODE_TARGET: 1333 case PM_SUBTRACTION_MODE_1: 1334 maskSource = PM_SUBTRACTION_MASK_BAD_1; 1335 maskTarget = PM_SUBTRACTION_MASK_BAD_2 | PM_SUBTRACTION_MASK_CONVOLVE_1; 1336 break; 1337 case PM_SUBTRACTION_MODE_2: 1338 maskSource = PM_SUBTRACTION_MASK_BAD_2; 1339 maskTarget = PM_SUBTRACTION_MASK_BAD_1 | PM_SUBTRACTION_MASK_CONVOLVE_2; 1340 break; 1341 default: 1342 psAbort("Unsupported subtraction mode: %x", mode); 1343 } 1344 1200 1345 for (int j = yMin; j < yMax; j += fullSize) { 1201 1346 int ySubMax = PS_MIN(j + fullSize, yMax); // Range for subregion of interest … … 1211 1356 1212 1357 kernelImage = solvedKernel(kernelImage, solution, kernels, polyValues); 1213 if ( inWeight) {1214 kernelWeight = varianceKernel(kernel Image);1215 } 1216 1217 1358 if (weight) { 1359 kernelWeight = varianceKernel(kernelWeight, kernelImage); 1360 } 1361 1362 psRegion subRegion = psRegionSet(i, xSubMax, j, ySubMax); // Sub-region to convolve 1218 1363 if (useFFT) { 1219 1364 // Use Fast Fourier Transform to do the convolution 1220 1365 // This provides a big speed-up for large kernels 1221 convolveFFT(convImage, i nImage, subMask, kernelImage, psRegionSet(i, xSubMax, j, ySubMax),1366 convolveFFT(convImage, image, subMask, maskSource, kernelImage, subRegion, 1222 1367 background, size); 1223 if ( inWeight) {1224 convolveFFT(convWeight, inWeight, subMask, kernelWeight,1225 psRegionSet(i, xSubMax, j, ySubMax),0.0, size);1368 if (weight) { 1369 convolveFFT(convWeight, weight, subMask, maskSource, kernelWeight, subRegion, 1370 0.0, size); 1226 1371 } 1227 1372 } else { 1228 convolveDirect(convImage, inImage, kernelImage, psRegionSet(i, xSubMax, j, ySubMax), 1229 background, size); 1230 if (inWeight) { 1231 convolveDirect(convWeight, inWeight, kernelWeight, psRegionSet(i, xSubMax, j, ySubMax), 1232 0.0, size); 1373 convolveDirect(convImage, image, kernelImage, subRegion, background, size); 1374 if (weight) { 1375 convolveDirect(convWeight, weight, kernelWeight, subRegion, 0.0, size); 1233 1376 } 1234 1377 } 1235 1378 1236 1379 // Propagate the mask 1237 for (int y = j; y < ySubMax; y++) { 1238 for (int x = i; x < xSubMax; x++) { 1239 if (subMask && (subMask->data.PS_TYPE_MASK_DATA[y][x] & 1240 (PM_SUBTRACTION_MASK_INPUT | PM_SUBTRACTION_MASK_CONVOLVE))) { 1241 convMask->data.PS_TYPE_MASK_DATA[y][x] |= blank; 1242 convImage->data.F32[y][x] = NAN; 1243 if (inWeight) { 1244 convWeight->data.F32[y][x] = NAN; 1380 if (subMask) { 1381 for (int y = j; y < ySubMax; y++) { 1382 for (int x = i; x < xSubMax; x++) { 1383 if (subMask->data.PS_TYPE_MASK_DATA[y][x] & maskTarget) { 1384 convMask->data.PS_TYPE_MASK_DATA[y][x] |= blank; 1385 convImage->data.F32[y][x] = NAN; 1386 if (weight) { 1387 convWeight->data.F32[y][x] = NAN; 1388 } 1245 1389 } 1246 1390 } -
trunk/psModules/src/imcombine/pmSubtraction.h
r15325 r15443 6 6 * @author GLG, MHPCC 7 7 * 8 * @version $Revision: 1. 19$ $Name: not supported by cvs2svn $9 * @date $Date: 2007-1 0-17 02:45:40$8 * @version $Revision: 1.20 $ $Name: not supported by cvs2svn $ 9 * @date $Date: 2007-11-03 02:28:24 $ 10 10 * 11 11 * Copyright 2004-207 Institute for Astronomy, University of Hawaii … … 16 16 17 17 #include <pslib.h> 18 #include "pmSubtractionKernels.h" 19 #include "pmSubtractionStamps.h" 18 19 #include <pmHDU.h> 20 #include <pmFPA.h> 21 #include <pmSubtractionKernels.h> 22 #include <pmSubtractionStamps.h> 20 23 21 24 /// @addtogroup imcombine Image Combinations 22 25 /// @{ 23 26 27 /// Mask values for the subtraction mask 24 28 typedef enum { 25 PM_SUBTRACTION_MASK_CLEAR = 0x00, // No masking 26 PM_SUBTRACTION_MASK_REF = 0x01, // Reference image is bad 27 PM_SUBTRACTION_MASK_INPUT = 0x02, // Input image is bad 28 PM_SUBTRACTION_MASK_CONVOLVE = 0x04, // If convolved, would be bad 29 PM_SUBTRACTION_MASK_FOOTPRINT = 0x08, // Bad pixel within the stamp footprint 30 PM_SUBTRACTION_MASK_BORDER = 0x10, // Image border 31 PM_SUBTRACTION_MASK_REJ = 0x20, // Previously tried as a stamp, and rejected 29 PM_SUBTRACTION_MASK_CLEAR = 0x00, // No masking 30 PM_SUBTRACTION_MASK_BAD_1 = 0x01, // Image 1 is bad 31 PM_SUBTRACTION_MASK_BAD_2 = 0x02, // Image 2 is bad 32 PM_SUBTRACTION_MASK_CONVOLVE_1 = 0x04, // If image 1 is convolved, would be bad 33 PM_SUBTRACTION_MASK_CONVOLVE_2 = 0x08, // If image 2 is convolved, would be bad 34 PM_SUBTRACTION_MASK_FOOTPRINT_1 = 0x10, // Bad pixel within the stamp footprint of image 1 35 PM_SUBTRACTION_MASK_FOOTPRINT_2 = 0x20, // Bad pixel within the stamp footprint of image 2 36 PM_SUBTRACTION_MASK_BORDER = 0x40, // Image border 37 PM_SUBTRACTION_MASK_REJ = 0x80, // Previously tried as a stamp, and rejected 32 38 } pmSubtractionMasks; 33 39 … … 45 51 bool pmSubtractionConvolveStamp(pmSubtractionStamp *stamp, ///< Stamp to convolve 46 52 const pmSubtractionKernels *kernels, ///< Kernel parameters 47 int footprint ///< Half-size of region over which to calculate equation 53 int footprint, ///< Half-size of region over which to calculate equation 54 pmSubtractionMode mode ///< Mode for subtraction (which to convolve) 48 55 ); 49 56 … … 51 58 bool pmSubtractionCalculateEquation(pmSubtractionStampList *stamps, ///< Stamps 52 59 const pmSubtractionKernels *kernels, ///< Kernel parameters 53 int footprint ///< Half-size of region over which to calculate equation 60 int footprint, ///< Half-size of region over which to calculate equation 61 pmSubtractionMode mode ///< Mode for subtraction (which to convolve) 54 62 ); 55 63 … … 59 67 ); 60 68 69 /// Calculate deviations 70 psVector *pmSubtractionCalculateDeviations(pmSubtractionStampList *stamps, ///< Stamps 71 const psVector *solution, ///< Solution vector 72 int footprint, ///< Half-size of stamp 73 const pmSubtractionKernels *kernels, ///< Kernel parameters 74 pmSubtractionMode mode ///< Mode for subtraction 75 ); 76 61 77 /// Reject stamps 62 78 int pmSubtractionRejectStamps(pmSubtractionStampList *stamps, ///< Stamps 79 const psVector *deviations, ///< Deviations for each stamp 63 80 psImage *subMask, ///< Subtraction mask 64 const psVector *solution, ///< Solution vector65 int footprint, ///< Region to mask if stamp is bad66 81 float sigmaRej, ///< Number of RMS deviations above zero at which to reject 67 const pmSubtractionKernels *kernels ///< Kernel parameters82 int footprint ///< Half-size of stamp 68 83 ); 69 84 … … 81 96 82 97 /// Convolve image in preparation for subtraction 83 bool pmSubtractionConvolve(psImage **outImage, ///< Output image 84 psImage **outWeight, ///< Output weight map (or NULL) 85 psImage **outMask, ///< Output mask (or NULL) 86 const psImage *inImage, ///< Input image 87 const psImage *inWeight, ///< Input weight map (or NULL) 98 bool pmSubtractionConvolve(pmReadout *out, ///< Output image 99 const pmReadout *ro1, // Input image 1 100 const pmReadout *ro2, // Input image 2 88 101 const psImage *subMask, ///< Subtraction mask (or NULL) 89 102 psMaskType blank, ///< Mask value for blank regions … … 91 104 const psVector *solution, ///< The solution vector 92 105 const pmSubtractionKernels *kernels, ///< Kernel parameters 106 pmSubtractionMode mode, ///< Mode for subtraction 93 107 bool useFFT ///< Use Fast Fourier Transform for the convolution? 94 108 ); -
trunk/psModules/src/imcombine/pmSubtractionKernels.h
r14671 r15443 14 14 PM_SUBTRACTION_KERNEL_RINGS, ///< Rings Instead of the Normal Gaussian Subtraction 15 15 } pmSubtractionKernelsType; 16 17 /// Modes --- specifies which image to convolve 18 typedef enum { 19 PM_SUBTRACTION_MODE_ERR, // Error in the mode 20 PM_SUBTRACTION_MODE_TARGET, // Convolve image 1 to match target PSF 21 PM_SUBTRACTION_MODE_1, // Convolve image 1 22 PM_SUBTRACTION_MODE_2, // Convolve image 2 23 PM_SUBTRACTION_MODE_UNSURE, // Not sure yet which image to convolve so try to satisfy both 24 PM_SUBTRACTION_MODE_DUAL, // Dual convolution 25 } pmSubtractionMode; 16 26 17 27 /// Kernels specification -
trunk/psModules/src/imcombine/pmSubtractionMatch.c
r15329 r15443 50 50 51 51 static bool getStamps(pmSubtractionStampList **stamps, // Stamps to read 52 const pmReadout *r eference, // Reference readout53 const pmReadout * input, // Input readout, or NULL to generate fake stamps52 const pmReadout *ro1, // Readout 1 53 const pmReadout *ro2, // Readout 2 54 54 const psImage *subMask, // Mask for subtraction, or NULL 55 55 psImage *weight, // Weight map … … 57 57 float threshold, // Threshold for stamp finding 58 58 float stampSpacing, // Spacing between stamps 59 float targetWidth,// Target width for fake stamps60 59 int size, // Kernel half-size 61 int footprint // Convolution footprint for stamps 60 int footprint, // Convolution footprint for stamps 61 pmSubtractionMode mode // Mode for subtraction 62 62 ) 63 63 { 64 64 psTrace("psModules.imcombine", 3, "Finding stamps...\n"); 65 *stamps = pmSubtractionStampsFind(*stamps, r eference->image, subMask, region, threshold, stampSpacing);65 *stamps = pmSubtractionStampsFind(*stamps, ro1->image, subMask, region, threshold, stampSpacing, mode); 66 66 if (!*stamps) { 67 67 psError(PS_ERR_UNKNOWN, false, "Unable to find stamps."); … … 71 71 memCheck(" find stamps"); 72 72 73 if (!input && !pmSubtractionStampsGenerate(*stamps, targetWidth, footprint, size)) {74 psError(PS_ERR_UNKNOWN, false, "Unable to generate target stamps.");75 return false;76 }77 78 memCheck(" generate stamps");79 80 73 psTrace("psModules.imcombine", 3, "Extracting stamps...\n"); 81 if (!pmSubtractionStampsExtract(*stamps, reference->image, input ? input->image : NULL, 82 weight, footprint, size)) { 74 if (!pmSubtractionStampsExtract(*stamps, ro1->image, ro2 ? ro2->image : NULL, weight, footprint, size)) { 83 75 psError(PS_ERR_UNKNOWN, false, "Unable to extract stamps."); 84 76 return false; … … 94 86 95 87 96 bool pmSubtractionMatch(pmReadout *convolved, const pmReadout *r eference, const pmReadout *input,88 bool pmSubtractionMatch(pmReadout *convolved, const pmReadout *ro1, const pmReadout *ro2, 97 89 int footprint, float regionSize, float stampSpacing, float threshold, 98 const psArray *sources, const char *stampsName, float targetWidth,90 const psArray *sources, const char *stampsName, 99 91 pmSubtractionKernelsType type, int size, int spatialOrder, 100 92 const psVector *isisWidths, const psVector *isisOrders, 101 93 int inner, int ringsOrder, int binning, bool optimum, const psVector *optFWHMs, 102 94 int optOrder, float optThreshold, int iter, float rej, psMaskType maskBad, 103 psMaskType maskBlank, float badFrac )95 psMaskType maskBlank, float badFrac, pmSubtractionMode mode) 104 96 { 105 97 PS_ASSERT_PTR_NON_NULL(convolved, false); 106 PS_ASSERT_PTR_NON_NULL(r eference, false);107 PS_ASSERT_IMAGE_NON_NULL(r eference->image, false);108 PS_ASSERT_IMAGE_TYPE(r eference->image, PS_TYPE_F32, false);109 if (r eference->mask) {110 PS_ASSERT_IMAGE_NON_NULL(r eference->mask, false);111 PS_ASSERT_IMAGE_TYPE(r eference->mask, PS_TYPE_MASK, false);112 PS_ASSERT_IMAGES_SIZE_EQUAL(r eference->mask, reference->image, false);113 } 114 if (r eference->weight) {115 PS_ASSERT_IMAGE_NON_NULL(r eference->weight, false);116 PS_ASSERT_IMAGE_TYPE(r eference->weight, PS_TYPE_F32, false);117 PS_ASSERT_IMAGES_SIZE_EQUAL(r eference->weight, reference->image, false);118 } 119 if ( input) {120 PS_ASSERT_IMAGE_NON_NULL( input->image, false);121 PS_ASSERT_IMAGE_TYPE( input->image, PS_TYPE_F32, false);122 PS_ASSERT_IMAGES_SIZE_EQUAL( input->image, reference->image, false);123 if ( input->mask) {124 PS_ASSERT_IMAGE_NON_NULL( input->mask, false);125 PS_ASSERT_IMAGE_TYPE( input->mask, PS_TYPE_MASK, false);126 PS_ASSERT_IMAGES_SIZE_EQUAL( input->mask, reference->image, false);127 } 128 if ( input->weight) {129 PS_ASSERT_IMAGE_NON_NULL( input->weight, false);130 PS_ASSERT_IMAGE_TYPE( input->weight, PS_TYPE_F32, false);131 PS_ASSERT_IMAGES_SIZE_EQUAL( input->weight, reference->image, false);98 PS_ASSERT_PTR_NON_NULL(ro1, false); 99 PS_ASSERT_IMAGE_NON_NULL(ro1->image, false); 100 PS_ASSERT_IMAGE_TYPE(ro1->image, PS_TYPE_F32, false); 101 if (ro1->mask) { 102 PS_ASSERT_IMAGE_NON_NULL(ro1->mask, false); 103 PS_ASSERT_IMAGE_TYPE(ro1->mask, PS_TYPE_MASK, false); 104 PS_ASSERT_IMAGES_SIZE_EQUAL(ro1->mask, ro1->image, false); 105 } 106 if (ro1->weight) { 107 PS_ASSERT_IMAGE_NON_NULL(ro1->weight, false); 108 PS_ASSERT_IMAGE_TYPE(ro1->weight, PS_TYPE_F32, false); 109 PS_ASSERT_IMAGES_SIZE_EQUAL(ro1->weight, ro1->image, false); 110 } 111 if (ro2) { 112 PS_ASSERT_IMAGE_NON_NULL(ro2->image, false); 113 PS_ASSERT_IMAGE_TYPE(ro2->image, PS_TYPE_F32, false); 114 PS_ASSERT_IMAGES_SIZE_EQUAL(ro2->image, ro1->image, false); 115 if (ro2->mask) { 116 PS_ASSERT_IMAGE_NON_NULL(ro2->mask, false); 117 PS_ASSERT_IMAGE_TYPE(ro2->mask, PS_TYPE_MASK, false); 118 PS_ASSERT_IMAGES_SIZE_EQUAL(ro2->mask, ro1->image, false); 119 } 120 if (ro2->weight) { 121 PS_ASSERT_IMAGE_NON_NULL(ro2->weight, false); 122 PS_ASSERT_IMAGE_TYPE(ro2->weight, PS_TYPE_F32, false); 123 PS_ASSERT_IMAGES_SIZE_EQUAL(ro2->weight, ro1->image, false); 132 124 } 133 125 } else if (!stampsName && !sources) { … … 144 136 } 145 137 // stampsName may be anything 146 // targetWidth can be just about anything (except maybe negative, but it can be NAN)147 138 // We'll check kernel type when we allocate the kernels 148 139 PS_ASSERT_INT_POSITIVE(size, false); … … 196 187 } 197 188 198 psImage *inImage = NULL, *inMask = NULL; // Input image, mask, weight199 if (input) {200 inImage = input->image;201 inMask = input->mask;202 }203 204 189 // Where does our weight map come from? 205 190 psImage *weight = NULL; // Weight image to use 206 if (input && input->weight) { 207 weight = input->weight; 208 } else if (reference->weight) { 209 weight = reference->weight; 210 } else if (input) { 211 weight = input->image; 191 if (ro1->weight && ro2 && ro2->weight) { 192 weight = (psImage*)psBinaryOp(NULL, ro1->weight, "+", ro2->weight); 193 } else if (ro1->weight) { 194 weight = psMemIncrRefCounter(ro1->weight); 195 } else if (ro2) { 196 if (ro2->weight) { 197 weight = psMemIncrRefCounter(ro2->weight); 198 } else { 199 weight = (psImage*)psBinaryOp(NULL, ro1->image, "+", ro2->image); 200 } 212 201 } else { 213 weight = reference->image;202 weight = psMemIncrRefCounter(ro1->image); 214 203 } 215 204 … … 221 210 psVector *solution = NULL; // Solution to match PSF 222 211 pmSubtractionKernels *kernels = NULL; // Kernel basis functions 223 224 int numCols = reference->image->numCols, numRows = reference->image->numRows; // Image dimensions 212 int numCols = ro1->image->numCols, numRows = ro1->image->numRows; // Image dimensions 225 213 226 214 memCheck("start"); 227 215 228 subMask = pmSubtractionMask(reference->mask, inMask, maskBad, size, footprint, badFrac, useFFT); 216 subMask = pmSubtractionMask(ro1->mask, ro2 ? ro2->mask : NULL, maskBad, size, footprint, 217 badFrac, useFFT); 229 218 if (!subMask) { 230 219 psError(PS_ERR_UNKNOWN, false, "Unable to generate subtraction mask."); 220 psFree(weight); 231 221 return false; 232 222 } … … 260 250 261 251 if (sources) { 262 stamps = pmSubtractionStampsSetFromSources(sources, subMask, region, stampSpacing, 263 input ? 0 : 2 * footprint); 252 stamps = pmSubtractionStampsSetFromSources(sources, subMask, region, stampSpacing, mode); 264 253 } else if (stampsName && strlen(stampsName) > 0) { 265 // Read stamps from file 266 psTrace("psModules.imcombine", 3, "Reading stamps from %s...\n", stampsName); 267 const char *stampFormat = input ? "%f %f" : "%f %f %f"; // Format for reading stamp file 268 psArray *stampsData = stampsData = psVectorsReadFromFile(stampsName, stampFormat); 269 psVector *xStamp = NULL, *yStamp = NULL, *fluxStamp = NULL; // Stamp positions and fluxes 270 if (!stampsData) { 271 psError(PS_ERR_IO, false, "Unable to read stamps file %s", stampsName); 272 goto ERROR; 273 } 274 xStamp = stampsData->data[0]; 275 yStamp = stampsData->data[1]; 276 if (!input) { 277 fluxStamp = stampsData->data[2]; 278 } 279 280 // Correct for IRAF/FITS (unit-offset) positions to C (zero-offset) positions 281 psBinaryOp(xStamp, xStamp, "-", psScalarAlloc(1.0, PS_TYPE_F32)); 282 psBinaryOp(yStamp, yStamp, "-", psScalarAlloc(1.0, PS_TYPE_F32)); 283 284 stamps = pmSubtractionStampsSet(xStamp, yStamp, fluxStamp, reference->image, subMask, 285 region, stampSpacing, input ? 0 : footprint + size); 286 psFree(stampsData); 254 stamps = pmSubtractionStampsSetFromFile(stampsName, subMask, region, stampSpacing, mode); 255 } 256 257 // We get the stamps here; we will also attempt to get stamps at the first iteration, but it 258 // doesn't matter. 259 if (!getStamps(&stamps, ro1, ro2, subMask, weight, NULL, threshold, stampSpacing, 260 size, footprint, mode)) { 261 goto MATCH_ERROR; 262 } 263 264 if (mode == PM_SUBTRACTION_MODE_UNSURE || mode == PM_SUBTRACTION_MODE_TARGET) { 265 pmSubtractionMode newMode = pmSubtractionOrder(stamps, footprint); // Subtraction mode 266 switch (newMode) { 267 case PM_SUBTRACTION_MODE_1: 268 psLogMsg("psModules.imcombine", PS_LOG_INFO, "Convolving image 1 to match image 2."); 269 break; 270 case PM_SUBTRACTION_MODE_2: 271 if (mode == PM_SUBTRACTION_MODE_TARGET) { 272 psError(PS_ERR_BAD_PARAMETER_VALUE, true, 273 "Input PSF is larger than target PSF --- can't match image."); 274 goto MATCH_ERROR; 275 } 276 psLogMsg("psModules.imcombine", PS_LOG_INFO, "Convolving image 2 to match image 1."); 277 break; 278 default: 279 psError(PS_ERR_UNKNOWN, false, "Unable to determine subtraction order."); 280 goto MATCH_ERROR; 281 } 282 mode = newMode; 287 283 } 288 284 289 285 // Define kernel basis functions 290 286 if (optimum && (type == PM_SUBTRACTION_KERNEL_ISIS || type == PM_SUBTRACTION_KERNEL_GUNK)) { 291 if (!getStamps(&stamps, reference, input, subMask, weight, NULL,292 threshold, stampSpacing, targetWidth, size, footprint)) {293 goto ERROR;294 }295 287 kernels = pmSubtractionKernelsOptimumISIS(type, size, inner, spatialOrder, optFWHMs, optOrder, 296 stamps, footprint, optThreshold );288 stamps, footprint, optThreshold, mode); 297 289 if (!kernels) { 298 290 psErrorClear(); … … 314 306 psLogMsg("psModules.imcombine", PS_LOG_INFO, "Iteration %d.", k); 315 307 316 if (!getStamps(&stamps, r eference, input, subMask, weight, region,317 threshold, stampSpacing, targetWidth, size, footprint)) {318 goto ERROR;308 if (!getStamps(&stamps, ro1, ro2, subMask, weight, region, threshold, stampSpacing, 309 size, footprint, mode)) { 310 goto MATCH_ERROR; 319 311 } 320 312 321 313 psTrace("psModules.imcombine", 3, "Calculating equation...\n"); 322 if (!pmSubtractionCalculateEquation(stamps, kernels, footprint )) {314 if (!pmSubtractionCalculateEquation(stamps, kernels, footprint, mode)) { 323 315 psError(PS_ERR_UNKNOWN, false, "Unable to calculate least-squares equation."); 324 goto ERROR;316 goto MATCH_ERROR; 325 317 } 326 318 … … 331 323 if (!solution) { 332 324 psError(PS_ERR_UNKNOWN, false, "Unable to calculate least-squares equation."); 333 goto ERROR;325 goto MATCH_ERROR; 334 326 } 335 327 336 328 memCheck(" solve equation"); 337 329 330 psVector *deviations = pmSubtractionCalculateDeviations(stamps, solution, footprint, kernels, 331 mode); // Deviations for each stamp 332 if (!deviations) { 333 psError(PS_ERR_UNKNOWN, false, "Unable to calculate deviations."); 334 goto MATCH_ERROR; 335 } 336 337 memCheck(" calculate deviations"); 338 338 339 psTrace("psModules.imcombine", 3, "Rejecting stamps...\n"); 339 numRejected = pmSubtractionRejectStamps(stamps, subMask, solution, footprint, rej, kernels);340 numRejected = pmSubtractionRejectStamps(stamps, deviations, subMask, rej, footprint); 340 341 if (numRejected < 0) { 341 342 psError(PS_ERR_UNKNOWN, false, "Unable to reject stamps."); 342 goto ERROR; 343 } 343 psFree(deviations); 344 goto MATCH_ERROR; 345 } 346 psFree(deviations); 347 344 348 memCheck(" reject stamps"); 345 349 } … … 350 354 if (!solution) { 351 355 psError(PS_ERR_UNKNOWN, false, "Unable to calculate least-squares equation."); 352 goto ERROR; 353 } 354 (void)pmSubtractionRejectStamps(stamps, subMask, solution, footprint, NAN, kernels); 356 goto MATCH_ERROR; 357 } 358 psVector *deviations = pmSubtractionCalculateDeviations(stamps, solution, footprint, kernels, 359 mode); // Deviations for each stamp 360 if (!deviations) { 361 psError(PS_ERR_UNKNOWN, false, "Unable to calculate deviations."); 362 goto MATCH_ERROR; 363 } 364 (void)pmSubtractionRejectStamps(stamps, deviations, subMask, footprint, NAN); 365 psFree(deviations); 355 366 } 356 367 psFree(stamps); … … 372 383 psError(PS_ERR_UNKNOWN, false, "Unable to generate kernel image."); 373 384 psFree(convKernels); 374 goto ERROR;385 goto MATCH_ERROR; 375 386 } 376 387 … … 380 391 psFree(kernel); 381 392 psFree(convKernels); 382 goto ERROR;393 goto MATCH_ERROR; 383 394 } 384 395 psFree(kernel); … … 416 427 417 428 psTrace("psModules.imcombine", 2, "Convolving...\n"); 418 if (!pmSubtractionConvolve(&convolved->image, &convolved->weight, &convolved->mask, 419 reference->image, reference->weight, subMask, maskBlank, region, 420 solution, kernels, useFFT)) { 421 psError(PS_ERR_UNKNOWN, false, "Unable to convolve reference image."); 422 goto ERROR; 429 if (!pmSubtractionConvolve(convolved, ro1, ro2, subMask, maskBlank, region, 430 solution, kernels, mode, useFFT)) { 431 psError(PS_ERR_UNKNOWN, false, "Unable to convolve image."); 432 goto MATCH_ERROR; 423 433 } 424 434 psFree(kernels); … … 461 471 psFree(subMask); 462 472 subMask = NULL; 473 psFree(weight); 474 weight = NULL; 463 475 464 476 if (!pmSubtractionBorder(convolved->image, convolved->weight, convolved->mask, size, maskBlank)) { 465 477 psError(PS_ERR_UNKNOWN, false, "Unable to set border of convolved image."); 466 goto ERROR;478 goto MATCH_ERROR; 467 479 } 468 480 … … 472 484 return true; 473 485 474 ERROR:486 MATCH_ERROR: 475 487 psFree(region); 476 488 psFree(regionString); … … 479 491 psFree(stamps); 480 492 psFree(solution); 493 psFree(weight); 481 494 return false; 482 495 } 496 497 // Calculate the second order moments for an image 498 static float subtractionOrderMoment(const psKernel *kernel, // Image for which to measure moments 499 int radius // Maximum radius 500 ) 501 { 502 assert(kernel && kernel->kernel); 503 504 int xMin = PS_MAX(kernel->xMin, -radius), xMax = PS_MIN(kernel->xMax, radius); // Bounds in x 505 int yMin = PS_MAX(kernel->yMin, -radius), yMax = PS_MIN(kernel->yMax, radius); // Bounds in y 506 507 float xCentroid = 0.0, yCentroid = 0.0; // Centroid (first moment) 508 float sum = 0.0; // Sum (zero-th moment) 509 for (int y = yMin; y <= yMax; y++) { 510 for (int x = xMin; x <= xMax; x++) { 511 xCentroid += kernel->kernel[y][x] * x; 512 yCentroid += kernel->kernel[y][x] * y; 513 sum += kernel->kernel[y][x]; 514 } 515 } 516 xCentroid /= sum; 517 yCentroid /= sum; 518 519 float eta20 = 0.0, eta02 = 0.0; // Second moments 520 for (int y = yMin; y <= yMax; y++) { 521 float yDiff = y - yCentroid; 522 for (int x = xMin; x <= xMax; x++) { 523 float xDiff = x - xCentroid; 524 eta20 += PS_SQR(xDiff) * kernel->kernel[y][x]; 525 eta02 += PS_SQR(yDiff) * kernel->kernel[y][x]; 526 } 527 } 528 529 // Normalise to calculate the scale-invariant 530 float sum2 = PS_SQR(sum); 531 eta20 /= sum2; 532 eta02 /= sum2; 533 // eta11 /= sum2; 534 535 return eta20 + eta02; 536 } 537 538 #if 0 539 // Calculate the deviations for a particular subtraction order 540 static psVector *subtractionOrderDeviation(float *sumKernel, // Sum of the kernel 541 pmSubtractionStampList *stamps, // Stamps to convolve 542 const pmSubtractionKernels *kernels, // Kernel basis functions 543 int footprint, // Stamp footprint 544 pmSubtractionMode mode // Mode of subtraction 545 ) 546 { 547 assert(stamps); 548 assert(footprint >= 0); 549 assert(mode == PM_SUBTRACTION_MODE_1 || mode == PM_SUBTRACTION_MODE_2); 550 551 if (!pmSubtractionCalculateEquation(stamps, kernels, footprint, mode)) { 552 psError(PS_ERR_UNKNOWN, false, "Unable to calculate least-squares equation."); 553 return NULL; 554 } 555 556 psVector *solution = pmSubtractionSolveEquation(NULL, stamps); 557 if (!solution) { 558 psError(PS_ERR_UNKNOWN, false, "Unable to calculate least-squares equation."); 559 return NULL; 560 } 561 562 if (sumKernel) { 563 float sum = 0.0; // Sum of the kernel 564 psImage *image = pmSubtractionKernelImage(solution, kernels, 0.0, 0.0); // Image of kernel 565 for (int y = 0; y < image->numRows; y++) { 566 for (int x = 0; x < image->numCols; x++) { 567 sum += image->data.F32[y][x]; 568 } 569 } 570 psFree(image); 571 *sumKernel = sum; 572 } 573 574 psVector *deviations = pmSubtractionCalculateDeviations(stamps, solution, footprint, kernels, mode); 575 psFree(solution); 576 if (!deviations) { 577 psError(PS_ERR_UNKNOWN, false, "Unable to calculate deviations."); 578 return NULL; 579 } 580 581 return deviations; 582 } 583 #endif 584 585 pmSubtractionMode pmSubtractionOrder(pmSubtractionStampList *stamps, int radius) 586 { 587 PS_ASSERT_INT_POSITIVE(radius, PM_SUBTRACTION_MODE_ERR); 588 589 psVector *mask = psVectorAlloc(stamps->num, PS_TYPE_MASK); // Mask for stamps 590 psVector *moments = psVectorAlloc(stamps->num, PS_TYPE_F32); // Moments 591 for (int i = 0; i < stamps->num; i++) { 592 pmSubtractionStamp *stamp = stamps->stamps->data[i]; // Stamp of interest 593 if (stamp->status != PM_SUBTRACTION_STAMP_CALCULATE && stamp->status != PM_SUBTRACTION_STAMP_USED) { 594 mask->data.PS_TYPE_MASK_DATA[i] = 0xff; 595 continue; 596 } 597 mask->data.PS_TYPE_MASK_DATA[i] = 0; 598 moments->data.F32[i] = subtractionOrderMoment(stamp->image1, radius) / 599 subtractionOrderMoment(stamp->image2, radius); 600 } 601 602 psStats *stats = psStatsAlloc(PS_STAT_ROBUST_MEDIAN); 603 if (!psVectorStats(stats, moments, NULL, mask, 0xff)) { 604 psError(PS_ERR_UNKNOWN, false, "Unable to calculate statistics for moments ratio."); 605 psFree(mask); 606 psFree(moments); 607 psFree(stats); 608 return PM_SUBTRACTION_MODE_ERR; 609 } 610 psFree(moments); 611 psFree(mask); 612 613 psLogMsg("psModules.imcombine", PS_LOG_INFO, "Median ratio of second moments: %lf", stats->robustMedian); 614 pmSubtractionMode mode = (stats->robustMedian <= 1.0 ? PM_SUBTRACTION_MODE_1 : PM_SUBTRACTION_MODE_2); 615 psFree(stats); 616 617 return mode; 618 } 619 620 621 -
trunk/psModules/src/imcombine/pmSubtractionMatch.h
r15305 r15443 4 4 #include <pslib.h> 5 5 6 #include "pmHDU.h" 7 #include "pmFPA.h" 8 #include "pmSubtractionKernels.h" 6 #include <pmHDU.h> 7 #include <pmFPA.h> 8 #include <pmSubtractionKernels.h> 9 #include <pmSubtractionStamps.h> 9 10 10 11 /// Match two images 11 12 bool pmSubtractionMatch(pmReadout *convolved, ///< Output convolved data 12 const pmReadout *r eference, ///< Reference data13 const pmReadout * input, ///< Input data13 const pmReadout *ro1, ///< Image 1 14 const pmReadout *ro2, ///< Image 2 14 15 // Stamp parameters 15 16 int footprint, ///< Stamp half-size … … 19 20 const psArray *sources, ///< Sources for stamps 20 21 const char *stampsName, ///< Filename for stamps 21 float targetWidth, ///< Width of PSF for simulated target22 22 // Kernel parameters 23 23 pmSubtractionKernelsType type, ///< Kernel type … … 38 38 psMaskType maskBad, ///< Value to mask 39 39 psMaskType maskBlank, ///< Mask for blank region 40 float badFrac ///< Maximum fraction of bad input pixels to accept 40 float badFrac, ///< Maximum fraction of bad input pixels to accept 41 pmSubtractionMode mode ///< Mode of subtraction 41 42 ); 42 43 44 /// Determine which image to convolve 45 pmSubtractionMode pmSubtractionOrder(pmSubtractionStampList *stamps, ///< Stamps that have been extracted 46 int footprint ///< Stamp half-size 47 ); 48 49 43 50 #endif -
trunk/psModules/src/imcombine/pmSubtractionParams.c
r15247 r15443 50 50 #endif 51 51 52 /// Select the appropriate convolution, given the kernel basis function and subtraction mode 53 static inline psKernel *selectConvolution(const pmSubtractionStamp *stamp, // Stamp 54 int kernelIndex, // Index for kernel component 55 pmSubtractionMode mode // Mode of subtraction 56 ) 57 { 58 switch (mode) { 59 case PM_SUBTRACTION_MODE_1: 60 return stamp->convolutions1->data[kernelIndex]; 61 case PM_SUBTRACTION_MODE_2: 62 return stamp->convolutions2->data[kernelIndex]; 63 default: 64 psAbort("Unsupported subtraction mode: %x", mode); 65 } 66 return NULL; // Unreached 67 } 68 52 69 // Accumulate cross-term sums for a stamp 53 70 static void accumulateCross(double *sumI, // Sum of I(x)/sigma(x)^2 … … 55 72 double *sumIC, // Sum of I(x)conv(x)/sigma(x)^2 56 73 const pmSubtractionStamp *stamp, // Stamp with weight 57 const psKernel * input, // Input image, I(x)74 const psKernel *target, // Target stamp 58 75 int kernelIndex, // Index for kernel component 59 int footprint // Size of region of interest 76 int footprint, // Size of region of interest 77 pmSubtractionMode mode // Mode of subtraction 60 78 ) 61 79 { 62 80 psKernel *weight = stamp->weight; // Weight, sigma(x)^2 63 psKernel *convolution = s tamp->convolutions->data[kernelIndex]; // Convolution of interest81 psKernel *convolution = selectConvolution(stamp, kernelIndex, mode); // Convolution of interest 64 82 65 83 for (int y = -footprint; y <= footprint; y++) { 66 psF32 *in = & input->kernel[y][-footprint]; // Dereference input84 psF32 *in = &target->kernel[y][-footprint]; // Dereference input 67 85 psF32 *wt = &weight->kernel[y][-footprint]; // Dereference weight 68 86 psF32 *conv = &convolution->kernel[y][-footprint]; // Dereference convolution … … 82 100 const pmSubtractionStamp *stamp, // Stamp with input and weight 83 101 int kernelIndex, // Index for kernel component 84 int footprint // Size of region of interest 102 int footprint, // Size of region of interest 103 pmSubtractionMode mode // Mode of subtraction 85 104 ) 86 105 { 87 106 psKernel *weight = stamp->weight; // Weight, sigma(x)^2 88 psKernel *convolution = s tamp->convolutions->data[kernelIndex]; // Convolution of interest107 psKernel *convolution = selectConvolution(stamp, kernelIndex, mode); // Convolution of interest 89 108 90 109 for (int y = -footprint; y <= footprint; y++) { … … 100 119 } 101 120 102 static double accumulateChi2( psKernel *input, // Input stamp121 static double accumulateChi2(const psKernel *target, // Target stamp 103 122 pmSubtractionStamp *stamp, // Stamp with weight 104 123 int kernelIndex, // Index for kernel component 105 124 double coeff, // Coefficient of convolution 106 125 double bg, // Background term 107 int footprint // Size of region of interest 126 int footprint, // Size of region of interest 127 pmSubtractionMode mode // Mode of subtraction 108 128 ) 109 129 { 110 130 double chi2 = 0.0; 111 131 psKernel *weight = stamp->weight; // Weight, sigma(x)^2 112 psKernel *convolution = s tamp->convolutions->data[kernelIndex]; // Convolution of interest132 psKernel *convolution = selectConvolution(stamp, kernelIndex, mode); // Convolution of interest 113 133 114 134 for (int y = -footprint; y <= footprint; y++) { 115 psF32 *in = & input->kernel[y][-footprint]; // Dereference input135 psF32 *in = &target->kernel[y][-footprint]; // Dereference input 116 136 psF32 *wt = &weight->kernel[y][-footprint]; // Dereference weight 117 137 psF32 *conv = &convolution->kernel[y][-footprint]; // Dereference convolution … … 125 145 126 146 // Return the initial value of chi^2 127 static double initialChi2( psKernel *input, // Input stamp147 static double initialChi2(const psKernel *target, // Target stamp 128 148 const pmSubtractionStamp *stamp, // Stamp with weight 129 int footprint // Size of convolution 149 int footprint, // Size of convolution 150 pmSubtractionMode mode // Mode of subtraction 130 151 ) 131 152 { 132 153 psKernel *weight = stamp->weight; // Weight map 133 psKernel *reference = stamp->reference; // Reference stamp 154 psKernel *source; // Source stamp 155 switch (mode) { 156 case PM_SUBTRACTION_MODE_1: 157 source = stamp->image1; 158 break; 159 case PM_SUBTRACTION_MODE_2: 160 source = stamp->image2; 161 break; 162 default: 163 psAbort("Unsupported subtraction mode: %x", mode); 164 } 134 165 135 166 double chi2 = 0.0; // Chi^2 136 167 for (int y = -footprint; y <= footprint; y++) { 137 psF32 *in = & input->kernel[y][-footprint]; // Dereference input168 psF32 *in = &target->kernel[y][-footprint]; // Dereference input 138 169 psF32 *wt = &weight->kernel[y][-footprint]; // Dereference weight 139 psF32 *ref = & reference->kernel[y][-footprint]; // Derference reference170 psF32 *ref = &source->kernel[y][-footprint]; // Derference reference 140 171 for (int x = -footprint; x <= footprint; x++, in++, wt++, ref++) { 141 172 float diff = *in - *ref; // Temporary value … … 148 179 149 180 // Subtract a convolution from the input 150 static void subtractConvolution(psKernel * input, // Input stamp181 static void subtractConvolution(psKernel *target, // Target stamp 151 182 const pmSubtractionStamp *stamp, // Stamp with weight 152 183 int kernelIndex, // Index for kernel component 153 184 float coeff, // Coefficient of subtraction 154 185 float bg, // Background term 155 int footprint // Size of region of interest156 )157 { 158 psKernel *convolution = stamp->convolutions->data[kernelIndex]; // Convolution of interest 159 186 int footprint, // Size of region of interest 187 pmSubtractionMode mode // Mode of subtraction 188 ) 189 { 190 psKernel *convolution = selectConvolution(stamp, kernelIndex, mode); // Convolution of interest 160 191 for (int y = -footprint; y <= footprint; y++) { 161 psF32 *in = & input->kernel[y][-footprint]; // Dereference input192 psF32 *in = &target->kernel[y][-footprint]; // Dereference input 162 193 psF32 *conv = &convolution->kernel[y][-footprint]; // Dereference convolution 163 194 for (int x = -footprint; x <= footprint; x++, in++, conv++) { … … 173 204 int spatialOrder, const psVector *fwhms, int maxOrder, 174 205 const pmSubtractionStampList *stamps, int footprint, 175 float tolerance )206 float tolerance, pmSubtractionMode mode) 176 207 { 177 208 if (type != PM_SUBTRACTION_KERNEL_ISIS && type != PM_SUBTRACTION_KERNEL_GUNK) { … … 210 241 // Need to save the stamp inputs --- we're changing the values! 211 242 int numStamps = stamps->num; // Number of stamps 212 psArray * inputs = psArrayAlloc(numStamps); // Deep copies of the inputs243 psArray *targets = psArrayAlloc(numStamps); // Deep copies of the targets 213 244 psVector *badStamps = psVectorAlloc(numStamps, PS_TYPE_U8); // Mark the bad stamps 214 245 psVectorInit(badStamps, 0); … … 219 250 continue; 220 251 } 221 psKernel *input = stamp->input; // Input image of interest 222 psImage *copy = psImageCopy(NULL, input->image, PS_TYPE_F32); // Copy of the image 223 inputs->data[i] = psKernelAllocFromImage(copy, size + footprint, size + footprint); 252 psKernel *target; // Target image of interest 253 switch (mode) { 254 case PM_SUBTRACTION_MODE_1: 255 target = stamp->image2; 256 break; 257 case PM_SUBTRACTION_MODE_2: 258 target = stamp->image1; 259 break; 260 default: 261 psAbort("Unsupported subtraction mode: %x", mode); 262 } 263 psImage *copy = psImageCopy(NULL, target->image, PS_TYPE_F32); // Copy of the image 264 targets->data[i] = psKernelAllocFromImage(copy, size + footprint, size + footprint); 224 265 psFree(copy); // Drop reference 225 266 } … … 238 279 continue; 239 280 } 240 if (!pmSubtractionConvolveStamp(stamp, kernels, footprint )) {281 if (!pmSubtractionConvolveStamp(stamp, kernels, footprint, mode)) { 241 282 psError(PS_ERR_UNKNOWN, false, "Unable to convolve stamp %d.", i); 242 psFree( inputs);283 psFree(targets); 243 284 psFree(kernels); 244 285 psFree(badStamps); … … 258 299 "Sum of 1/sigma^2 is non-finite for stamp %d (%d,%d)\n", 259 300 i, (int)stamp->x, (int)stamp->y); 260 psFree( inputs);301 psFree(targets); 261 302 psFree(kernels); 262 303 psFree(badStamps); … … 265 306 266 307 for (int j = 0; j < numKernels; j++) { 267 accumulateConvolutions(&sumC->data.F64[j], &sumCC->data.F64[j], stamp, j, footprint );268 } 269 270 lastChi2 += initialChi2( inputs->data[i], stamp, footprint);308 accumulateConvolutions(&sumC->data.F64[j], &sumCC->data.F64[j], stamp, j, footprint, mode); 309 } 310 311 lastChi2 += initialChi2(targets->data[i], stamp, footprint, mode); 271 312 numPixels += PS_SQR(2 * footprint + 1); 272 313 } … … 297 338 } 298 339 pmSubtractionStamp *stamp = stamps->stamps->data[j]; // Stamp of interest 299 accumulateCross(&sumI, &sumII, &sumIC, stamp, inputs->data[j], i, footprint);340 accumulateCross(&sumI, &sumII, &sumIC, stamp, targets->data[j], i, footprint, mode); 300 341 } 301 342 … … 310 351 } 311 352 pmSubtractionStamp *stamp = stamps->stamps->data[j]; // Stamp of interest 312 chi2 += accumulateChi2( inputs->data[j], stamp, i, coeff, bg, footprint);353 chi2 += accumulateChi2(targets->data[j], stamp, i, coeff, bg, footprint, mode); 313 354 } 314 355 … … 328 369 if (bestIndex == -1) { 329 370 psError(PS_ERR_UNKNOWN, false, "Unable to find best kernel component in round %d.", iter); 330 psFree( inputs);371 psFree(targets); 331 372 psFree(sumC); 332 373 psFree(sumCC); … … 345 386 } 346 387 pmSubtractionStamp *stamp = stamps->stamps->data[j]; // Stamp of interest 347 subtractConvolution( inputs->data[j], stamp, bestIndex, bestCoeff, bestBG, footprint);388 subtractConvolution(targets->data[j], stamp, bestIndex, bestCoeff, bestBG, footprint, mode); 348 389 } 349 390 … … 361 402 lastChi2 = bestChi2; 362 403 } 363 psFree( inputs);404 psFree(targets); 364 405 psFree(sumC); 365 406 psFree(sumCC); … … 401 442 pmSubtractionStamp *stamp = stamps->stamps->data[j]; // Stamp of interest 402 443 psArray *convolutions = convNew->data[j]; // Convolutions for this stamp 403 convolutions->data[rank] = psMemIncrRefCounter(s tamp->convolutions->data[i]);444 convolutions->data[rank] = psMemIncrRefCounter(selectConvolution(stamp, i, mode)); 404 445 } 405 446 } … … 420 461 } 421 462 pmSubtractionStamp *stamp = stamps->stamps->data[i]; // Stamp of interest 422 psFree(stamp->convolutions); 423 stamp->convolutions = convNew->data[i]; 463 psFree(stamp->convolutions1); 464 psFree(stamp->convolutions2); 465 switch (mode) { 466 case PM_SUBTRACTION_MODE_1: 467 stamp->convolutions1 = convNew->data[i]; 468 stamp->convolutions2 = NULL; 469 break; 470 case PM_SUBTRACTION_MODE_2: 471 stamp->convolutions1 = NULL; 472 stamp->convolutions2 = convNew->data[i]; 473 break; 474 default: 475 psAbort("Unsupported subtraction mode: %x", mode); 476 } 424 477 } 425 478 -
trunk/psModules/src/imcombine/pmSubtractionParams.h
r14804 r15443 15 15 const pmSubtractionStampList *stamps, ///< Stamps 16 16 int footprint, ///< Convolution footprint for stamps 17 float tolerance ///< Maximum difference in chi^2 17 float tolerance, ///< Maximum difference in chi^2 18 pmSubtractionMode mode // Mode for subtraction 18 19 ); 19 20 -
trunk/psModules/src/imcombine/pmSubtractionStamps.c
r15286 r15443 4 4 5 5 #include <stdio.h> 6 #include <string.h> 6 7 #include <pslib.h> 7 8 … … 45 46 psFree(stamp->matrix); 46 47 psFree(stamp->vector); 47 psFree(stamp-> reference);48 psFree(stamp->i nput);48 psFree(stamp->image1); 49 psFree(stamp->image2); 49 50 psFree(stamp->weight); 50 psFree(stamp->convolutions); 51 psFree(stamp->convolutions1); 52 psFree(stamp->convolutions2); 51 53 } 52 54 … … 65 67 // Is this position unmasked? 66 68 static bool checkStampMask(int x, int y, // Coordinates of stamp 67 const psImage *mask 69 const psImage *mask, // Mask 70 pmSubtractionMode mode // Mode for subtraction 68 71 ) 69 72 { … … 74 77 return false; 75 78 } 76 return (mask->data.PS_TYPE_MASK_DATA[y][x] & (PM_SUBTRACTION_MASK_BORDER | 77 PM_SUBTRACTION_MASK_FOOTPRINT | PM_SUBTRACTION_MASK_REJ)) ? 78 false : true; 79 80 psMaskType maskVal = PM_SUBTRACTION_MASK_BORDER | PM_SUBTRACTION_MASK_REJ; // Mask value 81 switch (mode) { 82 case PM_SUBTRACTION_MODE_1: 83 case PM_SUBTRACTION_MODE_TARGET: 84 maskVal |= PM_SUBTRACTION_MASK_FOOTPRINT_1; 85 break; 86 case PM_SUBTRACTION_MODE_2: 87 maskVal |= PM_SUBTRACTION_MASK_FOOTPRINT_2; 88 break; 89 case PM_SUBTRACTION_MODE_UNSURE: 90 case PM_SUBTRACTION_MODE_DUAL: 91 maskVal |= PM_SUBTRACTION_MASK_FOOTPRINT_1 | PM_SUBTRACTION_MASK_FOOTPRINT_2; 92 break; 93 default: 94 psAbort("Unsupported subtraction mode: %x", mode); 95 } 96 97 return (mask->data.PS_TYPE_MASK_DATA[y][x] & maskVal) ? false : true; 79 98 } 80 99 … … 140 159 stamp->status = PM_SUBTRACTION_STAMP_INIT; 141 160 142 stamp-> reference= NULL;143 stamp->i nput= NULL;161 stamp->image1 = NULL; 162 stamp->image2 = NULL; 144 163 stamp->weight = NULL; 145 stamp->convolutions = NULL; 164 stamp->convolutions1 = NULL; 165 stamp->convolutions2 = NULL; 146 166 147 167 return stamp; … … 151 171 pmSubtractionStampList *pmSubtractionStampsFind(pmSubtractionStampList *stamps, const psImage *image, 152 172 const psImage *subMask, const psRegion *region, 153 float threshold, float spacing )173 float threshold, float spacing, pmSubtractionMode mode) 154 174 { 155 175 PS_ASSERT_IMAGE_NON_NULL(image, NULL); … … 226 246 for (int y = subRegion->y0; y <= subRegion->y1 ; y++) { 227 247 for (int x = subRegion->x0; x <= subRegion->y1 ; x++) { 228 if (checkStampMask(x, y, subMask ) && image->data.F32[y][x] > fluxStamp) {248 if (checkStampMask(x, y, subMask, mode) && image->data.F32[y][x] > fluxStamp) { 229 249 fluxStamp = image->data.F32[y][x]; 230 250 xStamp = x; … … 242 262 243 263 // Reset the postage stamps since we're making a new stamp 244 psFree(stamp-> reference);245 psFree(stamp->i nput);264 psFree(stamp->image1); 265 psFree(stamp->image2); 246 266 psFree(stamp->weight); 247 stamp->reference = stamp->input = stamp->weight = NULL; 248 249 stamp->status = PM_SUBTRACTION_STAMP_CALCULATE; 267 psFree(stamp->convolutions1); 268 psFree(stamp->convolutions2); 269 stamp->image1 = stamp->image2 = stamp->weight = NULL; 270 stamp->convolutions1 = stamp->convolutions2 = NULL; 271 272 stamp->status = PM_SUBTRACTION_STAMP_FOUND; 250 273 numFound++; 251 274 psTrace("psModules.imcombine", 5, "Found stamp in subregion %d: %d,%d\n", … … 266 289 pmSubtractionStampList *pmSubtractionStampsSet(const psVector *x, const psVector *y, const psVector *flux, 267 290 const psImage *image, const psImage *subMask, 268 const psRegion *region, float spacing, int exclusionZone) 291 const psRegion *region, float spacing, pmSubtractionMode mode) 292 269 293 { 270 294 PS_ASSERT_VECTOR_NON_NULL(x, NULL); … … 289 313 } 290 314 PS_ASSERT_FLOAT_LARGER_THAN(spacing, 0.0, NULL); 291 PS_ASSERT_INT_NONNEGATIVE(exclusionZone, NULL);292 315 293 316 int numStars = x->n; // Number of stars 294 psVector *exclude = psVectorAlloc(numStars, PS_TYPE_U8); // Exclude a star?295 psVectorInit(exclude, 0);296 297 // Apply exclusion zone around each star --- important when we're convolving to a specified PSF; less so298 // when we're trying to get a good subtraction.299 if (exclusionZone > 0) {300 psTrace("psModules.imcombine", 2, "Applying exclusion zone of %d pixels for stamps\n", exclusionZone);301 // We use something resembling a binary search --- coordinates are sorted in the x dimension, and then302 // to exclude stars within a nominated distance, we need only examine (i.e., calculate the303 // 2-dimensional distance to) other stars in the list that are within that distance of the x304 // coordinate of the star of interest. By marking both stars when we find a violation of the305 // exclusion zone, we need only search upwards from the x coordinate of the star of interest.306 307 int minDistance2 = PS_SQR(exclusionZone); // Minimum square distance for other stars308 psVector *indexes = psVectorSortIndex(NULL, x); // Indices for sorting in x309 for (int i = 0; i < numStars - 1; i++) {310 int iIndex = indexes->data.S32[i]; // Index for star i311 if (exclude->data.U8[iIndex]) {312 continue;313 }314 float ix = x->data.F32[iIndex], iy = y->data.F32[iIndex]; // Coordinates for star i315 float jx, jy; // Coordinates for star j316 for (int j = i + 1, jIndex = indexes->data.S32[j];317 j < numStars && (jx = x->data.F32[jIndex]) < ix + exclusionZone;318 j++, jIndex = indexes->data.S32[j]) {319 jy = y->data.F32[jIndex];320 if (PS_SQR(ix - jx) + PS_SQR(iy - jy) < minDistance2) {321 exclude->data.U8[iIndex] = 0xff;322 exclude->data.U8[jIndex] = 0xff;323 psTrace("psModules.imcombine", 5, "Excluding stamps %d,%d and %d,%d\n",324 (int)x->data.F32[iIndex], (int)y->data.F32[iIndex],325 (int)x->data.F32[jIndex], (int)y->data.F32[jIndex]);326 // Would 'break' here, but there might be more stamps within the exclusion zone.327 }328 }329 }330 psFree(indexes);331 }332 333 317 pmSubtractionStampList *stamps = pmSubtractionStampListAlloc(subMask->numCols, subMask->numRows, 334 318 region, spacing); // Stamp list … … 347 331 // Put the stars into their appropriate subregions 348 332 for (int i = 0; i < numStars; i++) { 349 if (exclude->data.U8[i]) {350 // Star has been excluded351 continue;352 }353 333 float xStamp = x->data.F32[i], yStamp = y->data.F32[i]; // Coordinates of stamp 354 334 int xPix = xStamp + 0.5, yPix = yStamp + 0.5; // Pixel coordinate of stamp … … 357 337 continue; 358 338 } 359 if (!checkStampMask(xPix, yPix, subMask )) {339 if (!checkStampMask(xPix, yPix, subMask, mode)) { 360 340 // Not a good stamp 361 341 continue; … … 386 366 } 387 367 } 388 psFree(exclude);389 368 390 369 // Sort the list by flux, with the brightest last … … 421 400 422 401 423 bool pmSubtractionStampsExtract(pmSubtractionStampList *stamps, psImage * reference, psImage *input,402 bool pmSubtractionStampsExtract(pmSubtractionStampList *stamps, psImage *image1, psImage *image2, 424 403 psImage *weight, int footprint, int kernelSize) 425 404 { 426 405 PM_ASSERT_SUBTRACTION_STAMP_LIST_NON_NULL(stamps, false); 427 PS_ASSERT_IMAGE_NON_NULL(reference, false); 428 PS_ASSERT_IMAGE_TYPE(reference, PS_TYPE_F32, false); 429 if (input) { 430 PS_ASSERT_IMAGE_NON_NULL(input, false); 431 PS_ASSERT_IMAGES_SIZE_EQUAL(input, reference, false); 432 PS_ASSERT_IMAGE_TYPE(input, PS_TYPE_F32, false); 433 } 434 if (weight) { 435 PS_ASSERT_IMAGE_NON_NULL(weight, false); 436 PS_ASSERT_IMAGES_SIZE_EQUAL(weight, reference, false); 437 PS_ASSERT_IMAGE_TYPE(weight, PS_TYPE_F32, false); 438 } 406 PS_ASSERT_IMAGE_NON_NULL(image1, false); 407 PS_ASSERT_IMAGE_TYPE(image1, PS_TYPE_F32, false); 408 if (image2) { 409 PS_ASSERT_IMAGE_NON_NULL(image2, false); 410 PS_ASSERT_IMAGES_SIZE_EQUAL(image2, image1, false); 411 PS_ASSERT_IMAGE_TYPE(image2, PS_TYPE_F32, false); 412 } 413 PS_ASSERT_IMAGE_NON_NULL(weight, false); 414 PS_ASSERT_IMAGES_SIZE_EQUAL(weight, image1, false); 415 PS_ASSERT_IMAGE_TYPE(weight, PS_TYPE_F32, false); 439 416 PS_ASSERT_INT_NONNEGATIVE(footprint, false); 440 417 PS_ASSERT_INT_NONNEGATIVE(kernelSize, false); 441 418 442 int numCols = reference->numCols, numRows = reference->numRows; // Size of images419 int numCols = image1->numCols, numRows = image1->numRows; // Size of images 443 420 int size = kernelSize + footprint; // Size of postage stamps 444 445 if (!weight) {446 // Use the input (or if I must, the reference) as a rough approximation to the variance map, and HOPE447 // that it's positive.448 weight = input ? input : reference;449 }450 421 451 422 for (int i = 0; i < stamps->num; i++) { 452 423 pmSubtractionStamp *stamp = stamps->stamps->data[i]; // Stamp of interest 453 if (!stamp || stamp->status != PM_SUBTRACTION_STAMP_ CALCULATE) {424 if (!stamp || stamp->status != PM_SUBTRACTION_STAMP_FOUND) { 454 425 continue; 455 426 } … … 468 439 } 469 440 441 // Catch memory leaks --- these should have been freed and NULLed before 442 assert(stamp->image1 == NULL); 443 assert(stamp->image2 == NULL); 444 assert(stamp->weight == NULL); 445 470 446 psRegion region = psRegionSet(x - size, x + size + 1, y - size, y + size + 1); // Region of interest 471 447 472 psImage * refSub = psImageSubset(reference, region); // Subimage with stamp473 stamp-> reference = psKernelAllocFromImage(refSub, size, size);474 psFree( refSub);// Drop reference475 476 if (i nput) {477 psImage * inSub = psImageSubset(input, region); // Subimage with stamp478 stamp->i nput = psKernelAllocFromImage(inSub, size, size);479 psFree( inSub);// Drop reference448 psImage *sub1 = psImageSubset(image1, region); // Subimage with stamp 449 stamp->image1 = psKernelAllocFromImage(sub1, size, size); 450 psFree(sub1); // Drop reference 451 452 if (image2) { 453 psImage *sub2 = psImageSubset(image2, region); // Subimage with stamp 454 stamp->image2 = psKernelAllocFromImage(sub2, size, size); 455 psFree(sub2); // Drop reference 480 456 } 481 457 482 458 psImage *wtSub = psImageSubset(weight, region); // Subimage with stamp 483 459 stamp->weight = psKernelAllocFromImage(wtSub, size, size); 484 psFree(wtSub); // Drop reference 460 psFree(wtSub); // Drop reference 461 462 stamp->status = PM_SUBTRACTION_STAMP_CALCULATE; 485 463 } 486 464 … … 488 466 } 489 467 490 468 #if 0 491 469 bool pmSubtractionStampsGenerate(pmSubtractionStampList *stamps, float fwhm, int footprint, int kernelSize) 492 470 { … … 517 495 float yStamp = y - (int)(y + 0.5); // y coordinate of star in stamp frame 518 496 519 psFree(stamp->i nput);520 stamp->i nput= psKernelAlloc(-size, size, -size, size);521 psKernel * input = stamp->input; // Target stamp497 psFree(stamp->image2); 498 stamp->image2 = psKernelAlloc(-size, size, -size, size); 499 psKernel *target = stamp->image2; // Target stamp 522 500 523 501 // Put in a Waussian, just for fun! … … 525 503 for (int u = -size; u <= size; u++) { 526 504 float z = (PS_SQR(u + xStamp) + PS_SQR(v + yStamp)) / (2.0 * PS_SQR(sigma)); 527 input->kernel[v][u] = flux / sigma * 0.5 * M_2_SQRTPI * M_SQRT1_2 / (1.0 + z + PS_SQR(z));505 target->kernel[v][u] = flux / sigma * 0.5 * M_2_SQRTPI * M_SQRT1_2 / (1.0 + z + PS_SQR(z)); 528 506 } 529 507 } … … 533 511 return true; 534 512 } 535 513 #endif 536 514 537 515 pmSubtractionStampList *pmSubtractionStampsSetFromSources(const psArray *sources, const psImage *subMask, 538 516 const psRegion *region, float spacing, 539 int exclusionZone)517 pmSubtractionMode mode) 540 518 { 541 519 PS_ASSERT_ARRAY_NON_NULL(sources, NULL); … … 561 539 562 540 pmSubtractionStampList *stamps = pmSubtractionStampsSet(x, y, flux, NULL, subMask, region, 563 spacing, exclusionZone); // Stamps to return541 spacing, mode); // Stamps to return 564 542 psFree(x); 565 543 psFree(y); … … 572 550 return stamps; 573 551 } 552 553 554 pmSubtractionStampList *pmSubtractionStampsSetFromFile(const char *filename, const psImage *subMask, 555 const psRegion *region, float spacing, 556 pmSubtractionMode mode) 557 { 558 PS_ASSERT_STRING_NON_EMPTY(filename, NULL); 559 // Let pmSubtractionStampsSet take care of the rest of the assertions 560 561 const char *format = (mode == PM_SUBTRACTION_MODE_TARGET ? "%f %f %f" : "%f %f"); // Format of file 562 psArray *data = psVectorsReadFromFile(filename, format); 563 if (!data) { 564 psError(PS_ERR_IO, false, "Unable to read stamps file %s", filename); 565 return NULL; 566 } 567 psVector *x = data->data[0], *y = data->data[1]; // Stamp positions 568 psVector *flux = (mode == PM_SUBTRACTION_MODE_TARGET ? data->data[2] : NULL); // Stamp fluxes 569 570 // Correct for IRAF/FITS (unit-offset) positions to C (zero-offset) positions 571 psBinaryOp(x, x, "-", psScalarAlloc(1.0, PS_TYPE_F32)); 572 psBinaryOp(y, y, "-", psScalarAlloc(1.0, PS_TYPE_F32)); 573 574 pmSubtractionStampList *stamps = pmSubtractionStampsSet(x, y, flux, NULL, subMask, region, spacing, 575 mode); 576 psFree(data); 577 578 return stamps; 579 580 } -
trunk/psModules/src/imcombine/pmSubtractionStamps.h
r14802 r15443 9 9 typedef enum { 10 10 PM_SUBTRACTION_STAMP_INIT, ///< Initial state 11 PM_SUBTRACTION_STAMP_FOUND, ///< Found a suitable source for this stamp 12 PM_SUBTRACTION_STAMP_CALCULATE, ///< Calculate matrix and vector values for this stamp 11 13 PM_SUBTRACTION_STAMP_USED, ///< Use this stamp 12 14 PM_SUBTRACTION_STAMP_REJECTED, ///< This stamp has been rejected 13 PM_SUBTRACTION_STAMP_CALCULATE, ///< Calculate matrix and vector values for this stamp14 15 PM_SUBTRACTION_STAMP_NONE ///< No stamp in this region 15 16 } pmSubtractionStampStatus; … … 54 55 float flux; ///< Flux 55 56 float xNorm, yNorm; ///< Normalised position 56 psKernel * reference;///< Reference image postage stamp57 psKernel *i nput;///< Input image postage stamp57 psKernel *image1; ///< Reference image postage stamp 58 psKernel *image2; ///< Input image postage stamp 58 59 psKernel *weight; ///< Weight image postage stamp 59 psArray *convolutions; ///< Convolutions of the reference for each kernel component 60 psArray *convolutions1; ///< Convolutions of image 1 for each kernel component 61 psArray *convolutions2; ///< Convolutions of image 2 for each kernel component 60 62 psImage *matrix; ///< Associated matrix 61 63 psVector *vector; ///< Assoicated vector … … 72 74 const psRegion *region, ///< Region to search, or NULL 73 75 float threshold, ///< Threshold for stamps in the image 74 float spacing ///< Rough spacing for stamps 76 float spacing, ///< Rough spacing for stamps 77 pmSubtractionMode mode ///< Mode for subtraction 75 78 ); 76 79 77 80 /// Set stamps based on a list of x,y 78 ///79 /// We may optionally apply an exclusion zone around each star --- this is important when we're convolving to80 /// a specified PSF; less so when we're only trying to get a good subtraction.81 81 pmSubtractionStampList *pmSubtractionStampsSet(const psVector *x, ///< x coordinates for each stamp 82 82 const psVector *y, ///< y coordinates for each stamp … … 86 86 const psRegion *region, ///< Region to search, or NULL 87 87 float spacing, ///< Rough spacing for stamps 88 int exclusionZone ///< Exclusion zone around each star88 pmSubtractionMode mode ///< Mode for subtraction 89 89 ); 90 90 91 /// 91 /// Set stamps based on a list of sources 92 92 pmSubtractionStampList *pmSubtractionStampsSetFromSources( 93 const psArray *sources, ///< Sources for each stamp 94 const psImage *subMask, ///< Mask, or NULL 95 const psRegion *region, ///< Region to search, or NULL 96 float spacing, ///< Rough spacing for stamps 97 int exclusionZone ///< Exclusion zone around each star 93 const psArray *sources, ///< Sources for each stamp 94 const psImage *subMask, ///< Mask, or NULL 95 const psRegion *region, ///< Region to search, or NULL 96 float spacing, ///< Rough spacing for stamps 97 pmSubtractionMode mode ///< Mode for subtraction 98 ); 99 100 /// Set stamps based on values in a file 101 pmSubtractionStampList *pmSubtractionStampsSetFromFile( 102 const char *filename, ///< Filename of file containing x,y (or x,y,flux) on each line 103 const psImage *subMask, ///< Mask, or NULL 104 const psRegion *region, ///< Region to search, or NULL 105 float spacing, ///< Rough spacing for stamps 106 pmSubtractionMode mode ///< Mode for subtraction 98 107 ); 99 108 … … 107 116 ); 108 117 109 /// Generate target for stamps based on list110 bool pmSubtractionStampsGenerate(pmSubtractionStampList *stamps, ///< Stamps111 float fwhm, ///< FWHM for each stamp112 int footprint, ///< Stamp footprint size113 int size ///< Kernel half-size114 );115 116 118 #endif
Note:
See TracChangeset
for help on using the changeset viewer.
