使用Node.js在深度學(xué)習(xí)中做圖片預(yù)處理的方法
背景
最近在做一個(gè)和對(duì)象識(shí)別相關(guān)的項(xiàng)目,由于團(tuán)隊(duì)內(nèi)技術(shù)棧偏向 JavaScript
,在已經(jīng)用 Python
和 Tensorflow
搭建好了對(duì)象識(shí)別服務(wù)器后,為了不再增加團(tuán)隊(duì)成員維護(hù)成本,所以盡可能將訓(xùn)練和識(shí)別之外的任務(wù)交給 Node.js
來(lái)做,今天要講到的圖片預(yù)處理就是其中之一。
這里對(duì)還不了解深度學(xué)習(xí)的人就幾個(gè)概念做個(gè)簡(jiǎn)單的解釋
- 對(duì)象識(shí)別:對(duì)象識(shí)別可理解為計(jì)算機(jī)在一張圖片中發(fā)現(xiàn)某個(gè)或某些指定的物體,比如找到里面所有的狗。
- 訓(xùn)練:計(jì)算機(jī)學(xué)會(huì)對(duì)象識(shí)別這個(gè)本領(lǐng)就像人類學(xué)會(huì)說(shuō)話一樣,需要不斷地練習(xí),深度學(xué)習(xí)中管這個(gè)過(guò)程叫做 “訓(xùn)練”。
- 訓(xùn)練集:人類學(xué)會(huì)說(shuō)話需要看別人怎么說(shuō),聽(tīng)別人的聲音等等,這些能夠讓自己學(xué)會(huì)說(shuō)話的信息在深度學(xué)習(xí)中稱為訓(xùn)練集,只不過(guò)對(duì)象識(shí)別中需要的訓(xùn)練集只有圖片。
做圖片預(yù)處理的目的是為了解決對(duì)象識(shí)別中訓(xùn)練集不足的問(wèn)題。當(dāng)對(duì)象識(shí)別應(yīng)用于某個(gè)專用領(lǐng)域的時(shí)候,就會(huì)遇到這個(gè)問(wèn)題。如果你是識(shí)別一只狗,這樣的圖片一大把,而且有人已經(jīng)訓(xùn)練好了,并且可以提供服務(wù)給大家使用了。如果你是識(shí)別團(tuán)隊(duì)內(nèi)的文化衫,這樣的圖片就太少了,費(fèi)了老半天勁拍 100 張,這樣的數(shù)據(jù)量依然少得可憐。要知道網(wǎng)上那些成熟的 AI 服務(wù),訓(xùn)練集隨隨便便就成千上萬(wàn),甚至以億為單位。當(dāng)然,專用領(lǐng)域一般需求也比較簡(jiǎn)單,需要識(shí)別出來(lái)的東西種類不多,特征也比較明顯,但是仍然會(huì)希望訓(xùn)練集越大越好,這時(shí)候就可以對(duì)所擁有的圖片做一些處理,來(lái)生成新的圖片,從而擴(kuò)充當(dāng)前的訓(xùn)練集,這個(gè)過(guò)程就叫圖片預(yù)處理了。
常見(jiàn)的圖片預(yù)處理方式有以下幾種:
- 旋轉(zhuǎn)。由于旋轉(zhuǎn)的角度可以是任意值,所以需要隨機(jī)生成一些角度來(lái)旋轉(zhuǎn),這又稱為隨機(jī)旋轉(zhuǎn)。
- 翻轉(zhuǎn)。相當(dāng)于在圖片旁邊放面鏡子,新圖片就是鏡子內(nèi)的圖片,一般有水平翻轉(zhuǎn)和豎直翻轉(zhuǎn)兩種。
- 調(diào)節(jié)亮度。調(diào)節(jié)過(guò)手機(jī)的亮度就能體會(huì)這個(gè)意思。
- 調(diào)節(jié)飽和度。調(diào)節(jié)過(guò)傳統(tǒng)電視就能體會(huì)到這個(gè)意思,飽和度越高,色彩顯示越鮮艷,反之給人一種冷色的感覺(jué)。
- 調(diào)節(jié)色相。這個(gè)相當(dāng)于給整個(gè)圖片變顏色一樣,想象一下以前調(diào)出來(lái)的綠色電視。
- 調(diào)節(jié)對(duì)比度。這個(gè)會(huì)讓圖片亮的地方更亮,暗的地方更暗。也可以想象一下電視上的對(duì)比度調(diào)節(jié),不得不說(shuō)電視機(jī)啟蒙了這些專業(yè)名詞。
上述每項(xiàng)操作都需要視場(chǎng)景而選擇,目前適用于我們團(tuán)隊(duì)的處理方式主要也就是上面這些。還有一些白化、Gamma 處理等操作,由于不是那么直觀,有興趣的人可以自己去了解。
安裝 gm
gm 是一個(gè)圖片處理的 npm
庫(kù),性能在 Node.js
庫(kù)中應(yīng)該算佼佼者了,它底層默認(rèn)使用的是 GraphicsMagick
,所以你需要先安裝 GraphicsMagick
,在 Mac 系統(tǒng)中直接用 Homebrew
安裝:
brew install graphicsmagick
其他系統(tǒng)的安裝方式可以直接前往官網(wǎng)查看。
如果你需要在圖片上添加文字,還需要安裝ghostscript
,在 Mac 上可以用brew install ghostscript
安裝。由于本文沒(méi)涉及到這一個(gè)功能,所以可以不用安裝。
同時(shí),需要將 gm
安裝在你的項(xiàng)目下:
npm i gm -S
預(yù)處理
為了直觀,我選了一張圖片作為預(yù)處理對(duì)象:
另外,在本文的示例代碼中,每種預(yù)處理方法的函數(shù)名都是參照 Tensorflow
中 Image
模塊的同名方法而定,更多處理圖片的方法可以前往 Tensorflow 文檔官網(wǎng)自行查看,同時(shí)去 gm 官方文檔 中尋找相同作用的方法。
翻轉(zhuǎn)
沿 Y 軸翻轉(zhuǎn)用到了 gm
的 .flip
方法:
import gm from 'gm'; /** * 沿 Y 軸翻轉(zhuǎn),即上下顛倒 * @param inputPath 輸入的圖像文件路徑 * @param outputPath 輸出的圖像文件路徑 * @param callback 處理后的回調(diào)函數(shù) */ function flip(inputPath, outputPath, callback) { gm(inputPath) .flip() .write(outputPath, callback); }
翻轉(zhuǎn)后的效果如下圖所示:
沿 X 軸翻轉(zhuǎn)用到了 gm
的 .flop
方法:
import gm from 'gm'; /** * 沿 X 軸翻轉(zhuǎn),即上下顛倒 * @param inputPath 輸入的圖像文件路徑 * @param outputPath 輸出的圖像文件路徑 * @param callback 處理后的回調(diào)函數(shù) */ function flop(inputPath, outputPath, callback) { gm(inputPath) .flop() .write(outputPath, callback); }
翻轉(zhuǎn)后的效果如下圖所示:
你還可以把 .flip
和 .flop
組合起來(lái)使用,形成對(duì)角線翻轉(zhuǎn)的效果:
如果把原圖看成一個(gè)前端組件,即一個(gè)購(gòu)物按鈕組,里面每個(gè)按鈕的背景可以自定義,按鈕里面由文字、分隔線、文字三種元素組成,那么上面翻轉(zhuǎn)后的圖片是可以看成同一個(gè)組件的,即可以拿來(lái)作為訓(xùn)練集。
有時(shí)候,翻轉(zhuǎn)帶來(lái)的效果并不是自己想要的,可能翻轉(zhuǎn)后,和原來(lái)的圖片就不應(yīng)該視作同一個(gè)東西了,這時(shí)候這種方法就有局限性了。
調(diào)整亮度
相比之后,調(diào)整亮度就顯得更加普適了,無(wú)論是什么圖片,調(diào)整亮度后,里面的東西依然還是原來(lái)的那個(gè)東西。
調(diào)整亮度用到了 gm
的 .modulate
方法:
/** * 調(diào)整亮度 * @param inputPath 輸入的圖像文件路徑 * @param outputPath 輸出的圖像文件路徑 * @param brightness 圖像亮度的值,基準(zhǔn)值是 100,比 100 高則是增加亮度,比 100 低則是減少亮度 * @param callback 處理后的回調(diào)函數(shù) */ function adjustBrightness(inputPath, outputPath, brightness, callback) { gm(inputPath) .modulate(brightness, 100, 100) .write(outputPath, callback); }
.modulate
方法是一個(gè)多功能的方法,可以同時(shí)調(diào)整圖片的亮度、飽和度和色相三種特性,這三種特性分別對(duì)應(yīng)著該方法的三個(gè)參數(shù),這里只調(diào)整亮度,所以只改變第一個(gè)參數(shù)(比 100 高則是增加亮度,比 100 低則是減少亮度),其他保持 100 基準(zhǔn)值不變。
我把亮度從 0 - 200 的圖片都生成了出來(lái),并進(jìn)行了對(duì)比,選出了一個(gè)亮度處理較為合適的區(qū)間??梢钥纯?0 - 200 之間相鄰亮度相差為 10 的圖片之間的差別(提示:每張圖片的左上角標(biāo)識(shí)出了該圖片的亮度):
可以看到亮度為 60 以下的圖片,都太暗了,細(xì)節(jié)不夠明顯,亮度為 150 以上的圖片,都太亮了,也是細(xì)節(jié)不夠明顯。而經(jīng)過(guò)多張圖片綜合對(duì)比之后,我認(rèn)為 [60, 140] 這個(gè)區(qū)間的圖片質(zhì)量比較好,與原圖相比不會(huì)丟失太多細(xì)節(jié)。
再來(lái)看看亮度為 50 和 60 的兩張圖片,其實(shí)看起來(lái)像是一張圖片一樣,不符合訓(xùn)練集多樣性的原則,更何況是相鄰亮度相差為 1 的兩張圖片。所以最終決定作為訓(xùn)練集的相鄰兩張圖片亮度差為 20,這樣差異就比較明顯,比如亮度為 80 和亮度為 100 的兩張圖片。
最終,調(diào)節(jié)亮度產(chǎn)生的新圖片將會(huì)是 4 張。從亮度為 60 的圖片開(kāi)始,每增加 20 亮度就選出來(lái)加入訓(xùn)練集,直到亮度為 140 的圖片,其中亮度為 100 的圖片不算。
調(diào)節(jié)飽和度
調(diào)節(jié)飽和度也是用 .modulate
方法,只不過(guò)是調(diào)節(jié)第二個(gè)參數(shù):
/** * 調(diào)整飽和度 * @param inputPath 輸入的圖像文件路徑 * @param outputPath 輸出的圖像文件路徑 * @param saturation 圖像飽和度的值,基準(zhǔn)值是 100,比 100 高則是增加飽和度,比 100 低則是減少飽和度 * @param callback 處理后的回調(diào)函數(shù) */ function adjustSaturation(inputPath, outputPath, saturation, callback) { gm(inputPath) .modulate(100, saturation, 100) .write(outputPath, callback); }
同樣按調(diào)節(jié)亮度的方法來(lái)確定飽和度的范圍以及訓(xùn)練集中相鄰兩張圖片的飽和度相差多少。可以看看相鄰飽和度相差為 10 的圖片之間的差別(提示:每張圖片的左上角標(biāo)識(shí)出了該圖片的飽和度):
調(diào)節(jié)飽和度的產(chǎn)生的圖片細(xì)節(jié)沒(méi)有丟,大多都能夠用作訓(xùn)練集中的圖片,與亮度一樣,飽和度相差 20 的兩張圖片差異性明顯。另外,飽和度大于 140 的時(shí)候,圖片改變就不明顯了。所以調(diào)節(jié)飽和度產(chǎn)生的新圖片將會(huì)是 6 張。從飽和度為 0 的圖片開(kāi)始,每增加 20 飽和度就選出來(lái)加入訓(xùn)練集,直到飽和度為 140 的圖片,其中飽和度為 100 的圖片不算。
調(diào)節(jié)色相
調(diào)節(jié)色相的方法在此場(chǎng)景下是最有用的方法,產(chǎn)生的訓(xùn)練集最多,率先來(lái)看下色相相鄰為 10 的圖片之間的差距吧(提示:每張圖片的左上角標(biāo)識(shí)出了該圖片的色相):
幾乎每個(gè)圖片都能作為新的訓(xùn)練集,由于色相調(diào)節(jié)范圍只能在 0 - 200 之間,所以從色相為 0 的圖片開(kāi)始,每增加 10 色相就選出來(lái)加入訓(xùn)練集,直到色相為 190 的圖片,其中色相為 100 的圖片不算。 這樣就能夠產(chǎn)生 20 張圖片作為訓(xùn)練集。
至于調(diào)節(jié)色相的代碼則和亮度、飽和度一樣,只是改變了第三個(gè)參數(shù):
/** * 調(diào)整色相 * @param inputPath 輸入的圖像文件路徑 * @param outputPath 輸出的圖像文件路徑 * @param hue 圖像色相的值,基準(zhǔn)值是 100,比 100 高則是增加色相,比 100 低則是減少色相 * @param callback 處理后的回調(diào)函數(shù) */ function adjustHue(inputPath, outputPath, hue, callback) { gm(inputPath) .modulate(100, 100, hue) .write(outputPath, callback); }
調(diào)節(jié)色相并不是萬(wàn)能的,只是適用于這個(gè)場(chǎng)景,當(dāng)然,我們團(tuán)隊(duì)的需求都是類似這個(gè)場(chǎng)景的。但是,如果你要訓(xùn)練識(shí)別梨的人工智能,告訴它有個(gè)藍(lán)色的梨顯然是不合適的。
調(diào)節(jié)對(duì)比度
調(diào)整對(duì)比度用到了 gm
的 .contrast
方法:
/** * 調(diào)整對(duì)比度 * @param inputPath 輸入的圖像文件路徑 * @param outputPath 輸出的圖像文件路徑 * @param multiplier 調(diào)節(jié)對(duì)比度的因子,默認(rèn)是 0,可以為負(fù)值,n 表示增加 n 次對(duì)比度,-n 表示降低 n 次對(duì)比度 * @param callback 處理后的回調(diào)函數(shù) */ function adjustContrast(inputPath, outputPath, multiplier, callback) { gm(inputPath) .contrast(multiplier) .write(outputPath, callback); }
下面是對(duì)比度因子從 -10 到 10 之間的圖像,可以看到圖片質(zhì)量較好的區(qū)間是 [-5, 2],其他都會(huì)丟失一些細(xì)節(jié)。另外相鄰對(duì)比度因子的圖片之間的差異也比較明顯,所以每張圖片都可作為訓(xùn)練集,這樣又多出 7 張圖片。
總結(jié)
通過(guò)上述 5 種方法,可以在一張圖片的基礎(chǔ)上額外獲得 40 張圖片,即訓(xùn)練集是原來(lái)的 40 倍。這還是在沒(méi)有多種方法混合使用的情況下,如果混合使用,恐怕幾百倍都不止。
gm
還支持對(duì)圖片進(jìn)行其他處理方式,你可以自己去發(fā)掘,每種方式在特定場(chǎng)景下都有自己的局限性,需要你去甄選。希望大家都有一個(gè)自己滿意的訓(xùn)練集。
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
Node.js實(shí)現(xiàn)簡(jiǎn)單的爬取的示例代碼
這篇文章主要介紹了Node.js實(shí)現(xiàn)簡(jiǎn)單的爬取的示例代碼,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-06-06Node.js控制臺(tái)彩色輸出的方法與原理實(shí)例詳解
這篇文章主要給大家介紹了關(guān)于Node.js控制臺(tái)彩色輸出的方法與原理的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用Node.js具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-12-12如何發(fā)布一個(gè)npm包到?Nexus私有倉(cāng)庫(kù)
這篇文章主要介紹了如何發(fā)布一個(gè)npm包到?Nexus私有倉(cāng)庫(kù),通過(guò)實(shí)例代碼介紹了如何添加nexus權(quán)限及配置?npm?私庫(kù)免登錄設(shè)置的相關(guān)知識(shí),感興趣的朋友跟隨小編一起看看吧2024-03-03Node.js HTTP服務(wù)器中的文件、圖片上傳的方法
這篇文章主要介紹了Node.js HTTP服務(wù)器中的文件、圖片上傳的方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-09-09nodejs簡(jiǎn)單實(shí)現(xiàn)TCP服務(wù)器端和客戶端的聊天功能示例
這篇文章主要介紹了nodejs簡(jiǎn)單實(shí)現(xiàn)TCP服務(wù)器端和客戶端的聊天功能,結(jié)合實(shí)例形式分析了nodejs基于TCP協(xié)議實(shí)現(xiàn)的聊天程序客戶端與服務(wù)器端具體步驟與相關(guān)操作技巧,代碼備有較為詳盡的注釋便于理解,需要的朋友可以參考下2018-01-01NodeJS?基于?Dapr?構(gòu)建云原生微服務(wù)應(yīng)用快速入門(mén)教程
Dapr?是一個(gè)可移植的、事件驅(qū)動(dòng)的運(yùn)行時(shí),它使任何開(kāi)發(fā)人員能夠輕松構(gòu)建出彈性的、無(wú)狀態(tài)和有狀態(tài)的應(yīng)用程序,并可運(yùn)行在云平臺(tái)或邊緣計(jì)算中,它同時(shí)也支持多種編程語(yǔ)言和開(kāi)發(fā)框架,本文重點(diǎn)介紹NodeJS云原生微服務(wù)應(yīng)用,感興趣的朋友一起看看吧2022-07-07node中IO以及定時(shí)器優(yōu)先級(jí)詳解
這篇文章主要給大家介紹了關(guān)于node中IO以及定時(shí)器優(yōu)先級(jí)的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用node具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-05-05node.js中的path.extname方法使用說(shuō)明
這篇文章主要介紹了node.js中的path.extname方法使用說(shuō)明,本文介紹了path.extname的方法說(shuō)明、語(yǔ)法、使用實(shí)例和實(shí)現(xiàn)源碼,需要的朋友可以參考下2014-12-12nodejs實(shí)現(xiàn)文件或文件夾上傳功能的代碼示例
在平常的工作中,經(jīng)常會(huì)遇到需要將本地項(xiàng)目文件同步到遠(yuǎn)端服務(wù)器的情況,所以每次遇到都需要考慮如何將文件上傳到服務(wù)器上,所以本文就給大家介紹一下nodejs實(shí)現(xiàn)文件或文件夾上傳功能,需要的朋友可以參考下2023-08-08