博客 / 詳情

返回

基於OpenCV+QT開發超實用的視頻編輯器

1. 背景

在生活工作當中,很多時候我們都有裁剪、水印、旋轉等視頻編輯的需求。作為一個程序員,這些需求我們常常用ffmpeg命令工具搞定。但是ffmpeg命令工具可見性和可操作性差。

現在隨着深度學習和人工智能熱門,大量的技術涌現,但opencv作為老牌的圖像視頻庫,一直是在大量的生產環境(包括嵌入式設備)中應用,不管你用什麼深度學習的平台,opencv都是作為圖像圖像領域及佳的選擇,可以很方便的與第三方深度學習框架結合 ,提供基礎算法支持。

而用過或者學習過QT的同學們都知道這是c++程序員必須學習的技能,包括現在熱門的Python也是在大量的應用QT來做界面,QT的設計及其精美,他的信號槽機制很好的將界面與業務隔離開來,並且界面可以使用類似CSS的設置做得很炫,不會像MFC一樣自動生成的代碼和你手寫的代碼融合在一起,而且QT還有一項跨平台能力(包括Windows、Linux、Mac、iphone,Android等平台)。

今天我們基於OpenCV+QT開發一款帶UI界面的視頻編輯工具。在滿足我們功能的基礎上,充分了解和學期opencv及QT技術。

2. 功能介紹

編輯工具的功能主要包含:

  1. 視頻畫面添加水印;
  2. 視頻畫面亮度調整;
  3. 視頻畫面對比度調整;
  4. 視頻畫面旋轉;
  5. 視頻畫面鏡像;
  6. 視頻尺寸調整;
  7. 視頻圖像模糊;
  8. 兩路視頻融合。

編輯工具操作界面如下圖所示:

image.png

3. OpenCV實戰

3.1 OpenCV 環境搭建

今天我們用的是3.4版本,基於Mac環境搭建。下載源碼後執行如下命令編譯:

git clone https://github.com/opencv/opencv.git
cd opencv 
mkdir build
cd build
cmake -D CMAKE_BUILD_TYPE=RELEASE -D CMAKE_INSTALL_PREFIX=/usr/local/opencv3 -D BUILD_opencv_world=ON -D WITH_GSTREAMER=OFF -D OPENCV_ENABLE_NONFREE=ON ..
make -j8
sudo make install

如果編譯順利的話,最終opencv相關lib庫,頭文件include均會安裝到/usr/local/opencv3

3.2 OpenCV核心類型Mat介紹

Mat類是Opencv中儲存圖像的一種數據結構。Mat類可以看做是存放矩陣的容器,他包含了兩部分,分別是用來存放圖片信息的信息頭,和一個指向圖片儲存矩陣的指針。信息頭往往佔用空間比較小,而且各個圖片之間的信息頭是完全獨立的。而圖片儲存矩陣往往佔用較大的空間,並且可以多個圖片的矩陣指針指向同一個內存空間。下面主要減少利用Mat創建矩陣。

3.2.1 利用Mat類的構造函數創建矩陣

Mat類有很多構造函數可以用來創建矩陣結構,並且給與賦值,這裏距離介紹一種,其函數定義為

 Mat(int rows, int cols, int type, const Scalar& s);

這個構造函數具有四個參數,其特點是能夠定義矩陣的結構並且能夠賦予初值

  • 第一個參數表示矩陣的行數
  • 第二個參數表示矩陣的列數
  • 第三個參數表示矩陣儲存數據的類型,具有格式 CV_[位數] [有無符號] [數據類型] [通道數],如CV_8UC3 表示存儲數據為8位無符號char類型,並且具有三個通道
  • 第四個參數是一種向量類型的變量,能夠給予矩陣賦予初值,這個向量最多有四個維度。

3.2.2 利用成員函數create創建矩陣

使用這種方法創建的矩陣只是一種開闢內存空間,而不能賦予初值

Mat m;
m.create(3, 3, CV_8UC3);

3.3 OpenCV圖像處理實戰

上面我們功能介紹裏面提到了旋轉、裁剪都功能均可以利用OpenCV提供的現成函數實現。用到頭文件:

#include <opencv2/imgcodecs.hpp>
#include <opencv2/imgproc.hpp>
#include <opencv2/highgui.hpp>
#include <iostream>

using namespace cv;
cv::Mat src1, src2;
cv::Mat dest; //src1.copyTo(dest);

3.3.1 旋轉

//旋轉90度
rotate(dest, dest, ROTATE_90_COUNTERCLOCKWISE);
//旋轉180度
rotate(dest, dest, ROTATE_180);

3.3.2 翻轉

//左右上下翻轉
flip(dest, dest, -1);
//上下翻轉
flip(dest, dest, 1);
//左右翻轉
flip(dest, dest, 0);

3.3.3 修改大小

cv::resize(dest, dest, Size(width, height));

3.3.4 裁剪

dest = dest(Rect(x, y, w, h));

3.3.5 灰度

cvtColor(dest,dest, COLOR_BGR2GRAY);

3.3.6 混合

addWeighted(src2, a, dest, 1-a,0,dest);

3.4 OpenCV視頻IO接口

上面介紹的均為基於圖片的操作,我們要操作的是視頻,其實視頻都是有一幀一幀的圖像組成,圖像知道怎麼處理了就可以開始處理視頻了。OpenCV為我們提供了視頻的IO接口:

3.4.1 打開視頻源

VideoCapture cap1;
bool ret = cap1.open(file);
//獲取幀率
fps = cap1.get(CAP_PROP_FPS);
//獲取視頻寬度
width = cap1.get(CAP_PROP_FRAME_WIDTH);
//獲取視頻高度
height = cap1.get(CAP_PROP_FRAME_HEIGHT);

3.4.1 讀取視頻幀

Mat mat1;
cap1.read(mat1);

4. QT實戰

4.1 環境搭建

基於官方教程https://doc.qt.io/qt-5/macos.html安裝QTCreator即可。

新建視頻編輯工程,在pro配置文件中增加opencv庫路徑:

DEFINES += QT_MULTIMEDIA_LIB QT_WIDGETS_LIB

LIBS += -L"/usr/local/opencv3/lib" \
    -lopencv_core \
    -lopencv_highgui  \
    -lopencv_imgproc   \
    -lopencv_ml \
    -lopencv_objdetect \
    -lopencv_video \
    -lopencv_dnn \
    -lopencv_imgcodecs \
    -lopencv_shape \
    -lopencv_videoio \

4.2 繪製視頻

視頻繪製我們基於QT提供的QOpenGLWidget,通過QOpenGLWidget提供的機制將Mat中的圖像內容渲染到屏幕:

QImage img;
void CustomQOpenGLWidget::SetImage(cv::Mat mat){
    QImage::Format fmt = QImage::Format_RGB888;
    int pixSize = 3;
    if(mat.type() == CV_8UC1){
        fmt = QImage::Format_Grayscale8;
        pixSize = 1;
    }
    if(img.isNull() || img.format() != fmt){
        delete img.bits();
        uchar *buf = new uchar[width()*height() * pixSize];
        img = QImage(buf, width(), height(), fmt);
    }
    Mat des;
    cv::resize(mat, des, Size(img.size().width(), img.size().height()));
    if(pixSize > 1){
        cv::cvtColor(des, des, COLOR_BGR2RGB);
    }
    memcpy(img.bits(), des.data, des.rows*des.rows*des.elemSize());
    update();
}
void CustomQOpenGLWidget::paintEvent(QPaintEvent *e){
     QPainter p;
     p.begin(this);
     p.drawImage(QPoint(0, 0),img);
     p.end();
 }

5. 總結

至此我們已經基於OpenCV+QT實現了一個簡單實用的視頻編輯工具。當然我們也可以基於ffmpeg的視頻IO + OpenGL實現;也可以基於OpenGl + OpenCV實現Android、iOS平台的編輯工具。方法有很多,我們選擇用最少的代碼進行最快的實現。

當然裏面也會涉及很多細節,包括視頻的同步,線程的同步,以及音頻合成以及音視頻同步。後面的文章我們在介紹這方面的內容。

user avatar mengzyou 頭像 wuduyouou_5de642de9c1e5 頭像 yjx 頭像 wangying_5ea4fb9de961c 頭像
4 位用戶收藏了這個故事!

發佈 評論

Some HTML is okay.