google-cloud-vision 0.20.0
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 +7 -0
- data/lib/google-cloud-vision.rb +120 -0
- data/lib/google/cloud/vision.rb +477 -0
- data/lib/google/cloud/vision/annotate.rb +235 -0
- data/lib/google/cloud/vision/annotation.rb +449 -0
- data/lib/google/cloud/vision/annotation/entity.rb +228 -0
- data/lib/google/cloud/vision/annotation/face.rb +1512 -0
- data/lib/google/cloud/vision/annotation/properties.rb +222 -0
- data/lib/google/cloud/vision/annotation/safe_search.rb +154 -0
- data/lib/google/cloud/vision/annotation/text.rb +222 -0
- data/lib/google/cloud/vision/annotation/vertex.rb +92 -0
- data/lib/google/cloud/vision/credentials.rb +31 -0
- data/lib/google/cloud/vision/image.rb +578 -0
- data/lib/google/cloud/vision/location.rb +99 -0
- data/lib/google/cloud/vision/project.rb +284 -0
- data/lib/google/cloud/vision/service.rb +75 -0
- data/lib/google/cloud/vision/version.rb +22 -0
- metadata +202 -0
@@ -0,0 +1,92 @@
|
|
1
|
+
# Copyright 2016 Google Inc. All rights reserved.
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
# you may not use this file except in compliance with the License.
|
5
|
+
# You may obtain a copy of the License at
|
6
|
+
#
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
#
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
# See the License for the specific language governing permissions and
|
13
|
+
# limitations under the License.
|
14
|
+
|
15
|
+
|
16
|
+
module Google
|
17
|
+
module Cloud
|
18
|
+
module Vision
|
19
|
+
class Annotation
|
20
|
+
##
|
21
|
+
# # Vertex
|
22
|
+
#
|
23
|
+
# A vertex in a set of bounding polygon vertices.
|
24
|
+
#
|
25
|
+
# See {Face::Bounds} and {Text}.
|
26
|
+
#
|
27
|
+
# @attr_reader [Integer] x The X coordinate.
|
28
|
+
# @attr_reader [Integer] y The Y coordinate.
|
29
|
+
#
|
30
|
+
# @example
|
31
|
+
# require "google/cloud"
|
32
|
+
#
|
33
|
+
# gcloud = Google::Cloud.new
|
34
|
+
# vision = gcloud.vision
|
35
|
+
#
|
36
|
+
# image = vision.image "path/to/text.png"
|
37
|
+
# text = image.text
|
38
|
+
#
|
39
|
+
# text.bounds.count #=> 4
|
40
|
+
# vertex = text.bounds.first
|
41
|
+
# vertex.x #=> 13
|
42
|
+
# vertex.y #=> 8
|
43
|
+
#
|
44
|
+
class Vertex
|
45
|
+
attr_reader :x, :y
|
46
|
+
|
47
|
+
##
|
48
|
+
# @private Creates a new Vertex instance.
|
49
|
+
def initialize x, y
|
50
|
+
@x = x
|
51
|
+
@y = y
|
52
|
+
end
|
53
|
+
|
54
|
+
##
|
55
|
+
# Returns the object's property values as an array.
|
56
|
+
#
|
57
|
+
# @return [Array]
|
58
|
+
#
|
59
|
+
def to_a
|
60
|
+
[x, y]
|
61
|
+
end
|
62
|
+
|
63
|
+
##
|
64
|
+
# Converts object to a hash. All keys will be symbolized.
|
65
|
+
#
|
66
|
+
# @return [Hash]
|
67
|
+
#
|
68
|
+
def to_h
|
69
|
+
{ x: x, y: y }
|
70
|
+
end
|
71
|
+
|
72
|
+
# @private
|
73
|
+
def to_s
|
74
|
+
"(x: #{x.inspect}, y: #{y.inspect})"
|
75
|
+
end
|
76
|
+
|
77
|
+
# @private
|
78
|
+
def inspect
|
79
|
+
"#<Vertex #{self}>"
|
80
|
+
end
|
81
|
+
|
82
|
+
##
|
83
|
+
# @private New Annotation::Entity::Bounds::Vertex from a Google API
|
84
|
+
# Client object.
|
85
|
+
def self.from_gapi gapi
|
86
|
+
new gapi.x, gapi.y
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# Copyright 2016 Google Inc. All rights reserved.
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
# you may not use this file except in compliance with the License.
|
5
|
+
# You may obtain a copy of the License at
|
6
|
+
#
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
#
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
# See the License for the specific language governing permissions and
|
13
|
+
# limitations under the License.
|
14
|
+
|
15
|
+
|
16
|
+
require "google/cloud/credentials"
|
17
|
+
|
18
|
+
module Google
|
19
|
+
module Cloud
|
20
|
+
module Vision
|
21
|
+
##
|
22
|
+
# @private Represents the OAuth 2.0 signing logic for Vision.
|
23
|
+
class Credentials < Google::Cloud::Credentials
|
24
|
+
SCOPE = ["https://www.googleapis.com/auth/cloud-platform"]
|
25
|
+
PATH_ENV_VARS = %w(VISION_KEYFILE GOOGLE_CLOUD_KEYFILE GCLOUD_KEYFILE)
|
26
|
+
JSON_ENV_VARS = %w(VISION_KEYFILE_JSON GOOGLE_CLOUD_KEYFILE_JSON
|
27
|
+
GCLOUD_KEYFILE_JSON)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,578 @@
|
|
1
|
+
# Copyright 2016 Google Inc. All rights reserved.
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
# you may not use this file except in compliance with the License.
|
5
|
+
# You may obtain a copy of the License at
|
6
|
+
#
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
#
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
# See the License for the specific language governing permissions and
|
13
|
+
# limitations under the License.
|
14
|
+
|
15
|
+
|
16
|
+
require "google/cloud/vision/location"
|
17
|
+
require "google/apis/vision_v1"
|
18
|
+
require "stringio"
|
19
|
+
require "base64"
|
20
|
+
|
21
|
+
module Google
|
22
|
+
module Cloud
|
23
|
+
module Vision
|
24
|
+
##
|
25
|
+
# # Image
|
26
|
+
#
|
27
|
+
# Represents an image for the Vision service.
|
28
|
+
#
|
29
|
+
# See {Project#image}.
|
30
|
+
#
|
31
|
+
# The Cloud Vision API supports a variety of image file formats, including
|
32
|
+
# JPEG, PNG8, PNG24, Animated GIF (first frame only), and RAW. See [Best
|
33
|
+
# Practices - Image
|
34
|
+
# Types](https://cloud.google.com/vision/docs/image-best-practices#image_types)
|
35
|
+
# for the list of formats. Be aware that Cloud Vision sets upper limits on
|
36
|
+
# file size as well as the total combined size of all images in a request.
|
37
|
+
# Reducing your file size can significantly improve throughput; however,
|
38
|
+
# be careful not to reduce image quality in the process. See [Best
|
39
|
+
# Practices - Image
|
40
|
+
# Sizing](https://cloud.google.com/vision/docs/image-best-practices#image_sizing)
|
41
|
+
# for current file size limits.
|
42
|
+
#
|
43
|
+
# @see https://cloud.google.com/vision/docs/image-best-practices Best
|
44
|
+
# Practices
|
45
|
+
#
|
46
|
+
# @example
|
47
|
+
# require "google/cloud"
|
48
|
+
#
|
49
|
+
# gcloud = Google::Cloud.new
|
50
|
+
# vision = gcloud.vision
|
51
|
+
#
|
52
|
+
# image = vision.image "path/to/text.png"
|
53
|
+
#
|
54
|
+
# image.context.languages = ["en"]
|
55
|
+
#
|
56
|
+
# text = image.text
|
57
|
+
# text.words.count #=> 28
|
58
|
+
#
|
59
|
+
class Image
|
60
|
+
# Returns the image context for the image, which accepts metadata values
|
61
|
+
# such as location and language hints.
|
62
|
+
# @return [Context] The context instance for the image.
|
63
|
+
attr_reader :context
|
64
|
+
|
65
|
+
##
|
66
|
+
# @private Creates a new Image instance.
|
67
|
+
def initialize
|
68
|
+
@io = nil
|
69
|
+
@url = nil
|
70
|
+
@vision = nil
|
71
|
+
@context = Context.new
|
72
|
+
end
|
73
|
+
|
74
|
+
##
|
75
|
+
# @private Whether the Image has content.
|
76
|
+
#
|
77
|
+
def io?
|
78
|
+
!@io.nil?
|
79
|
+
end
|
80
|
+
|
81
|
+
##
|
82
|
+
# @private Whether the Image is a URL.
|
83
|
+
#
|
84
|
+
def url?
|
85
|
+
!@url.nil?
|
86
|
+
end
|
87
|
+
|
88
|
+
##
|
89
|
+
# Performs the `FACE_DETECTION` feature on the image.
|
90
|
+
#
|
91
|
+
# @see https://cloud.google.com/vision/docs/pricing Cloud Vision Pricing
|
92
|
+
#
|
93
|
+
# @param [Integer] max_results The maximum number of results. The
|
94
|
+
# default is {Google::Cloud::Vision.default_max_faces}. Optional.
|
95
|
+
#
|
96
|
+
# @return [Array<Annotation::Face>] The results of face detection.
|
97
|
+
#
|
98
|
+
# @example
|
99
|
+
# require "google/cloud"
|
100
|
+
#
|
101
|
+
# gcloud = Google::Cloud.new
|
102
|
+
# vision = gcloud.vision
|
103
|
+
# image = vision.image "path/to/face.jpg"
|
104
|
+
#
|
105
|
+
# faces = image.faces
|
106
|
+
#
|
107
|
+
# face = faces.first
|
108
|
+
# face.bounds.face.count #=> 4
|
109
|
+
# face.bounds.face.first #=> #<Vertex (x: 153, y: 34)>
|
110
|
+
#
|
111
|
+
def faces max_results = Google::Cloud::Vision.default_max_faces
|
112
|
+
ensure_vision!
|
113
|
+
annotation = @vision.mark self, faces: max_results
|
114
|
+
annotation.faces
|
115
|
+
end
|
116
|
+
|
117
|
+
##
|
118
|
+
# Performs the `FACE_DETECTION` feature on the image and returns only
|
119
|
+
# the first result.
|
120
|
+
#
|
121
|
+
# @return [Annotation::Face] The first result of face detection.
|
122
|
+
#
|
123
|
+
def face
|
124
|
+
faces(1).first
|
125
|
+
end
|
126
|
+
|
127
|
+
##
|
128
|
+
# Performs the `LANDMARK_DETECTION` feature on the image.
|
129
|
+
#
|
130
|
+
# @see https://cloud.google.com/vision/docs/pricing Cloud Vision Pricing
|
131
|
+
#
|
132
|
+
# @param [Integer] max_results The maximum number of results. The
|
133
|
+
# default is {Google::Cloud::Vision.default_max_landmarks}. Optional.
|
134
|
+
#
|
135
|
+
# @return [Array<Annotation::Entity>] The results of landmark detection.
|
136
|
+
#
|
137
|
+
# @example
|
138
|
+
# require "google/cloud"
|
139
|
+
#
|
140
|
+
# gcloud = Google::Cloud.new
|
141
|
+
# vision = gcloud.vision
|
142
|
+
# image = vision.image "path/to/landmark.jpg"
|
143
|
+
#
|
144
|
+
# landmarks = image.landmarks
|
145
|
+
#
|
146
|
+
# landmark = landmarks.first
|
147
|
+
# landmark.score #=> 0.91912264
|
148
|
+
# landmark.description #=> "Mount Rushmore"
|
149
|
+
# landmark.mid #=> "/m/019dvv"
|
150
|
+
#
|
151
|
+
def landmarks max_results = Google::Cloud::Vision.default_max_landmarks
|
152
|
+
ensure_vision!
|
153
|
+
annotation = @vision.mark self, landmarks: max_results
|
154
|
+
annotation.landmarks
|
155
|
+
end
|
156
|
+
|
157
|
+
##
|
158
|
+
# Performs the `LANDMARK_DETECTION` feature on the image and returns
|
159
|
+
# only the first result.
|
160
|
+
#
|
161
|
+
# @return [Annotation::Entity] The first result of landmark detection.
|
162
|
+
#
|
163
|
+
def landmark
|
164
|
+
landmarks(1).first
|
165
|
+
end
|
166
|
+
|
167
|
+
##
|
168
|
+
# Performs the `LOGO_DETECTION` feature on the image.
|
169
|
+
#
|
170
|
+
# @see https://cloud.google.com/vision/docs/pricing Cloud Vision Pricing
|
171
|
+
#
|
172
|
+
# @param [Integer] max_results The maximum number of results. The
|
173
|
+
# default is {Google::Cloud::Vision.default_max_logos}. Optional.
|
174
|
+
#
|
175
|
+
# @return [Array<Annotation::Entity>] The results of logo detection.
|
176
|
+
#
|
177
|
+
# @example
|
178
|
+
# require "google/cloud"
|
179
|
+
#
|
180
|
+
# gcloud = Google::Cloud.new
|
181
|
+
# vision = gcloud.vision
|
182
|
+
# image = vision.image "path/to/logo.jpg"
|
183
|
+
#
|
184
|
+
# logos = image.logos
|
185
|
+
#
|
186
|
+
# logo = logos.first
|
187
|
+
# logo.score #=> 0.70057315
|
188
|
+
# logo.description #=> "Google"
|
189
|
+
# logo.mid #=> "/m/0b34hf"
|
190
|
+
#
|
191
|
+
def logos max_results = Google::Cloud::Vision.default_max_logos
|
192
|
+
ensure_vision!
|
193
|
+
annotation = @vision.mark self, logos: max_results
|
194
|
+
annotation.logos
|
195
|
+
end
|
196
|
+
|
197
|
+
##
|
198
|
+
# Performs the `LOGO_DETECTION` feature on the image and returns only
|
199
|
+
# the first result.
|
200
|
+
#
|
201
|
+
# @return [Annotation::Entity] The first result of logo detection.
|
202
|
+
#
|
203
|
+
def logo
|
204
|
+
logos(1).first
|
205
|
+
end
|
206
|
+
|
207
|
+
##
|
208
|
+
# Performs the `LABEL_DETECTION` feature on the image.
|
209
|
+
#
|
210
|
+
# @see https://cloud.google.com/vision/docs/pricing Cloud Vision Pricing
|
211
|
+
#
|
212
|
+
# @param [Integer] max_results The maximum number of results. The
|
213
|
+
# default is {Google::Cloud::Vision.default_max_labels}. Optional.
|
214
|
+
#
|
215
|
+
# @return [Array<Annotation::Entity>] The results of label detection.
|
216
|
+
#
|
217
|
+
# @example
|
218
|
+
# require "google/cloud"
|
219
|
+
#
|
220
|
+
# gcloud = Google::Cloud.new
|
221
|
+
# vision = gcloud.vision
|
222
|
+
# image = vision.image "path/to/face.jpg"
|
223
|
+
#
|
224
|
+
# labels = image.labels
|
225
|
+
#
|
226
|
+
# labels.count #=> 4
|
227
|
+
# label = labels.first
|
228
|
+
# label.score #=> 0.9481349
|
229
|
+
# label.description #=> "person"
|
230
|
+
# label.mid #=> "/m/01g317"
|
231
|
+
#
|
232
|
+
def labels max_results = Google::Cloud::Vision.default_max_labels
|
233
|
+
ensure_vision!
|
234
|
+
annotation = @vision.mark self, labels: max_results
|
235
|
+
annotation.labels
|
236
|
+
end
|
237
|
+
|
238
|
+
##
|
239
|
+
# Performs the `LABEL_DETECTION` feature on the image and returns only
|
240
|
+
# the first result.
|
241
|
+
#
|
242
|
+
# @return [Annotation::Entity] The first result of label detection.
|
243
|
+
#
|
244
|
+
def label
|
245
|
+
labels(1).first
|
246
|
+
end
|
247
|
+
|
248
|
+
##
|
249
|
+
# Performs the `TEXT_DETECTION` (OCR) feature on the image.
|
250
|
+
#
|
251
|
+
# @see https://cloud.google.com/vision/docs/pricing Cloud Vision Pricing
|
252
|
+
#
|
253
|
+
# @return [Annotation::Text] The results of text (OCR) detection.
|
254
|
+
#
|
255
|
+
# @example
|
256
|
+
# require "google/cloud"
|
257
|
+
#
|
258
|
+
# gcloud = Google::Cloud.new
|
259
|
+
# vision = gcloud.vision
|
260
|
+
# image = vision.image "path/to/text.png"
|
261
|
+
#
|
262
|
+
# text = image.text
|
263
|
+
#
|
264
|
+
# text = image.text
|
265
|
+
# text.locale #=> "en"
|
266
|
+
# text.words.count #=> 28
|
267
|
+
# text.text
|
268
|
+
# #=> "Google Cloud Client for Ruby an idiomatic, intuitive... "
|
269
|
+
#
|
270
|
+
def text
|
271
|
+
ensure_vision!
|
272
|
+
annotation = @vision.mark self, text: true
|
273
|
+
annotation.text
|
274
|
+
end
|
275
|
+
|
276
|
+
##
|
277
|
+
# Performs the `SAFE_SEARCH_DETECTION` feature on the image.
|
278
|
+
#
|
279
|
+
# @see https://cloud.google.com/vision/docs/pricing Cloud Vision Pricing
|
280
|
+
#
|
281
|
+
# @return [Annotation::SafeSearch] The results of safe search detection.
|
282
|
+
#
|
283
|
+
# @example
|
284
|
+
# require "google/cloud"
|
285
|
+
#
|
286
|
+
# gcloud = Google::Cloud.new
|
287
|
+
# vision = gcloud.vision
|
288
|
+
# image = vision.image "path/to/face.jpg"
|
289
|
+
#
|
290
|
+
# safe_search = image.safe_search
|
291
|
+
#
|
292
|
+
# safe_search.spoof? #=> false
|
293
|
+
# safe_search.spoof #=> "VERY_UNLIKELY"
|
294
|
+
#
|
295
|
+
def safe_search
|
296
|
+
ensure_vision!
|
297
|
+
annotation = @vision.mark self, safe_search: true
|
298
|
+
annotation.safe_search
|
299
|
+
end
|
300
|
+
|
301
|
+
##
|
302
|
+
# Performs the `IMAGE_PROPERTIES` feature on the image.
|
303
|
+
#
|
304
|
+
# @see https://cloud.google.com/vision/docs/pricing Cloud Vision Pricing
|
305
|
+
#
|
306
|
+
# @return [Annotation::Properties] The results of image properties
|
307
|
+
# detection.
|
308
|
+
#
|
309
|
+
# @example
|
310
|
+
# require "google/cloud"
|
311
|
+
#
|
312
|
+
# gcloud = Google::Cloud.new
|
313
|
+
# vision = gcloud.vision
|
314
|
+
# image = vision.image "path/to/logo.jpg"
|
315
|
+
#
|
316
|
+
# properties = image.properties
|
317
|
+
#
|
318
|
+
# properties.colors.count #=> 10
|
319
|
+
# color = properties.colors.first
|
320
|
+
# color.red #=> 247.0
|
321
|
+
# color.green #=> 236.0
|
322
|
+
# color.blue #=> 20.0
|
323
|
+
#
|
324
|
+
def properties
|
325
|
+
ensure_vision!
|
326
|
+
annotation = @vision.mark self, properties: true
|
327
|
+
annotation.properties
|
328
|
+
end
|
329
|
+
|
330
|
+
# @private
|
331
|
+
def to_s
|
332
|
+
@to_s ||= begin
|
333
|
+
if io?
|
334
|
+
@io.rewind
|
335
|
+
"(#{@io.read(16)}...)"
|
336
|
+
else
|
337
|
+
"(#{url})"
|
338
|
+
end
|
339
|
+
end
|
340
|
+
end
|
341
|
+
|
342
|
+
# @private
|
343
|
+
def inspect
|
344
|
+
"#<#{self.class.name} #{self}>"
|
345
|
+
end
|
346
|
+
|
347
|
+
##
|
348
|
+
# @private The Google API Client object for the Image.
|
349
|
+
def to_gapi
|
350
|
+
if io?
|
351
|
+
@io.rewind
|
352
|
+
Google::Apis::VisionV1::Image.new content: @io.read
|
353
|
+
elsif url?
|
354
|
+
Google::Apis::VisionV1::Image.new source: { gcsImageUri: @url }
|
355
|
+
else
|
356
|
+
fail ArgumentError, "Unable to use Image with Vision service."
|
357
|
+
end
|
358
|
+
end
|
359
|
+
|
360
|
+
##
|
361
|
+
# @private New Image from a source object.
|
362
|
+
def self.from_source source, vision = nil
|
363
|
+
if source.respond_to?(:read) && source.respond_to?(:rewind)
|
364
|
+
return from_io(source, vision)
|
365
|
+
end
|
366
|
+
# Convert Storage::File objects to the URL
|
367
|
+
source = source.to_gs_url if source.respond_to? :to_gs_url
|
368
|
+
# Everything should be a string from now on
|
369
|
+
source = String source
|
370
|
+
# Create an Image from the Google Storage URL
|
371
|
+
return from_url(source, vision) if source.start_with? "gs://"
|
372
|
+
# Create an image from a file on the filesystem
|
373
|
+
if File.file? source
|
374
|
+
unless File.readable? source
|
375
|
+
fail ArgumentError, "Cannot read #{source}"
|
376
|
+
end
|
377
|
+
return from_io(File.open(source, "rb"), vision)
|
378
|
+
end
|
379
|
+
fail ArgumentError, "Unable to convert #{source} to an Image"
|
380
|
+
end
|
381
|
+
|
382
|
+
##
|
383
|
+
# @private New Image from an IO object.
|
384
|
+
def self.from_io io, vision
|
385
|
+
if !io.respond_to?(:read) && !io.respond_to?(:rewind)
|
386
|
+
fail ArgumentError, "Cannot create an Image without an IO object"
|
387
|
+
end
|
388
|
+
new.tap do |i|
|
389
|
+
i.instance_variable_set :@io, io
|
390
|
+
i.instance_variable_set :@vision, vision
|
391
|
+
end
|
392
|
+
end
|
393
|
+
|
394
|
+
##
|
395
|
+
# @private New Image from an IO object.
|
396
|
+
def self.from_url url, vision
|
397
|
+
url = String url
|
398
|
+
unless url.start_with? "gs://"
|
399
|
+
fail ArgumentError, "Cannot create an Image without a Storage URL"
|
400
|
+
end
|
401
|
+
new.tap do |i|
|
402
|
+
i.instance_variable_set :@url, url
|
403
|
+
i.instance_variable_set :@vision, vision
|
404
|
+
end
|
405
|
+
end
|
406
|
+
|
407
|
+
protected
|
408
|
+
|
409
|
+
##
|
410
|
+
# Raise an error unless an active vision project object is available.
|
411
|
+
def ensure_vision!
|
412
|
+
fail "Must have active connection" unless @vision
|
413
|
+
end
|
414
|
+
end
|
415
|
+
|
416
|
+
class Image
|
417
|
+
##
|
418
|
+
# # Image::Context
|
419
|
+
#
|
420
|
+
# Represents an image context.
|
421
|
+
#
|
422
|
+
# @attr [Array<String>] languages A list of [ISO 639-1 language
|
423
|
+
# codes](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes)
|
424
|
+
# to use for text (OCR) detection. In most cases, an empty value
|
425
|
+
# will yield the best results as it will allow text detection to
|
426
|
+
# automatically detect the text language. For languages based on the
|
427
|
+
# latin alphabet a hint is not needed. In rare cases, when the
|
428
|
+
# language of the text in the image is known in advance, setting
|
429
|
+
# this hint will help get better results (although it will hurt a
|
430
|
+
# great deal if the hint is wrong).
|
431
|
+
#
|
432
|
+
# @example
|
433
|
+
# require "google/cloud"
|
434
|
+
#
|
435
|
+
# gcloud = Google::Cloud.new
|
436
|
+
# vision = gcloud.vision
|
437
|
+
#
|
438
|
+
# image = vision.image "path/to/landmark.jpg"
|
439
|
+
# image.context.area.min = { longitude: -122.0862462,
|
440
|
+
# latitude: 37.4220041 }
|
441
|
+
# image.context.area.max = { longitude: -122.0762462,
|
442
|
+
# latitude: 37.4320041 }
|
443
|
+
#
|
444
|
+
class Context
|
445
|
+
##
|
446
|
+
# Returns a lat/long rectangle that specifies the location of the
|
447
|
+
# image.
|
448
|
+
# @return [Area] The lat/long pairs for `latLongRect`.
|
449
|
+
attr_reader :area
|
450
|
+
|
451
|
+
attr_accessor :languages
|
452
|
+
|
453
|
+
##
|
454
|
+
# @private Creates a new Context instance.
|
455
|
+
def initialize
|
456
|
+
@area = Area.new
|
457
|
+
@languages = []
|
458
|
+
end
|
459
|
+
|
460
|
+
##
|
461
|
+
# Returns `true` if either `min` or `max` are not populated.
|
462
|
+
#
|
463
|
+
# @return [Boolean]
|
464
|
+
#
|
465
|
+
def empty?
|
466
|
+
area.empty? && languages.empty?
|
467
|
+
end
|
468
|
+
|
469
|
+
##
|
470
|
+
# @private
|
471
|
+
def to_gapi
|
472
|
+
return nil if empty?
|
473
|
+
gapi = Google::Apis::VisionV1::ImageContext.new
|
474
|
+
gapi.lat_long_rect = area.to_gapi unless area.empty?
|
475
|
+
gapi.language_hints = languages unless languages.empty?
|
476
|
+
gapi
|
477
|
+
end
|
478
|
+
|
479
|
+
##
|
480
|
+
# # Image::Context::Area
|
481
|
+
#
|
482
|
+
# A Lat/long rectangle that specifies the location of the image.
|
483
|
+
#
|
484
|
+
# @example
|
485
|
+
# require "google/cloud"
|
486
|
+
#
|
487
|
+
# gcloud = Google::Cloud.new
|
488
|
+
# vision = gcloud.vision
|
489
|
+
#
|
490
|
+
# image = vision.image "path/to/landmark.jpg"
|
491
|
+
#
|
492
|
+
# image.context.area.min = { longitude: -122.0862462,
|
493
|
+
# latitude: 37.4220041 }
|
494
|
+
# image.context.area.max = { longitude: -122.0762462,
|
495
|
+
# latitude: 37.4320041 }
|
496
|
+
#
|
497
|
+
# entity = image.landmark
|
498
|
+
#
|
499
|
+
class Area
|
500
|
+
# Returns the min lat/long pair.
|
501
|
+
# @return [Location]
|
502
|
+
attr_reader :min
|
503
|
+
|
504
|
+
# Returns the max lat/long pair.
|
505
|
+
# @return [Location]
|
506
|
+
attr_reader :max
|
507
|
+
|
508
|
+
##
|
509
|
+
# @private Creates a new Area instance.
|
510
|
+
def initialize
|
511
|
+
@min = Location.new nil, nil
|
512
|
+
@max = Location.new nil, nil
|
513
|
+
end
|
514
|
+
|
515
|
+
##
|
516
|
+
# Sets the min lat/long pair for the area.
|
517
|
+
#
|
518
|
+
# @param [Hash(Symbol => Float)] location A Hash containing the keys
|
519
|
+
# `:latitude` and `:longitude` with corresponding values
|
520
|
+
# conforming to the [WGS84
|
521
|
+
# standard](http://www.unoosa.org/pdf/icg/2012/template/WGS_84.pdf).
|
522
|
+
def min= location
|
523
|
+
if location.respond_to?(:to_h) &&
|
524
|
+
location.to_h.keys.sort == [:latitude, :longitude]
|
525
|
+
return @min = Location.new(location.to_h[:latitude],
|
526
|
+
location.to_h[:longitude])
|
527
|
+
end
|
528
|
+
fail ArgumentError, "Must pass a proper location value."
|
529
|
+
end
|
530
|
+
|
531
|
+
##
|
532
|
+
# Sets the max lat/long pair for the area.
|
533
|
+
#
|
534
|
+
# @param [Hash(Symbol => Float)] location A Hash containing the keys
|
535
|
+
# `:latitude` and `:longitude` with corresponding values
|
536
|
+
# conforming to the [WGS84
|
537
|
+
# standard](http://www.unoosa.org/pdf/icg/2012/template/WGS_84.pdf).
|
538
|
+
def max= location
|
539
|
+
if location.respond_to?(:to_h) &&
|
540
|
+
location.to_h.keys.sort == [:latitude, :longitude]
|
541
|
+
return @max = Location.new(location.to_h[:latitude],
|
542
|
+
location.to_h[:longitude])
|
543
|
+
end
|
544
|
+
fail ArgumentError, "Must pass a proper location value."
|
545
|
+
end
|
546
|
+
|
547
|
+
##
|
548
|
+
# Returns `true` if either `min` or `max` are not populated.
|
549
|
+
#
|
550
|
+
# @return [Boolean]
|
551
|
+
#
|
552
|
+
def empty?
|
553
|
+
min.to_h.values.reject(&:nil?).empty? ||
|
554
|
+
max.to_h.values.reject(&:nil?).empty?
|
555
|
+
end
|
556
|
+
|
557
|
+
##
|
558
|
+
# Deeply converts object to a hash. All keys will be symbolized.
|
559
|
+
#
|
560
|
+
# @return [Hash]
|
561
|
+
#
|
562
|
+
def to_h
|
563
|
+
{ min_lat_lng: min.to_h, max_lat_lng: max.to_h }
|
564
|
+
end
|
565
|
+
|
566
|
+
def to_gapi
|
567
|
+
return nil if empty?
|
568
|
+
Google::Apis::VisionV1::LatLongRect.new(
|
569
|
+
min_lat_lng: min.to_gapi,
|
570
|
+
max_lat_lng: max.to_gapi
|
571
|
+
)
|
572
|
+
end
|
573
|
+
end
|
574
|
+
end
|
575
|
+
end
|
576
|
+
end
|
577
|
+
end
|
578
|
+
end
|