Python批量处理脚本实现及方法总结

May 20,2018   5766 words   21 min

Tags: Python

在之前已经写过很多利用python批量调用exe等脚本了,这里结合最新正在做的项目简单做一总结,记录一下新学到的东西。

首先介绍一下项目需求,和之前类似,这一次也是需要批量通过控制台命令调用一些已有的exe文件执行相关功能,参数以exe启动参数的形式传入。 这次处理的是高光谱卫星,一共有32个谱段,谱段之间要相互配准。 因此如果手动调用配准程序,那对于一景数据而言就需要手动输入命令31次,十分不方便。 仿照之前在卫星中心做项目的时候才用的批量脚本,又进行了一些改进,编写了这次的脚本。

1.代码

废话不多说,先直接上代码。

import os
import sys

# exe path
exe_path = "F:\\RCStat\\shiftGPU\\GenMUX.exe"
# base img path
argv2 = "D:\\img\\base.tif"
# resample img path
argv3 = "D:\\img"
# output img path
argv4 = "D:\\output"
# separator
separator = " "
# number of threads
argv5 = "16"


def bindCommands(filenames, out_filenames):
    commands = []
    for i in range(out_filenames.__len__()):
        command = exe_path + separator + argv2 + separator + argv3 + "\\" + filenames[
            i] + separator + argv4 + "\\" + out_filenames[i] + separator + argv5
        commands.append(command)
    return commands


def generateOutputFilename(filenames):
    out_filenames = []
    for i in range(filenames.__len__()):
        temp = filenames[i].split('.')[0]
        temp = temp + "_out.tif"
        out_filenames.append(temp)
    return out_filenames


def loadFiles(root_dir):
    paths = []
    names = []
    for parent, dirname, filenames in os.walk(root_dir):
        for filename in filenames:
            if filename.__contains__(".tif"):
                paths.append(parent + "\\" + filename)
                names.append(filename)
    paths.sort()
    names.sort()
    return paths, names


if sys.argv.__len__() == 2 and sys.argv[1] == "help":
    print("Help info:")
    print("Argv[1]:Path of exe file.")
    print("Argv[2]:The Path of base image.")
    print("Argv[3]:The dir of images goint to be processed.Note that there should be no other files except tif images.")
    print("Argv[4]:The ourput dir of processed images.")
    print("Argv[5]:The number of threads.\n")
    print("Usage example:")
    print("python Resample_script.py F:\\RCStat\\shiftGPU\\GenMUX.exe D:\\img\\base.tif D:\\img D:\\output 16")
elif sys.argv.__len__() == 6:
    exe_path = sys.argv[1]
    argv2 = sys.argv[2]
    argv3 = sys.argv[3]
    argv4 = sys.argv[4]
    argv5 = sys.argv[5]

    paths, filenames = loadFiles(argv3)
    output = generateOutputFilename(filenames)
    results = bindCommands(filenames, output)
    for i in range(results.__len__()):
        print("Command[" + (i + 1).__str__().zfill(3) + "]:" + results[i] + "\n")
    if sys.version_info.major < 3:
        flag = raw_input("Is it all right?y/n\n")
    else:
        flag = input("Is it all right?y/n\n")
    if flag == 'y':
        for i in range(results.__len__()):
            print("Executing:" + results[i])
            os.system(results[i])
            print("Finished " + (i + 1).__str__() + "/" + results.__len__().__str__())
            print("-" * 50)
    else:
        print("Exit.")
        exit()
else:
    script_name = sys.argv[0][sys.argv[0].rfind('/') + 1:]
    print("Input 'python " + script_name + " help'to get help information.")

和之前的批量脚本相比,这个脚本完善了使用逻辑、提示信息和用户交互,这样可以对使用者更加友好,减少出错的可能性。 同时也学到了一些新的小技巧,都体现在代码里了。

2.另一个需求

由于在实际使用过程中发现直接指定某个谱段作为基准会导致和它相差较远的谱段精度较差。 如以25谱段作为基准进行谱段配准,第24谱段重采效果不错,到第2谱段效果就不太理想了。 因此采用了另一种“迭代”的办法。即如以32谱段作为基准影像重采31谱段,然后以31谱段的重采结果作为新的基准影像重采30谱段,以此类推。 在实现层面相比于上面那种不考虑输出的批量脚本要复杂一些。 代码如下。

import os
import sys
import shutil

# exe path
exe_path = "F:\\RCStat\\shiftGPU\\GeoFrameVideo.exe"
# resample img path
argv2 = "D:\\img"
# output img path
argv3 = "D:\\output"
# separator
separator = " "


def bindCommands(filenames, out_filenames):
    commands = []
    for i in range(out_filenames.__len__()):
        if i % 2 == 0:
            if i == 0:
                command = exe_path + separator + argv2 + "\\" + filenames[i] + separator + argv2 + "\\" + filenames[
                    i + 1] + separator + argv3 + "\\" + out_filenames[i]
                commands.append(command)
            else:
                command = exe_path + separator + argv3 + "\\" + out_filenames[i - 1] + separator + argv2 + "\\" + \
                          filenames[
                              i + 1] + separator + argv3 + "\\" + out_filenames[i]
                commands.append(command)
        else:
            command = exe_path + separator + argv3 + "\\" + out_filenames[i - 1] + separator + argv2 + "\\" + filenames[
                i + 1] + separator + argv3 + "\\" + out_filenames[i]
            commands.append(command)
    return commands


def generateOutputFilename(filenames):
    out_filenames = []
    for i in range(filenames.__len__()):
        if i == 0:
            continue
        temp = filenames[i].split('.')[0]
        temp = temp + "_out.tif"
        out_filenames.append(temp)
    return out_filenames


def loadFiles(root_dir):
    paths = []
    names = []
    for parent, dirname, filenames in os.walk(root_dir):
        for filename in filenames:
            if filename.__contains__(".tif"):
                paths.append(parent + "\\" + filename)
                names.append(filename)
    paths.sort()
    paths.reverse()
    names.sort()
    names.reverse()
    return paths, names


def copyFirstBaseIMG():
    first = argv2 + "\\" + filenames[0]
    first_outpath = argv3 + "\\" + filenames[0]
    print("Copying first base img...")
    shutil.copy(first, first_outpath)
    print("Finished.")


if sys.argv.__len__() == 2 and sys.argv[1] == "help":
    print("Help info:")
    print("Argv[1]:Path of exe file.")
    print("Argv[2]:The dir of images goint to be processed.Note that there should be no other files except tif images.")
    print("Argv[3]:The ourput dir of processed images.\n")
    print("Usage example:")
    print("python Resample_script.py F:\\RCStat\\shiftGPU\\GeoFrameVideo.exe D:\\img D:\\output")
elif sys.argv.__len__() == 4:
    exe_path = sys.argv[1]
    argv2 = sys.argv[2]
    argv3 = sys.argv[3]

    paths, filenames = loadFiles(argv2)
    output = generateOutputFilename(filenames)
    results = bindCommands(filenames, output)
    for i in range(results.__len__()):
        print("Command[" + (i + 1).__str__().zfill(3) + "]:" + results[i] + "\n")
    if sys.version_info.major < 3:
        flag = raw_input("Is it all right?y/n\n")
    else:
        flag = input("Is it all right?y/n\n")
    if flag == 'y':
        for i in range(results.__len__()):
            print("Executing:" + results[i])
            os.system(results[i])
            print("Finished " + (i + 1).__str__() + "/" + results.__len__().__str__())
            print("-" * 50)
        copyFirstBaseIMG()
    else:
        print("Exit.")
        exit()
else:
    script_name = sys.argv[0][sys.argv[0].rfind('/') + 1:]
    print("Input 'python " + script_name + " help'to get help information.")

以上便是这次项目中用到的比较有代表性的两个批量处理脚本,其它如CCD拼接、辐射校正等批量脚本本质上和这些都是相同的,只是exe和执行参数不同而已。 上面两个脚本其实从核心技术上来说就是字符串的生成与拼接,外加for循环从而实现批量执行的效果。 利用批量脚本可以在实际项目中节省很多时间,提高效率,让自己有更多的时间可以做更想做的事情,而不是一行行敲命令(手动敲还有可能出错)。

最后简单总结一下Python执行命令的几种不同方法和各自特点。

3.Python执行命令方法

(1)os模块

os.system()在一个子终端运行系统命令,不能获取命令执行后的返回信息,适用于简单情形。上面两个脚本都是采用这种方式实现的,简单易用。 os.popen()不但执行命令,同时将执行结果返回给指定的变量,便于后续处理。

(2)commands模块

commands模块中有commands.getoutput()函数可供调用,括号内为执行命令内容。其返回值是执行命令后系统输出的文本。 commands.getstatusoutput()不仅返回系统输出的文本还会返回系统执行命令的状态(是否成功)。

(3)subprocess模块

用法是:subprocess.call([“cmd”, “arg1”, “arg2”],shell=True)。

上面三种方法都可以执行系统命令,根据不同需求选择不同函数即可。 如果需要编写跨平台脚本,要考虑不同平台下的命令问题,有些命令可能Windows有单Linux没有,可以对平台进行判断,然后生成不同的命令来执行。

本文作者原创,未经许可不得转载,谢谢配合

返回顶部