# .h文件
#pragma once
#include
#include
#include
#ifdef ImageHandleDLL_EXPORTS
#define ImageHandle_EXPORTS extern "C" __declspec(dllexport)
#else
#define ImageHandle_EXPORTS extern "C" __declspec(dllimport)
#endif
typedef enum
{
OPERATION_SUCCESS = (0),
INPUT_CHANNELS_ERR = (1),
INPUT_EMPTY_ERR = (2),
PROCESS_FAILE = (3),
} ErrCode;
ImageHandle_EXPORTS ErrCode Read_Image(char * filepath, unsigned char **output_image_data, int &image_h, int &image_w, int &input_image_channels);
ImageHandle_EXPORTS ErrCode Write_Image(unsigned char **intput_image_data, char * filepath, int image_h, int image_w, int input_image_channels);
ImageHandle_EXPORTS ErrCode Image_Gray(unsigned char **input_image_data, unsigned char **output_image_data, int image_h, int image_w, int input_image_channels = 3);
# .cpp文件
ErrCode Read_Image(char * filepath, unsigned char **output_image_data, int &image_h, int &image_w, int &input_image_channels)
{
try {
cv::Mat src = cv::imread(filepath);
image_h = src.rows;
image_w = src.cols;
input_image_channels = src.channels();
if (output_image_data[0] == nullptr) {
output_image_data[0] = (unsigned char *)malloc(image_h*image_w *input_image_channels * sizeof(unsigned char));
}
memcpy(output_image_data[0], src.data, image_h * image_w * input_image_channels * sizeof(unsigned char));
return OPERATION_SUCCESS;
}
catch (std::exception e) {
if (output_image_data[0])
{
free(output_image_data[0]);
output_image_data = nullptr;
}
std::cout << e.what() << std::endl;
return PROCESS_FAILE;
}
}
ErrCode Write_Image(unsigned char **input_image_data, char * filepath, int image_h, int image_w, int input_image_channels)
{
try {
if (input_image_channels == 4)
{
cv::Mat input_image(image_h, image_w, CV_8UC4, input_image_data[0]);
cv::imwrite(filepath, input_image);
}
else if (input_image_channels == 3) {
if (input_image_data) {
cv::Mat input_image(image_h, image_w, CV_8UC3, input_image_data[0]);
cv::imwrite(filepath, input_image);
}
}
else if (input_image_channels == 1)
{
cv::Mat input_image(image_h, image_w, CV_8UC1, input_image_data[0]);
cv::imwrite(filepath, input_image);
}
else
{
return INPUT_CHANNELS_ERR;
}
return OPERATION_SUCCESS;
}
catch (std::exception e) {
std::cout << e.what() << std::endl;
return PROCESS_FAILE;
}
}
ErrCode Image_Gray(unsigned char **input_image_data, unsigned char **output_image_data, int image_h, int image_w, int input_image_channels)
{
try {
if (input_image_data[0] == nullptr)
{
return INPUT_EMPTY_ERR;
}
if (output_image_data[0] == nullptr)
{
output_image_data[0] = (unsigned char *)malloc(image_h*image_w * 1 * sizeof(unsigned char));
}
cv::Mat output_image;
if (input_image_channels == 3) {
cv::Mat input_image(image_h, image_w, CV_8UC3, input_image_data[0]);
cv::cvtColor(input_image, output_image, cv::COLOR_BGR2GRAY);
}
else if (input_image_channels == 4) {
cv::Mat input_image(image_h, image_w, CV_8UC4, input_image_data[0]);
cv::cvtColor(input_image, output_image, cv::COLOR_BGRA2GRAY);
}
else if (input_image_channels == 1) {
memcpy(output_image_data[0], output_image.data, image_h*image_w * 1 * sizeof(unsigned char));
return OPERATION_SUCCESS;
}
else {
if (output_image_data[0])
{
free(output_image_data[0]);
output_image_data[0] = nullptr;
}
return INPUT_CHANNELS_ERR;
}
memcpy(output_image_data[0], output_image.data, image_h*image_w * 1 * sizeof(unsigned char));
return OPERATION_SUCCESS;
}
catch (std::exception e) {
if (output_image_data[0])
{
free(output_image_data[0]);
output_image_data[0] = nullptr;
}
std::cout << e.what() << std::endl;
return PROCESS_FAILE;
}
}
利用visual studio 2017新建一个windows控制台应用空项目。
修改.cs文件如下:
#.cs文件
using System;
using System.Runtime.InteropServices;
namespace app_project
{
class Program
{
[DllImport("ImageHandle.dll")]
public static extern int Read_Image(string filepath,ref UIntPtr output_image_data, ref int image_h, ref int image_w, ref int input_image_channels);
[DllImport("ImageHandle.dll")]
public static extern int Write_Image(ref UIntPtr intput_image_data, string filepath, int image_h, int image_w, int input_image_channels);
[DllImport("ImageHandle.dll")]
public static extern int Image_Gray(ref UIntPtr input_image_data,ref UIntPtr output_image_data, int image_h, int image_w, int input_image_channels = 3);
static void Main(string[] args)
{
Console.WriteLine("测试");
string path = "test_align.jpg";
UIntPtr input_image_data = new UIntPtr();
int image_height = 0;
int image_width = 0;
int image_channels = 0;
Read_Image(path,ref input_image_data,ref image_height,ref image_width,ref image_channels);
UIntPtr output_image_data = new UIntPtr();
Image_Gray(ref input_image_data, ref output_image_data, image_height, image_width, image_channels);
string path_1 = "test_align_gray.jpg";
Write_Image(ref output_image_data, path_1, image_height, image_width, 1);
Console.WriteLine("OK");
Console.Read();
}
}
}
每添加一个接口,均要有一条[DllImport("*.dll")]
, 示例如下:
[DllImport("ImageHandle.dll")]
public static extern IntPtr GetLibraryVersion();
[DllImport("ImageHandle.dll")]
public static extern int Read_Image(string filepath, ref UIntPtr output_image_data, ref int image_h, ref int image_w, ref int input_image_channels);
int &
, 而对应在c#中形参类型为ref int
,其中ref
参数表示变量作为参数传给方法时,同时希望在方法执行完成后,对参数所做的修改能够反映到变量上;示例如下:Add( int &h, int &w, int &sum);
C# 方式:
Add(ref int h, ref int w, ref int sum);
char *
, 而在c#中形参类型为string
,示例如下:Read_Image(char * filepath);
C# 方式:
Read_Image(string filepath);
unsigned char **
, 而在c#中形参类型为ref IntPtr
,示例如下:Read_Image(unsigned char **intput_image_data);
C# 方式:
Read_Image(ref UIntPtr intput_image_data);
上述c++接口中,传递数组不能采用unsigned char *
,其原因为:UIntPtr类型被称之为“平台特定的类型”,资源的大小取决于使用的硬件和操作系统,但其大小总是足以包含系统的指针,类似含有窗口句柄参数(HANDLE)。