将图像传递给 openCV 中的 blur() 或 Canny() 时出现类似幽灵的伪像
Ghost-like artifact when passing image to blur() or Canny() in openCV
所以我有一些 C++ opencv 代码,我在 unity 中从 C# 调用这些代码来处理来自网络摄像头的输入。
我将 C++ 代码编译为 DLL,然后使用 DLLImport 将其导入 C#。我将固定的 GCHandle 引用传递给 C++ 代码,以便我可以从 C++ 操作图像数组。这一切都有效。我可以将每一帧传递到我的 C++ dll 并对其进行灰度化。效果非常好。
当我尝试做除了使框架灰度化以外的事情时,问题就出现了。我试着做一个简单的 blur() ,输出结果是左右都有一个奇怪的重影图像。我不确定会出什么问题。当我执行 GaussianBlur() 或 Canny() 时也会发生这种情况。
左边是我遮住摄像头的时候,你可以更清楚的看到那个诡异的神器。中间是通过 GaussianBlur() 后的工件本身。它似乎创建了图像的副本并将它们与自身叠加。右边是灰度显示它正常工作的时候。所以我认为这不是 C# 和 C++ 之间发生的事情,只有当我通过 opencv 的模糊或 gaussianblur 或 canny 传递帧时才会发生。
这里是unity中的C#代码
using UnityEngine;
using System.Collections;
using System;
using System.Runtime.InteropServices;
public class camera : MonoBehaviour {
[DllImport("tee")]
public static extern void bw([MarshalAs(UnmanagedType.LPStruct)]
IntPtr data,
int width,
int height);
WebCamTexture back;
Color32[] data;
Byte[] byteData;
Renderer rend;
String test;
Texture2D tex;
GCHandle dataHandle;
// Use this for initialization
void Start () {
back = new WebCamTexture();
back.Play();
rend = GetComponent<Renderer>();
tex = new Texture2D(back.width, back.height, TextureFormat.ARGB32, false);
data = back.GetPixels32();
dataHandle = GCHandle.Alloc(data, GCHandleType.Pinned);
}
void OnDisable()
{
dataHandle.Free();
}
// Update is called once per frame
void Update () {
back.GetPixels32(data);
bw(dataHandle.AddrOfPinnedObject(), back.width, back.height);
tex.SetPixels32(data);
tex.Apply();
rend.material.mainTexture = tex;
}
}
这里是编译成 DLL 的 C++ 代码
#include <opencv2\core\core.hpp>
#include <opencv2\imgproc\imgproc.hpp>
using namespace std;
using namespace cv;
extern "C"
{
__declspec(dllexport) void bw(int data, int width, int height) {
unsigned char * buffer = reinterpret_cast<unsigned char *>(data);
Mat mat = Mat(width, height, CV_8UC4, buffer).clone();
Mat gray;
cvtColor(mat, gray, CV_RGBA2GRAY);
Mat blurred;
GaussianBlur(gray, blurred, Size(3, 3), 2, 2);
if (blurred.isContinuous()) {
for (int i = 0; i < (width * height); i++) {
unsigned char * pxl = buffer + 4 * i;
pxl[0] = blurred.data[i]; //red channel
pxl[1] = blurred.data[i]; //green channel
pxl[2] = blurred.data[i]; //blue channel
pxl[3] = (unsigned char)255; // alpha channel
}
}
}
}
我认为您的问题是您访问 blurred
像素值的方式。您应该使用以下方式访问通道值
for (int i = 0; i < (width * height); i++) {
unsigned char * pxl = buffer + 4 * i;
pxl[0] = blurred.ptr<uchar>(i); //red channel
pxl[1] = blurred.ptr<uchar>(i); //green channel
pxl[2] = blurred.ptr<uchar>(i); //blue channel
pxl[3] = (unsigned char)255; // alpha channel
}
您可以研究的另一件事是 opencv 存储像素值的方式与数据缓冲区的指针访问方式(。您可以通过在访问模糊图像之前旋转模糊图像来轻松测试它,看看这是否给您正确的而是输出或创建 Mat mat = Mat(height,width, CV_8UC4, buffer).clone();
。
你说的模糊类型是对的,灰度图应该是一个通道。
尝试使用当前代码以另一种方式访问模糊图像中的值
根据OpenCV的文档,Mat构造函数将rows和cols作为参数,所以你应该切换width和height参数。看这里http://docs.opencv.org/2.4/modules/core/doc/basic_structures.html#mat-mat
另外一个问题,你知道C#中图片是怎么存储的吗?他们是否有任何类型的数据对齐(即行不连续)?因为当您创建包含 Mat 时,这也可能是一个问题。
我目前来自phone,我会尽快重新格式化我的答案
编辑:考虑一下,只有当 OpenCV 和 texture2D 都按行主要顺序存储图像时,在构建时切换宽度和高度的事情才有意义。我查了一下这里(http://rbwhitaker.wikidot.com/extracting-texture-data)好像是这样的
所以我有一些 C++ opencv 代码,我在 unity 中从 C# 调用这些代码来处理来自网络摄像头的输入。
我将 C++ 代码编译为 DLL,然后使用 DLLImport 将其导入 C#。我将固定的 GCHandle 引用传递给 C++ 代码,以便我可以从 C++ 操作图像数组。这一切都有效。我可以将每一帧传递到我的 C++ dll 并对其进行灰度化。效果非常好。
当我尝试做除了使框架灰度化以外的事情时,问题就出现了。我试着做一个简单的 blur() ,输出结果是左右都有一个奇怪的重影图像。我不确定会出什么问题。当我执行 GaussianBlur() 或 Canny() 时也会发生这种情况。
左边是我遮住摄像头的时候,你可以更清楚的看到那个诡异的神器。中间是通过 GaussianBlur() 后的工件本身。它似乎创建了图像的副本并将它们与自身叠加。右边是灰度显示它正常工作的时候。所以我认为这不是 C# 和 C++ 之间发生的事情,只有当我通过 opencv 的模糊或 gaussianblur 或 canny 传递帧时才会发生。
这里是unity中的C#代码
using UnityEngine;
using System.Collections;
using System;
using System.Runtime.InteropServices;
public class camera : MonoBehaviour {
[DllImport("tee")]
public static extern void bw([MarshalAs(UnmanagedType.LPStruct)]
IntPtr data,
int width,
int height);
WebCamTexture back;
Color32[] data;
Byte[] byteData;
Renderer rend;
String test;
Texture2D tex;
GCHandle dataHandle;
// Use this for initialization
void Start () {
back = new WebCamTexture();
back.Play();
rend = GetComponent<Renderer>();
tex = new Texture2D(back.width, back.height, TextureFormat.ARGB32, false);
data = back.GetPixels32();
dataHandle = GCHandle.Alloc(data, GCHandleType.Pinned);
}
void OnDisable()
{
dataHandle.Free();
}
// Update is called once per frame
void Update () {
back.GetPixels32(data);
bw(dataHandle.AddrOfPinnedObject(), back.width, back.height);
tex.SetPixels32(data);
tex.Apply();
rend.material.mainTexture = tex;
}
}
这里是编译成 DLL 的 C++ 代码
#include <opencv2\core\core.hpp>
#include <opencv2\imgproc\imgproc.hpp>
using namespace std;
using namespace cv;
extern "C"
{
__declspec(dllexport) void bw(int data, int width, int height) {
unsigned char * buffer = reinterpret_cast<unsigned char *>(data);
Mat mat = Mat(width, height, CV_8UC4, buffer).clone();
Mat gray;
cvtColor(mat, gray, CV_RGBA2GRAY);
Mat blurred;
GaussianBlur(gray, blurred, Size(3, 3), 2, 2);
if (blurred.isContinuous()) {
for (int i = 0; i < (width * height); i++) {
unsigned char * pxl = buffer + 4 * i;
pxl[0] = blurred.data[i]; //red channel
pxl[1] = blurred.data[i]; //green channel
pxl[2] = blurred.data[i]; //blue channel
pxl[3] = (unsigned char)255; // alpha channel
}
}
}
}
我认为您的问题是您访问 blurred
像素值的方式。您应该使用以下方式访问通道值
for (int i = 0; i < (width * height); i++) {
unsigned char * pxl = buffer + 4 * i;
pxl[0] = blurred.ptr<uchar>(i); //red channel
pxl[1] = blurred.ptr<uchar>(i); //green channel
pxl[2] = blurred.ptr<uchar>(i); //blue channel
pxl[3] = (unsigned char)255; // alpha channel
}
您可以研究的另一件事是 opencv 存储像素值的方式与数据缓冲区的指针访问方式(。您可以通过在访问模糊图像之前旋转模糊图像来轻松测试它,看看这是否给您正确的而是输出或创建 Mat mat = Mat(height,width, CV_8UC4, buffer).clone();
。
你说的模糊类型是对的,灰度图应该是一个通道。
尝试使用当前代码以另一种方式访问模糊图像中的值
根据OpenCV的文档,Mat构造函数将rows和cols作为参数,所以你应该切换width和height参数。看这里http://docs.opencv.org/2.4/modules/core/doc/basic_structures.html#mat-mat
另外一个问题,你知道C#中图片是怎么存储的吗?他们是否有任何类型的数据对齐(即行不连续)?因为当您创建包含 Mat 时,这也可能是一个问题。
我目前来自phone,我会尽快重新格式化我的答案
编辑:考虑一下,只有当 OpenCV 和 texture2D 都按行主要顺序存储图像时,在构建时切换宽度和高度的事情才有意义。我查了一下这里(http://rbwhitaker.wikidot.com/extracting-texture-data)好像是这样的