*この記事は以前Qiitaで書いたものです。
概要
PythonでImageNetから画像をダウンロードする方法を解説する記事。
ImageNetの画像をダウンロードする方法は2つある。 一つはImageNet経由で一括ダウンロードする方法と、もう一つはImageNetが管理している画像元のURL一覧取得して、そのURLを使って自分でダウンロードする方法である。
前者は、非営利目的の研究/教育目的のみ利用可能。 なのでそれ以外の人は後者の方法をとらなければならない。 今回は後者の方法をPythonを使ってダウンロードする。
ダウンロードに必要な知識と実際のコードをそれぞれ解説していく。
ImageNetとは
- 研究目的で作成された画像のデータベース
- 機械学習の学習データによく使用されている。
- 画像の種類はWordNetで管理 WordNet(Wikipedia)
- ImageNetが画像の著作権を保持しているわけではない。ImageNetは画像元のURLと画像のサムネイルを提供しているだけ。
- 画像数:14,197,122
- バウンディングボックス:1,034,908
WordnetIDとSynsetとは
ImageNetはWordNetという辞書で画像が管理されている。 具体的にはWordNetIDとSynsetという組み合わせで画像の種別を表現している。
例えば、WordNetID 「n02113335」 は、 Synset 「Poodle, poodle dog」 を表現している。
例から分かるように、Synsetは人間が分かる単語で表現され、WordNetIDはその単語と紐付いている番号('n' + 8桁の番号)である。
ImageNetのサイトで画像を探すときはSynsetで検索できる。またSynsetは親(上位概念)と子(下位概念)で構成されている。(「Poodle, poodle dog」の下位概念には「Toy poodle」がいる。)
左のツリーがSynsetの階層構造。 WordNetIDは、右上の黄色いマークを押すと取得できる。
人間に分かりやすいSynsetだけ分かればいいのでは?と思うが、プログラムで画像をダウンロードする際にはWordNetIDでダウンロードしたい種別を選択する必要がある。
ダウンロード方法
プログラムでダウンロードするためにはImageNetが提供しているAPIを使う。APIとはあるURLのことで、このURLにWordNetIDをくっつけてアクセスすると、そのWordNetIDに関する情報が取得できる。 APIにはいろいろな種類がある。
ImageNet API
No. | PageName | URL |
---|---|---|
1 | Synset検索画面のページ | http://www.image-net.org/synset?wnid=*** |
2 | 指定したwnidの下位概念のwnid表示 | http://www.image-net.org/api/text/wordnet.structure.hyponym?wnid=*** |
3 | 指定したwnidの下位概念のwnid表示(最下層まで探索) | http://www.image-net.org/api/text/wordnet.structure.hyponym?wnid=***&full=1 |
4 | 指定したwnidに対応するSynset表示 | http://www.image-net.org/api/text/wordnet.synset.getwords?wnid=*** |
5 | 指定したwnidに対応するファイル名と画像のURL表示 | http://www.image-net.org/api/text/imagenet.synset.geturls.getmapping?wnid=*** |
6 | 指定したwnidに対応する画像のURL表示 | http://www.image-net.org/api/text/imagenet.synset.geturls?wnid=*** |
- 米印にはWordNetIDが入ります。
- wnid = WordNetIDです。
順番に見ていくと、 1は「WordnetIDとSynsetとは」で見た検索画面にジャンプするURL。 2と3は、指定したWordNetIDの下位概念を表示する。2は直下のものしか表示しないが、3は最下層まで表示する。
4は、指定したWordNetIDに対応するSynsetを表示するURL。
5,6は、指定したWordNetIDに属する画像のURL一覧が表示される。5はファイル名も合わせて表示される。
n20113335_17679というのがファイル名になっている。 バウンディングボックスなどはファイル名と紐付いているので、5番のAPIでアクセスするのがいいと思う。
ということで画像ダウンロードに使うのは5番です。 方法としては、 1.Pythonのurllibを使って5番のページに情報取得の要求を出す。 2.ファイル名とURLの一覧が手に入る。 3.取得したURLに対してさらに情報取得の要求を出す。 4.URL先の画像データが手に入る。 5.画像データをファイルに書く。 以下3-5を繰り返す。
コード
以下サンプルコード
1.ファイル名と画像元URLの取得
from urllib import request IMG_LIST_URL="http://www.image-net.org/api/text/imagenet.synset.geturls.getmapping?wnid={}" url = IMG_LIST_URL.format("n02113335") with request.urlopen(url) as response: html = response.read()
URLをurlopen()
で開いて、read()
するだけでページの情報が取得できます。この時点でhtml
には、バイナリ型で以下のような文字列が入っている。
n02113335_17679 http://farm1.static.flickr.com/194/467227983_ce131cca2a.jpg n02113335_4957 http://static.flickr.com/164/388222083_d98ab2ec7e.jpg n02113335_4907 http://www.dkimages.com/discover/previews/919/65004609.JPG n02113335_4943 http://farm1.static.flickr.com/82/225053708_e1b941261a.jpg n02113335_4942 http://farm1.static.flickr.com/17/19821754_6cb866105a.jpg n02113335_4935 http://farm3.static.flickr.com/2397/2132261952_28dd898274.jpg ・ ・ ・
文字列として扱いたいのでdecodeする。(バイナリ型->文字列型)
data = html.decode()
あとはこれを1列目と2列目に分割すればファイル名と画像元のURLが取得できる。 例えば以下のようにする。
data = data.split() # data = [fname_0, url_0, fname_1, url_1, .....] fnames = data[::2] urls = data[1::2]
2.画像の取得
先ほど取得した1枚目のURLを使って、1と同様にアクセスする。
url="http://farm1.static.flickr.com/194/467227983_ce131cca2a.jpg" with request.urlopen(url) as response: img = response.read()
このときimgにバイナリ形式の画像データが入っている。 画像なので、以下のようにそのままバイナリ形式でファイルに書けばダウンロード完了。
with open('n02113335_17679.jpg', 'wb') as f: f.write(img)
ImageNet_Downloader
ここまで紹介したImageNetAPIのラッパークラスを書いてみた。中身の処理は先ほど説明したことがメインなので割愛。以下、クラスの簡単な使い方。
import downloader import os root_dir = os.getcwd() wnid = "n02113335" api = downloader.ImageNet(root_dir) api.download(wnid, verbose=True)
downloadでwnidを設定すると、そのwnidの画像をダウンロードし始める。以下のフォルダを作成して順次ダウンロードしていく。n02113335.txtは、ファイル名と画像のURLが書いてあるテキストファイル。
root/ ├ img/ │ └ n02113335/ │ └ n02113335_xxx.jpg │ └ n02113335_xxx.jpg │ └ .... ├ list/ │ └ n02113335.txt
example.py
を使うと簡単にダウンロードできる。
python example.py <WordnetID> -v
下位層も含めてダウンロードしたい場合は-r
をつける。
python example.py <WordnetID> -v -r
ダウンロードする枚数を指定した場合は、-limit <num>
を指定する。
python example.py <WordnetID> -v -r -limit 100
まとめ
Pythonのurllibを使うと簡単にネット上の画像をダウンロードできる。