【发布时间】:2016-06-25 18:01:10
【问题描述】:
简短介绍:我用 C++ (DirectX) 编写了一个带有 Oculus Rift 的增强现实应用程序。我的一个片段着色器计算全向相机模型的不失真。
我现在唯一的问题是读取渲染的不失真 texture2D 并将其进一步转换为使用 OpenCV 对现实世界进行 3DPose 跟踪/映射。有趣的是,我已经反其道而行之,这意味着我已经使用我的扭曲相机图像缓冲区创建了着色器资源视图以实现不失真。但不知何故,我现在陷入了相反的境地。
这是我遇到的代码:
void GraphicsAPI::UndistortionForLsdSlam()
{
// ------------------------------------ [ Version 4 ]
// Get Pointer to the rendered Shader Resource (Camera Undistortion)
ID3D11Resource* renderBuffer;
renderTextureRight_->GetRenderTargetView()->GetResource(&renderBuffer);
D3D11_TEXTURE2D_DESC texDesc;
texDesc.ArraySize = 1;
texDesc.BindFlags = 0;
texDesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
texDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
texDesc.Width = screenWidth_;
texDesc.Height = screenHeight_;
texDesc.MipLevels = 1;
texDesc.MiscFlags = 0;
texDesc.SampleDesc.Count = 1;
texDesc.SampleDesc.Quality = 0;
texDesc.Usage = D3D11_USAGE_STAGING;
// Copy Data from GPU only, into CPU Accessable Memory
ID3D11Texture2D* undistortedShaderTex;
device_->CreateTexture2D(&texDesc, 0, &undistortedShaderTex);
devicecontext_->CopyResource(undistortedShaderTex, renderBuffer);
// SaveDDSTextureToFile(devicecontext_, undistortedShaderTex, L"SCREENSHOT.dds");
// Map Resource GPU Resource
D3D11_MAPPED_SUBRESOURCE mappedResource;
if (FAILED(devicecontext_->Map(undistortedShaderTex, 0, D3D11_MAP_READ, 0, &mappedResource)))
std::cout << "Error: [CAM 2] could not Map Rendered Camera ShaderResource for Undistortion" << std::endl;
// Copy Memory of GPU Memory Layout (swizzled) to CPU
char* buffer = new char[(screenWidth_ * screenHeight_ * CAMERA_CHANNELS)];
char* mappedData = static_cast<char*>(mappedResource.pData);
for (UINT i = 0; i < screenHeight_; i++)
{
memcpy(buffer, mappedData, screenWidth_ * 4);
mappedData += mappedResource.RowPitch;
buffer += screenWidth_ * 4;
}
std::cout << "FINISHED LOOP .. " << std::endl;
devicecontext_->Unmap(undistortedShaderTex, 0);
// OpenCV IplImage Convertion
IplImage* frame = cvCreateImageHeader(cvSize(screenWidth_, screenHeight_), IPL_DEPTH_8U, CAMERA_CHANNELS);
frame->imageData = (char*)buffer;
frame->imageDataOrigin = frame->imageData;
cv::Mat mymat = cv::Mat(frame, true); // Access Violation here(!)
cv::imshow("Shader Undistortion", mymat);
错误信息:
ARift.exe 中 0x680EF41C (msvcr120.dll) 处的未处理异常: 0xC0000005:访问冲突读取位置0x1FD4EFFC
访问冲突恰好发生在尝试使用先前创建的 IplFrame 创建 cv::Mat() 时。出于测试目的,我更改了一行代码以使用我的失真相机缓冲区测试 OpenCV 转换并且它有效:
frame->imageData = (char*)buffer;
to(从扭曲的相机字符*内存缓冲区中读取相机帧):
frame->imageData = (char*)(ariftcontrol->caminput->lsdslamCameraBuffer);
所以这显然意味着,带有 char* 缓冲区的东西并不完全正确,但经过数小时的测试,我不明白为什么。首先我认为问题可能是因为我的两个相机都是 R8G8B8A8_UNORM 格式并且 RenderTargetTexture 设置为 DXGI_FORMAT_R32G32B32A32_FLOAT (这给了我一个 DirectX 调试错误消息)。但是我已经将 RenderTargetTexture 更改为 DXGI_FORMAT_R8G8B8A8_UNORM,因此 CopyResource() 函数可以工作,并且我还保存了图像以查看 CopyResource() 之后的样子。
这里是 DDS(可以清楚地看到它是我未失真的 2D 相机图像,但我不确定为什么它看起来像 .dds 一样奇怪):
Undistorted ShaderResource Cameraimage as .dds
这是相同的图像,仅保存为 .jpeg(看起来如预期): UNdistored ShaderResource Cameraimage as .jpeg
这意味着,从 GPU 中的 ShaderResource 到代码行的所有复制
// SaveDDSTextureToFile(devicecontext_, undistortedShaderTex, L"SCREENSHOT.dds");
似乎是正确的。正如我上面提到的,为了测试,我只将 IplImage->imageData 更改为我仍然失真的相机 char* 缓冲区,并且转换工作正常。所以它必须与 memcpy() 部分有关,但我实际上是从我将扭曲的相机缓冲区复制到 GPU ShaderResource 的地方复制了它,这就像一个魅力!
注意:这里的 CAMERA_CHANNLES 为 4。
谁能看到我在这里做错了什么? Í 感谢每一个帮助,谢谢! :)
干杯,
- M.
【问题讨论】:
-
旁注:
if (language == "c++") use c++ API
标签: c++ opencv image-processing directx memory-layout