? ? OpenPose是基于深度學(xué)習(xí)的姿勢(shì)估計(jì)開源框架歧蕉。
? ? 它的源碼托管在github上:OpenPose的鏈接
? ? 下載、安裝可以參考官方文檔,Visual Studio2017诺核、CUDA9的安裝方法可以參考國(guó)內(nèi)某些博客【OpenPose-Windows】 OpenPose1.4.0+VS2017+CUDA9.2+cuDNN9.2+Windows配置教程 - CSDN博客
一抄肖、前序準(zhǔn)備
????在將Debug換成Release,右鍵openpose項(xiàng)目點(diǎn)擊設(shè)為啟動(dòng)項(xiàng)目窖杀,再點(diǎn)擊生成漓摩,等待一段時(shí)間。
? ? 生成完畢后入客,在Examples文件下找到OpenPoseDemo項(xiàng)目點(diǎn)擊設(shè)為啟動(dòng)項(xiàng)目管毙,再點(diǎn)擊生成
二、解讀Demo文件
首先是注釋:
翻譯如下:
如果您想學(xué)習(xí)使用OpenPose庫(kù)桌硫,我們強(qiáng)烈建議您從examples / tutorial?文件夾開始夭咬。
此示例總結(jié)了OpenPose庫(kù)的所有功能:
????1.讀取圖像/視頻/網(wǎng)絡(luò)攝像頭的文件夾(producer模塊)
????2.提取并渲染該圖像的身體關(guān)鍵點(diǎn)/熱圖/ PAF(Part Affinity Fields)(pose模塊)
????3.提取并渲染該圖像的面部關(guān)鍵點(diǎn)/熱圖/ PAF(face模塊)
????4.將結(jié)果保存在磁盤上(filestream模塊)
????5.顯示渲染的姿勢(shì)(gui模塊)
????多線程場(chǎng)景中的所有內(nèi)容(thread模塊)
????第2~5點(diǎn)包含在wrapper模塊中
除了之前的OpenPose模塊,我們還需要使用:
????1. core模塊:
????????????對(duì)于pose模塊需要的Array類
`? ? ? ? ? ?Datum是thread模塊隊(duì)列(queue)之間發(fā)送的結(jié)構(gòu)體
????2. utilities模塊:
用于異常(error)和日志(log)記錄功能铆隘,分別是op :: error和op :: log
導(dǎo)入依賴包
chrono是C++中的時(shí)間標(biāo)準(zhǔn)模塊卓舵,擁有表示時(shí)間點(diǎn)、時(shí)間段的類膀钠,以及互相轉(zhuǎn)換的方法
thread模塊掏湾,顧名思義,是多線程標(biāo)準(zhǔn)模塊
gflags是Google開源的命令行參數(shù)解析工具肿嘲,用于聲名融击、定義、驗(yàn)證命令行參數(shù)雳窟,后面的代碼有體現(xiàn)
后面的#ifndef是允許Ubuntu 14使用Google Flags
最后引入openpose依賴庫(kù)
使用`--help`標(biāo)志查看所有可用的參數(shù)選項(xiàng)尊浪。
例如:
Linux下命令 `build / examples / openpose / openpose.bin --help`(保證根目錄在Openpose中)
Windows的方法下面討論,這個(gè)可以先不看
然后是地址欄參數(shù)的定義涩拙,有兩百多行际长,并且每個(gè)函數(shù)的第一個(gè)參數(shù)都是未定義的符號(hào),于是查看DEFINE_XXX的定義位置兴泥,發(fā)現(xiàn)就是gflags的宏定義類函數(shù)
格式是DEFINE_XXX(name, val, txt)
第一個(gè)參數(shù)name是參數(shù)名,第二個(gè)參數(shù)是參數(shù)默認(rèn)值虾宇,第三個(gè)參數(shù)是參數(shù)說(shuō)明
例如DEFINE_string(video, "", "......")搓彻,使用時(shí)寫上OpenPoseDemo.exe --video path
當(dāng)OpenPoseDemo --help時(shí)就會(huì)彈出txt
之后定義的int OpenPoseDemo()函數(shù)定義參數(shù)的驗(yàn)證、日志打印等操作
main函數(shù)調(diào)用OpenPoseDemo函數(shù)并返回OpenPoseDemo函數(shù)的返回值
具體解析放到最后(參閱附錄二)嘱朽,可以先跳過(guò)
三旭贬、Demo文件的使用
? ? 第一種方法(不建議):
? ? ? ? 在 build \ x64 \ Release 文件下找到OpenPoseDemo.exe文件,單獨(dú)運(yùn)行會(huì)顯示找不到各種dll文件搪泳,可以將exe文件與openpose.dll文件一同復(fù)制到?build \ bin 目錄下稀轨,然后在命令行下運(yùn)行,但是此方法會(huì)找不到其他依賴文件岸军,所以不建議使用
? ? 第二種方法:
? ? ? ? 更改地址欄參數(shù)的默認(rèn)值奋刽。
? ? ? ? 我們?cè)赩isual Studio中按Ctrl+F彈出的搜索框中輸入`DEFINE_string(image_dir`瓦侮,這是默認(rèn)的圖像識(shí)別文件夾,將要識(shí)別的目錄輸入即可佣谐,可以用openpose自帶的測(cè)試集肚吏,既把默認(rèn)參數(shù)改為:
? ? ????同理,在這一行的上一行狭魂,或者搜索`DEFINE_string(video`即可找到視頻的地址欄參數(shù)定義罚攀,輸入路徑及視頻文件名即可
? ? ????注意,識(shí)別的類型不能既是視頻雌澄,又是圖像斋泄,所以兩個(gè)參數(shù)不能同時(shí)不為空,否則會(huì)報(bào)錯(cuò)
? ? 第三種方法:
? ? ? ? 真正用地址欄傳參的方式镐牺,Visual Studio可以找到OpenPoseDemo項(xiàng)目炫掐,右鍵點(diǎn)擊屬性:
? ? ? ? 在打開的屬性頁(yè)面中,找到調(diào)試任柜,右側(cè)找到命令參數(shù):
輸入命令參數(shù)即可卒废,上圖的實(shí)例中還增加了--face(面部識(shí)別)和--hand(手部識(shí)別)
按F5運(yùn)行即可
附錄一、GUI快捷鍵大致翻譯? ? ? ??
? ? 當(dāng)在UI界面按h時(shí)會(huì)彈出快捷鍵幫助頁(yè)面宙地,大致翻譯一下
OpenPose命令:
改變默認(rèn)的OpenPose參數(shù)
? ??Z:是否使用面部檢測(cè)(標(biāo)志 --face)
? ??X:是否使用手部檢測(cè)(標(biāo)志 --hand)
? ??C:是否使用3D呈現(xiàn)
? ??-=:減少/增加NMS閾值(NMSThreshold)
? ??_+:減少/增加連接最小子集(ConnectMinSubsetScore)
? ??[ ]:減少/增加連接內(nèi)部閾值(ConnectInterThreshold)
? ??{ }:減少/增加連接內(nèi)部最小上界閾值(ConnectInterMinAboveThreshold)
? ??; \: 減少/增加簡(jiǎn)介最小子集計(jì)數(shù)(ConnectMinSubsetCnt)
呈現(xiàn)命令:
改變顯示類型(姿勢(shì)摔认、熱圖、PAF)
? ??B:是否混合幀的結(jié)果
? ??1:顯示姿勢(shì)/骨骼(基礎(chǔ)圖)
? ??2:顯示背景熱圖
? ??3:顯示所有熱圖(所有關(guān)節(jié))
? ??4:顯示所有PAF(關(guān)節(jié)及關(guān)節(jié)的鏈接肢體)
? ??,.:顯示上一個(gè)/下一個(gè)元素
? ??567890:聯(lián)想初始化熱圖
雜項(xiàng)
????G:突出顯示眼睛為金魚眼
只能使用GPU呈現(xiàn)
附錄二宅粥、openPoseDemo函數(shù)解析
? ? 函數(shù)參數(shù)為空参袱,返回類型為int,函數(shù)整體被包含在一個(gè)try塊中秽梅,可以看出如果程序正常返回0
????如果出現(xiàn)未預(yù)料到的異常抹蚀,將打印error日志,輸出結(jié)果為:錯(cuò)誤信息企垦,錯(cuò)誤所在的行环壤,錯(cuò)誤所在的函數(shù)名以及錯(cuò)誤所在的文件名并返回-1
? ? 再回到函數(shù)的開頭首先
op::log("Starting OpenPose demo...", op::Priority::High);
const auto timerBegin = std::chrono::high_resolution_clock::now();??
? ? 在控制臺(tái)打印日志出Starting OpenPose demo...優(yōu)先級(jí)為高
? ? timerBegin為當(dāng)前時(shí)間
? ? 用于檢查參數(shù)logging_level,如果不在[0, 255]之間钞诡,則打印“錯(cuò)誤的logging_level值”郑现,并且打印出錯(cuò)所在的具體信息。
? ? 下面兩行注釋有解釋:
? ? ? ? 這些是用于調(diào)試(Debug)的方法荧降,假如你在op::ConfigureLog::setPriorityThreshold方法中傳入op::Priority::None接箫,則打印所有日志信息,op::Profiler::setDefaultX能控制打印日志的速度
????應(yīng)用用戶定義配置給程序變量的Google標(biāo)記
? ? 看一下輸出大小朵诫, FLAGS_output_resolution看起來(lái)沒(méi)被定義過(guò)辛友,但其實(shí)前面得到宏定義類函數(shù)DEFINE_xxx已經(jīng)給了它定義,這個(gè)變量一看就與output_resolution相關(guān)剪返,用CTRL+F跳到定義處看看說(shuō)明
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.");
????這個(gè)變量定義的是顯示和輸出的分辨率废累。并且規(guī)定使用“-1x-1”就是-1乘-1的意思邓梅,程序會(huì)使用輸入的圖片分辨率作為顯示和誒輸出的分辨率,同時(shí)這個(gè)值為這個(gè)變量的默認(rèn)值
? ? 同理九默,看看第二個(gè)“網(wǎng)絡(luò)輸入大小”變量的含義震放,它所關(guān)聯(lián)的變量為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.");?
? ? 大致意思為:乘號(hào)兩側(cè)的變量值為16的倍數(shù),如果增加驼修,精度會(huì)變高殿遂,如果減少,速度會(huì)變快乙各。為了獲得最大的速度 - 精度平衡墨礁,它應(yīng)該保持最接近輸入值的寬高比可以處理要處理的圖像或視頻。因此耳峦,將乘號(hào)兩側(cè)的任意一值列為“-1”恩静,另一個(gè)變量會(huì)自動(dòng)根據(jù)輸入的長(zhǎng)寬比調(diào)整輸出的長(zhǎng)寬比,例如:如果輸入的圖像長(zhǎng)寬比為16:9蹲坷,那么“-1x368”就相當(dāng)于"656x368"
按照同樣的方法即可解析上面的代碼
? ? 接下來(lái)驶乾,聲明封裝器類型變量,然后用封裝器結(jié)構(gòu)體(wrapperStructPose)將Pose數(shù)據(jù)封裝循签,F(xiàn)ace级乐、Hand等同樣如此
????然后用封裝器變量注冊(cè):
? ? 下面是看disable_multi_thread參數(shù)值,如果為真值县匠,就要禁用多線程
????開始進(jìn)程风科,有兩個(gè)不同的方法在多線程環(huán)境下運(yùn)行程序
? ? 第一個(gè)方法是上面的opWrapper.exec(),作用如上面的注釋所說(shuō):?jiǎn)?dòng)乞旦,運(yùn)行\(zhòng)停止線程贼穆,當(dāng)其他所有線程單元完成后啟動(dòng)該線程。
? ? 下面的是注釋掉的是選項(xiàng)B:保持此線程空閑兰粉,以防你想要同時(shí)執(zhí)行其他操作故痊,例如 分析GPU內(nèi)存。
? ? 注意:如果使用Qt支持編譯OpenCV玖姑,選項(xiàng)B將不起作用崖蜜。 Qt需要主線程來(lái)繪制可視化結(jié)果,因此最終的GUI(使用OpenCV)將返回類似于以下內(nèi)容的異常:QMetaMethod :: invoke:無(wú)法在排隊(duì)連接中調(diào)用帶有返回值的方法客峭。
? ? 函數(shù)的最后,獲取結(jié)束時(shí)間并計(jì)算總時(shí)間然后打印出日志抡柿。
? ? openPoseDemo函數(shù)解析完畢舔琅!