一、SSD用于图片物体的定位与检测

SSD原理介绍这一篇博客对我的帮助比较大,很详细的介绍了SSD原理,送给大家做了解

1、下载SSD框架源码

1.1:闲话不多说——下载SSD源码,解压后打开文件,将checkpoints文件夹下的压缩包也解压出来,再在pycharm上建立工程,大体如下图所示:

1.2:打开demo文件夹,这里就是用于外测的图片集

2、SSD做目标检测

notebooks文件夹下,建立demo_test.py文件,在demo_test.py文件内写入如下代码后,直接运行demo_test.py(以下代码也是notebooks文件夹ssd_tests.ipynb内的代码,可以用notebook读取;我只是做了一些小改动)

# -*- coding:utf-8 -*-
# -*- author:zzZ_CMing  CSDN address:https://blog.csdn.net/zzZ_CMing
# -*- 2018/07/14; 15:19
# -*- python3.5
"""
address: https://blog.csdn.net/qq_35608277/article/details/78660469
本文代码来自于github中微软官方仓库
"""
import os
import cv2
import math
import random
import tensorflow as tf
import matplotlib.pyplot as plt
import matplotlib.cm as mpcm
import matplotlib.image as mpimg
from notebooks import visualization
from nets import ssd_vgg_300, ssd_common, np_methods
from preprocessing import ssd_vgg_preprocessing
import sys# 当引用模块和运行的脚本不在同一个目录下,需在脚本开头添加如下代码:
sys.path.append('./SSD-Tensorflow/')slim = tf.contrib.slim# TensorFlow session
gpu_options = tf.GPUOptions(allow_growth=True)
config = tf.ConfigProto(log_device_placement=False, gpu_options=gpu_options)
isess = tf.InteractiveSession(config=config)l_VOC_CLASS = ['aeroplane', 'bicycle', 'bird', 'boat', 'bottle','bus', 'car', 'cat', 'chair', 'cow','diningTable', 'dog', 'horse', 'motorbike', 'person','pottedPlant', 'sheep', 'sofa', 'train', 'TV']# 定义数据格式,设置占位符
net_shape = (300, 300)
# 预处理,以Tensorflow backend, 将输入图片大小改成 300x300,作为下一步输入
img_input = tf.placeholder(tf.uint8, shape=(None, None, 3))
# 输入图像的通道排列形式,'NHWC'表示 [batch_size,height,width,channel]
data_format = 'NHWC'# 数据预处理,将img_input输入的图像resize为300大小,labels_pre,bboxes_pre,bbox_img待解析
image_pre, labels_pre, bboxes_pre, bbox_img = ssd_vgg_preprocessing.preprocess_for_eval(img_input, None, None, net_shape, data_format,resize=ssd_vgg_preprocessing.Resize.WARP_RESIZE)
# 拓展为4维变量用于输入
image_4d = tf.expand_dims(image_pre, 0)# 定义SSD模型
# 是否复用,目前我们没有在训练所以为None
reuse = True if 'ssd_net' in locals() else None
# 调出基于VGG神经网络的SSD模型对象,注意这是一个自定义类对象
ssd_net = ssd_vgg_300.SSDNet()
# 得到预测类和预测坐标的Tensor对象,这两个就是神经网络模型的计算流程
with slim.arg_scope(ssd_net.arg_scope(data_format=data_format)):predictions, localisations, _, _ = ssd_net.net(image_4d, is_training=False, reuse=reuse)# 导入官方给出的 SSD 模型参数
ckpt_filename = '../checkpoints/ssd_300_vgg.ckpt'
# ckpt_filename = '../checkpoints/VGG_VOC0712_SSD_300x300_ft_iter_120000.ckpt'
isess.run(tf.global_variables_initializer())
saver = tf.train.Saver()
saver.restore(isess, ckpt_filename)# 在网络模型结构中,提取搜索网格的位置
# 根据模型超参数,得到每个特征层(这里用了6个特征层,分别是4,7,8,9,10,11)的anchors_boxes
ssd_anchors = ssd_net.anchors(net_shape)
"""
每层的anchors_boxes包含4个arrayList,前两个List分别是该特征层下x,y坐标轴对于原图(300x300)大小的映射
第三,四个List为anchor_box的长度和宽度,同样是经过归一化映射的,根据每个特征层box数量的不同,这两个List元素
个数会变化。其中,长宽的值根据超参数anchor_sizes和anchor_ratios制定。
"""# 加载辅助作图函数
def colors_subselect(colors, num_classes=21):dt = len(colors) // num_classessub_colors = []for i in range(num_classes):color = colors[i * dt]if isinstance(color[0], float):sub_colors.append([int(c * 255) for c in color])else:sub_colors.append([c for c in color])return sub_colorsdef bboxes_draw_on_img(img, classes, scores, bboxes, colors, thickness=2):shape = img.shapefor i in range(bboxes.shape[0]):bbox = bboxes[i]color = colors[classes[i]]# Draw bounding box...p1 = (int(bbox[0] * shape[0]), int(bbox[1] * shape[1]))p2 = (int(bbox[2] * shape[0]), int(bbox[3] * shape[1]))cv2.rectangle(img, p1[::-1], p2[::-1], color, thickness)# Draw text...s = '%s/%.3f' % (l_VOC_CLASS[int(classes[i]) - 1], scores[i])p1 = (p1[0] - 5, p1[1])# cv2.putText(img, s, p1[::-1], cv2.FONT_HERSHEY_DUPLEX, 1.5, color, 3)colors_plasma = colors_subselect(mpcm.plasma.colors, num_classes=21)# 主流程函数
def process_image(img, case, select_threshold=0.15, nms_threshold=.1, net_shape=(300, 300)):# select_threshold:box阈值——每个像素的box分类预测数据的得分会与box阈值比较,高于一个box阈值则认为这个box成功框到了一个对象# nms_threshold:重合度阈值——同一对象的两个框的重合度高于该阈值,则运行下面去重函数# 执行SSD模型,得到4维输入变量,分类预测,坐标预测,rbbox_img参数为最大检测范围,本文固定为[0,0,1,1]即全图rimg, rpredictions, rlocalisations, rbbox_img = isess.run([image_4d, predictions,localisations, bbox_img], feed_dict={img_input: img})# ssd_bboxes_select()函数根据每个特征层的分类预测分数,归一化后的映射坐标,# ancohor_box的大小,通过设定一个阈值计算得到每个特征层检测到的对象以及其分类和坐标rclasses, rscores, rbboxes = np_methods.ssd_bboxes_select(rpredictions, rlocalisations, ssd_anchors,select_threshold=select_threshold,img_shape=net_shape,num_classes=21, decode=True)"""这个函数做的事情比较多,这里说的细致一些:首先是输入,输入的数据为每个特征层(一共6个,见上文)的:rpredictions: 分类预测数据,rlocalisations: 坐标预测数据,ssd_anchors: anchors_box数据其中:分类预测数据为当前特征层中每个像素的每个box的分类预测坐标预测数据为当前特征层中每个像素的每个box的坐标预测anchors_box数据为当前特征层中每个像素的每个box的修正数据函数根据坐标预测数据和anchors_box数据,计算得到每个像素的每个box的中心和长宽,这个中心坐标和长宽会根据一个算法进行些许的修正,从而得到一个更加准确的box坐标;修正的算法会在后文中详细解释,如果只是为了理解算法流程也可以不必深究这个,因为这个修正算法属于经验算法,并没有太多逻辑可循。修正完box和中心后,函数会计算每个像素的每个box的分类预测数据的得分,当这个分数高于一个阈值(这里是0.5)则认为这个box成功框到了一个对象,然后将这个box的坐标数据,所属分类和分类得分导出,从而得到:rclasses:所属分类rscores:分类得分rbboxes:坐标最后要注意的是,同一个目标可能会在不同的特征层都被检测到,并且他们的box坐标会有些许不同,这里并没有去掉重复的目标,而是在下文中专门用了一个函数来去重"""# 检测有没有超出检测边缘rbboxes = np_methods.bboxes_clip(rbbox_img, rbboxes)rclasses, rscores, rbboxes = np_methods.bboxes_sort(rclasses, rscores, rbboxes, top_k=400)# 去重,将重复检测到的目标去掉rclasses, rscores, rbboxes = np_methods.bboxes_nms(rclasses, rscores, rbboxes, nms_threshold=nms_threshold)# 将box的坐标重新映射到原图上(上文所有的坐标都进行了归一化,所以要逆操作一次)rbboxes = np_methods.bboxes_resize(rbbox_img, rbboxes)if case == 1:bboxes_draw_on_img(img, rclasses, rscores, rbboxes, colors_plasma, thickness=8)return imgelse:return rclasses, rscores, rbboxes"""
# 只做目标定位,不做预测分析
case = 1
img = cv2.imread("../demo/person.jpg")
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
plt.imshow(process_image(img, case))
plt.show()
"""
# 做目标定位,同时做预测分析
case = 2
path = '../demo/person.jpg'
# 读取图片
img = mpimg.imread(path)
# 执行主流程函数
rclasses, rscores, rbboxes = process_image(img, case)
# visualization.bboxes_draw_on_img(img, rclasses, rscores, rbboxes, visualization.colors_plasma)
# 显示分类结果图
visualization.plt_bboxes(img, rclasses, rscores, rbboxes), rscores, rbboxes

3、SSD目标检测结果

会得到如下图示,如图已经成功的把物体标注出来,每个标记框中前一个数是标签项,后一个是预测的准确率;

# 标签项与其对应的标签内容
dict = {1:'aeroplane',    2:'bicycle', 3:'bird',   4:'boat',       5:'bottle',6:'bus',          7:'car',     8:'cat',    9:'chair',      10:'cow',11:'diningTable', 12:'dog',    13:'horse', 14:'motorbike', 15:'person',16:'pottedPlant', 17:'sheep',  18:'sofa',  19:'train',     20:'TV'}

-------------------------------------------------------------------------------------------------------------------------
-------------------------------------------------------------------------------------------------------------------------

二、SSD用于视频内物体的定位

以上demo文件夹内都只是图片,如果你想在视频中标记物体——首先你需要拍一段视频,建议不要太长不然你要跑很久,然后需要在主目录下建立Video文件夹,在其下建立inputoutput文件夹,如下图所示:

再将拍摄的视频存入input文件夹下,注意视频的名称哦!最后在主目录下建立demo_Video.py文件,存入如下代码,运行demo_Video.py

请注意:安装imageio:pip install imageio==2.4.1

# -*- coding:utf-8 -*-
# -*- author:zzZ_CMing  CSDN address:https://blog.csdn.net/zzZ_CMing
# -*- 2018/07/09; 15:19
# -*- python3.6
import os
import cv2
import math
import random
import tensorflow as tf
import matplotlib.pyplot as plt
import matplotlib.cm as mpcm
import matplotlib.image as mpimg
from notebooks import visualization
from nets import ssd_vgg_300, ssd_common, np_methods
from preprocessing import ssd_vgg_preprocessing
import sys# 当引用模块和运行的脚本不在同一个目录下,需在脚本开头添加如下代码:
sys.path.append('./SSD-Tensorflow/')slim = tf.contrib.slim# TensorFlow session
gpu_options = tf.GPUOptions(allow_growth=True)
config = tf.ConfigProto(log_device_placement=False, gpu_options=gpu_options)
isess = tf.InteractiveSession(config=config)l_VOC_CLASS = ['aeroplane', 'bicycle', 'bird', 'boat', 'bottle','bus', 'car', 'cat', 'chair', 'cow','diningTable', 'dog', 'horse', 'motorbike', 'person','pottedPlant', 'sheep', 'sofa', 'train', 'TV']# 定义数据格式,设置占位符
net_shape = (300, 300)
# 预处理,以Tensorflow backend, 将输入图片大小改成 300x300,作为下一步输入
img_input = tf.placeholder(tf.uint8, shape=(None, None, 3))
# 输入图像的通道排列形式,'NHWC'表示 [batch_size,height,width,channel]
data_format = 'NHWC'# 数据预处理,将img_input输入的图像resize为300大小,labels_pre,bboxes_pre,bbox_img待解析
image_pre, labels_pre, bboxes_pre, bbox_img = ssd_vgg_preprocessing.preprocess_for_eval(img_input, None, None, net_shape, data_format,resize=ssd_vgg_preprocessing.Resize.WARP_RESIZE)
# 拓展为4维变量用于输入
image_4d = tf.expand_dims(image_pre, 0)# 定义SSD模型
# 是否复用,目前我们没有在训练所以为None
reuse = True if 'ssd_net' in locals() else None
# 调出基于VGG神经网络的SSD模型对象,注意这是一个自定义类对象
ssd_net = ssd_vgg_300.SSDNet()
# 得到预测类和预测坐标的Tensor对象,这两个就是神经网络模型的计算流程
with slim.arg_scope(ssd_net.arg_scope(data_format=data_format)):predictions, localisations, _, _ = ssd_net.net(image_4d, is_training=False, reuse=reuse)# 导入官方给出的 SSD 模型参数
ckpt_filename = 'checkpoints/ssd_300_vgg.ckpt'
# ckpt_filename = '../checkpoints/VGG_VOC0712_SSD_300x300_ft_iter_120000.ckpt'
isess.run(tf.global_variables_initializer())
saver = tf.train.Saver()
saver.restore(isess, ckpt_filename)# 在网络模型结构中,提取搜索网格的位置
# 根据模型超参数,得到每个特征层(这里用了6个特征层,分别是4,7,8,9,10,11)的anchors_boxes
ssd_anchors = ssd_net.anchors(net_shape)
"""
每层的anchors_boxes包含4个arrayList,前两个List分别是该特征层下x,y坐标轴对于原图(300x300)大小的映射
第三,四个List为anchor_box的长度和宽度,同样是经过归一化映射的,根据每个特征层box数量的不同,这两个List元素
个数会变化。其中,长宽的值根据超参数anchor_sizes和anchor_ratios制定。
"""# 加载辅助作图函数
def colors_subselect(colors, num_classes=21):dt = len(colors) // num_classessub_colors = []for i in range(num_classes):color = colors[i * dt]if isinstance(color[0], float):sub_colors.append([int(c * 255) for c in color])else:sub_colors.append([c for c in color])return sub_colorsdef bboxes_draw_on_img(img, classes, scores, bboxes, colors, thickness=2):shape = img.shapefor i in range(bboxes.shape[0]):bbox = bboxes[i]color = colors[classes[i]]# Draw bounding box...p1 = (int(bbox[0] * shape[0]), int(bbox[1] * shape[1]))p2 = (int(bbox[2] * shape[0]), int(bbox[3] * shape[1]))cv2.rectangle(img, p1[::-1], p2[::-1], color, thickness)# Draw text...s = '%s/%.3f' % (l_VOC_CLASS[int(classes[i]) - 1], scores[i])p1 = (p1[0] - 5, p1[1])# cv2.putText(img, s, p1[::-1], cv2.FONT_HERSHEY_DUPLEX, 1.5, color, 3)colors_plasma = colors_subselect(mpcm.plasma.colors, num_classes=21)# 主流程函数
def process_image(img, select_threshold=0.4, nms_threshold=.1, net_shape=(300, 300)):# select_threshold:box阈值——每个像素的box分类预测数据的得分会与box阈值比较,高于一个box阈值则认为这个box成功框到了一个对象# nms_threshold:重合度阈值——同一对象的两个框的重合度高于该阈值,则运行下面去重函数# 执行SSD模型,得到4维输入变量,分类预测,坐标预测,rbbox_img参数为最大检测范围,本文固定为[0,0,1,1]即全图rimg, rpredictions, rlocalisations, rbbox_img = isess.run([image_4d, predictions, localisations, bbox_img],feed_dict={img_input: img})# ssd_bboxes_select函数根据每个特征层的分类预测分数,归一化后的映射坐标,# ancohor_box的大小,通过设定一个阈值计算得到每个特征层检测到的对象以及其分类和坐标rclasses, rscores, rbboxes = np_methods.ssd_bboxes_select(rpredictions, rlocalisations, ssd_anchors,select_threshold=select_threshold,img_shape=net_shape,num_classes=21, decode=True)"""这个函数做的事情比较多,这里说的细致一些:首先是输入,输入的数据为每个特征层(一共6个,见上文)的:分类预测数据(rpredictions),坐标预测数据(rlocalisations),anchors_box数据(ssd_anchors)其中:分类预测数据为当前特征层中每个像素的每个box的分类预测坐标预测数据为当前特征层中每个像素的每个box的坐标预测anchors_box数据为当前特征层中每个像素的每个box的修正数据函数根据坐标预测数据和anchors_box数据,计算得到每个像素的每个box的中心和长宽,这个中心坐标和长宽会根据一个算法进行些许的修正,从而得到一个更加准确的box坐标;修正的算法会在后文中详细解释,如果只是为了理解算法流程也可以不必深究这个,因为这个修正算法属于经验算法,并没有太多逻辑可循。修正完box和中心后,函数会计算每个像素的每个box的分类预测数据的得分,当这个分数高于一个阈值(这里是0.5)则认为这个box成功框到了一个对象,然后将这个box的坐标数据,所属分类和分类得分导出,从而得到:rclasses:所属分类rscores:分类得分rbboxes:坐标最后要注意的是,同一个目标可能会在不同的特征层都被检测到,并且他们的box坐标会有些许不同,这里并没有去掉重复的目标,而是在下文中专门用了一个函数来去重"""# 检测有没有超出检测边缘rbboxes = np_methods.bboxes_clip(rbbox_img, rbboxes)rclasses, rscores, rbboxes = np_methods.bboxes_sort(rclasses, rscores, rbboxes, top_k=400)# 去重,将重复检测到的目标去掉rclasses, rscores, rbboxes = np_methods.bboxes_nms(rclasses, rscores, rbboxes, nms_threshold=nms_threshold)# 将box的坐标重新映射到原图上(上文所有的坐标都进行了归一化,所以要逆操作一次)rbboxes = np_methods.bboxes_resize(rbbox_img, rbboxes)bboxes_draw_on_img(img, rclasses, rscores, rbboxes, colors_plasma, thickness=8)return img# 视频物体定位
import imageio        # pip install imageio==2.4.1
imageio.plugins.ffmpeg.download()
from moviepy.editor import VideoFileClipdef get_process_video(input_path, output_path):video = VideoFileClip(input_path)result = video.fl_image(process_image)result.write_videofile(output_path, fps=25)try:os.makedirs("Video/input/")os.makedirs("Video/output/")
except:input_folder = "Video/input/"input_video_name = sorted(os.listdir(input_folder))[-1]input_video_path = input_folder + input_video_nameoutput_video_path = "Video/output/output_" + input_video_nameget_process_video(input_video_path, output_video_path)

经过一段时间的等待,终于跑完程序;

打开Video/input文件夹,查看输出的视频是什么样子的吧!

由于博客里只能上传gif图,虽然原图画质很好,但到了这里怎么变成这样?我能怎么办——我也很绝望
但是依稀可以看到里面的汽车、行人、自行车都被不同的颜色框标注起来了,说明我们是成功的!赶快动手试一试,很好玩的

-------------------------------------------------------------------------------------------------------------------------
-------------------------------------------------------------------------------------------------------------------------

后续:

SSD目标检测(2):如何制作自己的数据集(详细说明附源码)
SSD目标检测(3):使用自己的数据集做预测(详细说明附源码)
这两篇是SSD框架的实际运用——因为SSD框架只有20类物体被标注,也就是说只能用来识别这特定的20种物体,而实际需求会随着环境有很大的改变,所以这两篇就是教大家如何利用SSD框架,制作自己的数据集,并通过自己的数据集标注定位新物体,这个拓展练习有趣且实用,也是模式识别常见的问题研究,大家赶快动手试一试吧。

【SSD目标检测】1:图片、视频内的物体检测与定位相关推荐

  1. 深度学习和目标检测系列教程 13-300:YOLO 物体检测算法

    @Author:Runsen YOLO,是目前速度更快的物体检测算法之一.虽然它不再是最准确的物体检测算法,但当您需要实时检测时,它是一个非常好的选择,而不会损失太多的准确性. YOLO 框架 在本篇 ...

  2. ICCV 2019 | 港大提出视频显著物体检测算法MGA,大幅提升分割精度

    点击我爱计算机视觉标星,更快获取CVML新技术 本文解读了香港大学联合中山大学和深睿医疗人工智能实验室 ICCV2019 论文<Motion Guided Attention for Video ...

  3. DAC 2018目标检测系统挑战赛落幕:中科院清华分获GPU与FPGA冠军(解决小物体检测的问题)

    本文由机器之心发布,作者:机器之心编辑部. 2018 年 6 月 28 日,由电子自动化设计顶级会议 DAC' 2018 主办的「低功耗目标检测系统设计挑战赛」于加州旧金山于落下帷幕.来自中科院计算所 ...

  4. 中科院自动化所博士带你入门CV物体检测算法

    物体检测通常是指在图像中检测出物体出现的位置及对应的类别,它是计算机视觉中的根本问题之一,同时也是最基础的问题,如图像分割.物体追踪.关键点检测等都依赖物体检测. 从应用来看,物体检测已广泛应用于大家 ...

  5. 详解通用物体检测算法:基于锚框与无需锚框

    物体检测通常是指在图像中检测出物体出现的位置及对应的类别,它是计算机视觉中的根本问题之一,同时也是最基础的问题,如图像分割.物体追踪.关键点检测等都依赖物体检测. 从应用来看,物体检测已广泛应用于大家 ...

  6. 物体检测中的评价指标【文末赠书】

    点击上方"3D视觉工坊",选择"星标" 干货第一时间送达 对于一个检测器,我们需要制定一定的规则来评价其好坏,从而选择需要的检测器.对于图像分类任务来讲,由于其 ...

  7. 物体检测的过去、现在和未来

    本报告分为4个部分,物体检测的简介.物体检测的过去.现在以及未来,每个部分都从学术和工业两种角度进行分析介绍. 上图简单描述了物体检测的发展历程时间轴.2012年深度学习热潮兴起,接着2013年有学者 ...

  8. 《深度学习之PyTorch物体检测实战》—读书笔记

    随书代码 物体检测与PyTorch 深度学习 为了赋予计算机以人类的理解能力与逻辑思维,诞生了人工智能(Artificial Intelligence, AI)这一学科.在实现人工智能的众多算法中,机 ...

  9. 清华优博论文丨物体检测中的特征构建与模型优化

    点击上方"小白学视觉",选择加"星标"或"置顶" 重磅干货,第一时间送达 摘 要:本文针对物体检测中的环境变化多样.物体尺度变化不一.搜索空 ...

  10. 深度学习二(Pytorch物体检测实战)

    深度学习二(Pytorch物体检测实战) 文章目录 深度学习二(Pytorch物体检测实战) 1.PyTorch基础 1.1.基本数据结构:Tensor 1.1.1.Tensor数据类型 1.1.2. ...

最新文章

  1. 通过Navicat for MySQL远程连接的时候报错mysql 1130的解决方法
  2. 逻辑运算符''取某值
  3. 二元树中和为某一值的所有路径
  4. C# Dapper 简单实例
  5. java中session对象登录_JavaWeb中Session对象的学习笔记
  6. 面对小点点谷歌广告表示很无奈
  7. fusion按照多个centos,设置静态ip
  8. 设计模式系列--Singleton
  9. 【JSP内置对象】之9大内置对象(JavaWeb必背必掌握)
  10. Android 实现计时器功能,Android计时器的三种实现方式(Chronometer、Timer、handler)...
  11. windows 7 专业版 64位 无法安装.Net 4.7版本解决方案
  12. ADA4939 ADA4930
  13. AfterEffects CS6安装插件教程
  14. vue3使用keep-alive页面切换时报错:TypeError: parentComponent.ctx.deactivate is not a function
  15. 浅谈微信活码架构及其简易实现
  16. hdr(host), hdr_beg(host) , path_beg
  17. Windows消息响应机制之四:PostQuitMessage和GetMessage函数
  18. 运维面试题(每日一题)
  19. [51nod1355]斐波那契的最小公倍数
  20. 青海哈里哈图国家森林公园雪景美若人间仙境

热门文章

  1. 供应链三道防线(读书笔记)2(共4)
  2. php把amr转换成mp3,php代码将amr格式录音转换为mp3
  3. fw325r虚拟服务器连接失败,fw325r重置后不能联网怎么办?
  4. Java项目部署到远程服务器(详细步骤)
  5. sql语句查询存储过程
  6. Md5是什么?MD5怎么校验?Md5校验工具怎么用?
  7. JavaWeb新闻发布系统案例1
  8. Ribbon界面开发
  9. 【MFC】Ribbon界面开发(三)
  10. 实力验证:金蝶EAS 8.2授权注册 (包含Apusic 9999连接数破解)