Java構(gòu)建汽車無人駕駛:汽車目標(biāo)檢測(cè)

Java構(gòu)建汽車無人駕駛:汽車目標(biāo)檢測(cè)

Java Autonomous Driving: Car Detection

原文地址: https://dzone.com/articles/java-autonomous-driving-car-detection-1


在這篇文章中,我們將用Java構(gòu)建一個(gè)實(shí)時(shí)視頻對(duì)象檢測(cè)應(yīng)用程序,用于汽車檢測(cè),這是自動(dòng)駕駛系統(tǒng)的一個(gè)關(guān)鍵組件。 在之前的文章中,我們能夠構(gòu)建一個(gè)圖像分類器(貓與狗); 現(xiàn)在,現(xiàn)在我們要檢測(cè)物體(即汽車,行人),并用邊框(矩形)標(biāo)記它們。 隨意下載代碼或使用自己的視頻運(yùn)行應(yīng)用程序(簡(jiǎn)短視頻示例)

此處輸入圖片的描述
此處輸入圖片的描述

目標(biāo)檢測(cè)本質(zhì)

Object Classification(物體分類)

首先,我們遇到了對(duì)象分類的問題,比如我們想知道在一個(gè)圖片中是否包含一個(gè)特定的物體,在下圖中即圖像中是否包含汽車。

此處輸入圖片的描述
此處輸入圖片的描述

我們?cè)?a target="_blank" rel="nofollow">前一篇文章中提到了使用現(xiàn)有的架構(gòu)VGG-16遷移學(xué)習(xí)去構(gòu)建圖像分類器。

Object Localization(物體定位)

現(xiàn)在我們可以說,我們擁有高置信度去判斷圖片中是否含有某一特定物體,我們就面臨著圖像中物體定位的挑戰(zhàn)。通常,這是通過用矩形或邊界框標(biāo)記對(duì)象來完成的。

此處輸入圖片的描述
此處輸入圖片的描述

除了圖片分類,我們需要額外去識(shí)別物體在圖像中的位置。這通過定義邊界框來完成。
邊界框通常表現(xiàn)為物體的中心
center(b^x, b^y)
,矩形的高
height(b^h)
,矩形的寬
width(b^w)
。
此處輸入圖片的描述
此處輸入圖片的描述

現(xiàn)在,我們就需要為我們的訓(xùn)練集數(shù)據(jù)中為圖像中的每一個(gè)物體都定義這四個(gè)變量。此外,網(wǎng)絡(luò)不僅會(huì)輸出圖像類別編號(hào)(即20%cat [1],70%dog [2],10%tiger [3])的概率,還會(huì)輸出上面定義邊界框的四個(gè)變量值。
提供邊界框點(diǎn)(中心,寬度,高度),我們的模型通過給我們更詳細(xì)的圖像內(nèi)容視圖輸出/預(yù)測(cè)更多的信息。
此處輸入圖片的描述
此處輸入圖片的描述

不難想象,在圖像訓(xùn)練數(shù)據(jù)中加入更多點(diǎn)可以讓我們更深入地了解圖像。 例如,在人臉上(即嘴巴,眼睛)的點(diǎn)可以告訴我們這個(gè)人在微笑,哭泣等等。

Object Detection(目標(biāo)檢測(cè))

我們可以更進(jìn)一步的定位圖像中的多個(gè)物體。

此處輸入圖片的描述
此處輸入圖片的描述

雖然結(jié)構(gòu)沒有太大變化,但這里的問題變得更加困難,因?yàn)槲覀冃枰獪?zhǔn)備更多的數(shù)據(jù)(多邊界框)。 原則上,我們只是將圖像分成較小的矩形,對(duì)于每個(gè)矩形,我們都有相同的額外的五個(gè)變量 -
P^c, (b^x, b^y), b^h, b^w
- 和正常的預(yù)測(cè)概率(20%cat [1],70%dog[2])。 稍后我們會(huì)看到更多細(xì)節(jié),但現(xiàn)在讓我們假設(shè)結(jié)構(gòu)與物體定位相同,不同之處在于我們有多個(gè)結(jié)構(gòu)。

Sliding Window Solution(滑動(dòng)窗口解決方案)

這是一個(gè)非常直觀的解決方案。這個(gè)想法是不使用一般的汽車圖像,而是盡可能的裁剪圖像使得圖像中只含有汽車。
我們使用裁剪之后的圖像,去訓(xùn)練一個(gè)網(wǎng)絡(luò)結(jié)構(gòu)類似于VGG-16或者其他深度網(wǎng)絡(luò)的卷積神經(jīng)網(wǎng)絡(luò)。

此處輸入圖片的描述
此處輸入圖片的描述

此處輸入圖片的描述
此處輸入圖片的描述

這種方法的結(jié)果很好,但是這種模型只能用于檢測(cè)圖像中是否含有汽車,所以在檢測(cè)真實(shí)場(chǎng)景的圖像中會(huì)有問題,因?yàn)樗锩姘衅渌奈矬w(比如說樹、人、交通標(biāo)志等)。
除此之外,現(xiàn)實(shí)圖像一般也比訓(xùn)練數(shù)據(jù)的尺寸要大。
此處輸入圖片的描述
此處輸入圖片的描述

為了克服這些問題,我們可以只分析圖像中的一部分并且分析這一部分是否含有汽車的一部分。更精確的說法是,我們使用滑動(dòng)的矩形框掃描整個(gè)圖片,在每一次掃描的時(shí)候使用我們的模型來判斷這一部分是否含有汽車。讓我們看一個(gè)示例:
此處輸入圖片的描述
此處輸入圖片的描述

總之,我們使用正常的卷積神經(jīng)網(wǎng)絡(luò)(VGG-16)來訓(xùn)練帶有不同大小裁剪圖像的模型,然后使用矩形掃描物體(汽車)的圖像。 我們可以看到,通過使用不同大小的矩形,我們可以計(jì)算出不同的車輛形狀和位置。
這個(gè)算法并不復(fù)雜,并且奏效。但是這個(gè)算法擁有兩個(gè)缺點(diǎn)。

  1. 第一個(gè)問題是性能問題。我們必須調(diào)用模型預(yù)測(cè)結(jié)果很多次。每一次矩形框移動(dòng),我們都需要調(diào)用模型用于獲取預(yù)測(cè)結(jié)果 - 并且我們需要使用不同的矩形框大小來重復(fù)做這一件事情。其中一個(gè)解決性能問題的方法是增加矩形框的步長(zhǎng)(使用大步長(zhǎng)),但是這樣我們可能會(huì)檢測(cè)不出來某些物體。在過去,模型主要是線性的,并且具有手動(dòng)設(shè)計(jì)的特征,因此預(yù)測(cè)并不昂貴。 所以這個(gè)算法用來做得很好。 目前,網(wǎng)絡(luò)規(guī)模(VGG-16的參數(shù)為1.38億),這種算法速度很慢,對(duì)于像自主駕駛這樣的實(shí)時(shí)視頻對(duì)象檢測(cè)幾乎沒有用處。


    此處輸入圖片的描述
    此處輸入圖片的描述

    另外一個(gè)導(dǎo)致算法性能不佳的原因是:當(dāng)我們移動(dòng)矩形框時(shí)(向右和向下移動(dòng)),許多共用的像素點(diǎn)并沒有重用而是重復(fù)計(jì)算了。在下一部分,我們將使用最新的卷積來克服這個(gè)問題。


    此處輸入圖片的描述
    此處輸入圖片的描述
  2. 即使使用不同大小的矩形框來掃描圖像,我們依舊可能無法檢測(cè)出圖像中包含的物體。模型可能無法輸出準(zhǔn)確的邊界框信息;例如:這個(gè)矩形中只包含物體的一部分。在下一個(gè)部分中我們將探討 YOLO (you only look once) 算法,這個(gè)將會(huì)為我們解決這個(gè)問題。

Convolutional Sliding Window Solution(卷積滑動(dòng)窗口解決方案)

我們看到滑動(dòng)窗口因?yàn)闊o法重用大量已經(jīng)計(jì)算過后的數(shù)值有性能問題。每一次滑動(dòng)窗口移動(dòng)之后,我們都需要計(jì)算模型中大量的參數(shù)(可能上百萬的參數(shù)),為了獲取一個(gè)預(yù)測(cè)值。在現(xiàn)實(shí)中,我們可以引入卷積結(jié)構(gòu)來重用這些計(jì)算結(jié)果。

Turn Fully Connected Layers Into Convolution(從全連接網(wǎng)絡(luò)轉(zhuǎn)向卷積神經(jīng)網(wǎng)絡(luò))

我們?cè)谇耙黄恼碌淖詈罂吹?,圖像分類結(jié)構(gòu) - 無論其大小和配置如何 - 訓(xùn)練不同層數(shù)的全連接層網(wǎng)絡(luò),輸出的數(shù)量取決于分類物體的種類。

為了簡(jiǎn)單起見,我們將以較小的網(wǎng)絡(luò)模型為例,但對(duì)于任何卷積網(wǎng)絡(luò)來說,相同的邏輯都是有效的。(VGG-16,AlexNet

此處輸入圖片的描述
此處輸入圖片的描述

有關(guān)卷積更加直觀詳細(xì)的解釋請(qǐng)查看之前一篇文章。
這個(gè)簡(jiǎn)單的網(wǎng)絡(luò)使用大小為32 x 32 x 3的彩色圖片作為網(wǎng)絡(luò)的輸入,使用SAME3x3x64 的卷積(這種卷積方式不會(huì)改變圖像的寬和高)獲取了一個(gè)大小為32 x 32 x 64的輸出(提示,輸出數(shù)據(jù)的第三個(gè)維度和卷積和的維度64大小相等,這通常用于對(duì)輸入數(shù)據(jù)的增益)。接下來使用最大池化削減寬度和高度,并且保持第三個(gè)維度的數(shù)據(jù)不發(fā)生變化(16 x 16 x 64)。在此之后,我們使用神經(jīng)元個(gè)數(shù)為256和128的兩層全連接網(wǎng)絡(luò)。在最后我們輸出五個(gè)種類的概率(通常使用soft-max)。
讓我們看看如何用卷積層替換全連接層,同時(shí)保持?jǐn)?shù)學(xué)效果相同(輸入16 X 16 X 64的線性函數(shù))。
此處輸入圖片的描述
此處輸入圖片的描述

我們只是使用卷積核來代替全連接層。在現(xiàn)實(shí)中,16x16x256的卷積核實(shí)際上是一個(gè)16x16x64x256的矩陣(多個(gè)卷積核),因?yàn)榫矸e核的第三個(gè)維度和輸入的第三個(gè)維度總是一樣的。為了簡(jiǎn)便,我們將其認(rèn)為是16 x 16 x 256。這意味著,這相當(dāng)于一個(gè)全連接層,因?yàn)檩敵? X 1 X 256的每個(gè)元素都是輸入16 X 16 X 64的每個(gè)元素的線性函數(shù)。

我們?yōu)槭裁匆獙⑷B接(FC)層轉(zhuǎn)換為卷積層的原因是因?yàn)檫@會(huì)給我們?cè)谶x擇輸出方式時(shí)帶來更大的靈活性。 借助FC,您將始終具有相同的輸出大小,即類數(shù)。

Convolution Sliding Window(卷積滑動(dòng)窗口)

想要看到使用卷積網(wǎng)絡(luò)替代全連接層背后的思想,我們需要輸入圖片的大小大于原來的圖片大小-32x32x3。讓我們使用36x36x3的圖片作為輸入。

此處輸入圖片的描述
此處輸入圖片的描述

這個(gè)圖像 (with green 36 X 36)比原有的圖像(blue 32 X 32)大四行四列。如果我們使用步長(zhǎng)為2的滑動(dòng)窗口和全連接層網(wǎng)絡(luò),我們需要移動(dòng)原有圖像大小9次才可以覆蓋整個(gè)圖像(圖中的黑色矩形示范了其中的三種移動(dòng)結(jié)果)。與此同時(shí),調(diào)用模型9次。

接下來讓我們嘗試將更大圖像應(yīng)用在我們只使用卷積層的新模型上。

此處輸入圖片的描述
此處輸入圖片的描述

正如同我們所看到的,相比于全連接層的輸出只能為1x1x5,輸出從1x1x5變成了3x3x5?;叵氲轿覀儽仨氁苿?dòng)9次才能覆蓋整個(gè)圖片 - 等一下,這是不是正好等于3x3?是的,這些3x3大小的單元表示了每一個(gè)滑動(dòng)窗口的1x1x5的分類概率輸出結(jié)果。
這是一種非常先進(jìn)的技術(shù),因?yàn)槲覀冎恍枰淮尉涂梢粤⒓传@得全部九個(gè)結(jié)果,而無需多次執(zhí)行帶有數(shù)百萬參數(shù)的模型。

YOLO (You Only Look Once)

此處輸入圖片的描述
此處輸入圖片的描述

雖然我們通過引入卷積滑動(dòng)窗口的方式解決了性能問題。但是我們的模型依舊不能輸出非常準(zhǔn)確的邊界框,即便使用大量不同大小的邊界框。讓我們看YOLO是如何解決這個(gè)問題。

首先,我們通常在每一個(gè)圖片中標(biāo)注我們想要檢測(cè)的物體。每一個(gè)物體都會(huì)使用四個(gè)變量,通過邊界框的方式進(jìn)行標(biāo)注 - 記住這四個(gè)變量是物體的中心 center(b^x, b^y) ,矩形的高height(b^h),矩形的寬width(b^w)。每個(gè)圖像都被會(huì)分割成更小的矩形 - 通常分為 19x19個(gè)矩形,為了簡(jiǎn)單起見,這里分割為8x9

此處輸入圖片的描述
此處輸入圖片的描述

紅色的邊界框和物體都是由很多藍(lán)色邊界框的一部分組成的,所以我恩枝江對(duì)象和邊界框分配給擁有對(duì)象中心的黃色框。我們使用額外的四個(gè)變量(除了告知物體為汽車,還額外提供物體的中心,寬度和高度)訓(xùn)練我們的模型,并且將這些變量分配給擁有中心點(diǎn)的邊界框。在神經(jīng)網(wǎng)絡(luò)使用這種標(biāo)注好的數(shù)據(jù)集訓(xùn)練完成以后,我們將用該模型用于預(yù)測(cè)這四個(gè)變量的值(除了識(shí)別物體的類別),值或者邊界框。
我們不是使用預(yù)定義的邊界框大小進(jìn)行掃描,而是試圖擬合對(duì)象,我們讓模型學(xué)習(xí)如何用邊界框標(biāo)記對(duì)象; 因此,邊界框現(xiàn)在是靈活的(被學(xué)習(xí))。 這樣,邊界框的精度就高得多并且靈活多了。
讓我們來看看現(xiàn)在我們?nèi)绾伪硎据敵?,除了?-車,2-行人這樣的類之外,我們還有額外的四個(gè)變量
(b^x,b^y,b^h,b^w)
。 實(shí)際上,還增加了另一個(gè)變量
P^c
,它會(huì)告訴我們圖像是否有任何我們想要檢測(cè)的對(duì)象。
此處輸入圖片的描述
此處輸入圖片的描述

  1. P^c = 1(紅色標(biāo)注) 意味著這里至少有一個(gè)我們想要被檢測(cè)出來的對(duì)象,所以就值得去查看被識(shí)別物體的分類概率和邊界框的值。
  2. P^c = 0(紅色標(biāo)注)意味著里面檢測(cè)出任何我們想要檢測(cè)出來的對(duì)象,我們不需要關(guān)心模型預(yù)測(cè)出來的分類概率和邊界框的值。

Bounding Box Specification(邊界框識(shí)別)

我們需要使用特殊的方法來標(biāo)記我們的數(shù)據(jù)以便于YOLO算法能正確的運(yùn)轉(zhuǎn)。YOLO V2格式需要邊界框的維度值(b^x,b^y,b^h,b^w)為原始圖片寬高的相對(duì)值。假設(shè)我們擁有一個(gè)300x400大小的圖片,并且邊界框的維度為B^{width}=30, B^{height}=15, B^{X} = 150, B^{Y} = 80。這些值需要轉(zhuǎn)換為B^{width}=30/300, B^{height}=15/400, B^{X} = 150/300, B^{Y} = 80/400。
這篇文章將會(huì)講述如何借助BBox Label Tool工具花費(fèi)很小的代價(jià)來標(biāo)注我們的數(shù)據(jù)。這個(gè)工具標(biāo)記的邊界框(給我們的是左上的點(diǎn)和右下的點(diǎn))與YOLO V2格式有些許的不一樣。但是將其轉(zhuǎn)化成為我們想要的數(shù)據(jù)是非常簡(jiǎn)單的事情。
除了YOLO需要訓(xùn)練數(shù)據(jù)的標(biāo)簽,在內(nèi)部實(shí)現(xiàn)中,預(yù)測(cè)方式也有所不同。

此處輸入圖片的描述
此處輸入圖片的描述

YOLO預(yù)測(cè)的邊界框是相對(duì)于擁有對(duì)象中心的框(黃色)進(jìn)行定義。黃色框左上角的點(diǎn)定義為(0,0),并且將右下角的點(diǎn)定義為(1,1)。所以中心店
(b^x,b^y)
的值范圍一定在
0 - 1
之間(sigmoid激活函數(shù)會(huì)確保這個(gè)結(jié)果),因?yàn)橹行狞c(diǎn)一定在這個(gè)黃色的邊界框之中。
b^h和b^w
是相對(duì)于黃色框的寬和高計(jì)算出來的相對(duì)值,所以其值可以大于1。在這個(gè)圖片中我們可以看到
b^w
是黃色邊框?qū)挾鹊?.8倍,高度是黃色邊框高度的1.6倍。
預(yù)測(cè)之后,我們可以看到預(yù)測(cè)框與開始標(biāo)記的實(shí)際邊界框相交多少?;旧希覀?cè)噲D最大化它們之間的交集,所以理想情況下,預(yù)測(cè)的邊界框與標(biāo)記的邊界框完全相交。
在原則上就是這樣!你提供更加專業(yè)的使用邊界框
(b^x,b^y,b^h,b^w)
標(biāo)注的訓(xùn)練數(shù)據(jù),分割圖像,并分配給包含中心的框(負(fù)責(zé)檢測(cè)對(duì)象),訓(xùn)練卷積滑動(dòng)窗口神經(jīng)網(wǎng)絡(luò),并且預(yù)測(cè)出對(duì)象和位置。

Two More Problems(還有兩個(gè)問題)

即使我們?cè)噲D在本篇文章提供更加詳細(xì)的解釋,但是在事實(shí)中,我們還有兩個(gè)小問題需要去解決。


此處輸入圖片的描述
此處輸入圖片的描述

首先,即使在訓(xùn)練時(shí)間內(nèi),對(duì)象被分配到一個(gè)盒子(包含對(duì)象中心的盒子),在測(cè)試時(shí)間(預(yù)測(cè)時(shí)),幾個(gè)盒子(黃色)可能認(rèn)為它們具有對(duì)象的中心(帶有紅色 ),因此為同一個(gè)對(duì)象定義自己的邊界框。 這是用非最大抑制算法解決的。 目前,Deeplearning4j沒有提供實(shí)現(xiàn),所以請(qǐng)?jiān)贕itHub上找到一個(gè)簡(jiǎn)單的實(shí)現(xiàn)(removeObjectsIntersectingWithMax)。 它的作用是首先選擇最大Pc概率的盒子作為預(yù)測(cè)(它不僅具有1或0值,而是可以在0-1范圍內(nèi))。 然后,刪除每個(gè)與該框相交超過特定閾值的框。 它再次啟動(dòng)相同的邏輯,直到?jīng)]有剩下的邊界框。

此處輸入圖片的描述
此處輸入圖片的描述

其次,由于我們預(yù)測(cè)了多個(gè)物體(汽車,行人,交通信號(hào)燈等),因此可能發(fā)生兩個(gè)或更多物體的中心是一個(gè)箱體。 這些情況通過引入錨箱來解決。 使用錨箱,我們選擇幾個(gè)邊界框的形狀,我們發(fā)現(xiàn)更多用于我們想要檢測(cè)的對(duì)象。 YOLO V2文件通過k-means算法實(shí)現(xiàn),但也可以手動(dòng)完成。 之后,我們修改輸出以包含我們之前看到的相同結(jié)構(gòu)(Pc,bx,by,bh,bw,C1,C2 ...),但對(duì)于每個(gè)選定的錨箱形狀。 所以,我們現(xiàn)在可能有這樣的事情:


此處輸入圖片的描述
此處輸入圖片的描述

Application(應(yīng)用)

訓(xùn)練深度網(wǎng)絡(luò)需要付出很多努力,并需要有意義的數(shù)據(jù)和處理能力。 正如我們?cè)谥暗奈恼轮兴龅哪菢?,我們將使用轉(zhuǎn)移學(xué)習(xí)。 這一次,我們不打算修改架構(gòu)并用不同的數(shù)據(jù)訓(xùn)練,而是直接使用網(wǎng)絡(luò)。

我們打算使用Tiny YOLO; 以下問題引用于網(wǎng)上:

Tiny YOLO基于Darknet參考網(wǎng)絡(luò),速度比普通的YOLO模型快得多,但是相比普通的模型準(zhǔn)確率有所降低。 要使用VOC訓(xùn)練的版本:

wget https://pjreddie.com/media/files/tiny-yolo-voc.weights
./darknet detector test cfg/voc.data cfg/tiny-yolo-voc.cfg tiny-yolo-voc.weights data/dog.jpg

好吧,這不是完美的,但兄弟,它確實(shí)很快。 在GPU上,它運(yùn)行速度大于200 FPS。

Deeplearning4j 0.9.1的當(dāng)前發(fā)行版本不提供TinyYOLO,但0.9.2-SNAPSHOT提供。 所以首先,我們需要告訴Maven在哪里加載SNAPSHOT版本:


<repositories>
    <repository>
        <id>a</id>
        <url>http://repo1.maven.org/maven2/</url>
    </repository>
    <repository>
        <id>snapshots-repo</id>
        <url>https://oss.sonatype.org/content/repositories/snapshots</url>
        <releases>
            <enabled>false</enabled>
        </releases>
        <snapshots>
            <enabled>true</enabled>
            <updatePolicy>daily</updatePolicy>
        </snapshots>
    </repository>
</repositories>
<dependencies>
    <dependency>
        <groupId>org.deeplearning4j</groupId>
        <artifactId>deeplearning4j-core</artifactId>
        <version>${deeplearning4j}</version>
    </dependency>
    <dependency>
        <groupId>org.nd4j</groupId>
        <artifactId>nd4j-native-platform</artifactId>
        <version>${deeplearning4j}</version>
    </dependency>

接下來我們要用非常簡(jiǎn)短的代碼來加載模型:

private TinyYoloPrediction() {
    try {
        preTrained = (ComputationGraph) new TinyYOLO().initPretrained();
        prepareLabels();
    } catch (IOException e) {
        throw new RuntimeException(e);
    }
}

prepareLabels() 只是使用PASCAL VOC數(shù)據(jù)集中用于訓(xùn)練模型的標(biāo)簽. 運(yùn)行 preTrained.summary() 去查看模型架構(gòu)的時(shí)候不要感到有任何壓力。

視頻的每一幀是CarVideoDetection使用JavaCV進(jìn)行捕獲的:

FFmpegFrameGrabber grabber;
grabber = new FFmpegFrameGrabber(f);
grabber.start();
while (!stop) {
    videoFrame[0] = grabber.grab();
    if (videoFrame[0] == null) {
        stop();
        break;
    }
    v[0] = new OpenCVFrameConverter.ToMat().convert(videoFrame[0]);
    if (v[0] == null) {
        continue;
    }
    if (winname == null) {
        winname = AUTONOMOUS_DRIVING_RAMOK_TECH + ThreadLocalRandom.current().nextInt();
    }
    if (thread == null) {
        thread = new Thread(() -> {
            while (videoFrame[0] != null && !stop) {
                try {
                    TinyYoloPrediction.getINSTANCE().markWithBoundingBox(v[0], videoFrame[0].imageWidth, videoFrame[0].imageHeight, true, winname);
                } catch (java.lang.Exception e) {
                    throw new RuntimeException(e);
                }
            }
        });
        thread.start();
    }
    TinyYoloPrediction.getINSTANCE().markWithBoundingBox(v[0], videoFrame[0].imageWidth, videoFrame[0].imageHeight, false, winname);
    imshow(winname, v[0]);

因此,代碼正在從視頻獲取幀并傳遞到TinyYOLO預(yù)先訓(xùn)練好的模型。 從那里,圖像幀首先被縮放到416 X 416 X 3(RGB),然后傳給TinyYOLO用于預(yù)測(cè)和標(biāo)記邊界框:

public void markWithBoundingBox(Mat file, int imageWidth, int imageHeight, boolean newBoundingBOx,String winName) throws Exception {
    int width = 416;
    int height = 416;
    int gridWidth = 13;
    int gridHeight = 13;
    double detectionThreshold = 0.5;
    Yolo2OutputLayer outputLayer = (Yolo2OutputLayer) preTrained.getOutputLayer(0);
   
        INDArray indArray = prepareImage(file, width, height);
        INDArray results = preTrained.outputSingle(indArray);
        predictedObjects = outputLayer.getPredictedObjects(results, detectionThreshold);
        System.out.println("results = " + predictedObjects);
        markWithBoundingBox(file, gridWidth, gridHeight, imageWidth, imageHeight);
    imshow(winName, file);
}

預(yù)測(cè)之后,我們應(yīng)該已經(jīng)擁有了邊界框尺寸的預(yù)測(cè)值。我們已經(jīng)實(shí)現(xiàn)了非最大抑制算法(removeObjectsIntersectingWithMax)因?yàn)?,正如我們所提到的,YOLO算法在測(cè)試時(shí),在預(yù)測(cè)每一個(gè)對(duì)象的時(shí)候回?fù)碛胁恢灰粋€(gè)邊界框。相比(b^x,b^y,b^h,b^w),我們將會(huì)使用topLeftbottomRight左上點(diǎn)和右下點(diǎn)。gridWidthgridHeight使我們打算將圖片分割成為多少個(gè)更小的邊界框,在我們的案例中被分割為13x13。w和h為原始圖像的尺寸。

在此之后,除了播放視頻的線程之外我們將會(huì)啟用另外一個(gè)線程,我們更新視頻以獲取檢測(cè)到的對(duì)象的矩形和標(biāo)簽。

考慮我們運(yùn)行在CPU上時(shí),(實(shí)時(shí))預(yù)測(cè)的速度非常的快;如果運(yùn)行在GPU上,我們會(huì)獲得更好的實(shí)時(shí)檢測(cè)效果。

Running Application (運(yùn)行應(yīng)用)

即使你的電腦上沒有安裝Java,這個(gè)應(yīng)用可以在沒有任何Java背景知識(shí)的條件下下載和運(yùn)行。你可以嘗試使用自己的視頻。

在源代碼中執(zhí)行RUN類即可運(yùn)行。如果你不想使用IDE來打開這個(gè)工程,你可以運(yùn)行mvn clean install exec:java命令。

在運(yùn)行這個(gè)應(yīng)用之后,你將會(huì)看到如下圖所示的結(jié)果:


此處輸入圖片的描述
此處輸入圖片的描述

Enjoy!


github代碼地址: https://github.com/klevis/AutonomousDriving
gitee開源中國(guó)地址: https://gitee.com/sjsdfg/AutonomousDriving

更多文檔可以查看 https://github.com/sjsdfg/deeplearning4j-issues
你的star是我持續(xù)分享的動(dòng)力

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容