facer 0.0.3
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.
- 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
|