Windows 에서 GUI 개발은 MFC 보다 UI도 풍부하고 다루기 쉬운 C# 으로 개발하는게 편리하다.
이러한 .NET 환경에서 OpenCV(C++) 을 사용하기 위해서는 Wrapper 인 OpenCVSharp 을 이용하는 방법도 있으나 interface를 새로 알아야 한다는 단점이 있다.
하지만 직접 OpenCV를 C++ 그대로 사용하고자 할때는 C++/CLI(Managed Code와 Native C++ 혼용) 환경을 이용하자.
GUI(C#) 에서 읽어들인 BMP 메모리를 C++/CLI 에 전달하여 OpenCV로 처리한 후 결과 이미지를 다시 GUI에 전달하는 방법은 아래와 같이 .NET Managed memory 와 Native Heap memory에의 변환 처리가 필요하다.
1. Bitmap -> OpenCV Mat 변환
cv::Mat ImgPrc::ToMat(System::Drawing::Bitmap^ bitmap) { // 24 bpp(BGR칼라) 또는 8 bpp(그레이) 만 가능 if ((bitmap->PixelFormat != System::Drawing::Imaging::PixelFormat::Format24bppRgb) && (bitmap->PixelFormat != System::Drawing::Imaging::PixelFormat::Format8bppIndexed)) { throw gcnew NotSupportedException("Only images of type CV_8UC3 OR CV_8UC1 are supported for conversion to Bitmap"); } // Bitmap 에 읽고 쓰기 Lock을 설정 System::Drawing::Imaging::BitmapData^ bmpdata = bitmap->LockBits( System::Drawing::Rectangle(0, 0, bitmap->Width, bitmap->Height), System::Drawing::Imaging::ImageLockMode::ReadWrite, bitmap->PixelFormat ); // bpp 를 OpenCV에 맞게 설정 int type = (bitmap->PixelFormat == System::Drawing::Imaging::PixelFormat::Format24bppRgb) ? CV_8UC3 : CV_8UC1; // 로우의 바이트 수 int wb = bmpdata->Stride; // 변환 cv::Mat cv_img(cv::Size(bitmap->Width, bitmap->Height), type, bmpdata->Scan0.ToPointer(), wb); bitmap->UnlockBits(bmpdata); return cv_img; } |
2. OpenCV Mat -> Bitmap 변환
System::Drawing::Bitmap^ CMatch::ToBmp(cv::Mat img) { System::Drawing::Imaging::PixelFormat fmt; // OpenCV 타입을 .NET 타입으로 설정 switch (img.type()) { case CV_8UC3: fmt = System::Drawing::Imaging::PixelFormat::Format24bppRgb; break; case CV_8UC1: fmt = System::Drawing::Imaging::PixelFormat::Format8bppIndexed; break; default: throw gcnew NotSupportedException("Only images of type 8, 24 bpp are supported for conversion to Bitmap"); } // 이미지를 담을 메니지드 메모리 할당 System::Drawing::Bitmap^ bmpimg = gcnew System::Drawing::Bitmap(img.cols, img.rows, fmt); // 할당된 메모리를 Lock System::Drawing::Imaging::BitmapData^ data = bmpimg->LockBits( System::Drawing::Rectangle(0, 0, img.cols, img.rows), System::Drawing::Imaging::ImageLockMode::WriteOnly, fmt); // Mat 의 데이터 메모리 포인터 uchar* srcData = img.data; // Managed 의 Bitmap 데이터 메모리 포인터 uchar* dstData = reinterpret_cast<uchar*>(data->Scan0.ToPointer()); // 한 로우씩 카피 for (int row = 0; row < data->Height; ++row) { memcpy(reinterpret_cast<void*>(&dstData[row * data->Stride]), reinterpret_cast<void*>(&srcData[row * img.step]), img.cols * img.channels()); } bmpimg->UnlockBits(data); return bmpimg; } |
'opencv' 카테고리의 다른 글
(opencv) 이미지위의 직선상의 픽셀위치 구하기 (0) | 2025.02.08 |
---|---|
(opencv) pixel access time (1) | 2025.02.08 |
contour / labelling (0) | 2023.12.07 |
공백 메우기 (2) | 2023.12.02 |
b/w 이미지의 칼럼(수직방향)별 검정(=0)픽셀수 카운트 (0) | 2023.12.02 |