【问题标题】:Flickering in cam video display, why?cam 视频显示闪烁,为什么?
【发布时间】:2012-03-17 19:15:50
【问题描述】:

即使我(我认为我)关闭了背景擦除,我的摄像头视频显示也会闪烁。为什么?

即使是视频演示上方的文本显示也会闪烁。

完整代码at Bitbucket.

也许是最相关的代码,显示视频的小工具:

class ImageDisplay:
    public gizmo::SubGizmo
{
typedef gizmo::SubGizmo Base;
private:
    winapi::graphics::ColorDib      dib_;

protected:
    void onPaint( raw::DcHandle const dc ) CPP_IS_OVERRIDE
    {
        dib_.renderOn( dc );
    }

    bool onWmEraseBkgnd( raw::DcHandle const dc )
    {
        CPP_DECLARE_UNUSED( dc );
        return true;        // Just say it's done, so it won't be done again.
    }

    void onWmPaint() CPP_IS_OVERRIDE
    {
        callOnPaint();
    }

    virtual raw::LResult dispatchWm(
        raw::UInt const     messageId,
        raw::WParam const   wParam,
        raw::LParam const   lParam
        )
    {
        CPP_DUMMY_USE_OF( wParam );  CPP_DUMMY_USE_OF( lParam );

        typedef ImageDisplay W;
        switch( messageId )
        {
        case WM_ERASEBKGND:
            return FORWARD_WM_TO( this, W::onWmEraseBkgnd, WM_ERASEBKGND, wParam, lParam );
        }

        return Base::dispatchWm( messageId, wParam, lParam );
    }

public:
    void setImage( cvapi::ImageRef const newImage )
    {
        dib_ = win_cv::dibFrom( newImage );
        setExtent( newImage.extent() );
    }

    ImageDisplay(
        Gizmo&                  parent,
        int const               x,
        int const               y,
        cvapi::ImageRef const&  pic
        )
        : Base( parent, x, y, pic.width(), pic.height() )
        , dib_( win_cv::dibFrom( pic ) )
    {}
};

视频制作线程的主要代码:

void imageProducer( 
    wstring const&              namePattern,
    PutFunction const           putResult,
    Thread::Control const&      threadControl
    )
{
    assert( !!putResult );

    cv::VideoCapture cap( 0 );  // Open the default camera.
    hopefully( cap.isOpened() )
        || throwX( "cam::imageProducer: VideoCapture::<init> failed" );

    for(;;)
    {
        cv::Mat frame;

        if( threadControl.exitIsRequested() ) { return; }
        cap >> frame;           // Get a new frame from camera.

        if( threadControl.exitIsRequested() ) { return; }
        putResult( frame );
    }
}

putResult 函数只是调用 Windows 的 SendMessage,它与显示线程同步。

我看不到闪烁是如何设法潜入的?


编辑:我找到了一个修复方法,即将WS_CLIPCHILDREN 添加到主窗口,并使用RedrawWindow 强制立即重绘控件(子窗口)。为什么它起作用的大谜团。更大的谜团:没有应用RedrawWindowWS_CLIPCHILDREN 会导致极度缓慢,比如每 20 秒 1 帧?

EDIT 2:没有持续。 :-(

编辑 3* S O L V E D *。和mea culpa。所有这些闪烁都是由主窗口代码中对InvalidateRect 的不当调用引起的。我可能只是为了测试而把它放在那里,而忘记删除它。啊!

【问题讨论】:

  • 你双缓冲输出了吗?
  • @DeadMG:我不确定这是否适用。正如您在上面看到的,我只是将图像复制到一个 DIB,然后在 WM_PAINT 上对该 DIB 进行位爆破。双缓冲是您在显示读取另一个缓冲区时写入一个缓冲区,然后将它们切换到下一个周期。
  • @Alf:双缓冲适用于您想要显示平滑动画图像的任何情况。
  • @DeadMG:嗯,它有点双缓冲。但是使用 WM_PAINT 您可以复制到设备上下文。我想我必须使用特定于供应商的显卡来进行真正的双缓冲。
  • 我想,如果打开表单的双缓冲也很重要。

标签: c++ winapi video opencv flicker


【解决方案1】:

过失。所有这些闪烁都是由于在主窗口代码中对 Windows 的 InvalidateRect 的不当调用引起的。我可能只是为了测试东西而把那个电话放在那里,而忘记删除它。啊!

学习点:

在您完全检查自己代码中的所有内容之前,不要责怪“系统”(这里是 Windows API,还有编译器等)。这就像你眼镜上的脏指纹。你从来没有把手指放在眼镜上,但这些指纹却出现了;与代码中神秘的不良语句相同。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-04-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-09-29
    • 2013-05-17
    • 2013-04-29
    相关资源
    最近更新 更多