def main():
    ##  Initial print
    print('\n')
    print('########################################################')
    print('#############   REGRIDDING BACKPROJECTION  #############')
    print('########################################################')
    print('\n')

    ##  Get the startimg time of the reconstruction
    time1 = time.time()

    ##  Get input arguments
    args = getArgs()

    ##  Get input/output directory
    pathin, pathout = utils.get_io_path(args)

    print('\nInput path:\n', pathin)
    print('\nOutput path:\n', pathout)

    ##  Get input files
    file_list, file1, nimg, ext = utils.get_input(args, pathin)

    print('\nNumber of input files: ', nimg)
    print('Extension of the files: ', ext)

    ##  Read first sinogram
    sino = io.readImage(pathin + file1).astype(myfloat)
    nang, npix = sino.shape

    print('\nSinogram to reconstruct:\n', file1)
    print('Number of projection angles: ', nang)
    print('Number of pixels: ', npix)

    if args.plot is True:
        dis.plot(sino, 'Input sinogram')

    ##  Getting projection geometry
    if args.geometry == '0':
        print(
            '\nDealing with equiangular projections distributed between 0 and'
            + ' 180 degrees ---> [0,180)')
        angles = utils.create_projection_angles(nang)

    else:
        print('\nReading list of projection angles:\n', pathin + args.geometry)
        angles = utils.create_projection_angles(textfile=pathin +
                                                args.geometry)

    ##  Set center of rotation axis
    if args.ctr == None:
        ctr = 0.0
        print('Center of rotation axis placed at pixel: ', npix * 0.5)
    else:
        if args.ctr == -1:
            ctr = proc.search_rot_ctr(sino, None, 'a')
            print('Center of rotation axis placed at pixel: ', ctr)
        else:
            ctr = args.ctr
            print('Center of rotation axis placed at pixel: ', ctr)
            if args.dbp is True:
                sino[:, :] = proc.sino_correct_rot_axis(sino, ctr)
                print('Center of rotation corrected')
                ctr = 0.0

    ##  Enable edge padding
    if args.edge_pad is True:
        sino = proc.sino_edge_padding(sino, 0.5).astype(myfloat)
        i1 = int((sino.shape[1] - npix) * 0.5)
        i2 = i1 + npix
        npix = sino.shape[1]

        if ctr != 0.0:
            ctr += i1

        if args.plot is True:
            dis.plot(sino, 'Edge padded sinogram')
    else:
        i1 = 0
        i2 = npix

    ##  External sinogram filtering
    if args.filt == 'ramp-ext' or args.filt == 'conv-ext':
        if filt == 'ramp-ext':
            sino = fil.filter_fft(sino, 'ramp')

        elif filt == 'conv-ext':
            sino = fil.filter_convolve(sino)

        sino *= 4.0 / myfloat(npix)
        args.filt = 0

    ##  Differential sinogram fo DBP
    if args.dbp is True:
        print('\nDifferential backprojection enabled')
        print(
            'Computing differential sinogram by means of Savitzky-Golay method'
        )
        print('Savizky-Golay window length: ', args.sg)
        sino[:, :] = proc.diff_sino_savitzky_golay(sino, window_size=args.sg)

        if args.plot is True:
            dis.plot(sino, 'Differential sinogram')

    ##  Initialize projectior class
    tp = cpj.projectors(npix, angles, ctr=ctr, args=args)

    ##  Apply forward projection operator
    time_rec1 = time.time()
    reco = tp.fbp(sino)
    time_rec2 = time.time()

    ##  Crop reconstruction
    if args.edge_pad:
        reco = reco[i1:i2, i1:i2]

    ##  Display reconstruction
    if args.plot is True:
        dis.plot(reco, 'Reconstruction')

    ##  Save reconstruction
    save_reconstruction(pathout, file1, args, reco)

    ##  Reconstruct sinograms from all the other images in the stack
    if args.filein is None:
        pool = mproc.Pool()
        for i in range(1, nimg):
            pool.apply_async(
                multi_thread,
                (pathin, pathout, file_list[0][i], args, [i1, i2]))
        pool.close()
        pool.join()
    time2 = time.time()

    print('\nTime elapsed to run the 1st backward gridrec: ',
          time_rec2 - time_rec1)
    print('Total time elapsed for the run of the program: ', time2 - time1)

    print('\n')
    print('##############################################')
    print('####   REGRIDDING BACKPROJECTION DONE !   ####')
    print('##############################################')
    print('\n')
def main():
    ##  Initial print
    print('\n')
    print('##########################################################')
    print('##########################################################')
    print('#####                                                #####')
    print('#####          ADMM Iterative Reconstruction         #####')
    print('#####                                                #####')
    print('##########################################################')
    print('##########################################################')
    print('\n')

    ##  Get input arguments
    args = getArgs()

    ##  Get input and output paths
    pathin, pathout = utils.get_io_path(args)

    print('\nInput path:\n', pathin)
    print('\nOutput path:\n', pathout)

    ##  Get input sinogram
    sino_list = []
    filein = []

    if args.filein is not None:
        sinoname = pathin + args.filein
        sino = io.readImage(sinoname).astype(myfloat)
        if args.angle_pi is True:
            sino = sino[:sino.shape[0] - 1, :]
        nang, npix = sino.shape
        nz = 1
        sino_list.append(sino)
        filein.append(args.filein)
        print('\nSinogram to reconstruct:\n', sinoname)

    else:
        print('\nReading stack of images\n')
        curr_dir = os.getcwd()
        os.chdir(pathin)

        for f in os.listdir('./'):
            if f.endswith('.DMP') is True:
                ext = '.DMP'
                break
            elif f.endswith('.tif') is True:
                ext = '.tif'
                break
            else:
                sys.exit('\nERROR: no .DMP or .tif file found in:\n' + pathin)

        filein.append(sorted(glob.glob('*' + ext)))
        nz = len(filein[0])
        os.chdir(curr_dir)

        print('Stack extension: ', ext)
        print('Number of slices: ', nz)

        print('\nLoading images .... ')
        for i in range(nz):
            if i == 0:
                sino = io.readImage(pathin + filein[0][i]).astype(myfloat)
                nang, npix = sino.shape
                sino_list.append(sino)
            else:
                sino_list.append(
                    io.readImage(pathin + filein[0][i]).astype(myfloat))
        print(' done! ')

    print('\nNumber of projection angles: ', nang)
    print('Number of pixels: ', npix)

    ##  Check plot
    if args.plot is True:
        if nz == 1:
            dis.plot(sino_list[0], 'Input sinogram')
        else:
            nzz = np.int(nz * 0.5)
            dis.plot(sino_list[nzz], 'Input sinogram')

    ##  Center of rotation axis
    if args.ctr == -1:
        ctr = npix * 0.5

    elif args.ctr != -1:
        ctr = args.ctr

    ##  Enable edge padding
    if args.lt is True:
        edf = 0.87
    elif args.lt is False and args.edge_padding != 0:
        edf = args.edge_padding
    else:
        edf = 0.0

    if edf:
        npix_old = npix
        for i in range(nz):
            sino_list[i] = proc.sino_edge_padding(sino_list[i], edf)
        npix = sino_list[0].shape[1]
        i1 = myint((npix - npix_old) * 0.5)
        i2 = i1 + npix_old
        ctr += i1

        print('\nEdge padding: ', edf)
        print('Number of edge-padded pixels: ', npix)
        print('Index start: ', i1, '   Index end: ', i2)
        print('Center of rotation axis new position: ', ctr)

        if args.plot is True:
            if nz == 1:
                dis.plot(sino_list[0], 'Sinogram with edge-padding')
            else:
                nzz = np.int(nz * 0.5)
                dis.plot(sino_list[nzz], 'Input sinogram')

    else:
        npix_old = npix
        i1 = 0
        i2 = npix

    ##  Compute differential sinogram if DBP option enabled
    if args.dbp is True:
        print('\nComputing differential sinogram ....')
        for i in range(nz):
            sino_list[i] = proc.diff_sino_savitzky_golay(sino_list[i],
                                                         window_size=args.sg)

        if args.plot is True:
            dis.plot(sino_list[0], 'Differential sinogram')

    ##  Correct for the center of rotation axis
    if args.ctr != -1:
        for i in range(nz):
            sino_list[i] = proc.sino_correct_rot_axis(sino_list[i], ctr)

    print('\nCenter of rotation axis position: ', ctr)
    print('Center of rotation corrected')

    ##  Get geometry
    if args.geometry == '0':
        angles = utils.create_projection_angles(nang)
    else:
        angles = utils.create_projection_angles(textfile=pathin +
                                                args.geometry)

    ##  Getting stopping criterion
    print('\nSetup of the iterative procedure:')

    if nz == 0:
        labelout = pathout + filein[0][:len(filein[0]) - 4]
    else:
        labelout = pathout + filein[0][0][:len(filein[0]) - 4]

    param = cap.admm_param(npix_old, nang, nz, ctr, labelout, args)

    print('Projectors enabled: ', args.projector)

    if args.dbp is True:
        print('DBP reconstruction enabled')

    if args.dpc is True:
        print('DPC reconstruction enabled')

    if args.n_iter is not None:
        print('Number of iterations: ', param.n_iter)

    if args.eps is not None:
        print('Stopping epsilon: ', param.eps)

    if args.n_iter_pcg is not None:
        print('Number of PCG iterations: ', param.n_iter_pcg)

    if args.plot is True:
        print('Interactive plot:', param.plot)

    if args.logfile is True:
        print('Interactive plot:', param.logfile)

    if param.reg is not None:
        if param.reg == 'cg':
            print('Conjugate gradient')
        if param.reg == 'lasso':
            print('Regularization type: Lasso L1')
        elif param.reg == 'lasso-tv':
            print('Regularization type: Lasso TV')
        elif param.reg == 'pp-breg':
            print('Regularization type: Plug and Play -- TV Bregman')
        elif param.reg == 'pp-chamb':
            print('Regularization type: Plug and Play -- TV Chambolle')
        elif param.reg == 'pp-nlmeans':
            print('Regularization type: Plug and Play -- Non Local Means')
        elif param.reg == 'pp-tgv':
            print(
                'Regularization type: Plug and Play -- Total generalized variation'
            )
        elif param.reg == 'pp-nltv':
            print(
                'Regularization type: Plug and Play -- Non-local total variation'
            )

        if param.reg != 'cg':
            print('\nLambda 1: ', param.lambd1)
            print('Lambda 2: ', param.lambd2)
            print('Mu:       ', param.mu)

    if args.init_object is True:
        print('\nInitialization with FBP reconstruction:', param.init_object)

    if param.mask is not None:
        print('\nObject support enabled')
        if param.plot is True:
            dis.plot(param.mask, 'Object support')

    if param.mask_add is not None:
        print('\nAdditional supports provided')
        if param.plot is True:
            if param.mask_add_n == 1:
                dis.plot(param.mask_add[0])
            else:
                dis.plot_multi(param.mask_add)

    if param.lt is True:
        print('\nLocal tomography mode enabled')

    ##  Iterative reconstruction
    print('\n\nReconstructing with ADMM ....')
    time1 = time.time()
    reco_list, info = admm(sino_list, angles, param)
    time2 = time.time()
    print('.... reconstruction done!')

    for i in range(nz):
        ##  Crop reconstruction if edge-padding enabled
        if edf != 0.0:
            reco = reco_list[i, i1:i2, i1:i2]
        else:
            reco = reco_list[i, :, :]

        ##  Show reconstruction
        if args.plot is True and nz == 1 and args.reg != 'cg':
            dis.plot(reco, 'Reconstruction')
            plot_convergence_curves(info)
        elif args.plot is True and i == nzz and args.reg != 'cg':
            nzz = np.int(nz * 0.5)
            dis.plot(reco_list[nzz, :, :],
                     'Reconstruction of slice ' + str(nzz))

        ##  Save reconstruction
        if nz == 1:
            save_reco(pathout, filein[0], args, param, reco)
        else:
            save_reco(pathout, filein[0][i], args, param, reco)

    ##  Time elapsed for the reconstruction
    time_tot = (time2 - time1) / 60.0
    print('\nTime elapsed for the reconstruction: ', time_tot)

    ##  Write log file
    if args.logfile is True:
        write_logfile(pathin, pathout, args, angles, ctr, param, time_tot,
                      info)

        write_info(pathout, filein[0], info, param, args)

    ##  Final print
    print('\n')
    print('\n')
    print('##########################################################')
    print('##########################################################')
    print('#####                                                #####')
    print('#####             ADMM Reconstruction done!          #####')
    print('#####                                                #####')
    print('##########################################################')
    print('##########################################################')
    print('\n')
예제 #3
0
def main():
    ##  Initial print
    print('\n')
    print('##########################################################')
    print('##########################################################')
    print('#####                                                #####')
    print('#####       STATISTICAL ITERATIVE RECONSTRUCTION     #####')
    print('#####                                                #####')
    print('##########################################################')
    print('##########################################################')
    print('\n')

    ##  Getting arguments
    args = getArgs()

    ##  Get input & output paths
    pathin, pathout = utils.get_io_path(args)

    print('\nInput path: \n', pathin)
    print('\nOutput path:\n', pathout)

    ##  Get input sinogram
    sino_list = []
    filein = []

    if args.filein is not None:
        sinoname = pathin + args.filein
        sino = io.readImage(sinoname).astype(myfloat)
        nang, npix = sino.shape
        nz = 1
        sino_list.append(sino)
        filein.append(args.filein)
        print('\nSinogram to reconstruct:\n', sinoname)

    else:
        print('\nReading stack of images\n')
        curr_dir = os.getcwd()
        os.chdir(pathin)

        for f in os.listdir('./'):
            if f.endswith('.DMP') is True:
                ext = '.DMP'
                break
            elif f.endswith('.tif') is True:
                ext = '.tif'
                break
            else:
                sys.exit('\nERROR: no .DMP or .tif file found in:\n' + pathin)

        filein.append(sorted(glob.glob('*' + ext)))
        nz = len(filein[0])
        os.chdir(curr_dir)

        print('Stack extension: ', ext)
        print('Number of slices: ', nz)

        print('\nLoading images .... ')
        for i in range(nz):
            if i == 0:
                sino = io.readImage(pathin + filein[0][i]).astype(myfloat)
                nang, npix = sino.shape
                sino_list.append(sino)
            else:
                sino_list.append(
                    io.readImage(pathin + filein[0][i]).astype(myfloat))
        print(' done! ')

    print('\nNumber of projection angles: ', nang)
    print('Number of pixels: ', npix)

    ##  Check plot
    if args.plot is True:
        if nz == 1:
            dis.plot(sino_list[0], 'Input sinogram')
        else:
            nzz = np.int(0.5 * nz)
            dis.plot(sino_list[nzz], 'Input sinogram')

    ##  Center of rotation axis
    if args.ctr == -1:
        ctr = npix * 0.5

    elif args.ctr != -1:
        ctr = args.ctr

    ##  Enable edge padding
    if args.lt is True:
        edf = 0.87
    elif args.lt is False and args.edge_padding != 0:
        edf = args.edge_padding
    else:
        edf = 0.0

    if edf:
        npix_old = npix
        for i in range(nz):
            sino_list[i] = proc.sino_edge_padding(sino_list[i], edf)
        npix = sino_list[0].shape[1]
        i1 = myint((npix - npix_old) * 0.5)
        i2 = i1 + npix_old
        ctr += i1

        print('\nEdge padding: ', edf)
        print('Number of edge-padded pixels: ', npix)
        print('Index start: ', i1, '   Index end: ', i2)
        print('Center of rotation axis new position: ', ctr)

        if args.plot is True:
            dis.plot(sino_list[0], 'Sinogram with edge-padding')

    else:
        npix_old = npix
        i1 = 0
        i2 = npix

    ##  Correct for the center of rotation axis
    if args.ctr != -1:
        for i in range(nz):
            sino_list[i] = proc.sino_correct_rot_axis(sino_list[i], ctr)

    print('\nCenter of rotation axis position: ', ctr)
    print('Center of rotation corrected')

    ##  Get geometry
    if args.geometry == '0':
        angles = utils.create_projection_angles(nang)
    else:
        angles = utils.create_projection_angles(textfile=pathin +
                                                args.geometry)

    ##  Setup iterative procedure
    print('\nSetup of the iterative procedure:')

    if nz == 0:
        labelout = pathout + filein[0][:len(filein[0]) - 4]
    else:
        labelout = pathout + filein[0][0][:len(filein[0]) - 4]

    param = csp.sir_param(nang, npix_old, nz, ctr, labelout, args)

    print('Selected projector: ', args.projector)

    if args.eps is not None:
        print('Stopping threshold: ', param.eps)

    if args.n_iter is not None:
        print('Number of iterations: ', param.n_iter)

    if args.plot is True:
        print('Interactive plot:', param.plot)

    if args.logfile is True:
        print('Interactive plot:', param.logfile)

    if param.reg is not None:
        if param.reg == 'huber':
            print('Regularization type: Huber penalty')
            print('Huber constant ---> delta: ')
        elif param.reg == 'tikhonov':
            print('Regularization type: l2 penalty')
        elif param.reg == 'haar':
            print('Regularization type: l1 penalty')

        print('Regularization constant (beta): ', param.reg_cost)

    if args.init_object is True:
        print('Initialization with FBP reconstruction:', param.init_object)

    ##  Reconstruction
    print('\n\nPerforming STASTICAL ITERATIVE RECONSTRUCTION ....')
    time1 = time.time()
    reco_list, info = sir(sino_list, angles, param)
    time2 = time.time()
    print('.... reconstruction done!')

    for i in range(nz):
        ##  Crop reconstruction if edge-padding enabled
        if edf != 0.0:
            reco = reco_list[i, i1:i2, i1:i2]
        else:
            reco = reco_list[i, :, :]

        ##  Show reconstruction
        if args.plot is True and nz == 1:
            dis.plot(reco, 'Reconstruction')
        elif args.plot is True and i == nzz:
            dis.plot(reco, 'Reconstruction')

        ##  Save reconstruction
        if nz == 1:
            save_reco(pathout, filein[0], args, param, reco)
        else:
            save_reco(pathout, filein[0][i], args, param, reco)

    ##  Time elapsed for the reconstruction
    time_tot = (time2 - time1) / 60.0
    print('\nTime elapsed for the reconstruction: ', time_tot)

    ##  Write log file
    if args.logfile is True:
        write_logfile(pathin, pathout, args, angles, ctr, param, time_tot,
                      info)

        write_info(pathout, filein[0], info, param, args)

    ##  Final print
    print('\n')
    print('\n')
    print('##########################################################')
    print('##########################################################')
    print('#####                                                #####')
    print('#####   STATISTICAL ITERATIVE RECONSTRUCTION DONE!   #####')
    print('#####                                                #####')
    print('##########################################################')
    print('##########################################################')
    print('\n')
def main():
    ##  Initial print
    print('\n')
    print('###########################################################')
    print('#############   FORWARD REGRIDDING PROJECTOR  #############')
    print('###########################################################')
    print('\n')

    ##  Get the startimg time of the reconstruction
    time1 = time.time()

    ##  Get input arguments
    args = getArgs()

    ##  Get input/output directory
    pathin, pathout = utils.get_io_path(args)

    print('\nInput path:\n', pathin)
    print('\nOutput path:\n', pathout)

    ##  Get input files
    file_list, file1, nimg, ext = utils.get_input(args, pathin)

    print('\nNumber of input files: ', nimg)
    print('Extension of the files: ', ext)

    ##  Read first image
    image = io.readImage(pathin + file1).astype(myfloat)
    npix = image.shape[0]

    print('\nFirst image to forward project: ', file1)
    print('Number of pixels: ', npix)

    if args.plot is True:
        dis.plot(image, 'Input image')

    ##  Get projection angles
    if args.geometry == '0' or args.geometry == '1':
        nang = args.nang
        angle_type = myint(args.geometry)

        if args.angle_range.find(':') == -1 or args.geometry == -1:
            angle_start = myfloat(args.angle_range)
            angle_end = angle_start + 180.0

        else:
            angle_aux = args.angle_range.find(':')
            angle_start = myfloat(angle_aux[0])
            angle_end = myfloat(angle_aux[1])

        angles = utils.create_projection_angles(nang, angle_start, angle_end)

    else:
        angles = utils.create_projection_angles(pathin + args.geometry)

    nang = len(angles)

    print('\nNumber of views: ', nang)
    print('Selected angle range: [ ', angle_start, ' , ', angle_end, ' )')
    print('Angles:\n', angles)

    ##  Initialize projectior class
    tp = cpj.projectors(npix, angles, args=args)

    ##  Apply forward projection operator
    time_rec1 = time.time()
    sino = tp.A(image)
    time_rec2 = time.time()

    ##  Display sinogram
    if args.plot is True:
        dis.plot(sino, 'Sinogram')

    ##  Save sinogram
    save_sinogram(pathout, file1, angles, args, sino)

    ##  Create sinograms from all the other images in the stack
    if args.filein is None:
        pool = mproc.Pool()
        for i in range(1, nimg):
            pool.apply_async(multi_thread,
                             (pathin, pathout, file_list[0][i], angles, args))
        pool.close()
        pool.join()
    time2 = time.time()

    print('\nTime elapsed to run the 1st forward gridrec: ',
          time_rec2 - time_rec1)
    print('Total time elapsed for the run of the program: ', time2 - time1)

    print('\n')
    print('#######################################')
    print('####    FORWARD PROJECTION DONE !  ####')
    print('#######################################')
    print('\n')
def main():
    ##  Initial print
    print('\n')
    print('########################################################')
    print('####              CREATE VIRTUAL SINOGRAM           ####')
    print('########################################################')
    print('\n')  



    ##  Get arguments
    args = getArgs()



    ##  Get input/output directory
    pathin , pathout = utils.get_io_path( args )
    
    print('\nInput path:\n', pathin)
    print('\nOutput path:\n', pathout)



    ##  Get input files
    file_list , file1 , nimg , ext = utils.get_input( args , pathin )
    
    print('\nNumber of input files: ' , nimg)
    print('Extension of the files: ', ext)



    ##  Read first sinogram
    sino = io.readImage( pathin + file1 ).astype( myfloat )
    nang , npix = sino.shape

    print('\nSinogram to reconstruct:\n', file1)
    print('Number of projection angles: ', nang)
    print('Number of pixels: ', npix)     

    if args.plot is True:
        dis.plot( sino , 'Input sinogram' )



    ##  Set center of rotation axis
    if args.ctr == None:
        ctr = 0.0
        print('Center of rotation axis placed at pixel: ', npix * 0.5)  
    else:
        ctr = args.ctr
        print('Center of rotation axis placed at pixel: ', ctr)



    ##  Enable edge-padding
    if args.edge_pad is True:
        sino = proc.sino_edge_padding( sino , 0.5 ).astype( myfloat )
        i1 = int( ( sino.shape[1] - npix ) * 0.5 )
        i2 = i1 + npix            
        npix = sino.shape[1]

        if ctr != 0.0:
            ctr += i1
        
        if args.plot is True:
            dis.plot( sino , 'Edge padded sinogram' )
    else:
        i1 = 0
        i2 = npix 



    ##  Prepare projectors
    ang = np.arange( nang ) * 180.0 / myfloat( nang )  
    tp = cpj.projectors( npix , ang , kernel='kb' , oversampl=2.32 , 
                         W=6.6 , errs=6.0e-6 , interp='lin' , 
                         radon_degree=0 , filt=args.filt , ctr=ctr ) 



    ##  Reconstruct
    reco = tp.fbp( sino )
    if args.plot is True:
        dis.plot( reco , 'Reconstruction' ) 
    #reco = reco[i1:i2,i1:i2]



    ##  Zero-out pixels outside resolution circle
    reco_new = reco.copy();  reco_new[:] = 0.0
    io.writeImage( 'reco.DMP' , reco[i1:i2,i1:i2] ) 
    reco_new[i1:i2,i1:i2] = utils.resol_circle_constr( reco[i1:i2,i1:i2] )
    reco[:] = reco_new[:]

    if args.plot is True:
        dis.plot( reco , 'Constrained reconstruction' )
    io.writeImage( 'reco_circle.DMP' , reco )



    ##  Background equalization
    reco[:] = background_equalization( reco )

    if args.plot is True:
        dis.plot( reco , 'Equalized reconstruction' )
    io.writeImage( 'reco_equaliz.DMP' , reco )



    ##  Forward projection
    nang_new = np.int( npix * np.pi / 2.0 )
    ang_new  = np.arange( nang_new ) * 180.0 / np.float32( nang_new )
    tp       = cpj.projectors( npix , ang_new , kernel='kb' , oversampl=2.32 , 
                               W=6.6 , errs=6.0e-6 , interp='lin' , 
                               radon_degree=0 ) 
    sino = tp.A( reco )
    #sino = sino[:,i1:i2]

    if args.plot is True:
        dis.plot( sino , 'Forward projection' )
    io.writeImage( 'sino_circle.DMP' , sino )



    ##  Save output file
    if args.fileout is None:
        filein    = args.filein
        extension = filein[len(filein)-4:]
        fileout   = filein[:len(filein)-4] + '_virt.tif'
    else:
        fileout = args.fileout
    io.writeImage( pathout + fileout , sino )
    print( '\nWritten output file:\n' , pathout + fileout )
def main():
    ##  Initial print
    print('\n')
    print('##################################################################')
    print('#############   TOMOGRAPHIC GRIDDING RECONSTRUCTION  #############')
    print('##################################################################')
    print('\n')

    ##  Get the startimg time of the reconstruction
    time1 = time.time()

    ##  Get input arguments
    args = getArgs()

    ##  Get input/output directory
    pathin, pathout = utils.get_io_path(args)

    print('\nInput path:\n', pathin)
    print('\nOutput path:\n', pathout)

    ##  Get input files
    file_list, file1, nimg, ext = utils.get_input(args, pathin)

    print('\nNumber of input files: ', nimg)
    print('Extension of the files: ', ext)

    ##  Read first sinogram
    sino = io.readImage(pathin + file1).astype(myfloat)
    nang, npix = sino.shape

    print('\nSinogram to reconstruct:\n', file1)
    print('Number of projection angles: ', nang)
    print('Number of pixels: ', npix)

    if args.plot is True:
        dis.plot(sino, 'Input sinogram')

    ##  Enable edge padding
    if args.edge_pad is True:
        sino = proc.sino_edge_padding(sino, 0.5).astype(myfloat)
        i1 = int((sino.shape[1] - npix) * 0.5)
        i2 = i1 + npix
        npix = sino.shape[1]
        ctr = args.ctr

        if ctr != 0.0:
            ctr += i1

        if args.plot is True:
            dis.plot(sino, 'Edge padded sinogram')
    else:
        i1 = 0
        i2 = npix
        ctr = args.ctr

    ##  Getting projection geometry
    if args.geometry == '0':
        print(
            '\nDealing with equiangular projections distributed between 0 and'
            + ' 180 degrees ---> [0,180)')
        angles = utils.create_projection_angles(nang)

    else:
        print('\nReading list of projection angles:\n', pathin + args.geometry)
        angles = utils.create_projection_angles(textfile=pathin +
                                                args.geometry)

    if args.plot is True:
        print('\nProjection angles:')
        pp.printArray(angles)

    ##  Enable object support calculation
    if args.object_support is True:
        print('\nObject support calculation enabled')
        mask = ob.object_support(sino)
        if args.plot is True:
            dis.plot(mask, 'Object support mask')

    ##  Differential sinogram fo DBP
    if args.dbp is True:
        print('\nDifferential backprojection enabled')
        print(
            'Computing differential sinogram by means of Savitzky-Golay method'
        )
        sino[:, :] = proc.diff_sino_savitzky_golay(sino, window_size=11)

        if args.plot is True:
            dis.plot(sino, 'Differential sinogram')

    ##  Initialize projectior class
    tp = cpj.projectors(npix, angles, ctr=ctr, args=args)

    ##  Apply forward projection operator
    time_rec1 = time.time()
    reco = tp.fbp(sino)
    time_rec2 = time.time()

    ##  Crop reconstruction
    if args.edge_pad:
        reco = reco[i1:i2, i1:i2]

    ##  Apply object support mask
    if args.object_support is True:
        reco[mask == 0] = 0.0

    ##  Display reconstruction
    if args.plot is True:
        dis.plot(reco, 'Reconstruction')

    ##  Save reconstruction
    save_reconstruction(pathout, file1, args, reco)

    ##  Reconstruct sinograms from all the other images in the stack
    if args.filein is None:
        pool = mproc.Pool()
        for i in range(1, nimg):
            pool.apply_async(
                multi_thread,
                (pathin, pathout, file_list[0][i], args, [i1, i2]))
        pool.close()
        pool.join()
    time2 = time.time()

    print('\nTime elapsed to run the 1st backward gridrec: ',
          time_rec2 - time_rec1)
    print('Total time elapsed for the run of the program: ', time2 - time1)

    print('\n')
    print('##############################################')
    print('####    GRIDDING RECONSTRUCTION DONE !    ####')
    print('##############################################')
    print('\n')