karolinska 0.1.1 → 0.1.2
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 +4 -4
- data/lib/karolinska/cluster_request.rb +59 -0
- data/lib/karolinska/error.rb +16 -0
- data/lib/karolinska/fake.rb +5 -0
- data/lib/karolinska/feature_set.rb +425 -0
- data/lib/karolinska/feature_sets.rb +415 -0
- data/lib/karolinska/single_request.rb +71 -0
- data/lib/karolinska/test_set.rb +53 -0
- data/lib/karolinska/version.rb +1 -1
- metadata +8 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA1:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: bc54653db22d4ec980e3ae52664f2641f6457621
|
|
4
|
+
data.tar.gz: 31139b2b11bf17c530cf04c78725dbed0deb6d51
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: bd7f048729fec8caa7e7787d0519cdeaa14034e0530486b7e1c6417d1d2d17b44ee26cac9efdc9dc6a8c4557649d81dc66cfd22fbd708eece28b4dfd65339100
|
|
7
|
+
data.tar.gz: 6bc22d75a74574529d2d4cba01ef35f34065341c96d7a49afe1929dffc172b542edb2cea22ee74805c895fb5749ae8ed0ef45b7009f0998300f421b2786d0dae
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
module Karolinska
|
|
2
|
+
class ClusterRequest
|
|
3
|
+
|
|
4
|
+
include BenchmarkMethods
|
|
5
|
+
|
|
6
|
+
# benchmark :karolinska_request
|
|
7
|
+
|
|
8
|
+
require 'net/http/post/multipart'
|
|
9
|
+
|
|
10
|
+
ENDPOINT = 'http://35.161.196.215/Dps.aspx?SaveImagesAtServer=true&Timeout=30000'
|
|
11
|
+
PASSWORD = 'Karolinska'
|
|
12
|
+
|
|
13
|
+
def initialize(paths)
|
|
14
|
+
@paths = paths
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def start
|
|
18
|
+
url = URI.parse ENDPOINT
|
|
19
|
+
request = Net::HTTP::Post::Multipart.new url.path,
|
|
20
|
+
"file1" => UploadIO.new(@paths[:front], "image/jpeg", "front.jpg"),
|
|
21
|
+
"file2" => UploadIO.new(@paths[:left], "image/jpeg", "left.jpg"),
|
|
22
|
+
"file3" => UploadIO.new(@paths[:right], "image/jpeg", "right.jpg"),
|
|
23
|
+
"file4" => UploadIO.new(@paths[:up], "image/jpeg", "upward.jpg"),
|
|
24
|
+
"file5" => UploadIO.new(@paths[:down], "image/jpeg", "downward.jpg")
|
|
25
|
+
|
|
26
|
+
json, status = karolinska_request(request)
|
|
27
|
+
# Rails.logger.debug json
|
|
28
|
+
return [json, status]
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
private
|
|
32
|
+
|
|
33
|
+
def karolinska_request(request)
|
|
34
|
+
url = URI.parse ENDPOINT
|
|
35
|
+
response = Net::HTTP.start(url.host, url.port) do |http|
|
|
36
|
+
http.request(request)
|
|
37
|
+
end
|
|
38
|
+
rescue Timeout::Error => error
|
|
39
|
+
Rails.logger.error "#{error}".red
|
|
40
|
+
[nil, error]
|
|
41
|
+
else
|
|
42
|
+
|
|
43
|
+
case response
|
|
44
|
+
when Net::HTTPOK
|
|
45
|
+
unless response.body.blank?
|
|
46
|
+
[JSON.parse(response.body), 200]
|
|
47
|
+
else
|
|
48
|
+
Rails.logger.error "Karolinska returned an empty string".red
|
|
49
|
+
[{}, "Empty String"]
|
|
50
|
+
end
|
|
51
|
+
when Net::HTTPClientError, Net::HTTPInternalServerError, Net::HTTPBadResponse, Net::HTTPHeaderSyntaxError, Net::ProtocolError
|
|
52
|
+
msg = "#{response.class}: #{response.code}, #{response.message}"
|
|
53
|
+
Rails.logger.error msg.red
|
|
54
|
+
[{}, msg]
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# From Karolinska 2.2.2 documentation:
|
|
2
|
+
#
|
|
3
|
+
# 400 Bad Request. Bad format.
|
|
4
|
+
# 401 Unauthorized. Authorization error.
|
|
5
|
+
# 403 Forbidden. For example more than five posted images.
|
|
6
|
+
# 408 Request Timeout. Timeout exception.
|
|
7
|
+
# 501 Not Supported. For example not supported image type.
|
|
8
|
+
# 503 Service Unavailable. Web service is unavailable.
|
|
9
|
+
|
|
10
|
+
module Karolinska
|
|
11
|
+
class Error
|
|
12
|
+
class Base < StandardError; end
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
end
|
|
16
|
+
end
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
module Karolinska
|
|
2
|
+
module Fake
|
|
3
|
+
SET = {"AfroTexture"=>"misses", "Age"=>"15 - 25", "Cheekbones"=>"low (0,88)", "Cheeks"=>"wide (0,57)", "Chin"=>"oval (0,81)", "Corners"=>"up", "CrowFeet"=>"no", "Detected"=>true, "EarLeft"=>"misses", "EarRight"=>"misses", "EyeDistance"=>"normal (0,96)", "EyeSizeLeft"=>"normal (0,68)", "EyeSizeOpposed"=>"big (0,90)", "EyebrowDistance"=>"normal (0,28)", "EyebrowLeftEyedistance"=>"high (0,89)", "EyebrowRightEyedistance"=>"high (0,94)", "Eyecircles"=>"no", "Filtrum"=>"Visible (0.00)", "FiltrumAltitude"=>"high (0,31)", "FiltrumCurvature"=>"concave (0,95)", "Fitted"=>true, "Forehead_central"=>"misses", "Forehead_top"=>"misses", "Forehead_under"=>"misses", "Gender"=>"Male (0,73)", "HairGrade"=>"misses", "HairLength"=>"misses", "HairLow"=>"misses", "HairStretch"=>"misses", "HairStyle"=>"misses", "Iris"=>"normal (0,79)", "Jawbones"=>"normal (0,73)", "LeftCheekbone"=>"small (0,99)", "LeftEarChin"=>"misses", "LeftEarForehead"=>"misses", "LeftEarHeadDistance"=>"misses", "LeftEarLowerChin"=>"misses", "LeftEarNosebridge"=>"misses", "LeftEarNoseroot"=>"misses", "Lines"=>"yes (0.17)", "LipDistDecideBent"=>"straight (0,00)", "LowerLip"=>"thin (0,97)", "MouthSize"=>"normal (0,82)", "MouthWidth"=>"normal (0,21)", "NoseBridge_central"=>"misses", "NoseBridge_top"=>"misses", "NoseBridge_under"=>"misses", "NoseCurve"=>"curveless (0,86)", "NoseLength"=>"long (0,98)", "NoseNostrilsWidth"=>"normal (0,98)", "NoseSideWidth"=>"normal (0,73)", "NoseTipAltitude"=>"high (0,99)", "NoseTipWidthStretch"=>"wide (0,14)", "NoseWidth"=>"normal (0,98)", "OpposedCheekbone"=>"wide (1,00)", "OpposedEarChin"=>"misses", "OpposedEarForehead"=>"misses", "OpposedEarHeadDistance"=>"misses", "OpposedEarLowerChin"=>"misses", "OpposedEarNosebridge"=>"misses", "OpposedEarNoseroot"=>"misses", "UpperLip"=>"thin (0,54)", "VerticalEarDiff"=>"misses", "VerticalMagnitude"=>"normal", "WidthMagnitude"=>"small", "Wrinkle"=>"Visible (1.00)", "interest"=>"misses"}
|
|
4
|
+
end
|
|
5
|
+
end
|
|
@@ -0,0 +1,425 @@
|
|
|
1
|
+
module Karolinska
|
|
2
|
+
class FeatureSet < Struct.new( :raw, :view, :statuscode)
|
|
3
|
+
|
|
4
|
+
# Use Fakeset: Karolinska::Fake::SET
|
|
5
|
+
# fs = Karolinska::FeatureSet.new(Karolinska::Fake::SET, :front)
|
|
6
|
+
|
|
7
|
+
# => [#<struct Karolinska::FeatureSet raw={"Age"=>"30 - 40", "Cheekbones"=>"average (0,69)", "Cheeks"=>"normal (0,89)", "Chin"=>"oval (0,59)", "Corners"=>"straight", "CrowFeet"=>"yes (1.00)", "Detected"=>true, "EarL
|
|
8
|
+
# eft"=>"misses", "EarRight"=>"misses", "EyeDistance"=>"normal (0,93)", "EyeSizeLeft"=>"normal (0,66)", "EyeSizeOpposed"=>"small (0,78)", "EyebrowDistance"=>"normal (0,96)", "EyebrowLeftEyedistance"=>"high (0,67)", "
|
|
9
|
+
# EyebrowRightEyedistance"=>"average (0,91)", "Eyecircles"=>"no", "Filtrum"=>"Visible (0.00)", "FiltrumAltitude"=>"high (0,92)", "FiltrumCurvature"=>"fleet (0,82)", "Fitted"=>true, "Forehead_central"=>"misses", "Fore
|
|
10
|
+
# head_top"=>"misses", "Forehead_under"=>"misses", "Gender"=>"Female (0,96)", "HairLow"=>"misses", "Iris"=>"normal (0,71)", "Jawbones"=>"wide (0,48)", "LeftCheekbone"=>"wide (1,00)", "LeftEarChin"=>"misses", "LeftEar
|
|
11
|
+
# Forehead"=>"misses", "LeftEarHeadDistance"=>"misses", "LeftEarLowerChin"=>"misses", "LeftEarNosebridge"=>"misses", "LeftEarNoseroot"=>"misses", "Lines"=>"no", "LipDistDecideBent"=>"misses", "LowerLip"=>"thin (0,98)
|
|
12
|
+
# ", "MouthSize"=>"normal (0,15)", "MouthWidth"=>"small (0,78)", "NoseBridge_central"=>"misses", "NoseBridge_top"=>"misses", "NoseBridge_under"=>"misses", "NoseCurve"=>"convex (1,00)", "NoseLength"=>"normal (0,99)",
|
|
13
|
+
# "NoseNostrilsWidth"=>"normal (0,99)", "NoseSideWidth"=>"small (0,88)", "NoseTipAltitude"=>"average (0,92)", "NoseTipWidthStretch"=>"normal (0,85)", "NoseWidth"=>"small (0,87)", "OpposedCheekbone"=>"small (0,99)", "
|
|
14
|
+
# OpposedEarChin"=>"misses", "OpposedEarForehead"=>"misses", "OpposedEarHeadDistance"=>"misses", "OpposedEarLowerChin"=>"misses", "OpposedEarNosebridge"=>"misses", "OpposedEarNoseroot"=>"misses", "UpperLip"=>"medium
|
|
15
|
+
# (0,38)", "VerticalEarDiff"=>"misses", "VerticalMagnitude"=>"normal", "WidthMagnitude"=>"small", "Wrinkle"=>"Visible (0.63)", "interest"=>"misses"}, view=:left>]
|
|
16
|
+
|
|
17
|
+
# A feature description: "low (0,88)"
|
|
18
|
+
|
|
19
|
+
FEATURES = [:age,:center_forehead_width,:cheek_width,:cheeks_height,:cheeks_width,:chin_width,:chin_wrinkles,:crow_feet,:detected,:ear_chin_axis,:ear_lower_chin_axis,:ear_nosebridge_axis,:ear_noseroot_axis,:ear_noseroot_axis,:ear_protruding,:ear_size,:eye_size,:eyebrow_distance,:eyecircles,:eyes_distance,:face_strechiness,:face_width,:filtrum,:fitted,:forehead_protruding,:gender,:iris_orientation,:jaw_width,:left_cheek_width,:left_ear_chin_axis,:left_ear_lower_chin_axis,:left_ear_nosebridge_axis,:left_ear_noseroot_axis,:left_ear_protruding,:left_ear_size,:left_eye_size,:left_eyebrow_eye_distance,:left_forehead_protruding,:lower_forehead_width,:lower_lip_fullness,:mouth_size,:mouth_width,:mouthcorner_orientation,:nose_bottom_width,:nose_center_width,:nose_length,:nose_top_width,:nose_width,:nosetip_orientation,:nosetip_width,:nosewings_width,:nostrills_width,:pallium,:pallium_height,:prominence,:right_cheek_width,:right_ear_chin_axis,:right_ear_lower_chin_axis,:right_ear_nosebridge_axis,:right_ear_noseroot_axis,:right_ear_protruding,:right_ear_size,:right_eye_size,:right_forehead_protruding,:upper_forehead_width,:upper_lip_curvature,:upper_lip_fullness,:wrinkles]
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def to_hsh
|
|
23
|
+
FEATURES.inject({}){|hsh, m| hsh.update({m => self.send(m.to_s)} )}
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def detected
|
|
28
|
+
raw["Detected"] if raw
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
# Is the detected face fitted (true, false)
|
|
32
|
+
def fitted
|
|
33
|
+
raw["Fitted"] if raw
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
# The direction of the face (left, frontal face, right, upwards, downwards), inclusive certainty [0.0, 1.0]
|
|
37
|
+
# TODO not yet in the result string
|
|
38
|
+
|
|
39
|
+
# def face_direction
|
|
40
|
+
# rate raw["Gaze"]
|
|
41
|
+
# end
|
|
42
|
+
|
|
43
|
+
# obvious
|
|
44
|
+
def gender
|
|
45
|
+
rate raw["Gender"], strong: nil, average: nil, weak: nil
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
# obvious
|
|
49
|
+
def age
|
|
50
|
+
raw["Age"] if raw
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
# Prominence part (upper, central, lower) inclusive certainty [0.0, 1.0].
|
|
54
|
+
def prominence
|
|
55
|
+
rate raw["interest"], strong: "upper", average: "central", weak: "lower"
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
# Vertical hole between the nose and the upper border of the mouth (visible, notvisible) inclusive certainty [0.0, 1.0]
|
|
59
|
+
def filtrum
|
|
60
|
+
rate raw["Filtrum"], strong: "visible", average: nil, weak: "notvisible"
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
# Filtrum (pallium) curvature (convex, fleet, concave), inclusive certainty [0.0, 1.0]
|
|
64
|
+
def pallium
|
|
65
|
+
rate raw["FiltrumCurvature"], strong: "convex", average: "fleet", weak: "concave"
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
# filtrum (pallium) altitude (low, average, high), inclusive certainty [0.0, 1.0]
|
|
69
|
+
def pallium_height
|
|
70
|
+
rate raw["FiltrumAltitude"], strong: "high", average: "average", weak: "low"
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
# The distance between the eyebrows (close, normal, far apart), inclusive certainty [0.0, 1.0]
|
|
74
|
+
def eyebrow_distance
|
|
75
|
+
rate raw["EyebrowDistance"], strong: "far apart", average: "normal", weak: "close"
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
# The distance between the eyebrows and left eye (low, average, high), inclusive certainty [0.0, 1.0]
|
|
79
|
+
def left_eyebrow_eye_distance
|
|
80
|
+
rate raw["EyebrowLeftEyedistance"], strong: "high", average: "average", weak: "low"
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
# The distance between the eyebrows and right eye (low, average, high), inclusive certainty [0.0, 1.0]
|
|
84
|
+
def right_eyebrow_eye_distance
|
|
85
|
+
rate raw["EyebrowRightEyedistance"], strong: "high", average: "average", weak: "low"
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
# The size of the left eye (small, normal, big), inclusive certainty [0.0, 1.0]
|
|
89
|
+
def left_eye_size
|
|
90
|
+
rate raw["EyeSizeLeft"], strong: "big", average: "normal", weak: "small"
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
# The size of the right eye (small, normal, big), inclusive certainty [0.0, 1.0]
|
|
94
|
+
def right_eye_size
|
|
95
|
+
rate raw["EyeSizeOpposed"], strong: "big", average: "normal", weak: "small"
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
# Distance between the eyes (close, normal, far apart), inclusive certainty [0.0, 1.0]
|
|
99
|
+
def eyes_distance
|
|
100
|
+
rate raw["EyeDistance"], strong: "far apart", average: "normal", weak: "close"
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
# The stretchiness of the face (withdrawn, normal, stretched)
|
|
104
|
+
def face_strechiness
|
|
105
|
+
rate raw["VerticalMagnitude"], strong: "stretched", average: "normal", weak: "withdrawn"
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
# The width of the face (small, average, wide)
|
|
109
|
+
def face_width
|
|
110
|
+
rate raw["WidthMagnitude"], strong: "wide", average: "average", weak: "small"
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
# The width magnitude of the nose (small, normal, big), inclusive certainty [0.0, 1.0]
|
|
114
|
+
def nose_width
|
|
115
|
+
rate raw["NoseWidth"], strong: "big", average: "normal", weak: "small"
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
# The length magnitude of the nose (short, normal, long), inclusive certainty [0.0, 1.0]
|
|
119
|
+
def nose_length
|
|
120
|
+
rate raw["NoseLength"], strong: "long", average: "normal", weak: "short"
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
# Width of the nose upper bridge (small, normal, wide)
|
|
124
|
+
def nose_top_width
|
|
125
|
+
rate raw["NoseBridge_top"], strong: "wide", average: "normal", weak: "small"
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
# Width of the nose central bridge (small, normal, wide)
|
|
129
|
+
def nose_center_width
|
|
130
|
+
rate raw["NoseBridge_central"], strong: "wide", average: "normal", weak: "small"
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
# Width of the nose lower bridge (small, normal, wide)
|
|
134
|
+
def nose_bottom_width
|
|
135
|
+
rate raw["NoseBridge_under"], strong: "wide", average: "normal", weak: "small"
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
# Nose tip width stretch (small, normal, wide), inclusive certainty [0.0, 1.0]
|
|
139
|
+
def nostrills_width
|
|
140
|
+
rate raw["NoseNostrilsWidth"], strong: "wide", average: "normal", weak: "small"
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
# Nose tip width stretch (small, normal, wide), inclusive certainty [0.0, 1.0]
|
|
144
|
+
def nosetip_width
|
|
145
|
+
rate raw["NoseTipWidthStretch"], strong: "wide", average: "normal", weak: "small"
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
# Nose wings width (small, normal, wide), inclusive certainty [0.0, 1.0]
|
|
149
|
+
def nosewings_width
|
|
150
|
+
rate raw["NoseSideWidth"], strong: "wide", average: "normal", weak: "small"
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
def nosetip_orientation
|
|
154
|
+
rate raw["NoseTipAltitude"], strong: "convex", average: "normal", weak: "concave"
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
# Direction of the mouth corners (down, straight, up), inclusive certainty [0.0, 1.0]
|
|
158
|
+
def mouthcorner_orientation
|
|
159
|
+
rate raw["Corners"], strong: "wide", average: "normal", weak: "small"
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
# Size of the mouth (small, normal, big), inclusive certainty [0.0, 1.0]
|
|
163
|
+
def mouth_size
|
|
164
|
+
rate raw["MouthSize"], strong: "big", average: "normal", weak: "small"
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
# The width of the mouth (small, normal, big), inclusive certainty [0.0, 1.0]
|
|
168
|
+
def mouth_width
|
|
169
|
+
rate raw["MouthWidth"], strong: "big", average: "normal", weak: "small"
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
# Upper lip curvature (straight, light curved, deep curved), inclusive certainty [0.0, 1.0]
|
|
173
|
+
def upper_lip_curvature
|
|
174
|
+
rate raw["LipDistDecideBent"], strong: "deep curved", average: "light curved", weak: "straight"
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
# The thickness of the upper lip (thin, medium, full), inclusive certainty [0.0, 1.0]
|
|
178
|
+
def upper_lip_fullness
|
|
179
|
+
rate raw["UpperLip"], strong: "full", average: "medium", weak: "thin"
|
|
180
|
+
end
|
|
181
|
+
|
|
182
|
+
# The fullness of the lower lip (thin, medium, full), inclusive certainty [0.0, 1.0]
|
|
183
|
+
def lower_lip_fullness
|
|
184
|
+
rate raw["LowerLip"], strong: "full", average: "medium", weak: "thin"
|
|
185
|
+
end
|
|
186
|
+
|
|
187
|
+
# The appearance of the chin (round, oval, pointy tip), inclusive certainty [0.0, 1.0]
|
|
188
|
+
def chin_width
|
|
189
|
+
rate raw["Chin"], strong: "round", average: "oval", weak: "pointy tip"
|
|
190
|
+
end
|
|
191
|
+
|
|
192
|
+
# The appearance of the jawbones (narrow, normal, wide), inclusive certainty [0.0, 1.0]
|
|
193
|
+
def jaw_width
|
|
194
|
+
rate raw["Jawbones"], strong: "wide", average: "normal", weak: "narrow"
|
|
195
|
+
end
|
|
196
|
+
|
|
197
|
+
# The location of the cheekbones (low, average, high), inclusive certainty [0.0, 1.0]
|
|
198
|
+
def cheeks_height
|
|
199
|
+
rate raw["Cheekbones"], strong: "high", average: "average", weak: "low"
|
|
200
|
+
end
|
|
201
|
+
|
|
202
|
+
# The width of the left cheekbone (small, normal, wide), inclusive certainty [0.0, 1.0]
|
|
203
|
+
def left_cheek_width
|
|
204
|
+
rate raw["LeftCheekbone"], strong: "wide", average: "normal", weak: "small"
|
|
205
|
+
end
|
|
206
|
+
|
|
207
|
+
# The width of the right cheekbone (small, normal, wide), inclusive certainty [0.0, 1.0]
|
|
208
|
+
def right_cheek_width
|
|
209
|
+
rate raw["OpposedCheekbone"], strong: "wide", average: "normal", weak: "small"
|
|
210
|
+
end
|
|
211
|
+
|
|
212
|
+
# Width of both cheekbones (small, normal, wide) inclusive certainty [0.0, 1.0]
|
|
213
|
+
def cheeks_width
|
|
214
|
+
rate raw["Cheeks"], strong: "wide", average: "normal", weak: "small"
|
|
215
|
+
end
|
|
216
|
+
|
|
217
|
+
# Width of the upper third forehead (small, normal, wide)
|
|
218
|
+
def upper_forehead_width
|
|
219
|
+
rate raw["Forehead_top"], strong: "wide", average: "normal", weak: "small"
|
|
220
|
+
end
|
|
221
|
+
|
|
222
|
+
# Width of the central third forehead (small, normal, wide)
|
|
223
|
+
def center_forehead_width
|
|
224
|
+
rate raw["Forehead_central"], strong: "wide", average: "normal", weak: "small"
|
|
225
|
+
end
|
|
226
|
+
|
|
227
|
+
# Width of the lower third forehead (small, normal, wide)
|
|
228
|
+
def lower_forehead_width
|
|
229
|
+
rate raw["Forehead_under"], strong: "wide", average: "normal", weak: "small"
|
|
230
|
+
end
|
|
231
|
+
|
|
232
|
+
# The size of the left ear (small, normal, big)
|
|
233
|
+
def left_ear_size
|
|
234
|
+
rate raw["EarLeft"], strong: "big", average: "normal", weak: "small"
|
|
235
|
+
end
|
|
236
|
+
|
|
237
|
+
# The size of the right ear (small, normal, big)
|
|
238
|
+
def right_ear_size
|
|
239
|
+
rate raw["EarRight"], strong: "big", average: "normal", weak: "small"
|
|
240
|
+
end
|
|
241
|
+
|
|
242
|
+
# Vertical ear difference (left higher, equal, right higher)
|
|
243
|
+
# def ears_diff
|
|
244
|
+
# rate raw["VerticalEarDiff"]
|
|
245
|
+
# end
|
|
246
|
+
|
|
247
|
+
# Distance from average left ear center to chin (small, average, large)
|
|
248
|
+
def left_ear_chin_axis
|
|
249
|
+
rate raw["LeftEarChin"], strong: "large", average: "average", weak: "small"
|
|
250
|
+
end
|
|
251
|
+
|
|
252
|
+
# Distance from average right ear center to chin (small, average, large)
|
|
253
|
+
def right_ear_chin_axis
|
|
254
|
+
rate raw["OpposedEarChin"], strong: "large", average: "average", weak: "small"
|
|
255
|
+
end
|
|
256
|
+
|
|
257
|
+
# Distance from average left ear center to lower chin (small, average, large)
|
|
258
|
+
def left_ear_lower_chin_axis
|
|
259
|
+
rate raw["LeftEarLowerChin"], strong: "large", average: "average", weak: "small"
|
|
260
|
+
end
|
|
261
|
+
|
|
262
|
+
# Distance from average right ear center to lower chin (small, average, large)
|
|
263
|
+
def right_ear_lower_chin_axis
|
|
264
|
+
rate raw["OpposedEarLowerChin"], strong: "large", average: "average", weak: "small"
|
|
265
|
+
end
|
|
266
|
+
|
|
267
|
+
# Distance from average left ear center to nose upper bridge (small, average, large)
|
|
268
|
+
def left_ear_nosebridge_axis
|
|
269
|
+
rate raw["LeftEarNosebridge"], strong: "large", average: "average", weak: "small"
|
|
270
|
+
end
|
|
271
|
+
|
|
272
|
+
# istance from average right ear center to nose upper bridge (small, average, large)
|
|
273
|
+
def right_ear_nosebridge_axis
|
|
274
|
+
rate raw["OpposedEarNosebridge"], strong: "large", average: "average", weak: "small"
|
|
275
|
+
end
|
|
276
|
+
|
|
277
|
+
# Distance from average left ear center to nose root (small, average, large)
|
|
278
|
+
def left_ear_noseroot_axis
|
|
279
|
+
rate raw["LeftEarNoseroot"], strong: "large", average: "average", weak: "small"
|
|
280
|
+
end
|
|
281
|
+
|
|
282
|
+
# Distance from average right ear center to nose root (small, average, large)
|
|
283
|
+
def right_ear_noseroot_axis
|
|
284
|
+
rate raw["OpposedEarNoseroot"], strong: "large", average: "average", weak: "small"
|
|
285
|
+
end
|
|
286
|
+
|
|
287
|
+
# Distance from average left ear center to the forehead (small, average, large)
|
|
288
|
+
def left_forehead_protruding
|
|
289
|
+
rate raw["LeftEarForehead"], strong: "large", average: "average", weak: "small"
|
|
290
|
+
end
|
|
291
|
+
|
|
292
|
+
# Distance from average right ear center to the forehead (small, average, large)
|
|
293
|
+
def right_forehead_protruding
|
|
294
|
+
rate raw["OpposedEarForehead"], strong: "large", average: "average", weak: "small"
|
|
295
|
+
end
|
|
296
|
+
|
|
297
|
+
# Left ear distance from head (small, average, large)
|
|
298
|
+
def left_ear_protruding
|
|
299
|
+
rate raw["LeftEarHeadDistance"], strong: "large", average: "average", weak: "small"
|
|
300
|
+
end
|
|
301
|
+
|
|
302
|
+
# Right ear distance from head (small, average, large)
|
|
303
|
+
def right_ear_protruding
|
|
304
|
+
rate raw["OpposedEarHeadDistance"], strong: "large", average: "average", weak: "small"
|
|
305
|
+
end
|
|
306
|
+
|
|
307
|
+
# Chin wrinkle (visible, not visible) inclusive certainty [0.0, 1.0]
|
|
308
|
+
def chin_wrinkles
|
|
309
|
+
rate raw["Wrinkle"], strong: "visible", average: nil, weak: "not visible"
|
|
310
|
+
end
|
|
311
|
+
|
|
312
|
+
# Facial lines as exposed by laughing or in the case of wrinkles (yes, no)
|
|
313
|
+
def wrinkles
|
|
314
|
+
rate raw["Lines"], strong: "yes", average: "", weak: "no"
|
|
315
|
+
end
|
|
316
|
+
|
|
317
|
+
# Crow features near the outside of the eyes (yes, no) inclusive certainty [0.0, 1.0]
|
|
318
|
+
def crow_feet
|
|
319
|
+
rate raw["CrowFeet"], strong: "yes", average: nil, weak: "no"
|
|
320
|
+
end
|
|
321
|
+
|
|
322
|
+
# Iris (upward, normal, downward) inclusive certainty [0.0, 1.0]
|
|
323
|
+
def iris_orientation
|
|
324
|
+
rate raw["Iris"], strong: "upward", average: "normal", weak: "downward"
|
|
325
|
+
end
|
|
326
|
+
|
|
327
|
+
# Presence of eye circles below the eye location (no, light, heavy)
|
|
328
|
+
def eyecircles
|
|
329
|
+
rate raw["Eyecircles"], strong: "heavy", average: "light", weak: "no"
|
|
330
|
+
end
|
|
331
|
+
|
|
332
|
+
# viewindependet merges below this line:
|
|
333
|
+
|
|
334
|
+
def ear_noseroot_axis
|
|
335
|
+
choose_certain_side left_ear_noseroot_axis, right_ear_noseroot_axis
|
|
336
|
+
end
|
|
337
|
+
|
|
338
|
+
def eye_size
|
|
339
|
+
choose_certain_side left_eye_size, right_eye_size
|
|
340
|
+
end
|
|
341
|
+
|
|
342
|
+
def cheek_width
|
|
343
|
+
choose_certain_side left_cheek_width, right_cheek_width
|
|
344
|
+
end
|
|
345
|
+
|
|
346
|
+
def ear_size
|
|
347
|
+
choose_certain_side left_ear_size, right_ear_size
|
|
348
|
+
end
|
|
349
|
+
|
|
350
|
+
def ear_chin_axis
|
|
351
|
+
choose_certain_side left_ear_chin_axis, right_ear_chin_axis
|
|
352
|
+
end
|
|
353
|
+
|
|
354
|
+
def ear_lower_chin_axis
|
|
355
|
+
choose_certain_side left_ear_lower_chin_axis, right_ear_lower_chin_axis
|
|
356
|
+
end
|
|
357
|
+
|
|
358
|
+
def ear_nosebridge_axis
|
|
359
|
+
choose_certain_side left_ear_nosebridge_axis, right_ear_nosebridge_axis
|
|
360
|
+
end
|
|
361
|
+
|
|
362
|
+
def ear_noseroot_axis
|
|
363
|
+
choose_certain_side left_ear_noseroot_axis, right_ear_noseroot_axis
|
|
364
|
+
end
|
|
365
|
+
|
|
366
|
+
def forehead_protruding
|
|
367
|
+
choose_certain_side left_forehead_protruding, right_forehead_protruding
|
|
368
|
+
end
|
|
369
|
+
|
|
370
|
+
def ear_protruding
|
|
371
|
+
choose_certain_side left_ear_protruding, right_ear_protruding
|
|
372
|
+
end
|
|
373
|
+
|
|
374
|
+
|
|
375
|
+
private
|
|
376
|
+
|
|
377
|
+
# this method rates the analysation and groups it into values of strong / average / weak by attaching integer values of +1, 0 and -1.
|
|
378
|
+
def rate value, *args
|
|
379
|
+
return nil if value == "misses"
|
|
380
|
+
# {certainty: nil, strong: nil, average: nil, weak: nil, description: nil, strength: nil, weight: nil}
|
|
381
|
+
opts = args.extract_options!
|
|
382
|
+
|
|
383
|
+
raise StandardError.new "missing param :strong" if !opts.has_key?(:strong)
|
|
384
|
+
raise StandardError.new "missing param :average" if !opts.has_key?(:average)
|
|
385
|
+
raise StandardError.new "missing param :weak" if !opts.has_key?(:weak)
|
|
386
|
+
|
|
387
|
+
# autodetect certainty
|
|
388
|
+
has_certainty = !!value[/\(.+\)/]
|
|
389
|
+
|
|
390
|
+
|
|
391
|
+
out = Hash.new
|
|
392
|
+
if has_certainty
|
|
393
|
+
|
|
394
|
+
out[:certainty] = value[/(\d[,.]\d+)/].gsub(',', '.').to_f
|
|
395
|
+
out[:description] = value.remove(/.\(.+\)/)
|
|
396
|
+
else
|
|
397
|
+
out[:description] = value
|
|
398
|
+
end
|
|
399
|
+
|
|
400
|
+
out[:weight] = case out[:description].downcase
|
|
401
|
+
when (opts[:strong] || "").downcase then :strong rescue 0
|
|
402
|
+
when (opts[:average] || "").downcase then :average rescue false
|
|
403
|
+
when (opts[:weak] || "").downcase then :weak rescue false
|
|
404
|
+
end
|
|
405
|
+
out[:view] = view
|
|
406
|
+
out
|
|
407
|
+
end
|
|
408
|
+
|
|
409
|
+
def choose_certain_side left, right
|
|
410
|
+
if (!left.nil? && !right.nil?)
|
|
411
|
+
order = [left, right]
|
|
412
|
+
[left, right].sort_by {|side|
|
|
413
|
+
side[:certainty]
|
|
414
|
+
}
|
|
415
|
+
order.last
|
|
416
|
+
else
|
|
417
|
+
left || right
|
|
418
|
+
end
|
|
419
|
+
end
|
|
420
|
+
|
|
421
|
+
|
|
422
|
+
|
|
423
|
+
|
|
424
|
+
end
|
|
425
|
+
end
|
|
@@ -0,0 +1,415 @@
|
|
|
1
|
+
module Karolinska
|
|
2
|
+
|
|
3
|
+
require 'delegate'
|
|
4
|
+
|
|
5
|
+
class FeatureSets < DelegateClass(Array)
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
# fs = Karolinska::TestSet.test_monique
|
|
9
|
+
|
|
10
|
+
def to_hsh
|
|
11
|
+
Karolinska::FeatureSet::FEATURES.inject({}){|hsh, m| hsh.update({m => self.send(m.to_s)} )}
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def initialize(arr=[])
|
|
15
|
+
super(arr)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def front
|
|
19
|
+
@front || find{|fs| fs.view == :front}
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def up
|
|
23
|
+
@up || find{|fs| fs.view == :up}
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def down
|
|
27
|
+
@down || find{|fs| fs.view == :down}
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def left
|
|
31
|
+
@left || find{|fs| fs.view == :left}
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def right
|
|
35
|
+
@right || find{|fs| fs.view == :right}
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def without_error
|
|
39
|
+
collect{|fs| fs.statuscode == 200} || []
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def detected
|
|
43
|
+
self.inject({}){|h,s| h.update({s.view => s.detected}); h}
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# Is the detected face fitted (true, false)
|
|
47
|
+
def fitted
|
|
48
|
+
self.inject({}){|h,s| h.update({s.view => s.fitted}); h}
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def status
|
|
52
|
+
self.inject({}){|h,s| h.update({s.view => s.statuscode}); h}
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def views
|
|
56
|
+
self.collect(&:view)
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
# def face_direction
|
|
60
|
+
# rate raw["Gaze"]
|
|
61
|
+
# end
|
|
62
|
+
|
|
63
|
+
# we have a certainty value in gender, so we can preiorize it.
|
|
64
|
+
def gender
|
|
65
|
+
priorize(attribute: "gender", left:1, front:1, right:2, up:1, down:1)
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
# Without certainty value, guessing, that the front view has most precise estimation.
|
|
69
|
+
def age
|
|
70
|
+
front.age
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
# Prominence part (upper, central, lower) inclusive certainty [0.0, 1.0].
|
|
74
|
+
def prominence
|
|
75
|
+
priorize(attribute: "prominence")
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
# Vertical hole between the nose and the upper border of the mouth (visible, notvisible) inclusive certainty [0.0, 1.0]
|
|
79
|
+
def filtrum
|
|
80
|
+
priorize(attribute: "filtrum")
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
# Filtrum (pallium) curvature (convex, fleet, concave), inclusive certainty [0.0, 1.0]
|
|
84
|
+
def pallium
|
|
85
|
+
priorize(attribute: "pallium")
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
# filtrum (pallium) altitude (low, average, high), inclusive certainty [0.0, 1.0]
|
|
89
|
+
def pallium_height
|
|
90
|
+
priorize(attribute: "pallium_height")
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
# The distance between the eyebrows (close, normal, far apart), inclusive certainty [0.0, 1.0]
|
|
94
|
+
def eyebrow_distance
|
|
95
|
+
priorize(attribute: "eyebrow_distance")
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
# The distance between the eyebrows and left eye (low, average, high), inclusive certainty [0.0, 1.0]
|
|
99
|
+
def left_eyebrow_eye_distance
|
|
100
|
+
priorize(attribute: "left_eyebrow_eye_distance", left: 1, front: 2, right:3)
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
# The distance between the eyebrows and right eye (low, average, high), inclusive certainty [0.0, 1.0]
|
|
104
|
+
def right_eyebrow_eye_distance
|
|
105
|
+
priorize(attribute: "right_eyebrow_eye_distance", right: 1, front: 2, left:3 )
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
# The size of the left eye (small, normal, big), inclusive certainty [0.0, 1.0]
|
|
109
|
+
def left_eye_size
|
|
110
|
+
priorize(attribute: "left_eye_size", left: 1, front: 2, right:3)
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
# The size of the right eye (small, normal, big), inclusive certainty [0.0, 1.0]
|
|
114
|
+
def right_eye_size
|
|
115
|
+
priorize(attribute: "right_eye_size", right: 1, front: 2, left:3)
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
# Distance between the eyes (close, normal, far apart), inclusive certainty [0.0, 1.0]
|
|
119
|
+
def eyes_distance
|
|
120
|
+
priorize(attribute: "eyes_distance")
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
# The stretchiness of the face (withdrawn, normal, stretched)
|
|
124
|
+
def face_strechiness
|
|
125
|
+
priorize(attribute: "face_strechiness")
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
# The width of the face (small, average, wide)
|
|
129
|
+
def face_width
|
|
130
|
+
priorize(attribute: "face_width")
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
# The width magnitude of the nose (small, normal, big), inclusive certainty [0.0, 1.0]
|
|
134
|
+
def nose_width
|
|
135
|
+
priorize(attribute: "nose_width")
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
# The length magnitude of the nose (short, normal, long), inclusive certainty [0.0, 1.0]
|
|
139
|
+
def nose_length
|
|
140
|
+
priorize(attribute: "nose_length", right:1, left:1, front:2, up:3, down:3, )
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
# Width of the nose upper bridge (small, normal, wide)
|
|
144
|
+
def nose_top_width
|
|
145
|
+
priorize(attribute: "nose_top_width")
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
# Width of the nose central bridge (small, normal, wide)
|
|
149
|
+
def nose_center_width
|
|
150
|
+
priorize(attribute: "nose_center_width")
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
# Width of the nose lower bridge (small, normal, wide)
|
|
154
|
+
def nose_bottom_width
|
|
155
|
+
priorize(attribute: "nose_bottom_width")
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
# Nose tip width stretch (small, normal, wide), inclusive certainty [0.0, 1.0]
|
|
159
|
+
def nostrills_width
|
|
160
|
+
priorize(attribute: "nostrills_width")
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
# Nose tip width stretch (small, normal, wide), inclusive certainty [0.0, 1.0]
|
|
164
|
+
def nosetip_width
|
|
165
|
+
priorize(attribute: "nosetip_width")
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
# Nose wings width (small, normal, wide), inclusive certainty [0.0, 1.0]
|
|
169
|
+
def nosewings_width
|
|
170
|
+
priorize(attribute: "nosewings_width")
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
# Direction of the mouth corners (down, straight, up), inclusive certainty [0.0, 1.0]
|
|
174
|
+
def mouthcorner_orientation
|
|
175
|
+
priorize(attribute: "mouthcorner_orientation")
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
# Size of the mouth (small, normal, big), inclusive certainty [0.0, 1.0]
|
|
179
|
+
def mouth_size
|
|
180
|
+
priorize(attribute: "mouth_size")
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
# The width of the mouth (small, normal, big), inclusive certainty [0.0, 1.0]
|
|
184
|
+
def mouth_width
|
|
185
|
+
priorize(attribute: "mouth_width")
|
|
186
|
+
end
|
|
187
|
+
|
|
188
|
+
# Upper lip curvature (straight, light curved, deep curved), inclusive certainty [0.0, 1.0]
|
|
189
|
+
def upper_lip_curvature
|
|
190
|
+
priorize(attribute: "upper_lip_curvature")
|
|
191
|
+
end
|
|
192
|
+
|
|
193
|
+
# The thickness of the upper lip (thin, medium, full), inclusive certainty [0.0, 1.0]
|
|
194
|
+
def upper_lip_fullness
|
|
195
|
+
priorize(attribute: "upper_lip_fullness")
|
|
196
|
+
end
|
|
197
|
+
|
|
198
|
+
# The fullness of the lower lip (thin, medium, full), inclusive certainty [0.0, 1.0]
|
|
199
|
+
def lower_lip_fullness
|
|
200
|
+
priorize(attribute: "lower_lip_fullness")
|
|
201
|
+
end
|
|
202
|
+
|
|
203
|
+
# The appearance of the chin (round, oval, pointy tip), inclusive certainty [0.0, 1.0]
|
|
204
|
+
def chin_width
|
|
205
|
+
priorize(attribute: "chin_width")
|
|
206
|
+
end
|
|
207
|
+
|
|
208
|
+
# The appearance of the jawbones (narrow, normal, wide), inclusive certainty [0.0, 1.0]
|
|
209
|
+
def jaw_width
|
|
210
|
+
priorize(attribute: "jaw_width")
|
|
211
|
+
end
|
|
212
|
+
|
|
213
|
+
# The location of the cheekbones (low, average, high), inclusive certainty [0.0, 1.0]
|
|
214
|
+
def cheeks_height
|
|
215
|
+
priorize(attribute: "cheeks_height")
|
|
216
|
+
end
|
|
217
|
+
|
|
218
|
+
# The width of the left cheekbone (small, normal, wide), inclusive certainty [0.0, 1.0]
|
|
219
|
+
def left_cheek_width
|
|
220
|
+
priorize(attribute: "left_cheek_width")
|
|
221
|
+
end
|
|
222
|
+
|
|
223
|
+
# The width of the right cheekbone (small, normal, wide), inclusive certainty [0.0, 1.0]
|
|
224
|
+
def right_cheek_width
|
|
225
|
+
priorize(attribute: "right_cheek_width")
|
|
226
|
+
end
|
|
227
|
+
|
|
228
|
+
# Width of both cheekbones (small, normal, wide) inclusive certainty [0.0, 1.0]
|
|
229
|
+
def cheeks_width
|
|
230
|
+
priorize(attribute: "cheeks_width")
|
|
231
|
+
end
|
|
232
|
+
|
|
233
|
+
# Width of the upper third forehead (small, normal, wide)
|
|
234
|
+
def upper_forehead_width
|
|
235
|
+
priorize(attribute: "upper_forehead_width")
|
|
236
|
+
end
|
|
237
|
+
|
|
238
|
+
# Width of the central third forehead (small, normal, wide)
|
|
239
|
+
def center_forehead_width
|
|
240
|
+
priorize(attribute: "center_forehead_width")
|
|
241
|
+
end
|
|
242
|
+
|
|
243
|
+
# Width of the lower third forehead (small, normal, wide)
|
|
244
|
+
def lower_forehead_width
|
|
245
|
+
priorize(attribute: "lower_forehead_width")
|
|
246
|
+
end
|
|
247
|
+
|
|
248
|
+
# The size of the left ear (small, normal, big)
|
|
249
|
+
def left_ear_size
|
|
250
|
+
priorize(attribute: "left_ear_size")
|
|
251
|
+
end
|
|
252
|
+
|
|
253
|
+
# The size of the right ear (small, normal, big)
|
|
254
|
+
def right_ear_size
|
|
255
|
+
priorize(attribute: "right_ear_size")
|
|
256
|
+
end
|
|
257
|
+
|
|
258
|
+
# Vertical ear difference (left higher, equal, right higher)
|
|
259
|
+
# def ears_diff
|
|
260
|
+
# rate raw["VerticalEarDiff"]
|
|
261
|
+
# end
|
|
262
|
+
|
|
263
|
+
# Distance from average left ear center to chin (small, average, large)
|
|
264
|
+
def left_ear_chin_axis
|
|
265
|
+
priorize(attribute: "left_ear_chin_axis", left:1, front:2, right:3)
|
|
266
|
+
end
|
|
267
|
+
|
|
268
|
+
# Distance from average right ear center to chin (small, average, large)
|
|
269
|
+
def right_ear_chin_axis
|
|
270
|
+
priorize(attribute: "right_ear_chin_axis", right:1, front:2, left:3)
|
|
271
|
+
end
|
|
272
|
+
|
|
273
|
+
# Distance from average left ear center to lower chin (small, average, large)
|
|
274
|
+
def left_ear_lower_chin_axis
|
|
275
|
+
priorize(attribute: "left_ear_lower_chin_axis", left:1, front:2, right:3)
|
|
276
|
+
end
|
|
277
|
+
|
|
278
|
+
# Distance from average right ear center to lower chin (small, average, large)
|
|
279
|
+
def right_ear_lower_chin_axis
|
|
280
|
+
priorize(attribute: "right_ear_lower_chin_axis", right:1, front:2, left:3)
|
|
281
|
+
end
|
|
282
|
+
|
|
283
|
+
# Distance from average left ear center to nose upper bridge (small, average, large)
|
|
284
|
+
def left_ear_nosebridge_axis
|
|
285
|
+
priorize(attribute: "left_ear_nosebridge_axis", left:1, front:2, right:3)
|
|
286
|
+
end
|
|
287
|
+
|
|
288
|
+
# istance from average right ear center to nose upper bridge (small, average, large)
|
|
289
|
+
def right_ear_nosebridge_axis
|
|
290
|
+
priorize(attribute: "right_ear_nosebridge_axis", right:1, front:2, left:3)
|
|
291
|
+
end
|
|
292
|
+
|
|
293
|
+
# Distance from average left ear center to nose root (small, average, large)
|
|
294
|
+
def left_ear_noseroot_axis
|
|
295
|
+
priorize(attribute: "left_ear_noseroot_axis", left:1, front:2, right:3)
|
|
296
|
+
end
|
|
297
|
+
|
|
298
|
+
# Distance from average right ear center to nose root (small, average, large)
|
|
299
|
+
def right_ear_noseroot_axis
|
|
300
|
+
priorize(attribute: "right_ear_noseroot_axis", right:1, front:2, left:3)
|
|
301
|
+
end
|
|
302
|
+
|
|
303
|
+
# Distance from average left ear center to the forehead (small, average, large)
|
|
304
|
+
def forehead_protruding
|
|
305
|
+
priorize(attribute: "forehead_protruding", right:1, left:2, front:3)
|
|
306
|
+
end
|
|
307
|
+
|
|
308
|
+
# Left ear distance from head (small, average, large)
|
|
309
|
+
def left_ear_protruding
|
|
310
|
+
priorize(attribute: "left_ear_protruding")
|
|
311
|
+
end
|
|
312
|
+
|
|
313
|
+
# Chin wrinkle (visible, not visible) inclusive certainty [0.0, 1.0]
|
|
314
|
+
def chin_wrinkles
|
|
315
|
+
priorize(attribute: "chin_wrinkles")
|
|
316
|
+
end
|
|
317
|
+
|
|
318
|
+
# Facial lines as exposed by laughing or in the case of wrinkles (yes, no)
|
|
319
|
+
def wrinkles
|
|
320
|
+
priorize(attribute: "wrinkles")
|
|
321
|
+
end
|
|
322
|
+
|
|
323
|
+
# Crow features near the outside of the eyes (yes, no) inclusive certainty [0.0, 1.0]
|
|
324
|
+
def crow_feet
|
|
325
|
+
priorize(attribute: "crow_feet")
|
|
326
|
+
end
|
|
327
|
+
|
|
328
|
+
# Iris (upward, normal, downward) inclusive certainty [0.0, 1.0]
|
|
329
|
+
def iris_orientation
|
|
330
|
+
priorize(attribute: "iris_orientation")
|
|
331
|
+
end
|
|
332
|
+
|
|
333
|
+
# Presence of eye circles below the eye location (no, light, heavy)
|
|
334
|
+
def eyecircles
|
|
335
|
+
priorize(attribute: "eyecircles")
|
|
336
|
+
end
|
|
337
|
+
|
|
338
|
+
def nosetip_orientation
|
|
339
|
+
priorize(attribute: "nosetip_orientation")
|
|
340
|
+
end
|
|
341
|
+
|
|
342
|
+
def left_forehead_protruding
|
|
343
|
+
priorize(attribute: "left_forehead_protruding", left:1, front:2, right:3)
|
|
344
|
+
end
|
|
345
|
+
|
|
346
|
+
def right_forehead_protruding
|
|
347
|
+
priorize(attribute: "right_forehead_protruding", right:3, front:2, left:1)
|
|
348
|
+
end
|
|
349
|
+
|
|
350
|
+
def right_ear_protruding
|
|
351
|
+
priorize(attribute: "right_ear_protruding", right:3, front:2, left:1)
|
|
352
|
+
end
|
|
353
|
+
|
|
354
|
+
def ear_noseroot_axis
|
|
355
|
+
priorize(attribute: "ear_noseroot_axis", left:1, front:2, right:1)
|
|
356
|
+
end
|
|
357
|
+
|
|
358
|
+
def eye_size
|
|
359
|
+
priorize(attribute: "ear_noseroot_axis")
|
|
360
|
+
end
|
|
361
|
+
|
|
362
|
+
def cheek_width
|
|
363
|
+
priorize(attribute: "ear_noseroot_axis")
|
|
364
|
+
end
|
|
365
|
+
|
|
366
|
+
def ear_size
|
|
367
|
+
priorize(attribute: "ear_size")
|
|
368
|
+
end
|
|
369
|
+
|
|
370
|
+
def ear_chin_axis
|
|
371
|
+
priorize(attribute: "ear_size")
|
|
372
|
+
end
|
|
373
|
+
|
|
374
|
+
def ear_lower_chin_axis
|
|
375
|
+
priorize(attribute: "ear_size")
|
|
376
|
+
end
|
|
377
|
+
|
|
378
|
+
def ear_nosebridge_axis
|
|
379
|
+
priorize(attribute: "ear_nosebridge_axis")
|
|
380
|
+
end
|
|
381
|
+
|
|
382
|
+
def ear_protruding
|
|
383
|
+
priorize(attribute: "ear_protruding")
|
|
384
|
+
end
|
|
385
|
+
|
|
386
|
+
|
|
387
|
+
private
|
|
388
|
+
|
|
389
|
+
# priorize the features by estimated view logically, secondly on the certainty of the given attribute
|
|
390
|
+
# def priorize(*args)
|
|
391
|
+
# prios = {front: 1, left: 2, right: 2, up: 3, down:3}
|
|
392
|
+
# @prios = prios.update(args.extract_options!)
|
|
393
|
+
# raise StandardError.new "missing param :attribute" if !prios.has_key?(:attribute)
|
|
394
|
+
# self.sort_by!{ |fs| [@prios[fs.view], (fs.send(@prios[:attribute])[:certainty] rescue 1) ] }
|
|
395
|
+
# self.first.send(@prios[:attribute]) rescue nil
|
|
396
|
+
# end
|
|
397
|
+
|
|
398
|
+
def priorize(*args)
|
|
399
|
+
@prios = {front: 1, left: 2, right: 2, up: 3, down:3}.update(args.extract_options!)
|
|
400
|
+
raise Karolinska::Error::Base.new "missing param :attribute" if !@prios.has_key?(:attribute)
|
|
401
|
+
method = @prios.delete(:attribute)
|
|
402
|
+
sorted_views = Hash[@prios.sort_by{ |_, v| -v }.reverse].keys
|
|
403
|
+
sorted_views = sorted_views & views
|
|
404
|
+
|
|
405
|
+
feature_values = sorted_views.collect do |view|
|
|
406
|
+
self.send(view).send(method)
|
|
407
|
+
end
|
|
408
|
+
|
|
409
|
+
feature_values.compact.first
|
|
410
|
+
|
|
411
|
+
end
|
|
412
|
+
|
|
413
|
+
|
|
414
|
+
end
|
|
415
|
+
end
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
module Karolinska
|
|
2
|
+
class SingleRequest
|
|
3
|
+
|
|
4
|
+
include BenchmarkMethods
|
|
5
|
+
|
|
6
|
+
benchmark :karolinska_request
|
|
7
|
+
|
|
8
|
+
require 'net/http/post/multipart'
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
ENDPOINT = 'http://92.111.221.231:85/Fid.aspx'
|
|
12
|
+
PASSWORD = 'Karolinska'
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def initialize(path, view)
|
|
16
|
+
@path = path
|
|
17
|
+
@view = case view
|
|
18
|
+
when :front
|
|
19
|
+
"Frontal"
|
|
20
|
+
when :left
|
|
21
|
+
"Left"
|
|
22
|
+
when :right
|
|
23
|
+
"Right"
|
|
24
|
+
when :up
|
|
25
|
+
"Upward"
|
|
26
|
+
when :down
|
|
27
|
+
"Downward"
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def start
|
|
32
|
+
url = URI.parse ENDPOINT
|
|
33
|
+
request = Net::HTTP::Post::Multipart.new url.path,
|
|
34
|
+
"file" => UploadIO.new(@path, "image/jpeg", "image.jpg"),
|
|
35
|
+
"Sid" => PASSWORD,
|
|
36
|
+
"View" => @view
|
|
37
|
+
|
|
38
|
+
json, status = karolinska_request(request)
|
|
39
|
+
# Rails.logger.debug json
|
|
40
|
+
return [json, status]
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
private
|
|
44
|
+
|
|
45
|
+
def karolinska_request(request)
|
|
46
|
+
url = URI.parse ENDPOINT
|
|
47
|
+
response = Net::HTTP.start(url.host, url.port) do |http|
|
|
48
|
+
http.request(request)
|
|
49
|
+
end
|
|
50
|
+
rescue Timeout::Error => error
|
|
51
|
+
Rails.logger.error "#{error}".red
|
|
52
|
+
[nil, error]
|
|
53
|
+
else
|
|
54
|
+
|
|
55
|
+
case response
|
|
56
|
+
when Net::HTTPOK
|
|
57
|
+
unless response.body.blank?
|
|
58
|
+
[JSON.parse(response.body), 200]
|
|
59
|
+
else
|
|
60
|
+
Rails.logger.error "Karolinska returned an empty string".red
|
|
61
|
+
[{}, "Empty String"]
|
|
62
|
+
end
|
|
63
|
+
when Net::HTTPClientError, Net::HTTPInternalServerError, Net::HTTPBadResponse, Net::HTTPHeaderSyntaxError, Net::ProtocolError
|
|
64
|
+
msg = "#{response.class}: #{response.code}, #{response.message}"
|
|
65
|
+
Rails.logger.error msg.red
|
|
66
|
+
[{}, msg]
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
end
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
module Karolinska
|
|
2
|
+
module TestSet
|
|
3
|
+
|
|
4
|
+
# usage: Karolinska::TestSet.test_sander
|
|
5
|
+
|
|
6
|
+
FILESLOC = "./test/fixtures/files"
|
|
7
|
+
|
|
8
|
+
class Person < Struct.new(:name, :res)
|
|
9
|
+
|
|
10
|
+
def paths
|
|
11
|
+
{
|
|
12
|
+
front: "#{FILESLOC}/#{name}/#{res}/front.jpg",
|
|
13
|
+
left: "#{FILESLOC}/#{name}/#{res}/left.jpg",
|
|
14
|
+
right: "#{FILESLOC}/#{name}/#{res}/right.jpg",
|
|
15
|
+
up: "#{FILESLOC}/#{name}/#{res}/up.jpg",
|
|
16
|
+
down: "#{FILESLOC}/#{name}/#{res}/down.jpg"
|
|
17
|
+
}
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# usage: Karolinska::TestSet.test_peter
|
|
23
|
+
def self.test_peter
|
|
24
|
+
paths = Person.new("peter", "highres").paths
|
|
25
|
+
paths.delete(:up)
|
|
26
|
+
paths.delete(:down)
|
|
27
|
+
Karolinska::Scan.new(paths).connect
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
# usage: Karolinska::TestSet.test_sander
|
|
31
|
+
def self.test_sander
|
|
32
|
+
Karolinska::Scan.new(Person.new("sander", "lowres").paths).connect
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# usage: Karolinska::TestSet.test_monique
|
|
36
|
+
def self.test_monique
|
|
37
|
+
Karolinska::Scan.new(Person.new("monique", "lowerres").paths).connect(true)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def self.test_marcus
|
|
41
|
+
Karolinska::Scan.new(Person.new("marcus", "lowerres").paths).connect
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def self.test_marieke
|
|
45
|
+
Karolinska::Scan.new(Person.new("marieke", "lowerres").paths).connect
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def self.test_chris
|
|
49
|
+
Karolinska::Scan.new(Person.new("chris", "lowres").paths).connect
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
end
|
|
53
|
+
end
|
data/lib/karolinska/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: karolinska
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.1.
|
|
4
|
+
version: 0.1.2
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Sebastian Arcila Valenzuela
|
|
@@ -69,6 +69,13 @@ files:
|
|
|
69
69
|
- bin/setup
|
|
70
70
|
- karolinska.gemspec
|
|
71
71
|
- lib/karolinska.rb
|
|
72
|
+
- lib/karolinska/cluster_request.rb
|
|
73
|
+
- lib/karolinska/error.rb
|
|
74
|
+
- lib/karolinska/fake.rb
|
|
75
|
+
- lib/karolinska/feature_set.rb
|
|
76
|
+
- lib/karolinska/feature_sets.rb
|
|
77
|
+
- lib/karolinska/single_request.rb
|
|
78
|
+
- lib/karolinska/test_set.rb
|
|
72
79
|
- lib/karolinska/version.rb
|
|
73
80
|
homepage: http://your.mom
|
|
74
81
|
licenses: []
|