日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 人文社科 > 生活经验 >内容正文

生活经验

Tensorflow C++ API调用Keras模型实现RGB图像语义分割

發布時間:2023/11/27 生活经验 29 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Tensorflow C++ API调用Keras模型实现RGB图像语义分割 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

我的實驗是基于PSPNet模型實現二維圖像的語義分割,下面的代碼直接從得到的h5文件開始往下做。。。

也不知道是自己的檢索能力出現了問題還是咋回事,搜遍全網都沒有可以直接拿來用的語義分割代碼,東拼西湊,算是搞成功了。

實驗平臺:Windows、VS2015、Tensorflow1.8 api、Python3.6

具體的流程為:keras訓練模型 --> model.h5 --> 轉換成.pb文件 --> tensorflow 載入.pb 驗證正確性 --> tensorflow C++ api調用 .pb文件

1. 將訓練好的h5模型轉換為pb文件

# convert .h5 to .pb
import tensorflow as tf
from tensorflow.python.framework import graph_io
from keras import backend as K
from nets.pspnet import pspnet
from keras.models import load_model
from keras.models import Model, load_model
from keras.models import model_from_jsondef freeze_session(session, keep_var_names=None, output_names=None, clear_devices=True):from tensorflow.python.framework.graph_util import convert_variables_to_constantsgraph = session.graphwith 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_graphK.set_learning_phase(0)keras_model = load_model('./model.h5')
/*如果h5不包含模型結構,需要先load json然后再load weights
json_file = '/model.json'
with open(json_file, 'r') as f:json_str = f.read()
model = model_from_json(json_str)
keras_model.load_weights('./model.h5')
*/# .inputs和.outputs非常重要,需要記錄下來
print('Inputs are:', keras_model.inputs)
print('Outputs are:', keras_model.outputs)
// 保存pb文件
frozen_graph = freeze_session(K.get_session(), output_names=[keras_model.output.op.name])
graph_io.write_graph(frozen_graph, "./", "model.pb", as_text=False)

2. 在Python中驗證pb文件是否可用

import numpy as np
import tensorflow as tf
import cv2
from PIL import Image
//INPUT_TENSOR_NAME和OUTPUT_TENSOR_NAME 是基于1中的結果
INPUT_TENSOR_NAME = 'input_1:0'
OUTPUT_TENSOR_NAME = 'main/truediv:0'
INPUT_SIZE = 473
colors = [(73, 73, 73), (0, 255, 255), (255, 255, 0)]
num_classes = 3with tf.gfile.FastGFile('./model.pb', "rb") as f:graph_def = tf.GraphDef()graph_def.ParseFromString(f.read())g_in = tf.import_graph_def(graph_def, name="")
sess = tf.Session(graph=g_in)def run(image):height, width = image.shape[0:2]# 歸一化很重要,卡了我1天多image = (image - image.min())/(image.max() - image.min())resized_image = cv2.resize(image, (INPUT_SIZE, INPUT_SIZE))input_x = sess.graph.get_tensor_by_name(INPUT_TENSOR_NAME)out_softmax = sess.graph.get_tensor_by_name(OUTPUT_TENSOR_NAME)batch_seg_map = sess.run(out_softmax,feed_dict={input_x: [np.asarray(resized_image)]})# batch_seg_map是[1,473,473,3],batch_seg_map[0]尺寸是[473,473,3]# seg_map 便是預測結果seg_map = batch_seg_map[0]seg_map = seg_map.argmax(axis=-1).reshape([INPUT_SIZE, INPUT_SIZE])seg_img = np.zeros((np.shape(seg_map)[0], np.shape(seg_map)[1], 3))# 根據seg_map 中每個像素的值來賦予mask顏色for c in range(num_classes):seg_img[:, :, 0] += ((seg_map[:, :] == c) * (colors[c][0])).astype('uint8')seg_img[:, :, 1] += ((seg_map[:, :] ==c) * (colors[c][1])).astype('uint8')seg_img[:, :, 2] += ((seg_map[:, :] == c) * (colors[c][2])).astype('uint8')image = cv2.resize(seg_img, (int(width), int(height)))return imageinput_image = cv2.imread('./img/image.jpg')
seg_map = run(input_image)
cv2.imwrite("./out.jpg", seg_map)

3. 在C++程序中調用pb文件

坑太多,小小的錯誤可能就得不到預期結果。

#include <fstream>
#include <utility>
#include <iostream>
#include <vector>
#include <opencv2/opencv.hpp>
#include "tensorflow/core/public/session.h"
#include "tensorflow/core/graph/default_device.h"using namespace std;
using namespace cv;#define INPUT_W 474
#define INPUT_H 474
#define num_classes 4// Define a function to convert Opencv's Mat data to tensorflow tensor. In python, just perform np.reshape on the matrix read in cv2.imread(), and the data type becomes a tensor, that is, tensor is the same as a matrix. Then you can even enter the entrance of the network
// In the C++ version, the input of the network also needs to be a tensor data type, so the input image needs to be converted into a tensor. If you use Opencv to read the image, the format is a Mat, you need to consider how to convert a Mat to tensor
void CVMat_to_Tensor(cv::Mat& img, tensorflow::Tensor& output_tensor, int input_rows, int input_cols)
{Mat resize_img;resize(img, resize_img, cv::Size(input_cols, input_rows));Mat dst = resize_img.reshape(1, 1);// 第二個坑 rgb圖像的歸一化for (int i = 0; i < dst.cols; i++) {dst.at<float>(0, i) = dst.at<float>(0, i) / 255.0;}resize_img = dst.reshape(3, INPUT_H);float * p = (&output_tensor)->flat<float>().data();cv::Mat tempMat(input_rows, input_cols, CV_32FC3, p);resize_img.convertTo(tempMat, CV_32FC3);}void tensor2Mat(tensorflow::Tensor &t, cv::Mat &image) {float *p = t.flat<float>().data();image = Mat(INPUT_H, INPUT_W, CV_32FC3, p); //根據分類個數來,現在是3分類,如果是4分類就寫成CV_32FC4}int main(int argc, char ** argv)
{/* --------------------Configuration key information------------------------- -----------*/std::string model_path = "./psp_1w_resnet50_wudongjie.pb"; // pb model addressstd::string image_path = "./model/image.jpg"; // test pictureint input_height = INPUT_H; // Enter the image height of the networkint input_width = INPUT_W; // input network image widthstd::string input_tensor_name = "input_1:0"; // The name of the input node of the networkstd::string output_tensor_name = "main/truediv:0"; // The name of the output node of the network/* --------------------Create session------------------------------------*/tensorflow::Session * session;tensorflow::Status status = tensorflow::NewSession(tensorflow::SessionOptions(), &session); // Create a new session Session/* --------------------Read model from pb file------------------------------------*/tensorflow::GraphDef graphdef; //Define a graph for the current modeltensorflow::Status status_load = tensorflow::ReadBinaryProto(tensorflow::Env::Default(), model_path, &graphdef); // read graph model from pb fileif (!status_load.ok()) // Determine whether the read model is correct, if it is wrong, print out the wrong information{std::cout << "ERROR: Loading model failed..." << model_path << std::endl;std::cout << status_load.ToString() << "\n";return -1;}tensorflow::Status status_create = session->Create(graphdef); // Import the model into the session Sessionif (!status_create.ok()) // Determine whether the model is imported into the session successfully, if it is wrong, print out the error message{std::cout << "ERROR: Creating graph in session failed..." << status_create.ToString() << std::endl;return -1;}std::cout << "<------Sucessfully created session and load graph------>" << std::endl;/* --------------------Load test picture------------------------ ------------*/cv::Mat img = cv::imread(image_path, -1); // read image, read grayscale imageimg.convertTo(img, CV_32FC3);//第一個小坑,整個程序都讀取Floatif (img.empty()){std::cout << "can't open the image!!!!!" << std::endl;return -1;}// Create a tensor as the input network interfacetensorflow::Tensor resized_tensor(tensorflow::DT_FLOAT, 		    tensorflow::TensorShape({1, input_height,input_width, 3}));// Save the Mat format picture read by opencv into tensorCVMat_to_Tensor(img, resized_tensor, input_height, input_width);std::cout << resized_tensor.DebugString() << std::endl;/* --------------------Test with network------------------------ ------------*/std::cout << std::endl << "<------------------Runing the model with test_image------------------->" << std::endl;// Run forward, the output result must be a vector of tensorstd::vector<tensorflow::Tensor> outputs;std::string output_node = output_tensor_name; // output node nametensorflow::Status status_run = session->Run({ { input_tensor_name, resized_tensor } }, { output_node }, {}, &outputs);if (!status_run.ok()){std::cout << "ERROR: Run failed..." << std::endl;std::cout << status_run.ToString() << std::endl;return -1;}// Extract the output valuestd::cout << "Output tensor size: " << outputs.size() << std::endl;for (std::size_t i = 0; i < outputs.size(); i++){std::cout << outputs[i].DebugString() << std::endl;}tensorflow::Tensor t = outputs[0];cv::Mat outimage = cv::Mat::zeros(INPUT_H, INPUT_W, CV_32FC3);cv::Mat class_Mat;tensor2Mat(t, class_Mat);int output_height = t.shape().dim_size(1);int output_width = t.shape().dim_size(2);//根據分類數目設置顏色個數int colors[num_classes][3] = { { 73, 73, 73 },{ 0, 255, 255 },{ 255, 255, 0 } };//根據one-hot編碼實現每個像素的分類,選取三通道中概率最大值最為分類結果,并賦予顏色for (int i = 0; i < output_height; i++){for (int j = 0; j < output_width; j++){int index = 0;for (int k = 1; k < num_classes; k++) {				if ((float)class_Mat.at<Vec3f>(i, j)[k] >(float)class_Mat.at<Vec3f>(i, j)[k - 1]) {//3分類所以是Vec3findex = k;}}if (index ==0) {outimage.at<Vec3f>(i, j)[0] = colors[0][0];outimage.at<Vec3f>(i, j)[1] = colors[0][1];outimage.at<Vec3f>(i, j)[2] = colors[0][2];}else if (index == 1) {outimage.at<Vec3f>(i, j)[0] = colors[1][0];outimage.at<Vec3f>(i, j)[1] = colors[1][1];outimage.at<Vec3f>(i, j)[2] = colors[1][2];}else {outimage.at<Vec3f>(i, j)[0] = colors[2][0];outimage.at<Vec3f>(i, j)[1] = colors[2][1];outimage.at<Vec3f>(i, j)[2] = colors[2][2];}}}// 記得最后要resize到原圖像大小resize(outimage, outimage, cv::Size(img.cols, img.rows));imshow("img", outimage);waitKey();return 0;
}

tensorflow::Tensor::DebugString()只能輸出第一組數據,像這樣:

如果想遍歷tensor中所有元素的值,可以使用 auto tensor_map = resized_tensor.tensor<float, 4>,然后來三個for循環就可以了,獲取某一索引元素也是可以的

for (int y = 0; y < input_height; ++y) {for (int x = 0; x < input_width; ++x) {for (int c = 0; c < 3; ++c) {cout<<tensor_map (0, y, x, c)<<endl;}}
}

經過反復嘗試,代碼是沒問題的,但是還有很大的優化空間,后期會用CUDA把C++程序重寫一遍,但是最耗時的session->Run這一預測過程目前還不知道怎么加速。希望大家提點建議,一起進步。

總結

以上是生活随笔為你收集整理的Tensorflow C++ API调用Keras模型实现RGB图像语义分割的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。