使用csharp 编写winform程序,不仅速度快,而且容易界面美化并找到其他类库的支持;而使用 opencv编写图形图像处理程序,是目前比较流行,而且高效的一种方法。如果需要将两者结合,需要解决的问题就是使用 csharp调用vc 下编写的库文件。两个难点,一个是平台调用的内存控制问题,一个是参数传递问题。关注点在解决实际问题
在现实中,我发现问题比较大的是两点,一点是内存控制问题,一个是平台调用问题。
  一、内存控制:(1-6种方法是我验证后失败的方法,关注问题解决者可直接看第7点)
、验证 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;
}
个主要函数进行拼接操作。在运行状态下 (ctrl+F5),不溢出。
、采用动态加载 dll文件的方式进行函数调用。(具体见 Zealic.Windows)
就是采用loaddll 的方式动态地将 dll调入程序中,并且采用freedll的方式动态地将 dll文件注销掉。这个方法在运行状态下 (ctrl+F5),溢出,没有效果。
、采用轻量化代码生成的方法 (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模式下都能够运行正常。
、这个时候,我开始想是不是我的 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文件需要若干秒的执行时间),会发生内存无法情况的情况。因为非托管方式下,垃圾回收器无法管理非托管代码内存。但是我已经显示地将内存注销了,只是不能被垃圾回收器回收。
、所以我强制进行垃圾回收
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
    {
        [ STAThread]
        static void Main()
        {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            Application.Run(new Form1());
        }
 
        [ DllImport("F:\\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)
{              
               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,直接的内存操作,需要在外部结合起来进行边界检查
 
            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:\\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的图像,要用上面的所有知识。

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

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

    现在将Csharp调用基于Opencv编写的类库文件(Dll)的方法定下来,我取名叫做GreenOpenCsharpWarper,简称GOCW. 一.CLR编写的DLL部分 1.按照正常方法引入Ope ...

  2. 编写Java程序,模拟五子棋博弈过程中的异常声明和异常抛出

    返回本章节 返回作业目录 需求说明: 模拟五子棋博弈过程中的异常声明和异常抛出,判断用户所下棋子的位置,是否超越了棋盘的边界. 棋盘的横坐标的范围为0-9,纵坐标范围为0-14,如果用户所放棋子的坐标 ...

  3. 用apt-get解决dpkg过程中出现的依赖问题

    dpkg命令不解决依赖问题,这点对新手很不友好 当使用dpkg -i *.deb 安装出现依赖问题的时候,可以尝试如下解决方法: apt-get -f -y install # 复制粘贴回车,inst ...

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

    /* class Person{ String name; String sex; boolean flag = true; public void setPerson(String name, St ...

  5. 用Service+Broadcast解决倒计时过程中Activity被销毁的问题

    主要思想是这样的:将倒计时CountDownTimer放在Service里面进行,每过一秒就一条发广播,在主Activity里注册广播,收到广播后更新UI. 一.写一个类CodeTimerServic ...

  6. 【4opencv】为基于OpenCV的图像处理程序编写界面—关于QT\MFC\CSharp的选择以及GOCW的介绍

            基于OpenCV编写图像处理项目,除了算法以外,比较重要一个问题就是界面设计问题.对于c++语系的程序员来说,一般来说有QT/MFC两种考虑.QT的确功能强大,特别是QML编写andr ...

  7. 为基于OpenCV的图像处理程序编写界面—关于QT\MFC\CSharp的选择以及GOCW的介绍

            基于OpenCV编写图像处理项目,除了算法以外,比较重要一个问题就是界面设计问题.对于c++语系的程序员来说,一般来说有QT/MFC两种考虑.QT的确功能强大,特别是QML编写andr ...

  8. 【Ubuntu】Ubuntu系统启动过程中,输入用户名与密码后登录一直卡在紫色界面问题(未解决,最后通过重装系统)

    0. 前言 由于本电脑为公用电脑,可能由于其他人点了图像界面中推荐的内核更新,导致原来安装的NVIDIA显卡驱动 430 与升级后的 5.0 内核不兼容,从而导致输入用户名后登录一直卡在紫色界面.在排 ...

  9. 红帽企业版RHEL7.1在研域工控板上,开机没有登陆窗口 -- 编写xorg.conf 简单三行解决Ubuntu分辩率不可调的问题

    红帽企业版RHEL7.1在研域工控板上,开机没有登陆窗口 没有登陆窗口 的原因分析: 没有登陆窗口的原因是因为有多个屏幕在工作,其中一个就是build-in 屏幕(内置的虚拟屏幕)和外接的显示器,并且 ...

随机推荐

  1. HDU 2087 - 剪花布条 - [KMP算法]

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2087 Time Limit: 1000/1000 MS (Java/Others) Memory Li ...

  2. 数据库和struts2的拦截器

    1.READ UNCOMMITTED:脏读.不可重复读.虚读都有可能发生2.READ COMMITTED:防止脏读的发生,不可重复读,虚读都有可能发生3.REPEATABLE READ:防止脏读,不可 ...

  3. android speakerphone/

    http://www.cnblogs.com/innost/archive/2011/01/22/1942149.html http://blog.sina.com.cn/s/blog_5418969 ...

  4. 动画-缩放,旋转 CGAffineTransform

    CGAffineTransform transform; // = CGAffineTransformScale(flyImoji.transform, 8, 8);    transform = C ...

  5. Maven中的pom.xml配置文件详解

    原文:http://blog.csdn.net/u012152619/article/details/51485297 <project xmlns="http://maven.apa ...

  6. bokeyuan_python文章爬去入mongodb读取--LOWBIPROGRAMMER

    # -*- coding: utf-8 -*- import requests,os from lxml import etree from pymongo import * class Boke(o ...

  7. 青蛙的约会---poj1061(扩展欧几里德)

    题目链接:http://poj.org/problem?id=1061 就是找到满足 (X+mt)-(Y+nt) = Lk 的 t 和 k 即可 上式可化简为 (n-m)t + Lk = X-Y;满足 ...

  8. MySQL如何开启慢查询

    一 简介 开启慢查询日志,可以让MySQL记录下查询超过指定时间的语句,通过定位分析性能的瓶颈,才能更好的优化数据库系统的性能.   二 参数说明 slow_query_log 慢查询开启状态 slo ...

  9. Shell初学(一)hello world

    精简: 1.创建:可以使用 vi/vim 命令来创建文件如: test.sh   ,扩展名并不影响脚本执行,写什么都可以. 2.hello_world: #!/bin/bash            ...

  10. js-jquery-插件开发(一)

    jQuery插件开发模式 jQuery插件开发方式主要有三种:1.通过$.extend()来扩展jQuery 主要是在jQuery命名空间或者理解成jQuery身上添加了一个静态方法2.通过$.fn ...