使用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. Solr学习笔记之4、Solr配置文件简介

    Solr学习笔记之4.Solr配置文件简介 摘自<Solr in Action>. 1. solr.xml – Defines one or more cores per Solr ser ...

  2. hyperledger

    http://hyperledger-fabric.readthedocs.io/en/latest/prereqs.html https://github.com/hyperledger/block ...

  3. less语言特性(一) —— 变量

    近两年移动市场不断扩大,HTML5也逐渐升温,为了使我们前端工作更有效率,各种框架层出不穷,本章将介绍LESSCSS框架.LESSCSS是一种动态样式语言,属于CSS预处理语言的一种,它使用类似CSS ...

  4. hibernate注解(三)1+N问题

    一.什么时候会遇到1+N的问题? 前提:Hibernate默认表与表的关联方法是fetch="select",不是fetch="join",这都是为了懒加载而准 ...

  5. 控制div显示隐藏(有文字图片介绍)

    <div class="toggle"> <p id="zi">收起</p> <p id="zhe" ...

  6. mysql 数据库的操作

    1.数据库的查看 1)查看mysql中所有的数据库    "show databases;" mysql> show databases; +---------------- ...

  7. 最强Mac电脑 工作站级别一体机iMac Pro公布

    版权声明:本文为博主原创文章,未经博主同意不得转载. https://blog.csdn.net/a2Ni5KFDaIO1E6/article/details/78795857 前不久传出消息,苹果将 ...

  8. 009-spring cloud gateway-过滤器GatewayFilter、GlobalFilter、GatewayFilterChain、作用、生命周期、GatewayFilterFactory内置过滤器

    一.概述 在Spring-Cloud-Gateway之请求处理流程中最终网关是将请求交给过滤器链表进行处理. 核心接口:GatewayFilter,GlobalFilter,GatewayFilter ...

  9. golang语言中的context详解,Go Concurrency Patterns: Context

    https://blog.golang.org/context Introduction In Go servers, each incoming request is handled in its ...

  10. visual studio code 编辑器的配置及快捷键等, vscode, csc

    visual studio code (vsc) 对开发node.js,javascript,python,html,golang等比较友好,同时支持git浏览及分屏对比,运行速度快,所以是值得一用的 ...