C# 将OpenCV Mat转换为Texture2D?

C# 将OpenCV Mat转换为Texture2D?,c#,c++,opencv,unity3d,C#,C++,Opencv,Unity3d,元上下文: cv::Mat _currentFrame; void GetRawImageBytes(unsigned char* data, int width, int height) { //Resize Mat to match the array passed to it from C# cv::Mat resizedMat(height, width, _currentFrame.type()); cv::resize(_currentFrame, resiz

元上下文:

cv::Mat _currentFrame;

void GetRawImageBytes(unsigned char* data, int width, int height)
{
   //Resize Mat to match the array passed to it from C#
    cv::Mat resizedMat(height, width, _currentFrame.type());
    cv::resize(_currentFrame, resizedMat, resizedMat.size(), cv::INTER_CUBIC);

    //You may not need this line. Depends on what you are doing
    cv::imshow("Nicolas", resizedMat);

    //Convert from RGB to ARGB 
    cv::Mat argb_img;
    cv::cvtColor(resizedMat, argb_img, CV_RGB2BGRA);
    std::vector<cv::Mat> bgra;
    cv::split(argb_img, bgra);
    std::swap(bgra[0], bgra[3]);
    std::swap(bgra[1], bgra[2]);
    std::memcpy(data, argb_img.data, argb_img.total() * argb_img.elemSize());
}
我目前正在开发一款利用opencv替代普通输入(键盘、鼠标等)的游戏。在DC++中,我使用UNIGIS3D的C脚本和OpenCV。我的目标是在我的游戏中创建一个来自opencv的图像

代码上下文:

cv::Mat _currentFrame;

void GetRawImageBytes(unsigned char* data, int width, int height)
{
   //Resize Mat to match the array passed to it from C#
    cv::Mat resizedMat(height, width, _currentFrame.type());
    cv::resize(_currentFrame, resizedMat, resizedMat.size(), cv::INTER_CUBIC);

    //You may not need this line. Depends on what you are doing
    cv::imshow("Nicolas", resizedMat);

    //Convert from RGB to ARGB 
    cv::Mat argb_img;
    cv::cvtColor(resizedMat, argb_img, CV_RGB2BGRA);
    std::vector<cv::Mat> bgra;
    cv::split(argb_img, bgra);
    std::swap(bgra[0], bgra[3]);
    std::swap(bgra[1], bgra[2]);
    std::memcpy(data, argb_img.data, argb_img.total() * argb_img.elemSize());
}
正如在OpenCV中通常所做的那样,我使用Mat来表示我的图像。这是我导出图像字节的方式:

cv::Mat _currentFrame;

...

extern "C" byte * EXPORT GetRawImage()
{
    return _currentFrame.data;
}
这就是我从C#导入的方式:

从我对OpenCV的理解来看,当在uchar指针中序列化时,我希望字节数组的结构是这样的:

b1, g1, r1, b2, g2, r2, ...
我正在使用以下方法将此BGR阵列转换为RGB阵列:

public static void BGR2RGB(ref byte[] buffer) {
    byte swap;
    for (int i = 0; i < buffer.Length; i = i + 3) {
        swap = buffer[i];
        buffer[i] = buffer[i + 2];
        buffer[i + 2] = swap;
    }
}
结果:

cv::Mat _currentFrame;

void GetRawImageBytes(unsigned char* data, int width, int height)
{
   //Resize Mat to match the array passed to it from C#
    cv::Mat resizedMat(height, width, _currentFrame.type());
    cv::resize(_currentFrame, resizedMat, resizedMat.size(), cv::INTER_CUBIC);

    //You may not need this line. Depends on what you are doing
    cv::imshow("Nicolas", resizedMat);

    //Convert from RGB to ARGB 
    cv::Mat argb_img;
    cv::cvtColor(resizedMat, argb_img, CV_RGB2BGRA);
    std::vector<cv::Mat> bgra;
    cv::split(argb_img, bgra);
    std::swap(bgra[0], bgra[3]);
    std::swap(bgra[1], bgra[2]);
    std::memcpy(data, argb_img.data, argb_img.total() * argb_img.elemSize());
}
最终的图像似乎以某种方式分散,它类似于某些形状,但它似乎也是形状的三倍。这是我在镜头前握着我的手:

[我、我的手和相机]

通过一些测试,我得出结论,我正确地解码了通道,因为使用手机发射RGB光,我可以重现真实世界的颜色:

[红色测试]

[蓝色测试]

[绿色测试]

图像中还有一些奇怪的线条:

[幽灵般的线条]

还有我的脸可以与这些图像进行比较:

[镜头前的我的脸]

问题:

cv::Mat _currentFrame;

void GetRawImageBytes(unsigned char* data, int width, int height)
{
   //Resize Mat to match the array passed to it from C#
    cv::Mat resizedMat(height, width, _currentFrame.type());
    cv::resize(_currentFrame, resizedMat, resizedMat.size(), cv::INTER_CUBIC);

    //You may not need this line. Depends on what you are doing
    cv::imshow("Nicolas", resizedMat);

    //Convert from RGB to ARGB 
    cv::Mat argb_img;
    cv::cvtColor(resizedMat, argb_img, CV_RGB2BGRA);
    std::vector<cv::Mat> bgra;
    cv::split(argb_img, bgra);
    std::swap(bgra[0], bgra[3]);
    std::swap(bgra[1], bgra[2]);
    std::memcpy(data, argb_img.data, argb_img.total() * argb_img.elemSize());
}
既然我能够正确地解码颜色通道,那么在解码OpenCV数组时我假设了什么错误?这是因为我不知道Unity的
LoadRawTextureData
是如何工作的,或者我是否以错误的方式解码了某些东西

OpenCV
Mat.data
数组是如何构造的

更新

多亏了@Programmer,他的解决方案发挥了神奇的作用

[我很高兴]

我稍微改变了他的剧本,没有必要做一些事情。在我的情况下,我需要使用BGR2RGBA,而不是RGB2RGBA:

extern "C" void EXPORT GetRawImage( byte *data, int width, int height )
{
    cv::Mat resizedMat( height, width, _currentFrame.type() );
    cv::resize( _currentFrame, resizedMat, resizedMat.size(), cv::INTER_CUBIC );

    cv::Mat argbImg;
    cv::cvtColor( resizedMat, argbImg, CV_BGR2RGBA );
    std::memcpy( data, argbImg.data, argbImg.total() * argbImg.elemSize() );
}

使用
SetPixels32
而不是
LoadRawTextureData
。不是从C++返回数组数据,而是从C ^中做。在C++中创建<代码> COLL32 < /COR>数组,并用“代码> GCHANDLE”将其插入.OLLC/<代码>,将被钉住的代码> COLL32 数组发送到C++,使用<代码> CV::调整大小< /C> >调整<代码> CV::MAT以匹配从C *发送的像素大小。您必须执行此步骤,否则会出现一些错误或问题

< >最后,将代码> CV::MAT<代码>从RGB转换为ARGB,然后使用 STD::MeMCPY 从C++中更新数组。然后可以使用
SetPixels32
函数将更新后的
Color32
数组加载到
Texture2D
中。我就是这样做的,它一直在为我工作,没有任何问题。也许还有其他更好的方法,但我从未找到过

C++:

cv::Mat _currentFrame;

void GetRawImageBytes(unsigned char* data, int width, int height)
{
   //Resize Mat to match the array passed to it from C#
    cv::Mat resizedMat(height, width, _currentFrame.type());
    cv::resize(_currentFrame, resizedMat, resizedMat.size(), cv::INTER_CUBIC);

    //You may not need this line. Depends on what you are doing
    cv::imshow("Nicolas", resizedMat);

    //Convert from RGB to ARGB 
    cv::Mat argb_img;
    cv::cvtColor(resizedMat, argb_img, CV_RGB2BGRA);
    std::vector<cv::Mat> bgra;
    cv::split(argb_img, bgra);
    std::swap(bgra[0], bgra[3]);
    std::swap(bgra[1], bgra[2]);
    std::memcpy(data, argb_img.data, argb_img.total() * argb_img.elemSize());
}

有两种可能的原因导致这种结果:-1。通道不匹配。2.像素类型不匹配。尝试几件事:-1。验证Mat的通道数。(img.channels())2。查看unity文档以获取rawdata的更多详细信息。(在通道、数据类型方面)。希望这将有助于至少定位错误。imho行结尾看起来不匹配(如果通道数正确,但请检查opencv mat通道数不为4!!)。检查Mat.ISTION并进行一些研究,看看Unity的图像是否有固定的字节,每行或某些东西。调试:创建一个空CV::用CVY8UC3格式的MAT,在中间画一条垂直线,并使用您的函数将其赋予纹理。纹理中那条线的出现会给你很多提示。我回家后会试试看!看来它会起作用的非常感谢,但对我来说,结果图像是垂直和水平翻转的。所以它是颠倒的,左是右。@link好吧,你可以翻转你正在加载的对象。