예제 #1
0
 def __init__(self,
              srxplanarconfig=None,
              configfile=None,
              args=None,
              **kwargs):
     '''
     init srxplanar form a SrXplanarConfig instance, or config file, or args passed from cmd
     or kwargs. If both SrXplanarConfig instance and other configfile/args/kwargs is specified, 
     it will first init from config instance then update using configfile/args/kwargs
     
     :param srxplanarconfig: SrXplanarConfig, init srxplanar from a config instance
     :param configfile: string, name of config file
     :param args: list of str, usually be sys.argv
     :param kwargs: you can use like 'xbeamcenter=1024' or a dict to update the value of xbeamcenter
     '''
     if srxplanarconfig != None:
         self.config = srxplanarconfig
         self.config.updateConfig(filename=configfile, args=args, **kwargs)
     else:
         self.config = SrXplanarConfig(filename=configfile,
                                       args=args,
                                       **kwargs)
     # init modulars
     self.loadimage = LoadImage(self.config)
     self.calculate = Calculate(self.config)
     self.mask = Mask(self.config, self.calculate)
     self.saveresults = SaveResults(self.config)
     return
예제 #2
0
 def __init__(self, srxplanarconfig=None, configfile=None, args=None, **kwargs):
     '''
     init srxplanar form a SrXplanarConfig instance, or config file, or args passed from cmd
     or kwargs. If both SrXplanarConfig instance and other configfile/args/kwargs is specified, 
     it will first init from config instance then update using configfile/args/kwargs
     
     :param srxplanarconfig: SrXplanarConfig, init srxplanar from a config instance
     :param configfile: string, name of config file
     :param args: list of str, usually be sys.argv
     :param kwargs: you can use like 'xbeamcenter=1024' or a dict to update the value of xbeamcenter
     '''
     if srxplanarconfig != None:
         self.config = srxplanarconfig
         self.config.updateConfig(filename=configfile, args=args, **kwargs)
     else:
         self.config = SrXplanarConfig(filename=configfile, args=args, **kwargs)
     # init modulars
     self.mask = Mask(self.config)
     self.loadimage = LoadImage(self.config)
     self.calculate = Calculate(self.config)
     self.saveresults = SaveResults(self.config)
     return
예제 #3
0
class SrXplanar(object):
    '''
    main modular for srxplanar
    '''

    def __init__(self, srxplanarconfig=None, configfile=None, args=None, **kwargs):
        '''
        init srxplanar form a SrXplanarConfig instance, or config file, or args passed from cmd
        or kwargs. If both SrXplanarConfig instance and other configfile/args/kwargs is specified, 
        it will first init from config instance then update using configfile/args/kwargs
        
        :param srxplanarconfig: SrXplanarConfig, init srxplanar from a config instance
        :param configfile: string, name of config file
        :param args: list of str, usually be sys.argv
        :param kwargs: you can use like 'xbeamcenter=1024' or a dict to update the value of xbeamcenter
        '''
        if srxplanarconfig != None:
            self.config = srxplanarconfig
            self.config.updateConfig(filename=configfile, args=args, **kwargs)
        else:
            self.config = SrXplanarConfig(filename=configfile, args=args, **kwargs)
        # init modulars
        self.mask = Mask(self.config)
        self.loadimage = LoadImage(self.config)
        self.calculate = Calculate(self.config)
        self.saveresults = SaveResults(self.config)
        return

    def updateConfig(self, filename=None, args=None, **kwargs):
        '''
        update config using configfile/args/kwargs, then rerun all prepareCalculation()
        
        :param configfile: string, name of config file
        :param args: list of str, usually be sys.argv
        :param kwargs: you can use like 'xbeamcenter=1024' or a dict to update the value of xbeamcenter
        
        :return: None
        '''
        self.config.updateConfig(filename=filename, args=args, **kwargs)
        # update instances
        self.calculate.prepareCalculation()
        self.saveresults.prepareCalculation()
        return

    def prepareCalculation(self, pic=None, automask=True):
        '''
        prepare data used in calculation
        
        :param pic: str, list of str, or 2d array, if provided, and automask is True, then 
            generate a dynamic mask
        :param automask: bool, if True, and pic is not None, then generate a dynamic mask
        
        :return: None
        '''
        self.staticmask = self.mask.staticMask()
        self.correction = self.calculate.genCorrectionMatrix()
        # if a pic is provided, then generate one-time dynamicmask
        if (pic != None) and automask:
            image = self._getPic(pic)
            # image *= self.correction
            dymask = self.mask.dynamicMask(image)
            if dymask != None:
                dymask = np.logical_or(self.staticmask, dymask)
            else:
                dymask = self.staticmask
            
            if self.config.avgmask:
                mask = self.genAvgMask(image, dymask=dymask)
                self.staticmask = np.logical_or(dymask, mask)

        self.calculate.genIntegrationInds(self.staticmask)
        return
    
    def genAvgMask(self, pic, high=None, low=None, dymask=None, cropedges=None):
        '''
        generate a mask that automatically mask the pixels, whose intensities are 
        too high or too low compare to the pixels which have similar twotheta value
        
        :param pic: string or 2d array, image file (array)
        :param high: float (default: 2.0), int > avgint * high will be masked
        :param low: float (default: 0.5), int < avgint * low will be masked
        :param dymask: 2d bool array, mask array used in calculation, True for masked pixel, 
            if None, then use self.staticmask
        :param cropedges: crop the image, maske pixels around the image edge (left, right, 
            top, bottom), must larger than 0, if None, use self.config.corpedges
        
        :return 2d bool array, True for masked pixel, edgemake included, dymask not included
        '''
        image = self._getPic(pic)
        if dymask == None:
            dymask = self.staticmask
        high = self.config.avgmaskhigh if high == None else high
        low = self.config.avgmasklow if low == None else low
        
        self.calculate.genIntegrationInds(dymask)
        chi = self.calculate.intensity(image)
        index = np.rint(self.calculate.tthorqmatrix / self.config.tthorqstep).astype(int)
        index[index >= len(chi[1]) - 1] = len(chi[1]) - 1
        avgimage = chi[1][index.ravel()].reshape(index.shape)
        mask = np.ones((self.config.ydimension, self.config.xdimension), dtype=bool)
        ce = self.config.cropedges if cropedges == None else cropedges
        mask[ce[2]:-ce[3], ce[0]:-ce[1]] = np.logical_or(image[ce[2]:-ce[3], ce[0]:-ce[1]] < avgimage * low,
                                                        image[ce[2]:-ce[3], ce[0]:-ce[1]] > avgimage * high)
        return mask
        
    def _picChanged(self, extramask=None):
        '''
        update all pic related data (such as dynamic mask) when a new image is read
        
        :param extramask: 2d array, extra mask applied in integration
        
        :return: None
        '''
        dynamicmask = self.mask.dynamicMask(self.pic)

        if dynamicmask != None:
            mask = np.logical_or(self.staticmask, dynamicmask)
            if extramask != None:
                mask = np.logical_or(mask, extramask)
        elif extramask != None:
            mask = np.logical_or(self.staticmask, extramask)
        else:
            mask = self.staticmask

        if (dynamicmask != None) or (extramask != None):
            self.calculate.genIntegrationInds(mask)
        return

    def _getSaveFileName(self, imagename=None, filename=None):
        '''
        get the save file name, the priority order is self.output> filename> imagename > 'output'(default name)
        
        :param imagename: string, filename/path of image file (drop this term if it is an image array)
        :param filename: string, 
        
        :return: string, name of file to be saved 
        '''
        rv = 'output'
        if self.config.output != None and self.config.output != '':
            rv = self.config.output
        elif filename != None:
            rv = filename
        elif imagename != None and isinstance(imagename, (str, unicode)):
            rv = imagename
        return rv

    def _getPic(self, image, flip=None, correction=None):
        '''
        load picture to 2d array
        
        :param image: could be a string, a list of string or a 2d array, 
            if string, load the image file using the string as the path.
            if list of string, load the image files using the string as their path
            and sum them togethor
            if 2d array, use that array directly
        :param flip: flip the image/2d array,
            if None: flip on the string/list of string, not flip on the 2d array
            Flip behavior is controlled in self.config
        :param correction: apply correction to the returned 2d array
            if None: correct on the string/list of string, not correct on the 2d array
            
        :return: 2d array of image
        '''
        if isinstance(image, list):
            rv = np.zeros((self.config.ydimension, self.config.xdimension))
            for imagefile in image:
                rv += self._getPic(imagefile)
            rv /= len(image)
        elif isinstance(image, (str, unicode)):
            rv = self.loadimage.loadImage(image)
            if correction == None or correction == True:
                ce = self.config.cropedges
                rv[ce[2]:-ce[3], ce[0]:-ce[1]] = rv[ce[2]:-ce[3], ce[0]:-ce[1]] * self.correction 
                # rv *= self.correction
        else:
            rv = image
            if flip == True:
                rv = self.loadimage.flipImage(rv)
            if correction == True:
                # rv *= self.correction
                ce = self.config.cropedges
                rv[ce[2]:-ce[3], ce[0]:-ce[1]] = rv[ce[2]:-ce[3], ce[0]:-ce[1]] * self.correction
        if rv.dtype.kind != 'f':
            rv = rv.astype(float)
        return rv

    def integrate(self, image, savename=None, savefile=True, flip=None, correction=None, extramask=None):
        '''
        integrate 2d image to 1d diffraction pattern, then save to disk
        
        :param image: str or 2d array, 
            if str, then read image file using it as file name.
            if 2d array, integrate this 2d array.
        :param savename: str, name of file to save
        :param savefile: boolean, if True, save file to disk, if False, do not save file to disk
        :param flip: flip the image/2d array,
            if None: flip on the string/list of string, not flip on the 2d array
            Flip behavior is controlled in self.config
        :param correction: apply correction to the returned 2d array
            if None: correct on the string/list of string, not correct on the 2d array
        :param extramask: 2d array, extra mask applied in integration 
        
        :return: dict, rv['chi'] is a 2d array of integrated intensity, shape is (2, len of intensity) 
            or (3, len of intensity) in [tth or q, intensity, (uncertainty)]. rv['filename'] is the 
            name of file to save to disk
        '''
        rv = {}
        self.pic = self._getPic(image, flip, correction)

        rv['filename'] = self._getSaveFileName(imagename=image, filename=savename)
        self._picChanged(extramask=extramask)
        # calculate
        rv['chi'] = self.chi = self.calculate.intensity(self.pic)
        # save
        if savefile:
            rv['filename'] = self.saveresults.save(rv)
        return rv

    def integrateFilelist(self, filelist, summation=None, filename=None, flip=None, correction=None, extramask=None):
        '''
        process all file in filelist, integrate them separately or together
        
        :param filelist: list of string, files to be integrated (full path)
        :param summation: bool or None, sum all files together or not, if None,
            use self.config.summation
        :param filename: file name of output file
        :param flip: flip the image/2d array,
            if None: flip on the string/list of string, not flip on the 2d array
            Flip behavior is controlled in self.config
        :param correction: apply correction to the returned 2d array
            if None: correct on the string/list of string, not correct on the 2d array
        :param extramask: 2d array, extra mask applied in integration 
        
        :return: list of dict, in each dict, rv['chi'] is a 2d array of integrated intensity, shape is (2, len of intensity) 
            or (3, len of intensity) as [tth or q, intensity, (uncertainty)]. rv['filename'] is the 
            name of file to save to disk
        '''
        summation = self.config.summation if summation == None else summation
        if (summation)and(len(filelist) > 1):
            image = self._getPic(filelist, flip, correction)
            if filename == None:
                if isinstance(filelist[-1], str):
                    filename = os.path.splitext(filelist[-1])[0] + '_sum.chi'
                else:
                    filename = 'Sum_xrd.chi'
            rv = [self.integrate(image, savename=filename, extramask=extramask)]
        else:
            i = 0
            rv = []
            for imagefile in filelist:
                if filename == None:
                    rvv = self.integrate(imagefile, flip=flip, correction=correction, extramask=extramask)
                else:
                    rvv = self.integrate(imagefile, savename=filename + '%03d' % i,
                                         flip=flip, correction=correction, extramask=extramask)
                rv.append(rvv)
        return rv

    def process(self):
        '''
        process the images according to filenames/includepattern/excludepattern/summation
        by default, it will scan current/tifdirectory and integrate all files match 
        includepattern/excludepattern and/or filenames.
        
        Usually this one is called from cmd line rather then script.
        
        :return: None
        '''
        if not self.config.nocalculation:
            filelist = self.loadimage.genFileList()
            if len(filelist) > 0:
                self.prepareCalculation(pic=filelist[0])
                self.integrateFilelist(filelist)
            else:
                print 'No input files or configurations'
                self.config.args.print_help()
        # mask creating
        elif self.config.createmask != '':
            self.createMask()
        # if no config is passed to srxplanar
        else:
            print 'No input files or configurations'
            self.config.args.print_help()
        return

    def createMask(self, filename=None, pic=None, addmask=None):
        '''
        create and save a mask according to addmask, pic, 1 stands for masked pixel in saved file
        
        :param filename: name of mask file to save, 'mask.npy' if it is None
        :param pic: 2d image array, may used in generating dynamic mask, Be careful if this one is flipped or not
        :param addmask: list of str, control how to generate mask, see Mask module for detail
        
        :return: 2d array, 1 stands for masked pixel here
        '''
        filename = self.config.createmask if filename == None else filename
        filename = 'mask.npy' if filename == '' else filename
        addmask = self.config.addmask if addmask == None else addmask
        if not hasattr(self, 'mask'):
            self.mask = Mask(self.config)
        if not hasattr(self, 'loadimage'):
            self.loadimage = LoadImage(self.config)
        if pic == None:
            filelist = self.loadimage.genFileList()
            if hasattr(self, 'pic'):
                if self.pic != None:
                    pic = self.pic
                else:
                    pic = self.loadimage.loadImage(filelist[0]) if len(filelist) > 0 else None
            else:
                pic = self.loadimage.loadImage(filelist[0]) if len(filelist) > 0 else None
        rv = self.mask.saveMask(filename, pic, addmask)
        return rv
예제 #4
0
class SrXplanar(object):
    '''
    main modular for srxplanar
    '''
    def __init__(self,
                 srxplanarconfig=None,
                 configfile=None,
                 args=None,
                 **kwargs):
        '''
        init srxplanar form a SrXplanarConfig instance, or config file, or args passed from cmd
        or kwargs. If both SrXplanarConfig instance and other configfile/args/kwargs is specified, 
        it will first init from config instance then update using configfile/args/kwargs
        
        :param srxplanarconfig: SrXplanarConfig, init srxplanar from a config instance
        :param configfile: string, name of config file
        :param args: list of str, usually be sys.argv
        :param kwargs: you can use like 'xbeamcenter=1024' or a dict to update the value of xbeamcenter
        '''
        if srxplanarconfig != None:
            self.config = srxplanarconfig
            self.config.updateConfig(filename=configfile, args=args, **kwargs)
        else:
            self.config = SrXplanarConfig(filename=configfile,
                                          args=args,
                                          **kwargs)
        # init modulars
        self.loadimage = LoadImage(self.config)
        self.calculate = Calculate(self.config)
        self.mask = Mask(self.config, self.calculate)
        self.saveresults = SaveResults(self.config)
        return

    def updateConfig(self, filename=None, args=None, **kwargs):
        '''
        update config using configfile/args/kwargs, then rerun all prepareCalculation()
        
        :param configfile: string, name of config file
        :param args: list of str, usually be sys.argv
        :param kwargs: you can use like 'xbeamcenter=1024' or a dict to update the value of xbeamcenter
        
        :return: None
        '''
        self.config.updateConfig(filename=filename, args=args, **kwargs)
        # update instances
        self.calculate.prepareCalculation()
        self.saveresults.prepareCalculation()
        return

    def prepareCalculation(self, pic=None):
        '''
        prepare data used in calculation
        
        :param pic: str, list of str, or 2d array, if provided, and automask is True, then 
            generate a dynamic mask
        
        :return: None
        '''
        self.staticmask = self.mask.staticMask()
        self.correction = self.calculate.genCorrectionMatrix()
        self.staticmask = np.logical_or(self.mask.edgeMask(), self.staticmask)
        self.calculate.genIntegrationInds(self.staticmask)
        return

    def _picChanged(self, extramask=None):
        '''
        update all pic related data (such as dynamic mask) when a new image is read
        
        :param extramask: 2d array, extra mask applied in integration
        
        :return: None
        '''
        dynamicmask = self.mask.dynamicMask(self.pic, dymask=self.staticmask)

        if dynamicmask != None:
            mask = np.logical_or(self.staticmask, dynamicmask)
            if extramask != None:
                mask = np.logical_or(mask, extramask)
        elif extramask != None:
            mask = np.logical_or(self.staticmask, extramask)
        else:
            mask = self.staticmask

        if (dynamicmask != None) or (extramask != None):
            self.calculate.genIntegrationInds(mask)
        return

    def _getSaveFileName(self, imagename=None, filename=None):
        '''
        get the save file name, the priority order is self.output> filename> imagename > 'output'(default name)
        
        :param imagename: string, filename/path of image file (drop this term if it is an image array)
        :param filename: string, 
        
        :return: string, name of file to be saved 
        '''
        rv = 'output'
        if self.config.output != None and self.config.output != '':
            rv = self.config.output
        elif filename != None:
            rv = filename
        elif imagename != None and isinstance(imagename, (str, unicode)):
            rv = imagename
        return rv

    def _getPic(self, image, flip=None, correction=None):
        '''
        load picture to 2d array
        
        :param image: could be a string, a list of string or a 2d array, 
            if string, load the image file using the string as the path.
            if list of string, load the image files using the string as their path
            and sum them togethor
            if 2d array, use that array directly
        :param flip: flip the image/2d array,
            if None: flip on the string/list of string, not flip on the 2d array
            Flip behavior is controlled in self.config
        :param correction: apply correction to the returned 2d array
            if None: correct on the string/list of string, not correct on the 2d array
            
        :return: 2d array of image
        '''
        if isinstance(image, list):
            rv = np.zeros((self.config.ydimension, self.config.xdimension))
            for imagefile in image:
                rv += self._getPic(imagefile)
            rv /= len(image)
        elif isinstance(image, (str, unicode)):
            rv = self.loadimage.loadImage(image)
            if correction == None or correction == True:
                ce = self.config.cropedges
                rv[ce[2]:-ce[3],
                   ce[0]:-ce[1]] = rv[ce[2]:-ce[3],
                                      ce[0]:-ce[1]] * self.correction
                # rv *= self.correction
        else:
            rv = image
            if flip == True:
                rv = self.loadimage.flipImage(rv)
            if correction == True:
                # rv *= self.correction
                ce = self.config.cropedges
                rv[ce[2]:-ce[3],
                   ce[0]:-ce[1]] = rv[ce[2]:-ce[3],
                                      ce[0]:-ce[1]] * self.correction
        if rv.dtype.kind != 'f':
            rv = rv.astype(float)
        return rv

    def integrate(self,
                  image,
                  savename=None,
                  savefile=True,
                  flip=None,
                  correction=None,
                  extramask=None):
        '''
        integrate 2d image to 1d diffraction pattern, then save to disk
        
        :param image: str or 2d array, 
            if str, then read image file using it as file name.
            if 2d array, integrate this 2d array.
        :param savename: str, name of file to save
        :param savefile: boolean, if True, save file to disk, if False, do not save file to disk
        :param flip: flip the image/2d array,
            if None: flip on the string/list of string, not flip on the 2d array
            Flip behavior is controlled in self.config
        :param correction: apply correction to the returned 2d array
            if None: correct on the string/list of string, not correct on the 2d array
        :param extramask: 2d array, extra mask applied in integration 
        
        :return: dict, rv['chi'] is a 2d array of integrated intensity, shape is (2, len of intensity) 
            or (3, len of intensity) in [tth or q, intensity, (uncertainty)]. rv['filename'] is the 
            name of file to save to disk
        '''
        rv = {}
        self.pic = self._getPic(image, flip, correction)

        rv['filename'] = self._getSaveFileName(imagename=image,
                                               filename=savename)
        self._picChanged(extramask=extramask)
        # calculate
        rv['chi'] = self.chi = self.calculate.intensity(self.pic)
        # save
        if savefile:
            rv['filename'] = self.saveresults.save(rv)
        return rv

    def integrateFilelist(self,
                          filelist,
                          summation=None,
                          filename=None,
                          flip=None,
                          correction=None,
                          extramask=None):
        '''
        process all file in filelist, integrate them separately or together
        
        :param filelist: list of string, files to be integrated (full path)
        :param summation: bool or None, sum all files together or not, if None,
            use self.config.summation
        :param filename: file name of output file
        :param flip: flip the image/2d array,
            if None: flip on the string/list of string, not flip on the 2d array
            Flip behavior is controlled in self.config
        :param correction: apply correction to the returned 2d array
            if None: correct on the string/list of string, not correct on the 2d array
        :param extramask: 2d array, extra mask applied in integration 
        
        :return: list of dict, in each dict, rv['chi'] is a 2d array of integrated intensity, shape is (2, len of intensity) 
            or (3, len of intensity) as [tth or q, intensity, (uncertainty)]. rv['filename'] is the 
            name of file to save to disk
        '''
        summation = self.config.summation if summation == None else summation
        if (summation) and (len(filelist) > 1):
            image = self._getPic(filelist, flip, correction)
            if filename == None:
                if isinstance(filelist[-1], str):
                    filename = os.path.splitext(filelist[-1])[0] + '_sum.chi'
                else:
                    filename = 'Sum_xrd.chi'
            rv = [
                self.integrate(image, savename=filename, extramask=extramask)
            ]
        else:
            i = 0
            rv = []
            for imagefile in filelist:
                if filename == None:
                    rvv = self.integrate(imagefile,
                                         flip=flip,
                                         correction=correction,
                                         extramask=extramask)
                else:
                    rvv = self.integrate(imagefile,
                                         savename=filename + '%03d' % i,
                                         flip=flip,
                                         correction=correction,
                                         extramask=extramask)
                rv.append(rvv)
        return rv

    def process(self):
        '''
        process the images according to filenames/includepattern/excludepattern/summation
        by default, it will scan current/tifdirectory and integrate all files match 
        includepattern/excludepattern and/or filenames.
        
        Usually this one is called from cmd line rather then script.
        
        :return: None
        '''
        if not self.config.nocalculation:
            filelist = self.loadimage.genFileList()
            if len(filelist) > 0:
                self.prepareCalculation(pic=filelist[0])
                self.integrateFilelist(filelist)
            else:
                print 'No input files or configurations'
                self.config.args.print_help()
        # mask creating
        elif self.config.createmask != '':
            self.createMask()
        # if no config is passed to srxplanar
        else:
            print 'No input files or configurations'
            self.config.args.print_help()
        return

    def createMask(self, filename=None, pic=None, addmask=None):
        '''
        create and save a mask according to addmask, pic, 1 stands for masked pixel in saved file
        
        :param filename: name of mask file to save, 'mask.npy' if it is None
        :param pic: 2d image array, may used in generating dynamic mask, Be careful if this one is flipped or not
        :param addmask: list of str, control how to generate mask, see Mask module for detail
        
        :return: 2d array, 1 stands for masked pixel here
        '''
        filename = self.config.createmask if filename == None else filename
        filename = 'mask.npy' if filename == '' else filename
        addmask = self.config.addmask if addmask == None else addmask
        if not hasattr(self, 'mask'):
            self.mask = Mask(self.config)
        if not hasattr(self, 'loadimage'):
            self.loadimage = LoadImage(self.config)
        if pic == None:
            filelist = self.loadimage.genFileList()
            if hasattr(self, 'pic'):
                if self.pic != None:
                    pic = self.pic
                else:
                    pic = self.loadimage.loadImage(
                        filelist[0]) if len(filelist) > 0 else None
            else:
                pic = self.loadimage.loadImage(
                    filelist[0]) if len(filelist) > 0 else None
        rv = self.mask.saveMask(filename, pic, addmask)
        return rv