karolinska 0.1.1 → 0.1.2
Sign up to get free protection for your applications and to get access to all the features.
- 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: []
|