Changeset 15630 for trunk/psLib/src/fits/psFitsImage.c
- Timestamp:
- Nov 15, 2007, 3:04:56 PM (18 years ago)
- File:
-
- 1 edited
-
trunk/psLib/src/fits/psFitsImage.c (modified) (26 diffs)
Legend:
- Unmodified
- Added
- Removed
-
trunk/psLib/src/fits/psFitsImage.c
r15335 r15630 7 7 * @author Robert DeSonia, MHPCC 8 8 * 9 * @version $Revision: 1. 19$ $Name: not supported by cvs2svn $10 * @date $Date: 2007-1 0-19 23:52:39$9 * @version $Revision: 1.20 $ $Name: not supported by cvs2svn $ 10 * @date $Date: 2007-11-16 01:04:56 $ 11 11 * 12 12 * Copyright 2004-2005 Maui High Performance Computing Center, University of Hawaii … … 21 21 #include <string.h> 22 22 23 #include "psFits.h" 23 #include "psAbort.h" 24 #include "psType.h" 24 25 #include "psAssert.h" 25 #include "psFitsImage.h"26 26 #include "psError.h" 27 28 #include "psImageStructManip.h"29 #include "psMemory.h"30 27 #include "psString.h" 31 28 #include "psLogMsg.h" 32 29 #include "psTrace.h" 33 30 #include "psVector.h" 34 31 #include "psRandom.h" 32 #include "psImageStructManip.h" 33 34 #include "psFits.h" 35 #include "psFitsFloat.h" 36 #include "psFitsFloatFile.h" 35 37 #include "psFitsHeader.h" 36 38 37 #define MAX_STRING_LENGTH 256 // maximum length string for FITS routines 39 #include "psMemory.h" 40 41 #include "psFitsImage.h" 42 43 #define MAX_STRING_LENGTH 256 // maximum length string for FITS routines 38 44 39 45 // Information required to read a FITS file … … 49 55 } p_psFitsReadInfo; 50 56 51 static p_psFitsReadInfo *p_psFitsReadInfoAlloc(const psFits *fits, // The FITS file handle 52 psRegion region, // Region to read 53 int z // z-plane to read in cube 54 ) 57 // Read the vital statistics of this FITS image, in preparation for reading the image 58 static p_psFitsReadInfo *p_psFitsReadInfoAlloc( 59 const psFits *fits, // The FITS file handle 60 psRegion region, // Region to read 61 int z // z-plane to read in cube 62 ) 55 63 { 56 64 PS_ASSERT_FITS_NON_NULL(fits, NULL); … … 61 69 62 70 int status = 0; // CFITSIO status 63 char fitsErr[80]; // CFITSIO error message string64 71 65 72 // check to see if we even are positioned on an image HDU 66 73 int hduType; // Type of HDU 67 74 if (fits_get_hdu_type(fits->fd, &hduType, &status) != 0) { 68 (void)fits_get_errstatus(status, fitsErr); 69 psError(PS_ERR_IO, true, 70 _("Could not determine the HDU type. CFITSIO Error: %s"), 71 fitsErr); 75 psFitsError(status, true, "Could not determine the HDU type."); 72 76 goto bad; 73 77 } 74 78 if (hduType != IMAGE_HDU) { 75 psError(PS_ERR_IO, true, 76 _("Current FITS HDU type must be an image.")); 79 psError(PS_ERR_IO, true, _("Current FITS HDU type must be an image.")); 77 80 goto bad; 78 81 } … … 80 83 // Get the data type 'bitPix' from the FITS image 81 84 if (fits_get_img_equivtype(fits->fd, &info->bitPix, &status) != 0) { 82 fits_get_errstatus(status, fitsErr); 83 psError(PS_ERR_IO, true, 84 _("Could not determine image data type. CFITSIO Error: %s"), 85 fitsErr); 85 psFitsError(status, true, "Could not determine image data type."); 86 86 goto bad; 87 87 } … … 89 89 /* Get the dimensions 'nAxis' from the FITS image */ 90 90 if (fits_get_img_dim(fits->fd, &info->nAxis, &status) != 0) { 91 (void)fits_get_errstatus(status, fitsErr); 92 psError(PS_ERR_IO, true, 93 _("Could not determine image dimensions. CFITSIO Error: %s"), 94 fitsErr); 91 psFitsError(status, true, "Could not determine image dimensions."); 95 92 goto bad; 96 93 } … … 99 96 if ((info->nAxis < 2) || (info->nAxis > 3)) { 100 97 psError(PS_ERR_IO, true, 101 _("Image number of dimensions, %d, is not valid. Only two or three dimensions supported for FITS I/O."), 102 info->nAxis); 98 _("Image number of dimensions, %d, is not supported."), info->nAxis); 103 99 goto bad; 104 100 } … … 106 102 /* Get the Image size from the FITS file */ 107 103 if (fits_get_img_size(fits->fd, info->nAxis, info->nAxes, &status) != 0) { 108 (void)fits_get_errstatus(status, fitsErr); 109 psError(PS_ERR_IO, true, 110 _("Could not determine image size. CFITSIO Error: %s"), 111 fitsErr); 104 psFitsError(status, true, "Could not determine image size."); 112 105 goto bad; 113 106 } … … 133 126 info->increment[2] = 1; 134 127 135 switch (info->bitPix) { 136 case BYTE_IMG: 137 info->psDatatype = PS_TYPE_U8; 138 info->fitsDatatype = TBYTE; 139 break; 140 case SBYTE_IMG: 141 info->psDatatype = PS_TYPE_S8; 142 info->fitsDatatype = TSBYTE; 143 break; 144 case USHORT_IMG: 145 info->psDatatype = PS_TYPE_U16; 146 info->fitsDatatype = TUSHORT; 147 break; 148 case SHORT_IMG: 149 info->psDatatype = PS_TYPE_S16; 150 info->fitsDatatype = TSHORT; 151 break; 152 case ULONG_IMG: 153 info->psDatatype = PS_TYPE_U32; 154 info->fitsDatatype = TUINT; 155 break; 156 case LONG_IMG: 157 info->psDatatype = PS_TYPE_S32; 158 info->fitsDatatype = TINT; 159 break; 160 case LONGLONG_IMG: 161 info->psDatatype = PS_TYPE_S64; 162 info->fitsDatatype = TLONGLONG; 163 break; 164 case FLOAT_IMG: 165 info->psDatatype = PS_TYPE_F32; 166 info->fitsDatatype = TFLOAT; 167 break; 168 case DOUBLE_IMG: 169 info->psDatatype = PS_TYPE_F64; 170 info->fitsDatatype = TDOUBLE; 171 break; 172 default: 173 psError(PS_ERR_IO, true, 174 _("FITS image type, BITPIX=%d, is not supported."), 175 info->bitPix); 128 // Check scale and zero 129 double bscale = 0.0, bzero = 0.0; // Scale and zero point 130 if (fits_read_key_dbl(fits->fd, "BSCALE", &bscale, NULL, &status) && status != KEY_NO_EXIST) { 131 psFitsError(status, true, "Unable to read header."); 176 132 goto bad; 177 133 } 178 134 status = 0; 135 if (fits_read_key_dbl(fits->fd, "BZERO", &bzero, NULL, &status) && status != KEY_NO_EXIST) { 136 psFitsError(status, true, "Unable to read header."); 137 goto bad; 138 } 139 status = 0; 140 141 if ((bscale != 0.0 && bscale != 1.0) || bzero != (int)bzero) { 142 // It's a floating-point image that's been quantised 143 // cfitsio will apply the scale and zero point for us if we choose the correct data type 144 switch (info->bitPix) { 145 case BYTE_IMG: 146 case SBYTE_IMG: 147 case USHORT_IMG: 148 case SHORT_IMG: 149 case ULONG_IMG: 150 case LONG_IMG: 151 case FLOAT_IMG: 152 info->psDatatype = PS_TYPE_F32; 153 info->fitsDatatype = TFLOAT; 154 break; 155 case LONGLONG_IMG: 156 case DOUBLE_IMG: 157 info->psDatatype = PS_TYPE_F64; 158 info->fitsDatatype = TDOUBLE; 159 break; 160 default: 161 psError(PS_ERR_IO, true, _("FITS image type, BITPIX=%d, is not supported."), info->bitPix); 162 goto bad; 163 } 164 } else { 165 switch (info->bitPix) { 166 case BYTE_IMG: 167 info->psDatatype = PS_TYPE_U8; 168 info->fitsDatatype = TBYTE; 169 break; 170 case SBYTE_IMG: 171 info->psDatatype = PS_TYPE_S8; 172 info->fitsDatatype = TSBYTE; 173 break; 174 case USHORT_IMG: 175 info->psDatatype = PS_TYPE_U16; 176 info->fitsDatatype = TUSHORT; 177 break; 178 case SHORT_IMG: 179 info->psDatatype = PS_TYPE_S16; 180 info->fitsDatatype = TSHORT; 181 break; 182 case ULONG_IMG: 183 info->psDatatype = PS_TYPE_U32; 184 info->fitsDatatype = TUINT; 185 break; 186 case LONG_IMG: 187 info->psDatatype = PS_TYPE_S32; 188 info->fitsDatatype = TINT; 189 break; 190 case LONGLONG_IMG: 191 info->psDatatype = PS_TYPE_S64; 192 info->fitsDatatype = TLONGLONG; 193 break; 194 case FLOAT_IMG: 195 info->psDatatype = PS_TYPE_F32; 196 info->fitsDatatype = TFLOAT; 197 break; 198 case DOUBLE_IMG: 199 info->psDatatype = PS_TYPE_F64; 200 info->fitsDatatype = TDOUBLE; 201 break; 202 default: 203 psError(PS_ERR_IO, true, _("FITS image type, BITPIX=%d, is not supported."), info->bitPix); 204 goto bad; 205 } 206 } 179 207 return info; 180 208 … … 211 239 212 240 return true; 241 } 242 243 // Apply the BSCALE and BZERO for an image with a "fuzz" 244 // The idea is that the "fuzz" (adding a random number between 0 and 1) preserves the expectation value of 245 // the image (e.g., a value of 0.1 will get translated to zero 90% of the time, and unity 10% of the time), 246 // though at the cost of adding an additional variance of 1/12 (a standard deviation of ~0.29). 247 static psImage *scaleImageWrite(psImage *image, // Image to which to apply BSCALE and BZERO 248 int bitpix, // Output BITPIX 249 double bscale, // Scaling 250 double bzero, // Zero point 251 psRandom *rng // Random number generator (for the "fuzz"), or NULL 252 ) 253 { 254 assert(image); 255 256 if (!PS_IS_PSELEMTYPE_REAL(image->type.type) || bitpix == 0) { 257 return psMemIncrRefCounter(image); 258 } 259 260 psElemType outType; // Type for output image 261 // Choosing to use signed types because those don't require BSCALE,BZERO to represent them in the FITS 262 // file 263 switch (bitpix) { 264 case 8: 265 outType = PS_TYPE_S8; 266 break; 267 case 16: 268 outType = PS_TYPE_S16; 269 break; 270 case 32: 271 outType = PS_TYPE_S32; 272 break; 273 case 64: 274 outType = PS_TYPE_S64; 275 break; 276 default: 277 psError(PS_ERR_BAD_PARAMETER_VALUE, true, "Target bitpix (%d) is not one of 8,16,32,64", bitpix); 278 return NULL; 279 } 280 281 if (bscale == 1.0 && bzero == 0.0) { 282 return psImageCopy(NULL, image, outType); 283 } 284 285 int numCols = image->numCols, numRows = image->numRows; // Size of image 286 psImage *out = psImageAlloc(numCols, numRows, outType); // Output image 287 288 if (!psMemIncrRefCounter(rng)) { 289 // Don't blab about which seed we're going to get --- it's not necessary for this purpose 290 psU64 seed = p_psRandomGetSystemSeed(false); 291 rng = psRandomAlloc(PS_RANDOM_TAUS, seed); 292 } 293 294 295 #define SCALE_WRITE_OUT_CASE(IN, INTYPE, OUT, OUTTYPE) \ 296 case PS_TYPE_##OUTTYPE: { \ 297 ps##INTYPE scale = 1.0 / bscale; \ 298 ps##INTYPE zero = bzero; \ 299 for (int y = 0; y < numRows; y++) { \ 300 for (int x = 0; x < numCols; x++) { \ 301 /* Add random factor [0,1): adds a variance of 1/12, but preserves the expectation value */ \ 302 ps##INTYPE random = psRandomUniform(rng); \ 303 (OUT)->data.OUTTYPE[y][x] = ((IN)->data.INTYPE[y][x] - zero) * scale + random; \ 304 } \ 305 } \ 306 break; \ 307 } 308 309 #define SCALE_WRITE_IN_CASE(IN, INTYPE, OUT) \ 310 case PS_TYPE_##INTYPE: { \ 311 switch (outType) { \ 312 SCALE_WRITE_OUT_CASE(IN, INTYPE, OUT, S8); \ 313 SCALE_WRITE_OUT_CASE(IN, INTYPE, OUT, S16); \ 314 SCALE_WRITE_OUT_CASE(IN, INTYPE, OUT, S32); \ 315 SCALE_WRITE_OUT_CASE(IN, INTYPE, OUT, S64); \ 316 default: \ 317 psAbort("Should be unreachable."); \ 318 } \ 319 break; \ 320 } 321 322 switch (image->type.type) { 323 SCALE_WRITE_IN_CASE(image, F32, out); 324 SCALE_WRITE_IN_CASE(image, F64, out); 325 default: 326 psAbort("Should be unreachable."); 327 } 328 329 psFree(rng); 330 331 return out; 332 } 333 334 335 336 // Determine BSCALE and BZERO for an image, and generate a new image with it applied 337 // TRUE = BZERO + BSCALE * FITS 338 static psImage *scaleImageDetermineWrite(double *bscale, // Scaling, to return 339 double *bzero, // Zero point, to return 340 psImage *image, // Image to scale 341 int bitpix, // Desired bits per pixel 342 psRandom *rng // Random number generator for scaleImageWrite 343 ) 344 { 345 PS_ASSERT_PTR_NON_NULL(bscale, NULL); 346 PS_ASSERT_PTR_NON_NULL(bzero, NULL); 347 PS_ASSERT_IMAGE_NON_NULL(image, NULL); 348 PS_ASSERT_IMAGE_TYPE_F32_OR_F64(image, NULL); 349 350 *bscale = 0.0; 351 *bzero = 0.0; 352 353 switch (bitpix) { 354 case 0: 355 // No scaling applied 356 return psMemIncrRefCounter(image); 357 case 8: 358 case 16: 359 case 32: 360 case 64: 361 // Nothing to do; just allowing these values to pass through 362 break; 363 default: 364 psError(PS_ERR_BAD_PARAMETER_VALUE, true, "Target bitpix (%d) is not one of 8,16,32,64", bitpix); 365 return NULL; 366 } 367 368 int numCols = image->numCols, numRows = image->numRows; 369 double range = pow(2.0, bitpix); // Range of values for target BITPIX 370 371 #define SCALE_DETERMINE_CASE(IN, INTYPE) \ 372 case PS_TYPE_##INTYPE: { \ 373 ps##INTYPE min = INFINITY, max = -INFINITY; /* Minimum and maximum values */ \ 374 for (int y = 0; y < numRows; y++) { \ 375 for (int x = 0; x < numCols; x++) { \ 376 ps##INTYPE value = (IN)->data.INTYPE[y][x]; /* Value of interest */ \ 377 if (isfinite(value)) { \ 378 if (value < min) { \ 379 min = value; \ 380 } \ 381 if (value > max) { \ 382 max = value; \ 383 } \ 384 } \ 385 } \ 386 } \ 387 if (!isfinite(min) || !isfinite(max)) { \ 388 psWarning("No valid values in image to derive BSCALE,BZERO --- using original image."); \ 389 *bscale = 1.0; \ 390 *bzero = 0.0; \ 391 return psMemIncrRefCounter(image); \ 392 } \ 393 if (min == max) { \ 394 *bscale = 1.0; \ 395 *bzero = min; \ 396 } else { \ 397 *bscale = (max - min) / (range - 1.0); \ 398 *bzero = min + 0.5 * range * (*bscale); \ 399 } \ 400 break; \ 401 } 402 403 switch (image->type.type) { 404 SCALE_DETERMINE_CASE(image, F32); 405 SCALE_DETERMINE_CASE(image, F64); 406 default: 407 psAbort("Should be unreachable."); 408 } 409 psTrace("psLib.fits", 3, "BSCALE = %.10lf, BZERO = %.10lf\n", *bscale, *bzero); 410 411 return scaleImageWrite(image, bitpix, *bscale, *bzero, rng); 412 } 413 414 415 #if 0 416 // This function to apply BSCALE and BZERO to an image read immediately from disk should not be necessary at 417 // the present time, since cfitsio should apply the scaling itself in the process of reading. However, we may 418 // later desire it. 419 static psImage *scaleImageRead(psFits *fits, psImage *image) 420 { 421 PS_ASSERT_IMAGE_NON_NULL(image, NULL); 422 423 if (bscale == 0.0) { 424 // BSCALE = 0 means don't apply anything 425 return psMemIncrRefCounter(image); 426 } 427 428 psElemType inType = image->type.type; // Type for input image 429 psElemType outType; // Type for output image 430 switch (inType) { 431 case PS_TYPE_S8: 432 case PS_TYPE_S16: 433 case PS_TYPE_S32: 434 case PS_TYPE_U8: 435 case PS_TYPE_U16: 436 outType = PS_TYPE_F32; 437 break; 438 case PS_TYPE_S64: 439 case PS_TYPE_U32: 440 case PS_TYPE_U64: 441 outType = PS_TYPE_F64; 442 break; 443 // Including floating-point types just in case someone wants to apply a BSCALE and BZERO to them. 444 case PS_TYPE_F32: 445 outType = PS_TYPE_F32; 446 break; 447 case PS_TYPE_F64: 448 outType = PS_TYPE_F64; 449 break; 450 default: 451 psError(PS_ERR_BAD_PARAMETER_VALUE, true, "Unsupported image type: %x", inType); 452 return NULL; 453 } 454 455 int numCols = image->numCols, numRows = image->numRows; 456 psImage *out = psImageAlloc(numCols, numRows, outType); // Output scaled image 457 458 459 #define SCALE_READ_OUT_CASE(INTYPE, OUTTYPE) \ 460 case PS_TYPE_##OUTTYPE: { \ 461 for (int y = 0; y < numRows; y++) { \ 462 for (int x = 0; x < numCols; x++) { \ 463 out->data.OUTTYPE[y][x] = image->data.INTYPE[y][x] * bscale + bzero; \ 464 } \ 465 } \ 466 break; \ 467 } 468 469 #define SCALE_READ_IN_CASE(INTYPE) \ 470 case PS_TYPE_##INTYPE: { \ 471 switch (outType) { \ 472 SCALE_READ_OUT_CASE(INTYPE, F32); \ 473 SCALE_READ_OUT_CASE(INTYPE, F64); \ 474 default: \ 475 psAbort("Should never get here: type %x should be F32 or F64", outType); \ 476 } \ 477 break; \ 478 } 479 480 switch (inType) { 481 SCALE_READ_IN_CASE(S8); 482 SCALE_READ_IN_CASE(S16); 483 SCALE_READ_IN_CASE(S32); 484 SCALE_READ_IN_CASE(S64); 485 SCALE_READ_IN_CASE(U8); 486 SCALE_READ_IN_CASE(U16); 487 SCALE_READ_IN_CASE(U32); 488 SCALE_READ_IN_CASE(U64); 489 SCALE_READ_IN_CASE(F32); 490 SCALE_READ_IN_CASE(F64); 491 default: 492 psAbort("Should never get here: type %x should be integer", inType); 493 } 494 495 return out; 496 } 497 #endif 498 499 // Convert an image to the desired BITPIX 500 static psImage *convertImageWrite(double *bscale, // Scaling applied 501 double *bzero, // Zero point applied 502 psFitsFloat *floatType, // Type of custom floating-point 503 psFits *fits, // FITS file pointer 504 const psImage *image, // Current type 505 psRandom *rng, // Random number generator 506 bool newScaleZero // Determine a new BSCALE and BZERO? 507 ) 508 { 509 assert(bscale); 510 assert(bzero); 511 assert(floatType); 512 assert(fits); 513 assert(image); 514 515 *bscale = 0.0; 516 *bzero = 0.0; 517 *floatType = PS_FITS_FLOAT_NONE; 518 519 // Custom floating-point 520 if (PS_IS_PSELEMTYPE_REAL(image->type.type) && fits->conventions.psBitpix && 521 fits->floatType != PS_FITS_FLOAT_NONE) { 522 *floatType = fits->floatType; 523 return psFitsFloatImageWrite(image, fits->floatType); 524 } 525 526 // Automatically select what we're given 527 if (fits->bitpix == 0) { 528 return psMemIncrRefCounter((psImage*)image); // Casting away const 529 } 530 531 // Quantise floating-point images 532 if (PS_IS_PSELEMTYPE_REAL(image->type.type) && fits->bitpix > 0) { 533 if (newScaleZero) { 534 return scaleImageDetermineWrite(bscale, bzero, (psImage*)image, fits->bitpix, rng); 535 } 536 // Get the current BSCALE and BZERO 537 int status = 0; // Status of cfitsio 538 if (fits_read_key_dbl(fits->fd, "BSCALE", bscale, NULL, &status) && status != KEY_NO_EXIST) { 539 psFitsError(status, true, "Unable to read header."); 540 return NULL; 541 } 542 status = 0; 543 if (fits_read_key_dbl(fits->fd, "BZERO", bzero, NULL, &status) && status != KEY_NO_EXIST) { 544 psFitsError(status, true, "Unable to read header."); 545 return NULL; 546 } 547 status = 0; 548 if (*bscale == 0.0) { 549 psError(PS_ERR_IO, true, 550 "Supposed to use old values of BSCALE and BZERO, but they don't exist."); 551 return NULL; 552 } 553 return scaleImageWrite((psImage*)image, fits->bitpix, *bscale, *bzero, rng); 554 } 555 556 // Choose the appropriate output type, given the input type and desired bits per pixel 557 #define CONVERT_TYPE_INT_CASE(OUTTYPE, INTYPE, BITPIX) \ 558 case BITPIX: \ 559 OUTTYPE = PS_IS_PSELEMTYPE_UNSIGNED(INTYPE) ? PS_TYPE_U##BITPIX : PS_TYPE_S##BITPIX; \ 560 break; 561 #define CONVERT_TYPE_FLOAT_CASE(OUTTYPE, BITPIX) \ 562 case -BITPIX: /* Note the use of the negative sign */ \ 563 OUTTYPE = PS_TYPE_F##BITPIX; \ 564 break; 565 566 *bscale = 1.0; 567 *bzero = 0.0; 568 psElemType inType = image->type.type; // Type for input image 569 psElemType outType; // Type for output image 570 switch (fits->bitpix) { 571 CONVERT_TYPE_INT_CASE(outType, inType, 8); 572 CONVERT_TYPE_INT_CASE(outType, inType, 16); 573 CONVERT_TYPE_INT_CASE(outType, inType, 32); 574 CONVERT_TYPE_INT_CASE(outType, inType, 64); 575 CONVERT_TYPE_FLOAT_CASE(outType, 32); 576 CONVERT_TYPE_FLOAT_CASE(outType, 64); 577 default: 578 psError(PS_ERR_BAD_PARAMETER_VALUE, true, "Target bitpix (%d) is not one of 8,16,32,64", 579 fits->bitpix); 580 return NULL; 581 } 582 583 if (outType == inType) { 584 return psMemIncrRefCounter((psImage*)image); 585 } 586 return psImageCopy(NULL, image, outType); 213 587 } 214 588 … … 232 606 if (fits_read_subset(fits->fd, info->fitsDatatype, info->firstPixel, info->lastPixel, 233 607 info->increment, NULL, output->data.V[0], &anynull, &status) != 0) { 234 char fitsErr[80]; // CFITSIO error message string 235 (void)fits_get_errstatus(status, fitsErr); 236 psError(PS_ERR_IO, true, 237 _("Reading FITS file failed. CFITSIO Error: %s"), 238 fitsErr); 239 return false; 240 } 608 psFitsError(status, true, "Reading FITS file failed."); 609 return false; 610 } 611 612 // No need to apply the BSCALE, BZERO because cfitsio does this for us 241 613 242 614 return true; … … 259 631 p_psFitsReadInfo *info = p_psFitsReadInfoAlloc(fits, region, z); 260 632 261 psImage *output = psImageAlloc(info->lastPixel[0] - info->firstPixel[0] + 1, 262 info->lastPixel[1] - info->firstPixel[1] + 1, 263 info->psDatatype); 264 265 if (!fitsReadImage(output, fits, info)) { 633 // Size of image 634 int numCols = info->lastPixel[0] - info->firstPixel[0] + 1; 635 int numRows = info->lastPixel[1] - info->firstPixel[1] + 1; 636 637 psImage *inImage = psImageAlloc(numCols, numRows, info->psDatatype); // Image to read in 638 639 psFitsFloat floatType = psFitsFloatImageCheck(fits); // Type of custom floating-point 640 psImage *outImage = (floatType == PS_FITS_FLOAT_NONE ? psMemIncrRefCounter(inImage) : 641 psImageAlloc(numCols, numRows, psFitsFloatImageType(floatType))); // Output image 642 643 if (!fitsReadImage(inImage, fits, info)) { 266 644 psFree(info); 267 psFree( output);645 psFree(inImage); 268 646 return NULL; 269 647 } 270 271 648 psFree(info); 272 return output; 273 } 274 275 psImage* psFitsReadImageBuffer(psImage *output, // Output image buffer 276 const psFits *fits, // the psFits object 649 650 if (floatType != PS_FITS_FLOAT_NONE) { 651 outImage = psFitsFloatImageRead(outImage, inImage, floatType); 652 } 653 psFree(inImage); 654 655 return outImage; 656 } 657 658 psImage* psFitsReadImageBuffer(psImage *outImage, // Output image buffer 659 const psFits *fits, // the psFits object 277 660 psRegion region, // the region in the FITS image to read 278 661 int z // the z-plane in the FITS image cube to read … … 282 665 PS_ASSERT_INT_NONNEGATIVE(z, NULL); 283 666 284 if (out put && output->parent) {667 if (outImage && outImage->parent) { 285 668 psError(PS_ERR_IO, true, "Unable to read into a buffer for a child image.\n"); 286 669 return NULL; … … 295 678 p_psFitsReadInfo *info = p_psFitsReadInfoAlloc(fits, region, z); 296 679 297 output = psImageRecycle(output, info->lastPixel[0] - info->firstPixel[0] + 1, 298 info->lastPixel[1] - info->firstPixel[1] + 1, 299 info->psDatatype); 300 301 if (!fitsReadImage(output, fits, info)) { 680 // Size of image 681 int numCols = info->lastPixel[0] - info->firstPixel[0] + 1; 682 int numRows = info->lastPixel[1] - info->firstPixel[1] + 1; 683 684 psFitsFloat floatType = psFitsFloatImageCheck(fits); // Type of custom floating-point 685 psImage *inImage; // Image to read in 686 if (floatType == PS_FITS_FLOAT_NONE) { 687 inImage = psImageRecycle(outImage, numCols, numRows, info->psDatatype); 688 outImage = psMemIncrRefCounter(inImage); 689 } else { 690 inImage = psImageAlloc(numCols, numRows, info->psDatatype); 691 outImage = psImageRecycle(outImage, numCols, numRows, psFitsFloatImageType(floatType)); 692 } 693 694 if (!fitsReadImage(inImage, fits, info)) { 302 695 psFree(info); 303 psFree(output); 696 psFree(inImage); 697 psFree(outImage); 304 698 return NULL; 305 699 } 306 307 700 psFree(info); 308 return output; 701 702 if (floatType != PS_FITS_FLOAT_NONE) { 703 outImage = psFitsFloatImageRead(outImage, inImage, floatType); 704 } 705 psFree(inImage); 706 707 return outImage; 309 708 } 310 709 311 710 bool psFitsWriteImage(psFits* fits, 312 constpsMetadata* header,711 psMetadata* header, 313 712 const psImage* input, 314 713 int numZPlanes, … … 324 723 } 325 724 326 bool psFitsInsertImage(psFits* fits, 327 const psMetadata* header, 328 const psImage* input, 329 int numZPlanes, 330 const char* extname, 331 bool after) 725 bool psFitsInsertImage(psFits* fits, psMetadata* header, const psImage* image, int numZPlanes, 726 const char* extname, bool after) 332 727 { 333 728 PS_ASSERT_FITS_NON_NULL(fits, false); 334 729 PS_ASSERT_FITS_WRITABLE(fits, false); 335 PS_ASSERT_IMAGE_NON_NULL(i nput, false);336 337 int numCols = i nput->numCols; // Number of columns for image338 int numRows = i nput->numRows; // Number of rows for image730 PS_ASSERT_IMAGE_NON_NULL(image, false); 731 732 int numCols = image->numCols; // Number of columns for image 733 int numRows = image->numRows; // Number of rows for image 339 734 int status = 0; // Status from cfitsio 735 736 double bscale = 0.0, bzero = 0.0; // Scale and zero point to put in header (*already* applied to data) 737 psFitsFloat floatType; // Custom floating-point convention type 738 psImage *diskImage = convertImageWrite(&bscale, &bzero, &floatType, fits, image, 739 NULL, true); // Image to write out 740 if (!diskImage) { 741 psError(PS_ERR_UNKNOWN, false, "Unable to convert image to desired disk format."); 742 return false; 743 } 340 744 341 745 // determine the FITS-equivalent parameters 342 746 int bitPix; // Bits per pixel 343 double bZero; // Zero offset747 double cfitsioBzero = 0.0; // Zero point for cfitsio to apply 344 748 int dataType; // cfitsio data type 345 if (! p_psFitsTypeToCfitsio(input->type.type, &bitPix, &bZero, &dataType) ) { 346 return false; 347 } 749 if (!p_psFitsTypeToCfitsio(diskImage->type.type, &bitPix, &cfitsioBzero, &dataType)) { 750 psFree(diskImage); 751 return false; 752 } 753 if (cfitsioBzero != 0.0) { 754 assert(bzero == 0.0 && bscale == 1.0); // p_psFitsTypeToCfitsio and convertImageWrite must not clash 755 bscale = 1.0; 756 bzero = cfitsioBzero; 757 } 758 assert(bitPix == fits->bitpix || fits->bitpix == 0); 348 759 349 760 int naxis = 3; // Number of axes … … 377 788 } 378 789 790 // write the header, if any. 379 791 if (header && !psFitsWriteHeader(fits, header)) { 380 792 psError(PS_ERR_IO, false, "Unable to write FITS header.\n"); 381 return false; 382 } 383 384 if (bZero != 0) { // set the bscale/bzero 385 fits_write_key_dbl(fits->fd, "BZERO", bZero, 12, "Pixel Value Offset", &status); 386 fits_write_key_dbl(fits->fd, "BSCALE", 1.0, 12, "Pixel Value Scale", &status); 387 fits_set_bscale(fits->fd, 1.0, bZero, &status); 388 } 389 390 // write the header, if any. 793 psFree(diskImage); 794 return false; 795 } 796 797 // We only want cfitsio to do the scale and zero if the type conversion requires it (e.g., input type is 798 // an unsigned integer type). In all other cases, we have already converted the image to use the 799 // appropriate scale and zero (because we want to apply a randomiser to the quantisation). 800 fits_set_bscale(fits->fd, 1.0, cfitsioBzero, &status); 801 802 if (bscale != 0.0) { 803 fits_write_key_dbl(fits->fd, "BZERO", bzero, 12, 804 "Scaling: TRUE = BZERO + BSCALE * DISK", &status); 805 fits_write_key_dbl(fits->fd, "BSCALE", bscale, 12, 806 "Scaling: TRUE = BZERO + BSCALE * DISK", &status); 807 if (psFitsError(status, true, "Could not write BSCALE/BZERO headers to file.")) { 808 psFree(diskImage); 809 return false; 810 } 811 } 812 813 if (floatType != PS_FITS_FLOAT_NONE) { 814 psFitsFloatImageSet(fits, floatType); 815 } 816 391 817 if (extname && strlen(extname) > 0) { 392 psFitsSetExtName(fits,extname); 393 } 394 395 if (input->parent == NULL) { // if no parent, assume that the image data is contiguous 396 fits_write_img(fits->fd, 397 dataType, // datatype 398 1, // writing to the first z-plane 399 numCols*numRows, // number of elements to write, i.e., the whole image 400 input->data.V[0], // the data 401 &status); 402 } else { // image data may not be contiguous; write one row at a time 818 psFitsSetExtName(fits, extname); 819 } 820 821 if (image->parent == NULL) { 822 // if no parent, assume that the image data is contiguous 823 fits_write_img(fits->fd, dataType, 1, numCols*numRows, diskImage->data.V[0], &status); 824 } else { 825 // image data may not be contiguous; write one row at a time 403 826 int firstPixel = 1; 404 827 for (int row = 0; row < numRows; row++) { 405 fits_write_img(fits->fd, 406 dataType, // datatype 407 firstPixel, 408 numCols, // number of elements to write, i.e., one row's worth 409 input->data.V[row],// the raw row data 410 &status); 411 firstPixel += numCols; // move to next row 412 } 413 } 414 415 if (status != 0) { 416 char fitsErr[MAX_STRING_LENGTH]; 417 (void)fits_get_errstatus(status, fitsErr); 418 psError(PS_ERR_IO, true, 419 _("Could not write data to file. CFITSIO Error: %s"), 420 fitsErr); 828 fits_write_img(fits->fd, dataType, firstPixel, numCols, diskImage->data.V[row], &status); 829 firstPixel += numCols; 830 } 831 } 832 833 psFree(diskImage); 834 835 if (psFitsError(status, true, "Could not write image to file.")) { 421 836 return false; 422 837 } … … 426 841 } 427 842 428 bool psFitsUpdateImage(psFits* fits, 429 const psImage* input, 430 int x0, 431 int y0, 432 int z) 843 bool psFitsUpdateImage(psFits* fits, const psImage* input, int x0, int y0, int z) 433 844 { 434 845 PS_ASSERT_FITS_NON_NULL(fits, false); … … 440 851 // check to see if we are positioned on an image HDU 441 852 int hduType; 442 if ( fits_get_hdu_type(fits->fd, &hduType, &status) != 0) { 443 char fitsErr[MAX_STRING_LENGTH]; 444 (void)fits_get_errstatus(status, fitsErr); 445 psError(PS_ERR_IO, true, 446 _("Could not determine the HDU type. CFITSIO Error: %s"), 447 fitsErr); 853 if (fits_get_hdu_type(fits->fd, &hduType, &status) != 0) { 854 psFitsError(status, true, "Could not determine the HDU type."); 448 855 return NULL; 449 856 } 450 857 if (hduType != IMAGE_HDU) { 451 psError(PS_ERR_IO, true, 452 _("Current FITS HDU type must be an image.")); 858 psError(PS_ERR_IO, true, _("Current FITS HDU type must be an image.")); 453 859 return NULL; 454 860 } … … 457 863 int numRows = input->numRows; 458 864 865 double bscale = 0.0, bzero = 0.0; // Scale and zero point to put in header (*already* applied to data) 866 psFitsFloat floatType; // Custom floating-point convention type 867 psImage *diskImage = convertImageWrite(&bscale, &bzero, &floatType, fits, input, 868 NULL, false); // Image to write out 869 if (!diskImage) { 870 psError(PS_ERR_UNKNOWN, false, "Unable to convert image to desired disk format."); 871 return false; 872 } 873 459 874 // determine the FITS-equivalent parameters 460 int bitPix; 461 double bZero; 462 int dataType; 463 if (! p_psFitsTypeToCfitsio(input->type.type, &bitPix, &bZero, &dataType) ) { 464 return false; 465 } 875 int bitPix; // Bits per pixel 876 double cfitsioBzero = 0.0; // Zero point for cfitsio to apply 877 int dataType; // cfitsio data type 878 if (! p_psFitsTypeToCfitsio(diskImage->type.type, &bitPix, &cfitsioBzero, &dataType)) { 879 psFree(diskImage); 880 return false; 881 } 882 if (cfitsioBzero != 0.0) { 883 assert(bzero == 0.0 && bscale == 1.0); // p_psFitsTypeToCfitsio and convertImageWrite must not clash 884 bscale = 1.0; 885 bzero = cfitsioBzero; 886 } 887 assert(bitPix == fits->bitpix || fits->bitpix == 0); 466 888 467 889 //check to see if the HDU has the same datatype … … 476 898 char* fitsTypeStr; 477 899 char* imageTypeStr; 478 PS_TYPE_NAME(fitsTypeStr,fileBitpix); 479 PS_TYPE_NAME(imageTypeStr,input->type.type); 480 psError(PS_ERR_IO, true, 481 _("Can not update a %s image given a %s image."), 482 fitsTypeStr, imageTypeStr); 900 PS_TYPE_NAME(fitsTypeStr, fileBitpix); 901 PS_TYPE_NAME(imageTypeStr, input->type.type); 902 psError(PS_ERR_IO, true, _("Can not update a %s image given a %s image."), fitsTypeStr, imageTypeStr); 903 psFree(diskImage); 483 904 return false; 484 905 } … … 487 908 if (z >= nAxes[2]) { 488 909 psError(PS_ERR_BAD_PARAMETER_SIZE, true, 489 _("Current FITS HDU has %ld z-planes, but z-plane %d was specified."), 490 nAxes[2], z);910 _("Current FITS HDU has %ld z-planes, but z-plane %d was specified."), nAxes[2], z); 911 psFree(diskImage); 491 912 return false; 492 913 } … … 505 926 506 927 if (firstPixel[0] < 1 || firstPixel[0] > nAxes[0] || 507 firstPixel[1] < 1 || firstPixel[1] > nAxes[1] ||508 lastPixel[0] < 1 || lastPixel[0] > nAxes[0] ||509 lastPixel[1] < 1 || lastPixel[1] > nAxes[1]) {928 firstPixel[1] < 1 || firstPixel[1] > nAxes[1] || 929 lastPixel[0] < 1 || lastPixel[0] > nAxes[0] || 930 lastPixel[1] < 1 || lastPixel[1] > nAxes[1]) { 510 931 psError(PS_ERR_BAD_PARAMETER_VALUE, true, 511 932 "Input image [size of %ix%i] at position (%i,%i) does not all lay in the %lix%li FITS image.", 512 numCols, numRows, 513 x0, y0, 514 nAxes[0], nAxes[1]); 515 return false; 516 } 517 518 fits_write_subset(fits->fd, dataType, firstPixel, lastPixel, input->data.V[0], &status); 519 520 if ( status != 0) { 521 char fitsErr[MAX_STRING_LENGTH]; 522 (void)fits_get_errstatus(status, fitsErr); 523 psError(PS_ERR_IO, true, 524 _("Could not write data to file. CFITSIO Error: %s"), 525 fitsErr); 933 numCols, numRows, x0, y0, nAxes[0], nAxes[1]); 934 psFree(diskImage); 935 return false; 936 } 937 938 // We only want cfitsio to do the scale and zero if the type conversion requires it (e.g., input type is 939 // an unsigned integer type). In all other cases, we have already converted the image to use the 940 // appropriate scale and zero (because we want to apply a randomiser to the quantisation). 941 fits_set_bscale(fits->fd, 1.0, cfitsioBzero, &status); 942 943 fits_write_subset(fits->fd, dataType, firstPixel, lastPixel, diskImage->data.V[0], &status); 944 945 psFree(diskImage); 946 947 if (psFitsError(status, true, "Could not write data to file.")) { 526 948 return false; 527 949 } … … 537 959 long nAxes[3]; // Number of pixels on each axis 538 960 int status = 0; // cfitsio status value 539 char fitsErr[80] = ""; // CFITSIO error message string540 961 541 962 // Some of this replicates what is in psFitsReadImage, so it's a little inefficient. But it saves … … 549 970 550 971 if (fits_get_img_dim(fits->fd, &nAxis, &status) != 0) { 551 (void)fits_get_errstatus(status, fitsErr); 552 psError(PS_ERR_IO, true, 553 _("Could not determine image dimensions. CFITSIO Error: %s"), 554 fitsErr); 972 psFitsError(status, true, "Could not determine image dimensions."); 555 973 return NULL; 556 974 } … … 563 981 if (nAxis == 3) { 564 982 if (fits_get_img_size(fits->fd, nAxis, nAxes, &status) != 0) { 565 (void)fits_get_errstatus(status, fitsErr); 566 psError(PS_ERR_IO, true, 567 _("Could not determine image size. CFITSIO Error: %s"), 568 fitsErr); 983 psFitsError(status, true, "Could not determine image size."); 569 984 return NULL; 570 985 } … … 579 994 580 995 // Bad dimensionality 581 psError(PS_ERR_IO, true, 582 _("Image number of dimensions, %d, is not valid." 583 " Only two or three dimensions supported for FITS I/O."), nAxis); 996 psError(PS_ERR_IO, true, _("Image number of dimensions, %d, is not supported."), nAxis); 584 997 return NULL; 585 998 }
Note:
See TracChangeset
for help on using the changeset viewer.
