Skip to content

Commit

Permalink
add mnn project
Browse files Browse the repository at this point in the history
  • Loading branch information
MaybeShewill-CV committed Nov 5, 2019
1 parent 63d8dfc commit 9dba8a9
Show file tree
Hide file tree
Showing 6 changed files with 483 additions and 2 deletions.
3 changes: 3 additions & 0 deletions mnn_project/config.ini
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[LaneNet]
# 模型文件路径
model_file_path=~/MNN-0.2.1.0/beec_task/lane_detection/model/lanenet_model.mnn
155 changes: 155 additions & 0 deletions mnn_project/config_parser.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
/************************************************
* Author: MaybeShewill-CV
* File: configParser.cpp
* Date: 2019/10/10 上午10:39
************************************************/

#include "config_parser.h"

#include <algorithm>
#include <cctype>
#include <fstream>
#include <iostream>
#include <sstream>
#include <string>

namespace beec {
namespace config_parse_utils {

ConfigParser::ConfigParser(const std::string &filename) {

std::ifstream fin(filename);

if (fin.good()) {
std::string line;
std::string current_header = "";
while (std::getline(fin, line)) {
trim(line);

// Skip empty lines
if (line.size() == 0)
continue;

switch (line[0]) {
case '#':
case ';':
// Ignore comments
break;
case '[':
// Section header
current_header = read_header(line);
break;
default:
// Everything else will be configurations
read_configuration(line, current_header);
}
}
fin.close();
} else {
throw std::runtime_error("File `" + filename + "` does not exist");
}
}

std::map<std::string, std::string> ConfigParser::get_section(const std::string &section_name) const {

if (_m_sections.count(section_name) == 0) {
std::string error = "No such key: `" + section_name + "`";
throw std::out_of_range(error);
}
return _m_sections.at(section_name);
}

std::map<std::string, std::string> ConfigParser::operator[](const std::string &section_name) const {

if (_m_sections.count(section_name) == 0) {
std::string error = "No such key: `" + section_name + "`";
throw std::out_of_range(error);
}
return _m_sections.at(section_name);
}

void ConfigParser::dump(FILE *log_file) {

// Set up iterators
std::map<std::string, std::string>::iterator itr1;
std::map<std::string, std::map<std::string, std::string> >::iterator itr2;
for (itr2 = _m_sections.begin(); itr2 != _m_sections.end(); itr2++) {
fprintf(log_file, "[%s]\n", itr2->first.c_str());
for (itr1 = itr2->second.begin(); itr1 != itr2->second.end(); itr1++) {
fprintf(log_file, "%s=%s\n", itr1->first.c_str(), itr1->second.c_str());
}
}
}

std::string ConfigParser::read_header(const std::string &line) {

if (line[line.size() - 1] != ']')
throw std::runtime_error("Invalid section header: `" + line + "`");
return trim_copy(line.substr(1, line.size() - 2));
}

void ConfigParser::read_configuration(const std::string &line, const std::string &header) {
if (header == "") {
std::string error = "No section provided for: `" + line + "`";
throw std::runtime_error(error);
}

if (line.find('=') == std::string::npos) {
std::string error = "Invalid configuration: `" + line + "`";
throw std::runtime_error(error);
}

std::istringstream iss(line);
std::string key;
std::string val;
std::getline(iss, key, '=');

if (key.size() == 0) {
std::string error = "No key found in configuration: `" + line + "`";
throw std::runtime_error(error);
}

std::getline(iss, val);

_m_sections[header][trim_copy(key)] = trim_copy(val);
}

// trim from start (in place)
void ConfigParser::ltrim(std::string &s) {
s.erase(s.begin(), std::find_if(s.begin(), s.end(), [](int ch) {
return !std::isspace(ch);
}));
}

// trim from end (in place)
void ConfigParser::rtrim(std::string &s) {
s.erase(std::find_if(s.rbegin(), s.rend(), [](int ch) {
return !std::isspace(ch);
}).base(), s.end());
}

// trim from both ends (in place)
void ConfigParser::trim(std::string &s) {
ltrim(s);
rtrim(s);
}

// trim from start (copying)
std::string ConfigParser::ltrim_copy(std::string s) {
ltrim(s);
return s;
}

// trim from end (copying)
std::string ConfigParser::rtrim_copy(std::string s) {
rtrim(s);
return s;
}

// trim from both ends (copying)
std::string ConfigParser::trim_copy(std::string s) {
trim(s);
return s;
}
}
}
64 changes: 64 additions & 0 deletions mnn_project/config_parser.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
/************************************************
* Author: MaybeShewill-CV
* File: configParser.h
* Date: 2019/10/10 上午10:39
************************************************/

#ifndef MNN_CONFIGPARSER_H
#define MNN_CONFIGPARSER_H

// Config parser

#include <exception>
#include <stdio.h>
#include <string>
#include <map>

const extern int __CONFIG_BUFFER_SIZE;

namespace beec {
namespace config_parse_utils {

class ConfigParser {

using config_values = std::map<std::string, std::string>;
public:
explicit ConfigParser(const std::string& filename);

~ConfigParser() = default;

config_values get_section(const std::string& section_name) const;

config_values operator[](const std::string& section_name) const;

void dump(FILE* log_file);

private:
std::map<std::string, std::map<std::string, std::string> > _m_sections;

std::string read_header(const std::string& line);

void read_configuration(const std::string& line, const std::string& header);

// trim from start (in place)
void ltrim(std::string &s);

// trim from end (in place)
void rtrim(std::string &s);

// trim from both ends (in place)
void trim(std::string &s);

// trim from start (copying)
std::string ltrim_copy(std::string s);

// trim from end (copying)
std::string rtrim_copy(std::string s);

// trim from both ends (copying)
std::string trim_copy(std::string s);
};
}
}

#endif //MNN_CONFIGPARSER_H
4 changes: 2 additions & 2 deletions mnn_project/freeze_lanenet_model.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# @Time : 2019/11/5 下午4:53
# @Author : LuoYao
# @Site : ICode
# @Author : MaybeShewill-CV
# @Site : https://github.com/MaybeShewill-CV/lanenet-lane-detection
# @File : freeze_lanenet_model.py.py
# @IDE: PyCharm
"""
Expand Down
162 changes: 162 additions & 0 deletions mnn_project/lanenet_model.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
/************************************************
* Author: MaybeShewill-CV
* File: lanenetModel.cpp
* Date: 2019/11/5 下午5:19
************************************************/

#include "lanenet_model.h"

#include <glog/logging.h>

#include <AutoTime.hpp>

namespace lane_detection {
/******************Public Function Sets***************/

/***
*
* @param config
*/
LaneNet::LaneNet(const beec::config_parse_utils::ConfigParser &config) {
using config_content = std::map<std::string, std::string>;

config_content config_section;
try {
config_section = config["LaneNet"];
} catch (const std::out_of_range& e) {
LOG(ERROR) << e.what();
LOG(ERROR) << "Can not get LaneNet section content in config file, please check again";
_m_successfully_initialized = false;
return;
}

if (config_section.find("model_file_path") == config_section.end()) {
LOG(ERROR) << "Can not find \"model_file_path\" field in config section";
_m_successfully_initialized = false;
return;
} else {
_m_lanenet_model_file_path = config_section["model_file_path"];
}

_m_lanenet_model = std::unique_ptr<MNN::Interpreter>(MNN::Interpreter::createFromFile(
_m_lanenet_model_file_path.c_str()));
if (nullptr == _m_lanenet_model) {
LOG(ERROR) << "Construct lanenet mnn interpreter failed";
_m_successfully_initialized = false;
return;
}

MNN::ScheduleConfig mnn_config;
mnn_config.type = MNN_FORWARD_CPU;
mnn_config.numThread = 4;

MNN::BackendConfig backend_config;
backend_config.precision = MNN::BackendConfig::Precision_High;
backend_config.power = MNN::BackendConfig::Power_High;
mnn_config.backendConfig = &backend_config;

_m_lanenet_session = _m_lanenet_model->createSession(mnn_config);
if (nullptr == _m_lanenet_session) {
LOG(ERROR) << "Construct laneNet mnn session failed";
_m_successfully_initialized = false;
return;
}

std::string input_node_name = "lanenet/input_tensor";
std::string pix_embedding_output_name = "lanenet/final_pixel_embedding_output";
std::string binary_output_name = "lanenet/final_binary_output";
_m_input_tensor_host = _m_lanenet_model->getSessionInput(
_m_lanenet_session, input_node_name.c_str());
_m_binary_output_tensor_host = _m_lanenet_model->getSessionOutput(
_m_lanenet_session, binary_output_name.c_str());
_m_pix_embedding_output_tensor_host = _m_lanenet_model->getSessionOutput(
_m_lanenet_session, pix_embedding_output_name.c_str());
_m_input_node_size_host.width = _m_input_tensor_host->width();
_m_input_node_size_host.height = _m_input_tensor_host->height();

for (auto i : _m_binary_output_tensor_host->shape()) {
LOG(INFO) << i;
}

_m_successfully_initialized = true;
return;
}

/***
* Destructor
*/
LaneNet::~LaneNet() {
_m_lanenet_model->releaseModel();
_m_lanenet_model->releaseSession(_m_lanenet_session);
}

/***
* Detect lanes on image using lanenet model
* @param input_image
* @param binary_seg_result
* @param pix_embedding_result
*/
void LaneNet::detect(const cv::Mat &input_image, cv::Mat &binary_seg_result, cv::Mat &pix_embedding_result) {

// preprocess
cv::Mat input_image_copy;
input_image.copyTo(input_image_copy);
{
AUTOTIME
preprocess(input_image, input_image_copy);
}

// run session
MNN::Tensor input_tensor_user(_m_input_tensor_host, MNN::Tensor::DimensionType::TENSORFLOW);
{
AUTOTIME
auto input_tensor_user_data = input_tensor_user.host<float>();
auto input_tensor_user_size = input_tensor_user.size();
::mempcpy(input_tensor_user_data, input_image_copy.data, input_tensor_user_size);

_m_input_tensor_host->copyFromHostTensor(&input_tensor_user);
_m_lanenet_model->runSession(_m_lanenet_session);
}

// output graph node
MNN::Tensor binary_output_tensor_user(
_m_binary_output_tensor_host, MNN::Tensor::DimensionType::TENSORFLOW);
MNN::Tensor pix_embedding_output_tensor_user(
_m_pix_embedding_output_tensor_host, MNN::Tensor::DimensionType::TENSORFLOW);
_m_binary_output_tensor_host->copyToHostTensor(&binary_output_tensor_user);
_m_pix_embedding_output_tensor_host->copyToHostTensor(&pix_embedding_output_tensor_user);

auto binary_output_data = binary_output_tensor_user.host<float>();
cv::Mat binary_output_mat(_m_input_node_size_host, CV_32FC1, binary_output_data);
binary_output_mat *= 255;
binary_output_mat.convertTo(binary_seg_result, CV_8UC1);

auto pix_embedding_output_data = pix_embedding_output_tensor_user.host<float>();
cv::Mat pix_embedding_output_mat(
_m_input_node_size_host, CV_32FC4, pix_embedding_output_data);
pix_embedding_output_mat.convertTo(pix_embedding_result, CV_8UC4);
}

/***************Private Function Sets*******************/

/***
* Resize image and scale image into [-1.0, 1.0]
* @param input_image
* @param output_image
*/
void LaneNet::preprocess(const cv::Mat &input_image, cv::Mat& output_image) {

if (input_image.type() != CV_32FC3) {
input_image.convertTo(output_image, CV_32FC3);
}

if (output_image.size() != _m_input_node_size_host) {
cv::resize(output_image, output_image, _m_input_node_size_host);
}

cv::divide(output_image, cv::Scalar(127.5, 127.5, 127.5), output_image);
cv::subtract(output_image, cv::Scalar(1.0, 1.0, 1.0), output_image);

return;
}
}
Loading

0 comments on commit 9dba8a9

Please sign in to comment.