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)

然后会输出模型的每层信息,以及输入输出信息:


image.png

二、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;
}

输入图像:


image.png

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


image

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

完结,撒花...

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,293评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,604评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,958评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,729评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,719评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,630评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,000评论 3 397
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,665评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,909评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,646评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,726评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,400评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,986评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,959评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,197评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,996评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,481评论 2 342

推荐阅读更多精彩内容