LoginSignup
16
16

More than 5 years have passed since last update.

image-matchの使い方

Posted at

はじめに

image-matchは平たく言えば画像検索エンジンです。
任意の画像を登録し、画像をキーに画像を見つけることができます。Elasticsearchと組み合わせることで非常に高速に画像検索を行うことも可能です。

前提条件

項目 説明
検証日 2016.04.08
OS Mac OS X 10.10.5
Python 2.7.11
Elasticsearch 2.2.1

事前準備

$ brew install py2cairo cairo elasticsearch
$ pip install numpy scipy image_match

使い方

画像比較してみる

image-matchのREADMEの例をやってみます。

first.py
from image_match.goldberg import ImageSignature

gis = ImageSignature()
# a = gis.generate_signature('https://upload.wikimedia.org/wikipedia/commons/thumb/e/ec/Mona_Lisa,_by_Leonardo_da_Vinci,_from_C2RMF_retouched.jpg/687px-Mona_Lisa,_by_Leonardo_da_Vinci,_from_C2RMF_retouched.jpg')
a = gis.generate_signature('687px-Mona_Lisa,_by_Leonardo_da_Vinci,_from_C2RMF_retouched.jpg')
#b = gis.generate_signature('https://pixabay.com/static/uploads/photo/2012/11/28/08/56/mona-lisa-67506_960_720.jpg')
b = gis.generate_signature('mona-lisa-67506_960_720.jpg')

print(gis.normalized_distance(a, b))

c = gis.generate_signature('https://upload.wikimedia.org/wikipedia/commons/e/e0/Caravaggio_-_Cena_in_Emmaus.jpg')
print(gis.normalized_distance(a, c))

d = gis.generate_signature('https://c2.staticflickr.com/8/7158/6814444991_08d82de57e_z.jpg')
print(gis.normalized_distance(a, d))

実行してみます。

$ python first.py
0.220951701409
0.684462753815
0.422527138625

対象画像にURLを指定すると画像を取得して検索することができます。時間が少しかかるので、事前にcurlなどで落として直接ファイルのパスを指定するとよいでしょう。

with Elasticsearch

Elasticsearchと一緒に使ってみましょう。

$ elasticsearch
[2016-04-08 15:18:47,952][INFO ][node                     ] [Alexander Lexington] version[2.2.1], pid[59417], build[d045fc2/2016-03-09T09:38:54Z]
[2016-04-08 15:18:47,952][INFO ][node                     ] [Alexander Lexington] initializing ...
[2016-04-08 15:18:48,945][INFO ][plugins                  ] [Alexander Lexington] modules [lang-expression, lang-groovy], plugins [], sites []
[2016-04-08 15:18:48,998][INFO ][env                      ] [Alexander Lexington] using [1] data paths, mounts [[/ (/dev/disk1)]], net usable_space [69.9gb], net total_space [232.6gb], spins? [unknown], types [hfs]
[2016-04-08 15:18:48,998][INFO ][env                      ] [Alexander Lexington] heap size [990.7mb], compressed ordinary object pointers [true]
[2016-04-08 15:18:48,999][WARN ][env                      ] [Alexander Lexington] max file descriptors [10240] for elasticsearch process likely too low, consider increasing to at least [65536]
[2016-04-08 15:18:52,884][INFO ][node                     ] [Alexander Lexington] initialized
[2016-04-08 15:18:52,884][INFO ][node                     ] [Alexander Lexington] starting ...
[2016-04-08 15:18:53,095][INFO ][transport                ] [Alexander Lexington] publish_address {127.0.0.1:9300}, bound_addresses {[fe80::1]:9300}, {[::1]:9300}, {127.0.0.1:9300}
[2016-04-08 15:18:53,109][INFO ][discovery                ] [Alexander Lexington] elasticsearch_hattori-h/FnX_ySN8RP2my8GcBTZsvw
[2016-04-08 15:18:56,148][INFO ][cluster.service          ] [Alexander Lexington] new_master {Alexander Lexington}{FnX_ySN8RP2my8GcBTZsvw}{127.0.0.1}{127.0.0.1:9300}, reason: zen-disco-join(elected_as_master, [0] joins received)
[2016-04-08 15:18:56,182][INFO ][http                     ] [Alexander Lexington] publish_address {127.0.0.1:9200}, bound_addresses {[fe80::1]:9200}, {[::1]:9200}, {127.0.0.1:9200}
[2016-04-08 15:18:56,182][INFO ][node                     ] [Alexander Lexington] started
[2016-04-08 15:18:56,230][INFO ][gateway                  ] [Alexander Lexington] recovered [0] indices into cluster_state
[2016-04-08 15:34:22,441][INFO ][cluster.metadata         ] [Alexander Lexington] [images] creating index, cause [auto(index api)], templates [], shards [5]/[1], mappings [image]
[2016-04-08 15:34:22,889][INFO ][cluster.routing.allocation] [Alexander Lexington] Cluster health status changed from [RED] to [YELLOW] (reason: [shards started [[images][4]] ...]).
[2016-04-08 15:34:22,998][INFO ][cluster.metadata         ] [Alexander Lexington] [images] update_mapping [image]

Elasticsearchを起動後に、以下のスクリプトを実行します。

first_with_es.py
import json
from elasticsearch import Elasticsearch
from image_match.elasticsearch_driver import SignatureES

es = Elasticsearch()
ses = SignatureES(es)

image_set = (
    'https://upload.wikimedia.org/wikipedia/commons/thumb/e/ec/Mona_Lisa,_by_Leonardo_da_Vinci,_from_C2RMF_retouched.jpg/687px-Mona_Lisa,_by_Leonardo_da_Vinci,_from_C2RMF_retouched.jpg',
    'https://pixabay.com/static/uploads/photo/2012/11/28/08/56/mona-lisa-67506_960_720.jpg',
    'https://upload.wikimedia.org/wikipedia/commons/e/e0/Caravaggio_-_Cena_in_Emmaus.jpg',
    'https://c2.staticflickr.com/8/7158/6814444991_08d82de57e_z.jpg',
)
for img in image_set:
    print("add image to Elasticsearch. img=%s" % img)
    ses.add_image(img)


search_image_set = (
    'https://pixabay.com/static/uploads/photo/2012/11/28/08/56/mona-lisa-67506_960_720.jpg',
    'http://i.imgur.com/CVYBCCy.jpg',
    'http://i.imgur.com/T5AusYd.jpg',
)
for img in search_image_set:
    print("=== search %s ===" % img)
    print(json.dumps(ses.search_image(img, all_orientations=True), indent=2))
$ first_with_es.py
add image to Elasticsearch. img=https://upload.wikimedia.org/wikipedia/commons/thumb/e/ec/Mona_Lisa,_by_Leonardo_da_Vinci,_from_C2RMF_retouched.jpg/687px-Mona_Lisa,_by_Leonardo_da_Vinci,_from_C2RMF_retouched.jpg
add image to Elasticsearch. img=https://pixabay.com/static/uploads/photo/2012/11/28/08/56/mona-lisa-67506_960_720.jpg
add image to Elasticsearch. img=https://upload.wikimedia.org/wikipedia/commons/e/e0/Caravaggio_-_Cena_in_Emmaus.jpg
add image to Elasticsearch. img=https://c2.staticflickr.com/8/7158/6814444991_08d82de57e_z.jpg
=== search https://pixabay.com/static/uploads/photo/2012/11/28/08/56/mona-lisa-67506_960_720.jpg ===
[
  {
    "path": "https://pixabay.com/static/uploads/photo/2012/11/28/08/56/mona-lisa-67506_960_720.jpg",
    "score": 2.435569,
    "dist": 0.0,
    "id": "AVP0lC4XSbcGjA3_XZUG"
  },
  {
    "path": "https://upload.wikimedia.org/wikipedia/commons/thumb/e/ec/Mona_Lisa,_by_Leonardo_da_Vinci,_from_C2RMF_retouched.jpg/687px-Mona_Lisa,_by_Leonardo_da_Vinci,_from_C2RMF_retouched.jpg",
    "score": 0.029808408,
    "dist": 0.22095170140933634,
    "id": "AVP0lCRBSbcGjA3_XZUF"
  },
  {
    "path": "https://c2.staticflickr.com/8/7158/6814444991_08d82de57e_z.jpg",
    "score": 0.004886414,
    "dist": 0.42325822368808808,
    "id": "AVP0lDflSbcGjA3_XZUI"
  }
]
=== search http://i.imgur.com/CVYBCCy.jpg ===
[
  {
    "path": "https://pixabay.com/static/uploads/photo/2012/11/28/08/56/mona-lisa-67506_960_720.jpg",
    "score": 0.20739666,
    "dist": 0.15454905655638429,
    "id": "AVP0lC4XSbcGjA3_XZUG"
  },
  {
    "path": "https://upload.wikimedia.org/wikipedia/commons/thumb/e/ec/Mona_Lisa,_by_Leonardo_da_Vinci,_from_C2RMF_retouched.jpg/687px-Mona_Lisa,_by_Leonardo_da_Vinci,_from_C2RMF_retouched.jpg",
    "score": 0.016346568,
    "dist": 0.24980626832071956,
    "id": "AVP0lCRBSbcGjA3_XZUF"
  },
  {
    "path": "https://c2.staticflickr.com/8/7158/6814444991_08d82de57e_z.jpg",
    "score": 0.0031033582,
    "dist": 0.43156216266051023,
    "id": "AVP0lDflSbcGjA3_XZUI"
  }
]
=== search http://i.imgur.com/T5AusYd.jpg ===
[
  {
    "path": "https://pixabay.com/static/uploads/photo/2012/11/28/08/56/mona-lisa-67506_960_720.jpg",
    "score": 1.5544797,
    "dist": 0.069116439263706961,
    "id": "AVP0lC4XSbcGjA3_XZUG"
  },
  {
    "path": "https://upload.wikimedia.org/wikipedia/commons/thumb/e/ec/Mona_Lisa,_by_Leonardo_da_Vinci,_from_C2RMF_retouched.jpg/687px-Mona_Lisa,_by_Leonardo_da_Vinci,_from_C2RMF_retouched.jpg",
    "score": 0.029808408,
    "dist": 0.22484320805049718,
    "id": "AVP0lCRBSbcGjA3_XZUF"
  },
  {
    "path": "https://c2.staticflickr.com/8/7158/6814444991_08d82de57e_z.jpg",
    "score": 0.004886414,
    "dist": 0.42394015619010844,
    "id": "AVP0lDflSbcGjA3_XZUI"
  }
]

scoreの数値が大きい(distが小さい,近い)ほど似ている画像ということになります。

16
16
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
16
16