You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ID3D11Texture2D转cv::Mat图像失真问题求助

解决ID3D11Texture2D转cv::Mat图像失真问题

问题根源

你的代码核心问题是忽略了Direct3D纹理内存的行对齐特性:D3D为了内存访问效率,会将纹理每行的字节数对齐到特定边界(通常是256字节),实际行字节数由resource.RowPitch给出,而非你假设的scWidth * CAMERA_CHANNELS。直接按连续内存拷贝会把每行末尾的填充数据也复制到cv::Mat,导致图像行错位,出现你截图中的失真。

修正后的代码

D3D11_TEXTURE2D_DESC capturedTextureDesc;
texture->GetDesc(&capturedTextureDesc);
capturedTextureDesc.Usage = D3D11_USAGE_STAGING;
capturedTextureDesc.BindFlags = 0;
capturedTextureDesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
capturedTextureDesc.MiscFlags = 0;

winrt::com_ptr<ID3D11Texture2D> userTexture = nullptr;
winrt::check_hresult(d3dDevice->CreateTexture2D(&capturedTextureDesc, NULL, userTexture.put()));
d3dContext->CopyResource(userTexture.get(), texture.get());

D3D11_MAPPED_SUBRESOURCE resource;
winrt::check_hresult(d3dContext->Map(userTexture.get(), 0, D3D11_MAP_READ, 0, &resource));

int scWidth = capturedTextureDesc.Width;
int scHeight = capturedTextureDesc.Height;
int CAMERA_CHANNELS = 4; // 假设纹理格式为BGRA8

// 直接构造cv::Mat,指定正确的行步长
cv::Mat mt(scHeight, scWidth, CV_8UC4);
unsigned char* mappedData = reinterpret_cast<unsigned char*>(resource.pData);

// 逐行拷贝,跳过D3D的行对齐填充
for (int y = 0; y < scHeight; ++y) {
    memcpy(mt.ptr(y), mappedData + y * resource.RowPitch, scWidth * CAMERA_CHANNELS);
}

d3dContext->Unmap(userTexture.get(), 0);

// 如果需要转为OpenCV常用的BGR格式(去掉Alpha通道),添加以下代码:
// cv::Mat bgrMat;
// cvtColor(mt, bgrMat, cv::COLOR_BGRA2BGR);
// return bgrMat;

return mt;

关键修正点说明

  1. 行对齐处理:通过resource.RowPitch获取D3D纹理实际行字节数,逐行拷贝时只复制有效像素数据(scWidth * CAMERA_CHANNELS字节),跳过每行末尾的填充部分。
  2. 直接构造cv::Mat:摒弃老旧的IplImage接口,直接创建CV_8UC4类型的cv::Mat,减少内存拷贝和兼容性问题。
  3. 像素格式适配:D3D纹理常用BGRA8格式,OpenCV默认BGR格式,如果不需要Alpha通道,可通过cvtColor转为CV_8UC3的BGR图像。

内容的提问来源于stack exchange,提问作者S.T.A.L.K.E.R

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.22 05:17:13