【问题标题】:EMGU (openCV) Passing a image back and forth between C# & C++EMGU (openCV) 在 C# 和 C++ 之间来回传递图像
【发布时间】:2015-05-28 06:04:34
【问题描述】:

我正在尝试做的事情在概念上似乎很简单。但是,我很难使用它(底部的错误消息)。我在这里使用 EMGU 文档和先前的问题解决了大部分问题。

我有一个带有 Imagebox 控件和一个按钮的窗体。单击按钮时,我想加载图像(从文件)并将其传递给 C++ dll,该 dll 可以获取图像文件并将相同的文件传递回 C# 程序,该程序可以显示在 Imagebox 控件上

C#

    private void rbtnLoadImage_Click(object sender, EventArgs e)
    {
        Image<Bgr, Int32> img1 = new Image<Bgr, Int32>("abc_color.jpg");
        IntPtr pnt = CvInvoke.cvCreateImageHeader(new Size(img1.Width, img1.Height), IPL_DEPTH.IPL_DEPTH_32S , img1.NumberOfChannels);

        Marshal.StructureToPtr(img1.MIplImage, pnt, false);
        MIplImage mptr = (MIplImage)Marshal.PtrToStructure(testIplImagePass(pnt), typeof(MIplImage));
        Image<Bgr, Int32> img2 = Image<Bgr, Int32>.FromIplImagePtr(mptr.imageData);
        imgbox.Image = img2;
    }

    [DllImport("xyz.dll", CallingConvention = CallingConvention.Cdecl)]
    public static extern IntPtr testIplImagePass(IntPtr imagevar);

C++

    extern "C" { __declspec(dllexport) IplImage* testIplImagePass(IplImage* imagevar); }

    IplImage* testIplImagePass(IplImage* imagevar)
    {
        return imagevar;
    }

我收到的错误消息是“Emgu.CV.dll 中发生了类型为 'System.NotImplementedException' 的未处理异常。附加信息:未实现 239、249 通道图像的加载。”

就行了

    Image<Bgr, Int32> img2 = Image<Bgr, Int32>.FromIplImagePtr(mptr.imageData);

我在这里做错了什么?任何建议表示赞赏。

【问题讨论】:

  • 错误消息告诉您确切的问题。显然,您的mptr.imageData 指针指向的内存区域的结构表明图像具有 239,249 个通道。你确定你的指针设置正确吗? img1.NumberOfChannels 的值是多少?
  • 我不确定我是否正确设置了指针。查看上面的代码,我没有发现任何问题。我可能是错的。 img1.NumberOfChannels 为 3,宽高分别为 219 和 221。
  • 只是好奇,你为什么将pnt 传递给函数testIplImagePass?该函数似乎没有做任何事情。
  • 另外,您绝对确定这些价值观吗?如果你在第二行直接下断点IntPtr pnt = ...,你能验证图像的宽度、高度和通道数的值吗?
  • @ReticulatedSpline 我正在将图像“img1”编组为 IntPtr“pnt”:Marshal.StructureToPtr(img1.MIplImage, pnt, false);这被 C++ 中的“testIplImagePass”拾取并发送回 C#。我还再次检查了宽度/高度/等值,它们与上述保持一致。

标签: c# c++ opencv emgucv


【解决方案1】:

这种方法很简单,最少只需要一份图像数据的副本(在 C# 中从托管内存到非托管内存)。

此外,它是安全代码(没有 C# 指针或修复)。

代码是为&lt;Bgr, Byte&gt; 量身定制的。对于通用版本,您还需要传递元素大小和数量 C# 和 C++ 之间的通道数。

C#部分:

Image<Bgr, Byte> img = ImageSource();
int colWidth = img.Cols * 3;
int img_size = img.Rows * colWidth;
IntPtr unmanaged = Marshal.AllocHGlobal(img_size);
//Copy img data into unmanaged memory
for (int i = 0; i < img.Rows; i++)
    Marshal.Copy(img.Bytes, i * img.MIplImage.WidthStep, img_unmanaged + i * colWidth, 
                 colWidth);

//Call c++ function with
//void FooCpp(IntPtr unmanaged, int rows, int cols);
FooCpp(unmanaged, rows, cols);

//If the values for cols and rows have changed you need to pass them back to c# 
int newColWidth = newCols*3;

//Get back the data: outImg constructor DOES NOT COPY the data
//You can directly use outImg as long as unmanaged lives.
Image<Bgr, Byte> outImg = new Image<Bgr, Byte>(newCols, newRows, newColWidth, unmanaged);
img = outImg.Clone();
Marshal.FreeHGlobal(unmanaged);
unmanaged = IntPtr.Zero;

//continue to use img here

C++部分:

void FooCpp(unsigned char* imgPtr, int rows, int cols){
    //Optionally: create a cv::Mat image or just use the image data         
    cv::Mat img(rows, cols, CV_8UC3, imgPtr);

    //use and modify img here. 
    //Can also use imgPtr directly as long as you know what you're doing

    //Passback: you can relax row and cols limits as long as the size is smaller
    int newRows = std::min(rows, img.rows);
    int newCols = std::min(cols, img.cols);
    if (img.elemSize() == 3)
        for (int i = 0; i < newRows; i++)
            memcpy(imgPtr + i*newCols*img.elemSize(), img.data + i*img.step, 
                   newCols*img.elemSize());
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-10-09
    • 1970-01-01
    • 1970-01-01
    • 2010-09-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多