最近须要在 Linux 平台下开发一我的脸识别相关的应用,用到了虹软的人脸识别 SDK。以前在 Windows 平台用过,感受不错,SDK 里面还带了 Demo 能够快速看到效果。打开 Linux 版本的 SDK 里面没有发现 Demo,因而想着把 Windows 的 Demo 移植到 Linux。这篇文章记录了移植的过程,Linux 用的是 Ubuntu 20.04(使用虚拟机 VMware Workstation 15 Player)。html
到虹软官网下载人脸识别 SDK 3.1 Linux 增值版本 解压到合适的目录,并从官网获取 APP_ID、SDK_KEY 和 ACTIVE_KEY,用于写到配置文件用来激活 SDK。linux
到 OpenCV 官网下载源码,我用的版本是 3.4.9。能够按照官网的教程 Installation in Linux 自行编译,我参考官网教程使用下面的这些命令在 GCC 9.3.0(Ubuntu 20.04 自带的编译器) 上编译成功。git
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
Qt 使用的是 5.14.2 版本。github
原 Windows Demo 使用的是 Visual Studio 2015,在 Linux 下我这里用到了 Qt Creator 进行开发,所以须要编写 .pro 文件,包括如下几个方面:windows
更具体的内容查看文末提供的源码。安全
原源码文件使用的是 GBK 编码,须要转换为 UTF-8 编码。将下面的命令保存到 convert.sh
文件中并用 chmod u+x convert.sh
赋予可执行权限。bash
#!/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 头。ide
到这里已经能够用 Qt Creator 打开项目了,但在代码中还存在一些问题,一方面是原代码使用了一些 Windows 平台特有的 API,一方面是有些代码在 Linux 有兼容性问题。先去除 Windows 特有的依赖到编译经过,再补充必要的依赖,最后解决兼容性问题。函数
直接进行编译,逐步解决编译错误,经过下面的方式能够解决编译错误:ui
qDebug
改成 QDebug
。Sleep(milli)
改成 std::this_thread::sleep_for(std::chrono::milliseconds(milli))
。#pragma comment ...
。cv::Mat mat(ipl, false)
改为 cv::Mat mat = cv::cvarrToMat(ipl)
。IplImage(mat)
改为 cvIplImage(mat)
,在原来的代码里 cv::Mat 转为 IplImage 后有个取地址,对右值取地址是不安全的,须要用一个变量保存转换后的值再对这个变量取地址。CV_RGB
改为 cvScalar
。cv::cvtColor
须要额外包含头文件 opencv2/imgproc.hpp
。cv::VideoCapture
须要额外包含头文件 opencv2/videoio.hpp
strcpy_s
改为 strncpy
,仅有参数位置上的改变。TRUE
改成 true
,将 FALSE
改成 false
。改了编译错误后,忽略警告已经能够编译经过了,接下来是补充刚才删除的一些必要依赖及解决兼容性问题。
由于环境差别,可能出现错误的顺序不一致,但基本上是上面提到的错误之一。
原 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 时会有更多的说明。
在 Ubuntu 20.04 下,Qt 的 QFileDialog::getOpenFileName 和 QFileDialog::getExistingDirectory 存在一些问题,在打开时会卡死界面,经过将最后一个参数设置为 QFileDialog::DontUseNativeDialog
能够解决这个问题。