C++ 在cam视频显示中闪烁,为什么?

C++ 在cam视频显示中闪烁,为什么?,c++,winapi,video,opencv,flicker,C++,Winapi,Video,Opencv,Flicker,即使我(认为我)关闭了背景擦除功能,我的cam视频显示仍会闪烁。为什么? 甚至视频演示文稿上方的文本显示也会闪烁 完整代码 可能是最相关的代码,显示视频的gizmo: class ImageDisplay: public gizmo::SubGizmo { typedef gizmo::SubGizmo Base; private: winapi::graphics::ColorDib dib_; protected: void onPaint( raw::

即使我(认为我)关闭了背景擦除功能,我的cam视频显示仍会闪烁。为什么?

甚至视频演示文稿上方的文本显示也会闪烁

完整代码

可能是最相关的代码,显示视频的gizmo:

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 );
    }
}
void imageProducer(
wstring常量和名称模式,
PutFunction const putResult,
线程::控制常量和线程控制
)
{
断言(!!putResult);
cv::VideoCapture cap(0);//打开默认相机。
希望(cap.isopend())
||throwX(“cam::imageProducer:VideoCapture::failed”);
对于(;;)
{
cv::垫架;
if(threadControl.exitIsRequested()){return;}
cap>>frame;//从相机获取新帧。
if(threadControl.exitIsRequested()){return;}
结果(框架);
}
}
putResult
函数只调用Windows的
SendMessage
,它与显示线程同步

我看不出闪烁是如何潜入的


EDIT:我找到了一个修复方法,即将
WS_CLIPCHILDREN
添加到主窗口,并使用
RedrawWindow
强制立即重画控件(子窗口)。这是一个很大的谜团。更大的谜团:如果不应用
重画窗口
WS_CLIPCHILDREN
会导致极度缓慢,比如每20秒1帧

编辑2:它没有持续下去:-(

编辑3*SOLVEDD*。这是罪过。所有的闪烁都是由主窗口代码中对
无效设置的不适当调用引起的。我可能只是为了测试东西而把它放在那里,但忘记了删除它。啊!

这是罪过。所有的闪烁都是由对窗口的不适当调用引起的s'
invalidate
,在主窗口代码中。我可能只是为了测试东西而在那里打了那个调用,但忘了删除它。啊

学习点:


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

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