deepselect 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +11 -0
- data/.rspec +3 -0
- data/.travis.yml +5 -0
- data/CODE_OF_CONDUCT.md +74 -0
- data/Gemfile +9 -0
- data/Gemfile.lock +41 -0
- data/LICENSE.txt +21 -0
- data/README.md +78 -0
- data/Rakefile +6 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/deepselect.gemspec +30 -0
- data/example/images/image_komeda.jpg +0 -0
- data/example/images/image_starbucks.png +0 -0
- data/example/images/image_starbucks2.jpg +0 -0
- data/example/images/image_tully's.png +0 -0
- data/example/images/logo_doutor.jpg +0 -0
- data/example/images/logo_komeda.jpeg +0 -0
- data/example/images/logo_starbucks.png +0 -0
- data/example/images/logo_stmarc.png +0 -0
- data/example/images/logo_tully's.jpg +0 -0
- data/example/images/photo_komeda.jpg +0 -0
- data/example/images/photo_starbucks.jpg +0 -0
- data/example/images/photo_starbucks2.png +0 -0
- data/example/images/photo_stmarc.jpg +0 -0
- data/example/logo_recog.rb +63 -0
- data/lib/deepselect.rb +219 -0
- data/lib/deepselect/version.rb +3 -0
- metadata +143 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: d5f0760ebb6453fe873c7e877d6d9d9f3fb67035
|
4
|
+
data.tar.gz: 8df66a009ae50c0772418131fa54ff03d785860b
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 85cc991ef30d71742cb814d7740f76516cb60cf6769d521ad43d057d32b535a843343661defa3deeada18cf8a375148920edc91208680b272276effbe76971fd
|
7
|
+
data.tar.gz: d628a878eb00f590ce03bce17d9f82ba954722652501c858f4053c087f419ed61bcc5504b621fa175d4a9b49ba1840b936e7835364b81af28021d9865ad5cdf0
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/.travis.yml
ADDED
data/CODE_OF_CONDUCT.md
ADDED
@@ -0,0 +1,74 @@
|
|
1
|
+
# Contributor Covenant Code of Conduct
|
2
|
+
|
3
|
+
## Our Pledge
|
4
|
+
|
5
|
+
In the interest of fostering an open and welcoming environment, we as
|
6
|
+
contributors and maintainers pledge to making participation in our project and
|
7
|
+
our community a harassment-free experience for everyone, regardless of age, body
|
8
|
+
size, disability, ethnicity, gender identity and expression, level of experience,
|
9
|
+
nationality, personal appearance, race, religion, or sexual identity and
|
10
|
+
orientation.
|
11
|
+
|
12
|
+
## Our Standards
|
13
|
+
|
14
|
+
Examples of behavior that contributes to creating a positive environment
|
15
|
+
include:
|
16
|
+
|
17
|
+
* Using welcoming and inclusive language
|
18
|
+
* Being respectful of differing viewpoints and experiences
|
19
|
+
* Gracefully accepting constructive criticism
|
20
|
+
* Focusing on what is best for the community
|
21
|
+
* Showing empathy towards other community members
|
22
|
+
|
23
|
+
Examples of unacceptable behavior by participants include:
|
24
|
+
|
25
|
+
* The use of sexualized language or imagery and unwelcome sexual attention or
|
26
|
+
advances
|
27
|
+
* Trolling, insulting/derogatory comments, and personal or political attacks
|
28
|
+
* Public or private harassment
|
29
|
+
* Publishing others' private information, such as a physical or electronic
|
30
|
+
address, without explicit permission
|
31
|
+
* Other conduct which could reasonably be considered inappropriate in a
|
32
|
+
professional setting
|
33
|
+
|
34
|
+
## Our Responsibilities
|
35
|
+
|
36
|
+
Project maintainers are responsible for clarifying the standards of acceptable
|
37
|
+
behavior and are expected to take appropriate and fair corrective action in
|
38
|
+
response to any instances of unacceptable behavior.
|
39
|
+
|
40
|
+
Project maintainers have the right and responsibility to remove, edit, or
|
41
|
+
reject comments, commits, code, wiki edits, issues, and other contributions
|
42
|
+
that are not aligned to this Code of Conduct, or to ban temporarily or
|
43
|
+
permanently any contributor for other behaviors that they deem inappropriate,
|
44
|
+
threatening, offensive, or harmful.
|
45
|
+
|
46
|
+
## Scope
|
47
|
+
|
48
|
+
This Code of Conduct applies both within project spaces and in public spaces
|
49
|
+
when an individual is representing the project or its community. Examples of
|
50
|
+
representing a project or community include using an official project e-mail
|
51
|
+
address, posting via an official social media account, or acting as an appointed
|
52
|
+
representative at an online or offline event. Representation of a project may be
|
53
|
+
further defined and clarified by project maintainers.
|
54
|
+
|
55
|
+
## Enforcement
|
56
|
+
|
57
|
+
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
58
|
+
reported by contacting the project team at 7zip.deadlock@gmail.com. All
|
59
|
+
complaints will be reviewed and investigated and will result in a response that
|
60
|
+
is deemed necessary and appropriate to the circumstances. The project team is
|
61
|
+
obligated to maintain confidentiality with regard to the reporter of an incident.
|
62
|
+
Further details of specific enforcement policies may be posted separately.
|
63
|
+
|
64
|
+
Project maintainers who do not follow or enforce the Code of Conduct in good
|
65
|
+
faith may face temporary or permanent repercussions as determined by other
|
66
|
+
members of the project's leadership.
|
67
|
+
|
68
|
+
## Attribution
|
69
|
+
|
70
|
+
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
|
71
|
+
available at [http://contributor-covenant.org/version/1/4][version]
|
72
|
+
|
73
|
+
[homepage]: http://contributor-covenant.org
|
74
|
+
[version]: http://contributor-covenant.org/version/1/4/
|
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,41 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
deepselect (0.0.1)
|
5
|
+
menoh
|
6
|
+
rmagick
|
7
|
+
|
8
|
+
GEM
|
9
|
+
remote: https://rubygems.org/
|
10
|
+
specs:
|
11
|
+
diff-lcs (1.3)
|
12
|
+
menoh (1.0.0)
|
13
|
+
rake (10.5.0)
|
14
|
+
rmagick (2.16.0)
|
15
|
+
rspec (3.7.0)
|
16
|
+
rspec-core (~> 3.7.0)
|
17
|
+
rspec-expectations (~> 3.7.0)
|
18
|
+
rspec-mocks (~> 3.7.0)
|
19
|
+
rspec-core (3.7.1)
|
20
|
+
rspec-support (~> 3.7.0)
|
21
|
+
rspec-expectations (3.7.0)
|
22
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
23
|
+
rspec-support (~> 3.7.0)
|
24
|
+
rspec-mocks (3.7.0)
|
25
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
26
|
+
rspec-support (~> 3.7.0)
|
27
|
+
rspec-support (3.7.1)
|
28
|
+
|
29
|
+
PLATFORMS
|
30
|
+
ruby
|
31
|
+
|
32
|
+
DEPENDENCIES
|
33
|
+
bundler (~> 1.16)
|
34
|
+
deepselect!
|
35
|
+
menoh (~> 1.0)
|
36
|
+
rake (~> 10.0)
|
37
|
+
rmagick (~> 2.16)
|
38
|
+
rspec (~> 3.0)
|
39
|
+
|
40
|
+
BUNDLED WITH
|
41
|
+
1.16.1
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2018 7rpn
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,78 @@
|
|
1
|
+
# Deepselect
|
2
|
+
### Features
|
3
|
+
deepselect is a Ruby image recognition library using DeepLearning.
|
4
|
+
This library makes it easy to search for images.
|
5
|
+
|
6
|
+
deepselectはDeepLearningを使ったRubyの画像認識ライブラリです。
|
7
|
+
簡単に画像検索ができます。
|
8
|
+
|
9
|
+
## Installation
|
10
|
+
install the gem:
|
11
|
+
```
|
12
|
+
gem install deepselect
|
13
|
+
```
|
14
|
+
|
15
|
+
## Synopsis
|
16
|
+
|
17
|
+
```Ruby
|
18
|
+
require 'rmagick'
|
19
|
+
require "deepselect"
|
20
|
+
|
21
|
+
# 5 coffeeshop logo images (famous in Japan)
|
22
|
+
image_list = [
|
23
|
+
"logo_doutor.jpg", "logo_stmarc.png",
|
24
|
+
"logo_komeda.jpeg", "logo_starbucks.png",
|
25
|
+
"logo_tully's.jpg"
|
26
|
+
]
|
27
|
+
|
28
|
+
# Read Image
|
29
|
+
images = image_list.map do |name|
|
30
|
+
image_dir = "./images/"+name
|
31
|
+
image = Magick::Image.read(image_dir).first
|
32
|
+
end
|
33
|
+
|
34
|
+
# Read another Starbucks Image
|
35
|
+
starbucks_image = Magick::Image.read("./images/image_starbucks.png").first
|
36
|
+
puts "input: #{"./images/image_starbucks.png"} " # => ".images/image_starbucks.png"
|
37
|
+
|
38
|
+
# Search the array for the image most similar to the given image
|
39
|
+
selected_image = images.dselect{|dimage| dimage == starbucks_image}
|
40
|
+
puts "most similar image: #{selected_image.filename}" # => ".images/logo_starbucks.png"
|
41
|
+
```
|
42
|
+
|
43
|
+
## Options
|
44
|
+
```
|
45
|
+
images.dselect(take: "deafult", with: "") &block
|
46
|
+
```
|
47
|
+
#### args
|
48
|
+
* `take:` Specify how many of the most similar images to retrieve.
|
49
|
+
Interger 1,2,3... or String "all" are accepted.
|
50
|
+
* `with:` Specify whether to output similarity and index.
|
51
|
+
String are accepted. (ex. "similarity, index" )
|
52
|
+
|
53
|
+
As an example, when outputting two images with similarity:
|
54
|
+
``` Ruby
|
55
|
+
stmark_photo_image = Magick::Image.read("./images/photo_stmarc.jpg").first
|
56
|
+
selected_image = images.dselect(take: 2, with: "similarity"){|dimage| dimage == stmark_photo_image}
|
57
|
+
p selected_image
|
58
|
+
```
|
59
|
+
|
60
|
+
#### Cache
|
61
|
+
By caching feature vectors, the speed of the second search is faster than that of the first search.<br>
|
62
|
+
If you want to pre-store the feature vectors, use the dinit method.
|
63
|
+
```ruby
|
64
|
+
images.dinit # calc feature vector
|
65
|
+
|
66
|
+
selected_image = images.dselect{|dimage| dimage == compare_image}
|
67
|
+
```
|
68
|
+
|
69
|
+
## Requirements
|
70
|
+
**deepselect requires installation of Menoh and imagemagick.**<br>
|
71
|
+
Please check [the page of github Menoh](https://github.com/pfnet-research/menoh) for installation Menoh.
|
72
|
+
|
73
|
+
## License
|
74
|
+
deepselect is MIT license.
|
75
|
+
|
76
|
+
Note: Thankfully data/VGG16.onnx is download from 'https://www.dropbox.com/s/bjfn9kehukpbmcm/VGG16.onnx?dl=1'.<br>
|
77
|
+
That model is generated by onnx-chainer from pre-trained model which is uploaded at http://www.robots.ox.ac.uk/%7Evgg/software/very_deep/caffe/VGG_ILSVRC_16_layers.caffemodel<br>
|
78
|
+
That pre-trained model is released under Creative Commons Attribution License.
|
data/Rakefile
ADDED
data/bin/console
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "bundler/setup"
|
4
|
+
require "deepselect"
|
5
|
+
|
6
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
7
|
+
# with your gem easier. You can also use a different console, if you like.
|
8
|
+
|
9
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
10
|
+
# require "pry"
|
11
|
+
# Pry.start
|
12
|
+
|
13
|
+
require "irb"
|
14
|
+
IRB.start(__FILE__)
|
data/bin/setup
ADDED
data/deepselect.gemspec
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
|
2
|
+
lib = File.expand_path("../lib", __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require "deepselect/version"
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "deepselect"
|
8
|
+
spec.version = Deepselect::VERSION
|
9
|
+
spec.authors = ["7rpn"]
|
10
|
+
spec.email = ["7rpn.deadlock@gmail.com"]
|
11
|
+
|
12
|
+
spec.summary = %q{Image recognition library for Ruby}
|
13
|
+
spec.description = %q{Provides a method to retrieve the image most similar to the specified image from the array.}
|
14
|
+
spec.homepage = "https://github.com/7rpn/deepselect"
|
15
|
+
spec.license = "MIT"
|
16
|
+
|
17
|
+
spec.files = `git ls-files -z`.split("\x0").reject do |f|
|
18
|
+
f.match(%r{^(test|spec|features)/})
|
19
|
+
end
|
20
|
+
spec.bindir = "exe"
|
21
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
22
|
+
spec.require_paths = ["lib"]
|
23
|
+
|
24
|
+
spec.add_runtime_dependency "menoh"
|
25
|
+
spec.add_runtime_dependency "rmagick"
|
26
|
+
|
27
|
+
spec.add_development_dependency "bundler", "~> 1.16"
|
28
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
29
|
+
spec.add_development_dependency "rspec", "~> 3.0"
|
30
|
+
end
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
@@ -0,0 +1,63 @@
|
|
1
|
+
require 'open-uri'
|
2
|
+
require 'rmagick'
|
3
|
+
require 'menoh'
|
4
|
+
|
5
|
+
require "deepselect"
|
6
|
+
|
7
|
+
# ありがちな喫茶店ロゴ画像5つ
|
8
|
+
name_list = [
|
9
|
+
"logo_doutor.jpg", "logo_stmarc.png",
|
10
|
+
"logo_komeda.jpeg", "logo_starbucks.png",
|
11
|
+
"logo_tully's.jpg"
|
12
|
+
]
|
13
|
+
|
14
|
+
# 全部Magick::Imageとして読み込んでimages配列にぶちこむ
|
15
|
+
images = name_list.map do |name|
|
16
|
+
image_dir = "./images/"+name
|
17
|
+
image = Magick::Image.read(image_dir).first
|
18
|
+
end
|
19
|
+
|
20
|
+
# スターバックスの画像を読み込む
|
21
|
+
starbucks_image = Magick::Image.read("./images/image_starbucks.png").first
|
22
|
+
puts "input: #{"./images/image_starbucks.png"} "
|
23
|
+
|
24
|
+
# 配列の中から一番近い画像を取り出す
|
25
|
+
selected_image = images.dselect{|dimage| dimage == starbucks_image}
|
26
|
+
puts "output: #{selected_image.filename}" # => ./images/logo_starbucks.png
|
27
|
+
|
28
|
+
|
29
|
+
# スターバックスの画像もうひとつ
|
30
|
+
starbucks_image = Magick::Image.read("./images/image_starbucks2.jpg").first
|
31
|
+
selected_image = images.dselect{|dimage| dimage == starbucks_image}
|
32
|
+
puts selected_image.filename # => ./images/logo_starbucks.png
|
33
|
+
|
34
|
+
# コメダもやってみる
|
35
|
+
komeda_image = Magick::Image.read("./images/image_komeda.jpg").first
|
36
|
+
selected_image = images.dselect{|dimage| dimage == komeda_image}
|
37
|
+
puts selected_image.filename
|
38
|
+
|
39
|
+
# タリーズも
|
40
|
+
tullys_image = Magick::Image.read("./images/image_tully's.png").first
|
41
|
+
selected_image = images.dselect{|dimage| dimage == tullys_image}
|
42
|
+
puts selected_image.filename
|
43
|
+
|
44
|
+
|
45
|
+
# コメダの写真だったら...?
|
46
|
+
komeda_photo_image = Magick::Image.read("./images/photo_komeda.jpg").first
|
47
|
+
selected_image = images.dselect{|dimage| dimage == komeda_photo_image}
|
48
|
+
puts selected_image.filename
|
49
|
+
|
50
|
+
# スタバの写真,失敗する
|
51
|
+
starbucks_photo_image = Magick::Image.read("./images/photo_starbucks.jpg").first
|
52
|
+
selected_image = images.dselect{|dimage| dimage == starbucks_photo_image}
|
53
|
+
puts selected_image.filename
|
54
|
+
|
55
|
+
# スタバの写真,ここまで寄せれば成功
|
56
|
+
starbucks_photo_image2 = Magick::Image.read("./images/photo_starbucks2.png").first
|
57
|
+
selected_image = images.dselect{|dimage| dimage == starbucks_photo_image2}
|
58
|
+
puts selected_image.filename
|
59
|
+
|
60
|
+
# サンマルクの写真
|
61
|
+
stmark_photo_image = Magick::Image.read("./images/photo_stmarc.jpg").first
|
62
|
+
selected_image = images.dselect(take: 2, with: "similarity, index"){|dimage| dimage == stmark_photo_image}
|
63
|
+
p selected_image
|
data/lib/deepselect.rb
ADDED
@@ -0,0 +1,219 @@
|
|
1
|
+
require_relative "deepselect/version"
|
2
|
+
require 'rmagick'
|
3
|
+
require 'menoh'
|
4
|
+
|
5
|
+
require 'matrix'
|
6
|
+
require 'open-uri'
|
7
|
+
require 'fileutils'
|
8
|
+
|
9
|
+
class DSelect
|
10
|
+
@@vgg16_obj = nil
|
11
|
+
# self使いすぎではないでしょうか...? pythonかな?
|
12
|
+
# いずれselfを使わない形で書き直すか諦めてclass << selfする
|
13
|
+
|
14
|
+
# image同士を比較して特徴量出す
|
15
|
+
def self.compare(f1, f2)
|
16
|
+
# 引数がRmagick imageならfeature vectorへ変換
|
17
|
+
if f1.class == Magick::Image and f2.class == Magick::Image
|
18
|
+
f1,f2 = f1.to_vector, f2.to_vector # さすがに他のライブラリと被りそうな気が
|
19
|
+
end
|
20
|
+
|
21
|
+
# cos similarity
|
22
|
+
v1 = Vector.elements(f1)
|
23
|
+
v2 = Vector.elements(f2)
|
24
|
+
return v2.inner_product(v1)/(v1.norm() * v2.norm())
|
25
|
+
end
|
26
|
+
|
27
|
+
# vgg16返す
|
28
|
+
def self.vgg16
|
29
|
+
# 読み込み済みなら読み込んであるモデルを返す
|
30
|
+
return @@vgg16_obj if @@vgg16_obj
|
31
|
+
|
32
|
+
vgg16_dir = File.expand_path('./deepselect/data/VGG16.onnx', __dir__)
|
33
|
+
if File.exist?(vgg16_dir)
|
34
|
+
@@vgg16_obj = Menoh::Menoh.new(vgg16_dir)
|
35
|
+
else
|
36
|
+
# menohと同じようにモデルをダウンロードする
|
37
|
+
# url勝手に使うのダメだったら教えてください...!
|
38
|
+
model_parent_dir = File.expand_path('./deepselect/data', __dir__)
|
39
|
+
FileUtils.mkdir(model_parent_dir) unless File.exist?(model_parent_dir)
|
40
|
+
puts "model data downloading... (first time only)"
|
41
|
+
url = 'https://www.dropbox.com/s/bjfn9kehukpbmcm/VGG16.onnx?dl=1'
|
42
|
+
open(url) do |file|
|
43
|
+
File.open(vgg16_dir, "wb") do |out|
|
44
|
+
out.write(file.read)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
@@vgg16_obj = Menoh::Menoh.new(vgg16_dir)
|
48
|
+
end
|
49
|
+
return @@vgg16_obj
|
50
|
+
end
|
51
|
+
|
52
|
+
# ...? modelの各layerのid
|
53
|
+
def self.id
|
54
|
+
conv1_id = '140326425860192'.freeze
|
55
|
+
fc6_id = '140326200777584'.freeze
|
56
|
+
softmax_id = '140326200803680'.freeze
|
57
|
+
{conv1_id: conv1_id, fc6_id: fc6_id, softmax_id:softmax_id}
|
58
|
+
end
|
59
|
+
|
60
|
+
# モデルの詳細
|
61
|
+
def self.model_opt
|
62
|
+
conv1_id, fc6_id, softmax_id = self.id.values
|
63
|
+
|
64
|
+
input_shape = {
|
65
|
+
channel_num: 3,
|
66
|
+
width: 224,
|
67
|
+
height: 224
|
68
|
+
}
|
69
|
+
model_opt = {
|
70
|
+
backend: 'mkldnn',
|
71
|
+
input_layers: [
|
72
|
+
{
|
73
|
+
name: conv1_id,
|
74
|
+
dims: [
|
75
|
+
1, #image_list.size, # batch size
|
76
|
+
input_shape[:channel_num],
|
77
|
+
input_shape[:height],
|
78
|
+
input_shape[:width],
|
79
|
+
]
|
80
|
+
}
|
81
|
+
],
|
82
|
+
output_layers: [fc6_id, softmax_id]
|
83
|
+
}
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
class Magick::Image
|
88
|
+
# dselect内かどうかのフラグ もう少しいい書き方ないのか
|
89
|
+
attr_accessor :in_dselect
|
90
|
+
|
91
|
+
# calcurated feature vector
|
92
|
+
# モデルの情報とかもclassに保持するとよいかも
|
93
|
+
@vector = nil
|
94
|
+
|
95
|
+
# batch処理したほうが速いだろうけど
|
96
|
+
# とりあえず逐次処理
|
97
|
+
def to_vector
|
98
|
+
return @vector if @vector
|
99
|
+
|
100
|
+
vgg16 = DSelect.vgg16
|
101
|
+
opt = DSelect.model_opt
|
102
|
+
model = vgg16.make_model(opt)
|
103
|
+
|
104
|
+
# onnx variable name
|
105
|
+
conv1_id, fc6_id, softmax_id = DSelect.id.values
|
106
|
+
|
107
|
+
image = self.to_menoh_image
|
108
|
+
image_set = [{ name: conv1_id, data: image}]
|
109
|
+
result = model.run(image_set)
|
110
|
+
|
111
|
+
network_output = result.find { |x| x[:name] == fc6_id }
|
112
|
+
@vector = network_output[:data].first
|
113
|
+
|
114
|
+
return @vector
|
115
|
+
end
|
116
|
+
# alias :to_v :to_vector さすがに他のライブラリと被りそうな気が
|
117
|
+
|
118
|
+
alias :default_equal :==
|
119
|
+
def ==(image)
|
120
|
+
if self.in_dselect or image.in_dselect
|
121
|
+
# guard
|
122
|
+
unless image.class == Magick::Image
|
123
|
+
raise "現状dselectの比較相手はMagick::Imageのみ対応です" +
|
124
|
+
"images.dselect{|dselect_image| dselect_image == image} のノリで"
|
125
|
+
end
|
126
|
+
DSelect.compare(self, image)
|
127
|
+
else
|
128
|
+
return self.default_equal(image)
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
def to_menoh_image
|
133
|
+
# TODO: DRYできていない場所が多すぎるので直す
|
134
|
+
# model_optから引っ張ってくるのありだろうけどめんどいな
|
135
|
+
input_shape = {
|
136
|
+
channel_num: 3,
|
137
|
+
width: 224,
|
138
|
+
height: 224
|
139
|
+
}
|
140
|
+
image = self.resize_to_fill(input_shape[:width], input_shape[:height])
|
141
|
+
'BGR'.split('').map do |color|
|
142
|
+
image.export_pixels(0, 0, image.columns, image.rows, color).map { |pix| pix / 256 }
|
143
|
+
end.flatten
|
144
|
+
end
|
145
|
+
|
146
|
+
def comapre_vector(image)
|
147
|
+
if image.class != Magick::Image # or image.class != Array
|
148
|
+
# 文章長すぎ
|
149
|
+
err_stdout = "Error: あとでErrorClass名追加します
|
150
|
+
compare対象はMagick::Imageでないと駄目です
|
151
|
+
compare arg must be Magick::Image"
|
152
|
+
raise err_stdout
|
153
|
+
end
|
154
|
+
return DSelect.compare(self, image)
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
class Array
|
159
|
+
# block内で比較された対象の画像に,いちばん似てる画像を取り出すメソッド
|
160
|
+
def deepselect(take: "default", with: "")
|
161
|
+
return enum_for(__method__) unless block_given?
|
162
|
+
|
163
|
+
# dselect内かどうかのフラグ
|
164
|
+
# このフラグががtrueだと == をした時に特徴量を返す
|
165
|
+
self.each do |image|
|
166
|
+
image.in_dselect = true
|
167
|
+
end
|
168
|
+
|
169
|
+
# 特徴量計算
|
170
|
+
feature_vectors = self.map do |image|
|
171
|
+
result = yield image
|
172
|
+
unless result.class == Float
|
173
|
+
raise "Not a proper value is returned in dselect block"
|
174
|
+
end
|
175
|
+
result
|
176
|
+
end
|
177
|
+
|
178
|
+
self.each do |image| # 元に戻す
|
179
|
+
image.in_dselect = nil
|
180
|
+
end
|
181
|
+
|
182
|
+
# 特徴量が大きい順に並べる
|
183
|
+
zipped_image = [self, feature_vectors].transpose.map.with_index{|(image, num),i| [image, num, i]}
|
184
|
+
result = zipped_image.sort_by{|image, num,i| num}.reverse
|
185
|
+
|
186
|
+
# 指定された引数によって出力を変える
|
187
|
+
if with =~ /sim/ and with =~ /ind/ # 類似度とindex両方出力
|
188
|
+
# pass
|
189
|
+
elsif with =~ /sim/ # 類似度のみ
|
190
|
+
result = result.map{|image, num,i| [image,num] }
|
191
|
+
elsif with =~ /ind/ # indexのみ
|
192
|
+
result = result.map{|image, num,i| [image,i] }
|
193
|
+
else # どちらも出力しない,imageのみ返す
|
194
|
+
result = result.map{|image, num,i| image }
|
195
|
+
end
|
196
|
+
|
197
|
+
# 上位いくつ取得する?
|
198
|
+
if take == "default"
|
199
|
+
return result.first
|
200
|
+
end
|
201
|
+
if take == "all"
|
202
|
+
return result
|
203
|
+
end
|
204
|
+
if take.to_i > 0
|
205
|
+
return result.take(take.to_i)
|
206
|
+
end
|
207
|
+
raise "what is this arg error\ntake: #{take}" #このエラーはどうなのよ
|
208
|
+
end
|
209
|
+
alias :dselect :deepselect
|
210
|
+
|
211
|
+
# 初回の特徴量計算に時間がかかるため,事前にキャッシュしておきたい場合に叩くメソッド
|
212
|
+
# batch処理する仕様にすればもっと速いけど作りがめんどくなりそう
|
213
|
+
def deepinit
|
214
|
+
self.each do |image|
|
215
|
+
image.to_vector
|
216
|
+
end
|
217
|
+
end
|
218
|
+
alias :dinit :deepinit
|
219
|
+
end
|
metadata
ADDED
@@ -0,0 +1,143 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: deepselect
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- 7rpn
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2018-07-18 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: menoh
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rmagick
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: bundler
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '1.16'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '1.16'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rake
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '10.0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '10.0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: rspec
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '3.0'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '3.0'
|
83
|
+
description: Provides a method to retrieve the image most similar to the specified
|
84
|
+
image from the array.
|
85
|
+
email:
|
86
|
+
- 7rpn.deadlock@gmail.com
|
87
|
+
executables: []
|
88
|
+
extensions: []
|
89
|
+
extra_rdoc_files: []
|
90
|
+
files:
|
91
|
+
- ".gitignore"
|
92
|
+
- ".rspec"
|
93
|
+
- ".travis.yml"
|
94
|
+
- CODE_OF_CONDUCT.md
|
95
|
+
- Gemfile
|
96
|
+
- Gemfile.lock
|
97
|
+
- LICENSE.txt
|
98
|
+
- README.md
|
99
|
+
- Rakefile
|
100
|
+
- bin/console
|
101
|
+
- bin/setup
|
102
|
+
- deepselect.gemspec
|
103
|
+
- example/images/image_komeda.jpg
|
104
|
+
- example/images/image_starbucks.png
|
105
|
+
- example/images/image_starbucks2.jpg
|
106
|
+
- example/images/image_tully's.png
|
107
|
+
- example/images/logo_doutor.jpg
|
108
|
+
- example/images/logo_komeda.jpeg
|
109
|
+
- example/images/logo_starbucks.png
|
110
|
+
- example/images/logo_stmarc.png
|
111
|
+
- example/images/logo_tully's.jpg
|
112
|
+
- example/images/photo_komeda.jpg
|
113
|
+
- example/images/photo_starbucks.jpg
|
114
|
+
- example/images/photo_starbucks2.png
|
115
|
+
- example/images/photo_stmarc.jpg
|
116
|
+
- example/logo_recog.rb
|
117
|
+
- lib/deepselect.rb
|
118
|
+
- lib/deepselect/version.rb
|
119
|
+
homepage: https://github.com/7rpn/deepselect
|
120
|
+
licenses:
|
121
|
+
- MIT
|
122
|
+
metadata: {}
|
123
|
+
post_install_message:
|
124
|
+
rdoc_options: []
|
125
|
+
require_paths:
|
126
|
+
- lib
|
127
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
128
|
+
requirements:
|
129
|
+
- - ">="
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: '0'
|
132
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
133
|
+
requirements:
|
134
|
+
- - ">="
|
135
|
+
- !ruby/object:Gem::Version
|
136
|
+
version: '0'
|
137
|
+
requirements: []
|
138
|
+
rubyforge_project:
|
139
|
+
rubygems_version: 2.6.8
|
140
|
+
signing_key:
|
141
|
+
specification_version: 4
|
142
|
+
summary: Image recognition library for Ruby
|
143
|
+
test_files: []
|