반응형

C#에서 로드한 OpenCV 데이터를 C++ DLL 함수로 처리해 보자.

가장 효율적인 방법은 맨 아래 '가장 효율적인 방법'을 참고한다. 

 

C++ DLL 프로젝트를 만들고 OpenCV 라이브러리를 설정한 후 아래 코드를 빌드하고 DLL 파일을 만든다.

 

<Dll.h>

#pragma once
#include "opencv2/opencv.hpp"

extern "C" __declspec(dllexport) void cvt(uchar* srcData, int width, int height, int channels, int type);

 

<Dll.cpp>

#include "DllHeader.h"

extern "C" __declspec(dllexport) void cvt(uchar* srcData, int width, int height, int channels, int type)
{
	cv::Mat temp(height, width, type); // height, width, type 순이다.
	// Mat의 형식이 항상 일정하다면 temp를 전역 변수로 선언해 두고 사용하는게 효율적.
	memcpy(temp.data, srcData, width * height * channels); // 소스 데이터 복사.
	//cv::cvtColor(temp, temp, cv::COLOR_BGR2GRAY); 이건 컬러 채널이 (3채널에서 1채널로) 바뀌기 때문에 에러가 발생한다.
	cv::cvtColor(temp, temp, cv::COLOR_BGR2RGB); // 컬러 순서 변경.
	//cv::imshow("temp", temp);
	//cv::waitKey(0);
	memcpy(srcData, temp.data, width * height * channels); // 변경된 데이터를 소스에 복사.
}

 

더보기

좀 더 효율적인 <Dll.cpp>를 만들기 위해 memcpy()를 사용하지 않고 데이터 위치 포인터(srcData)를 그대로 대입한다.

#include "DllHeader.h"

extern "C" __declspec(dllexport) void cvt(uchar* srcData, int width, int height, int channels, int type)
{
	cv::Mat temp(height, width, type); // height, width, type 순이다.
	// Mat의 형식이 항상 일정하다면 temp를 전역 변수로 선언해 두고 사용하는게 효율적.
	temp.data = srcData; // 이미지 정보 포인터 변경.
	// 만약 temp를 전역변수로 둔다면 width, height, channels, type 정보도 필요 없다.
	cv::cvtColor(temp, temp, cv::COLOR_BGR2RGB); // 컬러 순서 변경.
}

 

아래 링크를 참고해 OpenCVSharp 프로젝트를 준비한다.

2021.11.20 - [OpenCV] - OpenCV with C#

 

 

using System;
using System.Drawing;
using System.Runtime.InteropServices;
using System.Windows.Forms;

using OpenCvSharp;

namespace OpenCVSharp
{
    public partial class Form1 : Form
    {
        // 위에서 만든 C++ DLL 파일을 프로젝트 디렉토리에 복사한다.
        // DLL 파일에서 C++용 OpenCV 라이브러리를 사용하므로 프로젝트 디렉토리에도
        // opencv_worldXXX.dll 파일이 있어야 한다.
        // 프로젝트 빌드시 AnyCPU가 아닌, DLL과 같은 아키텍쳐(x64)로 바꿔야 한다.
        
        [DllImport("Dll.dll")] // DLL 임포트.
        public extern static void cvt(IntPtr srcData, int width, int height, int channels, int type);

        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            try
            {
                OpenFileDialog dlg = new OpenFileDialog();
                if (dlg.ShowDialog() == DialogResult.OK)
                {
                    Mat mat = Cv2.ImRead(dlg.FileName);

                    // DLL 함수 사용.
                    cvt(mat.Data, mat.Width, mat.Height, mat.Channels(), mat.Type().Value);

                    if (pictureBox1.Image != null)
                    {
                        pictureBox1.Image.Dispose();
                    }

                    // Mat to Bitmap
                    System.IO.MemoryStream memoryStream = new System.IO.MemoryStream(mat.ToBytes());
                    pictureBox1.Image = new Bitmap(memoryStream);
                }
            }
            catch (Exception exc)
            {
                MessageBox.Show(exc.Message);
            }
        }
    }
}

 

빌드 후 프로그램을 실행하면 컬러 채널의 순서가 바뀐다.

 

※ 참고

가장 효율적인 방법 (아래 더보기 클릭)

더보기

OpenCVSharp에서 사용하는 Mat과 C++ OpenCV에서 사용하는 Mat은 서로 다르지만 OpenCVSharp Mat.CvPtr 포인터에 C++ OpenCV Mat 구조체의 위치가 저장되어 있다. 이 구조체를 C++ 에서 그대로 사용할 수 있다.

 

 <Dll.h> 

#pragma once
#include "opencv2/opencv.hpp"

extern "C" __declspec(dllexport) void cvt(cv::Mat* mat);

 

<Dll.cpp> 

#include "DllHeader.h"

extern "C" __declspec(dllexport) void cvt(cv::Mat* mat)
{
	cv::cvtColor(*mat, *mat, cv::COLOR_BGR2RGB);
}

 

 <Form.cs>

using System;
using System.Drawing;
using System.Runtime.InteropServices;
using System.Windows.Forms;

using OpenCvSharp;

namespace OpenCVSharp
{
    public partial class Form1 : Form
    {
        // 위에서 만든 C++ DLL 파일을 프로젝트 디렉토리에 복사한다.
        // DLL 파일에서 C++용 OpenCV 라이브러리를 사용하므로 프로젝트 디렉토리에도
        // opencv_worldXXX.dll 파일이 있어야 한다.
        // 프로젝트 빌드시 AnyCPU가 아닌, DLL과 같은 아키텍쳐(x64)로 바꿔야 한다.
        
        [DllImport("Dll.dll")] // DLL 임포트.
        public extern static void cvt(IntPtr mat);

        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            try
            {
                OpenFileDialog dlg = new OpenFileDialog();
                if (dlg.ShowDialog() == DialogResult.OK)
                {
                    Mat mat = Cv2.ImRead(dlg.FileName);
                    
                    // DLL 함수 사용. Mat.CvPtr: Native pointer of OpenCV structure.
                    cvt(mat.CvPtr);

                    if (pictureBox1.Image != null)
                    {
                        pictureBox1.Image.Dispose();
                    }

                    // Mat to Bitmap
                    System.IO.MemoryStream memoryStream = new System.IO.MemoryStream(mat.ToBytes());
                    pictureBox1.Image = new Bitmap(memoryStream);
                }
            }
            catch (Exception exc)
            {
                MessageBox.Show(exc.Message);
            }
        }
    }
}

 

 

※ 참고

2026.02.19 - [OpenCV] - [OpenCV] Python 에서 C++ DLL 사용하기

2025.02.16 - [OpenCV] - C# and Python OpenCV Image Data Share (Memory Mapped File)

2025.02.23 - [OpenCV] - C and Python OpenCV Image Data Share (Memory Mapped File)

 

반응형
Posted by J-sean
: