OpenCV4学习笔记(61)——dnn模块之调用googlenet模型实现动物图像分类_java opencv4.7.0 训练动物-程序员宅基地

技术标签: c++  dnn  学习笔记  opencv  

今天开始主要整理OpenCV中dnn模块的使用,包括各种神经网络模型的加载、调用,输入输出数据的组织等等内容。而今天要记录的是OpenCV中一个自带神经网络模型——googlenet模型的使用,这个模型是由caffe框架训练出来、主要针对多种野生动物的识别。下面开始通过代码逐步整理在OpenCV中对该模型进行调用,并对图像进行识别分类的流程。

首先我们需要加载googlenet模型的模型文件(.caffemodel)、配置文件(.prototxt),使用readNet()这个API来实现模型的加载。注意的是,在OpenCV中既可以通过readNet()对所有支持的神经网络模型进行加载,也可以使用针对某一种网络框架训练出的模型进行加载,都有相应的API可以调用,这些后续再整理。在这里我们使用readNet(),其参数含义如下:
(1)参数model:加载已训练模型的路径,不同模型对应不同后缀:
*.caffemodel ——Caffe
*.pb——TensorFlow
*.t7 or *.net——Torch
*.weights——Darknet
*.bin——DLDT
(2)参数config:已训练模型的描述文件:
*.prototxt ——Caffe
*.pbtxt ——TensorFlow
Torch中没有config文件
*.cfg ——Darknet
*.xml ——DLDT
(3)参数framework:声明加载的模型是由哪个框架训练出来的,也可以不加,函数会根据读取模型的格式来自己判断。
代码演示如下:

	string caffe_model_path = "D:\\opencv_c++\\opencv_tutorial\\data\\models\\googlenet(animal)\\bvlc_googlenet.caffemodel";
	string caffe_config = "D:\\opencv_c++\\opencv_tutorial\\data\\models\\googlenet(animal)\\bvlc_googlenet.prototxt";
	string labels = "D:\\opencv_c++\\opencv_tutorial\\data\\models\\googlenet(animal)\\classification_classes_ILSVRC2012.txt";
	Net caffe_net = readNet(caffe_model_path, caffe_config);

然后我们获取这个模型的相关信息,例如每一层神经层的类型、名称等等,当然这一步实际上可以忽略,这里只是作为演示。代码演示如下:

	vector<string> caffe_layer_name = caffe_net.getLayerNames();		//获取模型每层的名称
	for (int i = 0; i < caffe_layer_name.size(); i++)
	{
    
		int caffe_layer_id = caffe_net.getLayerId(caffe_layer_name[i]);		//根据每层的名称来获取每层的id
		Ptr<dnn::Layer> caffe_layer = caffe_net.getLayer(caffe_layer_id);			//根据id去索引到每一层
		//获取每一层的类型、名称
		string layer_type = caffe_layer->type;
		string layer_name = caffe_layer->name;
		cout << caffe_layer_id << "     layer_type:  " << layer_type << "; layer_name: " << layer_name << endl;
	}

然后我们需要读取该模型的标签集,并进行一定处理,以便后续分类ID的索引。

	//读取分类标签集
	ifstream fp(labels);
	vector<string>class_labels;
	if (!fp.is_open())
	{
    
		cout << "labels file can't open" << endl;
		exit(-1);
	}
	while (!fp.eof())				//如果指针不位于文件末尾,就继续读取文件
	{
    
		string class_name;
		getline(fp, class_name);			//读取文件中的每一行数据
		if (0 != class_name.length())				//如果不是空行,就将这一行的数据保存起来
		{
    
			class_labels.push_back(class_name);
		}
	}
	fp.close();

接下来我们读取图像

	Mat test_image = imread("D:\\opencv_c++\\opencv_tutorial\\data\\images\\tem.jpg");
	resize(test_image, test_image, Size(700, 700));
	imshow("test_image", test_image);
	Mat inputBlob = blobFromImage(test_image, 1.0, Size(224, 224), Scalar(104, 117, 123), true, false, 5);

注意无法直接将图像作为神经网络的输入,我们需要将图像转换为4维的blob才能作为输入。通过blobFromImage()进行转换,其参数含义如下:

(1)image:输入图像(具有1、3或4通道)
(2)size:输出图像的空间大小
(3)mean:从通道中减去平均值的标量,如果参数image具有BGR顺序且参数swapRB为true ,则值应按(平均值R,平均值G,平均值B)顺序排列。该值由模型训练时所确定,需要通过查询模型资料得知。
(4)scalefactor:对参数image的缩放比例
(5)swapRB: 表示是否交换3通道图像中的第一个和最后一个通道的标志
(6)crop:表示是否在调整大小后裁剪图像
(7)ddepth:输出blob的深度,选择CV_32F或CV_8U。

经过处理后将blob输入给神经网络,再进行前向传播得到预测结果,也就是分类结果。

	caffe_net.setPreferableBackend(DNN_BACKEND_INFERENCE_ENGINE);
	caffe_net.setPreferableTarget(DNN_TARGET_CPU);
	caffe_net.setInput(inputBlob);
	Mat prob = caffe_net.forward();

这里的前两句代码是设置神经网络运算的计算后台和目标设备,DNN_BACKEND_INFERENCE_ENGINE需要搭配openVINO使用,如果没有的话就设置DNN_BACKEND_OPENCV,否则会报错。

前向传播得到的结果是一个1行、1000列、单通道的矩阵,其中每一列的值就是每一个分类的置信度,由于总共是1000个分类,所以有1000列。我们需要找到其中置信度最大的像素坐标,那么该坐标的x值对应的就是在标签集中分类的ID,通过这个ID去索引到预测的分类。代码演示如下:

	prob = prob.reshape(1, 1);
	double maxval;
	Point maxloc;
	minMaxLoc(prob, NULL, &maxval, NULL, &maxloc);
	int classID = maxloc.x;
	string className = class_labels[classID];
	putText(test_image, className, Point(20, 20),FONT_HERSHEY_SIMPLEX,1, Scalar(0, 255, 0), 2);
	cout << "运行时间:  " << run_time << endl;
	imshow("test_image", test_image);

下面是运行效果:
该模型每一层的类型和名称
在这里插入图片描述
在这里插入图片描述
识别效果
在这里插入图片描述
在这里插入图片描述

总的来说,我们需要学习了解的是在OpenCV中如何去调用这些预训练好的模型,主要是输入输出数据的组织和转换,今天使用的googlenet模型的数据组织其实是比较简单的,其识别效果也不做评价了,因为在它标签集分类中可以看出大部分都是野生动物。。。

今天的笔记就到这吧~

PS:本人的注释比较杂,既有自己的心得体会也有网上查阅资料时摘抄下的知识内容,所以如有雷同,纯属我向前辈学习的致敬,如果有前辈觉得我的笔记内容侵犯了您的知识产权,请和我联系,我会将涉及到的博文内容删除,谢谢!

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/weixin_45224869/article/details/105976683

智能推荐

FTP上传下载工具类_vsftp下载工具类-程序员宅基地

文章浏览阅读419次。记录一篇将图片等静态资源上传至vsftpd服务器的工具类package com.zhouym.baiwei.utils;import java.io.File;import java.io.FileInputStream;import java.io.FileNotFoundException;import java.io.FileOutputStream;import java.i..._vsftp下载工具类

php 得到ashx,ASP.NET-C# Post 一般处理程序(ashx)并得到返回值-程序员宅基地

文章浏览阅读166次。var postUrl = "http://xxx.com/xxp/LoginInfo.ashx";var postString = "method=CheckPW&id=4454556289&pwd=&checkword=8888&sign=";HttpWebRequest httpRequset = null;HttpWebResponse httpRespon..._ashx处理实现响应post请求示例代码

Vim使用之高亮关键字方法-程序员宅基地

文章浏览阅读3.4k次。请注意,以上命令只会影响当前打开的 Vim 编辑器窗口。如果您想要永久更改 Vim 的配置,可以将命令添加到。是您想要使用的颜色主题的名称。例如,要使用 “morning” 主题,可以输入命令。查看当前可用的颜色主题:在 Vim 中,输入命令。,然后按下 Tab 键即可查看当前可用的颜色主题。更改当前的颜色主题:在 Vim 中,输入命令。开启语法高亮:在 Vim 中,输入命令。关闭语法高亮:在 Vim 中,输入命令。

lufylegend.js的简单使用-程序员宅基地

文章浏览阅读826次。js 引入<script type="text/javascript" src="js/lufylegend/lufylegend-1.10.1.min.js"></script>html<div id="legend"></div><img src="" alt="" class="photo_img">..._lufylegend.js

MongoDB入门级保姆教程_mongodb保姆间教程-程序员宅基地

文章浏览阅读687次,点赞3次,收藏4次。MongoDB是文档数据库,旨在简化开发和扩展,本文主要介绍关键概念和基础语句并提供操作和管理上的注意事项。_mongodb保姆间教程

输入若干个正整数,判断每个数从高位到低位各位数字是否按值从小到大排列_输入一批正整数(以零或负数为结束标志),判断每个数从高位到低位的各位数字是否按-程序员宅基地

文章浏览阅读1.1w次,点赞7次,收藏16次。4-2输入若干个正整数,判断每个数从高位到低位各位数字是否按值从小到大排列,请根据题意,将程序补充完整。#include <stdio.h>int fun1(int m);int main(void){ int n; scanf("%d", &n); while (n > 0) { if(fun1(..._输入一批正整数(以零或负数为结束标志),判断每个数从高位到低位的各位数字是否按

随便推点

深度学习和机器学习的区别_机器学习与深度学习的感想-程序员宅基地

文章浏览阅读4.6w次,点赞267次,收藏741次。最近在听深度学习的课,老师提了一个基本的问题:为什么会出现深度学习?或者说传统的机器学习有什么问题。老师讲解的时候一带而过,什么维度灾难啊之类的,可能觉得这个问题太浅显了吧(|| Д)````不过我发现自己确实还不太明白,于是Google了一下,发现一篇很棒的科普文,这里翻译一下,分享给大家:翻译自文章:https://www.analyticsvidhya.com/blog/2017/04/co..._机器学习与深度学习的感想

BCGControlBar教程:使用矢量图形_mfc toolbar 有svg-程序员宅基地

文章浏览阅读421次。BCGControlBar Pro for MFC最新试用版下载请猛戳&gt;&gt;&gt;BCGControlBar库提供了一种在工具栏/菜单/功能区和其他控件中使用可缩放矢量图形(SVG)的非常简单有效的方法。为什么需要使用矢量图形而不是光栅?高DPI支持是当今非常重要的应用程序功能之一:由于越来越多的客户使用高分辨率显示器,该程序应该具有DPI感知能力。许多年前,我们已经实现了..._mfc toolbar 有svg

浙大 | PTA 习题7-7 字符串替换 (15分)_例题3-7 统计英文字母和数字字符[2] 分数 15 作者 颜晖 单位 浙大城市学院 本题要-程序员宅基地

文章浏览阅读2.3k次。本题要求编写程序,将给定字符串中的大写英文字母按以下对应规则替换:原字母 对应字母 A Z B Y C X D W … … X C Y B Z A输入格式:输入在一行中给出一个不超过80个字符、并以回车结束的字符串。输出格式:输出在一行中给出替换完成后的字符串。输入样例:Only the 11 CAPItaL LeTtERS are replaced.输出样例:..._例题3-7 统计英文字母和数字字符[2] 分数 15 作者 颜晖 单位 浙大城市学院 本题要

Bioinformatics | 预测药物-药物相互作用的多模态深度学习框架_ddimdl-程序员宅基地

文章浏览阅读4.1k次,点赞4次,收藏38次。作者 | 朱玉磊审稿 | 李芬今天给大家介绍来自华中农业大学信息学院章文教授课题组在Bioinformatics上发表的一篇关于预测药物与药物相互作用事件的文章。作者提出了一个多模态深度..._ddimdl

制作一个有趣的QQ机器人_qrspeed官网-程序员宅基地

文章浏览阅读7.7k次,点赞19次,收藏72次。如何制作一个有趣的QQ机器人制作一个好玩的QQ机器人(只能手机进行操作哦)题记:这个机器人用来整蛊兄弟或者是在朋友面前装逼都是不错的选择QQ机器人简介机器人效果图机器人制作方法机器人必下软件如何制作机器人词库的编写编写词库的软件词库的编写规则给大家找了一个QR下载的官网(不想加群的兄弟姐妹看这个)结尾题记:这个机器人用来整蛊兄弟或者是在朋友面前装逼都是不错的选择)QQ机器人简介QQ机器人,根据字面意思,就是利用特定的代码,使一个QQ账号成功具备自我反应并作出应答,而这也是我今天想要教你们做的一款最_qrspeed官网

「离散数学」是一门什么样的学科_离散数学学什么-程序员宅基地

文章浏览阅读2.4k次,点赞6次,收藏13次。写这篇文章的动机是想探讨从离散数学开始入门数理逻辑的路径以及离散数学与数理逻辑之间的关系。以学习数理逻辑为目的学习离散数学,而一般的以学习计算机为目的的学习还是有相当的不同,最大的不同就是:以数理逻辑为目的的学习,应当以「证明」 — — 形式证明为目的,这其中包括了关于形式证明的理论 — — 一阶理论的句法和语义,以及关于形式证明的实践 — — 证明框架和策略。学习的中心内容有两个:「语言」 — — 「 一阶语言」;「结构」 — — 数学中关于「结构」的思想、概念、种类、实例以及「结构」和「语言」的关系。_离散数学学什么

推荐文章

热门文章

相关标签