最近,老师在做项目,要我实现上述标题需求。
配置环境:
系统:win7 X64
工具:vs2012
使用工具:OpenCVSharp
第一步:
主要工作为:怎么让openCV在C#的环境下进行使用?我们可以使用”障眼法“。
1、刚开始,是打算用emguCV搭建,但是工作过程中,由于emguCV在win7中对应的opencv的最新版本只有2.4.2,而我们想用的工具是vs2012,在配置emguCV之前,要先搭载openCV环境,一般的环境搭建的教程,都是VS2012+2.4.3的版本,所以放弃了使用这一工具。
2、后来经过搜索,打算用OpenCvSharp,这个配置简单,而且现在和openCV更新的一样快,版本已经到2.4.9了
这是openCVSharp的配置过程如下:
http://blog.csdn.net/sussii/article/details/8521635
这是在C#环境中opencv关于C++的一些API的应用:
https://github.com/shimat/opencvsharp/wiki/%5BCpp%5D-Accessing-Pixel
这里面既有C的API,又有C++的API的一些例子,在C#环境下
https://github.com/shimat/opencvsharp/wiki
这里是openCvSharp的一些教程
http://www.boyunjian.com/v/softd/OpenCVSharp.html
这里是openCvSharp对应的openCV的各种版本的下载和Sample
https://github.com/shimat/opencvsharp/releases
下载对应的openCvSharp版本,就可以根据配置过程进行配置,配置完成以后,可以在第二个网址中找一些在C#环境中opencv关于C++的一些API
进行测试。
我遇到的问题:报异常
“System.TypeInitializationException”类型的未经处理的异常在 OpenCvSharp_test.exe 中发生
其他信息: “OpenCvSharp.CPlusPlus.Mat”的类型初始值设定项引发异常。
原因:是因为在openCVsharp中的一个Dll没有拷贝到release或者debug下(至于是哪个,要看你是在那个环境下开发),这个库是OpenCvSharpExtern.dll这个库还不能在reference下引用,报错误:请确保是一个有效的程序集或者COM组件。把他直接拷贝到release下,或者Debug下就行。
第二步:环境配好了,我们下面就用这个环境,用C++建立动态链接库我就不多说了,在这里给一个参考网址,都是我测试过的。这个网址中内容的前三步是用C++建立动态链接库:
http://blog.sina.com.cn/s/blog_6fe1657d0100t72v.html
第四步以后就是我自己的了,下面是我在Dll中写的代码(已经测试成功),我这个DLL的名字是DemoDll.dll
<span style="font-size:14px;">#include "stdafx.h"
#include <opencv2/opencv.hpp>
using namespace cv;
extern "C" __declspec(dllexport) void Show()
{
Mat image = imread("1.jpg");
namedWindow("image");
imshow("image",image);
waitKey(0);
return ;
}</span>
第三步,在C#中用动态链接库(DLL),代码:
<span style="font-size:14px;">using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using System.Text;
//using OpenCvSharp;
//namespace OpenCvSharp_test
//{
// static class Program
// {
// /// <summary>
// /// 应用程序的主入口点。
// /// </summary>
// [STAThread]
// static void Main()
// {
// IplImage src = Cv.LoadImage("d:\\lena.jpg", LoadMode.GrayScale);
// IplImage dst = Cv.CreateImage(new CvSize(src.Width, src.Height), BitDepth.U8, 1);
// Cv.Canny(src, dst, 50, 200);
// Cv.NamedWindow("src image");
// Cv.ShowImage("src image", src);
// Cv.NamedWindow("dst image");
// Cv.ShowImage("dst image", dst);
// Cv.WaitKey(0);
// Cv.DestroyAllWindows();
// Cv.ReleaseImage(src);
// Cv.ReleaseImage(dst);
// Application.EnableVisualStyles();
// Application.SetCompatibleTextRenderingDefault(false);
// Application.Run(new Form1());
// }
// }
//}
//以上的注释部分是针对openCV2.0以前的关于C的接口的</span>
//下面的是针对C++接口的</span>
using OpenCvSharp;
using OpenCvSharp.CPlusPlus;
static class Program
{
/*[DllImport("dll_test.dll")]
public static extern int test2(Mat image,ref float fudian);
[DllImport("AddDll.dll")]
public static extern int Add(ref int x,ref int y);*/
[DllImport("DemoDll.dll")]
public static extern void Show();
static void Main()
{
Show(); //这是dll中的函数
}
}
</span>
注意的问题:1、这里在用C++生成DLL的时候,和在C#中使用DLL时候,环境要相同,否则会报异常。我的是X64系统,和vs2012。所以生成DLL的环境也应该是这个,C#的环境也是这个。
2、我这个还遇到的问题是传递参数的问题,若果你传递的是对于 int*, int&, 则都可用 ref int 对应。对于一些字符串,指针的参数什么的,这篇文章有详细说明:
http://jljlpch.iteye.com/blog/520509
但是上述文章中讲的并不是过于直观,所以这里还是给出一个例子,例子主要介绍的是参数传递的问题,代码中主要传递的参数有int ,char * 结构体,如下:
C++生成的Dll中的代码:
/*
实现功能:将一个图片中,所在行的像素值,按照一定的间隔(列数),将对应点的像素值提取出来。
*/
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/core/core.hpp"
#include <iostream>
#include <stdio.h>
#include <time.h>
using namespace std;
using namespace cv;
struct Node
{
int R;
int G;
int B;
};
extern "C" _declspec(dllexport) bool operator_Image(char *path , int rownum,int intervalNum,struct Node *Result,int *Num)
{
Mat src = imread(path);
int rows,cols;
int x = 0,y = 0;
//cout << src.row(100) << endl;
rows = src.rows;
cols = src.cols;
if (src.empty())
{
cout << "图片不存在!" << endl;
}
if (rows < intervalNum)
{
cout << "你输入的间隔有误!!" << endl;
}
//创建动态数组,用来保存像素的值
//Result = new int[cols/intervalNum*3*sizeof(int)];
//int savedata[10000] = {0};
*Num = cols/intervalNum*3;
int i = 0;
while(x<cols)
{
y = rownum;
//Result[i++] = src.at<Vec3b>(y,x)[0];
//Result[i++] = src.at<Vec3b>(y,x)[1];
//Result[i++] = src.at<Vec3b>(y,x)[2];
Result[i].G = src.at<Vec3b>(y,x)[0];
Result[i].B = src.at<Vec3b>(y,x)[1];
Result[i].R = src.at<Vec3b>(y,x)[2];
/*if (x%100 == 0)
{
printf("%d ",src.at<Vec3b>(y,x)[0]);
printf("%d ",src.at<Vec3b>(y,x)[1]);
printf("%d ",src.at<Vec3b>(y,x)[2]);
}*/
x = x+intervalNum;
i++;
}
return true;
}
C#生成的工程调用C++的dll代码如下:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;
public struct Node
{
int R;
int G;
int B;
};
namespace TestLSPVC
{
public partial class Form1 : Form
{
[DllImport("readcolpixelDll.dll", EntryPoint = "operator_Image", CharSet = CharSet.Ansi)]
public static extern bool operator_Image(string path , int rownum,int intervalNum, ref Node Result,ref int Num);
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
string path = "c:\\lena.jpg";
Node[] x = new Node[1000];
int Count=0;
operator_Image(path,100,100,ref x[0],ref Count);
}
}
}
3、本来在这里传递的参数是opencv的函数,如Mat,但是总是出现异常为:
这个错误托管调试助手“NonComVisibleBaseClass”在“D:\13liushuanpeng\OpenCvSharp_test\OpenCvSharp_test\bin\Release\OpenCvSharp_test.vshost.exe”中检测到故障。
其他信息: 执行了 QueryInterface 调用,请求提供 COM 可见的托管类“OpenCvSharp.CPlusPlus.Mat”的类接口。不过,由于该类是从非 COM 可见的类“OpenCvSharp.DisposableCvObject”派生的,QueryInterface 调用将失败。这样做的目的是避免非 COM 可见的基类受 COM 版本规则的约束。
目前还没有解决,希望有知道的联系我。