目录
调试faster rcnn算法实用的python脚本
一、前言
二、常用python脚本
三、后记
最近在做关于目标检测算法的研究,调试的第一个算法就是faster-rcnn,今天要说的时笔者在跑通这个算法,也就是训练、评估、数据制作等过程中用到的一些简单实用的python脚本,在这里分享出来,写的不好希望大家多多指正。
在调通了代码确保能够训练官方的Pascal_voc数据集之后,我们就自己标注数据集,希望训练自己的模型,采用的方法是实用labelimg工具一张一张的标,标注完之后图片名不统一,所以这个脚本就是统一命名全部图片,代码如下:
# -*- coding:utf8 -*-
import os
class BatchRename():
'''
批量重命名文件夹中的图片文件
'''
def __init__(self):
self.path = 'F:\\Desktop\\data\\video_cut\\1' #表示需要命名处理的文件夹
# self.path = '这边写上你需要重命名的图片的路径'
def rename(self):
filelist = os.listdir(self.path) #获取文件路径
total_num = len(filelist) #获取文件长度(个数)
i = 1 #表示文件的命名是从1开始的
for item in filelist:
if item.endswith('.jpg'): #初始的图片的格式为jpg格式的(或者源文件是png格式及其他格式,后面的转换格式就可以调整为自己需要的格式即可)
src = os.path.join(os.path.abspath(self.path), item)
#dst = os.path.join(os.path.abspath(self.path), ''+str(i) + '.jpg')#处理后的格式也为jpg格式的,当然这里可以改成png格式
dst = os.path.join(os.path.abspath(self.path), '000' + format(str(i), '0>3s') + '.jpg')#这种情况下的命名格式为0000000.jpg形式,可以自主定义想要的格式
try:
os.rename(src, dst)
print ('converting %s to %s ...' % (src, dst))
i = i + 1
except:
continue
print ('total %d to rename & converted %d jpgs' % (total_num, i))
if __name__ == '__main__':
demo = BatchRename()
demo.rename()
faster-rcnn算法可以测出单张的效果,在我修改了tf-faster-rcnn-master\tools下的demo.py之后,就能够测试多张,所以我想看到测试结果时,通常是一张张的图片放置在指定的路径下,然后,就能够跑很多demo,如下图所示:
每一张都是检测后的结果,这样看起来没有连续性,不够直观,所以此时利用这个脚本将所有的图片合成视频,就能够直观的看到效果,代码如下:
# -*- coding: UTF-8 -*-
import os
import cv2
import time
# 图片合成视频
def image2video(path,size):
filelist = os.listdir(path) #获取该目录下的所有文件名
'''
fps:
帧率:1秒钟有n张图片写进去[控制一张图片停留5秒钟,那就是帧率为1,重复播放这张图片5次]
如果文件夹下有50张 534*300的图片,这里设置1秒钟播放5张,那么这个视频的时长就是10秒
'''
fps = 3
#size = (1920,1080) #图片的分辨率片
# 导出的视频的存放目录
file_path = "F:\\Desktop\\data\\test_video\\2\\" + str(int(time.time())) + ".avi"#合成视频导出路径
fourcc = cv2.VideoWriter_fourcc('D', 'I', 'V', 'X')#不同视频编码对应不同视频格式(例:'I','4','2','0' 对应avi格式)
video = cv2.VideoWriter( file_path, fourcc, fps, size )
for item in filelist:
if item.endswith('.jpg'): #判断图片后缀是否是.jpg
item = path + '/' + item
img = cv2.imread(item) #使用opencv读取图像,直接返回numpy.ndarray 对象,通道顺序为BGR ,注意是BGR,通道值默认范围0-255。
video.write(img) #把图片写进视频
print (item)
video.release() #释放
#调用函数,给定所有图片的路径
image2video(r'F:\\Desktop\\data\\test_result\\2\\',(1280,720))
这个过程实际上就是对自己标注的数据集进行分析,因为我是把自己标注的数据集制作成Pascal_voc的样子,Pascal_voc共三个目录:
其中Annotations中对应的就是XML文件,每一个XML对应每一张图,也就是每一张原图生成一个XML,每个XML里保存的都是这个图片的重要信息,如:
VOC2012
2007_000392.jpg //文件名
//图像尺寸(长宽以及通道数)
500
332
3
1 //是否用于分割(在图像物体识别中01无所谓)
所以我们对所有的XML进行遍历,就可以分析下总共有几个object,每一类的object有多少,代码如下:同样,一些路径需要根据你们自身情况改动
#coding=utf-8
import xml.dom.minidom
import os
import sys
rootdir='F:/VOC2007/Annotations/'#存有xml文件的文件夹的绝对路径
list=os.listdir(rootdir)#列出文件夹下所有的目录与文件
classes_list=[]
classes_count_imag=[1,1,1,1,1,1,1]#统计含有各个目标的图片数
classes_count_object=[1,1,1,1,1,1,1]#统计各个目标的总数
for i in range(0,len(list)):
path=os.path.join(rootdir,list[i])
if os.path.isfile(path):
#用于区分imag和object
flag=[0,0,0,0,0,0,0]
#打开xml文档
dom=xml.dom.minidom.parse(path)
#得到文档元素对象
root=dom.documentElement
cc=dom.getElementsByTagName('name')
for i in range(len(cc)):
c1=cc[i]
#如果是新的目标则将其加入classes_list数组中
if classes_list.count(c1.firstChild.data)==0:
classes_list.append(c1.firstChild.data)
#统计imag和object的个数
else:
for j in range(0,len(classes_list)):
if(classes_list[j]==c1.firstChild.data):
if(flag[j]==0):
classes_count_imag[j]+=1
flag[j]=1
classes_count_object[j]+=1
print(classes_list)
print("Classes: "+str(len(classes_list)))
for i in range(len(classes_list)):
print("Class:%20s image:%10d张 object:%10d个"%(classes_list[i],classes_count_imag[i],classes_count_object[i]))
这个代码是评估用的,关于什么是p-r曲线,详情请看我之前的一篇博客。
因为做目标检测,最后看这个模型的好坏,就是利用p-r曲线和mAP来评估,mAP和各类的AP在跑算法跑到最后的时候,会自动帮你算出来,但是p-r曲线要自己画,画p-r曲线,最重要的是要有你测试结束后生成的pkl文件,生成在这个路径下:
tf-fastercnn/output/vgg16/voc_2007_test/default/vgg16_faster_rcnn_iter_70000
这里的pkl文件就是用来给我们画p-r曲线的,代码如下:
#! -*- coding=utf-8 -*-
import matplotlib.pyplot as plt
import pickle
import os
list = ['pedestrian', 'person', 'motorbike', 'bike', 'hat', 'motorbike1', 'person_trunc']
for i in list:
tmp = i + '_pr.pkl'
fp = open(tmp,'rb')
a = pickle.load(fp)
plt.ylim([0.0, 1.1])
plt.xlim([0.0, 1.1])
tmp = 'Faster R-CNN Precision-Recall Curve (' + i + ')'
plt.plot(a['rec'],a['prec'])
plt.xlabel('Recall')
plt.ylabel('Precision')
plt.title(tmp)
plt.show()
当然,如果你不明白这个pkl文件长啥样,里面是啥内容,你可以把pkl转成txt文本进行阅读(因为不能直接打开pkl文件,所以需要转化),代码如下:
#-*-coding:utf-8-*-
import pickle
import numpy as np
np.set_printoptions(threshold=np.NaN)
fr = open('./motorbike1_pr.pkl','rb')
inf = pickle.load(fr)
print (inf)
fo = open("motorbike_pr.txt", "wb")
fo.write(str(inf))
fo.close()
fr.close()
以上是在我调faster-rcnn时用到的脚本,希望可以提供帮助,接下来笔者将继续阅读faster-rcnn的源码,争取发出关于源码的解读,大家互相学习啦。