DirectX Histogram Effect无输出图像,局部边界为{0,0,0,0}问题排查
Direct2D Histogram Effect输出为空问题解决
我在演示Direct2D的Histogram Effect时遇到输出为空的问题:尝试切换硬件/软件渲染目标、确保输入位图宽度与bins数量匹配,且EndDraw未返回HR错误,但输出始终无内容,且输出图像的局部边界矩形为{0}。代码对其他单输入效果有效,仅Histogram Effect失效。
附上问题代码:
bool Display_Demo_Effect(ID2D1RenderTarget *arg_render_tgt, CLSID arg_clsid = CLSID_D2D1Histogram) { // DBG_TRACKER_FUNCTION_NAME_T; if (!arg_render_tgt) { return false; } if (arg_clsid == CLSID_NULL) { return false; } CComPtr<ID2D1DeviceContext> ccptr_dvctxt = nullptr; CComPtr<ID2D1BitmapRenderTarget> ccptr_bitmap_tgt = nullptr; CComPtr<ID2D1SolidColorBrush> ccptr_brush_sc = nullptr; CComPtr<ID2D1Bitmap> ccptr_bitmap = nullptr; CComPtr<ID2D1Effect> ccptr_demo_effect = nullptr; HRESULT hr = S_OK; bool alt_bmp_method = false; arg_render_tgt->QueryInterface(&ccptr_dvctxt); if (!ccptr_dvctxt) { /* Error Message */ return false; } if (alt_bmp_method) { // Match the default bins count D2D1_SIZE_F des_sz_f = { 256.0f, 256.0f }; D2D1_SIZE_U des_sz_u = { 256, 256 }; hr = ccptr_dvctxt->CreateCompatibleRenderTarget(des_sz_f, des_sz_u, &ccptr_bitmap_tgt); } else { // Default creation method hr = ccptr_dvctxt->CreateCompatibleRenderTarget(&ccptr_bitmap_tgt); } if (FAILED(hr)) { /* Error Message */ return false; } D2D1_COLOR_F demo_colr = { 0.45f, 0.56f, 0.72f, 0.66f }; D2D1_COLOR_F clr_colr = { 0.5f, 0.5f, 0.5f, 1.0f }; D2D1_ELLIPSE demo_ellipse = D2D1::Ellipse ( D2D1::Point2F(128.0f, 128.0f), 100.0f, 100.0f ); hr = ccptr_bitmap_tgt->CreateSolidColorBrush(demo_colr, &ccptr_brush_sc); if (FAILED(hr)) { /* Error Message */ return false; } // Draw an Ellipse on the bitmap ccptr_bitmap_tgt->BeginDraw(); hr = ccptr_bitmap_tgt->Flush(); ccptr_bitmap_tgt->Clear( {0.0f, 0.0f, 0.0f, 0.0f} ); ccptr_bitmap_tgt->FillEllipse(&demo_ellipse, ccptr_brush_sc); hr = ccptr_bitmap_tgt->EndDraw(); if (FAILED(hr)) { /* Error Message */ return false; } // Expose the bitmap ccptr_bitmap_tgt->GetBitmap(&ccptr_bitmap); if (FAILED(hr)) { /* Error Message */ return false; } hr = ccptr_dvctxt->CreateEffect(arg_clsid, &ccptr_demo_effect); if (FAILED(hr)) { /* Error Message */ return false; } // Configure the effect's input ccptr_demo_effect->SetInput(0, ccptr_bitmap); // Special considerations for Histogram if (arg_clsid == CLSID_D2D1Histogram) { UINT32 parm_bins = 256; ccptr_demo_effect->SetValue(D2D1_HISTOGRAM_PROP_NUM_BINS, parm_bins); ccptr_demo_effect->SetValue(D2D1_HISTOGRAM_PROP_CHANNEL_SELECT, D2D1_CHANNEL_SELECTOR_G); D2D1_RECT_F inp_local_rc = { 0.0f }; D2D1_RECT_F out_local_rc = { 0.0f }; D2D1_SIZE_F inp_sz = { 0.0f }; D2D1_SIZE_F out_sz = { 0.0f }; CComPtr<ID2D1Image> ccptr_inp_image = nullptr; CComPtr<ID2D1Image> ccptr_out_image = nullptr; ccptr_demo_effect->GetInput(0, &ccptr_inp_image); ccptr_demo_effect->GetOutput(&ccptr_out_image); // Display the input image local bounds if (ccptr_inp_image) { hr = ccptr_dvctxt->GetImageLocalBounds(ccptr_inp_image, &inp_local_rc); inp_sz = { fabsf(inp_local_rc.right - inp_local_rc.left), fabsf(inp_local_rc.bottom - inp_local_rc.top) }; // DisplayRC_Via_MsgBox(inp_local_rc); // DisplaySZ_Via_MsgBox(inp_sz); } if (ccptr_out_image) { hr = ccptr_dvctxt->GetImageLocalBounds(ccptr_out_image, &out_local_rc); out_sz = { fabsf(out_local_rc.right - out_local_rc.left), fabsf(out_local_rc.bottom - out_local_rc.top) }; // DisplayRC_Via_MsgBox(out_local_rc); // DisplaySZ_Via_MsgBox(out_sz); } } // Prove the dvctxt and input bitmap are valid ccptr_dvctxt->BeginDraw(); hr = ccptr_dvctxt->Flush(); ccptr_dvctxt->Clear(clr_colr); ccptr_dvctxt->DrawImage(ccptr_bitmap); hr = ccptr_dvctxt->EndDraw(); if (FAILED(hr)) { /* Error Message */ return false; } Sleep(3000); // Display the Effect: nothing is drawn ccptr_dvctxt->BeginDraw(); hr = ccptr_dvctxt->Flush(); ccptr_dvctxt->Clear(clr_colr); ccptr_dvctxt->DrawImage(ccptr_demo_effect); hr = ccptr_dvctxt->EndDraw(); // No failure even though nothing is displayed if (FAILED(hr)) { /* Error Message */ return false; } Sleep(3000); // Clear the window ccptr_dvctxt->BeginDraw(); hr = ccptr_dvctxt->Flush(); ccptr_dvctxt->Clear( {0.0f, 0.0f, 0.0f, 0.0f} ); hr = ccptr_dvctxt->EndDraw(); return true; }
问题根源
Histogram Effect的核心特性是计算图像的直方图统计数据,而非生成可视化的直方图图像。它的输出不是可直接绘制的图像资源,而是存储在D2D1_HISTOGRAM_PROP_HISTOGRAM_OUTPUT属性中的数值数组,因此直接调用DrawImage绘制它的输出不会显示任何内容,且输出图像的局部边界为{0}是正常行为。
修复方案
1. 获取直方图统计数据
在配置Histogram Effect后,添加代码读取统计结果:
if (arg_clsid == CLSID_D2D1Histogram) { UINT32 parm_bins = 256; ccptr_demo_effect->SetValue(D2D1_HISTOGRAM_PROP_NUM_BINS, parm_bins); ccptr_demo_effect->SetValue(D2D1_HISTOGRAM_PROP_CHANNEL_SELECT, D2D1_CHANNEL_SELECTOR_G); // 新增:读取直方图数据 std::vector<float> histogramData(parm_bins); hr = ccptr_demo_effect->GetValue( D2D1_HISTOGRAM_PROP_HISTOGRAM_OUTPUT, histogramData.data(), sizeof(float) * parm_bins ); if (FAILED(hr)) { /* 错误处理 */ } // ... 原有代码 }
2. 手动绘制可视化直方图
拿到统计数据后,需要自行绘制柱状图来展示结果。替换原代码中直接绘制Effect的部分:
// 替换原有的Effect绘制代码 ccptr_dvctxt->BeginDraw(); ccptr_dvctxt->Clear(clr_colr); UINT32 binCount = 256; float barWidth = 256.0f / binCount; float maxValue = 1.0f; // 找到统计值的最大值,用于归一化柱状图高度 for (float value : histogramData) { if (value > maxValue) maxValue = value; } // 绘制每个bin的柱状图 for (UINT32 i = 0; i < binCount; ++i) { float barHeight = (histogramData[i] / maxValue) * 200.0f; // 200为直方图最大高度 D2D1_RECT_F barRect = { i * barWidth, 256.0f - barHeight, // 从底部向上绘制 (i + 1) * barWidth, 256.0f }; ccptr_dvctxt->FillRectangle(barRect, ccptr_brush_sc); } hr = ccptr_dvctxt->EndDraw();
3. 额外注意事项
- 确保输入位图的像素格式支持所选通道:代码中选择的是G通道,当前的颜色设置和位图格式是兼容的。
- 读取直方图数据时,数组大小必须与
D2D1_HISTOGRAM_PROP_NUM_BINS设置的值一致,避免越界。
内容的提问来源于stack exchange,提问作者Sempai-Dami1
相关产品推荐
相关产品推荐

