【发布时间】: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 强制立即重绘控件(子窗口)。为什么它起作用的大谜团。更大的谜团:没有应用RedrawWindow,WS_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