2020年如今國內的硝煙漸漸彌散,但人們仍然不能懈怠。口罩依然是能讓你進入公共場所的“門票”。
佩戴口罩是阻斷呼吸道病毒傳播的方式之一,但難免會有些人不會自覺佩戴口罩。當人與人最舒適的距離是“你離我遠點”的情況下,AI正以一種溫暖的方式靠近人們,帶來特殊的安全感。如今,在AI的加持下,口罩作爲外出必備的保護傘的同時,也不再是“刷臉”通行的障礙物,能讓你在公司、校園、小區等場景中暢通無阻……
前段時間在Paddle Lite的QQ羣裏面看到小夥伴們對在樹莓派上部署實時的口罩識別很感興趣,想着目前這個時期,能用低成本部署口罩識別系統對很多場景的幫助還是很高的。可以應用在學校、公司等等,節約了人力,也能督促人們出門一定要帶好口罩。正好手裏有個樹莓派4B,可以搭建一個簡易版本的口罩識別系統,下面將我的實驗過程一步步與大家分享。
口罩模型介紹
PyramidBox-Lite是基於2018年百度發表於計算機視覺頂級會議ECCV 2018的論文PyramidBox而研發的輕量級模型,模型基於主幹網絡FaceBoxes,對於光照、口罩遮擋、表情變化、尺度變化等常見問題具有很強的魯棒性。該PaddleHub Module是針對於移動端優化過的模型,適合部署於移動端或者邊緣檢測等算力受限的設備上,並基於WIDER FACE數據集和百度自採人臉數據集進行訓練,支持預測。而針對此次疫情,百度宣佈免費開源業內首個口罩人臉檢測及分類模型。該模型可以有效檢測在密集人流區域中攜帶和未攜戴口罩的所有人臉,同時判斷該人員是否佩戴口罩。目前已通過飛槳PaddleHub開源出來,廣大開發者用幾行代碼即可快速上手,免費調用。
關於pyramidbox_lite_mobile_mask模型鏈接:
https://www.paddlepaddle.org.cn/hubdetail?name=pyramidbox_lite_mobile_mask&en_category=ObjectDetection
通過python執行以下代碼,即可通過PaddleHub獲取並保存pyramidbox_lite_mobile_mask口罩識別模型。
import paddlehub as hub
pyramidbox_lite_mobile_mask = hub.Module(name="pyramidbox_lite_mobile_mask")
# 將模型保存在test_program文件夾之中
pyramidbox_lite_mobile_mask.processor.save_inference_model(dirname="test_program")
Paddle Lite預測庫介紹
預測庫編譯
ArmLinux目前官網未提供編譯好的預測庫,所以需要自行編譯。這裏使用的預測庫是Paddle-Lite最新版本v2.3.0:
wget https://github.com/PaddlePaddle/Paddle-Lite/archive/v2.3.0.zip
ArmLinux編譯預測庫有兩種方式,交叉編譯和本地編譯(直接在樹莓派上編譯)
交叉編譯速度更快,本地編譯更加方便,兩種方式任選其一即可。詳細的編譯方法可參考Lite的官方文檔:
https://paddle-lite.readthedocs.io/zh/latest/user_guides/source_compile.html
模型轉換
使用opt工具將模型轉爲Paddle-Lite的模型
./opt
--model_file=./__model__
--param_file=./__params__
--optimize_out_type=naive_buffer
--optimize_out=model
Paddle Lite預測接口說明:
C++代碼調用Paddle-Lite執行預測庫僅需以下五步:
(1)引用頭文件和命名空間
#include "paddle_api.h"
using namespace paddle::lite_api;
(2)指定模型文件,創建Predictor
MobileConfig config;
config.set_model_from_file(model_file_path);
std::shared_ptr<PaddlePredictor> predictor =
CreatePaddlePredictor<MobileConfig>(config);
(3)設置模型輸入 (下面以全一輸入爲例)
std::unique_ptr<Tensor> input_tensor(std::move(predictor->GetInput(0)));
input_tensor->Resize({1, 3, 224, 224});
auto* data = input_tensor->mutable_data<float>();
for (int i = 0; i < ShapeProduction(input_tensor->shape()); ++i) {
data[i] = 1;
}
(4)執行預測
predictor->Run();
(5)獲得預測結果
std::unique_ptr<const Tensor> output_tensor(
std::move(predictor->GetOutput(0)));
auto output_data=output_tensor->data<float>();
系統實現
環境準備
1.硬件環境
首先是硬件準備,我們需要一塊嵌入式開發板以及攝像頭。這裏我使用的是樹莓派4B和500W像素的CSI攝像頭。
圖1 樹莓派4B 圖2 500W CSI攝像頭
2.軟件環境
操作系統我選用的是Debian-Pi-Aarch64,注意這是一個64位的系統(官方的Raspberry Pi系統是32位的)。
附上鍊接:
https://gitee.com/openfans-community/Debian-Pi-Aarch64/
進入系統後首先我們給攝像頭enable一下,這個系統開啓攝像頭的方式與Raspberry Pi是不一樣的。
打開終端sudo gedit /boot/config.txt文件中將start_x=1的註釋去掉後重啓即可開啓CSI攝像頭。
接下來安裝一下必要的軟件:
sudo apt-get update
sudo apt-get install gcc g++ make wget unzip libopencv-dev pkg-config
wget https://www.cmake.org/files/v3.10/cmake-3.10.3.tar.gz && tar -zxvf cmake-3.10.3.tar.gz
cd cmake-3.10.3
./configure && make -j4 && sudo make install
操作方法
如圖3所示,軟件系統的整體流程是先獲取視頻流,然後轉成圖像,基於圖像,做人臉檢測,如果檢測到人臉,再基於口罩識別模型判斷人臉是否佩戴口罩;根據識別結果,畫框並顯示口罩是否佩戴。核心的思想是先進行人臉檢測,再去分類是否佩戴口罩。
圖3 軟件流程圖
1.捕捉視頻流
首先準備要傳入的視頻數據,這裏我們需要用到OpenCV。
創建一個VideoCapture對象。
cv:: VideoCapture cap(-1);
設置一下分辨率,爲了保證性能可以不要設置太高。
cap.set(CV_CAP_PROP_FRAME_WIDTH, 640);
cap.set(CV_CAP_PROP_FRAME_HEIGHT, 480);
這裏使用了RunTime()函數,將檢測模型,分類模型和cap作爲參數傳入。
RunTime(detect_model_dir, classify_model_dir,cap);
2. 將輸入的視頻流取幀
cv::Mat img;
cap >> img;
3.人臉檢測
使用Lite API,基於人臉模型進行人臉檢測,生成人臉檢測框。
MobileConfig config;
config.set_model_dir(det_model_dir);
std::shared_ptr<PaddlePredictor> predictor =
CreatePaddlePredictor<MobileConfig>(config);
std::unique_ptr<Tensor> input_tensor0(std::move(predictor->GetInput(0)));
input_tensor0->Resize({1, 3, s_height, s_width});
auto* data = input_tensor0->mutable_data<float>();
predictor->Run();
std::unique_ptr<const Tensor> output_tensor0(std::move(predictor->GetOutput(0)));
auto* outptr = output_tensor0->data<float>();
auto shape_out = output_tensor0->shape();
int64_t out_len = ShapeProduction(shape_out);
4.口罩分類
對上述過程生成的每個人臉檢測框,進行預處理並執行口罩分類模型的預測,對檢測框分類是否佩戴口罩。
config.set_model_dir(class_model_dir);
predictor = CreatePaddlePredictor<MobileConfig>(config);
std::unique_ptr<Tensor> input_tensor1(std::move(predictor->GetInput(0)));
input_tensor1->Resize({1, 3, classify_h, classify_w});
auto* input_data = input_tensor1->mutable_data<float>();
5. 結果展示
使用cv::Scala框選結果,紅色的框選中人臉,黃色的label(wear mask、no mask)標記是否佩戴口罩
cv::rectangle(img, rec_clip, cv::Scalar(0, 0, 255), 2, cv::LINE_AA);
std::string text = outptr[1] > classify_threshold ? "wear mask" : "no mask";
int font_face = cv::FONT_HERSHEY_COMPLEX_SMALL;
double font_scale = 1.f;
int thickness = 1;
cv::Size text_size =cv::getTextSize(text, font_face, font_scale, thickness, nullptr);
float new_font_scale = rec_clip.width * 0.7 * font_scale / text_size.width;
text_size =cv::getTextSize(text, font_face, new_font_scale, thickness, nullptr);
cv::Point origin;
origin.x = rec_clip.x + 5;
origin.y = rec_clip.y + text_size.height + 5;
cv::putText(img,text,origin,font_face,new_font_scale,cv::Scalar(0, 255, 255),
thickness,cv::LINE_AA);
效果演示
圖4 未佩戴口罩
圖5 佩戴口罩
圖6 手遮擋口罩測試
最後,代碼僅做部分演示,完整項目公開在AI Studio上,歡迎大家Fork一下 ~
https://aistudio.baidu.com/aistudio/projectdetail/315730
如果您加入官方QQ羣,您將遇上大批志同道合的深度學習同學。官方QQ羣:703252161。
如果您想詳細瞭解更多飛槳的相關內容,請參閱以下文檔。
官網地址:https://www.paddlepaddle.org.cn
飛槳開源框架項目地址:
GitHub: https://github.com/PaddlePaddle/Paddle
Gitee: https://gitee.com/paddlepaddle/Paddle
END