导言:在这篇文章中讲了一些经常在CV会经常用到的一些python中的工具。
迭代器
__iter__()
:迭代器,生成迭代对象时调用,返回值必须是对象自己,然后for可以循环调用next方法next()
:每一次for循环都调用该方法(必须存在)
疑问:为什么list类型不是迭代器,但是其能放入for循环中遍历呢?
解答:迭代环境会优先使用迭代协议(也就是调用next方法),如果对象不支持迭代协议,则使用索引方式进行迭代,所以list可以被遍历。
生成器
如果一个def
的主体包含yield
,这个函数会自动变成一个生成器(即使它包含一个return)。生成器函数返回生成器的迭代器。“生成器的迭代器”通常就被称作“生成器”。要注意的是生成器就是一类特殊的迭代器。作为一个迭代器,生成器必须要定义一些方法(method),其中一个就是next()。如同迭代器一样,我们可以使用next()函数来获取下一个值。 而yield就是自带的next()函数:
外面调用生成器->调用该对象的next()函数->找到上一次yield出去的地方->继续执行yield后面的代码
lambda
lambda的一般形式是关键字lambda后面跟一个或多个参数,紧跟一个冒号,以后是一个表达式。lambda是一个表达式而不是一个语句。它能够出现在Python语法不允许def出现的地方。作为表达式,lambda返回一个值(即一个新的函数)。lambda用来编写简单的函数,而def用来处理更强大的任务。1
2f = lambda x, y, z :x + y + z
print f(1,2,3) #6
lambda后面的参数(:之前的)是从外界接受的参数,然后对其进行:后的运算。
4.python 继承
在子类中必须要执行父类的构造函数
1 | class B(A): |
import:
__import__()
函数用于动态加载类和函数
1 | __import__(mod_str) |
源码中首先使用importclass的方法,传入文件名以及类名。
然后使用`_import`来加载类。只是申明并未实例化。
得到的processors
是一个字典,包含了两个类1
2processors['recognition'] = import_class('processor.recognition.REC_Processor')
processors['demo'] = import_class('processor.demo.Demo')
得到类对象:
1 | Processor = processors[arg.processor] |
processors
中存储了两个类,只不过这两个类还并未实例化。p = Processor(sys.argv[2:])
实例化了此类。
import()的一个小实例:
文件T20190801中:1
2
3
4
5
6
7
8
9
10
11
def import_model(self,str):
mod_str, _sep, class_str = str.rpartition('.')
__import__(mod_str)
return getattr(sys.modules[mod_str], class_str)
def start(self):
train_x,train_y,test_x,test_y = self.makedata()
Model = (self.import_model("T20190801_Model.Model"))
model = Model()
print(model)
__import__(mod_str)
中只有传入文件名称就可以导入该文件了.
getattr(sys.modules[mod_str], class_str)
可以得到class_str
这个类,相当于类的申明。
可以使用这个申明来实例化类对象
文件T20190801_Model中:1
2
3
4
5
6
7
8
9
10
11
12
13
class Model(torch.nn.Module):
def __init__(self):
super(Model,self).__init__()
self.classification = nn.Sequential(
nn.Conv2d(1, 20, 5),
nn.ReLU(),
nn.Conv2d(20, 64, 5),
nn.ReLU()
)
def forward(self):
pass
rpartition
1 | mod_str, _sep, class_str = import_str.rpartition('.') |
rpartition()
方法类似于 partition()
方法,只是该方法是从目标字符串的末尾也就是右边开始搜索分割符。
如果字符串包含指定的分隔符,则返回一个3元的元组,第一个为分隔符左边的子串,第二个为分隔符本身,第三个为分隔符右边的子串。
实例:
1 |
|
parse 以及 subparsers:
每一个subparser可以继承父类的parse1
2
3
4# add sub-parser
subparsers = parser.add_subparsers(dest='processor')
for k, p in processors.items():
subparsers.add_parser(k, parents=[p.get_parser()])
k
是键,{"recognition" "demo"}
,即parser的名称,注意后面使用parse_args()时所输入的子parser器名称必须要和其一样。不然会报错。详细见下面例子
实例:1
2
3python3 main.py recognition -h #正确调用,因为parser有名为recognition的parse
python3 main.py sdeqds -h #错误,找不到名为sdeqds子parse。
p
是值,包含了两个类。
p.get_parser()
可以进入到该类的get_parser
方法中
在对应的类中,get_parser
都会执行。
subparsers = parser.add_subparsers(dest='processor')
得到的subparsers
可以有多个parser
,相当于parser
的子parsers
的句柄。向其中加入parser
使用add_parser
即可
parser.add_subparsers(dest=’processor’)返回的是子parser的句柄!!
使用add_parser()向subparsers中加入parser
add_parser(“名字”,parent = “父parser”)。
recognition
类的get_parser
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21def get_parser(add_help=False):
# parameter priority: command line > config > default
parent_parser = Processor.get_parser(add_help=False)
parser = argparse.ArgumentParser(
add_help=add_help,
parents=[parent_parser],
description='Spatial Temporal Graph Convolution Network')
# region arguments yapf: disable
# evaluation
parser.add_argument('--show_topk', type=int, default=[1, 5], nargs='+', help='which Top K accuracy will be shown')
# optim
parser.add_argument('--base_lr', type=float, default=0.01, help='initial learning rate')
parser.add_argument('--step', type=int, default=[], nargs='+', help='the epoch where optimizer reduce the learning rate')
parser.add_argument('--optimizer', default='SGD', help='type of optimizer')
parser.add_argument('--nesterov', type=str2bool, default=True, help='use nesterov or not')
parser.add_argument('--weight_decay', type=float, default=0.0001, help='weight decay for optimizer')
# endregion yapf: enable
return parser
调用处:subparsers.add_parser(k, parents=[p.get_parser()])
返回了一个parser
这个parser
继承了Processor的parser,并且添加了自己的参数。
各个类的父子关系:1
2
3|IO----|----demo
|
|----processor----|----REC_Processor
subparser
的作用可以复用相同的参数接口
所有parser写完后
调用根parse进行解析:
parser = argparse.ArgumentParser(description='Processor collection')
subparsers = parser.add_subparsers(dest='processor')
,添加子解析器
…arg = parser.parse_args()
,开启解析,定义了所有参数之后,你就可以给parse_args()
传递一组参数字符串来解析命令行。默认情况下,参数是从 sys.argv[1:] 中获取,但你也可以传递自己的参数列表。选项是使用GNU/POSIX
语法来处理的,所以在序列中选项和参数值可以混合。
parse_args() 的返回值是一个命名空间,包含传递给命令的参数。该对象将参数保存其属性,因此如果你的参数 dest
是 myoption
,那么你就可以args.myoption
来访问该值。
- 可以自己向parse_args中传递参数:
1
parser.parse_args(['-a', '-bval', '-c', '3'])
如果不parse_args()
不加参数则是默认从sys.argv[1:]
来传入
argparse.add_argument() dest参数的意义:
subparsers = parser.add_subparsers(dest='processor')
dest
指定的值用作key
值,从解析后的对象中取出用户输入的第一个参数
所以上述的parser拥有一个arg.processor的属性。而这个属性对应了cmd中第一个输入值。
python 中 三元表达式:
如果 i = 0 a为1,否则a = 101
2
3i = 1
a = 1 if i == 0 else 10
print(a)
zip的用法:
将两个list横向组合,每一个小组和为一个元组,放进list中。
也可以解压,但是解压是在解压target前面加一个*
号1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
a = [1,2,3]
b = [4,5,6]
c = [4,5,6,7,8]
zipped = zip(a,b) # 打包为元组的列表
## [(1, 4), (2, 5), (3, 6)]
zip(a,c) # 元素个数与最短的列表一致
## [(1, 4), (2, 5), (3, 6)]
zip(*zipped) # 与 zip 相反,*zipped 可理解为解压,返回二维矩阵式
## [(1, 2, 3), (4, 5, 6)]
nums = ['flower','flow','flight']
print(list(zip(*nums)))
# [('f', 'f', 'f'), ('l', 'l', 'l'), ('o', 'o', 'i'), ('w', 'w', 'g')]
numpy中concatenate函数:
将两个数组进行连接,前提是两个array,在拼接方向上满足形状一致即可。
切片操作:
通常一个切片操作要提供三个参数 [start_index: stop_index: step]
可以省略
start_index
:[:5:2]意思为从数组头开始,到下标5结束每隔2个单位取一个,[5]不包括。可以省略
stop_index
:[1::2]意思为从1开始到数组结尾,每隔两个取一个。可以省略
step
:[1:6:] step = 1可以[::1] -> 从头到尾步长为1遍历
可以[::-1] -> 步长为-1时,当步长<0时,
start_index
默认值为-1,stop_index
为-len(a)
可以[:-1:] -> 从头到最后一个元素依次遍历
1
2
3data_numpy[0, frame_index, :, m] = pose[0::2] #pose的偶数index的值
data_numpy[1, frame_index, :, m] = pose[1::2] #pose的奇数index的值
data_numpy[2, frame_index, :, m] = score
python OpenCV
video的读取操作:
cv2.VideoCapture()
函数:
1 | cap = cv2.VideoCapture(0) |
cap.isOpened()
函数:
返回true表示成功,false表示不成功
ret,frame = cap.read()
函数:
cap.read()
按帧读取视频,其中ret
是布尔值,如果读取帧是正确的则返回True,如果文件读取到结尾,它的返回值就为False。frame
就是每一帧的图像numpy_array
类型
resize
1 | frame = cv2.resize(frame,(360,256)) |
circle
it 是元组类型(x,y)1
cv2.circle(frame,it,3,(0,0,255),3)
json文件加载:
1 | output_path = "/home/joey/datasets/hmdb/hmdb51_sta/pullup_json/50_pull_ups_made_in_germany_pullup_f_nm_np1_le_med_2.json" |
读出来后,对json的操作就和字典的操作一模一样。