如何使用 c++/cli 从 C# 流到 OpenCV Mat?

Posted

技术标签:

【中文标题】如何使用 c++/cli 从 C# 流到 OpenCV Mat?【英文标题】:How to come from C# stream to OpenCV Mat by using c++/cli? 【发布时间】:2014-02-08 17:13:31 【问题描述】:

我正在从 Azure Blob 存储读取一些图像。这是 c# 中的流。

在 c++/cli 中我需要这样做:

cv::Mat img_object = imdecode(data, IMREAD_UNCHANGED);

其中数据的类型为 cv::InputArray

所以问题是我如何最好地从 c# 到 cv::mat?

public ref class Client

public:
    // TODO: Add your methods for this class here.
    void Method(Stream ^ img1, Stream ^ img2);
;

void Client::Method(...)


我只是输入了 Stream ^ img1,Stream ^img2,这不是必需的,只是不确定从 c# 流到 cv::Mat 类的最佳方法是什么。

我知道我可以将流保存在临时文件位置并使用 imread 代替,但最好在内存中执行。

在 csharp 中我只是有这样的东西:(我知道它不是正确的方法,但为了这个例子的目的,它说明了这一点)。

Client client = new Client();
client.Method(blob.GetStream(), blob.GetStream())

更新:先试试

void CVService::Stiching::StichingClient::FindHomography(cli::array<unsigned char>^ pCBuf1, cli::array<unsigned char> ^ pCBuf2)


    pin_ptr<unsigned char> data1 = &pCBuf1[0];
    pin_ptr<unsigned char> data2 = &pCBuf2[0];  

    Mat img_object = imdecode(*data1,IMREAD_COLOR);
    Mat img_scene = imdecode(*data2, IMREAD_COLOR);

    if (!img_object.data || !img_scene.data)
    
        return;
    
    imwrite("c:\\test.jpg", img_object);

public class WebRole : RoleEntryPoint

    public override bool OnStart()
    
        // For information on handling configuration changes
        // see the MSDN topic at http://go.microsoft.com/fwlink/?LinkId=166357.

        StichingClient client = new StichingClient();

        client.FindHomography(ReadByteArray(path1).Result
            , ReadByteArray(path2).Result);

        return base.OnStart();
    

    private async Task<byte[]> ReadByteArray(string p)
    
        using (var fs = File.OpenRead(p))
        
            using (var ms = new MemoryStream())
            
                await fs.CopyToAsync(ms);

                return ms.ToArray();
            
        
    


问题是加载的 cv::mat 的 data== 0 并且没有将图像写入磁盘。我已经验证传递的 char 数组包含数据。有什么方法可以找出为什么 imdecode 不解码图像?

更新 2

c++/cli 代码部分的以下测试有效:

Mat test1 = imread("DSC_023.tif");
std::vector<unsigned char> buf;     
imencode(".jpg", test1, buf);
Mat test2 = imdecode(buf, IMREAD_COLOR);

上面 4 行 test2 是加载的图像和 imdecode 作品。所以想知道为什么当数据以字节数组形式出现时它不起作用

【问题讨论】:

让我回顾一下:imdecode 问题归结为:如何从 Task 获取向量 ? (不知道,只是想跟随你的思路..) 没有。不是任务。那是异步等待。 client.FindHomography(byte[] , byte[]) 是 c++/cli 部分的内容。 哦,抱歉误读了。 我猜我没有将正确的数据传递给 imdecode,因为我已经证明,如果我只是用 c++ 中的 imread 读取数据,它就可以工作。 hmm,将不得不深入研究您的代码,但FindHomography 既不是返回像素,也不是图像的“磁盘上图像”版本,而是“转换”x,y 的向量点(仅位置,而不是'强度甚至'颜色'值) 【参考方案1】:

所以这是我的解决方案。它可以被清理掉,但它现在可以工作了。

void CVService::Stiching::StichingClient::FindHomography(cli::array<unsigned char>^ pCBuf1, cli::array<unsigned char> ^ pCBuf2)


    pin_ptr<unsigned char> data1 = &pCBuf1[0];
    pin_ptr<unsigned char> data2 = &pCBuf2[0];  

    pin_ptr<System::Byte> p1 = &pCBuf1[0];
    unsigned char* pby1 = p1;
    Mat img_data1(pCBuf1->Length, 1, CV_8U, pby1);

    pin_ptr<System::Byte> p2 = &pCBuf2[0];
    unsigned char* pby2 = p2;
    Mat img_data2(pCBuf2->Length, 1, CV_8U, pby2);

    cv::Mat img_object = imdecode(img_data1, IMREAD_UNCHANGED);
    cv::Mat img_scene = imdecode(img_data2, IMREAD_UNCHANGED);

    if (!img_object.data || !img_scene.data)
    
        return;
    
    imwrite("img_object.jpg", img_object);
    imwrite("img_scene.jpg", img_scene);

我通过转换从内存中的 Azure Blob 存储加载的两个图像来完成这项工作,现在可以对图像执行我的 opencv 操作。这里的测试只是将通过的两张图片写入文件系统。

【讨论】:

正是我需要的。一切都按预期工作,但有一个问题。内存泄漏不会有问题,不需要释放缓冲区吗?我只是在学习 c++,只是想知道 ;) @pksorensen 这将与 cli/cpp 一起使用,可从其他 .net 语言(如 c#)调用。 cli::array 是托管数组,.net 将处理内存,因为它们是在托管部分上创建的。

以上是关于如何使用 c++/cli 从 C# 流到 OpenCV Mat?的主要内容,如果未能解决你的问题,请参考以下文章

如何从 C# 访问 C++/CLI 中的类?

从本机 lib 读取流到 C#

C++/CLI:从模板类继承的函数在 C# 中不可见

使用 C++/CLI 包装器将二维数组从 C# 传递到非托管 C++

如何从 C++/CLI 调用 VB6 COM

从 c# 访问 C++ .lib 库