cloud_vision 1.0.3 → 1.0.4

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: f96c737ee30e5451e3c9a8ed5af6d6052de76f61
4
- data.tar.gz: 1d193a4bfa49f637616383b4a2468cc1d386df3d
3
+ metadata.gz: b9f762023e7140a0e2065bb1a99eca0e2abfec0c
4
+ data.tar.gz: bd64be2c0f64957c6d003884c6850dbcb218bb18
5
5
  SHA512:
6
- metadata.gz: f94ddf2341bc6ec97631a2f1e6ec8aa765d13b7e98965aa36c410241ae0cc1d9adb70a04cc1609ed439a3951cc05a1694f3d30e6ba92a6eb5264e5cc64575506
7
- data.tar.gz: f5e8dfca2d49756af027377640487ae19556b48d02b3025e73a62aad8592f9e5211bbd0687f5a317a72464fab1308493e7bab2079a49e1b0911ba52cf9fe2345
6
+ metadata.gz: 08f5fba82c324a7856d031a398716e79af8f3ce07e3b80a5928feb9d4aeb120584031755640a81ad35c5c45fede20f112f18b87fe003cd2f7d9cf0866ae64610
7
+ data.tar.gz: e7c29cb28fc49b26af410bc20cc0ba5586bc76aedce0ac37990fbc8b822c557c1ee1623266cf2e2583c1a15754341854a58a6131aea41ff19ac536bc1d1dff2e
@@ -0,0 +1,12 @@
1
+ module CloudVision
2
+ SAFETY_TEST = :safety
3
+ FACIAL_TEST = :faces
4
+ LABEL_TEST = :labels
5
+ TEXT_TEST = :text
6
+ LOGO_TEST = :logos
7
+ LANDMARK_TEST = :landmarks
8
+ PROPERTIES_TEST = :properties
9
+
10
+ require_relative 'cloud_vision/api'
11
+ require_relative 'cloud_vision/parser'
12
+ end
@@ -0,0 +1,94 @@
1
+ require 'net/https'
2
+ require 'base64'
3
+ require 'json'
4
+
5
+ module CloudVision
6
+ class Api
7
+ def initialize( api_key )
8
+ @uri = URI( "https://vision.googleapis.com/v1/images:annotate?key=#{api_key}" )
9
+
10
+ @cloud_vision = Net::HTTP.new( @uri.host, @uri.port )
11
+ @cloud_vision.use_ssl = true
12
+ end
13
+
14
+ def analyze( image_file, tests, options={} )
15
+ post_data = {
16
+ requests: [ {
17
+ image: {
18
+ content: Base64.strict_encode64( image_file.read )
19
+ },
20
+ features: build_feature_requests( tests )
21
+ } ]
22
+ }
23
+
24
+ response = send_request( post_data )
25
+
26
+ return_format = response.body
27
+
28
+ if return_format && !return_format.empty?
29
+ return_format = JSON.parse( return_format )
30
+ return_format = return_format[ 'responses' ].first
31
+ end
32
+
33
+ return_format
34
+ end
35
+
36
+ private
37
+
38
+ def send_request( body )
39
+ request = Net::HTTP::Post.new( @uri, {'Content-Type' => 'application/json'} )
40
+ request.body = JSON.generate( body )
41
+
42
+ @cloud_vision.request( request )
43
+ end
44
+
45
+ def build_feature_requests( tests )
46
+ features = []
47
+
48
+ if !tests.is_a?( Array )
49
+ tests = [ tests ]
50
+ end
51
+
52
+ tests.each do |detection_test|
53
+ filters = []
54
+
55
+ detection_test = detection_test.to_sym
56
+ if detection_test == FACIAL_TEST || detection_test == :all
57
+ filters << { type: 'FACE_DETECTION', max_results: 10 }
58
+ end
59
+
60
+ if detection_test == TEXT_TEST || detection_test == :all
61
+ filters << { type: 'TEXT_DETECTION', max_results: 10 }
62
+ end
63
+
64
+ if detection_test == LABEL_TEST || detection_test == :all
65
+ filters << { type: 'LABEL_DETECTION', max_results: 10 }
66
+ end
67
+
68
+ if detection_test == LOGO_TEST || detection_test == :all
69
+ filters << { type: 'LOGO_DETECTION', max_results: 10 }
70
+ end
71
+
72
+ if detection_test == LANDMARK_TEST || detection_test == :all
73
+ filters << { type: 'LANDMARK_DETECTION', max_results: 10 }
74
+ end
75
+
76
+ if detection_test == SAFETY_TEST || detection_test == :all
77
+ filters << { type: 'SAFE_SEARCH_DETECTION', max_results: 1 }
78
+ end
79
+
80
+ if detection_test == PROPERTIES_TEST || detection_test == :all
81
+ filters << { type: 'IMAGE_PROPERTIES', max_results: 1 }
82
+ end
83
+
84
+ if filters.empty?
85
+ raise( "Unrecognized test: #{detection_test.inspect}")
86
+ end
87
+
88
+ features += filters
89
+ end
90
+
91
+ features
92
+ end
93
+ end
94
+ end
@@ -0,0 +1,188 @@
1
+ require 'json'
2
+
3
+ module CloudVision
4
+ class Parser
5
+ RESPONSE_LABELS = {
6
+ SAFETY_TEST => 'safeSearchAnnotation',
7
+ FACIAL_TEST => 'faceAnnotations',
8
+ LABEL_TEST => 'labelAnnotations',
9
+ TEXT_TEST => 'textAnnotations',
10
+ LOGO_TEST => 'logoAnnotations',
11
+ LANDMARK_TEST => 'landmarkAnnotations',
12
+ PROPERTIES_TEST => 'imagePropertiesAnnotation'
13
+ }.freeze
14
+
15
+ RESPONSE_SCALE = {
16
+ 'VERY_UNLIKELY' => -2,
17
+ 'UNLIKELY' => -1,
18
+ 'UNKNOWN' => 0,
19
+ 'POSSIBLE' => 1,
20
+ 'LIKELY' => 2,
21
+ 'VERY_LIKELY' => 3
22
+ }.freeze
23
+
24
+ def self.parse_analysis( analysis )
25
+ parsed_data = {}
26
+
27
+ if analysis && analysis.is_a?( String )
28
+ analysis = JSON.parse( analysis )
29
+ elsif !analysis || !analysis.is_a?( Hash )
30
+ raise( 'Parsing Failed. Analysis must be valid JSON' )
31
+ end
32
+
33
+ if analysis[ RESPONSE_LABELS[SAFETY_TEST] ]
34
+ new_data = parse_safety( analysis )
35
+ parsed_data[ SAFETY_TEST ] = new_data
36
+ end
37
+
38
+ if analysis[ RESPONSE_LABELS[FACIAL_TEST] ]
39
+ new_data = parse_faces( analysis )
40
+ parsed_data[ FACIAL_TEST ] = new_data
41
+ end
42
+
43
+ if analysis[ RESPONSE_LABELS[LABEL_TEST] ]
44
+ new_data = parse_entity( analysis, LABEL_TEST )
45
+ parsed_data[ LABEL_TEST ] = new_data
46
+ end
47
+
48
+ if analysis[ RESPONSE_LABELS[TEXT_TEST] ]
49
+ new_data = parse_entity( analysis, TEXT_TEST )
50
+ parsed_data[ TEXT_TEST ] = new_data
51
+ end
52
+
53
+ if analysis[ RESPONSE_LABELS[LOGO_TEST] ]
54
+ new_data = parse_entity( analysis, LOGO_TEST )
55
+ parsed_data[ LOGO_TEST ] = new_data
56
+ end
57
+
58
+ if analysis[ RESPONSE_LABELS[LANDMARK_TEST] ]
59
+ new_data = parse_entity( analysis, LANDMARK_TEST )
60
+ parsed_data[ LANDMARK_TEST ] = new_data
61
+ end
62
+
63
+ if analysis[ RESPONSE_LABELS[PROPERTIES_TEST] ]
64
+ new_data = parse_properties( analysis )
65
+ parsed_data[ PROPERTIES_TEST ] = new_data
66
+ end
67
+
68
+ parsed_data
69
+ end
70
+
71
+ def self.parse_safety( analysis )
72
+ processed_data = {}
73
+
74
+ if analysis[ RESPONSE_LABELS[SAFETY_TEST] ]
75
+ analysis[ RESPONSE_LABELS[SAFETY_TEST] ].each do |risk_test, value|
76
+ processed_data[ risk_test.to_sym ] = RESPONSE_SCALE[ value ]
77
+ end
78
+ end
79
+
80
+ processed_data
81
+ end
82
+
83
+ def self.parse_faces( analysis )
84
+ processed_data = []
85
+
86
+ if analysis[ RESPONSE_LABELS[FACIAL_TEST] ]
87
+ analysis[ RESPONSE_LABELS[FACIAL_TEST] ].each do |face_data|
88
+ annotations = {}
89
+
90
+ # Only include face data for users with 4 bounding points
91
+ if face_data['boundingPoly']['vertices'].length == 4
92
+ top_left = face_data['boundingPoly']['vertices'][ 0 ]
93
+ bottom_right = face_data['boundingPoly']['vertices'][ 2 ]
94
+
95
+ annotations[ :face ] = {
96
+ x: top_left['x'],
97
+ y: top_left['y'],
98
+ width: bottom_right['x'].to_i - top_left['x'].to_i,
99
+ height: bottom_right['y'].to_i - top_left['y'].to_i
100
+ }
101
+ end
102
+
103
+ # Find the confidence in the image parse
104
+ annotations[ :confidence ] = face_data[ 'detectionConfidence' ]
105
+
106
+ # Store the image quality metrics
107
+ annotations[ :quality ] = {
108
+ under_exposed: RESPONSE_SCALE[ face_data['underExposedLikelihood'] ],
109
+ blurred: RESPONSE_SCALE[ face_data['blurredLikelihood'] ],
110
+ headwear: RESPONSE_SCALE[ face_data['headwearLikelihood'] ]
111
+ }
112
+
113
+ # Parse the sentiment analysis data
114
+ annotations[ :sentiment ] = {
115
+ joy: RESPONSE_SCALE[ face_data['joyLikelihood'] ],
116
+ sorrow: RESPONSE_SCALE[ face_data['sorrowLikelihood'] ],
117
+ anger: RESPONSE_SCALE[ face_data['angerLikelihood'] ],
118
+ surprise: RESPONSE_SCALE[ face_data['surpriseLikelihood'] ]
119
+ }
120
+
121
+ processed_data << annotations
122
+ end
123
+ end
124
+
125
+ processed_data
126
+ end
127
+
128
+ def self.parse_entity( analysis, target )
129
+ processed_data = []
130
+
131
+ if analysis[ RESPONSE_LABELS[target] ]
132
+ analysis[ RESPONSE_LABELS[target] ].each do |label_data|
133
+ entity_data = {
134
+ description: label_data[ 'description' ],
135
+ locale: label_data[ 'locale' ],
136
+ score: label_data[ 'score' ].to_f * 100,
137
+ confidence: label_data[ 'confidence' ].to_f * 100,
138
+ relevance: label_data[ 'topicality' ].to_f * 100
139
+ }
140
+
141
+ # Some entity responses do not report confidence or relevance data
142
+ if entity_data[ :confidence ] == 0 && entity_data[ :relevance ] == 0
143
+ entity_data.delete( :relevance )
144
+ entity_data.delete( :confidence )
145
+ end
146
+
147
+ # Text filters include no score either.
148
+ if entity_data[ :score ] == 0
149
+ entity_data.delete( :score )
150
+ end
151
+
152
+ # Landmarks include no locale either.
153
+ if !entity_data[ :locale ]
154
+ entity_data.delete( :locale )
155
+ end
156
+
157
+ processed_data << entity_data
158
+ end
159
+ end
160
+
161
+ processed_data
162
+ end
163
+
164
+ def self.parse_properties( analysis )
165
+ processed_data = {}
166
+
167
+ properties_data = analysis[ RESPONSE_LABELS[PROPERTIES_TEST] ]
168
+ if properties_data && properties_data[ 'dominantColors' ]
169
+ properties_data = properties_data[ 'dominantColors' ][ 'colors' ]
170
+ processed_data[ :colors ] = []
171
+
172
+ properties_data.each do |color_data|
173
+ red = color_data[ 'color' ][ 'red' ].to_i.to_s( 16 )
174
+ green = color_data[ 'color' ][ 'green' ].to_i.to_s( 16 )
175
+ blue = color_data[ 'color' ][ 'blue' ].to_i.to_s( 16 )
176
+
177
+ processed_data[ :colors ] << {
178
+ hex: "##{red}#{green}#{blue}".upcase,
179
+ score: color_data[ 'score' ].to_f * 100,
180
+ percentage: color_data[ 'pixelFraction' ].to_f * 100
181
+ }
182
+ end
183
+ end
184
+
185
+ processed_data
186
+ end
187
+ end
188
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cloud_vision
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.3
4
+ version: 1.0.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ben Roux
@@ -15,7 +15,10 @@ email: liquid.ise@gmail.com
15
15
  executables: []
16
16
  extensions: []
17
17
  extra_rdoc_files: []
18
- files: []
18
+ files:
19
+ - lib/cloud_vision.rb
20
+ - lib/cloud_vision/api.rb
21
+ - lib/cloud_vision/parser.rb
19
22
  homepage: https://github.com/liquidise/cloud_vision_gem
20
23
  licenses:
21
24
  - MIT