基于OpenCV的垃圾分类项目的C++代码详解——学习笔记(二)

基于OpenCV C++垃圾分类项目的代码详解(工训总结)——对传入图像进行DNN网络分类

Begin

今天给大家介绍一个现成的人工神经网络——基于caffe框架的DNN(深度神经网络),这也是官方给出的例子。下面来分析一下此网络优缺点。功能、代码、细节问题、结果

一、优缺点

优点: 优点很明显,现成的,不用过多的改进网络的结构,也不需要知道网络底层是如何实现的,网络的各方面细节也不需要知道,直接拿来把接口改成自己需要的返回参数即可,适合于没学过人工神经网络和刚入门的小伙伴(也适合我)。

缺点: 缺点也很明显,因为是现成的,所以对具体问题的解决方案表现出不稳定性,往往和期望有所偏差,由于不知道网络具体的实现细节和原理,所以无法进行修改网络,只能围绕着网络的外围做一些修改和改动,以适应对具体问题的处理。(我就是围绕着网络的外围建立了新的标签文件,对原标签文件进行了容错性的处理。大神勿喷,我是小白,大佬请自动划走)。

二、功能

具体功能:对传入的图像进行分类,网络需要包含三个资源文件 :

bvlc_googlenet.caffemodel --------------训练文件
bvlc_googlenet.prototxt -------------------描述文件
synset_words.txt --------------------------- 标签文件 ,共一千个分类

三个文件的下载地址在这里,点一下就跳过去了

我们继续:对传入的图像先转化成二值图,之后进入网络进行分类处理(这里就不过多介绍了,主要就是提取特征之后进行一系列处理),我们通过 minMaxLoc();函数找到了此网络中一千个分类中相似度最大的那个结果的索引及相似度的值,通过和synset_words.txt标签文件中的一千个结果的对照,找出这张传入图片对照的具体标签,然后我们将这些信息显示在图片上,最后显示处理后的图片。

到此官方提供的例子的所有功能就结束了,但如果是具体问题的话(例如只是识别四类不同的垃圾),这个网络就会显得有些无能为力。原因是1000种分类太杂太多,对于同类垃圾会有不同的标签值,导致无法进行。

这里提供给大家一个我做比赛时的思路:由于网络提供的标签文件是1000种分类,假设我们只需要四种,那么此时我们只需要在原有标签文件的基础的外围再建立一个标签文件,将我们需要分为一类的标签写入这个外围的标签文件中并做好标记,当驱动外设时,从我们建立的外围标签文件中取出标签,根据我们所做的标记来对照分类。我称这种思路叫做------被欺骗的计算机.
这种思路下来比之前的1000种分类的效果好很多,但对于特征接近但不是一类的物品还是有些无能为力。

最好的方法肯定是精修一下 人工神经网络原理,对网络结构进行更改,这样出来的效果是最好的。或者,也可以找一个现成的网络分类的结果不是那么多的网络,再用上述的思路和计算机交流交流,效果也是挺不错的,但现成的网络分类结果的个数最好不要少于你需要的分类结果的个数(这个相信大家都懂)。

三、代码

重要到了大家期待的代码环节了。加上main()函数共有两个函数

先来说说第一个函数vector< string> readClassLabels();读取标签文件中内容。这个函数实现的代码比较简单,这里就不过多解释了

vector<string> readClassLabels()
{
    vector<string>classNames;  //存放name
    ifstream fp(labels_txt_file.c_str());//读入文件
    if (!fp.is_open())
    {
        cout << "文件未找到!!!" << endl;
        cout << "坏事了"<< endl;
        exit(-1);
    }
    string name;
    while (!fp.eof())  //当文件没有读到尾部
    {
        getline(fp, name); //读取文件每一行,从fp中读取,将结果放在name里面去
        if (name.length())
        {
            classNames.push_back(name.substr(name.find("n") + 1,name.find(" ") - 1));
            //classNames.push_back(name.substr(name.find(" ") + 1)); //从空格后面开始取字符

        }
    }
    fp.close();//关闭输入输出流
    return classNames;
}

这里substr()这个函数是剪切字符串的函数,后面的一堆是由于标签文件的格式原因,下面是标签文件的一部分截图:
在这里插入图片描述
主函数main();

int main()
{
    Mat src = imread("1.3.jpg");
    if (src.empty())
    {
        cout << "图片未找到!!!" << endl;
        return -1;
    }
    imshow("input image", src);
    vector<string> labels = readClassLabels();
    Net caffe_net = readNetFromCaffe(caffe_txt_file, caffe_model_file);

    if (caffe_net.empty())
    {

        return 0;
    }

    Mat inputblob = blobFromImage(src, 1.0, Size(224, 224), Scalar(104, 117, 123)); //将读进来的图像转为blob
    Mat prob;

    for(int i = 0; i < 10; i++)
    {
        caffe_net.setInput(inputblob, "data");//第一层是data
        prob=caffe_net.forward("prob");
    }

    Mat Matprob = prob.reshape(1, 1); //维度变成1*1000
    double Probability;   //最大相似度
    Point classindex;


    minMaxLoc(Matprob, NULL, &Probability, NULL, &classindex);//此函数要求Matprob必须为单通道的一位数组
    int Nameindex = classindex.x;     //最大相似度对应的索引
    cout<<"Probability:"<< Probability*100<<"%"<< endl; 
    cout << "value" << labels.at(Nameindex) << endl;
  //  cout << "NameValue:" << labels.at(Nameindex)  << endl;

    putText(src, labels.at(Nameindex), Point(20, 20), FONT_HERSHEY_SIMPLEX, 1.0, Scalar(0, 0, 255), 2, 8);

    imshow("result image", src);
    waitKey(0);

    return 0;

}

这段代码也没有什么好解释的,一些重要的地方已经注释了,有小伙伴不懂得可以留言给我。

上面这些完成之后,我们还需要在主函数之外定义一下三个标签文件的名字:

string caffe_model_file = "bvlc_googlenet.caffemodel";  //训练文件
string caffe_txt_file = "bvlc_googlenet.prototxt";   //描述文件
string labels_txt_file = "synset_words.txt";   //标签文件

下面我们来看看.h文件

#ifndef __dnet__H
#define __dnet__H
#include <opencv2/opencv.hpp>
#include <opencv2/dnn.hpp>
#include <iostream>
#include <fstream>
#include <string>

using namespace cv;
using namespace std;
using namespace cv::dnn;


vector<string> readClassLabels();


#endif

我们需要包含这些头文件,才能正常的用DNN网络。

四、细节问题

这里需要注意,安装的OpenCV的版本需要在3.4以上(在我印象里),我的是3.4.5,OpenCV3.4版本之后才兼容了dnn模块,这点很重要!!!

之后我们编译时需要在后面加上这个:

g++ dnet.cpp -o dnet `pkg-config --cflags --libs opencv`

到此,就完成了此网络的一次分类了,我们可以改变主函数的结构,进行循环多次分类,也可在外围建立新的标签文件,将需要处理的一类图像经过网络得到旧标签写入新标签并加入新的flag,之后相似的输入就被分成了同一类。这里我就不把我的具体比赛代码给大家了(很乱,哈哈哈)。

五、结果

我就将一张香蕉皮的照片分类结果放在这儿:
在这里插入图片描述
可以看出分类的结果的相似度为80.5459%,对应的标签文件为n07753592,这里的n被我剪切掉了,不过不重要,我们找到标签文件对照这个n07753592标签,得到了结果是
在这里插入图片描述
结果是正确的,对应的标签也没毛病。

我们更改源码,改变剪切字符串的那个函数:
在这里插入图片描述
得到的结果是:
在这里插入图片描述
和上面的那个的区别是把整个标签的内容放了出来。

六、终了

上述就是今天分享的所有内容了,如果对你有帮助,帮忙点个赞,我是小白,需要鼓励,嘻嘻嘻。

之后还会继续分享我的工训比赛的界面的规划,驱动等,如果有错误,请各位大佬批评指正,如果有和我一样的小白,哪里看不懂可以直接留言给我,我看到就会回复的,感谢。

  • 6
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
课程目的:OpenCV是应用非常广泛的开源视觉处理库,在图像处理、计算机视觉和自动驾驶中有着非常重要的作用。课程设计特色:(课程当前为第一期)1、C++与Python双语教学Python语言是在计算机视觉中应用最多的一种语言,在工作中,深度学习模型的训练基本上都是使用Python语言编写的训练代码OpenCV在这个过程中用于图像的预处理(例如图像读取、数据增强)和后处理,还可以用于显示处理的结果,功能强大,使用方便。但是在功能的部署的时候,不管是部署在服务端还是PC端,开发语言基本上用的是C++,所以如何有效的使用OpenCV进行模型或者功能的部署尤为重要。C++语言应用的好坏,在面试中可以看出一个面试者的工程实践能力的强弱,两种语言的开发掌握好了可以使工作如虎添翼。2、全模块讲解我出版了一本图书《学习OpenCV4:基于Python的算法实战》,虽然这本书是写的基于Python的算法实战,但是实际上这本书有详细的介绍算法的C++接口,还有一些C++方向的案例,是以Python为主。图书出版的时候就想双语写作,只是限于篇幅没有成行。本课程不仅采用双语教学,更是对C++的每个模块都做讲解,我们知道,很多的书其实只讲imgproc,如果你翻开一本书图像的形态学运算和图像滤波都是作为独立章节讲解的,那么这本书基本上就可以确定是只是讲解了imgproc模块,但是其他的模块在工作中也有很重要的作用。例如:core模块定义了C++的基本数据结构和基本运算(如四则运算);highgui模块是可视化与交互的模块;feature2d是特征点与特征匹配相关算法所在的模块;ml是机器学习相关的模块;dnn是深度学习相关的模块,可以使用OpenCV进行深度学习模型的部署。这些是很多的书和课程都不会讲的。3、讲解细致本课程会从环境搭建开始讲解,环境搭建尤为重要。从我多年的授课经验总结来看,如果只是给了代码,很多的入门用户环境问题处理不好的话,后面的学习很难进行下去,甚至会丧失学习的信心。4、会讲解C++和Python的开发语法问题是入门用户的一大难关,特别是C++语言。大学只是教授了C语言相关的内容,C++很多同学只懂一点皮毛,所以写代码步履维艰,我们在讲解代码的过程中会顺带讲解C++和Python的内容。我们还会讲解编译相关知识,还有库的装载与链接,这些是学校里不会教的,目前也几乎没有课程讲解。5、讲师经验丰富我讲解过C++OpenCV的多个课程,广受学员好评。我出版过两本图书《深度学习计算机视觉实战》和《学习OpenCV4》,两本书都是细致入微的讲解,主要针对的就是初学者,所以能够很好的处理课程的难易程度。6、讲义准备充分讲义准备的充分细致,标识清楚明确,重点和疑难点突出。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值