In C++/CLR managed mode, the image transmitted by the receiving c# end is processed and displayed

Most of the time, industrial vision workers prefer to use C#+halcon. If they just want to do applications, there is no problem in adopting this mode. However, if they want to improve their bottom development ability of image algorithms, they will generally choose to use C + + with Opencv for development. If they like to use c# to develop upper computers and combine C + + for algorithms, Then the hosting mode of C + + is a good choice.

First, let's talk about why I use C + + hosting mode:

1. Managed C + + can use unmanaged content;

2. Breakpoint debugging can be performed in managed mode, but I haven't found a method to debug breakpoints in unmanaged mode (DebugView can be used if you like unmanaged mode);

3. When calling the dll of C + +, it is used like using the dll of c# export, and there is no need to write things such as dllexport and dllimport;

Disadvantages: variable type conversion is a little troublesome

The test idea of C#/C + + mixed mode is as follows:

1. The C# end is used as the acquisition end of the image source, which is convenient for testing. halcon is directly used for image reading and transmission;

2. The C + + end, as the image receiving end, receives the image transmitted by c#;

3. Image display: pass the handle of the panel control at the c# end to the C + + end, and the C + + end processes and displays it through halcon;

The following describes the detailed configuration and code test routines of c# end and C + + end in managed mode:

C + + end configuration

1. Create a new blank project, add a class that needs to be called by the C# end, and set the configuration type to "dynamic library (. dll)"

2. In the configuration attribute, set the common language runtime support to clr mode, as shown in the following figure

 

3. In the configuration properties, select the language under C/C + +, find the item "conforming mode" and set it to "permitted"

If it is set to "yes" (permission -), the following errors will occur during compilation

  4. Add the class libraries mscorlib and System in the same way as C #

  5. If you need to view the transformation of variable values at breakpoints, you need to do the following operations

C + + side setting: set the debugger type to mixed mode

  C# end setting: check "enable local code debugging"

  6. C + + end test code

The C + + end adopts the mixed mode of OpenCV and halcon, which can be selected according to the specific situation. The configuration of halcon and opencv can be configured by themselves

6.1 add ref before the class

  6.2. H documents

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

	public:
		void initWinHandle(long handle, int width, int height);//Initialize window handle
		void getImageByHalcon(unsigned char* R, unsigned char* G, unsigned char* B, int width, int height, int channel);//halcon drawing
		void getImageByOpencv(unsigned char* R, unsigned char* G, unsigned char* B, int width, int height, int channel);//opencv drawing
	};

6.3. Cpp file

#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 is RGB mode and opencv is BGR mode
        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. After writing the code, a dll will be generated. Remember to set the generated directories of C + + and c# to the same directory, otherwise breakpoint debugging cannot be carried out

C# end configuration

1. Create a new form application and add a panel control and button control

2. Add the dll exported from the C + + side at the application

3. See the following for specific codes

 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 = "All image files|*.bmp;*.pcx;*.png;*.jpg;*.gif";
            opndlg.Title = "Open picture file";
            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. Displays the processed grayscale image

  5. Display the processed color image

 

Conclusion: the above mixed mode is suitable for people who like to toss. In fact, there is nothing above with QT. If you have any questions, please comment!

Tags: C++ C#

Posted on Wed, 24 Nov 2021 23:06:33 -0500 by penguin0