使用Caffe模型经过GoogLeNet训练的网络实现图像分类(c/c++,opencv,opencvdnn)

  • Post author:
  • Post category:其他




废话不多说,直接上代码,干货满满!!!



opencv中的dnn模块是很好用的!!!

#include "opencv2/opencv.hpp"
#include "opencv2/dnn.hpp"
#include <iostream>
#include <fstream>

/*
深度网络(Net)是由许多互相连接的层(layers)组合成的组合模型,Caffe定义的网络模型就是这样逐层(layers)连接。
Net包含了整个自顶向下的网络,网络由各个Layer组合而成;
Layer指处理数据的单层运算算子(比如卷积运算、pooling运算等);
Blob是网络运行时数据存储、传递和操作的接口;
*/

using namespace cv;
using namespace cv::dnn;//opencv dnn 模块
using namespace std;

String modelTxt = "bvlc_googlenet.prototxt";//模型参数 
String modelBin = "bvlc_googlenet.caffemodel";//模型配置文件即模型框架
String labelFile = "synset_words.txt";//imageNet标签文件

vector<String> readLabels();
int main(int argc, char** argv) {
	Mat testImage = imread("spacetrain.jpg");//读入分类图片,(可改写成capture cap即视频)
	if (testImage.empty()) 
	{
		cout << "could not load image..." << endl;
		return -1;
	}

	//使用caffe model创建Net
	Net net = dnn::readNetFromCaffe(modelTxt, modelBin);
	//dnn.readNetFromCaffe(prototxt, model)  用于进行SSD网络的caffe框架的加载
	//参数说明:prototxt表示caffe网络的结构文本,model表示已经训练好的参数结果
	//详情查看博客https://blog.csdn.net/weixin_33850015/article/details/93458287

	if (net.empty())
	{
		std::cerr << "Can't load network by using the following files: " << std::endl;//写到cerr的数据是不缓冲的。Cerr通常用于输出错误信息与其他不属于正常逻辑的输出内容
		std::cerr << "prototxt:   " << modelTxt << std::endl;
		std::cerr << "caffemodel: " << modelBin << std::endl;
		return -1;
	}

	// 读取分类数据
	vector<String> labels = readLabels();

	//GoogLeNet 接受224x224 RGB图像
	Mat inputBlob = blobFromImage(testImage, 1, Size(224, 224), Scalar(104, 117, 123), false, true);
	//blobFromImage()函数,在进行深度学习或者图片分类时,blobFromImage主要是用来对图片进行预处理。包含两个主要过程:整体像素值减去平均值(mean)通过缩放系数(scalefactor)对图片像素值进行缩放
	//参数说明:
	//输入神经网络进行处理或者分类的图片
	//图片减去平均值之后,还可以对剩下的像素值进行一定的尺度缩放,它的默认值是1,如果希望减去平均像素之后的值,全部缩小一半,那么可以将scalefactor设为1/2。
	//神经网络在训练的时候要求输入的图片尺寸
	//OpenCV中认为我们的图片通道顺序是BGR,但是我平均值假设的顺序是RGB,所以如果需要交换R和G,那么就要使swapRB=true
	//详情查看博客https://blog.csdn.net/u011341856/article/details/100041050

	Mat prob;
	for (int i = 0; i < 10; i++)
	{
		// 输入
		net.setInput(inputBlob, "data");
		// 分类预测
		prob = net.forward("prob");
	}

	// 读取分类索引,最大与最小值
	Mat probMat = prob.reshape(1, 1); //reshape the blob to 1x1000 matrix // 1000个分类

	Point classNumber; //一个点类 Point

	double classProb;
	minMaxLoc(probMat, NULL, &classProb, NULL, &classNumber); // 可能性最大的一个
	int classIdx = classNumber.x; // 分类索引号
	cout << "\n current image classification : %s, possible : %.2f \n", labels.at(classIdx).c_str(), classProb;
	//c_str()函数返回一个指向正规C字符串的指针, 内容与本string串相同
	//c_str():生成一个const char*指针,指向以空字符终止的数组。

	putText(testImage, labels.at(classIdx), Point(20, 20), FONT_HERSHEY_SIMPLEX, 0.5, Scalar(0, 99, 123), 2, 8);
	//putText()往指定位置进行文本写入
	//需要写字的原图像
	//需要写的内容,string类型的
	//需要写的内容的左下角的坐标
	//字体大小
	//颜色
	//字体的厚度
	//默认8

	imshow("Image Category", testImage);

	waitKey(0);
	return 0;
}


//读取图像的1000个分类标记文本数据 
vector<String> readLabels() 
{
	std::vector<String> classNames;
	std::ifstream fp(labelFile);//fp指向文件synset_words.txt
	if (!fp.is_open())
	{
		std::cerr << "File with classes labels not found: " << labelFile << std::endl;
		exit(-1);
	}

	std::string name;
	while (!fp.eof())
	{
		std::getline(fp, name);
		if (name.length())
			classNames.push_back(name.substr(name.find(' ') + 1));
	}

	fp.close();
	return classNames;
}



识别效果如图:

opencvdnn识别图


代码中使用的3个文件:

String modelTxt = “bvlc_googlenet.prototxt”;//模型参数

String modelBin = “bvlc_googlenet.caffemodel”;//模型配置文件即模型框架

String labelFile = “synset_words.txt”;//imageNet标签文件

请加QQ群 109530331,问我要,嘻嘻嘻嘻!!!!!!!!!!



版权声明:本文为qq_43475606原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。