本节: 以训练为主线介绍
零 创建路径部分代码
# /=== === === ===> 1:创建路径-start <=== === === ===\
# => 分别创建训练路径,测试路径
def creat_fold():
mkdir_train() # 不存在文件夹就创建
mkdir_test()
# => 创建存放训练图片路径的文件夹
def mkdir_train():
if not os.path.exists(train_feat_path):
os.mkdir(train_feat_path)
# => 创建存放测试图片路径的文件夹
def mkdir_test():
if not os.path.exists(test_feat_path):
os.mkdir(test_feat_path)
# \=== === === ===> 1:创建路径-end <=== === === ===/
一 训练部分代码
# /=== === === ===> 2:训练stage-start <=== === === ===\
# /=== ===> 1)训练准备,提取特征,训练 <=== ===\
def train_stage(train_feat_path):
shutil.rmtree(train_feat_path) # 递归删除文件夹下所有文件子文件,包括此文件train
mkdir_train() # 删除之后重新创建 train
extra_feat_train() # 获取训练特征并保存在文件夹 === ===> 2)提取特征
nk_train() # 训练 === ===> 3)训练
# \=== ===> 1)训练准备,提取特征,训练 <=== ===/
# /=== ===> 2)提取特征 <=== ===\
def extra_feat_train():
t_extra0 = time.time() # 计时start
train_name, train_label = get_name_label(train_label_path) # =>获得图片名称,对应的类别
# train_label_path = image_train\train.txt
train_image = get_image_list(train_image_path, train_name) # =>获得图片列表
# train_image_path = image_train\
get_feat(train_image, train_name, train_label, train_feat_path)
t_extra1 = time.time() # 计时end
print('训练特征提取结束,', '特征提取耗时是 : %f' % (t_extra1 - t_extra0) + '\n')
# =>从txt获得'图片名称list',对应的'类别list'
def get_name_label(file_path): # file_path = train_label_path = image_train\train.txt
print("read label from ", file_path)
name_list = [] # 用于存储名字的列表
label_list = [] # 用于存储标签的列表
with open(file_path) as f:
for line in f.readlines():
# 一般是name label 三部分,所以至少长度为3 所以可以通过这个方法来忽略空白行
if len(line) >= 3:
name_list.append(line.split(' ')[0]) # 以空格划分为两部分,前面部分为[0], 后面为[1]
label_list.append(line.split(' ')[1].replace('\n', '').replace('\r', ''))
# \r代表回车,\n代表换行, 都替换成'', 也就是去掉
if not str(label_list[-1]).isdigit():
# 因为[-1]是最后一个, 而每次append的最后一个都是最新的,检查它如果不是数字就报错
print("label必须为数字,得到的是:", label_list[-1], "程序终止,请检查文件")
exit(1)
return name_list, label_list
# 得到了两个列表,分别对应顺序放置 名字,标签 也是就是形如:
# name_list=['tbj1.jpg', 'tbj2.jpg',..., 'dw1.jpg']
# label_list=[1,1,...,2]
# =>获得'图片list'
def get_image_list(filePath, nameList):
# x1: filePath = train_image_path = image_train\
# x2: nameList = train_name = name_list 也就是上一个函数的第一个返回值, name_list=['tbj1.jpg', 'tbj2.jpg',..., 'dw1.jpg']
print('read image from ', filePath)
img_list = []
for name in nameList:
temp = Image.open(os.path.join(filePath, name)) # 形成一个完整的具体图片路径image_train\tbj1, 然后用Image打开
# print('测试是否有后缀.jpg', os.path.join(filePath, name)) # txt文件在起名字的时候就要写成dw1.jpg
# 测试是否有后缀.jpg image_train/337-4.jpg
# 这里我为了统计4个人一个人有几个照片起名方式为:337-4.jpg, 4表示第4个人zjc, 337表示这个人的第337个照片,上面列表dw1.jpg只是示意
img_list.append(temp.copy()) # 把这个图片copy出来,送进列表
temp.close() # 关掉这个,进行下一个图片的copy
# print('img_list[0]里面内容的格式', type(img_list[0]))
# img_list[0]里面内容的格式 <class 'PIL.Image.Image'>
# img_list = [<class 'PIL.Image.Image'>,...,<class 'PIL.Image.Image'>]
return img_list
# =>提取特征并保存
def get_feat(image_list, name_list, label_list, savePath):
# x1: image_list = train_image = img_list
# 也就上一个函数def get_image_list 的返回值list放到是<class 'PIL.Image.Image'>格式的图片
# x2: name_list = train_name 是def get_name_label的第一个返回值name_list=['tbj1.jpg', 'tbj2.jpg',..., 'dw1.jpg']
# x3: label_list = train_label 是def get_name_label的第二个返回值label_list = [1,1,...,2]
# x4: savePath = train_feat_path = train/ 特征被保存在这里
i = 0
for image in image_list:
try:
image = image.resize((64, 128)) # 调整图片大小,因为人高近似是宽的2倍
# 如果是灰度图片 把3改为-1
image = np.reshape(image, (image_height, image_width, 3))
except:
print('发送了异常,图片大小size不满足要求:', name_list[i])
continue
gray = rgb2gray(image) / 255.0
# 提取hog特征, 根据需求改, 这句话根据你的尺寸改改
fd = hog(gray, orientations=12, block_norm='L1', pixels_per_cell=[8, 8], cells_per_block=[4, 4],
visualize=False,
transform_sqrt=True)
'''
print('fd', fd) # fd [ 5.50173054e-04 5.32123593e-05 0.00000000e+00 ..., 2.04692958e-02]
print('fd.shape', fd.shape) # fd.shape (12480,)
print('type(fd)', type(fd)) # type(fd) <class 'numpy.ndarray'>
exit()
'''
fd = np.concatenate((fd, [label_list[i]])) # =>形如:label_list = [1,1,...,2]
'''
print('[label_list[i]]', [label_list[i]]) # [label_list[i]] ['1']
print('type([label_list[i]])', type([label_list[i]])) # type([label_list[i]]) <class 'list'>
print('type(label_list[i])', type(label_list[i])) # type(label_list[i]) <class 'str'>
exit()
'''
# =>fd就是后面 ===> 3)训练 <=== 里面的data = job.lib.load()
# 将image_list里面<class 'PIL.Image.Image'>格式图片resize, np.reshape之后与label_list = [1,1,...,2]对应
fd_name = name_list[i] + '.feat' # 对应名字name_list=['tbj1.jpg', 'tbj2.jpg',..., 'dw1.jpg']加后缀
fd_path = os.path.join(savePath, fd_name) # 前面加train/保存路径 = train/dw1.jpg.feat
# print('fd_path', fd_path) # train/001-1.jpg.feat
joblib.dump(fd, fd_path) # =>把相应的特征fd保存在对应的train/dw1.jpg.feat文件里面, 通过joblib的dump可以将模型保存到本地
i += 1
print("Test features are extracted and saved.")
# =>变成灰度图片
def rgb2gray(im):
gray = im[:, :, 0] * 0.2989 + im[:, :, 1] * 0.5870 + im[:, :, 2] * 0.1140
return gray
# \=== ===> 2)提取特征 <=== ===/
# /=== ===> 3)训练 <=== ===\
def nk_train():
t_train0 = time.time() # 计时start
features = []
labels = []
# train_feat_path = 'train/', 此目录下所有后缀为.feat的文件分别逐个给feat_path进行操作
for feat_path in glob.glob(os.path.join(train_feat_path, '*.feat')):
data = joblib.load(feat_path) # 通过joblib的load方法,加载保存的模型,在这里是加载hog特征eg: train/dw1.jpg.feat
features.append(data[:-1]) # 去掉最后的标签的特征, =>fd = np.concatenate((fd, [label_list[i]]))
labels.append(data[-1]) # 只要最后的标签
print("Training a Linear LinearSVM Classifier.")
clf = LinearSVC() # =>clf 1: 准备要训练的分类器clf
clf.fit(features, labels) # =>clf 2: 特征与标签匹配
# 下面的代码是保存模型的
if not os.path.exists(model_path): # 如果模型路径不存在, model_path = 'model/', 就创建路径
os.makedirs(model_path)
joblib.dump(clf, model_path + 'model') # =>clf 3: 通过joblib的dump可以将模型保存到本地'model/'的model文件中,clf是训练的分类器
print("训练之后的模型存放在model文件夹中")
# exit()
t_train1 = time.time() # 计时end
print('训练耗时是 : %f' % (t_train1 - t_train0) + '\n')
# \=== ===> 3)训练 <=== ===/
# \=== === === ===> 2:训练stage-end <=== === === ===/
二 训练
1主函数如下
if __name__ == '__main__':
creat_fold() # 创建文件
train_stage(train_feat_path) # 提取特征,并训练模型
# predict_stage(test_feat_path) # 预测
1 创建文件:
1)
=> creat_fold() # 让定义的函数实例化
定义的函数如下
=> def creat_fold():
=> mkdir_train() # 不存在文件夹就创建
=> mkdir_test()
2)
创建的文件分别为
# 创建存放训练图片路径的文件夹
=> def mkdir_train():
=> if not os.path.exists(train_feat_path): # 如果此路径不存在
=> os.mkdir(train_feat_path) # 创建此路径
注意:train_feat_path = 'train/'
# 创建存放测试图片路径的文件夹
=> def mkdir_test():
=> if not os.path.exists(test_feat_path): # 如果此路径不存在
=> os.mkdir(test_feat_path)
注意:test_feat_path = 'test/'
也就是看看这个 train test 文件夹 存在不存在,不存在就创建
2 训练阶段
if __name__ == '__main__':
creat_fold() # 创建文件
train_stage(train_feat_path) # 提取特征,并训练模型
# predict_stage(test_feat_path) # 预测
实例化train_stage()函数
=> train_stage( train_feat_path ) # 提取特征,并训练模型
1) 训练准备,提取特征, 训练
=> def train_stage(train_feat_path):
=> shutil.rmtree(train_feat_path) # 递归删除文件夹下所有文件子文件,包括此文件train
=> mkdir_train() # 删除之后重新创建 train
=> extra_feat_train() # 获取训练特征并保存在文件夹
=> nk_train() # 训练
注意:train_feat_path = 'train/'
# 创建存放训练图片路径的文件夹
def mkdir_train():
if not os.path.exists(train_feat_path): # 如果此路径不存在
os.mkdir(train_feat_path) # 创建此路径
2)提取特征
# 提取特征
def extra_feat_train():
t_extra0 = time.time() # 计时start
train_name, train_label = get_name_label(train_label_path) # =>获得图片名称,对应的类别
# train_label_path = image_train\train.txt
train_image = get_image_list(train_image_path, train_name) # =>获得图片列表
get_feat(train_image, train_name, train_label, train_feat_path)
t_extra1 = time.time() # 计时end
print('训练特征提取结束,', '特征提取耗时是 : %f' % (t_extra1 - t_extra0) + '\n')
get_name_label
# =>从txt获得'图片名称list',对应的'类别list'
def get_name_label(file_path): # file_path = train_label_path = image_train\train.txt
print("read label from ", file_path)
name_list = [] # 用于存储名字的列表
label_list = [] # 用于存储标签的列表
with open(file_path) as f:
for line in f.readlines():
# 一般是name label 三部分,所以至少长度为3 所以可以通过这个方法来忽略空白行
if len(line) >= 3:
name_list.append(line.split(' ')[0]) # 以空格划分为两部分,前面部分为[0], 后面为[1]
label_list.append(line.split(' ')[1].replace('\n', '').replace('\r', ''))
# \r代表回车,\n代表换行, 都替换成'', 也就是去掉
if not str(label_list[-1]).isdigit():
# 因为[-1]是最后一个, 而每次append的最后一个都是最新的,检查它如果不是数字就报错
print("label必须为数字,得到的是:", label_list[-1], "程序终止,请检查文件")
exit(1)
return name_list, label_list# 得到了两个列表,分别对应顺序放置 名字,标签 也是就是形如:
# name_list=['tbj1', 'tbj2',..., 'dw1']
# label_list=[1,1,...,2]
get_image_list
# =>获得'图片list'
def get_image_list(filePath, nameList):
# x1: filePath = train_image_path = image_train\
# x2: nameList = train_name = name_list 也就是上一个函数的第一个返回值, name_list=['tbj1.jpg', 'tbj2.jpg',..., 'dw1.jpg']
print('read image from ', filePath)
img_list = []
for name in nameList:
temp = Image.open(os.path.join(filePath, name)) # 形成一个完整的具体图片路径image128\tbj1, 然后用Image打开
# print('测试是否有后缀.jpg', os.path.join(filePath, name)) # txt文件在起名字的时候就要写成dw1.jpg
# 测试是否有后缀.jpg image_train/337-4.jpg
# 这里我为了统计4个人一个人有几个照片起名方式为:337-4.jpg, 4表示第4个人zjc, 337表示这个人的第337个照片,上面列表dw1.jpg只是示意
img_list.append(temp.copy()) # 把这个图片copy出来,送进列表
temp.close() # 关掉这个,进行下一个图片的copy
# print('img_list[0]里面内容的格式', type(img_list[0]))
# img_list[0]里面内容的格式 <class 'PIL.Image.Image'>
return img_list
get_feat
# =>提取特征并保存
def get_feat(image_list, name_list, label_list, savePath):
# x1: image_list = train_image = img_list
# 也就上一个函数def get_image_list 的返回值list放到是<class 'PIL.Image.Image'>格式的图片
# x2: name_list = train_name 是def get_name_label的第一个返回值name_list=['tbj1.jpg', 'tbj2.jpg',..., 'dw1.jpg']
# x3: label_list = train_label 是def get_name_label的第二个返回值label_list = [1,1,...,2]
# x4: savePath = train_feat_path = train/ 特征被保存在这里
i = 0
for image in image_list:
try:
image = image.resize((64, 128)) # 调整图片大小,因为人高近似是宽的2倍
# 如果是灰度图片 把3改为-1
image = np.reshape(image, (image_height, image_width, 3))
except:
print('发送了异常,图片大小size不满足要求:', name_list[i])
continue
gray = rgb2gray(image) / 255.0
# 提取hog特征, 根据需求改, 这句话根据你的尺寸改改
fd = hog(gray, orientations=12, block_norm='L1', pixels_per_cell=[8, 8], cells_per_block=[4, 4],
visualize=False,
transform_sqrt=True)
'''
print('fd', fd) # fd [ 5.50173054e-04 5.32123593e-05 0.00000000e+00 ..., 2.04692958e-02]
print('fd.shape', fd.shape) # fd.shape (12480,)
print('type(fd)', type(fd)) # type(fd) <class 'numpy.ndarray'>
exit()
'''
fd = np.concatenate( ( fd, [ label_list[i] ] ) )
# =>形如:[ label_list[0] ] = [1] label_list = [1,1,...,2]
# 将image_list里面<class 'PIL.Image.Image'>格式图片resize, np.reshape之后与label_list = [1,1,...,2]对应
'''
print('[label_list[i]]', [label_list[i]]) # [label_list[i]] ['1']
print('type([label_list[i]])', type([label_list[i]])) # type([label_list[i]]) <class 'list'>
print('type(label_list[i])', type(label_list[i])) # type(label_list[i]) <class 'str'>
'''
# =>fd就是后面 ===> 3)训练 <=== 里面的data = job.lib.load()
# 将image_list里面<class 'PIL.Image.Image'>格式图片resize, np.reshape之后与label_list = [1,1,...,2]对应
fd_name = name_list[i] + '.feat' # 对应名字name_list=['tbj1.jpg', 'tbj2.jpg',..., 'dw1.jpg']加后缀
fd_path = os.path.join(savePath, fd_name) # 前面加train/保存路径 = train/dw1.jpg.feat
print('fd_path', fd_path)
joblib.dump(fd, fd_path) # 把相应的特征fd保存在对应的train/dw1.jpg.feat文件里面, 通过joblib的dump可以将模型保存到本地
i += 1
print("Test features are extracted and saved.")
fd = np.concatenate((fd, [label_list[i]]))
joblib.dump(fd, fd_path) 通过joblib的dump可以将模型保存到本地
joblib.dump():博客具体解释:https://blog.csdn.net/zjc910997316/article/details/84404233
rgb2gray
# =>变成灰度图片
def rgb2gray(im):
gray = im[:, :, 0] * 0.2989 + im[:, :, 1] * 0.5870 + im[:, :, 2] * 0.1140
return gray
3) 训练
def nk_train():
t_train0 = time.time() # 计时start
features = []
labels = []
# train_feat_path = 'train/', 此目录下所有后缀为.feat的文件分别逐个给feat_path进行操作
for feat_path in glob.glob(os.path.join(train_feat_path, '*.feat')):
data = joblib.load(feat_path) # 通过joblib的load方法,加载保存的模型,在这里是加载hog特征eg: train/dw1.jpg.feat
features.append(data[:-1]) # 去掉最后的标签的特征, =>fd = np.concatenate((fd, [label_list[i]]))
labels.append(data[-1]) # 只要最后的标签
print("Training a Linear LinearSVM Classifier.")
clf = LinearSVC() # =>clf 1: 准备要训练的分类器clf
clf.fit(features, labels) # =>clf 2: 特征与标签匹配# 下面的代码是保存模型的
if not os.path.exists(model_path): # 如果模型路径不存在, model_path = 'model/', 就创建路径
os.makedirs(model_path)
joblib.dump(clf, model_path + 'model') # =>clf 3: 通过joblib的dump可以将模型保存到本地'model/'的model文件中,clf是训练的分类器
print("训练之后的模型存放在model文件夹中")
# exit()
t_train1 = time.time() # 计时end
print('训练耗时是 : %f' % (t_train1 - t_train0) + '\n')
clf1准备:clf = LinearSVC() # from sklearn.svm import LinearSVC
clf2匹配:clf.fit(features, labels)
clf3保存: joblib.dump(clf, model_path + 'model')model/model 没看做这个模型就叫 model
指令说明:
1 shutil.rmtree()
shutil.rmtree() 表示递归删除文件夹下的所有子文件夹和子文件。
因此如果想删除E盘下某个文件夹,可以用shutil.rmtree('E:\\myPython\\image-filter\\test', ignore_errors=True)
这样 test 文件夹内的所有文件(包括 test 本身)都会被删除,并且忽略错误。
2 .copy()
temp = Image.open(os.path.join(filePath, name))
temp.copy()
3 fd = np.concatenate((fd, [label_list[i]]))
4 joblib.dump(fd, fd_path)