opencv当摄像头使用(使用OpenCV库操作摄像头拍照)
opencv当摄像头使用(使用OpenCV库操作摄像头拍照)录制avi传入图像mat,源码内部出现错误宕机录制完视频大小为6KB,avi格式时注意 目前测试,即使PC上有编码器,但是OpenCV存储mat为对应的录像视频文件失败,出现:录制完视频大小为200多B(基本为0),mp4格式时(查看入坑一)
需求
使用openCV做功能,播放摄像头(usb和网络),对摄像头设备进行参数调整(亮度、对比度、饱和度、色调、增益、曝光度)调节,拍照和录像。
原理
使用OpenCV打开摄像头(可打开USB和网路哦摄像头),渲染图像显示,可使用OpenCV属性调整摄像头的各项参数,使用拍照可以将当前图片拍照,使用录像可以从当前时间点开始录像直至停止录像
注意
目前测试,即使PC上有编码器,但是OpenCV存储mat为对应的录像视频文件失败,出现:
录制完视频大小为200多B(基本为0),mp4格式时(查看入坑一)
录制完视频大小为6KB,avi格式时
录制avi传入图像mat,源码内部出现错误宕机
运行效果:
核心代码
打开摄像头代码
bool OpenCVManager::startCapture(int usb int width int height) { if(!_pVideoCapture->open(usb)) { qDebug() << __FILE__ << __LINE__ << "Failed to start capture :" << usb; return false; } _width = width; _height = height; _pVideoCapture->set(CV_CAP_PROP_FRAME_WIDTH _width); _pVideoCapture->set(CV_CAP_PROP_FRAME_HEIGHT _height); _width = _pVideoCapture->get(CV_CAP_PROP_FRAME_WIDTH); _height = _pVideoCapture->get(CV_CAP_PROP_FRAME_HEIGHT); _pVideoCapture->set(CV_CAP_PROP_FPS 25); _brightness = _pVideoCapture->get(cv::CAP_PROP_BRIGHTNESS); _contrast = _pVideoCapture->get(cv::CAP_PROP_CONTRAST); _saturation = _pVideoCapture->get(cv::CAP_PROP_SATURATION); _hue = _pVideoCapture->get(cv::CAP_PROP_HUE); _gain = _pVideoCapture->get(cv::CAP_PROP_GAIN); _exposure = _pVideoCapture->get(cv::CAP_PROP_EXPOSURE); QTimer::singleShot(0 this SLOT(slot_captrueFrame())); return true; }
调整属性代码
bool OpenCVManager::getShowProperty() const { return _showProperty; } void OpenCVManager::setShowProperty(bool value) { _showProperty = value; } double OpenCVManager::getBrightness() { return _brightness; } void OpenCVManager::setBrightness(double value) { _brightness = value; if(_pVideoCapture) { _pVideoCapture->set(cv::CAP_PROP_BRIGHTNESS _brightness); } } double OpenCVManager::getContrast() const { return _contrast; } void OpenCVManager::setContrast(double value) { _contrast = value; if(_pVideoCapture) { _pVideoCapture->set(cv::CAP_PROP_CONTRAST _contrast); } } double OpenCVManager::getSaturation() const { return _saturation; } void OpenCVManager::setSaturation(double value) { _saturation = value; if(_pVideoCapture) { _pVideoCapture->set(cv::CAP_PROP_SATURATION _saturation); } } double OpenCVManager::getHue() const { return _hue; } void OpenCVManager::setHue(double value) { _hue = value; if(_pVideoCapture) { _pVideoCapture->set(cv::CAP_PROP_HUE _hue); } } double OpenCVManager::getGain() const { return _gain; } void OpenCVManager::setGain(double value) { _gain = value; if(_pVideoCapture) { _pVideoCapture->set(cv::CAP_PROP_GAIN _gain); } } double OpenCVManager::getExposure() const { return _exposure; } void OpenCVManager::setExposure(double value) { _exposure = value; if(_pVideoCapture) { _pVideoCapture->set(cv::CAP_PROP_EXPOSURE _exposure); } }
拍照代码
void PhotoAndRecordWidget::on_pushButton_photo_clicked() { QString timeStr = QDateTime::currentDateTime().toString("yyyy-MM-hh hh_mm_ss"); QString dirName = "photos"; if(!QFile::exists(dirName)) { QDir dir; if(!dir.mkdir(dirName)) { ui->label_state->setText("创建文件夹 " dirName "失败!!!"); } } QString filePath = QString("%1/%2.png").arg(dirName).arg(timeStr); if(_image.save(filePath)) { ui->label_state->setText("保存照片至: " filePath); }else{ ui->label_state->setText("保存照片失败!!!"); } }
录像代码
开启录像
void OpenCVManager::startRecord(QString pathFile) { // 多线程处理 QMetaObject::invokeMethod(this "slot_startRecord" Qt::DirectConnection Q_ARG(QString pathFile)); } void OpenCVManager::slot_startRecord(QString filePath) { if(_pVideoWrite) { qDebug() << __FILE__ << __LINE__ << "It's recording!!!"; return; } _pVideoWrite = new cv::VideoWriter; QString ext = filePath.mid(filePath.lastIndexOf(".") 1); int cvFourcc = 0; if(ext == "mpg") { cvFourcc = CV_FOURCC('D' 'I' 'V' 'X'); qDebug() << __FILE__ << __LINE__<< ext << "DIVX" << cvFourcc; }else if(ext == "avi") { cvFourcc = CV_FOURCC('M' 'J' 'P' 'G'); qDebug() << __FILE__ << __LINE__<< ext << "MJPG" << cvFourcc; }else if(ext == "mp4") { // mp4目前录制不成功(可以生成文件,但是打开失败) // cvFourcc = CV_FOURCC('M' 'P' '4' '2'); cvFourcc = CV_FOURCC('M' 'J' 'P' 'G'); // cvFourcc = CV_FOURCC('I' 'Y' 'U' 'V'); qDebug() << __FILE__ << __LINE__<< ext << "MP42" << cvFourcc; } _pVideoWrite->open(filePath.toStdString() cvFourcc 25 cv::Size(_width _height)); _recordFilePath = filePath; _recording = true; }
录像过程
void OpenCVManager::slot_captrueFrame() { if(!_running) { return; } if(_pVideoCapture->isOpened()) { cv::Mat mat; *_pVideoCapture >> mat; if(_showProperty) { cv::putText(mat QString("brightness: %1").arg(_brightness).toStdString() cvPoint(0 30) cv::FONT_HERSHEY_COMPLEX 1.0 cv::Scalar(255)); cv::putText(mat QString(" contrast: %1").arg(_contrast ).toStdString() cvPoint(0 60) cv::FONT_HERSHEY_COMPLEX 1.0 cv::Scalar(255)); cv::putText(mat QString("saturation: %1").arg(_saturation).toStdString() cvPoint(0 90) cv::FONT_HERSHEY_COMPLEX 1.0 cv::Scalar(255)); cv::putText(mat QString(" hue: %1").arg(_hue ).toStdString() cvPoint(0 120) cv::FONT_HERSHEY_COMPLEX 1.0 cv::Scalar(255)); cv::putText(mat QString(" gain: %1").arg(_gain ).toStdString() cvPoint(0 150) cv::FONT_HERSHEY_COMPLEX 1.0 cv::Scalar(255)); cv::putText(mat QString(" exposure: %1").arg(_exposure ).toStdString() cvPoint(0 180) cv::FONT_HERSHEY_COMPLEX 1.0 cv::Scalar(255)); cv::putText(mat QString("press ESC out").toStdString() cvPoint(0 210) cv::FONT_HERSHEY_COMPLEX 1.0 cv::Scalar(255)); } if(_recording) { _pVideoWrite->write(mat); } emit signal_captureOneFrame(mat); QTimer::singleShot(10 this SLOT(slot_captrueFrame())); } }
关闭录像
void OpenCVManager::stopRecord() { // 多线程处理 QMetaObject::invokeMethod(this "slot_stopRecord" Qt::DirectConnection); } void OpenCVManager::slot_stopRecord() { if(_pVideoWrite) { _recording = false; _pVideoWrite->release(); delete _pVideoWrite; _pVideoWrite = 0; } }
入坑记录
入坑一:录制视频保存为空
解决方法:
编解码器得问题,cv::VideoWrite查阅相关资料发现其只支持固定的几个格式,其中就包括avi。
入坑二:录制视频奔溃
原因:
因为初始设置摄像头的宽高(400 x 400),根据测试推断摄像头会默认给最接近初始化设置的分辨率,但是却不是直接是设置的(400 x 400)而是返回了最接近的分辨率(320 x 240),除非设置的分辨率正好是摄像头本身支持。
所以设置分辨率是需要摄像头硬件支持。
解决方法:
进一步验证同时解决该问题