#! /usr/bin/env python # -*- coding: latin-1 -*- import os import glob import sys import os.path import re import fpformat from optparse import OptionParser import time from pyhdf import SD import Image, ImageDraw, ImagePalette from data2img import * from numpy import log,empty,where,float64 __VERSION__="0.0.2" __AUTHOR__="CGTD/UDEV Nicolas PASCAL (nicolas.pascal@icare.univ-lille1.fr)" """ This script create an image from the sds of an hdf file. For more details on the usage of this tool, call it with the -h option. LIMITATIONS: - The sds MUST have 2 dimensions HISTORY: -------- v0.0.2 : 21/09/2007 - Ajout choix colormap en ligne de commande v0.0.1 : 6/10/2006 - Adaptations to the new version of the numpy package : numpy.arange -> numpy.arange v0.0.0 : 07/2006 - creation TODO ajouter entr�e d'un fichier sans le full path pr�cis� """ scales=["linear","log"] class hdf2img: def __init__(self,infile,sds,val_min=None, val_max=None, invalid=None, invalid_idx=None, scale="linear", colormap="rainbow", verbose=False,overwrite=False, slope=1., offset=0., calibration_equation=0, is_palette_index=False): if not os.path.exists(infile): raise ValueError, "Invalid input file "+data2imginfile # the input file (full path) self.infile=infile # name of the sds to build the browse self.sds=sds # the colormap to use self.colormap=colormap # min threshold applied on datas self.val_min=val_min # max threshold applied on datas self.val_max=val_max # the invalid value self.invalid=invalid # the invalid_idx value #NH self.invalid_idx=invalid_idx #NH # the scale to use self.scale=scale # the calibration slope self.slope=slope # the calibration offset self.offset=offset # are values is_palette_index self.is_palette_index=is_palette_index # The calibration equation to use : 0->(slope*x+offset) ; 1->(slope*x-offset) self.calibration_equation=calibration_equation # display process informations or not self.verbose=verbose # overwrite existing output files or not self.overwrite=overwrite #---validate parameters self.check_args() #---read the sds datas self.read_hdf_data() #---build an image of it self.create_image() def check_args(self): """ validate the class attributes """ if self.sds==None: raise ValueError, "Invalid SDS. You must specified a sds to read" if self.scale not in scales: raise ValueError, "Invalid scale "+self.scale+". Must be one of "+str(scales) def read_hdf_data(self): """ read the SDS datas array in the HDF file """ if self.verbose: print "Start reading the HDF file "+self.infile # open the hdf file for reading hdf=SD.SD(self.infile) # read the sds data if self.verbose: print "Start reading the SDS "+self.sds sds=hdf.select(self.sds) self.data=sds.get() # turn [y,x] (HDF representation) data into [x,y] (numpy one) self.data.shape = ( self.data.shape[1],self.data.shape[0] ) def create_image(self): """ create the image of the sds """ #---convert the datas array into an image if self.verbose: print "Start creating the image" lutfile = self.colormap #NH # Set the scale to use if self.scale=="log": log_data=empty(self.data.shape,dtype=float64) log_data=log(self.data) # mask the invalid values data = log_data if self.invalid is not None : data=where(self.data!=self.invalid,log_data,self.invalid) self.img=data2img(data, colormap=self.colormap, val_min=log(self.val_min), val_max=log(self.val_max), invalid_val=self.invalid, invalid_val_idx=self.invalid_idx, is_palette_index=self.is_palette_index) else: # default is linear self.img=data2img(self.data, colormap=self.colormap, val_min=self.val_min, val_max=self.val_max, invalid_val=self.invalid, invalid_val_idx=self.invalid_idx, is_palette_index=self.is_palette_index) def save(self,outfile,format): """ Saves the image under the given filename. If format is omitted, the format is determined from the filename extension, if possible @param filename the output filename @param format the output format. The available output formats are : GIF, JPEG, PNG, BMP and many others. See the Python Imaging Library handbook for them (http://www.pythonware.com/library/pil/handbook/index.htm). TODO add format options support for compression and other stuffs like this... """ if self.img==None: raise ValueError, "The data's image hasn't been built yet" if not os.path.exists(os.path.dirname(outfile)): raise ValueError, "The output directory "+os.path.dirname(outfile)+"doesn't exist" if (self.overwrite is False) and (os.path.exists(outfile)): raise ValueError, "The file "+outfile+" already exists. Enable the -x option the overwrite it" if self.verbose: print "Start saving the image" self.img.save(outfile,format) ############## MAIN ############### ### set the available program options ### def init_prog_options(parser): parser.add_option("-o","--output", action="store", default="", type="string",dest="outfile",help="The output file name. If an extension is given, the output image file format will be based on it") parser.add_option("-i","--input", action="store", default="", type="string",dest="infile",help="The input file we want to build the browse") parser.add_option("-c","--colormap", action="store", default="rainbow", type="string",dest="colormap",help="The colormap (ocean,bw_linear,red_temp,blue,blue_red,rainbow,rainbow_white,lidar_nasa) to use or the colormap file name") parser.add_option("-s","--sds", action="store", default="", type="string",dest="sds",help="The name of the sds (the variable) [MANDATORY]") parser.add_option("-S","--scale", action="store", default="linear", type="string",dest="scale",help="The type of scale to use : linear(default), log") parser.add_option("-m","--threshold_min", action="store", default=None, type="float",dest="threshold_min",help="The values smaller than threshold_min will be clipped to it (optionnal)") parser.add_option("-n","--threshold_max", action="store", default=None, type="float",dest="threshold_max",help="The values greater than threshold_min will be clipped to it (optionnal)") parser.add_option("-f","--format", action="store", default=None, type="string",dest="format",help="The output file format. (optional : if not given, the format will be based on the output file extension)") parser.add_option("-w","--invalid", action="store", default=None, type="float",dest="invalid",help="The invalid fill value (optional)") parser.add_option("-u","--invalid_idx", action="store", default=0, type="float",dest="invalid_idx",help="The invalid fill value colormap index (optional)") parser.add_option("-v", "--verbose", action="store_true", dest="verbose", \ help="Print out processing informations") parser.add_option("-d", "--is_palette_index", action="store_true", dest="is_palette_index", \ default=False, help="Palette values are a index.") parser.add_option("-x", "--overwrite", action="store_true", dest="overwrite", \ default=False, help="Overwrite the output file if already existant") def parse_arguments(parser): # parse command line return parser.parse_args() def check_options(options): """ Check the validity of the command line arguments """ if not os.path.exists(options.infile): raise ValueError, "Invalid input file "+options.infile if not os.path.exists(os.path.dirname(options.outfile)): raise ValueError, "The output directory "+os.path.dirname(options.outfile)+" doesn't exist" if not options.overwrite and os.path.exists(options.outfile): raise ValueError, "The file "+options.outfile+" already exists. Enable the -x option the overwrite it" if options.scale not in scales: raise ValueError, "Invalid scale "+options.scale+". Must be one of "+str(scales) def test(): """ test function """ # build the image prog=hdf2img("/home/pascal/DATA/MODIS/MYD06_L2/2004/2004_01_01/MYD06_L2.A2004001.0000.004.2004077230457.hdf","Surface_Temperature",invalid=-32768.) # display it prog.img.show() # save it #prog.img.save("/home/pascal/test.png","PNG") def main(): """ Main function, deals with arguments and launch program """ # test that at least one argument is given if not sys.argv[1:]: sys.stdout.write("Sorry: you must specify at least one argument\n") sys.stdout.write("More help avalaible with -h or --help option\n") sys.exit(-1) #---set the command-line options parser = OptionParser() init_prog_options(parser) #---parse them (options, args) = parse_arguments(parser) #---check their validity check_options(options) #--run program prog=hdf2img(options.infile,options.sds, val_min=options.threshold_min,val_max=options.threshold_max,invalid=options.invalid,invalid_idx=options.invalid_idx, scale=options.scale, colormap=options.colormap, verbose=options.verbose, overwrite=options.overwrite, is_palette_index=options.is_palette_index) # saving the image to an output file is requested prog.save(options.outfile,options.format) if __name__ == '__main__': main()