Skip to content

fits.CompImageHDU writes unexpected/incorrect BZERO keyword after conversion from unsigned image data #5999

Closed

Description

@evertrol

When I read or create a FITS image HDU with unsigned integer data, then convert it to floating point and save it in a CompImageHDU, an additional BZERO keyword & value get written into the relevant header, even with Astropy telling me it's not there.

Here is a minimal example:

from __future__ import print_function                                               
import sys                                                                          
from tempfile import NamedTemporaryFile                                             
import numpy as np                                                                  
from astropy.io import fits                                                         
                                                                                    
data = np.arange(0, 100, dtype=np.uint16)                                            
hdu = fits.ImageHDU(data=data)                                                      
data = hdu.data.astype(np.float64)                                                  
header = hdu.header                                                                 
hdulist = [fits.PrimaryHDU(),                                                       
           fits.ImageHDU(data=data, header=header, name='normal'),                  
           fits.CompImageHDU(data=data, header=header, name='compressed')]          
                                                                                    
with NamedTemporaryFile() as tmpfile:                                               
    name = tmpfile.name                                                             
    fits.HDUList(hdulist).writeto(name, output_verify='warn')                       
                                                                                    
    print('HDU list as in memory')                                                  
    for hdu in hdulist:                                                             
        print('BZERO in', hdu.name, ':', hdu.header.get('bzero'))                   
        print('BSCALE in', hdu.name, ':', hdu.header.get('bscale'))                 
    print()                                                                         
    print('Re-opening test file')                                                   
    with fits.open(name) as hdulist:                                                
        for hdu in hdulist:                                                         
            print('BZERO in', hdu.name, ':', hdu.header.get('bzero'))               
            print('BSCALE in', hdu.name, ':', hdu.header.get('bscale'))             

This produces:

HDU list as in memory
BZERO in PRIMARY : None
BSCALE in PRIMARY : None
BZERO in NORMAL : None
BSCALE in NORMAL : None
BZERO in COMPRESSED : None
BSCALE in COMPRESSED : None

Re-opening test file
BZERO in PRIMARY : None
BSCALE in PRIMARY : None
BZERO in NORMAL : None
BSCALE in NORMAL : None
BZERO in COMPRESSED : 32768
BSCALE in COMPRESSED : None

The penultimate output line is obviously in error.
Changing the dtype in np.arange to uint32 shows a value of 2147483648, while using a signed integer or floating point dtype shows the BZERO keyword to be absent.
I find the interesting part that the BZERO key gets written (without an accompanying BSCALE key!), but the in-memory header does not contain it whatsoever. All other header keywords seem to be ok.

I've not had time yet to explore this in more depth in Astropy, nor compare it with other current issues with CompImageHDU to see if they are related.

So far, I've seen this happen with various combinations of Python 2.7 & 3.6, Astropy master, 1.3.0, 1.32 and 1.2.1, on Linux and macOS.

Activity

  1. evertrol commented on May 3, 2017

    @evertrol
    ContributorAuthor

    Additional note: the header of the "compressed image" actually looks as follows:

    XTENSION= 'IMAGE   '           / Image extension                                
    BITPIX  =                  -64 / array data type                                
    NAXIS   =                    2 / number of array dimensions                     
    NAXIS1  =                 1000 / width of table in bytes                        
    NAXIS2  =                 1000 / number of rows in table                        
    PCOUNT  =                    0 / number of parameters                           
    GCOUNT  =                    1 / number of groups                               
    EXTNAME = 'COMPRESSED'         / name of this binary table extension            
    BZERO   =                32768                                  
    

    Which is clearly an image HDU, not a binary table HDU as I would expect for a compressed image.

    Perhaps I'm misusing CompImageHDU somehow, but I don't see where.

  2. pllim commented on May 3, 2017

    @pllim
    Member

    The last PR that touched it was #5053. @mwcraig ?

  3. mwcraig commented on May 3, 2017

    @mwcraig
    Member

    Will look at it by Sunday some time, at latest. Next two days will be busy....

  4. saimn commented on May 9, 2017

    @saimn
    Contributor

    Which is clearly an image HDU, not a binary table HDU as I would expect for a compressed image.

    This HDU lies to you :

    In [2]: hdulist[-1]._header
    Out[2]: 
    XTENSION= 'BINTABLE'           / binary table extension                         
    BITPIX  =                    8 / array data type                                
    NAXIS   =                    2 / number of array dimensions                     
    NAXIS1  =                   32 / width of table in bytes                        
    NAXIS2  =                    1 / number of rows in table                        
    PCOUNT  =                    0 / number of group parameters                     
    GCOUNT  =                    1 / number of groups                               
    TFIELDS =                    4 / number of fields in each row                   
    TTYPE1  = 'COMPRESSED_DATA'    / label for field 1                              
    TFORM1  = '1PB     '           / data format of field: variable length array    
    TTYPE2  = 'GZIP_COMPRESSED_DATA' / label for field 2                            
    TFORM2  = '1PB     '           / data format of field: variable length array    
    TTYPE3  = 'ZSCALE  '           / label for field 3                              
    TFORM3  = '1D      '           / data format of field: 8-byte DOUBLE            
    TTYPE4  = 'ZZERO   '           / label for field 4                              
    TFORM4  = '1D      '           / data format of field: 8-byte DOUBLE            
    ZIMAGE  =                    T / extension contains compressed image            
    ZTENSION= 'IMAGE   '           / Image extension                                
    ZBITPIX =                  -64 / array data type                                
    ZNAXIS  =                    1 / number of array dimensions                     
    ZNAXIS1 =                  100                                                  
    ZPCOUNT =                    0 / number of parameters                           
    ZGCOUNT =                    1 / number of groups                               
    ZTILE1  =                  100 / size of tiles to be compressed                 
    ZCMPTYPE= 'RICE_1  '           / compression algorithm                          
    ZNAME1  = 'BLOCKSIZE'          / compression block size                         
    ZVAL1   =                   32 / pixels per block                               
    ZNAME2  = 'BYTEPIX '           / bytes per pixel (1, 2, 4, or 8)                
    ZVAL2   =                    4 / bytes per pixel (1, 2, 4, or 8)                
    ZNAME3  = 'NOISEBIT'           / floating point quantization level              
    ZVAL3   =                 16.0 / floating point quantization level              
    ZQUANTIZ= 'NO_DITHER'          / No dithering during quantization               
    EXTNAME = 'COMPRESSED'         / name of this binary table extension            
    BZERO   =                32768                                                  
    

    The issue looks indeed very similar to #5053.

  5. added 2 commits that reference this issue on Oct 23, 2024
    7f5f133
    70f616b
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions