快速構建深度學習影像資料集,微軟Bing和Google哪個更好用?

AI科技大本營發表於2018-04-18

640?wx_fmt=jpeg&wxfrom=5&wx_lazy=1

譯者 | Serene

編輯 | 明明

出品 | AI 科技大本營(公眾號ID:rgznai100)


【AI 科技大本營導讀】在本文中,作者將利用微軟的 Bing Image Search API 來建立深度學習影像資料集。Bing Image Search API 是微軟 Cognitive Services 的一個組成部分,主要是幫助使用者在視覺、語言、文字等手機應用和軟體中應用AI。相比較,利用 Google Images 來構建自己的資料集是一個乏味且需要手動的過程,主要原因是因為多年前,谷歌關停了自己的影像搜尋 API ,然而,我們需要的是一個通過查詢能夠自動下載影像的方案。


建立 Cognitive Services 帳戶


在本節中,我將會向你演示如何申請一個免費的Bing Image Search API賬戶。點開連結Bing Image Search API (https://azure.microsoft.com/en-us/try/cognitive-services/?api=bing-image-search-api),開始我們的註冊流程:


640?wx_fmt=jpeg

圖1:微軟 Bing Image Search API 註冊入口


從上圖的截圖中我們可以看到,這個試用版囊括了 Bing 中所有搜尋 API ,每月都有 3000 筆交易實現,已經能夠滿足使用者需求,這對於建立第一個深度學習影像資料集來說已將完全夠用了。


若要註冊 Bing Image Search API,請點選 “Get API Key” 按鍵。可以通過微軟賬號、Facebook 賬號、領英賬號甚至是 GitHub 賬號來註冊(方便起見我是用了GitHib賬號進行註冊的)。當完成註冊以後,就會看到如下圖中我的瀏覽器展示的頁面內容。



640?wx_fmt=jpeg

圖2:Microsoft Bing API 端點以及我需要使用該API時的金鑰


此時可以看到我的頁面中 Bing 搜尋終結點列表,包括兩個 API 金鑰。(請牢記的 API 金鑰,在下一節中就會用到它)


使用 Python 來構建你的深度學習資料集


在註冊完 Bing Image Search API 賬戶之後,現在我們已經做完了建立深度學習資料集的前期準備。


閱讀文件


在繼續下面的操作之前,我建議在瀏覽器中開啟下面兩個Bing影像搜尋API文件頁面:


  • Bing 影像搜尋 API – Python QuickStart(https://docs.microsoft.com/en-us/azure/cognitive-services/bing-image-search/quickstarts/python)

  • Bing 影像搜尋 API – Paging Webpages(https://docs.microsoft.com/en-us/azure/cognitive-services/bing-web-search/paging-webpages)


如果對 API 的工作原理或是當提出請求之後如何使用 API 依然存有疑問,可以參考上述兩個文件。


安裝 request 包


如果你的電腦系統中沒有安裝 request ,你可以通過如下方式來安裝:


$pip install requests


安裝Request包之後你會發現,向 HTTP 傳送請求會變得非常容易,而且能保證我們在向 Python 發出請求時不會遇到各種棘手的困難。除此之外請注意,如果你在虛擬環境中使用 Python ,那麼你需要在終端裡使用 workon 來訪問虛擬環境,再去安裝 request。


$ workon your_env_name
$ pip install requests


編寫你自己的Python影像下載程式碼


讓我們繼續向下走,開啟程式設計之旅。開啟一個新的指令碼檔案,將其命名 search_bing_api.py,為並在指令碼中輸入下述程式碼:


# import the necessary packages
from requests import exceptions
import argparse
import requests
import cv2
import os
# construct the argument parser and parse the arguments
ap = argparse.ArgumentParser()
ap.add_argument("-q", "--query", required=True,
   help="search query to search Bing Image API for")
ap.add_argument("-o", "--output", required=True,
   help="path to output directory of images")
args = vars(ap.parse_args())


匯入此指令碼中所需的軟體包。你需要在虛擬環境中提前安裝好 OpenCV 和 requests 。下面這個連結(https://www.pyimagesearch.com/opencv-tutorials-resources-guides/)給出了在系統中安裝 OpenCV 的相關教程。


接下來,我們來講解一下兩個命令列引數:


“query”:指的是你想要搜尋的影像關鍵字或特徵,比如說“神奇寶貝”、”聖誕老人”或者是“侏羅紀公園”之類的。


“output”:影像的輸出目錄路徑。我個人偏向於把影像分成獨立的類子目錄,因此在呼叫函式時,一定要指定你想下載的影像儲存進入的正確資料夾(如下面 “下載影像進行培訓深度神經網路” 部分所示)。


在這個指令碼中你不需要去修改命令列的任何引數,這些引數是程式執行時的輸入量。如果你不明白怎麼正確使用命令列引數,請參考我以前的部落格文章 my recent blog post(https://www.pyimagesearch.com/2018/03/12/python-argparse-command-line-arguments/)。


接下來配置一些全域性變數:


# set your Microsoft Cognitive Services API key along with (1) the
# maximum number of results for a given search and (2) the group size
# for results (maximum of 50 per request)
API_KEY = "YOUR_API_KEY_GOES_HERE"
MAX_RESULTS = 250
GROUP_SIZE = 50
# set the endpoint API URL
URL = "https://api.cognitive.microsoft.com/bing/v7.0/images/search"


在使用上述程式碼的時候,讀者必須更改 API_KEY 的值。請登入到 Microsoft Cognitive Services 並選擇要使用的服務來獲取 API 金鑰(如上所示,需要單擊“獲取 API 金鑰”按鈕),然後只需將 API 金鑰貼上到該變數的引號內即可。


當然在實際程式設計的時候也可以更改 MAX_RESULTS和GROUP_SIZE 這兩個引數的值。我在示例中只要求資料庫中有 250 張圖片,一共 5 次搜尋,每次搜尋返回最多 50 張圖片(可以通過改變 MMAX_RESULTS 引數來更改這個數量),同時我要求 Bing API 在每次執行搜尋和下載圖片命令時,都要返回單次下載下來的圖片數量值。


你也可以把 GROUP_SIZE 的引數看作是 per page 的返回值的數量。因此如果我們一共需要 250 張圖片,就需要把 “pages” 引數調成 5,“per page” 的值賦成 50。


注意:

1、所下載的圖片一定要與搜尋的關鍵詞有關係;

2、操作過程需要在 Bing AI 的免費服務範圍之內(否則就需要為所要求的服務付費)。


現在一起來看一看,在準備階段我們會碰到的所有可能的異常。這些異常可能會在獲取映像時出現。我先列出可能遇到的異常:


# when attempting to download images from the web both the Python
# programming language and the requests library have a number of
# exceptions that can be thrown so let's build a list of them now
# so we can filter on them
EXCEPTIONS = set([IOError, FileNotFoundError,
   exceptions.RequestException, exceptions.HTTPError,
   exceptions.ConnectionError, exceptions.Timeout])


在處理網路請求時,我們可能會丟擲一些異常,我們將嘗試找到他們並加以妥善解決。


接下來讓我們初始化搜尋引數並進行搜尋:


# store the search term in a convenience variable then set the
# headers and search parameters
term = args["query"]
headers = {"Ocp-Apim-Subscription-Key" : API_KEY}
params = {"q": term, "offset": 0, "count": GROUP_SIZE}
# make the search
print("[INFO] searching Bing API for '{}'".format(term))
search = requests.get(URL, headers=headers, params=params)
search.raise_for_status()
# grab the results from the search, including the total number of
# estimated results returned by the Bing API
results = search.json()
estNumResults = min(results["totalEstimatedMatches"], MAX_RESULTS)
print("[INFO] {} total results for '{}'".format(estNumResults,
   term))
# initialize the total number of images downloaded thus far
total = 0


對搜素變數引數進行了初始化。在執行該操作時若有任何問題請參閱相關 API documentation(https://docs.microsoft.com/en-us/rest/api/cognitiveservices/bing-images-api-v7-reference)


接下來我們執行搜尋命令,並以 JSON 格式獲取結果。我們執行了計算命令並輸出下一個終端的預計下載圖片數量。將總數進行初始化,因為之後要記錄下載圖片的總數量。


接下來執行程式,得到 GROUP_SIZE 的迴圈結果:


# loop over the estimated number of results in `GROUP_SIZE` groups
for offset in range(0, estNumResults, GROUP_SIZE):
   # update the search parameters using the current offset, then
   # make the request to fetch the results
   print("[INFO] making request for group {}-{} of {}...".format(
       offset, offset + GROUP_SIZE, estNumResults))
   params["offset"] = offset
   search = requests.get(URL, headers=headers, params=params)
   search.raise_for_status()
   results = search.json()
   print("[INFO] saving images for group {}-{} of {}...".format(
       offset, offset + GROUP_SIZE, estNumResults))


執行迴圈,通過迴圈得到 GROUP_SIZE 批處理結果的估計量(這是 API 允許的)。


當呼叫 requests.get 來獲取 JSON blob時,當前偏移量會作為引數被傳遞。


現在嘗試儲存當前批次中的影像:

           

# loop over the results
   for v in results["value"]:
       # try to download the image
       try:
           # make a request to download the image
           print("[INFO] fetching: {}".format(v["contentUrl"]))
           r = requests.get(v["contentUrl"], timeout=30)
           # build the path to the output image
           ext = v["contentUrl"][v["contentUrl"].rfind("."):]
           p = os.path.sep.join([args["output"], "{}{}".format(
               str(total).zfill(8), ext)])
           # write the image to disk
           f = open(p, "wb")
           f.write(r.content)
           f.close()
       # catch any errors that would not unable us to download the
       # image
       except Exception as e:
           # check to see if our exception is in our list of
           # exceptions to check for
           if type(e) in EXCEPTIONS:
               print("[INFO] skipping: {}".format(v["contentUrl"]))
               continue


接下來我們將迴圈播放當前這一批影像,並嘗試將每個影像下載到我們的輸出路徑資料夾中。


建立一個 try-catch 塊,以便我們捕捉到我們之前在指令碼中定義的可能的異常情況。如果遇到異常,我們將跳過該特定影像並繼續下載後面的圖片。


在 try 程式碼塊內部我們通過 URL獲取影像,併為它建立一個路徑+檔名。


然後我們嘗試開啟影像,並將檔案寫入磁碟。需要注意的是,我們在 “wb” 中建立了一個由 b 表示的二進位制檔案物件,然後訪問二進位制資料 viar.content。


接下來,我們看看 OpenCV 能否實際載入影像。如果能實現該操作,則說明:1、影像檔案已成功下載,2、影像路徑有效:


        # try to load the image from disk
       image = cv2.imread(p)
       # if the image is `None` then we could not properly load the
       # image from disk (so it should be ignored)
       if image is None:
           print("[INFO] deleting: {}".format(p))
           os.remove(p)
           continue
       # update the counter
       total += 1


只要影像資料不是無,我們就需要更新計數器(每次加1)並迴圈回到頂部。


否則,我們需要呼叫 os.remove 刪除無效映像,然後繼續回到初始迴圈,同時不更新計數器。 if 語句可能由於下載檔案時出現網路錯誤,未安裝正確的影像 I / O 庫等原因被觸發。如果想要了解更多關於 OpenCV 和 Python 中的 NoneType 錯誤的資訊,請參閱此處網頁refer to this blog post(https://www.pyimagesearch.com/2016/12/26/opencv-resolving-nonetype-errors/)


下載影像訓練深度學習神經網路系統


既然已經寫好了程式碼,現在就讓我們使用 Bing’s Image Search API 來下載深度學習資料集的影像。(需要使用本文的 “Download” 部分下載程式碼和示例目錄結構。)


現在建立一個資料集目錄:


$mkdirdataset


把下載的所以影像都儲存在資料集裡,執行以下命令來建立子目錄並搜尋 “charmander” (小火龍):


$ mkdir dataset/charmander
$ python search_bing_api.py --query "charmander" --output dataset/charmander
[INFO] searching Bing API for 'charmander'
[INFO] 250 total results for 'charmander'
[INFO] making request for group 0-50 of 250...
[INFO] saving images for group 0-50 of 250...
[INFO] fetching: http://fc06.deviantart.net/fs70/i/2012/355/8/2/0004_c___charmander_by_gaghiel1987-d5oqbts.png
[INFO] fetching: http://th03.deviantart.net/fs71/PRE/f/2010/067/5/d/Charmander_by_Woodsman819.jpg
[INFO] fetching: http://fc05.deviantart.net/fs70/f/2011/120/8/6/pokemon___charmander_by_lilnutta10-d2vr4ov.jpg
...
[INFO] making request for group 50-100 of 250...
[INFO] saving images for group 50-100 of 250...
...
[INFO] fetching: http://38.media.tumblr.com/f0fdd67a86bc3eee31a5fd16a44c07af/tumblr_nbhf2vTtSH1qc9mvbo1_500.gif
[INFO] deleting: dataset/charmander/00000174.gif
...


正如我在這篇文章開頭提到的,我們需要為搭建自己的 Pokedex 下載一些 Pokemon 的影像。


在上面的程式碼中,我正在下載一個受非常歡迎的寵物精靈—— 小火龍 Charmander 的影像。250 張圖片中,大部分都會成功下載;但是如上圖的輸出所示,有一些 OpenCV 無法開啟的檔案將被刪除。


同樣的,我們用上面的程式碼來下載皮卡丘的影像:


$ mkdir dataset/pikachu
$ python search_bing_api.py --query "pikachu" --output dataset/pikachu
[INFO] searching Bing API for 'pikachu'
[INFO] 250 total results for 'pikachu'
[INFO] making request for group 0-50 of 250...
[INFO] saving images for group 0-50 of 250...
[INFO] fetching: http://www.mcmbuzz.com/wp-content/uploads/2014/07/025Pikachu_OS_anime_4.png
[INFO] fetching: http://images4.fanpop.com/image/photos/23300000/Pikachu-pikachu-23385603-814-982.jpg
[INFO] fetching: http://images6.fanpop.com/image/photos/33000000/pikachu-pikachu-33005706-895-1000.png
...


還有傑尼龜(Squirtle) 的影像庫:


$ mkdir dataset/squirtle
$ python search_bing_api.py --query "squirtle" --output dataset/squirtle
[INFO] searching Bing API for 'squirtle'
[INFO] 250 total results for 'squirtle'
[INFO] making request for group 0-50 of 250...
[INFO] saving images for group 0-50 of 250...
[INFO] fetching: http://fc03.deviantart.net/fs71/i/2013/082/1/3/007_squirtle_by_pklucario-d5z1gj5.png
[INFO] fetching: http://fc03.deviantart.net/fs70/i/2012/035/b/2/squirtle_by_maii1234-d4oo1aq.jpg
[INFO] fetching: http://3.bp.blogspot.com/-yeK-y_dHCCQ/TWBkDZKi6vI/AAAAAAAAABU/_TVDXBrxrkg/s1600/Leo%2527s+Squirtle.jpg
...


同樣的,我們來處理妙蛙種子 (Bulbasaur) 的影像:


$ mkdir dataset/bulbasaur
$ python search_bing_api.py --query "bulbasaur" --output dataset/bulbasaur
[INFO] searching Bing API for 'bulbasaur'
[INFO] 250 total results for 'bulbasaur'
[INFO] making request for group 0-50 of 250...
[INFO] saving images for group 0-50 of 250...
[INFO] fetching: http://fc06.deviantart.net/fs51/f/2009/261/3/e/Bulbasaur_by_elfaceitoso.png
[INFO] skipping: http://fc06.deviantart.net/fs51/f/2009/261/3/e/Bulbasaur_by_elfaceitoso.png
[INFO] fetching: http://4.bp.blogspot.com/-b-dLFLsHtm4/Tq9265UAmjI/AAAAAAAAHls/CrkUUFrj6_c/s1600/001Bulbasaur+pokemon+firered+leafgreen.png
[INFO] skipping: http://4.bp.blogspot.com/-b-dLFLsHtm4/Tq9265UAmjI/AAAAAAAAHls/CrkUUFrj6_c/s1600/001Bulbasaur+pokemon+firered+leafgreen.png
[INFO] fetching: http://fc09.deviantart.net/fs71/i/2012/088/9/6/bulbasaur_by_songokukai-d4gecpp.png
...


最後下載超夢 (Mewtwo) 的影像:


$ mkdir dataset/mewtwo
$ python search_bing_api.py --query "mewtwo" --output dataset/mewtwo
[INFO] searching Bing API for 'mewtwo'
[INFO] 250 total results for 'mewtwo'
[INFO] making request for group 0-50 of 250...
[INFO] saving images for group 0-50 of 250...
[INFO] fetching: http://sickr.files.wordpress.com/2011/09/mewtwo.jpg
[INFO] fetching: http://4.bp.blogspot.com/-_7XMdCIyKDs/T3f-0h2X4zI/AAAAAAAABmQ/S2904beJlOw/s1600/Mewtwo+Pokemon+Wallpapers+3.jpg
[INFO] fetching: http://2.bp.blogspot.com/-3jDdQdPl1yQ/T3f-61gJXEI/AAAAAAAABmg/AUmKm65ckv8/s1600/Mewtwo+Pokemon+Wallpapers.jpg
...


下面讓我們通過一個黑科技命令來計算每次執行查詢命令時,程式下載的影像總數。


$ find . -type d -print0 | while read -d '' -r dir; do
> files=("$dir"/*)
> printf "%5d files in directory %s\n" "${#files[@]}" "$dir"
> done
   2 files in directory .
   5 files in directory ./dataset
 235 files in directory ./dataset/bulbasaur
 245 files in directory ./dataset/charmander
 245 files in directory ./dataset/mewtwo
 238 files in directory ./dataset/pikachu
 230 files in directory ./dataset/squirtle


在這裡我們可以看到,對於每一種神奇寶貝,相應的下載目錄下大約有 230-245 張圖片。理想情況下,我希望在圖片庫中,每種神奇寶貝都有 1,000 幅圖片左右,但為了做示例能簡單一些,又考慮到網路開銷(對於沒有快速/穩定的 Internet 連線的使用者),我只為每一隻神奇寶貝下載了 250 張圖片來當作圖片庫。


完善深度學習影像資料集


但是,我們每次下載下來的圖片並不一定全都和我們的搜尋關鍵詞有關係。雖說大部分應該都是這些神奇寶貝的圖片,但是總有幾張漏網之魚。不幸的是,這項工作是手動的,你需要到你的圖片目錄下一張一張去確認,然後刪掉與關鍵字不相符的圖片。


不過在蘋果電腦的 macOS 系統中這個過程還是非常快的。


我只需要開啟我的 “Finder” ,在 “CoverFloow” 檢視下,瀏覽所有圖片檔案即可。


640?wx_fmt=jpeg

圖3:.我正在使用 macOS 的 “Cover Flow” 檢視,以便快速瀏覽影像並過濾出我不想在深度學習資料集中使用的影像。


如果我發現了任何與關鍵字不相關的圖片,只需要在鍵盤上按 cmd+delete 刪除檔案即可。其他的作業系統上也有類似的快捷方式和工具。


刪除掉與目標不相關的圖片後,讓我們再重新做一次圖片計數:


$ find . -type d -print0 | while read -d '' -r dir; do
> files=("$dir"/*);
> printf "%5d files in directory %s\n" "${#files[@]}" "$dir";
> done
    3 files in directory .
    5 files in directory ./dataset
  234 files in directory ./dataset/bulbasaur
  238 files in directory ./dataset/charmander
  239 files in directory ./dataset/mewtwo
  234 files in directory ./dataset/pikachu
  223 files in directory ./dataset/squirtle


看這個新的圖片計數結果——每個目錄下我都僅僅刪除了很少的不相關圖片,這說明 Bing Image Search API 還是非常好用的。


另外,在實際操作中還應該剔除下載重複的圖片,在這裡,我沒有做這個步驟是因為在剔除不相關圖片時,我沒有發現太多的重複(除了小火龍的圖片,不知道為什麼會有那麼多重複)。如果想了解如何查詢到重複,可以參考下面這篇文章:this blog post on image hashing(https://www.pyimagesearch.com/2017/11/27/image-hashing-opencv-python/)


結語


本文講解了如何利用 Microsoft’s Bing Image Search API 來快速建立我們自己的深度學習影像資料集。我們學習了通過使用 API 來自動下載圖片,這比使用 Google Image 時需要手動下載每一張圖片更為方便。如果你想按照本文所講述的知識實際操作一下的話,你可以選擇 Bing Image Search API ,另外它將提供 30 天的免費試用期。


原文作者:Adrian Rosebrock

原文連結:https://www.pyimagesearch.com/2018/04/09/how-to-quickly-build-a-deep-learning-image-dataset/


招聘

AI科技大本營現招聘AI記者和資深編譯,有意者請將簡歷投至:gulei@csdn.net,期待你的加入


AI科技大本營讀者群(計算機視覺、機器學習、深度學習、NLP、Python、AI硬體、AI+金融、AI+PM方向)正在招募中,和你志同道合的小夥伴也在這裡!關注AI科技大本營微信公眾號,後臺回覆:讀者群,新增營長請務必備註姓名,研究方向。

640?wx_fmt=gif

640?wx_fmt=png


640?wx_fmt=png

AI科技大本營公眾號ID:rgznai100640?wx_fmt=jpeg


☟☟☟點選 | 閱讀原文 | 檢視更多精彩內容

相關文章