一、概述

本文主要记录的在使用Keras过程中,实现交通标志分类。

文本主要使用的环境为:

Python3.5.2

Tensorflow 1.7

Keras 2.1.4

win10

所有程序均亲测可以通过。文中将使用Keras对图像进行分类处理,处理过程包括了

1.图像的预处理

2.神经网络的训练,得到训练后的模型

3.使用训练后的模型,对图像进行预测。

二、图像预处理

本文获取的交通标志图片,是从德国一家交通标志数据集的站点 上获取图像,因为从网站上获取的图像是PPM格式的,所以使用Opencv将图像从PPM转换为png。具体实现代码如下:

  1. import cv2
  2. import os
  3. # 训练集路径
  4. ORIGINAL_TRAIN_PATH = 'datasets/Train'
  5. # 测试集路径
  6. ORIGINAL_TEST_PATH = 'datasets/Test'
  7. # 处理训练集的图像,将其转换为同名称的PNG格式
  8. for train_class in os.listdir(ORIGINAL_TRAIN_PATH):
  9. # train_class:当前文件夹的文件夹名称
  10. for pic in os.listdir(ORIGINAL_TRAIN_PATH + '/' + train_class):
  11. # pic:当前的PPM文件名称
  12. if not (pic.split('.')[1] == 'ppm'):
  13. continue
  14. # 读取图像文件
  15. im = cv2.imread(ORIGINAL_TRAIN_PATH + '/' + train_class + '/' + pic)
  16. # 获取文件名称
  17. name = pic.split('.')[0]
  18. # 生成新的文件名称
  19. new_name = name + '.png'
  20. print(new_name)
  21. # 生成图像文件
  22. cv2.imwrite('datasets/GTSRB_Final_Training_Images/GTSRB/Final_Training/Images/' + train_class + '/' + new_name, im)
  23. # 注释与训练集解析相同
  24. for test_class in os.listdir(ORIGINAL_TEST_PATH):
  25. for pic in os.listdir(ORIGINAL_TRAIN_PATH + '/' + test_class):
  26. if not (pic.split('.')[1] == 'ppm'):
  27. continue
  28. im = cv2.imread(ORIGINAL_TRAIN_PATH + '/' + test_class + '/' + pic)
  29. name = pic.split('.')[0]
  30. new_name = name + '.png'
  31. print(new_name)
  32. cv2.imwrite('datasets/GTSRB_Online-Test-Images-Sorted/GTSRB/Online-Test-sort/' + test_class + '/' + new_name, im)

三、训练神经网络

此过程使用了Keras搭建神经网络,使用的CNN是经典的LeNet,实验相对简单,适用性好。在图像的处理用,对图像分类存储的要求:

  • 图像按照一个文件类型一个文件夹的形式存放
  • 文件夹使用整数型表示,从0开始

完整的实现的代码如下:

  1. # 导入必要的模块
  2. from keras.models import Sequential
  3. from keras.layers.convolutional import Conv2D
  4. from keras.layers.convolutional import MaxPooling2D
  5. from keras.layers.core import Activation
  6. from keras.layers.core import Flatten
  7. from keras.layers.core import Dense
  8. from keras import backend as K
  9. import matplotlib
  10. matplotlib.use("Agg")
  11. from keras.preprocessing.image import ImageDataGenerator
  12. from keras.optimizers import Adam
  13. from keras.preprocessing.image import img_to_array
  14. from keras.utils import to_categorical
  15. from imutils import paths
  16. import matplotlib.pyplot as plt
  17. import numpy as np
  18. import argparse
  19. import random
  20. import cv2
  21. import os
  22. import sys
  23. sys.path.append('..')
  24. # matplotlib中,显示中文,置换字体
  25. from pylab import*
  26. mpl.rcParams['font.sans-serif'] = ['SimHei']
  27. # 搭建的神经网络模型(LeNet)
  28. class LeNet:
  29. @staticmethod
  30. def build(width, height, depth, classes):
  31. # 初始化模型
  32. model = Sequential()
  33. inputShape = (height, width, depth)
  34. # 如果使用了 "channels last", 更新输入shape
  35. if K.image_data_format() == "channels_first": # for tensorflow
  36. inputShape = (depth, height, width)
  37. # 设置第一层 CONV => RELU => POOL 层
  38. model.add(Conv2D(20, (5, 5), padding="same", input_shape=inputShape))
  39. model.add(Activation("relu"))
  40. model.add(MaxPooling2D(pool_size=(2, 2), strides=(2, 2)))
  41. # 设置第二层CONV => RELU => POOL 层
  42. model.add(Conv2D(50, (5, 5), padding="same"))
  43. model.add(Activation("relu"))
  44. model.add(MaxPooling2D(pool_size=(2, 2), strides=(2, 2)))
  45. # 首先 (也是唯一设置) FC => RELU 层
  46. model.add(Flatten())
  47. model.add(Dense(500))
  48. model.add(Activation("relu"))
  49. # softmax 分类器
  50. model.add(Dense(classes))
  51. model.add(Activation("softmax"))
  52. # 返回构建好的网络体系结构
  53. return model
  54. # 基本的参数配置信息:
  55. #训练迭代次数
  56. EPOCHS = 8
  57. #
  58. INIT_LR = 1e-3
  59. # 一个训练batch中的训练数据个数
  60. BS = 64
  61. # 分类数(分类个数,此模型是按照文件夹的个数分类的)
  62. CLASS_NUM = 43
  63. # 图像尺寸的大小(这个需要根据实际情况进行调整,此模型均归一化成正方形)
  64. norm_size = 64
  65. # 加载数据信息,图像与标签信息(图像与数字标签)
  66. def load_data(path):
  67. print("[INFO] loading images...")
  68. # 图像数据数组即:x
  69. data = []
  70. # 标签数据数组即:y
  71. labels = []
  72. # 获取图像路径
  73. imagePaths = sorted(list(paths.list_images(path)))
  74. random.seed(43)
  75. # 对图像路径随机分配处理
  76. random.shuffle(imagePaths)
  77. # 循环输入图像
  78. for imagePath in imagePaths:
  79. # 加载图像,预处理图像,并将其存储在数据列表中
  80. image = cv2.imread(imagePath)
  81. image = cv2.resize(image, (norm_size, norm_size))
  82. image = img_to_array(image)
  83. data.append(image)
  84. # 从图像路径中提取类标签并更新标签列表
  85. label = int(imagePath.split(os.path.sep)[-2])
  86. labels.append(label)
  87. # 数据进行归一化处理 将原始像素强度缩放到范围[0,1]
  88. data = np.array(data, dtype="float") / 255.0
  89. labels = np.array(labels)
  90. # 将标签从整数转换为矢量(即每个位置转换为0或1,)
  91. # to_categorical(y, num_classes=None)
  92. # 将类别向量(从0到nb_classes的整数向量)映射为二值类别矩阵,
  93. # 用于应用到以categorical_crossentropy为目标函数的模型中.
  94. # y: 类别向量
  95. # num_classes:总共类别数
  96. labels = to_categorical(labels, num_classes=CLASS_NUM)
  97. return data, labels
  98. # 训练神经网络
  99. def train(aug, trainX, trainY, testX, testY, args):
  100. print("[INFO] compiling model...")
  101. # 初始化模型
  102. model = LeNet.build(width=norm_size, height=norm_size, depth=3, classes=CLASS_NUM)
  103. opt = Adam(lr=INIT_LR, decay=INIT_LR / EPOCHS)
  104. model.compile(loss="categorical_crossentropy", optimizer=opt,
  105. metrics=["accuracy"])
  106. # 训练神经网络
  107. print("[INFO] training network...")
  108. H = model.fit_generator(aug.flow(trainX, trainY, batch_size=BS),
  109. validation_data=(testX, testY), steps_per_epoch=len(trainX) // BS,
  110. epochs=EPOCHS, verbose=1)
  111. # 将模型保存至硬盘
  112. print("[INFO] serializing network...")
  113. model.save(args["model"])
  114. # 绘制训练损失和准确性曲线并保存
  115. plt.style.use("ggplot")
  116. plt.figure()
  117. N = EPOCHS
  118. plt.plot(np.arange(0, N), H.history["loss"], label="train_loss")
  119. plt.plot(np.arange(0, N), H.history["val_loss"], label="val_loss")
  120. plt.plot(np.arange(0, N), H.history["acc"], label="train_acc")
  121. plt.plot(np.arange(0, N), H.history["val_acc"], label="val_acc")
  122. # 标题 X轴名称 Y轴名称
  123. plt.title("图像分类识别")
  124. plt.xlabel("迭代步数#")
  125. plt.ylabel("误差")
  126. plt.legend(loc="lower left")
  127. # 保存图像曲线
  128. plt.savefig(args["plot"])
  129. # 主程序入口
  130. if __name__=='__main__':
  131. args = {}
  132. # 存储模型的地址
  133. args['model'] = 'MODE/traffic_sign.model'
  134. # 输出训练曲线的地址
  135. args['plot'] = 'MODE/plot.png'
  136. # 训练图像集合文件夹路径
  137. args['dataset_train'] = "datasets/GTSRB_Final_Training_Images/GTSRB/Final_Training/Images"
  138. # 测试图像集合文件夹路径
  139. args['dataset_test'] = "datasets/GTSRB_Online-Test-Images-Sorted/GTSRB/Online-Test-sort"
  140. train_file_path = args['dataset_train']
  141. test_file_path = args['dataset_test']
  142. # 加载训练集合的输入端数据与输出端数据
  143. trainX,trainY = load_data(train_file_path)
  144. # 加载测试集合的输入端数据与输出端数据
  145. testX,testY = load_data(test_file_path)
  146. # 构建用于数据增强的图像生成器
  147. aug = ImageDataGenerator(rotation_range=30, width_shift_range=0.1,
  148. height_shift_range=0.1, shear_range=0.2, zoom_range=0.2,
  149. horizontal_flip=True, fill_mode="nearest")
  150. # 开始训练
  151. train(aug,trainX,trainY,testX,testY,args)

四、图像预测

预测图像时,程序执行的步骤如下:

  1. 加载训练好的模型
  2. 对输入图像进行必要的前处理,如修改尺寸,序列化;
  3. 将序列化的图像输入模型中
  4. 得到序列结果,找到最大概率与对应位置

测过程即为输入图像,得到它是哪种分类的可能性最大以及对应的概率。

具体实现代码如下:


  1. # 加载工程中必要的库
  2. from keras.preprocessing.image import img_to_array
  3. from keras.models import load_model
  4. import numpy as np
  5. import argparse
  6. import imutils
  7. import cv2
  8. # 根据使用的模型,确定图像需要resize的尺寸
  9. norm_size = 64
  10. # 预测函数,
  11. # 输入: 包含配置参数的字典
  12. def predict(args):
  13. # 加载训练好的卷积神经网络
  14. print("[INFO] loading network...")
  15. model = load_model(args["model"])
  16. # 加载图像
  17. image = cv2.imread(args["image"])
  18. # 因为对图像需要进行写入标签,影响较大所以复制一个图像
  19. orig = image.copy()
  20. # 预处理图像进行分类
  21. # 图像的尺寸重载
  22. image = cv2.resize(image, (norm_size, norm_size))
  23. # 图像的序列的归一化处理
  24. image = image.astype("float") / 255.0
  25. # 将图像进行序列化
  26. image = img_to_array(image)
  27. # 展开数组的形状.
  28. # 插入一个新的轴,该轴将出现在扩展阵列形状的轴位置
  29. image = np.expand_dims(image, axis=0)
  30. # 对输入的图像进行分类
  31. result = model.predict(image)[0]
  32. # print (result.shape)
  33. proba = np.max(result)
  34. label = str(np.where(result == proba)[0])
  35. label = "{}: {:.2f}%".format(label, proba * 100)
  36. print(label)
  37. # 在需要加载图像的情况下
  38. if args['show']:
  39. output = imutils.resize(orig, width=400)
  40. # 在图像上绘制标签字符串
  41. cv2.putText(output, label, (10, 25), cv2.FONT_HERSHEY_SIMPLEX,
  42. 0.7, (0, 255, 0), 2)
  43. # 显示带标签的图像
  44. cv2.imshow("Output", output)
  45. cv2.waitKey(0)
  46. # python predict.py --model traffic_sign.model -i ../2.png -s
  47. if __name__ == '__main__':
  48. args = {}
  49. # 模型的输入路径
  50. args['model'] = 'MODE/traffic_sign2.model'
  51. # 图像的输入路径
  52. args['image'] = 'predict/00000_00005.png'
  53. args['show'] = 'true'
  54. # 执行预测
  55. predict(args)

训练的图像如下图:

使用Keras对交通标志进行分类的更多相关文章

  1. 人工智能深度学习框架MXNet实战:深度神经网络的交通标志识别训练

    人工智能深度学习框架MXNet实战:深度神经网络的交通标志识别训练 MXNet 是一个轻量级.可移植.灵活的分布式深度学习框架,2017 年 1 月 23 日,该项目进入 Apache 基金会,成为 ...

  2. TSR交通标志检测与识别

    TSR交通标志检测与识别 说明: 传统图像处理算法的TSR集成在在ARM+DSP上运行,深度学习开发的TSR集成到FPGA上运行. 输入输出接口 Input: (1)图像视频分辨率(整型int) (2 ...

  3. AI在汽车中的应用:实用深度学习

    https://mp.weixin.qq.com/s/NIza8E5clC18eMF_4GMwDw 深度学习的“深度”层面源于输入层和输出层之间实现的隐含层数目,隐含层利用数学方法处理(筛选/卷积)各 ...

  4. 【Keras】从两个实际任务掌握图像分类

    我们一般用深度学习做图片分类的入门教材都是MNIST或者CIFAR-10,因为数据都是别人准备好的,有的甚至是一个函数就把所有数据都load进来了,所以跑起来都很简单,但是跑完了,好像自己还没掌握图片 ...

  5. 深度学习应用系列(二) | 如何使用keras进行迁移学习,以训练和识别自己的图片集

    本文的keras后台为tensorflow,介绍如何利用预编译的模型进行迁移学习,以训练和识别自己的图片集. 官网 https://keras.io/applications/ 已经介绍了各个基于Im ...

  6. TB3_Autorace之交通杆检测

    利用blob检测算法识别交通杆,控制TB3机器人完成对交通杆的起停动作! 上一篇博文中<TB3_Autorace之路标检测>订阅了原始图像信息,经过SIFT检测识别出道路交通标志,这里我们 ...

  7. GAN︱生成模型学习笔记(运行机制、NLP结合难点、应用案例、相关Paper)

    我对GAN"生成对抗网络"(Generative Adversarial Networks)的看法: 前几天在公开课听了新加坡国立大学[机器学习与视觉实验室]负责人冯佳时博士在[硬 ...

  8. 预测学习、深度生成式模型、DcGAN、应用案例、相关paper

    我对GAN"生成对抗网络"(Generative Adversarial Networks)的看法: 前几天在公开课听了新加坡国立大学[机器学习与视觉实验室]负责人冯佳时博士在[硬 ...

  9. TensorFlow和最近发布的slim

    笔者将和大家分享一个结合了TensorFlow和最近发布的slim库的小应用,来实现图像分类.图像标注以及图像分割的任务,围绕着slim展开,包括其理论知识和应用场景. 之前自己尝试过许多其它的库,比 ...

随机推荐

  1. java多线程的(一)-之java线程的使用

    一.摘要 每天都和电脑打交道,也相信大家使用过资源管理器杀掉过进程.而windows本身就是多进程的操作系统 在这里我们理解两组基本概念: 1.进程和线程的区别???? 2.并行与并发的区别???? ...

  2. C语言博客作业—数组

    一.PTA实验作业 题目1:简化的插入排序 1. 本题PTA提交列表 2. 设计思路 (1)定义n,number,i,j,temp; (2)输入n; (3)定义数组a[n+1]; //把所有的数都放入 ...

  3. 2017-2018-1 Java演绎法 第三周 作业

    团队任务:团队展示与选题 团队展示 队员学号及姓名 学号 姓名 主要负责工作 20162315 马军 日常统计,项目部分代码 20162316 刘诚昊 项目部分代码,代码质量测试 20162317 袁 ...

  4. alpha-咸鱼冲刺day4

    一,合照 emmmmm.自然还是没有的. 二,项目燃尽图 三,项目进展 QAQ具体工作量没啥进展.但是前后端终于可以数据交互了!.. 四,问题困难 日常啥都不会,百度真心玩一年. 还得自学nodejs ...

  5. Archlinux下i3wm与urxvt的配置

    前段时间学习了GitHub的两位前辈:Airblader和wlh320.他们的相关教程在https://github.com/Airblader/i3和https://github.com/wlh32 ...

  6. 20145237 《Java程序设计》第七周学习总结

    20145237 <Java程序设计>第七周学习总结 教材学习内容总结 第十三章   一.认识时间与日期   1.时间的度量   在正式认识Java提供了哪些时间处理API之前,得先来了解 ...

  7. 如何使用ILAsm与ILDasm修改.Net exe(dll)文件

    一.背景 最近项目组新上项目,交付的时间比较急迫,原本好的分支管理习惯没有遵守好,于是出现下面状况: 多个小伙伴在不同的分支上开发. 原本QA环境也存在一个阻碍性的bug A 一位同事在QA环境发布了 ...

  8. vue下拉列表

    最近在弄作品,做了个下拉列表.心想各位小哥哥.小姐姐可能会用到相同的需求,就把下拉列表封装一下,希望能对各位小哥哥,小姐姐有帮助 github地址:https://github.com/ClmPisc ...

  9. 新概念英语(1-63)Thank you, doctor.

    新概念英语(1-63)Thank you, doctor. Who else is in bed today? why? A:How's Jimmy today? B:Better. Thank yo ...

  10. 证明二叉查找树所有节点的平均深度为O(logN)

    数据结构与算法分析(c语言描述)第4章 P78 概念一:一棵树所有节点的深度和称为内部路径长 令D(N)为一棵有N节点的树的内部路径长么,即有D(1)=0, 设一棵树的左子树的内部路径长为D(i),则 ...