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

来源:AI科技大本营 / 作者:zz / 2018-04-14 22:01
在本文中,作者将利用微软的 Bing Image Search API 来建立深度学习图像数据集。Bing Image Search API 是微软 Cognitive Services 的一个组成部分,主要是帮助用户在视觉、语言


 

在本文中,作者将利用微软的 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),开始我们的注册流程:

 

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

 

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



此时可以看到我的页面中 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” 视图下,浏览所有图片文件即可。

 

如果我发现了任何与关键字不相关的图片,只需要在键盘上按 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 还是非常好用的。

 

另外,在实际操作中还应该剔除下载重复的图片,在这里,我没有做这个步骤是因为在剔除不相关图片时,我没有发现太多的重复(除了小火龙的图片,不知道为什么会有那么多重复)

 

结语

 

本文讲解了如何利用 Microsoft’s Bing Image Search API 来快速建立我们自己的深度学习图像数据集。我们学习了通过使用 API 来自动下载图片,这比使用 Google Image 时需要手动下载每一张图片更为方便。如果你想按照本文所讲述的知识实际操作一下的话,你可以选择 Bing Image Search API ,另外它将提供 30 天的免费试用期。
 

阅读延展

1
3