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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.22 22:55:57