SVM从零开始 (一)  原作者的解读 & 整体代码浏览  &文件夹详情介绍

一 开篇说明:

这个是我找到的博客的svm,
本篇文章就是对这个博客进行进一步详细解读

https://blog.csdn.net/q1242027878/article/details/74271694
github:
https://github.com/CHNicelee/HOG_SVM

二 原者的readme:

# HOG+SVM
使用说明:[点我查看博客](https://blog.csdn.net/q1242027878/article/details/74271694)
上面的hog_svm.py是用于训练的,通过提取图片的hog特征,然后通过SVM进行训练得到model,最后通过model进行预测,将结果写入result.txt文件之中。
代码不难,大家根据需要自己改改。
不要将hog的参数设置的太复杂。不然提取的特征会非常大,然后训练的时候会占满内存,导致机器死机

三 原作者的解释说明

注意事项:

1.    你的图片长宽可以不相等,设置好image_heightimage_width即可。
       如果图片大小不相等,可以使用change_size.py,把所有图片大小resize成一样的。ps:我没看到这个文件啊

2.    你图片对应的标签必须是这样的:

           001.jpg 1
           003.jpg 2

  前面是图片名称,后面是对应的类别(类别用数字表示),中间要用空格隔开每个标签占一行
  你要准备两个文件,一个是训练用的,一个是测试用的。
  训练样本标签预测的都是一样的格式
  大家可以看github上面的实例.(image文件夹)
   1) 这里是github下载的压缩包的样子

   2) 这些是解压之后的文件
image   文件里面是正方形图片
image128  里面是没有经过resize的长方形图片


   3) 打开image文件夹

   4) 打开train.txt文件

3.    你的训练和测试的图片可以放在同一个文件夹下面,也可以不同,设置好 train_image_pathtest_image_path 即可。

4.    你要根据你图片的大小,对这行代码进行一些调整,这个调整需要你先了解hog的知识:

       fd = hog (gray, orientations=18, pixels_per_cell=[8,8], cells_per_block=[4,4], visualise=False, transform_sqrt=True)

       这是我为128x128大小图片设置的提取 hog 特征的参数,你需要适当改变一些,到时候的效果也不同。

       orientations我是选9或18,即梯度方向的个数

       一般来说,图片越大,pixels_per_cell cells_per_block 里面的值可以相应变大。

5.    如果你要进行多次,建议你把文件位置的参数写死

#训练集图片的位置
train_image_path = '/home/icelee/Downloads/dataset/small_shixun/'
#测试集图片的位置
test_image_path = '/home/icelee/Downloads/dataset/small_shixun/'
#训练集标签的位置
train_label_path = '/home/icelee/Downloads/dataset/mydata.txt'
#测试集标签的位置
test_label_path = '/home/icelee/Downloads/dataset/test.txt'
#图片大小
image_height = 128
image_width = 128

6. 你需要安装 sk-learn库,hog,PIL库 等。可能还有一些零碎的库,大家用pip安装就好。

7. 实验都是彩色图片,如果你的图片是纯黑白的,很有可能需要改一下代码,看一下代码注释即可

    采用这个测试cifar-10,准确率有50%多一点点(乱猜的准确率是10%),所以效果还是可以的,虽然比不上深度学习。

    为了方便大家查看,代码放在了github https://github.com/CHNicelee/HOG_SVM

可能出现的错误

ValueError: Expected 2D array, got 1D array instead: array=[]. Reshape your data either using array.reshape(-1, 1) if your data has a single feature or array.reshape(1, -1) if it contains a single sample.
出现上面的错误说明没有正常读取到图片,所以请检查图片宽高是不是和设置的size一样路径是否正确
更改之后运行程序时,请选择重新获取特征。

 

四 原作者的hog_svm.py文件

# -*- coding=utf-8 -*-
import glob
import platform
import time
from PIL import Image
from skimage.feature import hog
import numpy as np
import os
import joblib
from sklearn.svm import LinearSVC
import shutil
import sys

# /=== === === ===> 1准备工作-start <=== === === ===\
# 第一个是你的类别   第二个是类别对应的名称   输出结果的时候方便查看
label_map = {1: 'cat',
             2: 'chick',
             3: 'snack',
             }
# 训练集图片的位置
train_image_path = 'image'
# 测试集图片的位置
test_image_path = 'image'

# 训练集标签的位置
train_label_path = os.path.join('image', 'train.txt')  # 此指令用于链接路径os.path.join
# 测试集标签的位置
test_label_path = os.path.join('image', 'train.txt')
# print(train_label_path) =>image128/train.txt

size = 128  # 用于调整图片大小

train_feat_path = 'train/'
test_feat_path = 'test/'
model_path = 'model/'  # 用于存储模型路径的构成,模型被放在model文件夹里
# \=== === === ===>  1准备工作-end  <=== === === ===/


# /=== === === ===>  2定义函数-start  <=== === === ===\
# 获得图片列表
def get_image_list(filePath, nameList):
    print('read image from ', filePath)
    img_list = []
    for name in nameList:
        temp = Image.open(os.path.join(filePath, name))
        img_list.append(temp.copy())
        temp.close()
    return img_list


# 提取特征并保存
def get_feat(image_list, name_list, label_list, savePath, size):
    i = 0
    for image in image_list:
        try:
            # 如果是灰度图片  把3改为-1
            image = np.reshape(image, (size, size, 3))
        except:
            print('发送了异常,图片大小size不满足要求:', name_list[i])
            continue
        gray = rgb2gray(image) / 255.0
        # 这句话根据你的尺寸改改,orientations是梯度的方向的个数
        fd = hog(gray, orientations=12, block_norm='L1', pixels_per_cell=[8, 8], cells_per_block=[4, 4],
                 visualize=False,
                 transform_sqrt=True)
        fd = np.concatenate((fd, [label_list[i]]))
        print(fd.shape)  # (32448+1,)
        fd_name = name_list[i] + '.feat'  # cat
        fd_path = os.path.join(savePath, fd_name)  # savePath为:  train_feat_path= 'train/' 和test_feat_path= 'test/'
        joblib.dump(fd, fd_path)  # 保存fd模型 到 train_feat_path= 'train/' #TODO
        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


# 获得图片名称与对应的类别
def get_name_label(file_path):
    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])
                label_list.append(line.split(' ')[1].replace('\n', '').replace('\r', ''))
                if not str(label_list[-1]).isdigit():
                    print("labeol必须为数字,得到的是:", label_list[-1], "程序终止,请检查文件")
                    exit(1)
    return name_list, label_list


# 提取特征
def extra_feat():
    train_name, train_label = get_name_label(train_label_path)  # train_label_path='/train/train.txt'
    # name_list=[cat.jpg,smallCat.jpg]    label_list=[1,1]
    test_name, test_label = get_name_label(test_label_path)  # test_label_path='/train/test.txt'

    train_image = get_image_list(train_image_path, train_name)
    test_image = get_image_list(test_image_path, test_name)
    get_feat(train_image, train_name, train_label, train_feat_path, size)
    get_feat(test_image, test_name, test_label, test_feat_path, size)


# 创建存放特征的文件夹
def mkdir():
    if not os.path.exists(train_feat_path):
        os.mkdir(train_feat_path)
    if not os.path.exists(test_feat_path):
        os.mkdir(test_feat_path)


# 训练和测试
def train_and_test():
    t0 = time.time()
    features = []
    labels = []
    correct_number = 0
    total = 0
    for feat_path in glob.glob(os.path.join(train_feat_path, '*.feat')):  # train_feat_path='train/'
        # glob.glob()这里是一个列表,feat_path是其中一个元素,就是路径
        data = joblib.load(feat_path)  # 读取fd模型 从 feat_path='train/*.feat'#TODO
        # print(feat_path)#特征的路径 train/yellowCat.jpg.feat
        # print(data)#yellocat的特征
        features.append(data[:-1])  # 其实就是去除了这行文本的最后一个字符(此处删除的是最后的标签)后剩下的部分
        # print(features)
        labels.append(data[-1])  # 把最后一个标签给了labels
        # print(labels)  标签列表['1', '2', '3', '2', '3', '1', '1', '3']
    print("Training a Linear LinearSVM Classifier.")
    clf = LinearSVC()  # TODO
    clf.fit(features, labels)
    # 下面的代码是保存模型的
    if not os.path.exists(model_path):
        os.makedirs(model_path)
    joblib.dump(clf, model_path + 'model')  # 保存clf模型 到 model/model#TODO
    # 下面的代码是加载模型  可以注释上面的代码   直接进行加载模型  不进行训练
    # clf = joblib.load(model_path+'model')
    print("训练之后的模型存放在model文件夹中")
    # exit()
    result_list = []
    for feat_path in glob.glob(os.path.join(test_feat_path, '*.feat')):  # test/*.feat
        total += 1
        if platform.system() == 'Windows':
            symbol = '\\'
        else:
            symbol = '/'
        image_name = feat_path.split(symbol)[1].split('.feat')[0]  # test/cat.jpg.feat得到cat
        data_test = joblib.load(feat_path)  # test/cat.jpg.feat读取到特征到data_test
        data_test_feat = data_test[:-1].reshape((1, -1)).astype(np.float64)  # 去掉最后的标签
        result = clf.predict(data_test_feat)  # 预测测试特征
        print(result)  # ???result[0]
        result_list.append(image_name + ' ' + label_map[int(result[0])] + '\n')  # cat 对应查找字典里面名字\n
        if int(result[0]) == int(data_test[-1]):
            correct_number += 1
    write_to_txt(result_list)
    rate = float(correct_number) / total
    t1 = time.time()
    print('准确率是: %f' % rate)
    print('耗时是 : %f' % (t1 - t0))


def write_to_txt(list):
    with open('result.txt', 'w') as f:
        f.writelines(list)
    print('每张图片的识别结果存放在result.txt里面')
# \=== === === ===>  2定义函数-end  <=== === === ===/


if __name__ == '__main__':

    mkdir()  # 不存在文件夹就创建
    # need_input = input('是否手动输入各个信息?y/n\n')

    # if need_input == 'y':
    #     train_image_path = input('请输入训练图片文件夹的位置,如 /home/icelee/image\n')
    #     test_image_path = input('请输入测试图片文件夹的位置,如 /home/icelee/image\n')
    #     train_label_path = input('请输入训练集合标签的位置,如 /home/icelee/train.txt\n')
    #     test_label_path = input('请输入测试集合标签的位置,如 /home/icelee/test.txt\n')
    #     size = int(input('请输入您图片的大小:如64x64,则输入64\n'))
    if sys.version_info < (3,):
        need_extra_feat = raw_input('是否需要重新获取特征?y/n\n')  # 判断系统版本,此指令用python2
    else:
        need_extra_feat = input('是否需要重新获取特征?y/n\n')

    if need_extra_feat == 'y':
        shutil.rmtree(train_feat_path)
        shutil.rmtree(test_feat_path)
        mkdir()
        extra_feat()  # 获取特征并保存在文件夹

    train_and_test()  # 训练并预测

 

四 我改进之后的代码: 拆解解读 & 文件夹详情介绍

注意:我们文件名为 hog_svm.py
这里是完整代码:https://blog.csdn.net/zjc910997316/article/details/99005087

1 首先是导入包

# -*- coding=utf-8 -*-
import glob
import platform
import time
from PIL import Image
from skimage.feature import hog  # 用来提取hog特征
import numpy as np
import os
import joblib
from sklearn.svm import LinearSVC
# 这个就是svm在机器学习库里面的名字, 关于sklearn.svm包中的SVC(kernel=”linear“)和LinearSVC的区别:
# # 请看https://blog.csdn.net/zjc910997316/article/details/84594763
import shutil
import sys

 

2 准备工作


# 第一个是你的类别   第二个是类别对应的名称   输出结果的时候方便查看
label_map = {1: 'tbj',
             2: 'dw',
             3: 'zsy',
             4: 'zjc',
             }
# 训练集图片的位置, 这里是相对位置
train_image_path = 'image_train'
# 测试集图片的位置
test_image_path = 'image_test'

# 训练集标签的位置
train_label_path = os.path.join('image_train', 'train.txt')
print(train_label_path)
# 测试集标签的位置
test_label_path = os.path.join('image_test', 'test.txt')

image_height = 128
image_width = 64

train_feat_path = 'train/'
test_feat_path = 'test/'
model_path = 'model/'

# 训练集标签的位置
=> train_label_path = os.path.join('image_train', 'train.txt')  # 此指令用于链接路径os.path.join
print(train_label_path)
image_train/train.txt
# 测试集标签的位置
test_label_path = os.path.join('image_test', 'train.txt')

=> size = 128  # 用于调整图片大小

=> train_feat_path = 'train/'
=> test_feat_path = 'test/'
=> model_path = 'model/'   # 用于存储模型路径的构成,模型被放在model文件夹里

=> label_map = {1: 'tbj',
             2: 'dw',
             3: 'zsy',
             4: 'zjc',
             }
#我们这里是给ssd检测出来的人进行分类,分类成是哪个同学 (比如 tbj  dw zsy ..)
# 这里是字典的形式保存了一类图片的 label (比如 tbj  dw zsy 等)
# 字典在这里的意义是让数字和标签对应上, 训练的时候只需要告诉机器
1 就知道是 tbj 同学

# 训练集图片的位置,
=> train_image_path = 'image_train'
# 测试集图片的位置
=> test_image_path = 'image_test'
# 这里是相对位置,这样写可以让hog_svm.py文件运行时找到

辅助工具 => Change_Name.py, Write_Label_txt.py

这里有8个文件:
依次介绍

image_train     存放训练图片 =>里面有train.txt, eg: 1-001.jpg 1 图片名,标签格式存储
image_test     存放测试图片     =>里面有test.txt, eg: 1-001.jpg 1 图片名,标签格式存储
model      保存的模型
train               保存训练图片的特征
test                 保存测试图片的特征
hog_svm.py   主程序
README.md 原作者的读我
result            运行结果展示 
辅助工具文件夹 里面有  =>ChangName.py  图片批量命名,改名程序
                                        =>Write_Label_txt.py  写test.txt, train.txt的程序

image_train
存放训练的图片

这里是4个同学的照片:
命名方式为
tbj同学: 第一张图片031-1.jpg,...,最后一张图片 245-1.jpg

dw同学: 第一张图片001-2.jpg,...,最后一张图片 162-2.jpg

zsy同学: 第一张图片001-3.jpg,...,最后一张图片 308-3.jpg

zjc同学: 第一张图片001-4.jpg,...,最后一张图片 337-4.jpg

这里的
-1表示tbj
-2表示dw
-3表示zsy
-4表示zjc

每个人的照片数量不同,tbj的前30张被用来做测试,在后面
局部图片示意

train.txt文件里面有:图片全名 和 标签 (部分截图)(前面30张被用来做测试了)

image_test

存放测试的图片

这里是4个同学的照片:
命名方式为
tbj同学: 第一张图片001-1.jpg,...,最后一张图片 030-1.jpg  (我这里只用30张图片做测试)
局部图片示意

test.txt文件夹 (全部截图)

model

此文件夹里面存放模型

train

存放训练图片的特征

(部分)

test

存放测试图片的特征

(全部)

hog_svm.py 主程序,后面会有介绍
训练
https://blog.csdn.net/zjc910997316/article/details/98943969
预测
https://blog.csdn.net/zjc910997316/article/details/99004997

README.md 原作者的读我文件,看我的博客就不需要看这个了

result  运行结果展示

可见有很多都是预测错的, 60%的正确率, -1表示tbj

辅助工具 => ChangName.py
图片批量改名程序
需要放在image_train,image_test文件夹里面使用

博客专门介绍
https://blog.csdn.net/zjc910997316/article/details/99069988
SVM从零开始 (四)  图片批量改名代码

辅助工具 => Write_Label_txt.py
test.txt, train.txt的程序

博客专门介绍
https://blog.csdn.net/zjc910997316/article/details/99076273
SVM从零开始 (五)  写训练集train.txt, 测试集test.txt 的代码

3 定义函数

1 创建路径


# /=== === === ===> 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 训练部分


# /=== === === ===> 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 <=== === === ===/

预测部分



# /=== === === ===> 3:预测stage-start <=== === === ===\
# /=== ===> 1)测试准备,提取特征,预测 <=== ===\
def predict_stage(test_feat_path):
    shutil.rmtree(test_feat_path)
    mkdir_test()
    extra_feat_test()  # 获取测试特征并保存在文件夹
    # nk_predict() # 多张图片的预测,非实时
    clf = joblib.load(model_path + 'model')  # 直接进行加载模型  不进行训练   joblib.load.predict
    nk_predict()
# \=== ===> 1)测试准备,提取特征,测试 <=== ===/


# /=== ===> 2)提取特征 <=== ===\test
def extra_feat_test():
    t_extra0 = time.time()
    test_name, test_label = get_name_label(test_label_path)
    test_image = get_image_list(test_image_path, test_name)
    get_feat(test_image, test_name, test_label, test_feat_path)
    t_extra1 = time.time()
    print('测试特征提取结束,', '特征提取耗时是 : %f' % (t_extra1 - t_extra0) + '\n')


# =>下面部分: 与上面训练部分同, 因而注释掉
# =>从txt获得'图片名称list',对应的'类别list'
'''
def get_name_label(file_path):  # file_path = train_label_path = image\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\
    # 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\tbj1, 然后用Image打开
        # print('测试是否有后缀.jpg', os.path.join(filePath, name))  # txt文件在起名字的时候就要写成dw1.jpg
        # 测试是否有后缀.jpg image/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)
        # =>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_predict():
    correct_number = 0
    total = 0
    clf = joblib.load(model_path + 'model')  # 直接进行加载模型  不进行训练
    t_predict0 = time.time()
    result_list = []
    for feat_path in glob.glob(os.path.join(test_feat_path, '*.feat')):
        total += 1
        if platform.system() == 'Windows':
            symbol = '\\'
        else:
            symbol = '/'
        image_name = feat_path.split(symbol)[1].split('.feat')[0]
        data_test = joblib.load(feat_path)
        data_test_feat = data_test[:-1].reshape((1, -1)).astype(np.float64)
        result = clf.predict(data_test_feat)
        result_list.append(image_name + ' ' + label_map[int(result[0])] + '\n')
        if int(result[0]) == int(data_test[-1]):
            correct_number += 1
    write_to_txt(result_list)
    rate = float(correct_number) / total
    t_predict1 = time.time()
    print('准确率是: %f' % rate + ' ', '预测耗时是 : %f' % (t_predict1 - t_predict0))
# \=== ===> 3)预测 <=== ===/


# /=== ===> 4)txt记录 <=== ===\
def write_to_txt(list):
    with open('result.txt', 'w') as f:
        f.writelines(list)
    print('每张图片的识别结果存放在result.txt里面' + '\n')
# \=== ===> 4)txt记录 <=== ===/

 

4 主函数


if __name__ == '__main__':
    # === ===> 创建路径 <=== ===
    creat_fold()
    # === ===> 训练 <=== ===
    train_stage(train_feat_path)  # 提取特征,并训练模型
    # === ===> 预测 <=== ===
    predict_stage(test_feat_path)  # 预测

 

 

 

 

 

 

 

 

 

 

  • 2
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

计算机视觉-Archer

图像分割没有团队的同学可加群

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值