c#调用c++ dll传输结构体数组
c++ dll
根据之前的c++ dll书写方法
将C++代码编译成一个dll文件
(1)在之前的C++代码上,在解决方案资源管理器中新建一个头文件(.h)
(2)在新建的头文件中,输入以下内容:
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <opencv2/opencv.hpp>
#include <iostream>
#include <math.h>
#include <opencv2/highgui/highgui_c.h>
#include <string>
#include <unordered_map>
#include <map>
#include <iomanip>
#include <cmath>
#include <string>
#include <vector>
using namespace std;
using namespace cv;
class Triple {
private:
char* _color;
float _percentage;
public:
Triple(char* color, float percentage) {
_color = color;
_percentage = percentage;
}
virtual ~Triple() {}
char* Getcolor() { return _color; }
float Getpercentage() { return _percentage; }
};
extern "C" __declspec(dllexport) void Mat_color_Find(char* qimage);
extern "C" __declspec(dllexport) void hsv_percentage(Mat hsv_image);//因为c#与c++之间,string不能直接转换
这里封装一个类Triple,包含两个变量,构造函数和析构函数,两个方法。
(3)在之前的C++文件中,直接修改代码
#include "hsv_percentage.h"
using namespace std;
using namespace cv;
unordered_map<char*, float> record;
typedef struct {
char color[32];
float percentage;
}Hsv;
Triple* triple;
extern "C" __declspec(dllexport) Hsv * Create() {
//Hsv hsv1[9];
Hsv* hsv = (Hsv*)malloc(sizeof(Hsv) * 9);
//triple = new Triple();
int i = 0;
for (auto it = record.begin(); it != record.end(); it++) {
//cout << it->first << " " << it->second << endl;
triple = new Triple(it->first,it->second);
strcpy_s(hsv[i].color, triple->Getcolor());
hsv[i].percentage = triple->Getpercentage();
i++;
}
return hsv;
}
/*
区分不同颜色,在图片中所占百分比
*/
void hsv_percentage(Mat hsv_image) {
int num_black = 0;
int num_grey = 0;
int num_white = 0;
int num_red = 0;
int num_orange = 0;
int num_yellow = 0;
int num_green = 0;
int num_blue = 0;
int num_purple = 0;
//vector<float> record(9,0);
float area = (float)(hsv_image.rows * hsv_image.cols);
for (int i = 0; i < hsv_image.rows; i++) //行数
{
for (int j = 0; j < hsv_image.cols; j++) //列数
{
//在这里操作具体元素
//{"black", 0, 0, 0, 180, 255, 46}
if ((hsv_image.at<Vec3b>(i, j)[0] >= 0 && hsv_image.at<Vec3b>(i, j)[0] <= 180)
&& (hsv_image.at<Vec3b>(i, j)[1] >= 0 && hsv_image.at<Vec3b>(i, j)[1] <= 255)
&& (hsv_image.at<Vec3b>(i, j)[2] >= 0 && hsv_image.at<Vec3b>(i, j)[2] <= 46)) {
num_black++;
}
//{ "grey",0,0,46,180,43,220 }
else if ((hsv_image.at<Vec3b>(i, j)[0] >= 0 && hsv_image.at<Vec3b>(i, j)[0] <= 180)
&& (hsv_image.at<Vec3b>(i, j)[1] >= 0 && hsv_image.at<Vec3b>(i, j)[1] <= 43)
&& (hsv_image.at<Vec3b>(i, j)[2] >= 46 && hsv_image.at<Vec3b>(i, j)[2] <= 220)) {
num_grey++;
}
// { "white",0,0,221,180,30,255 }
else if ((hsv_image.at<Vec3b>(i, j)[0] >= 0 && hsv_image.at<Vec3b>(i, j)[0] <= 180)
&& (hsv_image.at<Vec3b>(i, j)[1] >= 0 && hsv_image.at<Vec3b>(i, j)[1] <= 30)
&& (hsv_image.at<Vec3b>(i, j)[2] >= 221 && hsv_image.at<Vec3b>(i, j)[2] <= 255)) {
num_white++;
}
//{ "red", 156, 43, 46, 180, 255, 255 }
else if ((hsv_image.at<Vec3b>(i, j)[0] >= 156 && hsv_image.at<Vec3b>(i, j)[0] <= 180)
&& (hsv_image.at<Vec3b>(i, j)[1] >= 43 && hsv_image.at<Vec3b>(i, j)[1] <= 255)
&& (hsv_image.at<Vec3b>(i, j)[2] >= 46 && hsv_image.at<Vec3b>(i, j)[2] <= 255)) {
num_red++;
}
else if ((hsv_image.at<Vec3b>(i, j)[0] >= 0 && hsv_image.at<Vec3b>(i, j)[0] <= 10)
&& (hsv_image.at<Vec3b>(i, j)[1] >= 43 && hsv_image.at<Vec3b>(i, j)[1] <= 255)
&& (hsv_image.at<Vec3b>(i, j)[2] >= 46 && hsv_image.at<Vec3b>(i, j)[2] <= 255)) {
num_red++;
}
//{ "orange",11,43,46,25,255,255 }
else if ((hsv_image.at<Vec3b>(i, j)[0] >= 11 && hsv_image.at<Vec3b>(i, j)[0] <= 25)
&& (hsv_image.at<Vec3b>(i, j)[1] >= 43 && hsv_image.at<Vec3b>(i, j)[1] <= 255)
&& (hsv_image.at<Vec3b>(i, j)[2] >= 46 && hsv_image.at<Vec3b>(i, j)[2] <= 255)) {
num_orange++;
}
// { "yellow", 26, 43, 46, 34, 255, 255 }
else if ((hsv_image.at<Vec3b>(i, j)[0] >= 26 && hsv_image.at<Vec3b>(i, j)[0] <= 34)
&& (hsv_image.at<Vec3b>(i, j)[1] >= 43 && hsv_image.at<Vec3b>(i, j)[1] <= 255)
&& (hsv_image.at<Vec3b>(i, j)[2] >= 46 && hsv_image.at<Vec3b>(i, j)[2] <= 255)) {
num_yellow++;
}
//{ "green",35,43,46,99,255,255 },
else if ((hsv_image.at<Vec3b>(i, j)[0] >= 35 && hsv_image.at<Vec3b>(i, j)[0] <= 99)
&& (hsv_image.at<Vec3b>(i, j)[1] >= 43 && hsv_image.at<Vec3b>(i, j)[1] <= 255)
&& (hsv_image.at<Vec3b>(i, j)[2] >= 46 && hsv_image.at<Vec3b>(i, j)[2] <= 255)) {
num_green++;
}
//{ "blue",100,43,46,124,255,255 },
else if ((hsv_image.at<Vec3b>(i, j)[0] >= 100 && hsv_image.at<Vec3b>(i, j)[0] <= 124)
&& (hsv_image.at<Vec3b>(i, j)[1] >= 43 && hsv_image.at<Vec3b>(i, j)[1] <= 255)
&& (hsv_image.at<Vec3b>(i, j)[2] >= 46 && hsv_image.at<Vec3b>(i, j)[2] <= 255)) {
num_blue++;
}
// { "purple",125,43,46,155,255,255 }
else if ((hsv_image.at<Vec3b>(i, j)[0] >= 125 && hsv_image.at<Vec3b>(i, j)[0] <= 155)
&& (hsv_image.at<Vec3b>(i, j)[1] >= 43 && hsv_image.at<Vec3b>(i, j)[1] <= 255)
&& (hsv_image.at<Vec3b>(i, j)[2] >= 46 && hsv_image.at<Vec3b>(i, j)[2] <= 255)) {
num_purple++;
}
}
}
record.insert(make_pair((char*)"black", (float)num_black / area));
record.insert(make_pair((char*)"grey", (float)num_grey / area));
record.insert(make_pair((char*)"white", (float)num_white / area));
record.insert(make_pair((char*)"red", (float)num_red / area));
record.insert(make_pair((char*)"orange", (float)num_orange / area));
record.insert(make_pair((char*)"yellow", (float)num_yellow / area));
record.insert(make_pair((char*)"green", (float)num_green / area));
record.insert(make_pair((char*)"blue", (float)num_blue / area));
record.insert(make_pair((char*)"purple", (float)num_purple / area));
//(float)num / (float)(hsv_image.rows * hsv_image.cols);
return;
}
/*
在图片里查找指定颜色的比例
*/
void Mat_color_Find(char* qimage)
{
Mat image = imread(qimage);//将图片加载进来
if (image.empty())
{
cout << "could not load image...\n" << endl;
return;
}
Mat hsv_image;
cvtColor(image, hsv_image, CV_BGR2HSV);
hsv_percentage(hsv_image);
//rat = (float)num / (float)(hsv_image.rows * hsv_image.cols);
/*for (auto it = temp.begin(); it != temp.end(); it++) {
cout << it->first << " " << it->second << endl;
}*/
//Hsv* Create();
return;
}
本来我想直接,传unordered_map,但是,不同语言直接,无法之间传递不同的数据结构,对于C#调用C++,我采用的是结构体数组的方法。因为,我有9种颜色,一个结构体里面变量太多,所以,传递一个结构体数组即可。这里,主要介绍一下,结构体数组的传递方法:
//首先构建一个结构体
typedef struct {
char color[32];//为什么不传string,因为,从c#与c++数据对应关系不一样,直接传string,c#找不到内存地址
float percentage;
}Hsv;
//类
Triple* triple;
//返回结构体的指针地址,如果是数组,这个指针得加,不然,c#里面打印乱码
extern "C" __declspec(dllexport) Hsv * Create() {
//Hsv hsv1[9];
Hsv* hsv = (Hsv*)malloc(sizeof(Hsv) * 9);//就是这里得 * 9,因为,一个结构体是(Hsv*)malloc(sizeof(Hsv)),9种颜色偏移9
//triple = new Triple();
//数组初始化
int i = 0;
for (auto it = record.begin(); it != record.end(); it++) {
//cout << it->first << " " << it->second << endl;
triple = new Triple(it->first,it->second);
strcpy_s(hsv[i].color, triple->Getcolor());
hsv[i].percentage = triple->Getpercentage();
i++;
}
return hsv;
}
(4)在源文件文件夹下新建模块定义文件(.def),输入以下内容:
LIBRARY hsv_percentage
EXPORTS Mat_color_Find
EXPORTS hsv_percentage
EXPORTS Create
(5)生成解决方案,有问题看这里
C#调用dll文件
(1)新建一个C#项目:
(2)把hsv_percentage.dll文件复制到该工程的Debug目录下:
(3)在C#文件中引用该 .dll 文件,代码如下:
using System;
using System.Runtime.InteropServices;
using System.Collections.Generic;
namespace ConsoleApp7
{
class Program
{
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct Triple
{
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
public string color;
public float percentage;
};
[DllImport("hsv_percentage.dll")]
public static extern bool Mat_color_Find(string qimage);
[DllImport("hsv_percentage.dll")]
public static extern IntPtr Create();
public static Dictionary<string, float> CalcColorHist(string picpath) {
Dictionary<string, float> color_temp = new Dictionary<string, float>();
Mat_color_Find(picpath);
int workStationCount = 9;
int size = Marshal.SizeOf(typeof(Triple));
//IntPtr infosIntptr = Marshal.AllocHGlobal(size * workStationCount);
Triple[] triples = new Triple[workStationCount];
for (int i = 0; i < workStationCount; i++)
{
IntPtr ptr = Create() + i * size;
triples[i] = (Triple)Marshal.PtrToStructure(ptr, typeof(Triple));
/*Console.WriteLine(triples[i].color);
Console.WriteLine(triples[i].percentage);*/
color_temp.Add(triples[i].color, triples[i].percentage);
}
foreach (KeyValuePair<string, float> kvp in color_temp)
{
Console.WriteLine("Key = {0}, Value = {1}", kvp.Key, kvp.Value);
}
Console.ReadKey();
return color_temp;
}
static void Main(string[] args)
{
string s1 = "C:/Users/wenhaofu/Desktop/picture/2021-07-01.png";
CalcColorHist(s1);
}
}
}
(5)点击运行:
一些问题
关于c#中找不到函数的问题,你还需要包含opencv_world410d.dll