虹軟人臉識別——官方 Qt Demo 移植到 Linux

碼仔很忙發表於2020-06-23

一、前言

最近需要在 Linux 平臺下開發一個人臉識別相關的應用,用到了虹軟的人臉識別 SDK。之前在 Windows 平臺用過,感覺不錯,SDK 裡面還帶了 Demo 可以快速看到效果。開啟 Linux 版本的 SDK 裡面沒有發現 Demo,於是想著把 Windows 的 Demo 移植到 Linux。這篇文章記錄了移植的過程,Linux 用的是 Ubuntu 20.04(使用虛擬機器 VMware Workstation 15 Player)。

二、配置依賴

2.1 ArcFace SDK

到虹軟官網下載人臉識別 SDK 3.1 Linux 增值版本 解壓到合適的目錄,並從官網獲取 APP_ID、SDK_KEY 和 ACTIVE_KEY,用於寫到配置檔案用來啟用 SDK。

2.2 OpenCV

到 OpenCV 官網下載原始碼,我用的版本是 3.4.9。可以按照官網的教程 Installation in Linux 自行編譯,我參考官網教程使用下面的這些命令在 GCC 9.3.0(Ubuntu 20.04 自帶的編譯器) 上編譯成功。

sudo apt update
sudo apt install build-essential
sudo apt install cmake git libgtk2.0-dev pkg-config libavcodec-dev libavformat-dev libswscale-dev
cd <OpenCV 原始碼目錄>
mkdir build
cd build
cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=<自定義目錄> ..
make -j3    # 可以使用核心數 - 1 個執行緒來編譯
sudo make install

2.3 Qt

Qt 使用的是 5.14.2 版本。

三、專案檔案

3.1 .pro 檔案

原 Windows Demo 使用的是 Visual Studio 2015,在 Linux 下我這裡用到了 Qt Creator 進行開發,因此需要編寫 .pro 檔案,包括以下幾個方面:

  • 用到的 Qt 模組
  • 編譯出來的程式名
  • 用到的標頭檔案、原始檔和資原始檔
  • 依賴庫的標頭檔案及庫名

更具體的內容檢視文末提供的原始碼。

3.2 檔案編碼

原原始碼檔案使用的是 GBK 編碼,需要轉換為 UTF-8 編碼。將下面的命令儲存到 convert.sh 檔案中並用 chmod u+x convert.sh 賦予可執行許可權。

#!/bin/bash

for i in "$@"; do
    desc=$(file "$i")
    if $(echo $desc | grep -i "UTF-8 Unicode" > /dev/null); then
        if $(echo $desc | grep -i "(with BOM)" > /dev/null); then
            echo "Remove UTF-8 BOM: " $i
            sed -i "1s/^\xef\xbb\xbf//" "$i"
        fi
    elif $(echo $desc | grep -i "ISO-8859" > /dev/null); then
        echo     "GBK --> UTF-8   : " $i
        temp=temp.txt
        iconv -f gbk -t utf-8 -o "$temp" "$i"
        mv "$temp" "$i"
    fi
done

在原始碼根目錄下執行 find . -type f \( -name "*.h" -o -name "*.cpp" \) | xargs -I{} ./convert.sh "{}" 將所有的檔案的編碼從 GBK 轉為 UTF-8,並去除現有 UTF-8 檔案的 BOM 頭。

四、程式碼修改

到這裡已經可以用 Qt Creator 開啟專案了,但在程式碼中還存在一些問題,一方面是原始碼使用了一些 Windows 平臺特有的 API,一方面是有些程式碼在 Linux 有相容性問題。先去除 Windows 特有的依賴到編譯通過,再補充必要的依賴,最後解決相容性問題。

4.1 修改報錯直至編譯通過

直接進行編譯,逐步解決編譯錯誤,通過下面的方式可以解決編譯錯誤:

  • 刪除 Utils.cpp 中報錯的標頭檔案、GUID 巨集、listDevices 函式的主體、UTF8_To_string 和 string_To_UTF8 函式。
  • 將所有包含的 qDebug 改為 QDebug
  • Sleep(milli) 改為 std::this_thread::sleep_for(std::chrono::milliseconds(milli))
  • 刪除 MSVC 的連結庫的編譯指令 #pragma comment ...
  • 將原來使用 OpenCV 2 的介面遷移到目前的 OpenCV 3。
    • IplImage 到 cv::Mat 的轉換由 cv::Mat mat(ipl, false) 改成 cv::Mat mat = cv::cvarrToMat(ipl)
    • cv::Mat 到 IplImage 的轉換由 IplImage(mat) 改成 cvIplImage(mat),在原來的程式碼裡 cv::Mat 轉為 IplImage 後有個取地址,對右值取地址是不安全的,需要用一個變數儲存轉換後的值再對這個變數取地址。
    • 在呼叫 cvRectangle 時將 CV_RGB 改成 cvScalar
    • 使用 cv::cvtColor 需要額外包含標頭檔案 opencv2/imgproc.hpp
    • 使用 cv::VideoCapture 需要額外包含標頭檔案 opencv2/videoio.hpp
  • strcpy_s 改成 strncpy,僅有引數位置上的改變。
  • TRUE 改為 true,將 FALSE 改為 false

改了編譯錯誤後,忽略警告已經可以編譯通過了,接下來是補充剛才刪除的一些必要依賴及解決相容性問題。

因為環境差異,可能出現錯誤的順序不一致,但基本上是上面提到的錯誤之一。

4.2 重新實現獲取攝像頭列表的函式

原 Windows Demo 使用了 Windows 特有的 dshow 來查詢攝像頭,在這裡直接用 cv::VideoCapture 嘗試開啟來獲取攝像頭的索引:

auto list = std::vector<int>();
for (auto i = 0; i != 10; ++i)
{
    auto cap = cv::VideoCapture(i);
    if (cap.isOpened()) { list.emplace_back(i); }
    cap.release();
}

Demo 可以只開啟一個RGB攝像頭,也可以同時開啟一個RGB攝像頭和一個IR攝像頭。原始碼儲存獲取攝像頭的名稱,僅用來統計數量,具體開啟哪個攝像頭是通過settings.ini檔案來配置的。在改變探測攝像頭存在的數量的方式後,順帶改變了開啟攝像頭的邏輯,僅一個攝像頭就認為是僅開啟普通攝像頭。在settings.ini檔案中配置兩種攝像頭的索引,如果索引為 -1,則自動把小的索引認為是普通攝像頭,大的索引認為是紅外攝像頭,如果和真實情況不一致可手動指定攝像頭索引。

settings.ini檔案在後面執行 Demo 時會有更多的說明。

4.3 修復彈出檔案選擇框失敗的相容性問題

在 Ubuntu 20.04 下,Qt 的 QFileDialog::getOpenFileName 和 QFileDialog::getExistingDirectory 存在一些問題,在開啟時會卡死介面,通過將最後一個引數設定為 QFileDialog::DontUseNativeDialog 可以解決這個問題。

五、執行 Demo

5.1 介面預覽

5.2 配置

  1. 配置檔案已經隨原始碼打包好了,在執行時需要移動到可執行程式所在的同級目錄下。
  2. 在配置檔案中填入官網獲取的 APP_ID、SDK_KEY 和 ACTIVE_KEY。
  3. 編譯並執行。

六、原始碼下載

基於官方windows Qt Demo修改後的原始碼

相關文章