facer 0.0.3
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile +3 -0
- data/Manifest.txt +0 -0
- data/README +41 -0
- data/init.rb +1 -0
- data/lib/facer.rb +25 -0
- data/lib/facer/account.rb +54 -0
- data/lib/facer/faces.rb +107 -0
- data/lib/facer/namespace.rb +40 -0
- data/lib/linker.rb +52 -0
- data/test/facer_test.rb +8 -0
- metadata +110 -0
data/Gemfile
ADDED
data/Manifest.txt
ADDED
File without changes
|
data/README
ADDED
@@ -0,0 +1,41 @@
|
|
1
|
+
This Gem is a very alpha version and is provided as is without any warranty.
|
2
|
+
|
3
|
+
I coded it as a convenient and easy interface to face.com's API for a project I'm working on and I must prepone some assumption on using it:
|
4
|
+
|
5
|
+
- you are a brave
|
6
|
+
- you will send images with only ONE recognizable face at time
|
7
|
+
- you expect some errors and bugs and have the bravery and patience to fix them
|
8
|
+
|
9
|
+
If those requirements are met, go on and use it. If not stop reading and trash the gem...
|
10
|
+
|
11
|
+
If you are reading this you are brave (or crazy).
|
12
|
+
|
13
|
+
A little example of usage:
|
14
|
+
|
15
|
+
linkr=Facer::Linker.new("yourapp","yourkey","yoursecret")
|
16
|
+
puts linkr.account.private_namespaces?.inspect
|
17
|
+
puts linkr.account.limits?.inspect
|
18
|
+
|
19
|
+
trainSet={
|
20
|
+
"vanessa_paradis" => [
|
21
|
+
"http://www.superiorpics.com/hs/vanessa_paradis/main1.jpg",
|
22
|
+
"http://nymag.com/daily/fashion/14_paradis_lgl.jpg",
|
23
|
+
"http://imstars.aufeminin.com/stars/fan/vanessa-paradis/vanessa-paradis-20060208-107457.jpg",
|
24
|
+
"http://www.realbeauty.com/cm/realbeauty/images/NF/rby-hair-vanessa-paradis-5-de.jpg",
|
25
|
+
"http://www.wallpaperweb.org/wallpaper/babes/1280x960/vanessa_paradis_20070722_0171_1280x960.jpg",
|
26
|
+
"http://chansons-fle.wikispaces.com/file/view/vanessa_paradis_reference.jpg/59524266/vanessa_paradis_reference.jpg"
|
27
|
+
]
|
28
|
+
}
|
29
|
+
|
30
|
+
trainSet.each_pair do |key,value|
|
31
|
+
succ= linkr.faces.associate_multi(value,key,"yournamespace").inspect
|
32
|
+
puts "Associating #{key}: #{succ}"
|
33
|
+
end
|
34
|
+
|
35
|
+
puts linkr.faces.train_all("clinik").inspect
|
36
|
+
|
37
|
+
puts linkr.faces.recognize("http://static1.purepeople.com/articles/7/17/12/7/@/85769-vanessa-paradis-et-johnny-depp-637x0-1.jpg","yournamespace").inspect
|
38
|
+
puts linkr.faces.recognize("http://howzar.com/Galleries/Vanessa%20Paradis/vanessa-paradis-32.jpg","yournamespace").inspect
|
39
|
+
puts linkr.faces.recognize("http://pictures.directnews.co.uk/liveimages/Old+man+smiling_1500_19112072_0_0_7006461_300.jpg","yournamespace").inspect
|
40
|
+
|
41
|
+
Stefano Valicchia (stefano.valicchia@gmail.com)
|
data/init.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/lib/facer'
|
data/lib/facer.rb
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
$LOAD_PATH << './lib/facer'
|
3
|
+
require 'rubygems'
|
4
|
+
gem 'multipart-post'
|
5
|
+
|
6
|
+
require "net/http"
|
7
|
+
require "net/http/post/multipart"
|
8
|
+
require 'mime/types'
|
9
|
+
require "uri"
|
10
|
+
require "json"
|
11
|
+
|
12
|
+
require "linker"
|
13
|
+
require "namespace"
|
14
|
+
require "account"
|
15
|
+
require "faces"
|
16
|
+
|
17
|
+
# This class manage basilar operations on face.com.
|
18
|
+
# It's very alpha so you will find a very basical subset
|
19
|
+
# to use face.com services
|
20
|
+
# Author:: Stefano Valicchia (mailto:stefano.valicchiagmail.com)
|
21
|
+
# Copyright:: Copyright (c) 2002 Giano
|
22
|
+
# License:: Distributes under the same terms as Ruby
|
23
|
+
module Facer
|
24
|
+
VERSION = "0.0.3"
|
25
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
module Facer
|
2
|
+
# Base class to store security informations and obtain infos on the account
|
3
|
+
class Account
|
4
|
+
attr_reader :applicationName
|
5
|
+
attr_reader :apiKey
|
6
|
+
attr_reader :apiSecret
|
7
|
+
|
8
|
+
# Initialize the class passing a convenient linker reference
|
9
|
+
def initialize(linker, app_name,api_key,api_secret)
|
10
|
+
@linker=linker
|
11
|
+
@applicationName=applicationName
|
12
|
+
@apiKey=key
|
13
|
+
@apiSecret=secret
|
14
|
+
end
|
15
|
+
|
16
|
+
# Obtain all account's accessible namespaces
|
17
|
+
def namespaces?
|
18
|
+
t_namespaces=@linker.call("account","namespaces")
|
19
|
+
if(t_namespaces["status"].to_sym == :success)
|
20
|
+
out={}
|
21
|
+
t_namespaces["namespaces"].each do |namespace|
|
22
|
+
nm=Namespace.new(@linker,namespace["name"],namespace["size"],namespace["share_mode"].to_sym,namespace["owner"])
|
23
|
+
out[nm.name]=nm
|
24
|
+
end
|
25
|
+
return out
|
26
|
+
else
|
27
|
+
return {}
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
# Obtain all the namespaces owned by the account owner (public and private)
|
32
|
+
def owned_namespaces?
|
33
|
+
namespaces?.reject {|key,value| !value.owner}
|
34
|
+
end
|
35
|
+
|
36
|
+
# Obtain all account's private namespaces
|
37
|
+
def private_namespaces?
|
38
|
+
owned_namespaces?.reject {|key,value| value.shareMode!=:Private}
|
39
|
+
end
|
40
|
+
|
41
|
+
# Retrieve informations about current account's limits
|
42
|
+
def limits?
|
43
|
+
out=@linker.call("account","limits")
|
44
|
+
if(out["status"].to_sym == :success)
|
45
|
+
return out["usage"]
|
46
|
+
else
|
47
|
+
return nil
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
private
|
52
|
+
attr_accessor :linker
|
53
|
+
end
|
54
|
+
end
|
data/lib/facer/faces.rb
ADDED
@@ -0,0 +1,107 @@
|
|
1
|
+
module Facer
|
2
|
+
# Base class to query the api on faces and tags info
|
3
|
+
# All the queries are in the "simplest form" of a single image/single user query
|
4
|
+
# In this version of the gem I assume to use "single face" images
|
5
|
+
# You can provide images as a file path or a public url, the library will treat them accordingly
|
6
|
+
class Faces
|
7
|
+
# Initialize the class passing a convenient linker reference
|
8
|
+
def initialize(linker)
|
9
|
+
@linker=linker
|
10
|
+
end
|
11
|
+
|
12
|
+
# Detect if the provided image contains a face and, if yes, return face's informations
|
13
|
+
def detect(image,detector = :Normal)
|
14
|
+
ret={}
|
15
|
+
if(URI.parse(image).is_a?(URI::HTTP))
|
16
|
+
ret=@linker.call("faces","detect",{"urls" => image, "detector" => detector.to_s})
|
17
|
+
else
|
18
|
+
ret=@linker.call("faces","detect",{"detector" => detector.to_s},{"upload" => image})
|
19
|
+
end
|
20
|
+
if(ret["status"].to_sym == :success && ret["photos"].length == 1)
|
21
|
+
return ret["photos"][0]
|
22
|
+
end
|
23
|
+
return nil
|
24
|
+
end
|
25
|
+
|
26
|
+
# Force train a user against the images/tags library
|
27
|
+
def train(user,namespace)
|
28
|
+
ret=@linker.call("faces","train",{"uids" => "#{user}@#{namespace}"})
|
29
|
+
return ret["status"].to_sym == :success
|
30
|
+
end
|
31
|
+
|
32
|
+
# Force train all users in a namespace (veeeery long operation)
|
33
|
+
def train_all(namespace)
|
34
|
+
namespaces=@linker.account.private_namespaces?
|
35
|
+
if(!namespaces || !namespaces[namespace])
|
36
|
+
return false
|
37
|
+
end
|
38
|
+
users=namespaces[namespace].users?
|
39
|
+
success=true
|
40
|
+
users.each do |user|
|
41
|
+
success &= train(user,namespace)
|
42
|
+
end
|
43
|
+
return success
|
44
|
+
end
|
45
|
+
|
46
|
+
# Attempt to recognize a user in a image end, if so, provide user and face infos
|
47
|
+
def recognize(image,namespace,users = "",detector = :Normal)
|
48
|
+
if(users.empty?)
|
49
|
+
users="all@#{namespace}"
|
50
|
+
end
|
51
|
+
ret={}
|
52
|
+
if(URI.parse(image).is_a?(URI::HTTP))
|
53
|
+
ret=@linker.call("faces","recognize",{"urls" => image, "uids" => users, "detector" => detector.to_s, "namespace" => namespace})
|
54
|
+
else
|
55
|
+
ret=@linker.call("faces","recognize",{"uids" => users, "detector" => detector.to_s, "namespace" => namespace},{"upload" => image})
|
56
|
+
end
|
57
|
+
if(ret["status"].to_sym == :success && ret["photos"].length == 1)
|
58
|
+
img=ret["photos"][0]
|
59
|
+
if(img["tags"].length == 1)
|
60
|
+
tag=img["tags"][0]
|
61
|
+
if(tag["uids"] && tag["uids"].length>0)
|
62
|
+
return tag["uids"][0]
|
63
|
+
else
|
64
|
+
return {"confidence" => 0, "uid" => nil}
|
65
|
+
end
|
66
|
+
else
|
67
|
+
return {"confidence" => -1, "uid" => nil}
|
68
|
+
end
|
69
|
+
end
|
70
|
+
return nil
|
71
|
+
end
|
72
|
+
|
73
|
+
# Associace many images to a user. I assume every images contains a single face
|
74
|
+
def associate_multi(images,user,namespace, force_train = false, detector = :Normal)
|
75
|
+
success=true
|
76
|
+
images.each do |image|
|
77
|
+
success &= associate(image,user,namespace,false,detector)
|
78
|
+
end
|
79
|
+
if(success && force_train)
|
80
|
+
return train(user,namespace)
|
81
|
+
end
|
82
|
+
return success
|
83
|
+
end
|
84
|
+
|
85
|
+
# Associace a face image to a user. I assume the image contains a single face
|
86
|
+
def associate(image,user,namespace, force_train = false, detector = :Normal)
|
87
|
+
img=detect(image,detector)
|
88
|
+
if(img && img["tags"].length == 1)
|
89
|
+
tag=img["tags"][0]
|
90
|
+
if(tag["attributes"]["face"] && tag["attributes"]["face"]["value"].to_s == "true")
|
91
|
+
tid=tag["tid"]
|
92
|
+
ret=@linker.call("tags","save",{"tids" => tid, "uid" => "#{user}@#{namespace}"})
|
93
|
+
if(ret["status"].to_sym == :success)
|
94
|
+
if(force_train)
|
95
|
+
return train(user,namespace)
|
96
|
+
end
|
97
|
+
return true
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
return false
|
102
|
+
end
|
103
|
+
|
104
|
+
private
|
105
|
+
attr_accessor :linker
|
106
|
+
end
|
107
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
module Facer
|
2
|
+
# Base class to store informations and obtain infos on the namespace
|
3
|
+
class Namespace
|
4
|
+
attr_reader :name
|
5
|
+
attr_reader :size
|
6
|
+
attr_reader :shareMode
|
7
|
+
attr_reader :owner
|
8
|
+
|
9
|
+
# Initialize the class passing a convenient linker reference and infos about the namespace
|
10
|
+
def initialize(linker,name,size,shareMode,owner)
|
11
|
+
@linker=linker
|
12
|
+
@name=name
|
13
|
+
@size=size
|
14
|
+
@shareMode=shareMode
|
15
|
+
@owner=owner
|
16
|
+
end
|
17
|
+
|
18
|
+
# Retrieve namespace's user list
|
19
|
+
def users?
|
20
|
+
if(@owner && @shareMode==:Private)
|
21
|
+
t_users=@linker.call("account","users",{"namespaces" => @name})
|
22
|
+
out=[]
|
23
|
+
if(t_users["status"].to_sym == :success)
|
24
|
+
t_users["users"].each_pair do |key,namespace_users|
|
25
|
+
out+=namespace_users
|
26
|
+
end
|
27
|
+
return out
|
28
|
+
else
|
29
|
+
return []
|
30
|
+
end
|
31
|
+
else
|
32
|
+
return []
|
33
|
+
end
|
34
|
+
namespaces?.reject {|key,value| !value.owner}
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
attr_accessor :linker
|
39
|
+
end
|
40
|
+
end
|
data/lib/linker.rb
ADDED
@@ -0,0 +1,52 @@
|
|
1
|
+
require "net/http"
|
2
|
+
require "net/http/post/multipart"
|
3
|
+
require 'mime/types'
|
4
|
+
require "uri"
|
5
|
+
require "json"
|
6
|
+
module Facer
|
7
|
+
|
8
|
+
# This class hold the main linkage to face.com
|
9
|
+
# acting as a gateway to subclasses
|
10
|
+
class Linker
|
11
|
+
# The main uri to face.com api.
|
12
|
+
FaceComURI="http://api.face.com/"
|
13
|
+
|
14
|
+
attr_reader :account
|
15
|
+
attr_reader :faces
|
16
|
+
|
17
|
+
# Initialize the linker with security informations
|
18
|
+
def initialize(applicationName,key,secret)
|
19
|
+
@account=Account.new(self,applicationName,key,secret)
|
20
|
+
@faces=Faces.new(self)
|
21
|
+
end
|
22
|
+
|
23
|
+
# Call the service appending security informations to every request
|
24
|
+
def call(bclass,method,params = {},files = nil)
|
25
|
+
params ||={}
|
26
|
+
params["api_key"]=@account.apiKey
|
27
|
+
params["api_secret"]=@account.apiSecret
|
28
|
+
resp=callAPI(bclass,method,params,files)
|
29
|
+
return resp
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
33
|
+
# Call the service using post or multiform data for sending files and transpose to json the response
|
34
|
+
def callAPI(bclass,method,params,files)
|
35
|
+
uri=URI.parse("#{FaceComURI}#{bclass}/#{method}.json")
|
36
|
+
params ||= {}
|
37
|
+
if(files)
|
38
|
+
files.each_pair do |name,path|
|
39
|
+
params[name]=UploadIO.new(path, MIME::Types.type_for(path))
|
40
|
+
end
|
41
|
+
req = Net::HTTP::Post::Multipart.new(uri.path,params)
|
42
|
+
res = Net::HTTP.start(uri.host, uri.port) do |http|
|
43
|
+
http.request(req)
|
44
|
+
end
|
45
|
+
return JSON.parse(res.body)
|
46
|
+
else
|
47
|
+
res = Net::HTTP.post_form(uri,params)
|
48
|
+
return JSON.parse(res.body)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
data/test/facer_test.rb
ADDED
metadata
ADDED
@@ -0,0 +1,110 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: facer
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 25
|
5
|
+
prerelease:
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 0
|
9
|
+
- 3
|
10
|
+
version: 0.0.3
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- Stefano Valicchia
|
14
|
+
autorequire:
|
15
|
+
bindir: bin
|
16
|
+
cert_chain: []
|
17
|
+
|
18
|
+
date: 2011-01-11 00:00:00 +01:00
|
19
|
+
default_executable:
|
20
|
+
dependencies:
|
21
|
+
- !ruby/object:Gem::Dependency
|
22
|
+
name: multipart-post
|
23
|
+
prerelease: false
|
24
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ">="
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
hash: 21
|
30
|
+
segments:
|
31
|
+
- 1
|
32
|
+
- 0
|
33
|
+
- 1
|
34
|
+
version: 1.0.1
|
35
|
+
type: :runtime
|
36
|
+
version_requirements: *id001
|
37
|
+
- !ruby/object:Gem::Dependency
|
38
|
+
name: json
|
39
|
+
prerelease: false
|
40
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ">="
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
hash: 11
|
46
|
+
segments:
|
47
|
+
- 1
|
48
|
+
- 4
|
49
|
+
- 6
|
50
|
+
version: 1.4.6
|
51
|
+
type: :runtime
|
52
|
+
version_requirements: *id002
|
53
|
+
description: Simple wrapper for face.com api.
|
54
|
+
email: stefano.valicchia@gmail.com
|
55
|
+
executables: []
|
56
|
+
|
57
|
+
extensions: []
|
58
|
+
|
59
|
+
extra_rdoc_files:
|
60
|
+
- Gemfile
|
61
|
+
- Manifest.txt
|
62
|
+
- README
|
63
|
+
files:
|
64
|
+
- lib/facer/account.rb
|
65
|
+
- lib/facer/faces.rb
|
66
|
+
- lib/facer/namespace.rb
|
67
|
+
- lib/facer.rb
|
68
|
+
- lib/linker.rb
|
69
|
+
- init.rb
|
70
|
+
- Manifest.txt
|
71
|
+
- Gemfile
|
72
|
+
- README
|
73
|
+
- test/facer_test.rb
|
74
|
+
has_rdoc: true
|
75
|
+
homepage:
|
76
|
+
licenses: []
|
77
|
+
|
78
|
+
post_install_message:
|
79
|
+
rdoc_options:
|
80
|
+
- --title
|
81
|
+
- Facer
|
82
|
+
require_paths:
|
83
|
+
- lib
|
84
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
85
|
+
none: false
|
86
|
+
requirements:
|
87
|
+
- - ">="
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
hash: 3
|
90
|
+
segments:
|
91
|
+
- 0
|
92
|
+
version: "0"
|
93
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
94
|
+
none: false
|
95
|
+
requirements:
|
96
|
+
- - ">="
|
97
|
+
- !ruby/object:Gem::Version
|
98
|
+
hash: 3
|
99
|
+
segments:
|
100
|
+
- 0
|
101
|
+
version: "0"
|
102
|
+
requirements:
|
103
|
+
- The gem uses multipart-post gem and JSON gem
|
104
|
+
rubyforge_project:
|
105
|
+
rubygems_version: 1.4.1
|
106
|
+
signing_key:
|
107
|
+
specification_version: 3
|
108
|
+
summary: Wrapper for face.com API.
|
109
|
+
test_files:
|
110
|
+
- test/facer_test.rb
|