Published Date : 2019年11月5日11:15

PythonとPexels APIを使用した画像の収集
Collecting images using Python and the Pexels API


This blog has an English translation



画像認識シリーズ第2弾です。前回のブログ記事。

This is the second image recognition series. Last blog post.


最初に何をするか説明すると、まず人とは関係のない生き物の画像をPythonとPexels APIを使って集めていきます。 次に、Tensorflowを使って画像の特徴を学習し、分類モデルを作成する。 最後に、人の顔の画像を分類器に入れたとき、どのよう結果になるかを実験する。 以上です。

I'll explain what I'm going to do. First, I'll use Python and Pexels API to collect images of creatures that have nothing to do with people. Next, I use Tensorflow to learn image features and create a classification model. Finally, I do an experiment what will happen when I put an image of a person's fase into the classifier.


この手のものはやり尽くされていますが、ただ一から全部やってみたかった。それだけです。 つーことでお次はPythonとPexels APIを利用して画像を集めていきます。

This kind of thing is done by many people, but I just wanted to do it all from scratch. That's all. The next step is to use Python and the Pexels API to collect images.



目次

Table of Contents



概要
Overview


取り敢えず人と関係の無い画像を集める。 具体的には犬、猫、猿、鳥、魚、トカゲ。 一つの種類に付き大体200枚。

First of all, I collect images that are not related to people. Dogs, Cats, Monkeys, birds, Fish, and Lizards. About 200 sheets per kind.



集めるのに使うサイトはフリー素材が揃う「Pexels」。 そのAPIを使用してPythonで画像を収集する。

The site I'm using to collect the images is Pexels, a free image material site. The image acquisition method uses the API provided by the [Pexels] to collect images in Python.



APIの制限として、1時間ごとに200リクエストまで。 一ヶ月で20000リクエストまでです。

The API has a limit of 200 requests per 1 hour. Another API limitation is 20,000 requests per month.




PythonとPexels API
Python and the Pexels API



前回のブログ記事では、PexelsのAPIを利用できるようにしたあと、簡単なPythonスクリプトを実行しました。

In a previous blog post, I used the Pexels API to run a simple Python script.



それでは前回リクエストしたJSONファイルの中身を見ながら、画像収集用のスクリプトを完成させていきましょい

Let's complete the image collection script by looking at the contents of the JSON file you requested last time.



前回のおさらい、以下のPython Scriptを実行すると、以下の結果が得られる。

In the last blog post, I ran the following Python script and generated the following results.

working folder
working folder
    --- collector.py
collector.py
# Import API class from pexels_api package
from pexels_api import API
# Type your Pexels API
PEXELS_API_KEY = 'YOUR-PEXELS-API-KEY'
# Create API object
api = API(PEXELS_API_KEY)
# Search one 'kitten' photos
api.search('kitten', page=1, results_per_page=1)
results
{'total_results': 1844,
'page': 1,
'per_page': 1,
'photos': [{'id': 416160,
  'width': 3888,
  'height': 2592,
  'url': 'https://www.pexels.com/photo/animal-cat-face-close-up-feline-416160/',
  'photographer': 'Pixabay',
  'photographer_url': 'https://www.pexels.com/@pixabay',
  'photographer_id': 2659,
  'src': {'original': 'https://images.pexels.com/photos/416160/pexels-photo-416160.jpeg',
    'large2x': 'https://images.pexels.com/photos/416160/pexels-photo-416160.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=650&w=940',
    'large': 'https://images.pexels.com/photos/416160/pexels-photo-416160.jpeg?auto=compress&cs=tinysrgb&h=650&w=940',
    'medium': 'https://images.pexels.com/photos/416160/pexels-photo-416160.jpeg?auto=compress&cs=tinysrgb&h=350',
    'small': 'https://images.pexels.com/photos/416160/pexels-photo-416160.jpeg?auto=compress&cs=tinysrgb&h=130',
    'portrait': 'https://images.pexels.com/photos/416160/pexels-photo-416160.jpeg?auto=compress&cs=tinysrgb&fit=crop&h=1200&w=800',
    'landscape': 'https://images.pexels.com/photos/416160/pexels-photo-416160.jpeg?auto=compress&cs=tinysrgb&fit=crop&h=627&w=1200',
    'tiny': 'https://images.pexels.com/photos/416160/pexels-photo-416160.jpeg?auto=compress&cs=tinysrgb&dpr=1&fit=crop&h=200&w=280'},
  'liked': False}],
'next_page': 'https://api.pexels.com/v1/search/?page=2&per_page=1&query=kitten'}

つまり、'子猫'で検索したら'全ての結果'として、1844枚の画像があり、 '枚数'は一枚を指定したので、'横幅': 3888,'高さ': 2592,の画像URL'https://www.pexels.com/photo/animal-cat-face-close-up-feline-416160/'が得られましたと。

In other words, when you searched 'kitten', there were 1844 images in 'total_results'. In addition, since you specified only 1 image in 'results_per_page', you got only one image information of the image URL 'https://www.pexels.com/photo/animal-cat-face-close-up-feline-416160/' with 'width':3888, 'hight':2529.

やるべきことは、画像を300枚程度取得(後の画像選別の為に余裕を持って取得する)するために、 results_per_pageの数を増やすだけ。

In other words, All you have to do is increase the number of 'result_per_page' to get about 300 images. (A large number of images need to be acquired to select an image that is available later.)

しかし、あまりにも画像サイズがデカすぎると実際のTensorFlowの計算時に負荷が大きくなってしまうので、'medium'の画像URLを選択して、ダウンロードしていきます。

However, if the image size is too large, It's going to take a lot of the actual computation, so select the 'medium' image URL and download it.

詳しいAPIのDocumentationは公式のページを参考にしてくだちぃ。Read the documentation

For more information on the API documentation, please refer to the official page. Read the documentation




画像収集と選別
Image acquisition and selecting



それでは画像収集をするためにPythonスクリプトを書いていきます。

I'll write a Python script to do the image collection.

from pexels_api import API
import os
import urllib.request
import time

PEXELS_API_KEY = 'YOUR-PEXELS-API-KEY'

api = API(PEXELS_API_KEY)

headers = {
    "User-Agent": "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:47.0) Gecko/20100101 Firefox/47.0"
    }

creatures_list = ['cat','dog','bird','monkey','fish','lizard']
dir_names = ['cats','dogs','birds','monkeys','fish','lizards']

for idx, name in enumerate(creatures_list):
    api.search(name)

    print("Total results: ", api.total_results)

    dir_name = dirs[idx]

    if not os.path.exists(dir_name):
        os.mkdir(dir_name)

    total = 0
    while True:
        if total >= 300:
            print('next')
            break
        
        photos = api.get_entries()

        for photo in photos:

            file_name = f'{dir_name}/{total+1:03d}.jpg'

            res = urllib.request.Request(photo.medium, headers=headers)
            img = urllib.request.urlopen(res).read()
            
            try:
                with open(file_name, mode="wb") as f:
                    f.write(img)
            except PermissionError:
                print(f'Permission denied. The image of {total+1:03d} could not be saved.')
            
            total += 1

            if total >= 195:
                time.sleep(60 * 60)
            if total >= 300:
                time.sleep(60 * 60)
                break

        api.search_next_page()


URLから画像をダウンロードをした際、Permission Deniedになるのを防ぐために、Fire Foxを演じるようにする。

When you download an image from a URL, you may get Permission Denied. To prevent that, configure the user-agent.

headers = {
  "User-Agent": "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:47.0) Gecko/20100101 Firefox/47.0"
}

urllib.request.Requestとurllib.request.urlopenを使って一枚毎に画像をダウンロードする。

Download images one by one using urllib.request.Request and urllib.request.urlopen.

その際に、たま〜に画像をダウンロードできないよと、例外が発生するので、無視して次の処理へ進める。

At that time, an execption occurs the image cannot be downloaded sometimes, so ignore it and proceed to the next processing.


res = urllib.request.Request(photo.medium, headers=headers)
img = urllib.request.urlopen(res).read()

try:
    with open(file_name, mode="wb") as f:
        f.write(img)
except PermissionError:
    print(f'Permission denied. The image of {total+1:03d} could not be saved.')

API制限ごとに1時間の待機時間を指定する。大分時間がかかる。 一度無視して試したが、やはり制限がかかって無理だったので、仕方なしにこの方法を採用。

Specify one hour wait for each API limit. This takes a long time. I tried to ignore it once and proceed with the loop. But I couldn't download the image because of API restriction. So I had no choice but to adopt this method.


if total >= 195:
    time.sleep(60 * 60)
if total >= 300:
    time.sleep(60 * 60)
    break

デフォルトの設定だと、1ページあたり15枚の画像を取得するので、15枚ダウンロードしたらページ送りをして、画像を更新させる。さもないと同じ画像を15枚づつ取得するはめになる。

The default setting is to take 15 images per page, so once you've downloaded 15 images, you should be page through them to upadate them. Otherwise, you will get 15 dublicate images each time.

api.search_next_page()



Responsive image

画像を収集できたら、続いて必要な画像と不必要な画像を選別していきます。

Once you've collected the images, you'll need to sort out the ones you need and the ones you don't.

具体的には一匹だけ写っているもの、はっきりと顔が判別できるものに分けていきます。

To be more specific, we divide them into those in which only one creatures is in the picture and those in which the face can be clearly identified.


Responsive image

例えばこの中だと004.jpg 005.jpg 006.jpgを省きます。

For example, 004.jpg 005.jpg 006.jpg is deleted.

できるだけ正面を向いていて、顔が半分になっていないものが良いかと。この辺は各自の裁量で行ってくだちぃ。

As much as possible, the one with face of the living things facing the front is suitable. The one with only half face is also not suitable. However, this work of sorting should be done at your discretion.

これは可愛いけど、駄目な例っすね。

This is a cute image, but bad example.


Responsive image



それでは次回、画像分類器を作っていきましょう。

Next time, let's make an image classifier model.





See You Next Page!