若該文爲原創文章,未經容許不得轉載
原博主博客地址:https://blog.csdn.net/qq21497936
原博主博客導航:http://www.javashuo.com/article/p-wxwjppoc-mo.html
本文章博客地址:https://blog.csdn.net/qq21497936/article/details/108489004算法
紅胖子(紅模仿)的博文大全:開發技術集合(包含Qt實用技術、樹莓派、三維、OpenCV、OpenGL、ffmpeg、OSG、單片機、軟硬結合等等)持續更新中…(點擊傳送門)windows
嵌入式windows設備上的相機程序。
打開攝像頭,兼容多種攝像頭,攝像頭分辨率切換(攝像頭管理)。
對圖像進行翻轉、旋轉、亮度調整(圖像基本算法管理)
對調整後的圖像進行拍照、延時拍照。
對調整後的圖像進行錄像(編碼錄製)。
對照片和錄像進行回看(圖片瀏覽器、視頻播放器)
長時間運行穩定。瀏覽器
CSDN:https://download.csdn.net/download/qq21497936/12827160
QQ羣:1047134658(點擊「文件」搜索「camera」,羣內與博文同步更新)網絡
使用ffmpeg處理攝像頭、使用OpenCV處理錄像和播放;ide
《項目實戰:Qt+ffmpeg攝像頭檢測工具》
《項目實戰:Qt+OpenCV視頻播放器(支持播放器操做,如暫停、恢復、中止、時間、進度條拽託等)》
《OpenCV開發筆記(四):OpenCV圖片和視頻數據的讀取與存儲》
《FFmpeg開發筆記(一):ffmpeg介紹、windows開發環境搭建(mingw和msvc)》工具
FfmpegCameraManager.h:攝像頭管理類ui
#ifndef FFMPEGCAMERAMANAGER_H #define FFMPEGCAMERAMANAGER_H /************************************************************\ * 控件名稱: FfmpegCameraManager, ffmpeg管理類(用於攝像頭操做) * 控件描述: * 1.打開攝像頭 * 2.支持動態切換分辨率 * 做者:紅模仿 聯繫方式:QQ21497936 * 博客地址:https://blog.csdn.net/qq21497936 * 日期 版本 描述 * 2018年09年14日 v1.0.0 ffmpeg模塊封裝空類 * 2020年09年05日 v1.1.0 ffmpeg打開攝像頭,支持的動態分辨率切換 * 2020年09年08日 v1.2.0 兼容各類攝像頭,解決內存溢出bug,對最高幀率作了支持範圍內的限制 * 限制幀率通常爲25fps(除非最大小於25fps或者最小大於25fps) \************************************************************/ #include <QObject> #include <QString> #include <QDebug> #include <QTimer> #include <QThread> #include <QImage> #include <QProcess> #include <QMessageBox> #include <QDateTime> extern "C" { #include "libavcodec/avcodec.h" #include "libavformat/avformat.h" #include "libswscale/swscale.h" #include "libavdevice/avdevice.h" #include "libavformat/version.h" #include "libavutil/time.h" #include "libavutil/mathematics.h" #include "libavformat/avformat.h" #include "libswscale/swscale.h" #include "libswresample/swresample.h" #include "errno.h" #include "error.h" } #define LOG qDebug()<<__FILE__<<__LINE__<<QDateTime::currentDateTime().toString("hh:mm:ss:zzz") class FfmpegCameraManager : public QObject { Q_OBJECT public: public: explicit FfmpegCameraManager(QObject *parent = nullptr); signals: void signal_captureOneFrame(QImage image); public: static QString getAvcodecConfiguration(); public: bool init(); bool openUsbCamera(); QString getUsbCameraName(); QList<QString> getUsbCameraInfo(); int getCurrentFps(); int getCurrentSizeFpsIndex(); QList<QSize> getListSize() const; public slots: void slot_start(); void slot_stop(); void slot_setSizeFps(int index); protected slots: void slot_captureOneFrame(); signals: public slots: private: static bool _init; AVFormatContext *_pAVFormatContext; // 全局上下文 AVInputFormat *_pAVInputFormat; AVDictionary* _pAVDictionary; // 打開編碼器的配置 AVCodecContext *_pAVCodecContextForAudio; // 音頻解碼器上下文 AVCodecContext *_pAVCodecContextForVideo; // 視頻解碼器上下文(不帶音頻) AVCodec * _pAVCodecForAudio; // 音頻解碼器 AVCodec * _pAVCodecForVideo; // 視頻解碼器(不帶音頻) int _streamIndexForAudio; // 音頻流序號 int _streamIndexForVideo; // 視頻流序號 SwrContext *_pSwrContextForAudio; // 音頻轉換上下文 bool _running; bool _first; bool _opened; uint8_t *_pOutBuffer; AVFrame * _pFrame; AVFrame * _pFrameRGB; AVPacket *_pAVPacket; SwsContext *_pSwsContext; int _videoIndex; QString _cameraDescription; QList<QSize> _listSize; QList<int> _listFps; QList<QString> _listSizeFpsInfo; int _currentSizeFpsIndex; }; #endif // FfmpegCameraManager_H
FfmpegCameraManager.cpp:攝像頭管理類this
... bool FfmpegCameraManager::openUsbCamera() { if(!_init) { LOG << "未初始化"; return true; } _pAVInputFormat = av_find_input_format("dshow"); if(!_pAVInputFormat) { LOG << "Failed to av_find_input_format"; return false; } if(_cameraDescription == "") { LOG << "無攝像頭"; return false; } QString cameraDescription = QString("video=%1").arg(_cameraDescription); if(_listSizeFpsInfo.size() == 0) { LOG << "未獲取到分辨率和幀率"; return false; } // 設置分辨率 av_dict_set(&_pAVDictionary, "video_size", QString("%1x%2").arg(_listSize.at(_currentSizeFpsIndex).width()) .arg(_listSize.at(_currentSizeFpsIndex).height()).toUtf8().data(), 0); // 設置幀率 int frame = _listFps.at(_currentSizeFpsIndex); av_dict_set(&_pAVDictionary, "framerate", QString("%1").arg(frame).toUtf8().data(), 0); LOG << "打開攝像頭:" << _cameraDescription << "分辨率:" << _listSize.at(_currentSizeFpsIndex).width() << "x" << _listSize.at(_currentSizeFpsIndex).height() << "幀率:" << _listFps.at(_currentSizeFpsIndex); if(avformat_open_input(&_pAVFormatContext, cameraDescription.toUtf8().data(), _pAVInputFormat, &_pAVDictionary) != 0) { LOG << "打開攝像頭失敗"; return false; } LOG << "打開攝像頭成功"; _first = true; _opened = true; QTimer::singleShot(0, this, SLOT(slot_captureOneFrame())); return true; } ...
OpenCVManager.h:錄像與播放視頻類編碼
#ifndef OPENCVMANAGER_H #define OPENCVMANAGER_H /************************************************************\ * 控件名稱: OpenCVManager,OpenCV管理類 * 控件描述: * 1.OpenCV操做支持 * 2.支持錄像(.avi格式) * 做者:紅模仿 聯繫方式:QQ21497936 * 博客地址:https://blog.csdn.net/qq21497936 * 日期 版本 描述 * 2019年11月09日 v1.0.0 opencv拍照和錄像Demo * 2020年09月07日 v1.1.0 增長了單純錄像的接口 \************************************************************/ #include <QObject> #include <QImage> #include <QDateTime> #include <QTimer> // opencv #include "opencv/highgui.h" #include "opencv/cxcore.h" #include "opencv2/core/core.hpp" #include "opencv2/highgui/highgui.hpp" #include "opencv2/opencv.hpp" class OpenCVManager : public QObject { Q_OBJECT public: explicit OpenCVManager(QObject *parent = nullptr); ~OpenCVManager(); public: QString getWindowTitle() const; double getBrightness(); double getContrast() const; double getSaturation() const; double getHue() const; double getGain() const; bool getShowProperty() const; double getExposure() const; int getRotate() const; bool getMirror() const; public: void setBrightness(double value); void setContrast(double value); void setSaturation(double value); void setHue(double value); void setGain(double value); void setShowProperty(bool value); void setExposure(double value); void setRotate(int rotate); void setMirror(bool mirror); signals: void signal_captureOneFrame(cv::Mat mat); // 接收圖像後拋出信號 public: bool startCapture(int usb, int width = 1280, int height = 720); // 打開攝像頭, 0... bool startCapture(QString url, int width = 1280, int height = 720); // 打開攝像頭, 網絡攝像頭地址 bool stopCapture(); // 關閉攝像頭 void startRecord(QString filePath); // 開始錄像(使用的是opencv打開的攝像頭) void stopRecord(); // 中止錄像(使用的是opencv打開的攝像頭) public slots: void slot_inputRecordImage(QImage image); void slot_stopRecordFormOut(); public: // 單獨的一塊業務,使用的是開始錄像後,從類外面輸入QImage進行錄像 void startRecordFromOut(QString filePath, int fps); void inputRecordImage(QImage image); void stopRecordFormOut(); public slots: bool start(); // 開啓線程 bool stop(); // 關閉線程 protected slots: void slot_captrueFrame(); // 消息循環獲取圖像 void slot_stopCapture(); // 當正在採集中時(>>時),關閉攝像頭會致使程序崩潰,因此採集與中止放一個線程中(消息循環) protected slots: void slot_startRecord(QString filePath); // 錄像(使用的是opencv打開的攝像頭) void slot_stopRecord(); // 中止錄屏(使用的是opencv打開的攝像頭) public: static QImage cvMat2QImage(const cv::Mat &mat); static cv::Mat image2Mat(QImage image); // Qimage 轉 cv::Mat static QImage mat2Image(cv::Mat mat); // cv::Mat 轉 QImage private: cv::VideoCapture *_pVideoCapture; // 攝像頭實例 cv::VideoWriter *_pVideoWrite; // 錄像實例 QString _recordFilePath; // 錄製文件路徑 bool _running; // 線程是否運行 bool _showProperty; // 是否顯示屬性參數 double _brightness; // 亮度 double _contrast; // 對比度 double _saturation; // 飽和度 double _hue; // 色調 double _gain; // 增益 double _exposure; // 曝光度 int _width; // 寬度 int _height; // 高度 bool _recording; // 標誌是否正在錄像 bool _startRecording; int _rotate; // 旋轉度數 bool _mirror; // 是否翻轉 int _fps; // 幀率 int _index; // 幀序號 private: cv::VideoWriter *_pVideoWriteForOut; // 錄像實例(從外部輸入圖像,非從opencv打開攝像頭) QString _recordFilePathForOut; // 錄像文件路徑(從外部輸入圖像,非從opencv打開攝像頭) private: QString _windowTitle; }; #endif // OPENCVMANAGER_H
OpenCVManager.h:錄像與播放視頻類url
... void OpenCVManager::inputRecordImage(QImage image) { if(!_startRecording) { return; } cv::Mat mat = image2Mat(image); if(!_recording) { QString ext = _recordFilePath.mid(_recordFilePathForOut.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 << "avi" << cvFourcc; }else if(ext == "mp4") { // mp4目前錄製不成功(能夠生成文件,可是打開失敗) cvFourcc = CV_FOURCC('M','P','4','2'); qDebug() << __FILE__ << __LINE__<< ext << "MP42" << cvFourcc; } qDebug() << __FILE__ << __LINE__ << mat.type() << mat.channels(); _pVideoWriteForOut->open(_recordFilePath.toStdString(), cvFourcc, _fps, cv::Size(mat.cols, mat.rows)); std::vector<cv::Mat> listMat; cv::split(mat, listMat); std::vector<cv::Mat> listMat2; // 因爲opencv對avi中mat的限制大小隻能爲0xFFFF,修改源碼突破限制爲0xFFFFFFFF後 // 在錄像時,發現錄入的mat是正確的,錄製出來通道顏色變換了,須要手動對顏色通道進行修正 // 注意:僅限avi使用mjpg編碼格式 // 1 2 0 偏綠 // 0 1 2 偏藍 // 0 2 1 偏綠 // 1 2 3 嚴重不對 // 2 0 1 偏藍 // 2 1 0 偏藍 listMat2.push_back(listMat.at(0)); listMat2.push_back(listMat.at(1)); listMat2.push_back(listMat.at(2)); cv::merge(listMat2, mat); _pVideoWriteForOut->write(mat); _recording = true; }else{ std::vector<cv::Mat> listMat; cv::split(mat, listMat); std::vector<cv::Mat> listMat2; listMat2.push_back(listMat.at(0)); listMat2.push_back(listMat.at(1)); listMat2.push_back(listMat.at(2)); cv::merge(listMat2, mat); _pVideoWriteForOut->write(mat); } } ...
若該文爲原創文章,未經容許不得轉載
原博主博客地址:https://blog.csdn.net/qq21497936
原博主博客導航:http://www.javashuo.com/article/p-wxwjppoc-mo.html
本文章博客地址:https://blog.csdn.net/qq21497936/article/details/108489004