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;
关键修正点说明
- 行对齐处理:通过
resource.RowPitch获取D3D纹理实际行字节数,逐行拷贝时只复制有效像素数据(scWidth * CAMERA_CHANNELS字节),跳过每行末尾的填充部分。 - 直接构造cv::Mat:摒弃老旧的IplImage接口,直接创建CV_8UC4类型的cv::Mat,减少内存拷贝和兼容性问题。
- 像素格式适配:D3D纹理常用BGRA8格式,OpenCV默认BGR格式,如果不需要Alpha通道,可通过
cvtColor转为CV_8UC3的BGR图像。
内容的提问来源于stack exchange,提问作者S.T.A.L.K.E.R
相关产品推荐
相关产品推荐

