0.前言:
注:本文基于tensorflow-gpu1.12版本,windows10,python3.6
深度学习环境搭建见文章:https://blog.csdn.net/weixin_43435675/article/details/88359636
在桌面新建目标检测2文件夹,以下为本次项目会用到的文件:
1.下载图片
本文作者给读者演示的图片数据是来自ImageNet中的鲤鱼分类,网盘链接:链接:https://pan.baidu.com/s/17iI62gt9HyRbQ-Wr8h28jw 提取码:4swb
在桌面新建目标检测2,将下载好的压缩文件放入其中并解压,如下图所示:
2.挑选图片
在此数据集中,大部分图片都较为清晰,但是有极少数图片像素点少,不清晰。像素点少的图片不利于模型训练或模型测试,所以在本章节中实现用python代码选出部分图片文件:在目标检测2文件夹中cmd
重命名为:get_some_qualified_images
运行下一段代码:
import os
import random
from PIL import Image
import shutil
#获取1000张图片中随机选出数量为sample_number*2的一部分图片的路径
def get_some_imagePath(dirPath, sample_number):
fileName_list = os.listdir(dirPath)
all_filePath_list = [os.path.join(dirPath, fileName) for fileName in fileName_list]
all_imagePath_list = [filePath for filePath in all_filePath_list if '.jpg' in filePath]
some_filePath_list = random.sample(all_filePath_list, k=sample_number*2)
return some_filePath_list
#获取一部分像素足够,即长,宽都大于300的图片
def get_some_qualified_images(dirPath, sample_number, new_dirPath):
some_imagePath_list = get_some_imagePath(dirPath, sample_number)
if not os.path.isdir(new_dirPath):
os.mkdir(new_dirPath)
i = 0
for imagePath in some_imagePath_list:
image = Image.open(imagePath)
width, height = image.size
if width > 300 and height > 300:
i += 1
new_imagePath = 'selected_images/%03d.jpg' %i
shutil.copy(imagePath, new_imagePath)
if i == sample_number:
break
#获取数量为100的合格样本存放到selected_images文件夹中
get_some_qualified_images('n01440764', 100, 'selected_images')
在目标检测文件夹下多出下图红色框出
3.缩小图片
在上一章选择图片中,选出了100张像素足够的图片存放在selected_images文件夹中,即淘汰了像素过小的图片。在本章中用代码实现将像素过大的图片做缩小:与上一章操作相同在jupyter notebook中新建代码文件get_small_images.ipynb。
复制下一段代码进get_small_images.ipynb运行
import os
from PIL import Image
def get_smaller_images(dirPath, new_dirPath):
fileName_list = os.listdir(dirPath)
filePath_list = [os.path.join(dirPath, fileName) for fileName in fileName_list]
imagePath_list = [filePath for filePath in filePath_list if '.jpg' in filePath]
if not os.path.isdir(new_dirPath):
os.mkdir(new_dirPath)
for imagePath in imagePath_list:
image = Image.open(imagePath)
width, height = image.size
imageName = imagePath.split('\\')[-1]
save_path = os.path.join(new_dirPath, imageName)
if width >= 600 and height >= 600:
minification = min(width, height) // 300 #此变量表示缩小倍数
new_width = width // minification
new_height = height // minification
resized_image = image.resize((new_width, new_height), Image.ANTIALIAS)
print('图片%s原来的宽%d,高%d, 图片缩小后宽%d,高%d' %(
imageName, width, height, new_width, new_height))
resized_image.save(save_path)
else:
image.save(save_path)
get_smaller_images('selected_images', 'smaller_images')
在本文作者的实践中,图片经过PIL库打开再保存,保持图片质量的情况下,能够缩小图片文件大小3倍左右。使用的图片压缩算法不同,完成此步后,文件夹大小如下图所示
4.给图片打标签
使用打标签工具LabelImg,网盘链接:链接:https://pan.baidu.com/s/1YT_s0Ef95fOJAsiG69Bmkw 提取码:6epi
把压缩文件windows_v1.8.0.zip放到D盘根目录中,选择解压到当前文件夹。解压后D盘根目录下会有windows_v1.8.0文件夹,LabelImg软件在文件夹中。选择D盘根目录的原因:如果windows_v1.8.0文件夹路径中带有中文,打开LabelImg软件会闪退
在输入法为英文输入的情况下,按键盘上的w键则可以开始绘制方框,方框会框住图片中的物体。完成绘制方框后,还需要为方框标上类别,如下图所示,每完成一张图的打标签,一定要记得保存!!!
在本文演示中,需要给图片中的鲤鱼和人脸2个类别打标签。鲤鱼的标签名叫做fish,人脸的标签名叫human_face,打标签的结果如下图所示。注意:用方框框住物体时,尽量框住物体的所有部位,例如本文中的鱼,鱼鳍是一个重要特征。保证框住物体所有部位的情况下,也不要使方框四周留出过多空白
遇到特征不明显的图片,可以放弃为此图片打标签。用LabelImg软件打标签会给每张图片产生对应的xml文件。检查是否给所有图片都打上标签,在文件夹smaller_images中共有99个xml文件。因为有1张图片难以辨认,所以没有给它打标签
本文作者把已经打标签好的文件夹smaller_images做成压缩文件smaller_images.zip,并上传到百度网盘
链接:https://pan.baidu.com/s/13-fRksSjUeEii54gClA3Pw 提取码:57lz
5.xml转csv
xml转csv的意思是,将xml文件中的信息整合到csv文件中。
在桌面的目标检测2文件夹中新建代码文件xml_to_csv.ipynb,步骤与之前相同:打开cmd——>运行jupyter notebook——>新建代码文件——>代码文件重命名,复制下面一段代码到代码文件xml_to_csv.ipynb的单元格中,复制后运行即可:
import os
import pandas as pd
import xml.etree.ElementTree as ET
from sklearn.model_selection import train_test_split
def xmlPath_list_to_df(xmlPath_list):
xmlContent_list = []
for xmlPath in xmlPath_list:
tree = ET.parse(xmlPath)
root = tree.getroot()
for member in root.findall('object'):
value = (root.find('filename').text,
int(root.find('size')[0].text),
int(root.find('size')[1].text),
member[0].text,
int(member[4][0].text),
int(member[4][1].text),
int(member[4][2].text),
int(member[4][3].text)
)
xmlContent_list.append(value)
column_name = ['filename', 'width', 'height', 'class', 'xmin', 'ymin', 'xmax', 'ymax']
xmlContent_df = pd.DataFrame(xmlContent_list, columns=column_name)
return xmlContent_df
def dirPath_to_csv(dirPath):
fileName_list = os.listdir(dirPath)
all_xmlPath_list = [os.path.join(dirPath, fileName) for fileName in fileName_list if '.xml' in fileName]
train_xmlPath_list, test_xmlPath_list = train_test_split(all_xmlPath_list, test_size=0.1, random_state=1)
train_df = xmlPath_list_to_df(train_xmlPath_list)
train_df.to_csv('train.csv')
print('成功产生文件train.csv,训练集共有%d张图片' %len(train_xmlPath_list))
test_df = xmlPath_list_to_df(test_xmlPath_list)
test_df.to_csv('test.csv')
print('成功产生文件test.csv,测试集共有%d张图片' %len(test_xmlPath_list))
dirPath_to_csv('smaller_images')
为了使读者与本文作者的复现结果一致,本文作者将函数train_test_split的参数random_state的值设为1,这样每次划分的训练集和测试集总是相同。如果不设置此参数,则每次划分的训练集和测试集不同。上面一段代码的运行结果如下:
成功产生文件train.csv,训练集共有89张图片
成功产生文件test.csv,测试集共有10张图片
6.csv转tfrecord
csv转tfrecord的意思是,将csv文件中的信息和图片数据整合到tfrecord文件中。
6.1配环境
object_detection文件分享,或者可以到官网下载,可以参考我另一篇文章:https://blog.csdn.net/weixin_43435675/article/details/88201615
链接:https://pan.baidu.com/s/19T5KCZxEKjzYJLQoWIc2qA
提取码:2zk3
6.2运行代码
在桌面的目标检测文件夹中新建代码文件csv_to_tfrecord.ipynb,步骤与前面相同:
打开cmd——>运行jupyter notebook——>新建代码文件——>代码文件重命名
复制下面一段代码到代码文件csv_to_tfrecord.ipynb的单元格中,复制后运行即可:
import os
import pandas as pd
import tensorflow as tf
from object_detection.utils import dataset_util
import shutil
def csv2tfrecord(csv_path, imageDir_path, tfrecord_path):
objectInfo_df = pd.read_csv(csv_path)
tfrecord_writer = tf.python_io.TFRecordWriter(tfrecord_path)
for filename, group in objectInfo_df.groupby('filename'):
height = group.iloc[0]['height']
width = group.iloc[0]['width']
filename_bytes = filename.encode('utf-8')
image_path = os.path.join(imageDir_path, filename)
with open(image_path, 'rb') as file:
encoded_jpg = file.read()
image_format = b'jpg'
xmin_list = list(group['xmin'] / width)
xmax_list = list(group['xmax'] / width)
ymin_list = list(group['ymin'] / height)
ymax_list = list(group['ymax'] / height)
classText_list = [classText.encode('utf-8') for classText in group['class']]
classLabel_list = [classText_to_classLabel(classText) for classText in group['class']]
tf_example = tf.train.Example(
features = tf.train.Features(
feature = {
'image/height': dataset_util.int64_feature(height),
'image/width': dataset_util.int64_feature(width),
'image/filename': dataset_util.bytes_feature(filename_bytes),
'image/source_id': dataset_util.bytes_feature(filename_bytes),
'image/encoded': dataset_util.bytes_feature(encoded_jpg),
'image/format': dataset_util.bytes_feature(image_format),
'image/object/bbox/xmin': dataset_util.float_list_feature(xmin_list),
'image/object/bbox/xmax': dataset_util.float_list_feature(xmax_list),
'image/object/bbox/ymin': dataset_util.float_list_feature(ymin_list),
'image/object/bbox/ymax': dataset_util.float_list_feature(ymax_list),
'image/object/class/text': dataset_util.bytes_list_feature(classText_list),
'image/object/class/label': dataset_util.int64_list_feature(classLabel_list),
}))
tfrecord_writer.write(tf_example.SerializeToString())
tfrecord_writer.close()
print('成功产生tfrecord文件,保存在路径:%s' %tfrecord_path)
#如果训练自己的模型,目标检测的类别不同,需要修改此处
def classText_to_classLabel(row_label):
if row_label == 'fish':
return 1
elif row_label == 'human_face':
return 2
else:
return None
dir_name = 'training'
if not os.path.isdir(dir_name):
os.mkdir(dir_name)
csv2tfrecord('train.csv', 'smaller_images', 'training/train.tfrecord')
csv2tfrecord('test.csv', 'smaller_images', 'training/test.tfrecord')
运行结果:
成功产生tfrecord文件,保存在路径:training/train.tfrecord
成功产生tfrecord文件,保存在路径:training/test.tfrecord
成功运行后产生training文件夹:
7.编写pbtxt文件
在桌面文件夹目标检测2的文件夹training中,创建文本文件my_label_map.pbtxt。复制下面一段内容到文本文件my_label_map.pbtxt中。
item {
name : "fish"
id : 1
}
item {
name : "human_face"
id : 2
}
有一个细节需要特别注意,文本文件fish_label.pbtxt在Windows系统下默认编码格式是ANSI格式,工程中需要的就是此格式。但是本文作者在认为python3对utf-8编码支持较好,所以把文本文件fish_label.pbtxt的编码改成了utf-8格式,导致工程报错。
8.编写配置文件
在桌面文件夹目标检测2的文件夹training
中,创建配置文件ssdlite_mobilenet_v2_coco.config
。
本文作者给读者提供2种方式获得正确的配置文件。
8.1 网盘下载
链接:https://pan.baidu.com/s/1h4OEPEd-wxH4Yakq3c8_8g
提取码:6kr7
8.2 修改原生配置文件
原生配置文件ssdlite_mobilenet_v2_coco.config先复制1份到桌面文件目标检测2的文件夹training中
修改的部分为:用notepad++打开:
第9行的num_classes,对于本文来说,此数设置为2。
第143行的batch_size,对于本文来说,此数设置为5,读者根据自己的电脑配置,可以调高或者调低。
第177行input_path设置成"training/train.tfrecord"。
第179行label_map_path设置成"training/my_label_map.pbtxt"。
第191行input_path设置成"training/test.tfrecord"。
第193行label_map_path设置成"training/my_label_map.pbtxt"。
第158、159这2行需要删除。
修改保存后在training
文件夹下有以下几个文件:
9.训练模型
9.1解决第一个报错
在桌面文件夹目标检测2中cmd,运行程序:python object_detection/model_main.py --pipeline_config_path=training/ssdlite_mobilenet_v2_coco.config --model_dir=training --alsologtostderr
结果如下报错:
解决:新建环境变量,读者可以之前参考文章:https://blog.csdn.net/weixin_43435675/article/details/88122998
新建变量名为:PYTHONPATH,全部点确定按钮
9.2解决第二个报错
成功添加环境变量后,需要在桌面的目标检测文件夹中重新打开cmd。在cmd中运行命令:python object_detection/model_main.py --pipeline_config_path=training/ssdlite_mobilenet_v2_coco.config --model_dir=training --alsologtostderr
,运行结果如下图所示:
缺少pycocotools库,在linux系统中安装pycocotools库只需要运行命令:pip install pycocotools
但是在Windows上安装则复杂得多
9.2.1下载并安装Microsoft C++ build 14.0
首先下载Microsoft C++ build 14.0,链接:https://go.microsoft.com/fwlink/?LinkId=691126
9.2.2下载并安装pycocotools
打开git页面,链接:https://github.com/philferriere/cocoapi
对压缩文件cocoapi-master.zip选择解压到当前文件夹。进入文件夹cocoapi-master中的文件夹PythonAPI,在此文件夹下打开cmd运行指令:python setup.py build_ext install
如下图安装成功:
9.3解决第三个报错
进行完上面后,需要在桌面的目标检测文件夹中重新打开cmd。在cmd中运行命令:python object_detection/model_main.py --pipeline_config_path=training/ssdlite_mobilenet_v2_coco.config --model_dir=training --alsologtostderr
,运行结果如下图所示:
解决此报错,需要阅读本文作者的文章《目标检测1-运行tensorflow官方示例》中的第2章《proto文件转py文件》https://blog.csdn.net/weixin_43435675/article/details/88201615 就是把object_detection/protos文件夹中将proto文件转py文件。
9.4解决第四个报错
进行完第3章后,使用第3章中的cmd即可。在cmd中运行命令:python object_detection/model_main.py --pipeline_config_path=training/ssdlite_mobilenet_v2_coco.config --model_dir=training --alsologtostderr
,运行结果如下图所示:
将models-master/research/slim文件夹中的nets文件夹移动到桌面的目标检测2文件夹中,即文件夹object_detection同级目录。因为models-master.zip大小为439M,但我们其实只要nets文件夹。
本文作者提供nets文件夹压缩后的压缩文件nets.zip:链接:https://pan.baidu.com/s/1jf4Owi50nRF7CdQ-YVdvig 提取码:fg2t
9.5解决第五个报错
进行完第4章后,使用第4章中的cmd即可。在cmd中运行命令:python object_detection/model_main.py --pipeline_config_path=training/ssdlite_mobilenet_v2_coco.config --model_dir=training --alsologtostderr
,运行结果如下图所示:
如果要进行目标检测, 最少也需要配备版本为GTX 1060_显存6G的显卡
修改工程文件夹object_detection中的代码文件model_lib.py
如下图所示,找到第418行,将category_index.values()
修改为list(category_index.values())
修改代码文件model_lib.py完成后,则可以在cmd中重新输入命令开启模型训练。
模型训练稳定地进行一段时间后,会做一次模型评估,如下图所示:
10.查看训练效果
模型训练稳定地进行后,在桌面的目标检测文件夹中重新打开cmd。在cmd中运行命令:tensorboard --logdir=training
,出现下图,复制到浏览器中打开
11.模型测试
作者将目标检测做了压缩 链接:https://pan.baidu.com/s/18c4Ec6wfLRs-1RitxFQMzg 提取码:658j
解压后含以下三个文件夹,training文件夹里含已经训练好的20万次模型,将自己的目标检测2文件夹里object-detection和training替换成下载好的
11.1导出训练好的模型
在目标检测2文件夹中打开cmd,运行python object_detection/export_inference_graph.py --input_type=image_tensor --pipeline_config_path=training/ssdlite_mobilenet_v2_coco.config --trained_checkpoint_prefix=training/model.ckpt-200000 --output_directory=fish_inference_graph
运行正常需要安装PYQT5这个库,pip install pyqt5
即可安装好,此时目标检测2文件夹里多出了红色框出的文件夹
如上图红色框出是测试图片数据集
11.2下载并运行测试代码
检测代码文件:链接:https://pan.baidu.com/s/1wKrqnQCGfnHTS5n9nqZ_gw 提取码:vdj7
代码文件fish_detection.ipynb下载完成后,复制到桌面的文件夹目标检测2中,在目标检测2中打开cmd
输入jupyter notebook 并打开fish_detection.ipynb,如下图所示:
n01440764
文件夹中共有1300张图片,测试图片是随机选的10张图片: