IPP Software Navigation Tools IPP Links Communication Pan-STARRS Links

Changeset 17660 for trunk/psLib


Ignore:
Timestamp:
May 13, 2008, 3:27:25 PM (18 years ago)
Author:
Paul Price
Message:

Some fixes to image I/O: (1) when BITPIX=8, the FITS standard says unsigned ints (cf two's complement for BITPIX=16,32,64). Added some special cases for quantising to BITPIX=8 to accomodate this. (2) Adding support for marking bad pixels when doing compression. Out-of-range and non-finite pixels are written with value 2(BITPIX-1)-1, which is recovered (to NAN) when reading (through use of (Z)BLANK keyword). Added test for this. It doesn't pass yet --- the highest pixel in the image is being interpreted as NAN when it shouldn't be. Solution probably involves tweaking scaleRange() in psFitsScale.c, but not worrying about that now.

Location:
trunk/psLib
Files:
1 added
6 edited

Legend:

Unmodified
Added
Removed
  • trunk/psLib/src/fits/psFitsImage.c

    r17447 r17660  
    77 *  @author Robert DeSonia, MHPCC
    88 *
    9  *  @version $Revision: 1.28 $ $Name: not supported by cvs2svn $
    10  *  @date $Date: 2008-04-17 23:43:02 $
     9 *  @version $Revision: 1.29 $ $Name: not supported by cvs2svn $
     10 *  @date $Date: 2008-05-14 01:27:25 $
    1111 *
    1212 *  Copyright 2004-2005 Maui High Performance Computing Center, University of Hawaii
     
    246246static psImage *imageToDiskRepresentation(double *bscale, // Scaling applied
    247247                                          double *bzero, // Zero point applied
     248                                          long *blank, // Blank value (integer data)
    248249                                          psFitsFloat *floatType, // Type of custom floating-point
    249250                                          psFits *fits, // FITS file pointer
     
    284285        if (newScaleZero) {
    285286            // Choose an appropriate BSCALE and BZERO
    286             if (!psFitsScaleDetermine(bscale, bzero, image, fits)) {
     287            if (!psFitsScaleDetermine(bscale, bzero, blank, image, fits)) {
    287288                // We can't have the write dying for this reason --- try to save it somehow!
    288289                psWarning("Unable to determine BSCALE and BZERO for image --- setting to 1.0, 0.0");
     
    365366    psAssert(!output->parent, "impossible");            // No parents means the buffer is contiguous
    366367
     368    void *nullValue = NULL;             // Null value for data
     369    float nullFloat = NAN;              // Null value for floating point
     370    double nullDouble = NAN;            // Null value for double
     371    switch (info->psDatatype) {
     372      case PS_TYPE_F32:
     373        nullValue = &nullFloat;
     374        break;
     375      case PS_TYPE_F64:
     376        nullValue = &nullDouble;
     377        break;
     378      case PS_TYPE_U8:
     379      case PS_TYPE_U16:
     380      case PS_TYPE_U32:
     381      case PS_TYPE_U64:
     382      case PS_TYPE_S8:
     383      case PS_TYPE_S16:
     384      case PS_TYPE_S32:
     385      case PS_TYPE_S64:
     386        // Can't mark bad pixels any further than what is in the FITS image
     387        break;
     388      default:
     389        psAbort("Unknown type: %x", info->psDatatype);
     390    }
     391
    367392    int anynull = 0;                    // Are there any NULLs in the data?
    368393    int status = 0;                     // cfitsio status
    369394    if (fits_read_subset(fits->fd, info->fitsDatatype, info->firstPixel, info->lastPixel,
    370                          info->increment, NULL, output->data.V[0], &anynull, &status) != 0) {
     395                         info->increment, nullValue, output->data.V[0], &anynull, &status) != 0) {
    371396        psFitsError(status, true, "Reading FITS file failed.");
    372397        return false;
     
    498523
    499524    double bscale = 0.0, bzero = 0.0;   // Scale and zero point to put in header (*already* applied to data)
     525    long blank = 0;                     // Blank (undefined) value for image
    500526    psFitsFloat floatType;              // Custom floating-point convention type
    501     psImage *diskImage = imageToDiskRepresentation(&bscale, &bzero, &floatType, fits, image,
     527    psImage *diskImage = imageToDiskRepresentation(&bscale, &bzero, &blank, &floatType, fits, image,
    502528                                                   NULL, true); // Image to write out
    503529    if (!diskImage) {
     
    576602    }
    577603
     604    if (blank != 0) {
     605        // Some quantisation has taken place --- record the blank ("magic") pixel value
     606        char *keyword = (psFitsCompressionGetType(fits) != PS_FITS_COMPRESS_NONE &&
     607                         (!fits->options || fits->options->conventions.compression)) ?
     608            "ZBLANK" : "BLANK";         // Keyword for recording blank pixel value
     609        fits_write_key_lng(fits->fd, keyword, blank, "Value for undefined pixels", &status);
     610        fits_set_imgnull(fits->fd, blank, &status);
     611        if (psFitsError(status, true, "Could not write BLANK header to file.")) {
     612            psFree(diskImage);
     613            return false;
     614        }
     615    }
     616
    578617    if (floatType != PS_FITS_FLOAT_NONE) {
    579618        psFitsFloatImageSet(fits, floatType);
     
    629668
    630669    double bscale = 0.0, bzero = 0.0;   // Scale and zero point to put in header (*already* applied to data)
     670    long blank = 0;                     // Blank (undefined) value for image
    631671    psFitsFloat floatType;              // Custom floating-point convention type
    632     psImage *diskImage = imageToDiskRepresentation(&bscale, &bzero, &floatType, fits, input,
     672    psImage *diskImage = imageToDiskRepresentation(&bscale, &bzero, &blank, &floatType, fits, input,
    633673                                                   NULL, false); // Image to write out
    634674    if (!diskImage) {
  • trunk/psLib/src/fits/psFitsScale.c

    r17447 r17660  
    4646    psAssert(options, "impossible");
    4747
    48     double range = pow(2.0, options->bitpix); // Range of values for target BITPIX
     48    double range = pow(2.0, options->bitpix) - 1.0; // Range of values for target BITPIX, reduced by the BLANK
    4949    double min = INFINITY, max = -INFINITY; // Minimum and maximum values
    5050    int numCols = image->numCols, numRows = image->numRows; // Size of image
     
    8686        *bzero = min;
    8787    } else {
    88         *bscale = (max - min) / (range - 1.0);
     88        *bscale = (max - min) / range ;
    8989        *bzero = min + 0.5 * range * (*bscale);
    9090    }
     
    157157
    158158    return true;
    159 
    160 
    161     return true;
    162159}
    163160
     
    168165bool psFitsScaleDetermine(double *bscale, // Scaling, to return
    169166                          double *bzero, // Zero point, to return
     167                          long *blank,  // Blank value, to return
    170168                          const psImage *image, // Image to scale
    171169                          const psFits *fits // FITS options
     
    174172    PS_ASSERT_PTR_NON_NULL(bscale, false);
    175173    PS_ASSERT_PTR_NON_NULL(bzero, false);
     174    PS_ASSERT_PTR_NON_NULL(blank, false);
    176175    PS_ASSERT_IMAGE_NON_NULL(image, false);
    177176    PS_ASSERT_FITS_NON_NULL(fits, false);
     
    179178    *bscale = 1.0;
    180179    *bzero = 0.0;
     180    *blank = 0;
    181181
    182182    psFitsOptions *options = fits->options; // FITS options
     
    201201    }
    202202
     203    *blank = (1 << (options->bitpix - 1)) - 1;
     204
    203205    switch (options->scaling) {
    204206      case PS_FITS_SCALE_NONE:
     
    229231    }
    230232
    231     psTrace("psLib.fits", 3, "BSCALE = %.10lf, BZERO = %.10lf\n", *bscale, *bzero);
     233    if (options->bitpix == 8) {
     234        // FITS standard wants unsigned for BITPIX=8, two's-complement for BITPIX=16,32,64.
     235        *bzero -= *bscale * 128;
     236        *blank = 255;
     237    }
     238
     239
     240    psTrace("psLib.fits", 3, "BSCALE = %.10lf, BZERO = %.10lf, BLANK = %ld\n", *bscale, *bzero, *blank);
    232241    return true;
    233242}
     
    252261    switch (bitpix) {
    253262      case 8:
    254         outType = PS_TYPE_S8;
     263        // Note: Use unsigned integer for BITPIX=8
     264        outType = PS_TYPE_U8;
    255265        break;
    256266      case 16:
     
    283293#define SCALE_WRITE_OUT_CASE(IN, INTYPE, OUT, OUTTYPE) \
    284294    case PS_TYPE_##OUTTYPE: { \
    285         ps##INTYPE scale = 1.0 / bscale; \
    286         ps##INTYPE zero = bzero; \
    287         ps##INTYPE min = - (1 << (options->bitpix - 1)); \
    288         ps##INTYPE max = (1 << (options->bitpix - 1)) - 1; \
     295        double scale = 1.0 / bscale; \
     296        double zero = bzero; \
     297        /* Note: BITPIX=8 treated differently, since it uses unsigned values; the rest use signed */ \
     298        double min = bitpix == 8 ? 0 : -pow(2.0, options->bitpix - 1); \
     299        double max = bitpix == 8 ? 255 : (pow(2.0, options->bitpix - 1) - 1.0); \
    289300        for (int y = 0; y < numRows; y++) { \
    290301            for (int x = 0; x < numCols; x++) { \
     
    301312                        value += psRandomUniform(rng); \
    302313                    } \
    303                     /* Check for underflow and overflow */ \
    304                     (OUT)->data.OUTTYPE[y][x] = (value < min ? min : (value > max ? max : value)); \
     314                    /* Check for underflow and overflow; set either to max */ \
     315                    (OUT)->data.OUTTYPE[y][x] = (value < min || value > max ? max : value); \
    305316                } \
    306317            } \
     
    312323    case PS_TYPE_##INTYPE: { \
    313324        switch (outType) { \
    314             SCALE_WRITE_OUT_CASE(IN, INTYPE, OUT, S8); \
     325            SCALE_WRITE_OUT_CASE(IN, INTYPE, OUT, U8); \
    315326            SCALE_WRITE_OUT_CASE(IN, INTYPE, OUT, S16); \
    316327            SCALE_WRITE_OUT_CASE(IN, INTYPE, OUT, S32); \
  • trunk/psLib/src/fits/psFitsScale.h

    r16197 r17660  
    1010bool psFitsScaleDetermine(double *bscale, ///< Scaling, to return
    1111                          double *bzero, ///< Zero point, to return
     12                          long *blank,  ///< Blank value, to return
    1213                          const psImage *image, ///< Image to scale
    1314                          const psFits *fits ///< FITS options
  • trunk/psLib/test/fits

    • Property svn:ignore
      •  

        old new  
        1313gmon.out
        1414tap_psFits
         15tap_psFitsImage
  • trunk/psLib/test/fits/.cvsignore

    r12556 r17660  
    1313gmon.out
    1414tap_psFits
     15tap_psFitsImage
  • trunk/psLib/test/fits/Makefile.am

    r11439 r17660  
    1111
    1212TEST_PROGS = \
    13         tap_psFits
    14         tap_psFitsBlank_00
     13        tap_psFits \
     14        tap_psFitsBlank_00 \
     15        tap_psFitsImage
    1516
    1617if BUILD_TESTS
Note: See TracChangeset for help on using the changeset viewer.