ProcessingからPythonを実行したかった話
先日、とある機械学習をするのに画像データがある程度必要になったので、何か適当に画像を抜き取ってくる方法はないものかと探していました。
まぁ勝手にGo○gleさんの画像検索をスクレイピングして抜き出せばいいかなとか思っていたのだけれど、どうも規約違反らしいとのこと。 かと言って、他の画像検索サイトもおそらくグレーゾーンだろうと思ったので、それ用のAPI系を調べて見たけどどれも微妙……。
とりあえず今回はそれほど画像枚数はいらないのと、クエリに対して画像が返ってくるものがよかったので、G○ogleのcustom search apiを無料版で使ってみることに。
#! /usr/bin/python # -*- coding:utf-8 -*- import urllib import json import re import requests import os import sys def get_imageurl(): query = sys.argv[1] print(query) id = ID api_key = API_KEY page_to = 6 from_url = 'https://www.googleapis.com/customsearch/v1?' params = { 'key': api_key, 'q':query, 'cx':id, 'searchType':'image', 'alt':'json', 'lr' :'lang_ja', } start = 1 f = open('imageURL.txt','w') for i in range(0, page_to): params['start'] = start req_url = from_url + urllib.urlencode(params) res = urllib.urlopen(req_url) dump = json.loads(res.read()) for j in range(len(dump["items"])): f.write(dump["items"][j]["link"] + "\n") if not dump['queries'].has_key('nextPage'): break start = int(dump['queries']['nextPage'][0]['startIndex']) f.close() def download_image(url, timeout = 10): response = requests.get(url, allow_redirects=False, timeout=timeout) if response.status_code != 200: e = Exception("HTTP status: " + response.status_code) raise e content_type = response.headers["content-type"] if 'image' not in content_type: e = Exception("Content-Type: " + content_type) raise e return response.content def make_filename(base_dir, number, url): ext = ".png" filename = "%s%s"%(number, ext) fullpath = os.path.join(base_dir, filename) return fullpath def save_image(filename, image): with open(filename, "wb") as fout: fout.write(image) if __name__ == "__main__": get_imageurl() urls_txt = "imageURL.txt" query_dir = sys.argv[1] images_dir = "colorImageData/%s"%query_dir idx = 0 abs_path = os.path.dirname(os.path.abspath(__file__)) dir_path = "%s/%s"%(abs_path, images_dir) os.mkdir(dir_path) with open(urls_txt, "r") as fin: for line in fin: url = line.strip() filename = make_filename(dir_path, idx, url) print "%s" % (url) try: image = download_image(url) save_image(filename, image) idx += 1 except KeyboardInterrupt: break except Exception as err: print "%s" % (err)
日頃Pythonを書かないので、見よう見まねで色々書いてみて、なんとか画像を取得できるようになった。
使い方はターミナルとかで、
python getImageData.py [query]
[query]の部分に検索したい画像のクエリを入れて実行する感じ。
取得するページ数を指定する変数がこれ。
page_to = [page]
今回は1クエリあたり50枚の画像を使いたい。 実行すると1ページあたり10枚の画像を取得してるっぽいけど、取得できない画像もあるので、多めに回しておいて、必要数を満たす戦法。
全体の動きとしては
1. APIを使って、
[query]
で画像検索をした結果をJSON形式で取得2. JSONから画像のURL部分を抜き取って、
imageURL.txt
に書き込み3. 書き込んだURLから画像を取得して、
colorImageData
フォルダに保存
という感じ。
なんとも回りくどい感じになりましたが、まあ仕方ない。日頃Python書いてない人だから(言い訳) それに、ここまでは下準備ですから……。
では、このPythonのコードをProcessingで実行していきます。
ちなみに、"Processing Python" とかで検索すると、ProcessingのPython Modeについての記事がたくさん出てきて、そうじゃない……といった感じに。
また、Processingでは外部アプリケーションを実行できるlaunch()
という命令があるようですが、これだと[query]
を入力できないので、今回は使えそうにない……。
そこで今回は、ProcessBuilderというのを使っていきます。
import java.io.IOException; void pythonExec() { try { ProcessBuilder builder = new ProcessBuilder("python", sketchPath()+"/python/getImageData.py", [query]); Process process = builder.start(); int exitCode = process.waitFor(); if (exitCode==0) { process.destroy(); } } catch (IOException e) { e.printStackTrace(); } catch(InterruptedException ex) { ex.printStackTrace(); } }
はい、見ての通りjavaです。
このようにProcessBuilder
を使うと、ターミナルでの入力形式に乗っ取って、Pythonを実行することができるようになり、[query]
をパラメータとして設定できます。
あとはそのプロセスを実行して、waitFor()
で終了判定を行い、プロセスを閉じるだけ。
この感じだと、他のターミナル上のコマンドも実行できそうで、いろいろ活用できそうですね!