OpenCV 基本使用

守望者与托养者發表於2024-08-09

OpenCV 基本使用

參考教程:

GitHub - gaoxiang12/slambook2: edition 2 of the slambook

1. 安裝 OpenCV

1.1 下載 OpenCV

參考教程:

無法定位軟體包libjasper-dev的解決辦法-CSDN部落格

視覺slam14講ch5 opencv安裝 ubuntu20.04_libvtk5-dev-CSDN部落格

OpenCV提供了大量的開源影像演算法,是計算機視覺領域使用極廣的影像處理演算法庫。在Ubuntu系統下,OpenCV有從原始碼安裝和只安裝庫檔案兩種方式可以選擇:

(1)從原始碼安裝,是指從OpenCV網站下載所有的OpenCV原始碼,並在機器上編譯以便使用。好處是可以選擇的版本比較豐富,而且也能看到原始碼,不過需要花費一些編譯時間。

(2)只安裝庫檔案,是指透過Ubuntu安裝由Ubuntu社群人員已經編譯好的庫檔案,無須重新編譯一遍。

因為我們使用較新版本的OpenCV,所以必須選擇從原始碼安裝的方式來安裝它。一來,可以調整一些編譯選項,匹配程式設計環境(例如,需不需要GPU加速等);再者,可以使用一些額外的功能。OpenCV目前維護三個主要版本,分為OpenCV2.4系列、OpenCV 3系列和OpenCV 4系列。當前使用OpenCV 3系列。

從如下網站中下載原始碼:

Releases - OpenCV

頁面下滑,選擇OpenCV – 3.4.16版本,點選”Sources“進行下載

下載得到如下的壓縮包

opencv-3.4.16.zip檔案拖拽至虛擬機器的home資料夾下:

點選opencv-3.4.16.zip檔案,右鍵,選擇“提取到此處

1.2 配置依賴項並編譯

編譯之前,先來安裝OpenCV的依賴項:

rosnoetic@rosnoetic-VirtualBox:~$ sudo add-apt-repository "deb http://security.ubuntu.com/ubuntu xenial-security main"

rosnoetic@rosnoetic-VirtualBox:~$ sudo apt update

rosnoetic@rosnoetic-VirtualBox:~$ sudo apt upgrade

rosnoetic@rosnoetic-VirtualBox:~$ sudo apt-get install build-essential libgtk2.0-dev libvtk6-dev libjpeg-dev libtiff5-dev libjasper-dev libopenexr-dev libtbb-dev libcanberra-gtk-module

事實上,OpenCV的依賴項很多,缺少某些編譯項會影響它的部分功能。OpenCVcmake階段檢查依賴項是否會安裝,並調整自己的功能。如果電腦上有GPU並且安裝了相關依賴項,OpenCV也會把GPU加速開啟。不過當前,上述依賴項已經足夠了。

安裝完依賴項後進行編譯:

rosnoetic@rosnoetic-VirtualBox:~$ cd opencv-3.4.16/

rosnoetic@rosnoetic-VirtualBox:~/opencv-3.4.16$ mkdir build

rosnoetic@rosnoetic-VirtualBox:~/opencv-3.4.16$ cd build/

rosnoetic@rosnoetic-VirtualBox:~/opencv-3.4.16/build$ cmake ..

  • cmake 過程

接著進行編譯

rosnoetic@rosnoetic-VirtualBox:~/opencv-3.4.16/build$ make

整個編譯過程大概需要二十分鐘到一小時不等。

  • make 過程

make之後,呼叫sudo make installOpenCV安裝到電腦上(而不是僅僅編譯)。

rosnoetic@rosnoetic-VirtualBox:~/opencv-3.4.16/build$ sudo make install

  • make install 過程

2. 操作 OpenCV 影像

2.1 編寫 imageBasics 函式

2.1.1 建立資料夾

透過終端建立一個名為imageBasics的資料夾以儲存我們的VSCode專案,在/imageBasics目錄下開啟vscode

rosnoetic@rosnoetic-VirtualBox:~$ mkdir -p imageBasics

rosnoetic@rosnoetic-VirtualBox:~$ cd imageBasics/

rosnoetic@rosnoetic-VirtualBox:~/imageBasics$ code .

2.1.2 編寫原始碼

新建檔案imageBasics.cpp

imageBasics.cpp貼上如下程式碼並儲存(Ctrl+S)

#include <iostream>
#include <chrono>

using namespace std;

#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>

int main(int argc, char argv) {
    // 讀取argv[1]指定的影像
    cv::Mat image;
    //cv::image函式讀取制定路徑下的影像
    image = cv::imread(argv[1]);

    // 判斷影像檔案是否正確讀取
    if (image.data == nullptr) {
        // 資料不存在,可能是檔案不存在
        cerr << "檔案" << argv[1] << "不存在" <<endl;
        return 0;
    }

    // 檔案順利讀取,首先輸出一些基本資訊
    cout << "影像寬為: " << image.cols << ",高為: " << image.rows
              << ",通道數為" << image.channels() << endl;
    cv::imshow("image",image);   // cv::imshow顯示影像
    cv::waitKey(0);   // 暫停程式,等待一個按鍵輸入

    // 判斷imgae的型別
    if (image.type() != CV_8UC1 && image.type() != CV_8UC3) {
        // 影像型別不符合要求
        cout << "請輸入一張彩色圖或灰度圖" << endl;
        return 0;
    }

    // 遍歷影像,請注意以下遍歷方式也使用於隨機畫素訪問
    // 使用std::chrono給演算法計時
    chrono::steady_clock::time_point t1 = chrono::steady_clock::now();
    for (size_t y = 0; y < image.rows; y++) {
        // 用cv::Mat::ptr獲得影像的行指標,<unsigned char>指定型別,(y)是一個索引值,表示我們要訪問的行數
        unsigned char *row_ptr = image.ptr<unsigned char>(y);
        for (size_t x = 0; x < image.cols; x++) {
            // 訪問位於x,y處的畫素
            unsigned char *data_ptr = &row_ptr[x * image.channels()];   // data_ptr指標指向待訪問的畫素資料
            // 輸出該畫素的每個通道,如果是灰度圖,那麼通道是1
            for (int c = 0; c != image.channels(); c++) {
                unsigned char data = data_ptr[c];   // data為I(x,y)第c個通道的畫素值
            }
        }
    }
    chrono::steady_clock::time_point t2 = chrono::steady_clock::now();
    // 計算消耗時間
    chrono::duration<double> time_used = chrono::duration_cast<chrono::duration<double>> (t2-t1);
    cout << "遍歷圖所用時間: " << time_used.count() << "秒。"<< endl;

    // 關於cv::Mat的複製
    // 直接賦值並不會複製資料
    cv::Mat image_another = image;
    // 此時修改image_another,會導致image發生變化
    image_another(cv::Rect(0, 0, 100, 100)).setTo(0);   // 將左上角100*100的塊置為0
    cv::imshow("image",image);
    cv::waitKey(0);

    // 使用clone深複製複製資料
    cv::Mat image_clone = image.clone();
    image(cv::Rect(0, 0, 100, 100)).setTo(255);
    cv::imshow("image", image);
    cv::imshow("image_clone", image_clone);
    cv::waitKey(0);

    // 刪除所有的視窗
    cv::destroyAllWindows();

    return 0;
}

2.2 新建 CMakeLists.txt 檔案

新建CMakeLists.txt檔案

CMakeLists.txt中新增如下內容:

# 宣告要求的cmake最低版本
cmake_minimum_required(VERSION 2.8)

# 宣告一個cmake工程
project(IMAGEBASICS)

# 新增C++ 11支援
set(CMAKE_CXX_FLAGS "-std=c++11")

# 尋找OpenCV庫
find_package( OpenCV REQUIRED)
# 新增標頭檔案
include_directories(${OpenCV_INCLUDE_DIRS})

add_executable(imageBasics imageBasics.cpp)
# 連結OpenCV庫
target_link_libraries(imageBasics ${OpenCV_LIBS})

由於程式中使用了C++11標準(如nullptrchrono),因此需要設定編譯器set(CMAKE_CXX_FLAGS "-std=c++11")

2.3 cmake 編譯

ctrl+alt+T開啟終端,執行如下指令進行cmake編譯

rosnoetic@rosnoetic-VirtualBox:~$ cd imageBasics/

rosnoetic@rosnoetic-VirtualBox:~/imageBasics$ mkdir build

rosnoetic@rosnoetic-VirtualBox:~/imageBasics$ cd build/

rosnoetic@rosnoetic-VirtualBox:~/imageBasics/build$ cmake ..

我們新建了一箇中間資料夾”build“,然後進入build資料夾,透過cmake ..命令對上一層資料夾,也就是程式碼所在的資料夾進行編譯。這樣,cmake產生的中間檔案就會生成在build資料夾中,如下圖所示,和原始碼分開。

接著make對工程進行編譯

rosnoetic@rosnoetic-VirtualBox:~/imageBasics/build$ make

2.4 執行

ubuntu.png檔案拖拽至imageBasics/build資料夾下

進一步的呼叫可執行檔案:

rosnoetic@rosnoetic-VirtualBox:~/imageBasics/build$ ./imageBasics ubuntu.png 

依次顯示如下內容:

image視窗,按enter鍵執行下一個程式(也就是停留在了cv::waitKey()

相關文章