C++/CLR托管模式下接收C#端传递的图像进行处理和显示

很多时候做工业视觉的都喜欢用C#+halcon,纯粹只想做做应用的话,采用该模式搞下去也没啥问题,但是如果想提升一下自己对图像算法的底层开发能力,一般都还是会选择使用C++搭配Opencv进行开发,对于喜欢用C#开发上位机,结合C++做算法的话,那么C++的托管模式是一个不错的选择。

首先说下我为什么要用C++托管模式:

1、托管C++可以使用非托管内容;

2、托管模式下可以断点调试,非托管模式本人暂未找到可以断点调试的方法(如果喜欢非托管可以使用DebugView);

3、在调用c++的dll的时候,就像使用C#导出的dll一样去使用,不需要写dllexport和dllimport之类的玩意;

缺点:变量类型转换会稍微麻烦点


本次C#/C++混合模式测试思路为:

1、C#端作为图像源的获取端,便于测试直接使用halcon进行图像读取和传递;

2、C++端作为图像的接收端,接收C#传过来的图像;

3、图像显示:将C#端的panel控件的句柄传递到C++端,C++端通过halcon进行处理和显示;

下面具体介绍托管模式下C#端和C++端的详细配置和代码测试例程:

C++端配置

1、新建空白工程,添加一个需要供C#端进行调用的类,将配置类型设置为“动态库(.dll)”

2、在配置属性里,将公共语言运行时支持设置为clr模式,见下图

3、在配置属性里,选择C/C++下语言,找到“符合模式”一项,设置为“否(permissive)”

如果设置为“是(permissive-)”的话,编译的时候会出现以下错误

 4、添加类库mscorlib和System,添加方式同C#一样

 5、如果需要在断点的时候查看变量值的变化,需要进行一下操作

C++端设置:将调试器类型设置为混合模式

 C#端设置:勾选“启用本地代码调试”

 6、C++端测试代码

C++端采用opencv和halcon的混用模式,可根据具体情况去选择,halcon和Opencv的配置可自行配置

6.1 在类的前面加上ref

 6.2 .h文件

static HalconCpp::HWindow g_hwin;
public ref class MyAlgorithmPro
	{
	public:
		MyAlgorithmPro();
		~MyAlgorithmPro(void);

	public:
		void initWinHandle(long handle, int width, int height);//初始化窗口句柄
		void getImageByHalcon(unsigned char* R, unsigned char* G, unsigned char* B, int width, int height, int channel);//halcon取图
		void getImageByOpencv(unsigned char* R, unsigned char* G, unsigned char* B, int width, int height, int channel);//opencv取图
	};

6.3 .cpp文件

#include "MyAlgorithmPro.h"


MyAlgorithmPro::MyAlgorithmPro()
{
}


MyAlgorithmPro::~MyAlgorithmPro(void)
{
}


void MyAlgorithmPro::initWinHandle(long handle, int width, int height)
{
    g_hwin = HalconCpp::HWindow(0, 0, width, height, handle, "visible", "");
}

void MyAlgorithmPro::getImageByHalcon(unsigned char* R, unsigned char* G, unsigned char* B, 
    int width, int height, int channel)
{
    HObject img;

    switch (channel)
    {
    case 1:
        GenImage1(&img, "byte", width, height, (Hlong)R);
        break;
    case 3:
        GenImage3(&img, "byte", width, height, (Hlong)R, (Hlong)G, (Hlong)B);
        break;
    default:
        break;
    }
    

    g_hwin.SetPart(0, 0, height, width);
    g_hwin.DispObj(img);
    g_hwin.SetColor("red");
    g_hwin.DispCircle( height*0.5, width * 0.5, 50);
}

void MyAlgorithmPro::getImageByOpencv(unsigned char* R, unsigned char* G, unsigned char* B, 
    int width, int height, int channel)
{
    //cv::merge()
    cv::Mat img, rimg, gimg, bimg;
    std::vector<cv::Mat> vc;
    switch (channel)
    {
    case 1:
        img = cv::Mat(height, width, CV_8UC1, R);
        cv::circle(img, cv::Point(width*0.5, height*0.5), 200, cv::Scalar(100), -1);
        break;
    case 3:
        img = cv::Mat(height, width, CV_8UC3);
        rimg = cv::Mat(height, width, CV_8UC1, R);
        gimg = cv::Mat(height, width, CV_8UC1, G);
        bimg = cv::Mat(height, width, CV_8UC1, B);
        //halcon是RGB模式,opencv是BGR模式
        vc.push_back(bimg);
        vc.push_back(gimg);
        vc.push_back(rimg);
        cv::merge(vc, img);
        break;
    default:
        break;
    }

    HObject dstimg = MyClass::Mat2Hobject(img);
    g_hwin.SetPart(0, 0, height, width);
    g_hwin.DispObj(dstimg);
    g_hwin.SetColor("red");
    g_hwin.DispCircle(height * 0.5, width * 0.5, 50);
}

7、编写完代码后,会生成一个dll,记得将C++端和C#的生成目录都设置为同一个目录,否则是无法进行断点调试的

C#端配置

1、新建一个窗体应用程序,添加一个panel控件和按钮控件

2、在应用处添加C++端导出得dll

3、具体代码见下

 public partial class Form1 : Form
    {
        MyAlgorithmPro alg = new MyAlgorithmPro();

        public Form1()
        {
            InitializeComponent();
            initialWinHandle();
        }


        private void initialWinHandle()
        {
            alg.initWinHandle((int)panel1.Handle, panel1.Width, panel1.Height);
        }

        private void button1_Click(object sender, EventArgs e)
        {
            string curFilename = "";
            OpenFileDialog opndlg = new OpenFileDialog();
            opndlg.Filter = "所有图像文件|*.bmp;*.pcx;*.png;*.jpg;*.gif";
            opndlg.Title = "打开图片文件";
            if(opndlg.ShowDialog()==DialogResult.OK)
            {
                curFilename = opndlg.FileName;
            }


            HObject img = null;
            HTuple pointers = new HTuple(), type = new HTuple(), width = new HTuple(), height = new HTuple();
            HTuple redPointers = new HTuple(), greenPointers = new HTuple(), bluePointers = new HTuple();
            HTuple channels = new HTuple();
            HOperatorSet.GenEmptyObj(out img);
            HOperatorSet.ReadImage(out img, curFilename);
            HOperatorSet.CountChannels(img, out channels);
            if(channels.I==1)
            {
                HOperatorSet.GetImagePointer1(img, out pointers, out type, out width, out height);
                
                unsafe
                {
                    byte* ptr = (byte*)pointers.L;
                    alg.getImageByHalcon(ptr, ptr, ptr, width, height, channels);
                    //alg.getImageByOpencv(ptr, ptr, ptr, width, height, channels);
                }
            }
            else if(channels.I==3)
            {
                HOperatorSet.GetImagePointer3(img, out redPointers, out greenPointers, out bluePointers, out type, out width, out height);

                unsafe
                {
                    byte* bptr = (byte*)(redPointers.L);
                    byte* R = (byte*)redPointers.L;
                    byte* G = (byte*)greenPointers.L;
                    byte* B = (byte*)bluePointers.L;
                    alg.getImageByHalcon(R, G, B, width, height, channels);
                    //alg.getImageByOpencv(R, G, B, width, height, channels);
                }
            }
        }

    }

4、显示处理后的灰度图像

 5、显示处理后的彩色图像

结束语:以上混编模式适合喜欢折腾的人,其实用QT就没上面的事了,有疑问欢迎评论见!

Guess you like

Origin blog.csdn.net/oMoDao1/article/details/121529807