快速构建深度学习图像数据集,微软Bing和Google哪个更好用?

百家 作者:AI100 2018-04-14 09:18:43

译者 | 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),开始我们的注册流程:


图1:微软 Bing Image Search API 注册入口


从上图的截屏中我们可以看到,这个试用版囊括了 Bing 中所有搜索 API ,每月都有 3000 笔交易实现,已经能够满足用户需求,这对于建立第一个深度学习图像数据集来说已将完全够用了。


若要注册 Bing Image Search API,请点击 “Get API Key” 按键。可以通过微软账号、Facebook 账号、领英账号甚至是 GitHub 账号来注册(方便起见我是用了GitHib账号进行注册的)。当完成注册以后,就会看到如下图中我的浏览器展示的页面内容。



图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 %sn" "${#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” 视图下,浏览所有图片文件即可。


图3:.我正在使用 macOS 的 “Cover Flow” 视图,以便快速浏览图像并过滤出我不想在深度学习数据集中使用的图像。


如果我发现了任何与关键字不相关的图片,只需要在键盘上按 cmd+delete 删除文件即可。其他的操作系统上也有类似的快捷方式和工具。


删除掉与目标不相关的图片后,让我们再重新做一次图片计数:


$ find . -type d -print0 | while read -d '' -r dir; do
> files=("$dir"/*);
> printf "%5d files in directory %sn" "${#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科技大本营微信公众号,后台回复:读者群,添加营长请务必备注姓名,研究方向。



AI科技大本营
公众号ID:rgznai100


☟☟☟点击 | 阅读原文 | 查看更多精彩内容

关注公众号:拾黑(shiheibook)了解更多

[广告]赞助链接:

四季很好,只要有你,文娱排行榜:https://www.yaopaiming.com/
让资讯触达的更精准有趣:https://www.0xu.cn/

公众号 关注网络尖刀微信公众号
随时掌握互联网精彩
赞助链接