计算机视觉之目标检测(object detection)《1》

news2025/2/25 21:18:45

        在计算机视觉领域,除了识别图像并分类之外,我们很多时候想关注图像里面一些感兴趣的目标,比如视频监控中寻找一个或多个嫌疑犯;无人驾驶需要识别车辆、行人、红绿灯、路障等等,都是需要去及时掌握画面中的不同目标。我们将这类任务叫做目标检测(object detection)或物体检测。

本人在网上随便下载一张“狗与猫”的图片,将狗和猫当作是目标,然后对狗和猫进行标注。我们通常使用边界框(bounding box)来描述目标的位置,一般是一个矩形框。

画边界框(bounding box)

import d2lzh as d2l
from mxnet import contrib,gluon,image,nd
import numpy as np

d2l.set_figsize(figsize=(5, 5))
img=image.imread('dogcat.png').asnumpy()#高、宽、通道数(596, 605, 3)
dog_bbox,cat_bbox=[20,5,330,570],[333,200,590,590]#[Xmin,Ymin,Xmax,Ymax],分别是左上角与右下角的坐标

#画矩形框的辅助函数
#d2l包中已有
def bbox_to_rect(bbox,color):
    return d2l.plt.Rectangle(xy=(bbox[0],bbox[1]),width=bbox[2]-bbox[0],height=bbox[3]-bbox[1],fill=False,edgecolor=color,linewidth=1)

fig=d2l.plt.imshow(img)

fig.axes.add_patch(bbox_to_rect(dog_bbox,'blue'))
fig.axes.add_patch(bbox_to_rect(cat_bbox,'red'))

d2l.plt.show()

 

对于上面画目标的矩形框,有两个方法需要熟悉下,如下:

d2l.plt.Rectangle的用法

d2l.plt.Rectangle(xy=(400,30),width=100,height=150,fill=True,edgecolor='green',linewidth=2)

这个函数的作用是画矩形框,通过坐标与宽高。
xy=(400,30):左上角的坐标,有了左上角坐标,然后就可以开始画了,横向往右画宽度,纵向向下画高度
fill=True或False:表示是否填充
edgecolor='green':边框的颜色
linewidth=2:画笔的大小

fig.axes.add_patch的用法

将上面画好的矩形框,添加到画布上面,从字面意思来看,就相当于是在画布中加一块补丁

fig.axes.add_patch(d2l.plt.Rectangle(xy=(20,50),width=100,height=150,fill=True,edgecolor='green',linewidth=2))

我们看下效果图,猫上面一块补丁哈哈:

目标检测算法通常会在输入图像中采样大量的区域,然后判断这些区域中是否包含我们感兴趣的目标,并调整区域边缘从而更准确地预测目标的真实边界框(ground-truth bounding box)。不同模型使用的区域采样方法可能不同,这里介绍一种方法:以每个像素为中心生成多个大小和宽高比(aspect ration)不同的边界框,这些边界框我们叫做锚框(anchor box)

画锚框(anchor box)

import d2lzh as d2l
from mxnet import contrib, gluon, image, nd
import numpy as np

d2l.set_figsize(figsize=(8, 8))
img = image.imread('dogcat.png').asnumpy()  # 高、宽、通道数(596, 605, 3)
h, w = img.shape[0:2]
X = nd.random.uniform(shape=(1, 3, h, w))
# 生成锚框的方法
Y = contrib.nd.MultiBoxPrior(X, sizes=[0.75, 0.5, 0.25], ratios=[1, 1.2, 0.65])
# (批量大小,锚框个数,4)
print(596*605*5, Y.shape)  # 1802900 (1, 1802900, 4)

boxes = Y.reshape((h, w, 5, 4))
print(boxes.shape)  # (596, 605, 5, 4)

# 画出某个像素为中心的所有锚框
# d2lzh包中已有
def show_bboxes(axes, bboxes, labels=None, colors=None):
    def _make_list(obj, default_values=None):
        if obj is None:
            obj = default_values
        elif not isinstance(obj, (list, tuple)):
            obj = [obj]
        return obj
    labels = _make_list(labels)
    colors = _make_list(colors, ['b', 'g', 'r', 'm', 'w'])
    for i, bbox in enumerate(bboxes):
        color = colors[i % len(colors)]
        rect = d2l.bbox_to_rect(bbox.asnumpy(), color)
        axes.add_patch(rect)
        if labels and len(labels) > i:
            text_color = 'r' if color == 'w' else 'w'
            axes.text(rect.xy[0], rect.xy[1], labels[i], va='center', ha='center',
                      fontsize=9, color=text_color, bbox=dict(facecolor=color, lw=0))


bbox_scale = nd.array((w, h, w, h))  # 用来还原坐标值
fig = d2l.plt.imshow(img)
show_bboxes(fig.axes, boxes[300, 250, :, :]*bbox_scale, ['s=0.75,r=1','s=0.5,r=1', 's=0.25,r=1', 's=0.75,r=1.2', 's=0.75,r=0.65'])
d2l.plt.show()

其中的每个像素为中心产生的锚框数为5,这个5是怎么来的呢?

boxes=Y.reshape((h,w,5,4))

如果是按照每个像素都画锚框的话,那就会产生h*w*sizes*ratios个锚框,那计算复杂度容易过高。我们通常只需要包含sizes第一个元素或ratios第一个元素之间的组合即可
sizes=[0.75,0.5,0.25],ratios=[1,1.2,0.65] 会有六种组合:[0.75,1],[0.75,1.2],[0.75,0.65]以及[0.75,1],[0.5,1],[0.25,1],其中[0.75,1]重复了,所以就是5,也就是生成的锚框数公式为:sizes+ratios-1(这里的sizes和ratios指的是元素个数)

标注训练集的锚框

import d2lzh as d2l
from mxnet import contrib, gluon, image, nd
import numpy as np

d2l.set_figsize(figsize=(8, 8))
img = image.imread('dogcat.png').asnumpy()  # 高、宽、通道数(596, 605, 3)
h, w = img.shape[0:2]
X = nd.random.uniform(shape=(1, 3, h, w))
# 生成锚框的方法
Y = contrib.nd.MultiBoxPrior(X, sizes=[0.75, 0.5, 0.25], ratios=[1, 1.2, 0.65])
boxes = Y.reshape((h, w, 5, 4))


# 画出某个像素为中心的所有锚框
# d2lzh包中已有
def show_bboxes(axes, bboxes, labels=None, colors=None):
    def _make_list(obj, default_values=None):
        if obj is None:
            obj = default_values
        elif not isinstance(obj, (list, tuple)):
            obj = [obj]
        return obj
    labels = _make_list(labels)
    colors = _make_list(colors, ['b', 'g', 'r', 'm', 'w'])
    for i, bbox in enumerate(bboxes):
        color = colors[i % len(colors)]
        rect = d2l.bbox_to_rect(bbox.asnumpy(), color)
        axes.add_patch(rect)
        if labels and len(labels) > i:
            text_color = 'r' if color == 'w' else 'w'
            axes.text(rect.xy[0], rect.xy[1], labels[i], va='center', ha='center',
                      fontsize=9, color=text_color, bbox=dict(facecolor=color, lw=0))

ground_truth = nd.array([[0, 0.05, 0.02, 0.55, 0.95], [1, 0.56, 0.37, 0.97, 0.97]])
anchors = nd.array([[0, 0.1, 0.2, 0.3], [0.15, 0.2, 0.4, 0.4],
                    [0.63, 0.05, 0.88, 0.98], [0.66, 0.45, 0.8, 0.8], [0.57, 0.3, 0.92, 0.9]])
bbox_scale = nd.array((w, h, w, h))  # 用来还原坐标值
fig = d2l.plt.imshow(img)
#真实边界框
show_bboxes(fig.axes, ground_truth[:,1:]*bbox_scale, ['dog','cat'],'k')

#MultiBoxTarget函数为锚框标注类别和偏移量,形状(批量大小,包括背景的类别数,锚框数)
labels=contrib.nd.MultiBoxTarget(anchors.expand_dims(axis=0),ground_truth.expand_dims(axis=0),nd.zeros((1,3,5)))
print(labels[2][0][0],len(labels[2][0]))

tnames=[]
for i in labels[2][0]:
    if i==0:
        tnames.append('background')
    elif i==1:
        tnames.append('dog')
    else:
        tnames.append('cat')
print(tnames)#['background', 'dog', 'background', 'background', 'cat']
#锚框
show_bboxes(fig.axes,anchors*bbox_scale,tnames)
d2l.plt.show()

 其中MultiBoxTarget函数是为锚框标注类别和偏移量的,形状(批量大小,包括背景的类别数,锚框数)

labels=contrib.nd.MultiBoxTarget(anchors.expand_dims(axis=0),ground_truth.expand_dims(axis=0),nd.zeros((1,3,5)))
print(labels)
'''
[
[[0.0000000e+00 0.0000000e+00 0.0000000e+00 0.0000000e+00 1.0000002e+00
  9.2499981e+00 3.4657359e+00 7.6843362e+00 0.0000000e+00 0.0000000e+00
  0.0000000e+00 0.0000000e+00 0.0000000e+00 0.0000000e+00 0.0000000e+00
  0.0000000e+00 5.7142794e-01 1.1666666e+00 7.9111999e-01 5.9604639e-07]]
<NDArray 1x20 @cpu(0)>,
[[0. 0. 0. 0. 1. 1. 1. 1. 0. 0. 0. 0. 0. 0. 0. 0. 1. 1. 1. 1.]]
<NDArray 1x20 @cpu(0)>,
[[0. 1. 0. 0. 2.]]
<NDArray 1x5 @cpu(0)>]
'''

labels[0]:锚框的4个偏移量,其中负类锚框的偏移量为0
labels[1]:掩码变量,形状(批量大小,锚框个数*4),掩码变量中的元素跟每个锚框的4个偏移量一一对应。由于我们不关心对背景的检测,有关负类的偏移量不应影响目标函数。通过按元素乘法,掩码变量中的0可以在计算目标函数之前过滤掉负类的偏移量。
labels[2]:锚框标注的类别,0为背景,并令从0开始的目标类别的整数索引自加1(1狗2猫)

其中expand_dims表示增加一维,位置取决于axis指定的维度
print(anchors.expand_dims(axis=0).shape)#就从(5,4)变成了(1,5,4)

预测边界框(非极大值抑制)

上面的介绍,我们知道在模型预测阶段,将先为图像生成多个锚框,并为这些锚框一一预测类别和偏移量,当锚框数量较多时,同一目标可能会输出较多相似的预测边界框,为了使结果更简洁,我们可以移除相似的预测边界框,常用的方法就是非极大值抑制(non-maximum suppression,NMS)
为了简单起见,我们假设预测偏移量全是0,预测边界框即锚框,最后,构造每个类别的预测概率:

import d2lzh as d2l
from mxnet import contrib, gluon, image, nd
import numpy as np

d2l.set_figsize(figsize=(8, 8))
img = image.imread('dogcat.png').asnumpy()  # 高、宽、通道数(596, 605, 3)
h, w = img.shape[0:2]
anchors = nd.array([[0.05, 0.02, 0.55, 0.95], [0.06, 0.1, 0.56, 0.95], [0.15, 0.22, 0.64, 0.95], [0.56, 0.37, 0.97, 0.97]])#四个锚框
offset_preds = nd.array([0]*anchors.size)# 偏移量
cls_prods = nd.array([[0]*4, [0.94, 0.8, 0.75, 0.04],[0.06, 0.2, 0.25, 0.96]])  # 分别是背景、狗、猫的预测概率
bbox_scale = nd.array((w, h, w, h))  # 用来还原坐标值
fig = d2l.plt.imshow(img)
d2l.show_bboxes(fig.axes, anchors*bbox_scale,['dog=0.94', 'dog=0.8', 'dog=0.75', 'cat=0.96'])
d2l.plt.show()

图中标注了每个框的预测概率,然后我们使用MultiBoxDetection函数来执行非极大值抑制并设置阈值为0.5,这样就会让结果显得更加简洁。代码如下:

output=contrib.nd.MultiBoxDetection(cls_prods.expand_dims(axis=0),offset_preds.expand_dims(axis=0),anchors.expand_dims(axis=0),nms_threshold=0.5)
print(output)
[[[ 1.          0.96        0.55999994  0.37        0.97        0.97      ]
  [ 0.          0.94        0.05000001  0.01999998  0.55        0.95      ]
  [-1.          0.8         0.06        0.09999999  0.56        0.9499999 ]
  [-1.          0.75        0.14999999  0.21999997  0.64        0.95      ]]]
<NDArray 1x4x6 @cpu(0)>

我们可以看到[返回结果的形状是(批量大小,锚框的数量,6)]。 最内层维度中的六个元素提供了同一预测边界框的输出信息。 第一个元素是预测的类索引,从0开始(0代表狗,1代表猫),值-1表示背景或在非极大值抑制中被移除了。 第二个元素是预测的边界框的置信度。 其余四个元素分别是预测边界框左上角和右下角的 (x,y)(x,y) 轴坐标(范围介于0和1之间)。
最后将背景为-1的移除掉:

for i in output[0].asnumpy():
    if i[0]==-1:
        continue
    label=('dog=','cat=')[int(i[0])]+str(i[1])
    d2l.show_bboxes(fig.axes,[nd.array(i[2:])*bbox_scale],label)

实践中,在执行非极大值抑制前,我们甚至可以将置信度较低的预测边界框移除,从而减少此算法中的计算量。 我们也可以对非极大值抑制的输出结果进行后处理。例如,只保留置信度更高的结果作为最终输出。


错误出现:
如果那个MultiBoxDetection函数里面不增加一维的话,将会报错:
 Check failed: cshape.ndim() == 3U (2 vs. 3) : Provided: [3,4]
维度不匹配了,所以需要对类别预测、偏移量、锚框都做一个维度扩展:expand_dims(axis=0)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/39568.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

古瑞瓦特能源通过聆讯:上半年营收23亿 IDG投资9亿持股6.5%

雷递网 雷建平 11月26日古瑞瓦特能源&#xff08;简称&#xff1a;“Growatt Technology”&#xff09;日前递交招股书&#xff0c;准备在香港上市。上半年营收23.45亿古瑞瓦特能源于2011年在深圳成立&#xff0c;是一家分布式能源解决方案提供商&#xff0c;专注于可持续能源发…

Crack:GoJS 2.2.18 -2022-09-08 update

使用 JavaScript 和 TypeScript 为 Web 构建图表 流程图 构建交互式流程图或流程图。让您的用户使用 JSON 模型输出构建、修改和保存图表。状态图 可视化状态图和其他行为图。创建具有实时更新的图表以监控状态&#xff0c;或创建交互式图表以进行规划。桑基图 GoJS 允许对链接…

史上最全MATLAB误差分析工具箱,不看别后悔 【矢量化代码、效率嘎嘎快、支持计算50种指标】

在拟合、插值、模拟预测等计算中&#xff0c;往往需要通过不同指标参数来分析实际值与计算值之间差异依次衡量相关方法的可行性。常用的表征指标有残差平方和(SSE)、均方差(MSE)、均方根差(RMSE)、平均绝对误差(MAE)和决定系数R方(R-Squared)等等。 考虑到误差分析在实际应用中…

Kafka部署安装及简单使用

一、环境准备 1、jdk 8 2、zookeeper 3、kafka 说明&#xff1a;在kafka较新版本中已经集成了zookeeper&#xff0c;所以不用单独安装zookeeper&#xff0c;只需要在kafka文件目录中启动zookeeper即可 二、下载地址 Apache Kafka 三、部署 1、启动zookeeper -- 启动 .…

CSDN第11次竞赛题解与总结

CSDN第11次竞赛题解与总结前言建议题解T1圆小艺扩展完整代码T2K皇把妹完整代码T3筛选宝物完整代码T4圆桌完整代码总结前言 2022/11/27 CSDN第11次竞赛 由「壹合原码 & CSDN」联合主办 本次奖励还是不错的 (毕竟有赞助商)&#xff0c;前三十名都有奖励&#xff0c;连以前第…

跑步10年回望

回顾跑步这10年有点遗憾&#xff0c;最终还是决定放弃参加2022年厦马&#xff0c;因为要求更早到厦门&#xff0c;也担心回福州后影响小朋友上课&#xff0c;权衡之下还是决定申请退赛。本想在这次活动上实现全马破4的目标&#xff0c;却只能晒个退赛截图。。。今年是厦马20年&…

【敲级实用】:某小伙写了一个的办公脚本后~变精神了~

文章目录&#x1f4ef;小哔哔✏️注册有道智云✏️咋滴调用&#xff1f;✏️使用前的小操作✏️源代码专栏Python零基础入门篇&#x1f525;Python网络蜘蛛&#x1f525;Python数据分析Django基础入门宝典&#x1f525;小玩意儿&#x1f525;Web前端学习tkinter学习笔记Excel自…

基于储能电站服务的冷热电多微网系统双层优化配置(Matlab代码实现)

&#x1f468;‍&#x1f393;个人主页&#xff1a;研学社的博客 &#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜…

ETCD快速入门-01 ETCD概述

1.ETCD概述 1.1 ETCD概述 etcd是一个高可用的分布式的键值对存储系统&#xff0c;常用做配置共享和服务发现。由CoreOS公司发起的一个开源项目&#xff0c;受到ZooKeeper与doozer启发而催生的项目&#xff0c;名称etcd源自两个想法&#xff0c;即Linux的/etc文件夹和d分布式系…

一篇快速搞懂python模块、包和库

个人主页&#xff1a;天寒雨落的博客_CSDN博客-初学者入门C语言,python,数据库领域博主 &#x1f4ac; 热门专栏&#xff1a;python_天寒雨落的博客-CSDN博客 ​每日赠语&#xff1a;没有窘迫的失败&#xff0c;就不会有自豪的成功&#xff1b;失败不可怕&#xff0c;只要能从失…

用DIV+CSS技术设计的凤阳旅游网站(web前端网页制作课作业)HTML+CSS+JavaScript

&#x1f468;‍&#x1f393;学生HTML静态网页基础水平制作&#x1f469;‍&#x1f393;&#xff0c;页面排版干净简洁。使用HTMLCSS页面布局设计,web大学生网页设计作业源码&#xff0c;这是一个不错的旅游网页制作&#xff0c;画面精明&#xff0c;排版整洁&#xff0c;内容…

Android App开发语音处理之系统自带的语音引擎、文字转语音、语音识别的讲解及实战(超详细 附源码)

需要源码请点赞关注收藏后评论区留下QQ~~~ 一、系统自带的语音引擎 语音播报的本质是将书面文字转换成自然语言的音频流&#xff0c;这个转换操作被称作语音合成&#xff0c;又称TTS&#xff08;从文本到语音&#xff09;在转换过程中&#xff0c;为了避免机械合成的呆板和停顿…

一款客服系统有哪些必备的功能模块?

为了提升客户服务质量&#xff0c;和客户更好地进行沟通&#xff0c;越来越多的企业配置了客服系统。那一款优秀的客服系统需要配置哪些功能模块呢&#xff1f; 1、支持多渠道接入 新媒体的快速发展使得企业有机会通过更多的渠道和客户进行联系&#xff0c;比如公众号、微博、…

java环境安装与配置

这篇文章只是为了以后我配置环境方便而写 1&#xff0c;点击网址&#xff0c;进入Oracle官网 然后参照Java JDK下载安装及环境配置超详细图文教程 2&#xff0c;安装之后如果目录里没有jre文件夹 参考Jdk中没有jre文件夹怎么办&#xff1f; ①简单点就是&#xff0c;管理员模式…

京东零售大数据云原生平台化实践

分享嘉宾&#xff1a;吴维伟 京东 架构工程师 编辑整理&#xff1a;陈妃君 深圳大学 出品社区&#xff1a;DataFun 导读&#xff1a;随着业务调整和集群资源整合需求&#xff0c;大数据系统中集群数据迁移复杂混乱。本文将以京东大数据平台为例&#xff0c;介绍京东近一年在数…

HTML+CSS+JS制作一个迅雷看看电影网页设计实例 ,排版整洁,内容丰富,主题鲜明,简单的网页制作期末作业

HTML实例网页代码, 本实例适合于初学HTML的同学。该实例里面有设置了css的样式设置&#xff0c;有div的样式格局&#xff0c;这个实例比较全面&#xff0c;有助于同学的学习,本文将介绍如何通过从头开始设计个人网站并将其转换为代码的过程来实践设计。 文章目录一、网页介绍一…

FreeCAD二次开发-基于PyQT对话框与FC交互的开发

版本 FreeCAD0.18.2+PyCharm Community 2020.3.3 演示效果 环境搭建步骤 1.先安装好FreeCAD和PyCharm 2.添加环境变量 点击确定,全部关掉。 3.测试变量是否生效(CMD打开控制台,输入python回车) 弹出如下,说明可以进入FreeCAD自带的python解释器 4.创建工作台Workbench(…

Bridge Champ:Jelurida实践PlaytoOwn的Web 3社交游戏

Play-to-Own 为什么能引领Web3游戏 Web 3游戏将进入“Play-to-Own”的游戏新时代。解锁游戏中的经济活动将极大地扩大游戏产业的TAM&#xff0c;并加速价值创造。 以Axie Infinity为例&#xff0c;Axie普及了P2E模式&#xff0c;其DAU从2021年初的1万增长到峰值的300万&#…

基于遗传算法的微电网经济运行优化matlab程序

基于遗传算法的微电网经济运行优化matlab程序 摘 要: 微电网作为智能电网的一部分&#xff0c;是分布式电源接入电网的一种有效手段&#xff0c;微电网经济运行是其中一个重要研究方面。考察微电网经济性&#xff0c;通常是从最小运行成本和最小环境污染物排放成本两方面入手进…

Git clone时报错: OpenSSL SSL_read: Connection was reset, errno 10054

有段时间没有在GitHub上clone代码了&#xff0c;今天git clone&#xff1a; https://github.com/xxxxxx 居然直接给我抛出了错误&#xff1a; GitHub clone时,报错:Connection was reset, errno 10054 咦&#xff1f;这是什么鬼&#xff1f;然后想起以前clone时用的git地址…