tensorflow对python语言的支持非常好,大量的训练模型基本都是python端训练,但问题来了,生产上线的时候,用的最多的还是C/C++。目前关于C++部署的学习资料和介绍例子非常有限,很多资料都雷同相似,而且也未经过实际测试验证。针对其他不同的训练模型,难以适用,很可能到处碰到坑。 笔者就曾经碰过不少坑、浪费花了不少时间和精力。
这次LINUX端Python训练Deeplab v3+网络、数据集为VOC2012、训练模型输出采用saveModelBuild方式保存为tensorflow的*.pb模式, VS2017 + opencv400 , tensorflow库为VS2017 CPP编译的1.8.0版本,具体代码如下:
/*****************************************************
tensorflow c++ 接口部署深度学习模型
Author:
WSN@2019
******************************************************/
#include "pch.h"
#include
#include"opencv2/opencv.hpp"
/* tensorflow 宏定义*/
//tensorflow/core/platform/windows/cpu_info.h
#define COMPILER_MSVC
#define NOMINMAX
#define PLATFORM_WINDOWS
#include"tensorflow/core/public/session.h"
#include"tensorflow/core/platform/env.h"
#include"tensorflow/cc/saved_model/loader.h"
#include"google/protobuf/message.h"
using namespace tensorflow;
using namespace cv;
using namespace std;
tensorflow::Status loadGraph(std::string model_path, std::unique_ptr* sess)
{
tensorflow::SessionOptions session_options;
tensorflow::RunOptions run_options;
tensorflow::SavedModelBundle bundle;
tensorflow::Status status;
constexpr char kSavedModelTagServe[] = "serve"; /* 模型tag名称 */
status = LoadSavedModel(session_options, run_options, model_path, { kSavedModelTagServe }, &bundle);
if (!status.ok())
{
std::cerr << "Error reading graph definition from " + model_path + ": " + status.ToString() << std::endl;
return status;
}
*sess = std::move(bundle.session);
return status;
}
int main()
{
Mat img;
Status status;
std::cout << "Hello tensorflow!\n";
/* 创建session和加载tensorflow模型 */
SessionOptions options;
std::unique_ptr session(NewSession(options));
//NewSession(SessionOptions(), &session);
loadGraph("D:/tensorflow/myModels/voc", &session);
Mat segm; /* 分割图 */
int class_id = 21; /* 支持21种物体识别分割 */
std::vector colors;
/* 构建颜色colors表 */
if (colors.empty())
{
for (int label = 0; label < class_id; label++)
{
Vec3i color;
int c;
int j;
color[0] = color[1] = color[2] = 0;
c = label;
j = 0;
while (c)
{
color[0] |= ((c >> 0) & 1) << (7 - j);
color[1] |= ((c >> 1) & 1) << (7 - j);
color[2] |= ((c >> 2) & 1) << (7 - j);
c >>= 3;
j += 1;
}
colors.push_back(color);
}
}
string dir_path = "D:/deepLearning/dataset/voc2012/JPEGImages"; /* 测试图片路径 */
vector file_list;
cv::glob(dir_path, file_list); /* 从文件夹路径读取所有测试图片 */
for (int ii = 0; ii < file_list.size(); ii++)
{
String pp = file_list[ii];
Mat img = imread(pp, IMREAD_COLOR);
Mat input;
cout << "img:" << pp << endl;
imshow("input", img);
cvtColor(img, input, COLOR_BGR2RGB);
input.convertTo(input, CV_32F);
/* 从Opencv Mat格式构造tensorflow张量Tensor, N-H-W-C 格式, N = 1(batch size) 深度: C = 4 */
float* pdata = (float*)input.data;
Tensor input_tensor(DT_FLOAT, TensorShape({ 1, input.rows, input.cols, input.channels() }));
auto input_tensor_mapped = input_tensor.tensor(); /* 4 位模型输出的维度 */
/* 输入图象预处理 */
//Mat mean_(input.rows, input.cols, CV_32FC3, Scalar(123.68, 116.78, 103.94));
//Mat tmp;
//input -= mean_;
//input.convertTo(tmp, CV_8U);
//Mat sample_normalized;
//subtract(input, mean_, input);
//imshow("input-pre", tmp);
//waitKey();
/* 拷贝数据到张量input */
for (int i = 0; i < input.rows; i++)
{
float* source_row = pdata + (i * input.cols * input.channels());
for (int j = 0; j < input.cols; j++)
{
float* vval = source_row + (j * input.channels());
for (int c = 0; c < input.channels(); c++)
{
float* source_value = vval + c;
input_tensor_mapped(0, i, j, c) = *source_value;
}
}
}
/* pb模型输入: "image_tensor" 根据模型中name定义字段,可以从signature_def中查看 */
tensorflow::Tensor keep_prob(DT_FLOAT, TensorShape());
std::vector> inputs =
{
{ "image_tensor", input_tensor },
};
std::vector outputs;
/* pb模型输出时,"key:classes,name: ExpandDims:0","key: probabilities, name: softmax_tensor:0"
即模型中定义的输出张量name字段 */
status = session->Run(inputs, {"ExpandDims","softmax_tensor"}, {}, &outputs);
if (!status.ok())
{
std::cerr << status.ToString() << endl;
return -1;
}
/* 输出结果和可视化结果 */
tensorflow::Tensor output = std::move(outputs.at(0)); /* 类别calsses */
tensorflow::Tensor output2 = std::move(outputs.at(1)); /* 类别概率probabilities */
auto out_shape = output2.shape();
int ww, hh,depth,dims;
//tfTensor2cvMat(output, cc_Out);
ww = out_shape.dim_size(1);
hh = out_shape.dim_size(2);
depth = out_shape.dim_size(3);
dims = out_shape.dims();
//Mat cls_result = Mat::zeros(ww, hh, CV_8UC3);
auto tensor_dat = output.tensor();
int ch = output.dim_size(3); /* depth */
/* 分割结果着色 */
segm.create(input.rows, input.cols, CV_32SC3);
for (int row = 0; row < img.rows; row++)
{
for (int col = 0; col < img.cols; col++)
{
int32 cls = tensor_dat(0, row, col, ch);
int index = cls;
if (cls < 21 && cls >= 1)
segm.at(row, col) = colors[cls];
else
segm.at(row, col) = Vec3i(0,0,0);
}
}
segm.convertTo(segm, CV_8U);
Mat tmp;
addWeighted(img, 0.40, segm, 0.8, 0.0, tmp); /* 混合原图 */
imshow("segm", segm);
imshow("mix", tmp);
waitKey(20);
}
/* 关闭session */
session->Close();
return 1;
}
验证图片如下:
我已经将项目工程上传到了github,Models模型可以在我的github工程中,找到下载:
https://github.com/peterwkl2013/DeepVision
本文属于原创并经过测试,
如果觉得本文对您有了帮助,请给予的一点小鼓励
您的支持,是我继续前景的动力!!!谢谢~~