Opencv获取Usb摄像头的功能是非常简单易用的,但存在一个致命的问题就是摄像头断开了不知道o(╥﹏╥)o。
有一种常用的办法就是隔一段时间检测一次CV_CAP_PROP_HUE是否正常(网上最最常用的方法):
cv::VideoCapture m_v;
...
double dHue = m_v.get(CV_CAP_PROP_HUE);
if (dHue != 0)
{
LOG("摄像头断开\n");
m_v.release();
}
但是实际使用时,这个方法不能检测到所有的情况。(当然可能是因为我是隔一段时间才检测一次的缘故,但这个操作比较耗时,不可能一直检测)
通过调试发现,当摄像头断开后,每次read()虽然返回的还是true,Mat也不是empty,但是Mat的数据都是上一次的数据,于是推测可以通过直接判断Mat的内容来判断摄像头是否正常。经过调试发现摄像头断开时Mat的数据的确是初始状态的。于是可以通过检测read()后的Mat来判断摄像头是否正常:
bool checkMat(cv::Mat& mat)
{
for (int i = 0; i < mat.rows; i++)
{
uchar* pRow = (unsigned char*)mat.ptr<uchar>(i);
for (int j = 0; j < mat.cols * mat.channels(); j++)
{
#ifdef _DEBUG
if (pRow[j] != 0xcd)
#else
if (pRow[j])
#endif
{
return true;
}
}
}
return false;
}
在正常状态下,这个判断是很快的,所有这个判断可以在每一帧的后面使用。当然,这个要求Mat每次都得初始化。
cv::Mat m;
while (true)
{
m.release();
m_v.read(m);
if (!checkMat(frame))
{
LOG("摄像头断开\n");
m_v.release();
}
...
}
这样就能实时检测摄像头是否正常了。(^▽^)
当然,如果有更加高效的检测方法也欢迎在评价中留言。