findaface 0.0.6 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +14 -13
- data/findaface.gemspec +0 -1
- data/lib/findaface.rb +30 -30
- data/lib/findaface/version.rb +2 -2
- data/report.md +18 -0
- data/spec/findaface_spec.rb +56 -40
- data/spec/photos/eye.jpg +0 -0
- data/spec/photos/face.jpg +0 -0
- data/spec/photos/fruit.jpg +0 -0
- data/spec/photos/nose.jpg +0 -0
- metadata +12 -33
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7f96dc6603d1aedf09e21aa75755408409479d85
|
4
|
+
data.tar.gz: e65f03a7a0efb180a31e35aef2fa2b29e2c47f7c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5a0c7ed26464b1130f89b5c03a57035f31a523494ea0a74b70c9a3b4a627f9e3c3f03060abde40f1b3b4a8033e524d265d264f33bf04843e2bcef2ce188542ae
|
7
|
+
data.tar.gz: 16adb61b23f56c9bb24dcacc1af8610ad92003d1debd93aa898245fb0e084214fe3af9d9c4b54721b11f09d170258f5a4c36bbac01bee065ec8b8042e9898e54
|
data/README.md
CHANGED
@@ -1,11 +1,10 @@
|
|
1
1
|
# Findaface
|
2
2
|
|
3
|
-
When given a path to a picture, this gem attempts to determins whether it contains
|
4
|
-
faces and thus might be appropriate for a profile image. It is looking for faces bigger than 80 pixels squared.
|
3
|
+
When given a path to a picture, this gem attempts to determins whether it contains any faces and thus might be appropriate for a profile image. It is looking for faces bigger than 80 pixels squared.
|
5
4
|
|
6
5
|
It is a modified then gemified version of George Ogata's [find-face](https://github.com/howaboutwe/find-face). If you want a CLI that indicates where the biggest face in an image is, then use the original.
|
7
6
|
|
8
|
-
This gem simply compiles an executable to detect a face then calls it externally, so you won't have to include the humongous OpenCV library into your Ruby process, which can cause memory
|
7
|
+
This gem simply compiles an executable to detect a face then calls it externally, so you won't have to include the humongous OpenCV library into your Ruby process, which can cause a memory leaks / bloat or even a crash. This is what [Paperclip](https://github.com/thoughtbot/paperclip) does for ImageMagick. We also support [posix-spawn](https://github.com/rtomayko/posix-spawn) to mitigate the overhead of fork-exec.
|
9
8
|
|
10
9
|
## Installation
|
11
10
|
|
@@ -52,11 +51,11 @@ $ gem install findaface
|
|
52
51
|
## Usage
|
53
52
|
|
54
53
|
```
|
55
|
-
puts Findaface.has_face?('path/to/me.jpg')
|
54
|
+
puts Findaface.new.has_face?('path/to/me.jpg')
|
56
55
|
=> true
|
57
|
-
puts Findaface.has_face?('path/to/me_in_a_group.jpg')
|
58
|
-
=>
|
59
|
-
puts Findaface.has_face?('path/to/my_cat.jpg')
|
56
|
+
puts Findaface.new.has_face?('path/to/me_in_a_group.jpg')
|
57
|
+
=> true
|
58
|
+
puts Findaface.new.has_face?('path/to/my_cat.jpg')
|
60
59
|
=> false
|
61
60
|
```
|
62
61
|
|
@@ -84,10 +83,10 @@ Basically the scale factor is used to create your scale pyramid. More explanatio
|
|
84
83
|
* max_size: Objects bigger than this are ignored.
|
85
84
|
|
86
85
|
### Using multiple cascades
|
87
|
-
If you add multiple cascades then they will be applied in turn. If any of the cascades
|
88
|
-
findaface returns true.
|
86
|
+
If you add multiple cascades then they will be applied in turn. If any of the cascades match, then findaface returns true. You should add cascades before the first call to `has_face?` (unless you also want the default cascade to be applied).
|
89
87
|
```
|
90
|
-
Findaface.
|
88
|
+
findaface = Findaface.new
|
89
|
+
findaface.add_cascade(
|
91
90
|
{
|
92
91
|
cascade:'haarcascades/haarcascade_mcs_nose.xml',
|
93
92
|
fussyness:6,
|
@@ -96,7 +95,7 @@ Findaface.add_cascade(
|
|
96
95
|
max_size: 512,
|
97
96
|
}
|
98
97
|
)
|
99
|
-
|
98
|
+
findaface.add_cascade(
|
100
99
|
{
|
101
100
|
cascade:'haarcascades/haarcascade_eye.xml',
|
102
101
|
fussyness:6,
|
@@ -106,9 +105,11 @@ Findaface.add_cascade(
|
|
106
105
|
}
|
107
106
|
)
|
108
107
|
|
109
|
-
puts
|
108
|
+
puts findaface.has_face?('path/to/nose.jpg')
|
109
|
+
=> true
|
110
|
+
puts findaface.has_face?('path/to/eye.jpg')
|
110
111
|
=> true
|
111
|
-
puts
|
112
|
+
puts findaface.has_face?('path/to/mouth.jpg')
|
112
113
|
=> false
|
113
114
|
```
|
114
115
|
|
data/findaface.gemspec
CHANGED
@@ -27,6 +27,5 @@ Gem::Specification.new do |spec|
|
|
27
27
|
spec.add_development_dependency "rspec", "~> 2.14"
|
28
28
|
spec.add_development_dependency "pry"
|
29
29
|
spec.add_development_dependency "pry-doc"
|
30
|
-
spec.add_development_dependency "pry-debugger"
|
31
30
|
spec.add_development_dependency "awesome_print"
|
32
31
|
end
|
data/lib/findaface.rb
CHANGED
@@ -1,49 +1,49 @@
|
|
1
1
|
require 'findaface/version'
|
2
2
|
require 'posix/spawn'
|
3
3
|
|
4
|
-
|
4
|
+
class Findaface
|
5
5
|
LIB_PATH = File.dirname(File.expand_path(__FILE__))
|
6
6
|
EXECUTABLE = File.join(LIB_PATH, '../ext/findaface/findaface')
|
7
7
|
DEFAULT_CASCADE = {
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
8
|
+
cascade:'haarcascades/haarcascade_frontalface_alt2.xml',
|
9
|
+
fussyness:4,
|
10
|
+
max_size: 512,
|
11
|
+
min_size: 80,
|
12
|
+
scale_factor: 1.05,
|
13
|
+
}
|
14
14
|
DEFAULT_OPTIONS = DEFAULT_CASCADE.keys
|
15
15
|
|
16
|
-
|
17
|
-
|
18
|
-
|
16
|
+
class << self
|
17
|
+
attr_reader :cascades
|
18
|
+
end
|
19
19
|
|
20
|
-
def
|
20
|
+
def has_face?(path)
|
21
21
|
raise "#{path} file does not exist" unless File.exists?(path)
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
22
|
+
add_cascade(DEFAULT_CASCADE) if @cascades.nil?
|
23
|
+
commands = @cascades.map { |opts| build_command(opts, path) }
|
24
|
+
commands.each { |cmd| return true if POSIX::Spawn::system cmd }
|
25
|
+
false
|
26
26
|
end
|
27
27
|
|
28
|
-
def
|
28
|
+
def add_cascade(options)
|
29
29
|
raise "Invalid setting. Got #{options.keys.sort}, require #{DEFAULT_OPTIONS}" unless options.keys.sort == DEFAULT_OPTIONS
|
30
|
-
|
31
|
-
|
32
|
-
|
30
|
+
@cascades ||= []
|
31
|
+
@cascades << options
|
32
|
+
end
|
33
33
|
|
34
|
-
|
34
|
+
private
|
35
35
|
|
36
|
-
|
36
|
+
def build_command(options, path)
|
37
37
|
"#{EXECUTABLE} " +
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
38
|
+
"--cascade=#{cascade_path(options[:cascade])} " +
|
39
|
+
"--fussyness=#{options[:fussyness]} " +
|
40
|
+
"--scale_factor=#{options[:scale_factor]} " +
|
41
|
+
"--min_size=#{options[:min_size]} " +
|
42
|
+
"--max_size=#{options[:max_size]} " +
|
43
|
+
"#{path}" # > /dev/null 2>&1"
|
44
|
+
end
|
45
45
|
|
46
|
-
|
46
|
+
def cascade_path(cascade_path)
|
47
47
|
File.join(LIB_PATH, cascade_path)
|
48
|
-
|
48
|
+
end
|
49
49
|
end
|
data/lib/findaface/version.rb
CHANGED
@@ -1,3 +1,3 @@
|
|
1
|
-
|
2
|
-
VERSION = '0.0
|
1
|
+
class Findaface
|
2
|
+
VERSION = '1.0.0'
|
3
3
|
end
|
data/report.md
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
= False Negatives
|
2
|
+
![spec/test_photos/approval/real/real-05.jpg](spec/test_photos/approval/real/real-05.jpg)
|
3
|
+
![spec/test_photos/approval/real/real-06.jpg](spec/test_photos/approval/real/real-06.jpg)
|
4
|
+
![spec/test_photos/approval/real/real-08.jpg](spec/test_photos/approval/real/real-08.jpg)
|
5
|
+
![spec/test_photos/approval/real/real-15.jpg](spec/test_photos/approval/real/real-15.jpg)
|
6
|
+
![spec/test_photos/approval/real/real-24.jpg](spec/test_photos/approval/real/real-24.jpg)
|
7
|
+
![spec/test_photos/approval/real/real-28.jpg](spec/test_photos/approval/real/real-28.jpg)
|
8
|
+
![spec/test_photos/approval/real/real-29.jpg](spec/test_photos/approval/real/real-29.jpg)
|
9
|
+
![spec/test_photos/approval/real/real-33.jpg](spec/test_photos/approval/real/real-33.jpg)
|
10
|
+
![spec/test_photos/approval/real/real-34.jpg](spec/test_photos/approval/real/real-34.jpg)
|
11
|
+
![spec/test_photos/approval/real/real-35.jpg](spec/test_photos/approval/real/real-35.jpg)
|
12
|
+
![spec/test_photos/approval/real/real-36.jpg](spec/test_photos/approval/real/real-36.jpg)
|
13
|
+
![spec/test_photos/approval/real/real-38.jpg](spec/test_photos/approval/real/real-38.jpg)
|
14
|
+
![spec/test_photos/approval/real/real-40.jpg](spec/test_photos/approval/real/real-40.jpg)
|
15
|
+
![spec/test_photos/approval/real/real-41.jpg](spec/test_photos/approval/real/real-41.jpg)
|
16
|
+
![spec/test_photos/approval/real/real-43.jpg](spec/test_photos/approval/real/real-43.jpg)
|
17
|
+
![spec/test_photos/approval/real/real-45.jpg](spec/test_photos/approval/real/real-45.jpg)
|
18
|
+
![spec/test_photos/approval/real/real-50.jpg](spec/test_photos/approval/real/real-50.jpg)
|
data/spec/findaface_spec.rb
CHANGED
@@ -2,53 +2,69 @@ require_relative '../lib/findaface.rb'
|
|
2
2
|
|
3
3
|
describe Findaface, "has_face?" do
|
4
4
|
|
5
|
+
let(:face) { 'spec/photos/face.jpg' }
|
6
|
+
let(:eye) { 'spec/photos/eye.jpg' }
|
7
|
+
let(:nose) { 'spec/photos/nose.jpg' }
|
8
|
+
let(:fruit) { 'spec/photos/fruit.jpg' }
|
9
|
+
|
5
10
|
it "finds faces" do
|
6
|
-
|
7
|
-
Findaface.has_face?(path).should be_true
|
8
|
-
end
|
11
|
+
Findaface.new.has_face?(face).should be_true
|
9
12
|
end
|
10
13
|
|
11
14
|
it "doesn't give false positives" do
|
12
|
-
|
13
|
-
Findaface.has_face?(path).should be_false
|
14
|
-
end
|
15
|
+
Findaface.new.has_face?(eye).should_not be_true
|
15
16
|
end
|
16
17
|
|
17
|
-
|
18
|
-
|
19
|
-
Findaface.
|
18
|
+
context "with custom cascade options" do
|
19
|
+
before :each do
|
20
|
+
@nose_detecter = Findaface.new
|
21
|
+
@nose_detecter.add_cascade({
|
22
|
+
cascade:'haarcascades/haarcascade_mcs_nose.xml',
|
23
|
+
fussyness: 7,
|
24
|
+
scale_factor: 1.05,
|
25
|
+
min_size: 80,
|
26
|
+
max_size: 512,
|
27
|
+
})
|
28
|
+
end
|
29
|
+
|
30
|
+
it "finds a nose" do
|
31
|
+
@nose_detecter.has_face?(nose).should be_true
|
32
|
+
end
|
33
|
+
|
34
|
+
it "doesn't give false positives" do
|
35
|
+
@nose_detecter.has_face?(eye).should_not be_true
|
20
36
|
end
|
21
37
|
end
|
22
38
|
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
39
|
+
context "with multiple cascades" do
|
40
|
+
it "can detect a nose, eye, and face" do
|
41
|
+
findaface = Findaface.new
|
42
|
+
findaface.add_cascade(
|
43
|
+
{
|
44
|
+
cascade:'haarcascades/haarcascade_eye.xml',
|
45
|
+
fussyness: 8,
|
46
|
+
scale_factor: 1.05,
|
47
|
+
min_size: 100,
|
48
|
+
max_size: 512,
|
49
|
+
})
|
50
|
+
findaface.add_cascade({
|
51
|
+
cascade:'haarcascades/haarcascade_mcs_nose.xml',
|
52
|
+
fussyness: 8,
|
53
|
+
scale_factor: 1.044,
|
54
|
+
min_size: 100,
|
55
|
+
max_size: 512,
|
56
|
+
})
|
57
|
+
findaface.add_cascade(
|
58
|
+
{
|
59
|
+
cascade:'haarcascades/haarcascade_frontalface_alt2.xml',
|
60
|
+
fussyness: 8,
|
61
|
+
scale_factor: 1.05,
|
62
|
+
min_size: 100,
|
63
|
+
max_size: 512,
|
64
|
+
})
|
65
|
+
[eye, nose, face].each do |path|
|
66
|
+
findaface.has_face?(path).should be_true
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
54
70
|
end
|
data/spec/photos/eye.jpg
ADDED
Binary file
|
Binary file
|
Binary file
|
Binary file
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: findaface
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
4
|
+
version: 1.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Andrew Nagi
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-
|
11
|
+
date: 2014-08-02 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: posix-spawn
|
@@ -94,20 +94,6 @@ dependencies:
|
|
94
94
|
- - ">="
|
95
95
|
- !ruby/object:Gem::Version
|
96
96
|
version: '0'
|
97
|
-
- !ruby/object:Gem::Dependency
|
98
|
-
name: pry-debugger
|
99
|
-
requirement: !ruby/object:Gem::Requirement
|
100
|
-
requirements:
|
101
|
-
- - ">="
|
102
|
-
- !ruby/object:Gem::Version
|
103
|
-
version: '0'
|
104
|
-
type: :development
|
105
|
-
prerelease: false
|
106
|
-
version_requirements: !ruby/object:Gem::Requirement
|
107
|
-
requirements:
|
108
|
-
- - ">="
|
109
|
-
- !ruby/object:Gem::Version
|
110
|
-
version: '0'
|
111
97
|
- !ruby/object:Gem::Dependency
|
112
98
|
name: awesome_print
|
113
99
|
requirement: !ruby/object:Gem::Requirement
|
@@ -172,15 +158,12 @@ files:
|
|
172
158
|
- lib/readme.txt
|
173
159
|
- lib/softcascade/inria_caltech-17.01.2013.xml
|
174
160
|
- lib/softcascade/soft-cascade-17.12.2012.xml
|
161
|
+
- report.md
|
175
162
|
- spec/findaface_spec.rb
|
176
|
-
- spec/
|
177
|
-
- spec/
|
178
|
-
- spec/
|
179
|
-
- spec/
|
180
|
-
- spec/test_photos/has_face/face.jpg
|
181
|
-
- spec/test_photos/no_face/.gitkeep
|
182
|
-
- spec/test_photos/no_face/fruit.jpg
|
183
|
-
- spec/test_photos/small_faces/beach.jpg
|
163
|
+
- spec/photos/eye.jpg
|
164
|
+
- spec/photos/face.jpg
|
165
|
+
- spec/photos/fruit.jpg
|
166
|
+
- spec/photos/nose.jpg
|
184
167
|
homepage: ''
|
185
168
|
licenses:
|
186
169
|
- MIT
|
@@ -201,18 +184,14 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
201
184
|
version: '0'
|
202
185
|
requirements: []
|
203
186
|
rubyforge_project:
|
204
|
-
rubygems_version: 2.2.
|
187
|
+
rubygems_version: 2.2.2
|
205
188
|
signing_key:
|
206
189
|
specification_version: 4
|
207
190
|
summary: Finds a face in an image.
|
208
191
|
test_files:
|
209
192
|
- spec/findaface_spec.rb
|
210
|
-
- spec/
|
211
|
-
- spec/
|
212
|
-
- spec/
|
213
|
-
- spec/
|
214
|
-
- spec/test_photos/has_face/face.jpg
|
215
|
-
- spec/test_photos/no_face/.gitkeep
|
216
|
-
- spec/test_photos/no_face/fruit.jpg
|
217
|
-
- spec/test_photos/small_faces/beach.jpg
|
193
|
+
- spec/photos/eye.jpg
|
194
|
+
- spec/photos/face.jpg
|
195
|
+
- spec/photos/fruit.jpg
|
196
|
+
- spec/photos/nose.jpg
|
218
197
|
has_rdoc:
|