1. 程式人生 > >C#呼叫 opencv cv::Mat 影象, 採用折中方法

C#呼叫 opencv cv::Mat 影象, 採用折中方法

C# 用於介面的製作要比MFC高效許多,但是有時候為了效率需要用C++程式,這樣就涉及到了把C++核心演算法程式做成dll,在C#中進行呼叫。

之前有將IplImage*  這類結構用於C#呼叫,  整體結構較為複雜,現在我將更方便有效的方法介紹給大家,如果有更好的方法可以分享給我。

實現機制:

當然這裡需要注意一個問題,就是轉換的本質都是採用IplImage*    但是之前處理可以採用cv::Mat  進行各種處理

後面需要用到  IplImage* dst = &IplImage(src); (淺拷貝)   需要通過深拷貝 得到dst1  (程式碼如下 :  cvCopy(dst,dst1);)  再通過後面文中的方式就可以輕鬆傳遞資料啦。

Mat  在C++中很好用,不用處理釋放的問題,但是再製作dll呼叫的時候,記憶體釋放就是多麼的悲劇。這裡的啟示:有時候換一種方式處理問題更好。

下面我分別演示 彩色影象  和 灰度影象的讀取。

需要新增的標頭檔案等:

#include "stdafx.h"


#define DLL_API extern "C" _declspec(dllexport)     
 
#include <opencv2\opencv.hpp>  

彩色影象C++程式碼:

DLL_API uchar * _stdcall run1(char* filename, int & width, int & height, int & step )  
{  
  
        IplImage* uu = cvLoadImage(filename);  
	IplImage* dst1 = cvCreateImage(cvSize(uu->width,uu->height),8,1);
	cvCvtColor(uu,dst1,CV_RGB2GRAY);
	Mat ss(uu);
	uchar * data = new uchar[uu->width*uu->height*3];

	data= ss.data;
	width = ss.size().width;
	height = ss.size().height;
	step = ss.step;

	return data;
}

C#呼叫程式碼:
    [DllImport("opencv.dll")]
        public static extern IntPtr run1(string a , out int width, out int height, out int step); 
        private void button1_Click(object sender, EventArgs e)
        {
            string filename;
            OpenFileDialog op = new OpenFileDialog();
            if (op.ShowDialog() == DialogResult.OK)
            {
                filename = op.FileName;
                int width, height, step;
                IntPtr dst =  run1(filename,out width,out height, out step);
               Bitmap img = new Bitmap(width, height, step, System.Drawing.Imaging.PixelFormat.Format24bppRgb, dst);
               pictureBox1.Image = img;

            }
        }

其中,opencv.dll 為自己製作的C++的dll,pictureBox1 為C#中的控制元件。

灰度影象C++程式碼:

DLL_API uchar * _stdcall run1(char* filename, int & width, int & height, int & step )  
{  
  
    IplImage* uu = cvLoadImage(filename);  
	IplImage* dst1 = cvCreateImage(cvSize(uu->width,uu->height),8,1);
	cvCvtColor(uu,dst1,CV_RGB2GRAY);
	Mat ss(dst1);
	uchar * data = new uchar[uu->width*uu->height*3];

	data= ss.data;
	width = ss.size().width;
	height = ss.size().height;
	step = ss.step;
	return data;

}

可以看到程式碼和彩色影象C++程式碼並沒有太大區別,但是C#中會有區別,程式碼如下
        [DllImport("raildetection.dll")]
        public static extern IntPtr run1(string a , out int width, out int height, out int step); 
        private void button1_Click(object sender, EventArgs e)
        {
            string filename;
            OpenFileDialog op = new OpenFileDialog();
            if (op.ShowDialog() == DialogResult.OK)
            {
                filename = op.FileName;
                int width, height, step;
                IntPtr dst =  run1(filename,out width,out height, out step);
               Bitmap img = new Bitmap(width, height, step, <strong>System.Drawing.Imaging.PixelFormat.Format8bppIndexed</strong>,dst);               
               <strong>img.Palette = CvToolbox.GrayscalePalette;</strong> 
               pictureBox1.Image = img;

            }
        }
注:顏色加粗部分為區別部分

這個CvToolbox的結構體如下:

public static class CvToolbox
    {

       // #region Color Pallette
        /// <summary>
        /// The ColorPalette of Grayscale for Bitmap Format8bppIndexed
        /// </summary>
        public static readonly ColorPalette GrayscalePalette = GenerateGrayscalePalette();

        private static ColorPalette GenerateGrayscalePalette()
        {
            using (Bitmap image = new Bitmap(1, 1, PixelFormat.Format8bppIndexed))
            {
                ColorPalette palette = image.Palette;
                for (int i = 0; i < 256; i++)
                {
                    palette.Entries[i] = Color.FromArgb(i, i, i);
                }
                return palette;
            }
        }
    }

總結:影象用IplImage 讀取很重要,否則會報錯。

這樣大家就可以順利讀取cv::Mat 的中的資料啦!!!大笑 

有什麼不明白的可以留言!!!!