Ubuntu上运行tensorflow C++的完整例子
个人博客原文:http://www.bearoom.xyz/2019/08/25/ubuntu-tensorflow-cc-example/
之前记录的运行Tensorflow的C++接口的例子都是零散的,现在写一个完整的例子。
一、模型文件转换
首先是需要有训练好的模型文件,然后将其转化为tensorflow的C++接口能够读取的.pb文件,这个前面也有记录,现在贴下完整的代码:
###################################################
#
# Script to
# - Loading a pre-trained model(.h5)
# - Generate a .pb model file from .h5
#
##################################################
#Python
import numpy as np
import configparser
import time
from matplotlib import pyplot as plt
#Keras
from keras.models import model_from_json
from keras.models import Model
#scikit learn
from sklearn.metrics import roc_curve
from sklearn.metrics import roc_auc_score
from sklearn.metrics import confusion_matrix
from sklearn.metrics import precision_recall_curve
from sklearn.metrics import jaccard_similarity_score
from sklearn.metrics import f1_score
import sys
from keras.models import load_model
import tensorflow as tf
from keras import backend as K
from tensorflow.python.framework import graph_io
from tensorflow.python.framework.graph_util import convert_variables_to_constants
def freeze_session(session, keep_var_names=None, output_names=None, clear_devices=True):
graph = session.graph
with graph.as_default():
freeze_var_names = list(set(v.op.name for v in tf.global_variables()).difference(keep_var_names or []))
output_names = output_names or []
output_names += [v.op.name for v in tf.global_variables()]
input_graph_def = graph.as_graph_def()
if clear_devices:
for node in input_graph_def.node:
node.device = ""
frozen_graph = convert_variables_to_constants(session, input_graph_def, output_names, freeze_var_names)
return frozen_graph
model = model_from_json(open('CDNet_v4_architecture.json').read())
model.load_weights('CDNet_v4_best_weights.h5')
model.summary()
print('input is :', model.input.name)
print ('output is:', model.output.name)
"""------------------------保存为.pb格式------------------------"""
sess = K.get_session()
frozen_graph = freeze_session(K.get_session(), output_names=[model.output.op.name])
graph_io.write_graph(frozen_graph, './', 'CDNet_v4_best_weights.pb', as_text=False)
然后会输出模型的每层信息,以及输入输出信息:

二、CMakeLists.txt文件
CMakeLists.txt文件里面会添加opencv和tensorflow的路径:
#设置cmake的最小版本
cmake_minimum_required(VERSION 3.0)
#项目名称
project(demo)
#设置c++编译器
set(CMAKE_CXX_STANDARD 11)
#设置TENSORFLOW_DIR变量,变量内容为安装的tensorflow文件夹路径
set(TENSORFLOW_DIR /home/zcx/tensorflow-r1.12)
#项目中的include路径
include_directories(${TENSORFLOW_DIR})
include_directories(${TENSORFLOW_DIR}/tensorflow/contrib/makefile/downloads/absl)
include_directories(${TENSORFLOW_DIR}/bazel-genfiles)
include_directories(${TENSORFLOW_DIR}/tensorflow/contrib/makefile/downloads/eigen)
# opencv
include_directories(/usr/local/opencv347/include /usr/local/opencv347/include/opencv /usr/local/opencv347/include/opencv2)
#项目中lib路径
link_directories(${TENSORFLOW_DIR}/tensorflow/contrib/makefile/gen/lib)
link_directories(${TENSORFLOW_DIR}/bazel-bin/tensorflow)
link_directories(/usr/local/opencv347/lib)
add_executable(demo main.cpp)
#连接libtensorflow_cc.so和libtensorflow_framework库。
target_link_libraries(demo tensorflow_cc tensorflow_framework opencv_core opencv_highgui opencv_imgproc opencv_imgcodecs)
三、C++文件:
因为我这个模型是进行视网膜血管图像分割,最终的输出层是一个2维tensor,第一维图像长宽的乘积,即数据大小,第二维是通道数,因为有背景和血管两个类,所以分了两个通道。最后得到输出张量的时候也要通过赋值或者变形等操作将数据转为图像数据来显示。
#include <tensorflow/core/platform/env.h>
#include <tensorflow/core/public/session.h>
#include <iostream>
#include <opencv.hpp>
using namespace std;
using namespace tensorflow;
void CVMat_to_Tensor(cv::Mat &img, Tensor* output_tensor, int input_rows,int input_cols)
{
//imshow("input image",img);
//图像进行resize处理
cv::resize(img,img,cv::Size(input_cols,input_rows));
//imshow("resized image",img);
//归一化
img.convertTo(img,CV_32FC1);
img=img/255;
float *p = output_tensor->flat<float>().data();
cv::Mat tempMat(input_rows, input_cols, CV_32FC1, p);
img.convertTo(tempMat,CV_32FC1);
}
int main()
{
Session* session;
Status status = NewSession(SessionOptions(), &session);
if (!status.ok())
{
cout << status.ToString() << "\n";
return -1;
}
cout << "Session successfully created.\n";
string model_path = "./CDNet_v4_best_weights.pb";
GraphDef graphdef;
Status status_load = ReadBinaryProto(Env::Default(), model_path, &graphdef);
if (!status_load.ok())
{
cout << status_load.ToString() << "\n";
return -1;
}
Status status_create = session->Create(graphdef);
if (!status_create.ok())
{
cout << status_create.ToString() << "\n";
return -1;
}
//输出每一曾的名字
for (int i=0; i < graphdef.node_size(); i++)
{
std::string name = graphdef.node(i).name();
std::cout << name << std::endl;
}
cv::Mat src = cv::imread("21_training.tif", 0);
Tensor src_tensor = Tensor(DT_FLOAT, TensorShape({ 1, 1, 544, 544}));
CVMat_to_Tensor(src, &src_tensor, 544, 544);
string input_tensor_name="input_1:0";
string output_tensor_name="activation_1/truediv:0";
vector<tensorflow::Tensor> outputs;
string output_node = output_tensor_name;
Status status_run = session->Run({{input_tensor_name, src_tensor}}, {output_node}, {}, &outputs);
if (!status_run.ok())
{
cout << status_run.ToString() << "\n";
return -1;
}
std::cout << outputs[0].shape().dim_size(1) << std::endl;
std::cout << outputs[0].shape().dim_size(2) << std::endl;
float *pDstTensor = outputs[0].flat<float>().data();
cv::Mat tmp = cv::Mat(544, 544, CV_32FC2, pDstTensor);
cv::Mat tmp1 = cv::Mat(cv::Size(544, 544), CV_32FC1);
cv::Mat dst0 = cv::Mat(cv::Size(544, 544), CV_8UC1);
cv::Mat dst1 = cv::Mat(cv::Size(544, 544), CV_8UC1);
for (int i = 0; i < 544; i++)
{
float *ptrTmp = tmp.ptr<float>(i);
float *ptrTmp1 = tmp1.ptr<float>(i);
for (int j = 0; j < 544; j++)
{
*(ptrTmp1 + j) = *(ptrTmp + j*2)*255;
}
}
tmp1.convertTo(dst0, CV_8UC1);
cv::imwrite("dst0.jpg", dst0);
for (int i = 0; i < 544; i++)
{
float *ptrTmp = tmp.ptr<float>(i);
float *ptrTmp1 = tmp1.ptr<float>(i);
for (int j = 0; j < 544; j++)
{
*(ptrTmp1 + j) = *(ptrTmp + j*2 + 1)*255;
}
}
tmp1.convertTo(dst1, CV_8UC1);
cv::imwrite("dst1.jpg", dst1);
return 0;
}
输入图像:

输出图像我可视化了背景和血管两个通道,转为图像来显示,当然每个像素是乘以255转出来的,毕竟输出的是概率,在0-1之间:
背景(白的背景,黑的为血管):

血管(白的为血管,黑的为背景):

完结,撒花...
风鬟雨鬓,偏是来无准。
倦倚玉兰看月晕,容易语低香近。
软风吹遍窗纱,心期便隔天涯。
从此伤春伤别,黄昏只对梨花。
-- 纳兰性德 《清平乐·风鬟雨鬓》
Ubuntu上运行tensorflow C++的完整例子的更多相关文章
- 在 Ubuntu 上安装 TensorFlow (官方文档的翻译)
本指南介绍了如何在 Ubuntu 上安装 TensorFlow.这些指令也可能对其他 Linux 变体起作用, 但是我们只在Ubuntu 14.04 或更高版本上测试了(我们只支持) 这些指令. 一 ...
- .netcore跨平台 之 windows上编译,ubuntu上运行
1 下载并安装netcore sdk 下载地址 https://github.com/dotnet/cli 选取合适的版本下载安装即可 打开 CMD ,输入dotnet,出现以下信息说明已安装好 ...
- [转]linux(ubuntu)上运行网易popo
popo没有linux版,连web版和android版都没有,这个实在是不方便.搞了很久,终于搞定了ubuntu上运行popo,暂时还没出现什么问题. 首先要安装PlayOnLinux,直接安装win ...
- 在 ubuntu 上运行 php 脚本
在 ubuntu 上运行 php 脚本 一.配置运行环境 1.要在 ubuntu 上运行 php 脚本,需要安装 Apache2 和 PHP 具体步骤,请参考:Ubuntu 搭建Web服务器(MySQ ...
- Ubuntu上运行Blender,在控制台上查看运行结果
1.首先在控制台打开Blender. 具体操作:找到Blender的安装路径,我的是:/home/lcx/下载/blender-2.78c-linux-glibc219-x86_64 $cd /hom ...
- 在64位ubuntu上安装tensorflow
首先从ubuntu14.04的安装讲起 1.下载ubuntu14.04 64位的系统,下载地址如下: http://www.ubuntu.com/download/desktop 2.下载好64位的u ...
- 怎么在ubuntu上运行php代码?
1. 首先,你需要安装Apache2. sudo apt-get update sudo apt-get install apache2 当安装完以后,Apache就已经开始运行啦,你可以进行测试,通 ...
- ubuntu 上运行的django 出现No space left on device错误
运行django出现错误信息: [2016-02-16 14:33:24,476 pyinotify ERROR] add_watch: cannot watch /usr/local/lib/pyt ...
- 在CPU上运行Tensorflow
如果你是用的GPU版本的Tensorflow,你可以这样来使用CPU版本的Tensorlfow: config = tf.ConfigProto( device_count = {'GPU': 0} ...
随机推荐
- PLC与单片机执行指令区别
单片机执行指令方式与PLC执行指令方式对比 . 映射 对顺序功能图并行分支的理解. PLC与单片机都是顺序执行指令方式的. PLC执行指令分为3个阶段. PLC的一个指令周期包括 输入采样 程序执 ...
- 洛谷训练场——简单模拟 排座位(P1056)
题目描述 上课的时候总会有一些同学和前后左右的人交头接耳,这是令小学班主任十分头疼的一件事情.不过,班主任小雪发现了一些有趣的现象,当同学们的座次确定下来之后,只有有限的D对同学上课时会交头接耳. 同 ...
- HihoCoder第十三周:最近公共祖先 一
#1062 : 最近公共祖先·一 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 同城那样神奇,但这个网站仍然让小Ho乐在其中,但这是为什么呢? "为什么呢?& ...
- plsql调用执行存储过程
参考 https://www.cnblogs.com/enjoyjava/p/9131169.html ------------------------------------------------ ...
- STM32中ARM系列编译工具链的编译宏选择(__CC_ARM、__ICCARM__、__GNUC__、__TASKING__)
一 前言 stm32 f103中.关系到一个选择何种编译宏的问题.这里就梳理一下吧. 二 正文 1 在 core_cm3.h 文件中,有如下代码: #if defined ( __CC_ARM ) ...
- 154-PHP strpos函数
<?php $str='passwords'; //定义一个字符串 $position=strpos($str,'s'); //查找字母s第一次出现的位置 echo '字母s的位置是'.$pos ...
- JAVA-数据类型-复习
JAVA-数据类型-复习 Java中,一共有8种数据类型,4种整型,2种浮点型,1种用于表示Unicode编码的字符单元的字符类型char,1种布尔类型. 整型 类型 存储需求(字节)一个字节包含8个 ...
- Spark RDD 算子总结
Spark算子总结 算子分类 Transformation(转换) 转换算子 含义 map(func) 返回一个新的RDD,该RDD由每一个输入元素经过func函数转换后组成 filter(func) ...
- PGSQL基本操作语句
; --更新数据 ,,) ; --插入数据 ORDER BY app_name,flag asc/desc ; --查询数据并且排序 offset ; --查询起点0开始查询,返回5条数据 ORDER ...
- 【LeetCode】509. 斐波那契数
题目 斐波那契数,通常用 F(n) 表示,形成的序列称为斐波那契数列.该数列由 0 和 1 开始,后面的每一项数字都是前面两项数字的和.也就是: F(0) = 0, F(1) = 1 F(N) = ...