【OpenPose】1.OpenPoseDemo檔案的使用與解讀
OpenPose是基於深度學習的姿勢估計開源框架。
它的原始碼託管在github上:OpenPose的連結
下載、安裝可以參考官方文件,Visual Studio2017、CUDA9的安裝方法可以參考國內某些部落格【OpenPose-Windows】 OpenPose1.4.0+VS2017+CUDA9.2+cuDNN9.2+Windows配置教程 - CSDN部落格
一、前序準備
在將Debug換成Release,右鍵openpose專案點選設為啟動專案,再點選生成,等待一段時間。
生成完畢後,在Examples檔案下找到OpenPoseDemo專案點選設為啟動專案,再點選生成
二、解讀Demo檔案
首先是註釋:
註釋說明
翻譯如下:
如果您想學習使用OpenPose庫,我們強烈建議您從examples / tutorial 資料夾開始。
此示例總結了OpenPose庫的所有功能:
1.讀取影象/視訊/網路攝像頭的資料夾(producer模組)
2.提取並渲染該影象的身體關鍵點/熱圖/ PAF(Part Affinity Fields)(pose
3.提取並渲染該影象的面部關鍵點/熱圖/ PAF(face模組)
4.將結果儲存在磁碟上(filestream模組)
5.顯示渲染的姿勢(gui模組)
多執行緒場景中的所有內容(thread模組)
第2~5點包含在wrapper模組中
除了之前的OpenPose模組,我們還需要使用:
1. core
對於pose模組需要的Array類
` Datum是thread模組佇列(queue)之間傳送的結構體
2. utilities模組:
用於異常(error)和日誌(log)記錄功能,分別是op :: error和op :: log
匯入依賴包
依賴包匯入
chrono是C++中的時間標準模組,擁有表示時間點、時間段的類,以及互相轉換的方法
thread模組,顧名思義,是多執行緒標準模組
gflags是Google開源的命令列引數解析工具,用於聲名、定義、驗證命令列引數,後面的程式碼有體現
後面的#ifndef是允許Ubuntu 14使用Google Flags
最後引入openpose依賴庫
位址列引數說明
使用`--help`標誌檢視所有可用的引數選項。
例如:
Linux下命令 `build / examples / openpose / openpose.bin --help`(保證根目錄在Openpose中)
Windows的方法下面討論,這個可以先不看
位址列引數定義
然後是位址列引數的定義,有兩百多行,並且每個函式的第一個引數都是未定義的符號,於是檢視DEFINE_XXX的定義位置,發現就是gflags的巨集定義類函式
DEFINE_string
格式是DEFINE_XXX(name, val, txt)
第一個引數name是引數名,第二個引數是引數預設值,第三個引數是引數說明
例如DEFINE_string(video, "", "......"),使用時寫上OpenPoseDemo.exe --video path
當OpenPoseDemo --help時就會彈出txt
之後定義的int OpenPoseDemo()函式定義引數的驗證、日誌列印等操作
main函式呼叫OpenPoseDemo函式並返回OpenPoseDemo函式的返回值
具體解析放到最後(參閱附錄二),可以先跳過
三、Demo檔案的使用
第一種方法(不建議):
在 build \ x64 \ Release 檔案下找到OpenPoseDemo.exe檔案,單獨執行會顯示找不到各種dll檔案,可以將exe檔案與openpose.dll檔案一同複製到 build \ bin 目錄下,然後在命令列下執行,但是此方法會找不到其他依賴檔案,所以不建議使用
第二種方法:
更改位址列引數的預設值。
我們在Visual Studio中按Ctrl+F彈出的搜尋框中輸入`DEFINE_string(image_dir`,這是預設的影象識別資料夾,將要識別的目錄輸入即可,可以用openpose自帶的測試集,既把預設引數改為:
同理,在這一行的上一行,或者搜尋`DEFINE_string(video`即可找到視訊的位址列引數定義,輸入路徑及視訊檔名即可
注意,識別的型別不能既是視訊,又是影象,所以兩個引數不能同時不為空,否則會報錯
第三種方法:
真正用位址列傳參的方式,Visual Studio可以找到OpenPoseDemo專案,右鍵點選屬性:
在開啟的屬性頁面中,找到除錯,右側找到命令引數:
輸入命令引數即可,上圖的例項中還增加了--face(面部識別)和--hand(手部識別)
按F5執行即可
附錄一、GUI快捷鍵大致翻譯
當在UI介面按h時會彈出快捷鍵幫助頁面,大致翻譯一下
快捷鍵
OpenPose命令:
改變預設的OpenPose引數
Z:是否使用面部檢測(標誌 --face)
X:是否使用手部檢測(標誌 --hand)
C:是否使用3D呈現
-=:減少/增加NMS閾值(NMSThreshold)
_+:減少/增加連線最小子集(ConnectMinSubsetScore)
[ ]:減少/增加連線內部閾值(ConnectInterThreshold)
{ }:減少/增加連線內部最小上界閾值(ConnectInterMinAboveThreshold)
; \: 減少/增加簡介最小子集計數(ConnectMinSubsetCnt)
呈現命令:
改變顯示型別(姿勢、熱圖、PAF)
B:是否混合幀的結果
1:顯示姿勢/骨骼(基礎圖)
2:顯示背景熱圖
3:顯示所有熱圖(所有關節)
4:顯示所有PAF(關節及關節的連結肢體)
,.:顯示上一個/下一個元素
567890:聯想初始化熱圖
雜項
G:突出顯示眼睛為金魚眼
只能使用GPU呈現
附錄二、openPoseDemo函式解析
函式引數為空,返回型別為int,函式整體被包含在一個try塊中,可以看出如果程式正常返回0
如果出現未預料到的異常,將列印error日誌,輸出結果為:錯誤資訊,錯誤所在的行,錯誤所在的函式名以及錯誤所在的檔名並返回-1
捕獲到錯誤
再回到函式的開頭首先
op::log("Starting OpenPose demo...", op::Priority::High);
const auto timerBegin = std::chrono::high_resolution_clock::now();
在控制檯列印日誌出Starting OpenPose demo...優先順序為高
timerBegin為當前時間
logging_level
用於檢查引數logging_level,如果不在[0, 255]之間,則列印“錯誤的logging_level值”,並且打印出錯所在的具體資訊。
下面兩行註釋有解釋:
這些是用於除錯(Debug)的方法,假如你在op::ConfigureLog::setPriorityThreshold方法中傳入op::Priority::None,則列印所有日誌資訊,op::Profiler::setDefaultX能控制列印日誌的速度
應用使用者定義配置給程式變數的Google標記
看一下輸出大小, FLAGS_output_resolution看起來沒被定義過,但其實前面得到巨集定義類函式DEFINE_xxx已經給了它定義,這個變數一看就與output_resolution相關,用CTRL+F跳到定義處看看說明
DEFINE_string(output_resolution, "-1x-1",
"The image resolution (display and output). Use \"-1x-1\" to force the program to use the" " input image resolution.");
這個變數定義的是顯示和輸出的解析度。並且規定使用“-1x-1”就是-1乘-1的意思,程式會使用輸入的圖片解析度作為顯示和誒輸出的解析度,同時這個值為這個變數的預設值
同理,看看第二個“網路輸入大小”變數的含義,它所關聯的變數為net_resolution
DEFINE_string(net_resolution, "-1x368",
"Multiples of 16. If it is increased, the accuracy potentially increases. If it is"
" decreased, the speed increases. For maximum speed-accuracy balance, it should keep the"
" closest aspect ratio possible to the images or videos to be processed. Using `-1` in"
" any of the dimensions, OP will choose the optimal aspect ratio depending on the user's"
" input value. E.g. the default `-1x368` is equivalent to `656x368` in 16:9 resolutions,"
" e.g. full HD (1980x1080) and HD (1280x720) resolutions.");
大致意思為:乘號兩側的變數值為16的倍數,如果增加,精度會變高,如果減少,速度會變快。為了獲得最大的速度 - 精度平衡,它應該保持最接近輸入值的寬高比可以處理要處理的影象或視訊。因此,將乘號兩側的任意一值列為“-1”,另一個變數會自動根據輸入的長寬比調整輸出的長寬比,例如:如果輸入的影象長寬比為16:9,那麼“-1x368”就相當於"656x368"
按照同樣的方法即可解析上面的程式碼
接下來,宣告封裝器型別變數,然後用封裝器結構體(wrapperStructPose)將Pose資料封裝,Face、Hand等同樣如此
然後用封裝器變數註冊:
下面是看disable_multi_thread引數值,如果為真值,就要禁用多執行緒
開始程序,有兩個不同的方法在多執行緒環境下執行程式
第一個方法是上面的opWrapper.exec(),作用如上面的註釋所說:啟動,執行\停止執行緒,當其他所有執行緒單元完成後啟動該執行緒。
下面的是註釋掉的是選項B:保持此執行緒空閒,以防你想要同時執行其他操作,例如 分析GPU記憶體。
注意:如果使用Qt支援編譯OpenCV,選項B將不起作用。 Qt需要主執行緒來繪製視覺化結果,因此最終的GUI(使用OpenCV)將返回類似於以下內容的異常:QMetaMethod :: invoke:無法在排隊連線中呼叫帶有返回值的方法。
函式的最後,獲取結束時間並計算總時間然後打印出日誌。
openPoseDemo函式解析完畢!
作者:crossous
連結:https://www.jianshu.com/p/bcdfa75c42ac
來源:簡書
簡書著作權歸作者所有,任何形式的轉載都請聯絡作者獲得授權並註明出處。