训练详细步骤:YunYang1994/tensorflow-yolov3 训练自己的数据集
我这边使用自己的数据集已经训练好了权重文件,将该权重文件应用于evaluate.py
效果不错,但用video_demo.py
做实时检测却完全不行,查看代码发现,evaluate.py
只用了cfg.TEST.WEIGHT_FILE
即"./checkpoint/f_g_c_weights_files/yolov3_test_loss=15.8845.ckpt-47"
,而video_demp.py
使用的却是转换后的.pb
文件。
但是video_demo.py
使用的.pb
文件确实又是从cfg.TEST.WEIGHT_FILE
通过freeze_graph.py
转换过来的,照理来说也不应有问题。。。
尝试更改video_demo.py
里的input_size
(因为发现evaluate.py
里的input_size
和video_demp.py
里的不一样。。。)
video_demo.py
里的为416,evaluate.py
里的是使用的cfg.TEST.INPUT_SIZE
,为544。。。
将video_demo.py
里的改成544:
效果貌似比416好那么一丢丢???但还是不理想,胡乱识别。
算了,要不我还是根据evaluate.py
重写一个算了。。。。
给它命名为dontla_evaluate_detect.py
。。。
因为有现成的代码可以套用,所以没一会就写好了:
# -*- encoding: utf-8 -*-
"""
@File : dontla_evaluate_detect.py
@Time : 2019/11/21 13:11
@Author : Dontla
@Email : sxana@qq.com
@Software: PyCharm
"""
import cv2
import numpy as np
import tensorflow as tf
import core.utils as utils
from core.config import cfg
from core.yolov3 import YOLOV3
import pyrealsense2 as rs
class YoloTest(object):
def __init__(self):
# D·C 191111:__C.TEST.INPUT_SIZE = 544
self.input_size = cfg.TEST.INPUT_SIZE
self.anchor_per_scale = cfg.YOLO.ANCHOR_PER_SCALE
# Dontla 191106注释:初始化class.names文件的字典信息属性
self.classes = utils.read_class_names(cfg.YOLO.CLASSES)
# D·C 191115:类数量属性
self.num_classes = len(self.classes)
self.anchors = np.array(utils.get_anchors(cfg.YOLO.ANCHORS))
# D·C 191111:__C.TEST.SCORE_THRESHOLD = 0.3
self.score_threshold = cfg.TEST.SCORE_THRESHOLD
# D·C 191120:__C.TEST.IOU_THRESHOLD = 0.45
self.iou_threshold = cfg.TEST.IOU_THRESHOLD
self.moving_ave_decay = cfg.YOLO.MOVING_AVE_DECAY
# D·C 191120:__C.TEST.ANNOT_PATH = "./data/dataset/Dontla/20191023_Artificial_Flower/test.txt"
self.annotation_path = cfg.TEST.ANNOT_PATH
# D·C 191120:__C.TEST.WEIGHT_FILE = "./checkpoint/f_g_c_weights_files/yolov3_test_loss=15.8845.ckpt-47"
self.weight_file = cfg.TEST.WEIGHT_FILE
# D·C 191115:可写标记(bool类型值)
self.write_image = cfg.TEST.WRITE_IMAGE
# D·C 191115:__C.TEST.WRITE_IMAGE_PATH = "./data/detection/"(识别图片画框并标注文本后写入的图片路径)
self.write_image_path = cfg.TEST.WRITE_IMAGE_PATH
# D·C 191116:TEST.SHOW_LABEL设置为True
self.show_label = cfg.TEST.SHOW_LABEL
# D·C 191120:创建命名空间“input”
with tf.name_scope('input'):
# D·C 191120:建立变量(创建占位符开辟内存空间)
self.input_data = tf.placeholder(dtype=tf.float32, name='input_data')
self.trainable = tf.placeholder(dtype=tf.bool, name='trainable')
model = YOLOV3(self.input_data, self.trainable)
self.pred_sbbox, self.pred_mbbox, self.pred_lbbox = model.pred_sbbox, model.pred_mbbox, model.pred_lbbox
# D·C 191120:创建命名空间“指数滑动平均”
with tf.name_scope('ema'):
ema_obj = tf.train.ExponentialMovingAverage(self.moving_ave_decay)
# D·C 191120:在允许软设备放置的会话中启动图形并记录放置决策。(不懂啥意思。。。)allow_soft_placement=True表示允许tf自动选择可用的GPU和CPU
self.sess = tf.Session(config=tf.ConfigProto(allow_soft_placement=True))
# D·C 191120:variables_to_restore()用于加载模型计算滑动平均值时将影子变量直接映射到变量本身
self.saver = tf.train.Saver(ema_obj.variables_to_restore())
# D·C 191120:用于下次训练时恢复模型
self.saver.restore(self.sess, self.weight_file)
def predict(self, image):
# D·C 191107:复制一份图片的镜像,避免对图片直接操作改变图片的内在属性
org_image = np.copy(image)
# D·C 191107:获取图片尺寸
org_h, org_w, _ = org_image.shape
# D·C 191108:该函数将源图结合input_size,将其转换成预投喂的方形图像(作者默认544×544,中间为缩小尺寸的源图,上下空区域为灰图):
image_data = utils.image_preprocess(image, [self.input_size, self.input_size])
# D·C 191108:打印维度看看:
# print(image_data.shape)
# (544, 544, 3)
# D·C 191108:创建新轴,不懂要创建新轴干嘛?
image_data = image_data[np.newaxis, ...]
# D·C 191108:打印维度看看:
# print(image_data.shape)
# (1, 544, 544, 3)
# D·C 191110:三个box可能存放了预测框图(可能是N多的框,有用的没用的重叠的都在里面)的信息(但是打印出来的值完全看不懂啊喂?)
pred_sbbox, pred_mbbox, pred_lbbox = self.sess.run(
[self.pred_sbbox, self.pred_mbbox, self.pred_lbbox],
feed_dict={
self.input_data: image_data,
self.trainable: False
}
)
# D·C 191110:打印三个box的类型、形状和值看看:
# print(type(pred_sbbox))
# print(type(pred_mbbox))
# print(type(pred_lbbox))
# 都是<class 'numpy.ndarray'>
# print(pred_sbbox.shape)
# print(pred_mbbox.shape)
# print(pred_lbbox.shape)
# (1, 68, 68, 3, 6)
# (1, 34, 34, 3, 6)
# (1, 17, 17, 3, 6)
# print(pred_sbbox)
# print(pred_mbbox)
# print(pred_lbbox)
# D·C 191110:(-1,6)表示不知道有多少行,反正你给我整成6列,然后concatenate又把它们仨给叠起来,最终得到无数个6列数组(后面self.num_classes)个数存放的貌似是这个框属于类的概率)
pred_bbox = np.concatenate([np.reshape(pred_sbbox, (-1, 5 + self.num_classes)),
np.reshape(pred_mbbox, (-1, 5 + self.num_classes)),
np.reshape(pred_lbbox, (-1, 5 + self.num_classes))], axis=0)
# D·C 191111:打印pred_bbox和它的维度看看:
# print(pred_bbox)
# print(pred_bbox.shape)
# (18207, 6)
# D·C 191111:猜测是第一道过滤,过滤掉score_threshold以下的图片,过滤完之后少了好多:
# D·C 191115:bboxes维度为[n,6],前四列是坐标,第五列是得分,第六列是对应类下标
bboxes = utils.postprocess_boxes(pred_bbox, (org_h, org_w), self.input_size, self.score_threshold)
# D·C 191111:猜测是第二道过滤,过滤掉iou_threshold以下的图片:
bboxes = utils.nms(bboxes, self.iou_threshold)
return bboxes
def dontla_evaluate_detect(self):
pipeline = rs.pipeline()
config = rs.config()
config.enable_stream(rs.stream.depth, 1280, 720, rs.format.z16, 30)
config.enable_stream(rs.stream.color, 1280, 720, rs.format.bgr8, 30)
pipeline.start(config)
# 创建对齐对象(深度对齐颜色)
align = rs.align(rs.stream.color)
try:
while True:
frames = pipeline.wait_for_frames()
# 获取对齐帧集
aligned_frames = align.process(frames)
# 获取对齐后的深度帧和彩色帧
aligned_depth_frame = aligned_frames.get_depth_frame()
color_frame = aligned_frames.get_color_frame()
# 获取颜色帧内参
color_profile = color_frame.get_profile()
cvsprofile = rs.video_stream_profile(color_profile)
color_intrin = cvsprofile.get_intrinsics()
color_intrin_part = [color_intrin.ppx, color_intrin.ppy, color_intrin.fx, color_intrin.fy]
if not aligned_depth_frame or not color_frame:
continue
color_image = np.asanyarray(color_frame.get_data())
# D·C 191121:显示帧看看
# cv2.namedWindow('RealSense', cv2.WINDOW_AUTOSIZE)
# cv2.imshow('RealSense', color_frame)
# cv2.waitKey(1)
bboxes_pr = self.predict(color_image)
image = utils.draw_bbox(color_image, bboxes_pr, aligned_depth_frame, color_intrin_part,
show_label=self.show_label)
cv2.namedWindow('RealSense', cv2.WINDOW_AUTOSIZE)
cv2.imshow('RealSense', image)
cv2.waitKey(1)
finally:
pipeline.stop()
if __name__ == '__main__':
YoloTest().dontla_evaluate_detect()
运行试试,效果还行。。。