发布时间:2024-06-23 19:01
这篇博客是 对 Adrian Rosebrock 一篇 blog 的一些翻译和自己的理解,在这里,我很高兴和大家分享一下自己的收获。
今天我们来一起学习一下一个很基础的skill, 命令行参数(command line argument) 。
接下来的教程主要可以分为三个阶段:
1 什么是命令行参数
2 为什么我们要使用命令行参数
3 如何来使用python来解析命令行参数
4 如何使用 pycharm 来实现命令行参数
扎根于 computer science 的你, 命令行参数是必需要掌握的一项技能,
尤其是如果你现在正在接触计算机视觉, 图像处理 或者与deep learning相关的 一些领域,那么你更应该好好了解一下如何使用命令行参数。
如果你到现在还没有听说过 命令行参数, 或者是对他并不是很了解, 这都ok。 相信你可以通过今天的学习,也就是这篇blog的内容,来对命令行参数的概念以及使用都有一个很深入的理解。(真心的希望你能够花费一些时间在命令行参数的使用上,这真的会对你有很大的帮助)
你之所以能够看到这篇博客, 其中的一个原因可能是你遇到了如下的错误:
error: the following arguments are required: -i/–image, -p/–prototxt, -m/–model
也有可能是你首次遇到了 argparse 这个库, 这都不要紧。 如果你是遇到了 error ,那么通过今天的学习,你就可以自行解决这些error了。如果你是第一次看到 import argparse ,那么这篇博客也会消除你的一些困惑。 其实它远没有看上去或者你头脑中想象的那么难,真的so easy , 好了,我们开始吧。
(Command line arguments are flags given to a program/script at runtime.)
命令行参数(Command line arguments )是一些 需要在程序运行时 给出的标志(flags)( 类似于tensorflow的 feeddict 机制,只不过它的 placeholder 部分在你的程序中已经定义好了) 。 它包含了让程序可以顺利执行的一些额外的信息(additional information), 这些信息是在你写程序的时候没有给出的。譬如图像的路径,神经网络训练时的一些epoch, batch_size这类的参数,没有他们你的程序就不能正常运行。
(说实话这些定义总是让人觉得很困惑,不过看了下面的实例你可能就会慢慢理解了)
也并不是所有的程序都需要使用 命令行参数 来为变量赋值, 你可以在定义变量的时候直接给他初始化一个要用的值。这就引出了下面的内容, Why do we use command line arguments?
前面我们说过了, 命令行参数的使用就是为了 在程序运行的时候 给他传入一些运行所必需的参数。 为什么要这么做呢?
是因为这样一来,我们就不用费劲的到你的 scipt.py 文件中去一个个修改参数了。(假如你有三批数据需要训练,并且他们存储在不同的地方, 不使用 命令行参数 你就需要到你的 py 文件中去更改每次训练的路径。 而使用它,你需要先执行你的 py 文件, 然后通过 命令行 来给出路径所在。)
再计算机视觉和图像处理这方面, 你可能应用最多的就是路径的使用; 而在deep learning 方面, 你可以通过它去改变那些让人头疼的参数。
好了,剩下的内容就是 如何来使用python来解析命令行参数了,我们会通过两个案例和 argparse 库自身的一些实例来学习。
如果你是一个重度的pycharm用户, 在结尾你也能找到如何 run a script without ever leaving PyCharm ,ps : 如果你真的选择这样做的话。
(这篇文章中所有使用到的资料和文件你都可以在我的CSDN下载中得到
https://download.csdn.net/download/pierce_kk/11472499 )
我们先来看这个 simple_example.py 文件,
# import the necessary packages
import argparse
# construct the argument parse and parse the arguments
ap = argparse.ArgumentParser()
ap.add_argument(\"-n\", \"--name\", required=True,
help=\"name of the user\")
args = vars(ap.parse_args())
# display a friendly message to the user
print(\"Hi there {}, it\'s nice to meet you!\".format(args[\"name\"]))
首先, 我们需要 argparse 这个package ,所以我们在程序的最开始 import 进来。
然后 , 我们实例化一个 ArgumentParser类 的对象 , 将其命名为op
然后, 我们添加参数(argument), 这里的添加参数是指添加那些 你需要为其赋值的参数 , 例如要读取的文件名,要读取的文件路径, batch_size, epoch 等。 注意到这里,我们给了这个参数两个名字, - n 和 - name 一短一长 ,可以理解为简写和全拼吧(shorthand version & longhand version)。 这两个参数的意义是一样的,而且都可以正常使用 。
require参数的意思就是这个参数是不是 必须‘ 需要 ’, TRUE是必须需要,也就是程序运行的时候你必须要复制给他,
否则程序就会出现 error , False则代表不是必须的;
(更多的参数解释可以在这找到 : https://docs.python.org/3/library/argparse.html#argparse.ArgumentParser.add_argument)
第7行的 help 参数类似于一个提示的功能, 定义参数时 help 中加入对于参数的介绍,以免在以后使用这个 script 的时候忘记参数的含义。
你可以在终端输入如下的命令来 view the command usage
$ python simple_example.py --help
usage: simple_example.py [-h] -n NAME
optional arguments:
-h, --help show this help message and exit
-n NAME, --name NAME name of the user
我们来解析一下输入的指令 $ python simple_example.py --help , 一共分为三部分:
接着, 第八行, 是解析 命令行参数 的一个方法(methods), 他让python 和 argparse library 来解析我们输入到 命令行 当中的内容, 并且将其转化为 程序执行时所必需的参数 的类型。 (也就是说将你输入的 10 ,转换为程序需要的数据类型 可能是 int, float 等等。)
其实在官方的文档中, 第八行的标准写法是这样 :
args = op.parse_args()
也就是直接调用 parse_args() 这个方法, 在这里,原作者将其写成:
args = vars(ap.parse_args())
使用 vars (https://www.runoob.com/python/python-func-vars.html)将其转换成为一个 字典,是为了
so I can execute the script via my command line or in a Jupyter Notebook.
When using a Jupyter Notebook I can simply delete the command line arguments
parsing code and insert a dictionary named args with any hardcoded values.
# 不翻译了,大家自行体会一下
到这里, 可能你想要知道: 我们如何获取到 命令行 当中输入的值呢?
这个 so easy , 我们来看第11行,
我们指定了 args[\'\' name \'\'] , 接下来我们将会执行这个 py文件, 并且输入我们的名字到 command line argument.
你也可以根据如下的步骤来和我一起做(执行 simple_example 文件):
On this blog, I show commands and their arguments in a “shell” codeblock.
$ 代表了这是一条 terminal command ,并且在这个指示符的后面,你就该输入你的指令 和 参数了。
step 1 的下载部分就不再赘述了。
下面是从 step 2 开始到 step 5 的一个过程。
$ cd ~/Desktop/PyImageSearch
$
$ unzip command-line-arguments.zip
...
$
$ cd command-line-arguments
$ pwd
/Users/adrianrosebrock/Desktop
$
$ python simple_example.py --name Adrian
Hi there Adrian, it\'s nice to meet you!
$
$ python simple_example.py --name Stephanie
Hi there Stephanie, it\'s nice to meet you!
$
$ python simple_example.py --name YourNameHere
Hi there YourNameHere, it\'s nice to meet you!
Step 2:
I changed directory to where I downloaded the zip for this lesson (Line 1).
I pressed the enter/return button on Line 2 to make the output easier to read. This is optional.
Step 3:
I unzipped the .zip file associated with this lesson (Line 3).
The ... on Line 4 signifies that there was output from the unzipping process but I am not showing it here. Note that output doesn’t have a preceding $ .
Step 4:
Next I need to change directory into the folder that I just unzipped (Line 6).
Just to be sure I’m where I need to be, I print my working directory on Line 7 with the output being shown on Line 8.
Step 5:
I execute the command with argument on Line 10. I’m specifying my name after the --name flag. As long as my name doesn’t have any spaces, it will be displayed properly in the output.
NOTE : 如果在执行 step5 的时候没有输入 命令行参数, 或者说你输入了一个错误的参数,
就会出现如下的错误信息:
$ python simple_example.py
usage: simple_example.py [-h] -n NAME
simple_example.py: error: argument -n/--name is required
我们在上述的博文中通过一个简单的小例子来领会了 命令行参数 的概念,
下面的内容,是一个稍有深度的example, 来进一步熟悉 命令行参数的 使用。
In this next example we’ll be counting shapes in any given input image while annotating an output image that gets written to disk.
这次我们使用 命令行参数 来给定输入图像的路径 和 output要存储到的路径
这里只是使用了一些简单的图像处理方法,毕竟我们是要熟悉 命令行参数 的使用,而不是OpenCV的使用。
ok, 下面我们把 目光 转移到我们的 shape_counter.py 文件当中
Codeblock #1: Lines 1-20# import the necessary packages
import argparse
import imutils
import cv2
# construct the argument parser and parse the arguments
ap = argparse.ArgumentParser()
ap.add_argument(\"-i\", \"--input\", required=True,
help=\"path to input image\")
ap.add_argument(\"-o\", \"--output\", required=True,
help=\"path to output image\")
args = vars(ap.parse_args())
# load the input image from disk
image = cv2.imread(args[\"input\"])
# convert the image to grayscale, blur it, and threshold it
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
blurred = cv2.GaussianBlur(gray, (5,5), 0)
thresh = cv2.threshold(blurred, 60, 255, cv2.THRESH_BINARY)[1]
同样的,在第二行我们引入了 argparse 这个库来帮助我们解析与使用 命令行参数
7-12 行的作用依旧是 要使用的参数 的定义,这里我们与实验的目的相呼应, 定义了两个参数
即 input 和 output,这两个名字都属于 longhand version, 当然他们也都有各自的 shorthand version 。
你可以通过观察 help 的内容来判断这个 参数 的作用,(当然是在名字没有这么直白的情况下)
如果你 运行这个程序,并且给定 input 和 output 的值, 你能清除的知道这些值存储在哪里么?
他们在 args 这个字典当中, 你可以通过 字典 的 key 来 获取它的 value ,
ok , 下面我们做的其实就是这个, 也就是第 15 行 的为imread 填路径参数的这步,你能理解吗?
这是不是 so easy 呢? ( 如果你觉得不是,好吧,那我今晚的工作可能是失败的。 )
这里我们略去图像的处理过程, 直接跳到最后的 使用 命令行输入的参数 来为cv2.imwrite()的参数赋值 。
OK 程序到此结束, 让我们执行这个 script 并且给他的两个 参数 来赋值。
# img 1
$ python shape_counter.py --input input_01.png --output output_01.png
# img2
$ python shape_counter.py --input input_02.png --output output_02.png
两幅图像输出的结果分别如下:
img1 - output
img2 - output
下面是一些 错误使用命令行参数 的小案例, 通过这些案例你就能了解哪些事情是可以使用命令行参数来做的,而哪些则是不行的。
1 错误的给 前面例子的中 --input 直接赋予 绝对路径的值,
# construct the argument parser and parse the arguments
ap = argparse.ArgumentParser()
ap.add_argument(\"-i\", \"C:\\example\\input_image.png\", required=True,
help=\"path to input image\")
ap.add_argument(\"-o\", \"C:\\example\\output_image.png\", required=True,
help=\"path to output image\")
args = vars(ap.parse_args())
# 这里的 -i 和 -input 都只是你参数的一个名称,赋值操作是使用命令行来进行的,不要在这里直接赋值。
2 错误的给 - - help 赋值,
# construct the argument parser and parse the arguments
ap = argparse.ArgumentParser()
ap.add_argument(\"-i\", \"--input\", required=True,
help=\"/home/pi/my_input.png\")
ap.add_argument(\"-o\", \"--output\", required=True,
help=\"/home/pi/output_image.png\")
args = vars(ap.parse_args())
这是参数是对 参数 的使用方法和意义的一个简介,
并且使用命令行参数不会对 原始的script 进行修改。
3 about the dash ( - )
有些时候你可能会遇到这样命名的参数 - > --features-db 就像下面的程序当中的那样。
ap = argparse.ArgumentParser()
ap.add_argument(\"-d\", \"--dataset\", required=True, help=\"Path to the directory of indexed images\")
ap.add_argument(\"-f\", \"--features-db\", required=True, help=\"Path to the features database\")
ap.add_argument(\"-c\", \"--codebook\", required=True, help=\"Path to the codebook\")
ap.add_argument(\"-o\", \"--output\", required=True, help=\"Path to output directory\")
args = vars(ap.parse_args())
当你要获取这种形式命名的参数的 value 的时候,你需要使用 _ , 而不是 - 。
就像这样 :
featuresDB = h5py.File(args[\"features_db\"], mode=\"r\")
这样做是因为 argparse Python library replaces dashes with underscores during the parsing.
关于命令行参数使用技巧的分享就到这里了, 如果你不习惯在 terminal 当中工作, 那么你可能会多花一些时间来熟悉它,
但是,请相信我,你所花费的时间一定是值得的,并且我相信你可以熟练的掌握今天所分享的技巧。
你可能也会遇到或者想到过 如何在 pycharm 这个IDE 中使用 command line augment,
的确,pycharm是一个很好的 tools, 我们也可以通过 它 来实现命令行参数的解析操作,但是我并不建议你
使用这种方法。
其实 比起click around the GUI of your IDE and set up the arguments, 使用 terminal 是一种非常高效的方法。
虽说不建议, 但是这里还是给出方法。
首先, 我们先给出方法,
ap = argparse.ArgumentParser()
ap.add_argument(\'-i\', \'--image\', required=True,
help=\'the input of image\')
ap.add_argument(\'-o\', \'--output\', required=True,
help=\'the path of output file\')
# 将参数存储在一个dict当中,
args = vars(ap.parse_args())
# view the dict of paras
print(args)
img = cv2.imread(args[\'image\'])
cv2.namedWindow(\'show\', cv2.WINDOW_AUTOSIZE)
cv2.imshow(\'show\', img)
cv2.waitKey()
gray_img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# cv2.imwrite(\'GrayImage.jpg\', gray_img)
cv2.imwrite(args[\'output\'], gray_img)
cv2.destroyAllWindows()
你可以复制下这一段,
然后 点击 run -> edit configuration -> parameters (或者使用快捷键, alt + shift + f10 -> 0)
然后配置你的参数, 注意格式
-i 是你输入的shorthand version, 接着一个空格, 后面的是赋给它的值,
再空一格 , 然后在输入下一组参数与赋予的值。
如果你熟悉了 command line arguments 的使用,你就无需在打开一个个 script 去调节你的参数了,
仅仅是在 run 的时候直接在 terminal 中给就Ok了。
如果你喜欢 计算机视觉 或者 deeplearning 这个领域的一些内容, 你也可以关注 Adrian Rosebrock 的blog。
或者是持续关注我这个专栏的分享(PS 本人能力和水平有限)
如果你觉得我分享的内容帮助到了你, 请给我点个赞呀, 这是对我辛苦了一个晚上的莫大鼓励;
当然, 也欢迎你对我提出宝贵的意见 。
上传android程序到git,Android 进阶之旅 | git 上传代码到远程仓库
美股数据获取 python_几行Python代码,轻松获取美股阿里巴巴的交易数据
CloudBees CI使用Velero进行灾备(DR)概念验证
关于STM32.. Error: L6218E: Undefined symbol xxxx(referred from xxxx.o).问题解决
一文解析Pinia和Vuex,带你全面理解这两个Vue状态管理模式
Understanding the linux 2.6.8.1 scheduler