Changeset 19129
- Timestamp:
- Aug 19, 2008, 6:06:31 PM (18 years ago)
- Location:
- trunk/psLib
- Files:
-
- 2 edited
-
src/imageops/psImageInterpolate.c (modified) (7 diffs)
-
test/imageops/tap_psImageInterpolate2.c (modified) (3 diffs)
Legend:
- Unmodified
- Added
- Removed
-
trunk/psLib/src/imageops/psImageInterpolate.c
r18300 r19129 7 7 * @author Paul Price, IfA 8 8 * 9 * @version $Revision: 1.1 6$ $Name: not supported by cvs2svn $10 * @date $Date: 2008-0 6-24 02:04:55$9 * @version $Revision: 1.17 $ $Name: not supported by cvs2svn $ 10 * @date $Date: 2008-08-20 04:06:31 $ 11 11 * 12 12 * Copyright 2004-2007 Institute for Astronomy, University of Hawaii … … 162 162 } 163 163 164 // Generate the interpolation kernel; it should be normalised to unity 164 // Generate the interpolation kernel 165 // No need to normalise to unity 165 166 static inline void interpolateKernelGenerate(int xNum, int yNum, // Size of interpolation kernel 166 167 double kernel[xNum][yNum], // Kernel, to be set … … 204 205 double yFrac = y - yCentral - 0.5; // Fraction of pixel in y 205 206 double sigma = 0.5; // Gaussian sigma 206 double norm = 0.0; // Normalisation207 207 for (int j = 0, yPos = - (yNum - 1) / 2; j < yNum; j++, yPos++) { 208 208 for (int i = 0, xPos = - (xNum - 1) / 2; i < xNum; i++, xPos++) { 209 norm += kernel[j][i] = exp(-0.5 / PS_SQR(sigma) * (PS_SQR(xPos - xFrac) + 210 PS_SQR(yPos - yFrac))); 211 } 212 } 213 norm = 1.0 / norm; 214 for (int j = 0; j < yNum; j++) { 215 for (int i = 0; i < xNum; i++) { 216 kernel[j][i] *= norm; 209 kernel[j][i] = exp(-0.5 / PS_SQR(sigma) * (PS_SQR(xPos - xFrac) + 210 PS_SQR(yPos - yFrac))); 217 211 } 218 212 } … … 228 222 } 229 223 224 // Set up and check interpolation bounds 225 // This macro defines many useful values 226 #define INTERPOLATE_BOUNDS() \ 227 int xLast = image->numCols - 1, yLast = image->numRows - 1; /* Last pixels of image */ \ 228 /* Start and stop of kernel on image */ \ 229 int xStart = xCentral - (xNum - 1) / 2, xStop = xCentral + xNum / 2; \ 230 int yStart = yCentral - (yNum - 1) / 2, yStop = yCentral + yNum / 2; \ 231 if (xStart > xLast || xStop < 0 || yStart > yLast || yStop < 0) { \ 232 /* Interpolation kernel is entirely off the image */ \ 233 *imageValue = options->badImage; \ 234 if (varianceValue) { \ 235 *varianceValue = options->badVariance; \ 236 } \ 237 if (maskValue) { \ 238 *maskValue = options->badMask; \ 239 } \ 240 return PS_INTERPOLATE_STATUS_OFF; \ 241 } \ 242 int xMin, xMax, yMin, yMax; /* Minimum and maximum valid pixels on image */ \ 243 int iMin, iMax, jMin, jMax; /* Minimum and maximum valid pixels on kernel */ \ 244 bool offImage = false; /* At least one pixel of the kernel is off the image */ \ 245 if (xStart < 0) { \ 246 xMin = 0; \ 247 iMin = -xStart; \ 248 offImage = true; \ 249 } else { \ 250 xMin = xStart; \ 251 iMin = 0; \ 252 } \ 253 if (xStop > xLast) { \ 254 xMax = xLast; \ 255 iMax = xStop - xLast; \ 256 offImage = true; \ 257 } else { \ 258 xMax = xStop; \ 259 iMax = xNum; \ 260 } \ 261 if (yStart < 0) { \ 262 yMin = 0; \ 263 jMin = -yStart; \ 264 offImage = true; \ 265 } else { \ 266 yMin = yStart; \ 267 jMin = 0; \ 268 } \ 269 if (yStop > yLast) { \ 270 yMax = yLast; \ 271 jMax = yStop - yLast; \ 272 offImage = true; \ 273 } else { \ 274 yMax = yStop; \ 275 jMax = yNum; \ 276 } 277 230 278 // Interpolation engine using interpolation kernel 231 279 static psImageInterpolateStatus interpolateKernel(double *imageValue, double *varianceValue, … … 240 288 241 289 const psImage *image = options->image; // Image of interest 242 int xLast = image->numCols - 1; // Last pixel in x 243 int yLast = image->numRows - 1; // Last pixel in y 244 245 if (xCentral - (xNum - 1) / 2 < 0 || xCentral + xNum / 2 > xLast || 246 yCentral - (yNum - 1) / 2 < 0 || yCentral + yNum / 2 > yLast) { 247 // At least one pixel of the interpolation kernel is off the image 248 if (imageValue) { 249 *imageValue = options->badImage; 250 } 251 if (varianceValue) { 252 *varianceValue = options->badVariance; 253 } 254 if (maskValue) { 255 *maskValue = options->badMask; 256 } 257 return PS_INTERPOLATE_STATUS_OFF; 258 } 290 const psImage *mask = options->mask; // Image mask 291 const psImage *variance = options->variance; // Image variance 292 293 INTERPOLATE_BOUNDS(); 259 294 260 295 double kernel[yNum][xNum]; // Interpolation kernel for straight interpolation 261 296 interpolateKernelGenerate(xNum, yNum, kernel, xCentral, yCentral, x, y, options->mode); 262 297 263 // Image interpolation, according to image type 264 #define KERNEL_IMAGE_CASE(TYPE) \ 265 case PS_TYPE_##TYPE: { \ 266 for (int j = 0, yPix = yCentral - (yNum - 1) / 2; j < yNum; j++, yPix++) { \ 267 for (int i = 0, xPix = xCentral - (xNum - 1) / 2; i < xNum; i++, xPix++) { \ 268 *imageValue += kernel[j][i] * image->data.TYPE[yPix][xPix]; \ 269 } \ 270 } \ 271 break; \ 272 } 273 274 // Calculate the value for the image 275 if (imageValue) { 276 *imageValue = 0.0; 277 switch (image->type.type) { 278 KERNEL_IMAGE_CASE(U8); 279 KERNEL_IMAGE_CASE(U16); 280 KERNEL_IMAGE_CASE(U32); 281 KERNEL_IMAGE_CASE(U64); 282 KERNEL_IMAGE_CASE(S8); 283 KERNEL_IMAGE_CASE(S16); 284 KERNEL_IMAGE_CASE(S32); 285 KERNEL_IMAGE_CASE(S64); 286 KERNEL_IMAGE_CASE(F32); 287 KERNEL_IMAGE_CASE(F64); 288 default: 289 psError(PS_ERR_BAD_PARAMETER_TYPE, true, "Unrecognised type for image: %x", 290 image->type.type); 291 return PS_INTERPOLATE_STATUS_ERROR; 292 } 293 } 294 295 // Check the mask value 296 const psImage *mask = options->mask; // Image mask 297 psImageInterpolateStatus status = PS_INTERPOLATE_STATUS_GOOD; // Status of interpolation 298 if (maskValue) { 299 *maskValue = 0; 300 if (mask) { 301 psMaskType maskVal = options->maskVal; // Mask value 302 double badContrib = 0.0; // Amount of kernel on bad pixels 303 double totContrib = 0.0; // Total amount of kernel 304 bool badPix = false; // Is there a bad pixel? 305 for (int j = 0, yPix = yCentral - (yNum - 1) / 2; j < yNum; j++, yPix++) { 306 for (int i = 0, xPix = xCentral - (xNum - 1) / 2; i < xNum; i++, xPix++) { 307 if (mask->data.PS_TYPE_MASK_DATA[yPix][xPix] & maskVal) { 308 badContrib += fabs(kernel[j][i]); 309 badPix = true; 310 } 311 *maskValue |= mask->data.PS_TYPE_MASK_DATA[yPix][xPix]; 312 totContrib += fabs(kernel[j][i]); 313 } 298 float sumKernel = 0.0; // Sum of the kernel 299 double sumKernel2 = 0.0; // Sum of the kernel-squared 300 float sumBad = 0.0; // Sum of bad kernel-squared contributions 301 psMaskType maskVal = options->maskVal; // Value to mask 302 double sumImage = 0.0; // Sum of image multiplied by kernel 303 double sumVariance = 0.0; // Sum of variance multiplied by kernel-squared 304 305 bool wantVariance = variance && varianceValue; // Does the user want the variance value? 306 bool haveMask = mask && maskVal; // Does the user want the variance value? 307 308 // Add contributions in an area outside the image 309 #define INTERPOLATE_KERNEL_ADD_OFFIMAGE() { \ 310 float kernelValue = kernel[j][i]; /* Value of kernel */ \ 311 double kernelValue2 = PS_SQR(kernelValue); /* Square of kernel */ \ 312 sumBad += kernelValue2; \ 313 sumKernel2 += kernelValue2; \ 314 } 315 316 // Measure kernel contribution from outside image 317 if (offImage) { 318 // Bottom rows 319 for (int j = 0; j < jMin; j++) { 320 for (int i = 0; i < xNum; i++) { 321 INTERPOLATE_KERNEL_ADD_OFFIMAGE(); 314 322 } 315 316 if (badPix) { 317 if (badContrib / totContrib >= options->poorFrac) { 318 *maskValue |= options->badMask; 319 status = PS_INTERPOLATE_STATUS_BAD; 320 } else { 321 *maskValue |= options->poorMask; 322 status = PS_INTERPOLATE_STATUS_POOR; 323 } 323 } 324 // Two sides 325 for (int j = jMin; j < jMax; j++) { 326 for (int i = 0; i < iMin; i++) { 327 INTERPOLATE_KERNEL_ADD_OFFIMAGE(); 324 328 } 325 } 326 } 327 328 // Finally, the variance 329 const psImage *variance = options->variance; // Image variance 330 if (varianceValue && variance) { 331 *varianceValue = 0.0; 332 333 // Variance interpolation, according to image type 334 #define KERNEL_VARIANCE_CASE(TYPE) \ 335 case PS_TYPE_##TYPE: { \ 336 double sumKernel2 = 0.0; /* Sum of kernel squares */ \ 337 for (int j = 0, yPix = yCentral - (yNum - 1) / 2; j < yNum; j++, yPix++) { \ 338 for (int i = 0, xPix = xCentral - (xNum - 1) / 2; i < xNum; i++, xPix++) { \ 339 double kernel2 = PS_SQR(kernel[j][i]); /* Kernel squared */ \ 340 sumKernel2 += kernel2; \ 341 *varianceValue += kernel2 * variance->data.TYPE[yPix][xPix]; \ 342 } \ 343 } \ 344 *varianceValue /= sumKernel2; /* Normalise so that sum of kernel squares is unity */ \ 345 break; \ 329 for (int i = iMax + 1; i < xNum; i++) { 330 INTERPOLATE_KERNEL_ADD_OFFIMAGE(); 346 331 } 347 348 switch (variance->type.type) { 349 KERNEL_VARIANCE_CASE(U8); 350 KERNEL_VARIANCE_CASE(U16); 351 KERNEL_VARIANCE_CASE(U32); 352 KERNEL_VARIANCE_CASE(U64); 353 KERNEL_VARIANCE_CASE(S8); 354 KERNEL_VARIANCE_CASE(S16); 355 KERNEL_VARIANCE_CASE(S32); 356 KERNEL_VARIANCE_CASE(S64); 357 KERNEL_VARIANCE_CASE(F32); 358 KERNEL_VARIANCE_CASE(F64); 359 default: 360 psError(PS_ERR_BAD_PARAMETER_TYPE, true, "Unrecognised type for image: %x", 361 image->type.type); 362 return PS_INTERPOLATE_STATUS_ERROR; 363 } 332 } 333 // Top rows 334 for (int j = jMax + 1; j < yNum; j++) { 335 for (int i = 0; i < xNum; i++) { 336 INTERPOLATE_KERNEL_ADD_OFFIMAGE(); 337 } 338 } 339 } 340 341 #define INTERPOLATE_KERNEL_CASE(TYPE) \ 342 case PS_TYPE_##TYPE: { \ 343 if (wantVariance) { \ 344 if (haveMask) { \ 345 /* Variance and mask */ \ 346 for (int j = jMin, yPix = yMin; j < jMax; j++, yPix++) { \ 347 for (int i = iMin, xPix = xMin; i < iMax; i++, xPix++) { \ 348 float kernelValue = kernel[j][i]; /* Value of kernel */ \ 349 double kernelValue2 = PS_SQR(kernelValue); /* Square of kernel */ \ 350 if (mask->data.PS_TYPE_MASK_DATA[yPix][xPix] & maskVal) { \ 351 sumBad += kernelValue2; \ 352 } else { \ 353 sumImage += kernelValue * image->data.TYPE[yPix][xPix]; \ 354 sumVariance += kernelValue2 * variance->data.TYPE[yPix][xPix]; \ 355 sumKernel += kernelValue; \ 356 } \ 357 sumKernel2 += PS_SQR(kernelValue); \ 358 } \ 359 } \ 360 \ 361 } else { \ 362 /* Variance, no mask */ \ 363 for (int j = jMin, yPix = yMin; j < jMax; j++, yPix++) { \ 364 for (int i = iMin, xPix = xMin; i < iMax; i++, xPix++) { \ 365 float kernelValue = kernel[j][i]; /* Value of kernel */ \ 366 double kernelValue2 = PS_SQR(kernelValue); /* Square of kernel */ \ 367 sumImage += kernelValue * image->data.TYPE[yPix][xPix]; \ 368 sumVariance += kernelValue2 * variance->data.TYPE[yPix][xPix]; \ 369 sumKernel += kernelValue; \ 370 sumKernel2 += kernelValue2; \ 371 } \ 372 } \ 373 } \ 374 } else if (haveMask) { \ 375 /* Mask, no variance */ \ 376 for (int j = jMin, yPix = yMin; j < jMax; j++, yPix++) { \ 377 for (int i = iMin, xPix = xMin; i < iMax; i++, xPix++) { \ 378 float kernelValue = kernel[j][i]; /* Value of kernel */ \ 379 if (mask->data.PS_TYPE_MASK_DATA[yPix][xPix] & maskVal) { \ 380 sumBad += PS_SQR(kernelValue); \ 381 } else { \ 382 sumImage += kernelValue * image->data.TYPE[yPix][xPix]; \ 383 sumKernel += kernelValue; \ 384 } \ 385 sumKernel2 += PS_SQR(kernelValue); \ 386 } \ 387 } \ 388 } else { \ 389 /* Neither variance nor mask */ \ 390 for (int j = jMin, yPix = yMin; j < jMax; j++, yPix++) { \ 391 for (int i = iMin, xPix = xMin; i < iMax; i++, xPix++) { \ 392 float kernelValue = kernel[j][i]; /* Value of kernel */ \ 393 sumImage += kernelValue * image->data.TYPE[yPix][xPix]; \ 394 sumKernel += kernelValue; \ 395 } \ 396 } \ 397 } \ 398 } \ 399 break; 400 401 402 switch (image->type.type) { 403 INTERPOLATE_KERNEL_CASE(U8); 404 INTERPOLATE_KERNEL_CASE(U16); 405 INTERPOLATE_KERNEL_CASE(U32); 406 INTERPOLATE_KERNEL_CASE(U64); 407 INTERPOLATE_KERNEL_CASE(S8); 408 INTERPOLATE_KERNEL_CASE(S16); 409 INTERPOLATE_KERNEL_CASE(S32); 410 INTERPOLATE_KERNEL_CASE(S64); 411 INTERPOLATE_KERNEL_CASE(F32); 412 INTERPOLATE_KERNEL_CASE(F64); 413 default: 414 psError(PS_ERR_BAD_PARAMETER_TYPE, true, "Unrecognised type for image: %x", 415 image->type.type); 416 return PS_INTERPOLATE_STATUS_ERROR; 417 } 418 419 psImageInterpolateStatus status = PS_INTERPOLATE_STATUS_ERROR; // Status of interpolation 420 *imageValue = sumImage / sumKernel; 421 if (wantVariance) { 422 *varianceValue = sumVariance * PS_SQR(sumKernel) / sumKernel2; 423 } 424 if (sumBad == 0) { 425 // Completely good pixel 426 status = PS_INTERPOLATE_STATUS_GOOD; 427 } else if (sumBad / sumKernel2 < PS_SQR(options->poorFrac)) { 428 // Some pixels masked: poor pixel 429 if (haveMask && maskValue) { 430 *maskValue |= options->poorMask; 431 } 432 status = PS_INTERPOLATE_STATUS_POOR; 433 } else { 434 // Many pixels (or a few important pixels) masked: bad pixel 435 if (haveMask && maskValue) { 436 *maskValue |= options->badMask; 437 } 438 status = PS_INTERPOLATE_STATUS_BAD; 364 439 } 365 440 … … 472 547 473 548 const psImage *image = options->image; // Image of interest 474 int xLast = image->numCols - 1; // Last pixel in x 475 int yLast = image->numRows - 1; // Last pixel in y 476 477 if (xCentral - (xNum - 1) / 2 < 0 || xCentral + xNum / 2 > xLast || 478 yCentral - (yNum - 1) / 2 < 0 || yCentral + yNum / 2 > yLast) { 479 // At least one pixel of the interpolation kernel is off the image 480 if (imageValue) { 481 *imageValue = options->badImage; 482 } 483 if (varianceValue) { 484 *varianceValue = options->badVariance; 485 } 486 if (maskValue) { 487 *maskValue = options->badMask; 488 } 489 return PS_INTERPOLATE_STATUS_OFF; 490 } 549 const psImage *mask = options->mask; // Image mask 550 const psImage *variance = options->variance; // Image variance 551 552 INTERPOLATE_BOUNDS(); 491 553 492 554 double xKernel[xNum], yKernel[yNum]; // Interpolation kernels 493 555 interpolateSeparateGenerate(xNum, yNum, xKernel, yKernel, xCentral, yCentral, x, y, options->mode); 494 556 495 // Image interpolation, according to image type 496 #define SEPARATE_IMAGE_CASE(TYPE) \ 497 case PS_TYPE_##TYPE: { \ 498 for (int j = 0, yPix = yCentral - (yNum - 1) / 2; j < yNum; j++, yPix++) { \ 499 double xInterpValue = 0.0; /* Interpolation in x */ \ 500 for (int i = 0, xPix = xCentral - (xNum - 1) / 2; i < xNum; i++, xPix++) { \ 501 xInterpValue += xKernel[i] * image->data.TYPE[yPix][xPix]; \ 502 } \ 503 *imageValue += yKernel[j] * xInterpValue; /* Interpolating in y */ \ 504 } \ 505 break; \ 506 } 507 508 // Calculate the value for the image 509 if (imageValue) { 510 *imageValue = 0.0; 511 switch (image->type.type) { 512 SEPARATE_IMAGE_CASE(U8); 513 SEPARATE_IMAGE_CASE(U16); 514 SEPARATE_IMAGE_CASE(U32); 515 SEPARATE_IMAGE_CASE(U64); 516 SEPARATE_IMAGE_CASE(S8); 517 SEPARATE_IMAGE_CASE(S16); 518 SEPARATE_IMAGE_CASE(S32); 519 SEPARATE_IMAGE_CASE(S64); 520 SEPARATE_IMAGE_CASE(F32); 521 SEPARATE_IMAGE_CASE(F64); 522 default: 523 psError(PS_ERR_BAD_PARAMETER_TYPE, true, "Unrecognised type for image: %x", 524 image->type.type); 525 return PS_INTERPOLATE_STATUS_ERROR; 526 } 527 } 528 529 // Check the mask value 530 const psImage *mask = options->mask; // Image mask 531 psImageInterpolateStatus status = PS_INTERPOLATE_STATUS_GOOD; // Status of interpolation 532 if (maskValue) { 533 *maskValue = 0; 534 if (mask) { 535 psMaskType maskVal = options->maskVal; // Mask value 536 double badContrib = 0.0; // Amount of kernel on bad pixels 537 double totContrib = 0.0; // Total amount of kernel 538 bool badPix = false; // Number of bad pixels 539 for (int j = 0, yPix = yCentral - (yNum - 1) / 2; j < yNum; j++, yPix++) { 540 // Interpolation in x 541 double xBadContrib = 0.0; // Amount of x kernel on bad pixels 542 double xTotContrib = 0.0; // Total amount of x kernel 543 for (int i = 0, xPix = xCentral - (xNum - 1) / 2; i < xNum; i++, xPix++) { 544 if (mask->data.PS_TYPE_MASK_DATA[yPix][xPix] & maskVal) { 545 xBadContrib += fabs(xKernel[i]); 546 badPix = true; 547 } 548 *maskValue |= mask->data.PS_TYPE_MASK_DATA[yPix][xPix]; 549 xTotContrib += fabs(xKernel[i]); 550 } 551 // Interpolating in y 552 badContrib += fabs(yKernel[j]) * xBadContrib; 553 totContrib += fabs(yKernel[j]) * xTotContrib; 557 float sumKernel = 0.0; // Sum of the kernel 558 double sumKernel2 = 0.0; // Sum of the kernel-squared 559 float sumBad = 0.0; // Sum of bad kernel-squared contributions 560 psMaskType maskVal = options->maskVal; // Value to mask 561 double sumImage = 0.0; // Sum of image multiplied by kernel 562 double sumVariance = 0.0; // Sum of variance multiplied by kernel-squared 563 564 bool wantVariance = variance && varianceValue; // Does the user want the variance value? 565 bool haveMask = mask && maskVal; // Does the user want the variance value? 566 567 // Add contributions in an area outside the image 568 #define INTERPOLATE_SEPARATE_SETUP_OFFIMAGE_COL() \ 569 float xSumBad = 0.0; \ 570 double xSumKernel2 = 0.0; 571 #define INTERPOLATE_SEPARATE_ADD_OFFIMAGE_COL() { \ 572 float kernelValue = xKernel[i]; /* Value of kernel */ \ 573 double kernelValue2 = PS_SQR(kernelValue); /* Square of kernel */ \ 574 xSumBad += kernelValue2; \ 575 xSumKernel2 += kernelValue2; \ 576 } 577 #define INTERPOLATE_SEPARATE_ADD_OFFIMAGE_ROW() { \ 578 float kernelValue = yKernel[j]; /* Value of kernel */ \ 579 double kernelValue2 = PS_SQR(kernelValue); /* Square of kernel */ \ 580 sumBad += kernelValue2 * xSumBad; \ 581 sumKernel2 += kernelValue2 * xSumKernel2; \ 582 } 583 584 // Measure kernel contribution from outside image 585 if (offImage) { 586 // Bottom rows 587 for (int j = 0; j < jMin; j++) { 588 INTERPOLATE_SEPARATE_SETUP_OFFIMAGE_COL(); 589 for (int i = 0; i < xNum; i++) { 590 INTERPOLATE_SEPARATE_ADD_OFFIMAGE_COL(); 554 591 } 555 556 if (badPix) { 557 if (badContrib / totContrib >= options->poorFrac) { 558 *maskValue |= options->badMask; 559 status = PS_INTERPOLATE_STATUS_BAD; 560 } else { 561 *maskValue |= options->poorMask; 562 status = PS_INTERPOLATE_STATUS_POOR; 563 } 592 INTERPOLATE_SEPARATE_ADD_OFFIMAGE_ROW(); 593 } 594 // Two sides 595 for (int j = jMin; j < jMax; j++) { 596 INTERPOLATE_SEPARATE_SETUP_OFFIMAGE_COL(); 597 for (int i = 0; i < iMin; i++) { 598 INTERPOLATE_SEPARATE_ADD_OFFIMAGE_COL(); 564 599 } 565 } 566 } 567 568 // Finally, the variance 569 const psImage *variance = options->variance; // Image variance 570 if (varianceValue && variance) { 571 *varianceValue = 0.0; 572 573 // Variance interpolation, according to image type 574 #define SEPARATE_VARIANCE_CASE(TYPE) \ 575 case PS_TYPE_##TYPE: { \ 576 double ySumKernel2 = 0.0; /* Sum of kernel squared in y */ \ 577 for (int j = 0, yPix = yCentral - (yNum - 1) / 2; j < yNum; j++, yPix++) { \ 578 double xSumKernel2 = 0.0; /* Sum of kernel squared in x */ \ 579 double xInterpValue = 0.0; /* Interpolation in x */ \ 580 for (int i = 0, xPix = xCentral - (xNum - 1) / 2; i < xNum; i++, xPix++) { \ 581 double kernel2 = PS_SQR(xKernel[i]); /* Kernel squared */ \ 582 xSumKernel2 += kernel2; \ 583 xInterpValue += kernel2 * variance->data.TYPE[yPix][xPix]; \ 584 } \ 585 double kernel2 = PS_SQR(yKernel[j]); /* Kernel squared */ \ 586 ySumKernel2 += xSumKernel2 * kernel2; \ 587 *varianceValue += xInterpValue * kernel2; /* Interpolating in y */ \ 588 } \ 589 *varianceValue /= ySumKernel2; \ 590 break; \ 591 } 592 593 switch (variance->type.type) { 594 SEPARATE_VARIANCE_CASE(U8); 595 SEPARATE_VARIANCE_CASE(U16); 596 SEPARATE_VARIANCE_CASE(U32); 597 SEPARATE_VARIANCE_CASE(U64); 598 SEPARATE_VARIANCE_CASE(S8); 599 SEPARATE_VARIANCE_CASE(S16); 600 SEPARATE_VARIANCE_CASE(S32); 601 SEPARATE_VARIANCE_CASE(S64); 602 SEPARATE_VARIANCE_CASE(F32); 603 SEPARATE_VARIANCE_CASE(F64); 604 default: 605 psError(PS_ERR_BAD_PARAMETER_TYPE, true, "Unrecognised type for image: %x", 606 variance->type.type); 607 return PS_INTERPOLATE_STATUS_ERROR; 608 } 600 for (int i = iMax + 1; i < xNum; i++) { 601 INTERPOLATE_SEPARATE_ADD_OFFIMAGE_COL(); 602 } 603 INTERPOLATE_SEPARATE_ADD_OFFIMAGE_ROW(); 604 } 605 // Top rows 606 for (int j = jMax + 1; j < yNum; j++) { 607 INTERPOLATE_SEPARATE_SETUP_OFFIMAGE_COL(); 608 for (int i = 0; i < xNum; i++) { 609 INTERPOLATE_SEPARATE_ADD_OFFIMAGE_COL(); 610 } 611 INTERPOLATE_SEPARATE_ADD_OFFIMAGE_ROW(); 612 } 613 } 614 615 #define INTERPOLATE_SEPARATE_CASE(TYPE) \ 616 case PS_TYPE_##TYPE: { \ 617 if (wantVariance) { \ 618 if (haveMask) { \ 619 /* Variance and mask */ \ 620 for (int j = jMin, yPix = yMin; j < jMax; j++, yPix++) { \ 621 double xSumImage = 0.0; /* Sum of image multiplied by kernel in x */ \ 622 double xSumVariance = 0.0; /* Sum of image multiplied by kernel-squared in x */ \ 623 float xSumKernel = 0.0; /* Sum of kernel in x */ \ 624 double xSumKernel2 = 0.0; /* Sum of kernel-squared in x */ \ 625 float xSumBad = 0.0; /* Sum of bad kernel-squared in x */ \ 626 for (int i = iMin, xPix = xMin; i < iMax; i++, xPix++) { \ 627 float kernelValue = xKernel[i]; /* Value of kernel in x */ \ 628 double kernelValue2 = PS_SQR(kernelValue); /* Square of kernel in x */ \ 629 if (mask->data.PS_TYPE_MASK_DATA[yPix][xPix] & maskVal) { \ 630 xSumBad += kernelValue2; \ 631 } else { \ 632 xSumImage += kernelValue * image->data.TYPE[yPix][xPix]; \ 633 xSumVariance += kernelValue2 * variance->data.TYPE[yPix][xPix]; \ 634 xSumKernel += kernelValue; \ 635 } \ 636 xSumKernel2 += kernelValue2; \ 637 } \ 638 float kernelValue = yKernel[j]; /* Value of kernel in y */ \ 639 double kernelValue2 = PS_SQR(kernelValue); /* Value of kernel-squared in y */ \ 640 sumImage += kernelValue * xSumImage; \ 641 sumVariance += kernelValue2 * xSumVariance; \ 642 sumBad += kernelValue2 * xSumBad; \ 643 sumKernel += kernelValue * xSumKernel; \ 644 sumKernel2 += kernelValue2 * xSumKernel2; \ 645 } \ 646 } else { \ 647 /* Variance, no mask */ \ 648 for (int j = jMin, yPix = yMin; j < jMax; j++, yPix++) { \ 649 double xSumImage = 0.0; /* Sum of image multiplied by kernel in x */ \ 650 double xSumVariance = 0.0; /* Sum of image multiplied by kernel-squared in x */ \ 651 float xSumKernel = 0.0; /* Sum of kernel in x */ \ 652 double xSumKernel2 = 0.0; /* Sum of kernel-squared in x */ \ 653 for (int i = iMin, xPix = xMin; i < iMax; i++, xPix++) { \ 654 float kernelValue = xKernel[i]; /* Value of kernel */ \ 655 double kernelValue2 = PS_SQR(kernelValue); /* Square of kernel */ \ 656 xSumImage += kernelValue * image->data.TYPE[yPix][xPix]; \ 657 xSumVariance += kernelValue2 * variance->data.TYPE[yPix][xPix]; \ 658 xSumKernel += kernelValue; \ 659 xSumKernel2 += kernelValue2; \ 660 } \ 661 float kernelValue = yKernel[j]; /* Value of kernel in y */ \ 662 double kernelValue2 = PS_SQR(kernelValue); /* Value of kernel-squared in y */ \ 663 sumImage += kernelValue * xSumImage; \ 664 sumVariance += kernelValue2 * xSumVariance; \ 665 sumKernel += kernelValue * xSumKernel; \ 666 sumKernel2 += kernelValue2 * xSumKernel2; \ 667 } \ 668 } \ 669 } else if (haveMask) { \ 670 /* Mask, no variance */ \ 671 for (int j = jMin, yPix = yMin; j < jMax; j++, yPix++) { \ 672 double xSumImage = 0.0; /* Sum of image multiplied by kernel in x */ \ 673 float xSumKernel = 0.0; /* Sum of kernel in x */ \ 674 double xSumKernel2 = 0.0; /* Sum of kernel-squared in x */ \ 675 float xSumBad = 0.0; /* Sum of bad kernel-squared in x */ \ 676 for (int i = iMin, xPix = xMin; i < iMax; i++, xPix++) { \ 677 float kernelValue = xKernel[i]; /* Value of kernel */ \ 678 double kernelValue2 = PS_SQR(kernelValue); /* Value of kernel-squared */ \ 679 if (mask->data.PS_TYPE_MASK_DATA[yPix][xPix] & maskVal) { \ 680 xSumBad += kernelValue2; \ 681 } else { \ 682 xSumImage += kernelValue * image->data.TYPE[yPix][xPix]; \ 683 xSumKernel += kernelValue; \ 684 } \ 685 xSumKernel2 += kernelValue2; \ 686 } \ 687 float kernelValue = yKernel[j]; /* Value of kernel in y */ \ 688 double kernelValue2 = PS_SQR(kernelValue); /* Value of kernel-squared in y */ \ 689 sumImage += kernelValue * xSumImage; \ 690 sumBad += kernelValue2 * xSumBad; \ 691 sumKernel += kernelValue * xSumKernel; \ 692 sumKernel2 += kernelValue2 * xSumKernel2; \ 693 } \ 694 } else {\ 695 /* Neither variance nor mask */ \ 696 for (int j = jMin, yPix = yMin; j < jMax; j++, yPix++) { \ 697 double xSumImage = 0.0; /* Sum of image multiplied by kernel in x */ \ 698 float xSumKernel = 0.0; /* Sum of kernel in x */ \ 699 for (int i = iMin, xPix = xMin; i < iMax; i++, xPix++) { \ 700 float kernelValue = xKernel[i]; /* Value of kernel */ \ 701 xSumImage += kernelValue * image->data.TYPE[yPix][xPix]; \ 702 xSumKernel += kernelValue; \ 703 } \ 704 float kernelValue = yKernel[j]; /* Value of kernel in y */ \ 705 sumImage += kernelValue * xSumImage; \ 706 sumKernel += kernelValue * xSumKernel; \ 707 } \ 708 } \ 709 } \ 710 break; 711 712 713 switch (image->type.type) { 714 INTERPOLATE_SEPARATE_CASE(U8); 715 INTERPOLATE_SEPARATE_CASE(U16); 716 INTERPOLATE_SEPARATE_CASE(U32); 717 INTERPOLATE_SEPARATE_CASE(U64); 718 INTERPOLATE_SEPARATE_CASE(S8); 719 INTERPOLATE_SEPARATE_CASE(S16); 720 INTERPOLATE_SEPARATE_CASE(S32); 721 INTERPOLATE_SEPARATE_CASE(S64); 722 INTERPOLATE_SEPARATE_CASE(F32); 723 INTERPOLATE_SEPARATE_CASE(F64); 724 default: 725 psError(PS_ERR_BAD_PARAMETER_TYPE, true, "Unrecognised type for image: %x", 726 image->type.type); 727 return PS_INTERPOLATE_STATUS_ERROR; 728 } 729 730 psImageInterpolateStatus status = PS_INTERPOLATE_STATUS_ERROR; // Status of interpolation 731 *imageValue = sumImage / sumKernel; 732 if (wantVariance) { 733 *varianceValue = sumVariance * PS_SQR(sumKernel) / sumKernel2; 734 } 735 if (sumBad == 0) { 736 // Completely good pixel 737 status = PS_INTERPOLATE_STATUS_GOOD; 738 } else if (sumBad / sumKernel2 < PS_SQR(options->poorFrac)) { 739 // Some pixels masked: poor pixel 740 if (haveMask && maskValue) { 741 *maskValue |= options->poorMask; 742 } 743 status = PS_INTERPOLATE_STATUS_POOR; 744 } else { 745 // Many pixels (or a few important pixels) masked: bad pixel 746 if (haveMask && maskValue) { 747 *maskValue |= options->badMask; 748 } 749 status = PS_INTERPOLATE_STATUS_BAD; 609 750 } 610 751 … … 617 758 float x, float y, const psImageInterpolateOptions *options) 618 759 { 760 PS_ASSERT_PTR_NON_NULL(imageValue, PS_INTERPOLATE_STATUS_ERROR); 619 761 PS_ASSERT_PTR_NON_NULL(options, PS_INTERPOLATE_STATUS_ERROR); 620 762 -
trunk/psLib/test/imageops/tap_psImageInterpolate2.c
r12812 r19129 86 86 87 87 for (int i = 0; i < num; i++) { 88 float x = psRandomUniform(rng) * xSize;89 float y = psRandomUniform(rng) * ySize;88 float x = psRandomUniform(rng) * (xSize - 1); 89 float y = psRandomUniform(rng) * (ySize - 1); 90 90 91 91 // Values from interpolation … … 93 93 psMaskType maskVal; 94 94 95 bool success = psImageInterpolate(&imageVal, &varianceVal, &maskVal, x, y, interp);96 ok(s uccess, "Interpolation at %.2f,%.2f", x, y);97 skip_start( !success, 1, "Interpolation failed");95 psImageInterpolateStatus status = psImageInterpolate(&imageVal, &varianceVal, &maskVal, x, y, interp); 96 ok(status != PS_INTERPOLATE_STATUS_ERROR, "Interpolation at %.2f,%.2f (%x)", x, y, status); 97 skip_start(status == PS_INTERPOLATE_STATUS_ERROR, 1, "Interpolation failed"); 98 98 99 99 int xCentral, yCentral; // Central pixel of interpolation … … 112 112 if (xCentral - (xKernel - 1) / 2 < 0 || xCentral + xKernel / 2 > xSize - 1 || 113 113 yCentral - (yKernel - 1) / 2 < 0 || yCentral + yKernel / 2 > ySize - 1) { 114 ok(isnan(imageVal), "Interpolation = %f vs NAN (border)", imageVal); 114 ok(status == PS_INTERPOLATE_STATUS_BAD || status == PS_INTERPOLATE_STATUS_POOR, 115 "Interpolation at border"); 115 116 } else { 116 117 is_double_tol(imageVal, imageFunc(x, y), tol, "Interpolation = %f vs %f",
Note:
See TracChangeset
for help on using the changeset viewer.
