Changeset 15443 for trunk/psModules/src/imcombine/pmSubtraction.c
- Timestamp:
- Nov 2, 2007, 4:28:24 PM (19 years ago)
- File:
-
- 1 edited
-
trunk/psModules/src/imcombine/pmSubtraction.c (modified) (25 diffs)
Legend:
- Unmodified
- Added
- Removed
-
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 }
Note:
See TracChangeset
for help on using the changeset viewer.
