mask rcnn onnxruntime c++ 学习笔记

Posted 东东就是我

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了mask rcnn onnxruntime c++ 学习笔记相关的知识,希望对你有一定的参考价值。

https://www.zhihu.com/question/37608201/answer/72766337
https://www.zhihu.com/question/31128857/answer/2183474280

1.指针和引用

1.1定义

C++primer中对 对象的定义:对象是指一块能存储数据并具有某种类型的内存空间一个对象a,它有值和地址&a,运行程序时,计算机会为该对象分配存储空间,来存储该对象的值,我们通过该对象的地址,来访问存储空间中的值指针p也是对象,它同样有地址&p和存储的值p,只不过,p存储的数据类型是数据的地址。如果我们要以p中存储的数据为地址,来访问对象的值,则要在p前加解引用操作符"",即p。对象有常量(const)和变量之分,既然指针本身是对象,那么指针所存储的地址也有常量和变量之分,指针常量是指,指针这个对象所存储的地址是不可以改变的,而指向常量的指针的意思是,不能通过该指针来改变这个指针所指向的对象。我们可以把引用理解成变量的别名。定义一个引用的时候,程序把该引用和它的初始值绑定在一起,而不是拷贝它。计算机必须在声明r的同时就要对它初始化,并且,r一经声明,就不可以再和其它对象绑定在一起了。实际上,你也可以把引用看做是通过一个常量指针来实现的,它只能绑定到初始化它的对象上。

1 .2 代码

引用的主要功能是传递函数的参数和返回值。C++语言中,函数的参数和返回值的传递方式有三种:值传递、指针传递和引用传递。
①:以下是“值传递”的示例程序。由于Func1 函数体内的x 是外部变量n 的一份拷贝,改变x 的值不会影响n, 所以n 的值仍然是0void Func1(int x)


    x = x + 10;

int n = 0;
Func1(n);
cout << “n =<< n << endl; // n = 0

②:以下是“指针传递”的示例程序。由于Func2 函数体内的x 是指向外部变量n 的指针,改变该指针的内容将导致n 的值改变,所以n 的值成为10void Func2(int *x)


    (* x) = (* x) + 10;

&#8943;
int n = 0;
Func2(&n);
cout << “n =<< n << endl; // n = 10

③:以下是“引用传递”的示例程序。由于Func3 函数体内的x 是外部变量n 的引用,x和n 是同一个东西,改变x 等于改变n,所以n 的值成为10void Func3(int &x)


    x = x + 10;

&#8943;
int n = 0;
Func3(n);
cout << “n =<< n << endl; // n = 10

2.关键字

2.1 static

可以修饰全局变量、局部变量和函数,都表示范围的限定

2.1const

表示只读的意思,不可修改

https://www.jb51.net/article/216790.htm
https://blog.csdn.net/u014779536/article/details/111239643

3.vector

empty(); //判断容器是否为空

capacity(); //容器的容量 capacity一定会大于等于size

size(); //返回容器中元素的个数

resize(int num); //重新指定容器的长度为num,若容器变长,则以默认值填充新的位置;若容器变短,则末尾超出的元素被删除

resize(int num,elem); //重新指定容器的长度为num,若容器变长,则以elem数值填充新的位置;若容器变短,则末尾超出的元素被删除

push_back(elem); //尾部插入元素elem

pop_back(); //删除最后一个元素

insert(const_iterator pos, elem); //迭代器指向位置pos插入元素elem

insert(const_iterator pos, int count,elem); //迭代器指向位置pos插入count个元素elem

erase(const_iterator pos); //删除迭代器指向的元素

erase(const_iterator start,const_iterator end); //删除迭代器start到end之间的元素

clear(); //删除容器中所有元素

std::vector::emplace_back (C++11)
在序列尾部生成一个元素。
emplace_back() 的执行效率比 push_back() 高。因此,在实际使用时,建议大家优先选用 emplace_back()。

vector.reserve的优势 申请n个元素的内存空间

https://blog.csdn.net/qq_21033779/article/details/78921997

4.namesapce

5.std

5.1 std::pair

std::pair主要的作用是将两个数据组合成一个数据,两个数据可以是同一类型或者不同类型。
pair实质上是一个结构体,其主要的两个成员变量是first和second,

5.2 std::move

从实现上讲,std::move基本等同于一个类型转换:

5.3 std::optional

std::optional用来包装可以为空的类型
std::optional或者为空,或者包含一个有效值
std::optional emptyDouble = std::nullopt;

https://blog.csdn.net/lemonxiaoxiao/article/details/108603916

5.4 std::unique_ptr

unique_ptr独占管理对象,只有移动语义。
unique_ptr可以不占用对象,即为空。可以通过reset()或者赋值nullptr释放管理对象。
标准库早期版本中定了auto_ptr,它具有unique_ptr的部分特征,但不是全部。例如不能在容器中保存auto_ptr,不能从函数中返回auto_ptr等等,这也是unique_ptr主要的使用场景。

https://blog.csdn.net/qq_36268040/article/details/107292201

6.for

有以下几种形式:
1) for(auto elem : range)
创建range的拷贝,遍历时无法修改range中的元素。
2) for(auto& elem : range)
不创建range的拷贝,可以直接修改range中的元素,但一般用以下这种形式。
for(auto&& elem : range)
3)) for(const auto & elem : range)
不创建range的拷贝,只读range中的元素。

7.推理代码

//
// Copyright note: Redistribution and use in source, with or without modification, are permitted.
// 
// Created: August 2017
// 
// @author:  Andreas Richert
// @author:  Marco Dierschke
// SICK AG, Waldkirch
// email: TechSupport0905@sick.de

#include <cstdio>
#include <iostream>
#include <memory>
#include <sstream>

#include <boost/shared_ptr.hpp>
#include <boost/make_shared.hpp>

#include "VisionaryControl.h"
#include "CoLaParameterReader.h"
#include "CoLaParameterWriter.h"
#include "VisionarySData.h"    // Header specific for the Stereo data
#include "VisionaryDataStream.h"
#include "PointXYZ.h"
#include "PointCloudPlyWriter.h"

#include <chrono>
#include <thread>

#include <windows.h>
#include <windowsx.h>
#include "opencv.hpp" //opencv 的头文件
#include <opencv2/core/core.hpp>  
#include <opencv2/opencv.hpp>
#include <opencv2/highgui/highgui.hpp>  
#include <opencv2/imgproc/imgproc.hpp> 

#include <vector>
#include <stdlib.h> 
#include <algorithm>
#include <fstream>
#include <assert.h>
#include <iomanip>
#include <onnxruntime_cxx_api.h>
#include <cuda_provider_factory.h>
#include <onnxruntime_c_api.h>
#include <math.h>

using namespace cv;
using namespace std;
const float maskThreshold = 0.5;
const float classconfThresh = 0.5;
std::vector<Ort::Value> ort_inputs;
const cv::Scalar& meanVal = cv::Scalar(123.7, 116.8, 103.9);
std::array<float, 14> input_meta_ =  0, 640, 512, 3, 640, 512, 3, 0, 0, 640, 512, 1, 0, 0 ;
std::array<float, 1 * 640 * 512 * 3> input_images_;
std::array<float, 1 * 81840 * 4> input_anchors_;
std::vector<int64_t> anchors_dim =  1, 81840, 4 ;
std::vector<int64_t> images_dim =  1, 640, 512, 3 ;
std::vector<int64_t> metas_dim =  1, 14 ;
Ort::Value anchors_input_tensor_ nullptr ;
Ort::Value images_input_tensor_ nullptr ;
Ort::Value metas_input_tensor_ nullptr ;
using DataOutputType = std::pair<float*, std::vector<int64_t>>;


inline cv::Mat visualizeOneImageWithMask(const cv::Mat& img, const std::vector<std::array<float, 4>>& bboxes,
	const std::vector<uint64_t>& classIndices, const std::vector<cv::Mat>& masks, std::vector<PointXYZ>& pointCloud,const float maskThreshold = 0.5)

	cv::Mat result = img.clone();

	for (size_t i = 0; i < bboxes.size(); ++i) 
		const auto& curBbox = bboxes[i];
		cv::Mat curMask = masks[i].clone();
		const cv::Scalar& curColor =  0,0,255 ;
		const std::string curLabel = "box";

		cv::rectangle(result, cv::Point(curBbox[0], curBbox[1]), cv::Point(curBbox[2], curBbox[3]), curColor, 2);

		int baseLine = 0;
		cv::Size labelSize = cv::getTextSize(curLabel, cv::FONT_HERSHEY_COMPLEX, 0.35, 1, &baseLine);
		cv::rectangle(result, cv::Point(curBbox[0], curBbox[1]),
			cv::Point(curBbox[0] + labelSize.width, curBbox[1] + static_cast<int>(1.3 * labelSize.height)),
			curColor, -1);
		cv::putText(result, curLabel, cv::Point(curBbox[0], curBbox[1] + labelSize.height), cv::FONT_HERSHEY_COMPLEX,
			0.35, cv::Scalar(255, 255, 255));

		// ---------------------------------------------------------------------//
		// Visualize masks

		const cv::Rect curBoxRect(cv::Point(curBbox[0], curBbox[1]), cv::Point(curBbox[2], curBbox[3]));

		cv::resize(curMask, curMask, curBoxRect.size());


		cv::Mat finalMask = (curMask > maskThreshold);

		cv::Mat coloredRoi = (0.3 * curColor + 0.7 * result(curBoxRect));

		coloredRoi.convertTo(coloredRoi, CV_8UC3);


		cv::Mat hierarchy;
		finalMask.convertTo(finalMask, CV_8U);
		std::vector<cv::Mat> contours;
		cv::findContours(finalMask, contours, hierarchy, cv::RETR_TREE, cv::CHAIN_APPROX_SIMPLE);
		for (auto elem : contours) 
			//绘制轮廓的最小外接矩形  以curboxrect左上角坐标为00点
			RotatedRect rect = minAreaRect(elem);
			Point2f P[4];
			rect.points(P);
			vector<int> X_Contours;

			for (int j = 0; j <= 3; j++)
			
				line(result(curBoxRect), P[j], P[(j + 1) % 4], Scalar(255, 255, 255), 2);
			
			Point2f center=rect.center;
			float center_x = center.x+ curBbox[0];
			float center_y = center.y+ curBbox[1];
			Size2f wh=rect.size;
			float w = wh.width;
			float h = wh.height;
			float angle=rect.angle;
			PointXYZ xyz=pointCloud.at(center_x * img.rows + center_y);
			printf("中心点:x=%f,y=%f\\n", center_x, center_y);
			printf("长度:h=%f,w=%f\\n", h, w);
			printf("角度:angle=%f\\n", angle);
			printf("现实坐标:x=%f,y=%f,z=%f\\n", xyz.x,xyz.y,xyz.z);
			
		
		

		cv::drawContours(coloredRoi, contours, -1, curColor, 5, cv::LINE_8, hierarchy, 100);
		coloredRoi.copyTo(result(curBoxRect), finalMask);


	

	return result;


void OrtDetection(Mat& img, Ort::Session& session, std::vector<PointXYZ> & pointCloud)


	///1.Prepare for the "input_image"//

	cv::Mat img_;
	img.convertTo(img_, CV_32FC3);
	img_ -= meanVal;
	float* image_output = input_images_.data();
	fill(input_images_.begin(), input_images_.end(), 0.f);
	for (int i = 0; i < img.rows; ++i) 
		for (int j = 0; j < img.cols; ++j) 
			for (int c = 0; c < 3; ++c) 
				image_output[c * img.rows * img.cols + i * img.cols + j] = img_.ptr<float>(i, j)[c];
			
		
	
	auto allocator_info = Ort::MemoryInfo::CreateCpu(OrtArenaAllocator, OrtMemTypeDefault);
	images_input_tensor_ = Ort::Value::CreateTensor<float>(allocator_info, input_images_.data(), input_images_.size(), images_dim.data(), images_dim.size());
	/2.Prepare for the "input_anchors"/

	std::ifstream data("anchors.txt");
	float* anchors_output = input_anchors_.data();
	fill(input_anchors_.begin(), input_anchors_.end(), 0.f);
	for (int c = 0; c < 1; c++) 
		for (int i = 0; i < 81840; i++) 
			for (int j = 0; j < 4; j++) 
				data >> setprecision(20) >> anchors_output[c * 81840 * 4 + i * 4 + j]; //We load the matrix from TXT for the calculation process of anchors
																				 //is too complex to be tranferred from Python.
			
		
	
	anchors_input_tensor_ = Ort::Value::CreateTensor<float>(allocator_info, input_anchors_.data(), input_anchors_.size(), anchors_dim.data(), anchors_dim.size());

	/3.Prepare for the "input_image_meta"/

	metas_input_tensor_ = Ort::Value::CreateTensor<float>(allocator_info, input_meta_.data(), input_meta_.size(), metas_dim.data(), metas_dim.size());

	/4.Prepare for the model Inputs & Outputs indications/

	ort_inputs.push_back(std::move(images_input_tensor_));
	ort_inputs.push_back(std::move(metas_input_tensor_));
	ort_inputs.push_back(std::move(anchors_input_tensor_));

	std::vector<const char*> input_names =  "input_image", "input_image_meta", "input_anchors" ;
	const char* const output_names[] =  "mrcnn_detection", "mrcnn_class", "mrcnn_bbox" , "mrcnn_mask", "ROI", "rpn_class", "rpn_bbox" ;
	//for (size_t i = 0; i < 10; i++)
	//
	double timeStart = (double)cv::getTickCount();
	std::vector<Ort::Value> ort_outputs = session.Run(Ort::RunOptions nullptr , input_names.data(),
		ort_inputs.data(), ort_inputs.size(),
		output_names, 7);
	double nTime = ((double)cv::getTickCount() - timeStart) / cv::getTickFrequency以上是关于mask rcnn onnxruntime c++ 学习笔记的主要内容,如果未能解决你的问题,请参考以下文章

『计算机视觉』Mask-RCNN_关键点检测分支(待续)

Mask-RCNN : 代码使用

MASK-RCNN是什么?MASK(掩膜)又是什么?

『计算机视觉』RCNN学习_其二:Mask-RCNN

检测论文综述(一) : 从RCNN到Mask-RCNN

Mask-RCNN,ValueError:无法将输入数组从形状(70)广播到形状(1)