csharp编写界面,opencv编写类库,解决 Pinvoke过程中的参数传递和平台调用问题

使用csharp 编写winform程序,不仅速度快,而且容易界面美化并找到其他类库的支持;而使用 opencv编写图形图像处理程序,是目前比较流行,而且高效的一种方法。如果需要将两者结合,需要解决的问题就是使用 csharp调用vc 下编写的库文件。两个难点,一个是平台调用的内存控制问题,一个是参数传递问题。关注点在解决实际问题

在现实中,我发现问题比较大的是两点,一点是内存控制问题,一个是平台调用问题。

一、内存控制:(1-6种方法是我验证后失败的方法,关注问题解决者可直接看第7点)

1、验证 opencv下的dll 程序是否能够对内存起到很好的控制。方法是将图片路径写在 dll文件中,使用csharp调用 dll文件,以此来验证是否是函数内部的溢出。

DllExport void imageprocesstest1()

{

vector<Mat> inputmat;

vector<cv::Point2f> points1;

vector<cv::Point2f> points2;

vector<Point> locmat1;vector<Point> locmat2;

char cur_dir[50];

char strimg [50];

for (int iimg = 1;iimg<=23;iimg++)

{

inputmat.clear();

points1.clear();

points2.clear();

locmat2.clear();

locmat1.clear();

sprintf(cur_dir, "D:\\t\\SteelNo%d\\Camera01" ,iimg);

Mat tmp;

//读取数据

for (int i =1;i<=10;i++)//执行全部文件的遍历

{

if (i<10)

{

sprintf(strimg, "%s\\image00000%d.jpg",cur_dir,i);

}

else

{

sprintf(strimg, "%s\\image0000%d.jpg",cur_dir,i);

}

cv::Mat src= cv::imread(strimg,0);

if (!src.data)

return;

inputmat.push_back(src);

}

InputAdjust(inputmat);

MulitMatch(inputmat,locmat1,locmat2,5);

Mat ma = MulitAlign(inputmat,locmat1,locmat2);

if (ma.rows == 2 || ma.rows ==3)

{

return ;

}

else

{

Mat mb;

mb =MulitBlend(inputmat,ma,locmat1,locmat2);

if (mb.rows == 1)

{

return;

}

else

{

sprintf(strimg, "%s\\3.jpg",cur_dir);

imwrite(strimg,mb);

}

}

}

return;

}

在这个函数中,我对d盘 t文件目录下的23个文件夹进行遍历,调用 InputAdjust,MulitMatch ,MulitBlend这 3个主要函数进行拼接操作。在运行状态下 (ctrl+F5),不溢出。

2、采用动态加载 dll文件的方式进行函数调用。(具体见 Zealic.Windows)

就是采用loaddll 的方式动态地将 dll调入程序中,并且采用freedll的方式动态地将 dll文件注销掉。这个方法在运行状态下 (ctrl+F5),溢出,没有效果。

3、采用轻量化代码生成的方法 (dynamicmethod)进行dll 文件的调用。

DynamicLibrary golib = new DynamicLibrary("GOImage.dll" );

NativeMethodBuilder goBuilder = new NativeMethodBuilder();

goBuilder.ParameterLength = 3;

goBuilder.SetParameterInfo(0, typeof(string ));

goBuilder.SetParameterInfo(1, typeof(string ));

goBuilder.SetParameterInfo(2, typeof(int ));

NativeMethod method = goBuilder.MakeMethod(golib, "imageprocess");

method.Invoke(strtmp, strImagePath_Res, 1);

同样溢出。以上方法在F5模式下都能够运行正常。

4、这个时候,我开始想是不是我的 dll那个地方的资源没有释放掉。所以我特地生成了一个简单的函数。

DllExport void imageprocesstest( char *cur_dir,char *imagepath_res)

{

char DllBuff[50];

vector<Mat> inputmat;

Mat src;

for (int i = 1;i<=10;i++)//执行全部文件的遍历

{

if (i<10)

{

sprintf(DllBuff, "%s\\image00000%d.jpg",cur_dir,i);

}

else

{

sprintf(DllBuff, "%s\\image0000%d.jpg",cur_dir,i);

}

src= cv::imread(DllBuff,CV_LOAD_IMAGE_COLOR);

if (!src.data)

{

inputmat.clear();

return ;

}

for (int j=0;j<10;j++) //采用这种方式

{

inputmat.push_back(src); //将读取的结果压入inutmat

}

}

vector<Mat> (inputmat).swap(inputmat);

return ;

}

它的调用采用

[DllImport( "GOImage.dll",

EntryPoint = "imageprocesstest",

CharSet = CharSet.Ansi, CallingConvention = CallingConvention .Cdecl)]

public static extern int imageprocesstest(string ImagePath, string ImagePath_Res);

这个函数不执行任何函数,唯一的作用就是讲图片读进去,然后清空。其中

vector<Mat> (inputmat).swap(inputmat);

叫做vector 的swap方法,是 effiective c++上面推荐的一种确实能够清空 vector的方法。而mat对象时 opencv的内建对象,自己带注销代码,而且其注销无法被显示调用。

这个时候,依然是ctrl+F5会溢出。

我认为,现在的情况是,在重复调用一个 dll文件的情况下(而且这个 dll文件需要若干秒的执行时间),会发生内存无法情况的情况。因为非托管方式下,垃圾回收器无法管理非托管代码内存。但是我已经显示地将内存注销了,只是不能被垃圾回收器回收。

5、所以我强制进行垃圾回收

Gc.colect();

依然没有效果。所以这个方向的问题我卡在了这里。

6、这个时候,我想到了以前通过 com调用matlab 函数的时候也出现过这样的问题,但是当时是个小项目,就采用了一种方法对付了一下。现在也想看一下这种方法是否可行。

我们要达到的效果,就是输入一个目录,下面是以某种方式保存的图片,然后 进行拼接,得到对应的拼接图片。是否可以采用这种形式

Csharp调用图像处理的 dll文件,同时向param.log文件中以固定格式写入需要处理的图片的参数。 Dll文件收到后,按照param.log中指定的参数进行处理,同时将结果写入 result.log,并且在完成后,返回一个值, csharp在收到这个值后,到指定的地方读取 param.log,并显示出来。

如果采用这种方法,就只需要调用几次 dll文件,那么内存溢出的问题就不会影响到系统的稳定。但是这个问题仍然没有被解决。

7、最终,在研究appdomin后,我发现,可以讲pinvoke 的调用写在program.cs下面。

using System;

using System.Collections.Generic;

using System.Linq;

using System.Windows.Forms;

using System.Runtime.InteropServices;

using System.Text;

namespace WinFormTester

{

static class Program

{

/// <summary>

/// 应|用?程序的?主入?口点?。

/// </summary>

[ STAThread]

static void Main()

{

Application.EnableVisualStyles();

Application.SetCompatibleTextRenderingDefault(false);

Application.Run(new Form1());

}

[ DllImport("F:\\04.研D究?项?目?\\PInvoke\\stringbuilder\\Debug\\stringbuilder.dll" ,

EntryPoint = "stringbuilder",

CharSet = CharSet.Auto, CallingConvention = CallingConvention .Cdecl)]

public static extern Boolean ParamIsString(string str,  ref StringBuilder ip);

}

}

这种方法下再进行调用,解决内存问题。其原有我认为是。。

二、参数传递问题。传递int等系统默认变量很简单方便,回写的方法,最后能够传递image变量

1、int 写入,如果要写出,加*

2、算是解决吧 bool值

DllExport int stringbuilder( char *str,int **  str_out)

public static extern Boolean ParamIsString(string str,  ref int ip);

bool值的解决方法,装换为int类型后强制转换,0为假,不是0为真;

private void button1_Click(object sender, EventArgs e)

{

int k = Convert .ToInt32(textBox1.Text);

Boolean b = Program .ParamIsString(textBox1.Text,k);

textBox2.Text = b.ToString();

}

就返回值这一块,其实就是一个类型转换,不仅是可行的,而且可以灵活运用起来

3、string 写入,char*在里面,没有问题

To summarize, System.String is preferable when working with immutable strings, especially for input (In) arguments. On the other hand, System.Text.StringBuilder is preferable with changeable strings especially output (Out) arguments.

我相信,marsh和stringbuilder的方法一定可以解决这个问题,但是目前我还没有研究清楚。还是那句老话“一鸟在手胜过千鸟在林”我这里有一种可用的解决方法。

#include "stdafx.h"

#define DllExport extern "C"__declspec (dllexport)

DllExport bool stringbuilder( char *str,char * str_out)

{

//这a里?的?256应|该?是?一?个?内部?定义?的?值了?

char CharBuf[256];

//             memcpy(CharBuf,str,sizeof(char)*256);

//             memcpy(str_out,CharBuf,sizeof(char)*256);

strcpy(CharBuf,str);

strcat(CharBuf, "ddd");

strcpy(str_out,CharBuf);

return 1;

}

这里采用了stringcpy,直接的内存操作,需要在外部结合起来进行边界检查

//传?出?string 的?方?法。研D究?意a义?大于实现?意a义?。

byte[] srcBytes = System.Text.Encoding .ASCII.GetBytes(textBox1.Text);

byte[] resBytes = new byte[256];

bool b = Program .ParamIsString(ref srcBytes[0], ref resBytes[0]);

string res = (System.Text.Encoding .ASCII.GetString(resBytes, 0, resBytes.Length)).TrimEnd();

textBox2.Text = res;

以及

[DllImport( "F:\\04.研D究?项?目?\\PInvoke\\stringbuilder\\Debug\\stringbuilder.dll" ,

EntryPoint = "stringbuilder",

CharSet = CharSet.Auto, CallingConvention = CallingConvention .Cdecl)]

public static extern bool ParamIsString(ref byte src, ref byte res);

有很多需要注意的点  .没有办法传递中文,但是这个方法具有通用性,体现了这种的问题如何来解决。变长等

4、结构体,关键是内外要用一样的数据结构,然后能够修改,这样就很强。

OK,这样可以解决问题:

DllExport bool structbuilder(ImageInfo & imginfo, int width,int height,int type)

{

imginfo.width = width;

imginfo.height = height;

imginfo.type = type;

return 1;

}

[ DllImport("F:\\04.研D究?项?目?\\PInvoke\\stringbuilder\\Debug\\stringbuilder.dll" ,

EntryPoint = "structbuilder",

CharSet = CharSet.Auto, CallingConvention = CallingConvention .Cdecl)]

public static extern bool ParamIsStruct(ref ImageInfo src, int width, int height, int type);

[StructLayout( LayoutKind.Sequential)]

public struct ImageInfo

{

public int width;

public int height;

public int type;

};

并且,非常重要的一点是,这里可以对这些类进行重新的封装,这样能够把csharp的优点和c++原生代码的优点结合起来。结果就可以变得比较稳定。这是一个新的总结性的问题。

下面是传递图像。如果int是第一类,代表的是系统原生的类型,struct是一类,代表你能够研究清楚内存放置的结构,而string又是一类,代表的是内存的直接操作。好的opencv的图像,要用上面的所有知识。

时间: 2024-08-05 11:16:20

csharp编写界面,opencv编写类库,解决 Pinvoke过程中的参数传递和平台调用问题的相关文章

Csharp调用基于Opencv编写的类库文件

现在将Csharp调用基于Opencv编写的类库文件(Dll)的方法定下来,我取名叫做GreenOpenCsharpWarper,简称GOCW. 一.CLR编写的DLL部分 1.按照正常方法引入Opencv; 2.提供接口函数,进行图像处理(这里只是实现了cvtColor,实际过程中可以用自己编写的复杂函数) String^  Class1::Method(cli::array<unsigned char>^ pCBuf1){     pin_ptr<System::Byte> p

java多线程的等待唤醒机制及如何解决同步过程中的安全问题

/* class Person{ String name; String sex; boolean flag = true; public void setPerson(String name, String sex){ this.sex=sex; this.name=name; } } class Input implements Runnable{ int x=0; Person p; Input(Person p){ this.p=p; } public void run(){ while

如何解决直播过程中的直播功耗高问题 | 直播疑难杂症排查

继<直播技术详解>系列文章之后,我们推出了这个新的系列<直播疑难杂症排查>,把解决直播问题的经验逐步分享出来,同时也会穿插一些音视频开发的基础知识和优化经验,希望能够帮助到直播领域的开发者们. 本系列会涵盖的内容包括但不限于如下一些主题: 播放失败 直播卡顿 首开慢 延时高 音画不同步 马赛克严重 播放黑屏.花屏.绿屏 播放杂音.噪音.回声 点播拖动不准 直播发热问题 其他问题(待续) 问题现象 直播过程中手机发热严重,耗电快. 问题排查 导致手机功耗高,发热严重的根本因素,无外乎

解决运营过程中产生的大数据图片造成的困扰

案例: 某企业最近上了一套项目管理软件,大概有700多人在用,而该企业对图片编辑和保存特别多,基本都是大型图片直接粘贴保存入库. 在软件运营了一段时间后,管理员发现出了一些问题,在每天图片数据不断增长的情况下,数据库数据急剧增加,变得十分庞大,导致运行速度并的非常慢.给备份还原也带来了很大的压力,光数据库数据就10多G. 您是否也遇到过这样的问题?是否也在为庞大的图片数据不断增加而担心?所以选择一套好的解决方案是非常重要的,oKit项目管理软件在这方面有非常大的优势. 解决方案: oKit能自动

iOS 9应用开发教程之编辑界面与编写代码

iOS 9应用开发教程之编辑界面与编写代码 编辑界面 在1.2.2小节中提到过编辑界面(Interface builder),编辑界面是用来设计用户界面的,单击打开Main.storyboard文件就打开了编辑界面.在Xcode 5.0以后中,编辑界面直接使用的是故事板.本小节将对编辑界面进行介绍 1.界面的构成 单击Main.storyboard打开编辑界面后,可以看到编辑界面会有4部分组成,如图1.23所示. 编号为1的部分为dock. 编号为2的部分为画布:用于设计用户界面的地方,在画布中

使用OpenCV编写的LDA程序----C++ LDA代码

改写自OpenCV中的lda.cpp程序,通过改写的程序可以返回自己所需的信息(LDA算法过程中产生的我们感兴趣的中间值),实现算法的独立编译,也可以通过阅读程序,加深对LDA算法的理解. // main.cpp : 定义控制台应用程序的入口点. // #include "stdafx.h" #include <cxcore.hpp> #include <vector> #include <iostream> #include "lda.h

对于 UI 界面的编写工作,到底应该用 xib/storyboard 完成,还是用手写代码来完成

对于复杂的.动态生成的界面,建议使用手工编写界面. 对于需要统一风格的按钮或UI控件,建议使用手工用代码来构造.方便之后的修改和复用. 对于需要有继承或组合关系的 UIView 类或 UIViewController 类,建议用代码手工编写界面. 对于那些简单的.静态的.非核心功能界面,可以考虑使用 xib 或 storyboard 来完成. ----------转自唐巧的技术博客

Python爬虫(图片)编写过程中遇到的问题

最近我突然对网络爬虫开窍了,真正做起来的时候发现并不算太难,都怪我以前有点懒,不过近两年编写了一些程序,手感积累了一些肯定也是因素,总之,还是惭愧了.好了,说正题,我把这两天做爬虫的过程中遇到的问题总结一下: 需求:做一个爬虫,爬取一个网站上所有的图片(只爬大图,小图标就略过) 思路:1.获取网站入口,这个入口网页上有很多图片集合入口,进入这些图片集合就能看到图片链接了,所以爬取的深度为2,比较简单:2.各个子图片集合内所包含的图片链接有两种形式:一种是绝对图片路径(直接下载即可),另一种的相对

javascript小实例,编写一个方法,实现从n-m个数中随机选出一个整数

别怪我是一个闷葫芦,没那么多花哨的语言,废话不多说,先说说小实例的要求: 编写一个方法,实现从n-m个数中随机选出一个整数,要求:传递的参数不足两个或者不是有效数字,返回[0-1]之间的随机数,需要解决n和m两个数大小问题,如果m<n,两个参数的值进行交换: 看到这个求随机数的小实例,相信很多人都会写,也写过很多相关的程序代码,所以,重要的知识点没有,旨在给初学者一些启发,大牛可略过! 既然是给初学者看的,那么我们就从最基本的东西一步一步的看,便于理解,先拆分一下要求吧: 1.求一个n-m的随机