【发布时间】:2018-09-04 01:51:48
【问题描述】:
元上下文:
我目前正在开发一款使用 opencv 替代普通输入(键盘、鼠标等)的游戏。我通过 DllImports 在 C++ 中使用 Unity3D 的 C# 脚本和 opencv。我的目标是在我的游戏中创建一个来自 opencv 的图像。
代码上下文:
正如通常在 OpenCV 中所做的那样,我使用 Mat 来表示我的图像。这是我导出图像字节的方式:
cv::Mat _currentFrame;
...
extern "C" byte * EXPORT GetRawImage()
{
return _currentFrame.data;
}
这就是我从 C# 导入的方式:
[DllImport ("ImageInputInterface")]
private static extern IntPtr GetRawImage ();
...
public static void GetRawImageBytes (ref byte[] result, int arrayLength) {
IntPtr a = GetRawImage ();
Marshal.Copy(a, result, 0, arrayLength);
FreeBuffer(a);
}
以我理解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;
}
}
最后,我使用 Unity 的 LoadRawTextureData 将字节加载到纹理中:
this.tex = new Texture2D(
ImageInputInterface.GetImageWidth(),
ImageInputInterface.GetImageHeight(),
TextureFormat.RGB24,
false
);
...
ImageInputInterface.GetRawImageBytes(ref ret, ret.Length);
ImageInputInterface.BGR2RGB(ref ret);
tex.LoadRawTextureData(ret);
tex.Apply();
结果:
最终的图像似乎以某种方式分散,它类似于一些形状,但它似乎也是形状的三倍。这是我在镜头前握着我的手:
[我、我的手和相机]
做了一些测试,我得出结论,我正确解码了通道,因为使用我的手机发出 RGB 光,我可以重现现实世界的颜色:
[红色测试]
[蓝色测试]
[绿色测试]
图片中还有一些奇怪的线条:
[幽灵线]
还有我的脸可以比较这些图片:
[我在镜头前的脸]
问题:
既然我能够正确解码颜色通道,那么在解码 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() );
}
【问题讨论】:
-
这种类型的结果有两个可能的原因:- 1. CHANNELS 不匹配。 2. PIXEL-TYPE 不匹配。尝试一些事情:- 1. 验证 Mat 的通道数。 (img.channels()) 2. 检查统一文档以获取更多原始数据的详细信息。 (就通道、数据类型而言)。希望这将有助于至少找到错误。
-
恕我直言,看起来行结尾不匹配(如果通道数正确,但检查 opencv mat 通道数不是 4!!)。检查 mat.isContinuous 并研究一下 Unity 的图像是否有一些固定的 Bytes-per-Row 或其他东西。
-
用于调试:创建一个 CV_8UC3 格式的空 cv::Mat,在中间画一条垂直线,并使用您的函数将其赋予纹理。纹理中那条线的出现会给你很多提示。