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
是如何工作的,或者我是否以错误的方式解码了某些东西
OpenCVMat.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,然后使用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好吧,你可以翻转你正在加载的对象。