deepstack 0.0.1
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/deepstack/custom.rb +43 -0
- data/lib/deepstack/detection.rb +20 -0
- data/lib/deepstack/face.rb +85 -0
- data/lib/deepstack/scene.rb +20 -0
- data/lib/deepstack/version.rb +9 -0
- data/lib/deepstack.rb +111 -0
- metadata +52 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 6bd245c6bb369aed6c65f88277a186cd283d396b5eeafa28bc10e854dfbd027c
|
4
|
+
data.tar.gz: b428c594d92837534124004c0ff0ef4f0b0c2aad0a2cf40ef4faa69f38d904d3
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 1f4d4c306447142dd071a6a4a28ce8f36f2170cf23160401e7cbf1786d9b8124e9c72e1a144c13096b62ad03a361fe4684f0aa8d9fab4aee0b921017ed0fff8c
|
7
|
+
data.tar.gz: 2a7c706fbfe815f7faf5ce06294f1eff65c2c9aeec3cdddb865e97348475cf1ee3478b9152444e4a92ae3697eeae3ad4e97a1fd47edff3247578eae52b340953
|
@@ -0,0 +1,43 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Deepstack
|
4
|
+
# Custom Model
|
5
|
+
module Custom
|
6
|
+
#
|
7
|
+
# Register a custom inference method for convenience.
|
8
|
+
# The custom method is called "identify_<modelname>"
|
9
|
+
# Example:
|
10
|
+
# deepstack.register_custom_model('license_plate')
|
11
|
+
# deepstack.identify_license_plate(image)
|
12
|
+
#
|
13
|
+
# @param [Array] models a list of one or more custom model names to register
|
14
|
+
#
|
15
|
+
# @return [<Type>] <description>
|
16
|
+
#
|
17
|
+
def self.register_model(*models)
|
18
|
+
models.flatten.each do |model|
|
19
|
+
method_name = 'identify_'.concat model.gsub(/-+/, '_') # convert - to _
|
20
|
+
define_method(method_name) do |image, **options|
|
21
|
+
custom_inference(model, image, options)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
#
|
27
|
+
# Return predictions using a custom model
|
28
|
+
#
|
29
|
+
# @param [String] model custom model name
|
30
|
+
# @param [Object] image binary data or a File object
|
31
|
+
# @param [Hash] options additional fields for Deepstack, e.g. min_confidence: 0.5
|
32
|
+
#
|
33
|
+
# @return [Array] if successful, an array of Deepstack predictions
|
34
|
+
#
|
35
|
+
# @return [nil] if error
|
36
|
+
#
|
37
|
+
def custom_inference(model, image, **options)
|
38
|
+
target = "vision/custom/#{model}"
|
39
|
+
api_post(target, image, options)
|
40
|
+
predictions
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Deepstack
|
4
|
+
# APIs related to object detection
|
5
|
+
module Detection
|
6
|
+
#
|
7
|
+
# Perform object detection
|
8
|
+
#
|
9
|
+
# @param [Object] image raw image data or a File object of an image file
|
10
|
+
# @param [Hash] options additional fields for Deepstack, e.g. min_confidence: 0.5
|
11
|
+
#
|
12
|
+
# @return [Array] a list of predictions, or nil on error
|
13
|
+
#
|
14
|
+
def detect_objects(image, **options)
|
15
|
+
target = 'vision/detection'
|
16
|
+
api_post(target, image, **options)
|
17
|
+
predictions
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,85 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Deepstack
|
4
|
+
# APIs related to face recognition
|
5
|
+
module Face
|
6
|
+
#
|
7
|
+
# Perform face recognition
|
8
|
+
#
|
9
|
+
# @param [Object] image binary data or a File object
|
10
|
+
# @param [Hash] options additional fields for Deepstack, e.g. min_confidence: 0.5
|
11
|
+
#
|
12
|
+
# @return [Array] if successful, an array of Deepstack predictions
|
13
|
+
#
|
14
|
+
# @return [nil] if error
|
15
|
+
#
|
16
|
+
def recognize_faces(image, **options)
|
17
|
+
target = 'vision/face/recognize'
|
18
|
+
api_post(target, image, **options)
|
19
|
+
predictions
|
20
|
+
end
|
21
|
+
|
22
|
+
#
|
23
|
+
# Detect faces in an image
|
24
|
+
#
|
25
|
+
# @param [Object] image binary data or a File object
|
26
|
+
# @param [Hash] options additional fields for Deepstack, e.g. min_confidence: 0.5
|
27
|
+
#
|
28
|
+
# @return [Array] if successful, an array of Deepstack predictions
|
29
|
+
#
|
30
|
+
def detect_faces(image, **options)
|
31
|
+
target = 'vision/face/' # the URL ends with a slash
|
32
|
+
api_post(target, image, **options)
|
33
|
+
predictions
|
34
|
+
end
|
35
|
+
|
36
|
+
#
|
37
|
+
# Get a list of registered faces
|
38
|
+
#
|
39
|
+
# @return [Array] a list of userids
|
40
|
+
#
|
41
|
+
def face_list
|
42
|
+
target = 'vision/face/list'
|
43
|
+
api_post(target)&.dig('faces')
|
44
|
+
# {"success"=>true, "faces"=>["face_1", "face_2"], "duration"=>0}
|
45
|
+
end
|
46
|
+
|
47
|
+
#
|
48
|
+
# Delete the given list of faces / userids
|
49
|
+
#
|
50
|
+
# @param [Array] userids a list of userids to delete
|
51
|
+
#
|
52
|
+
# @return [Hash] A hash of `userid => boolean` that indicates success/failure
|
53
|
+
#
|
54
|
+
def delete_faces(*userids)
|
55
|
+
userids.flatten.compact.to_h { |userid| [userid, delete_face(userid)] }
|
56
|
+
end
|
57
|
+
|
58
|
+
#
|
59
|
+
# Delete the given face / userid
|
60
|
+
#
|
61
|
+
# @param [String] userid to delete
|
62
|
+
#
|
63
|
+
# @return [Boolean] true when successful
|
64
|
+
#
|
65
|
+
def delete_face(userid)
|
66
|
+
target = 'vision/face/delete'
|
67
|
+
api_post(target, userid: userid)
|
68
|
+
success?
|
69
|
+
end
|
70
|
+
|
71
|
+
#
|
72
|
+
# Register a face
|
73
|
+
#
|
74
|
+
# @param [String] userid to register
|
75
|
+
# @param [Array] images facial image data in binary form or File object
|
76
|
+
#
|
77
|
+
# @return [Boolean] true when successful
|
78
|
+
#
|
79
|
+
def register_face(userid, *images)
|
80
|
+
target = 'vision/face/register'
|
81
|
+
api_post(target, images, userid: userid)
|
82
|
+
success?
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Deepstack
|
4
|
+
# Scene Recognition
|
5
|
+
module Scene
|
6
|
+
#
|
7
|
+
# Return
|
8
|
+
#
|
9
|
+
# @param [Object] image binary data or a File object
|
10
|
+
# @param [Hash] options additional fields for Deepstack, e.g. min_confidence: 0.5
|
11
|
+
#
|
12
|
+
# @return [Hash] if successful, Deepstack result hash {'label' => 'scene', 'confidence' => 2.2}
|
13
|
+
#
|
14
|
+
# @return [nil] if error
|
15
|
+
def identify_scene(image, **options)
|
16
|
+
target = 'vision/scene'
|
17
|
+
api_post(target, image, **options)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
data/lib/deepstack.rb
ADDED
@@ -0,0 +1,111 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'pp'
|
4
|
+
require 'net/http'
|
5
|
+
require 'json'
|
6
|
+
require_relative 'deepstack/face'
|
7
|
+
require_relative 'deepstack/detection'
|
8
|
+
require_relative 'deepstack/scene'
|
9
|
+
require_relative 'deepstack/custom'
|
10
|
+
require_relative 'deepstack/version'
|
11
|
+
|
12
|
+
module Deepstack
|
13
|
+
# Deepstack API
|
14
|
+
class API
|
15
|
+
include Deepstack::Face
|
16
|
+
include Deepstack::Detection
|
17
|
+
include Deepstack::Scene
|
18
|
+
include Deepstack::Custom
|
19
|
+
|
20
|
+
attr_reader :duration, :predictions, :success
|
21
|
+
|
22
|
+
# Create a deepstack object connected to the given URL
|
23
|
+
def initialize(base_url)
|
24
|
+
@base_url = base_url
|
25
|
+
end
|
26
|
+
|
27
|
+
#
|
28
|
+
# The result of the last call
|
29
|
+
#
|
30
|
+
# @return [Boolean] true if the last call was successful
|
31
|
+
#
|
32
|
+
def success?
|
33
|
+
@success == true
|
34
|
+
end
|
35
|
+
|
36
|
+
#
|
37
|
+
# Make a POST request to Deepstack path target
|
38
|
+
#
|
39
|
+
# @param [String] path to the Deepstack API URL
|
40
|
+
# @param [Array] images zero or more images to post
|
41
|
+
# @param [Hash] args additional named fields to post
|
42
|
+
#
|
43
|
+
# @return [Hash] if successful, the json data returned by Deepstack, nil otherwise
|
44
|
+
#
|
45
|
+
def api_post(path, *images, **args)
|
46
|
+
uri = build_uri(path)
|
47
|
+
|
48
|
+
result = nil
|
49
|
+
10.times do
|
50
|
+
result = images ? post_files(uri, images.flatten, **args) : post(uri, args)
|
51
|
+
break unless result.is_a?(Net::HTTPRedirection)
|
52
|
+
|
53
|
+
uri.path = result['location']
|
54
|
+
end
|
55
|
+
raise Net::HTTPClientException, 'Too many redirections' if result.is_a?(Net::HTTPRedirection)
|
56
|
+
|
57
|
+
process_result(result)
|
58
|
+
end
|
59
|
+
|
60
|
+
private
|
61
|
+
|
62
|
+
def build_uri(path)
|
63
|
+
URI.join(@base_url, '/v1/', path)
|
64
|
+
end
|
65
|
+
|
66
|
+
def post(uri, **args)
|
67
|
+
Net::HTTP.post_form(uri, args)
|
68
|
+
end
|
69
|
+
|
70
|
+
def post_files(uri, *images, **args)
|
71
|
+
form_data = combine_images_and_args(images.flatten, **args)
|
72
|
+
req = Net::HTTP::Post.new(uri)
|
73
|
+
req.set_form(form_data, 'multipart/form-data')
|
74
|
+
Net::HTTP.start(uri.hostname, uri.port) { |http| http.request(req) }
|
75
|
+
end
|
76
|
+
|
77
|
+
def combine_images_and_args(*images, **args)
|
78
|
+
stringify_keys(args).concat(image_form_data(images.flatten))
|
79
|
+
end
|
80
|
+
|
81
|
+
def stringify_keys(hash)
|
82
|
+
hash.map { |k, v| [k.to_s, v] }
|
83
|
+
end
|
84
|
+
|
85
|
+
#
|
86
|
+
# Return an array of image entries for form data.
|
87
|
+
# The field name is 'image' for a single image
|
88
|
+
# For multiple images, the field names will be 'image1', 'image2', ...
|
89
|
+
#
|
90
|
+
# @param [Array<Object>] images an array of raw image data or a File object
|
91
|
+
#
|
92
|
+
# @return [Array] the image entries for set_form
|
93
|
+
#
|
94
|
+
def image_form_data(*images)
|
95
|
+
images = images.flatten
|
96
|
+
return [image_entry('image', images.first)] if images.length == 1
|
97
|
+
|
98
|
+
images.map.with_index(1) { |image, i| image_entry("image#{i}", image) }
|
99
|
+
end
|
100
|
+
|
101
|
+
def image_entry(name, image)
|
102
|
+
[name, image].tap { |result| result << { filename: "#{name}.jpg" } unless image.instance_of? File }
|
103
|
+
end
|
104
|
+
|
105
|
+
def process_result(result)
|
106
|
+
@result = result.is_a?(Net::HTTPSuccess) ? JSON.parse(result.body) : nil
|
107
|
+
%w[success duration predictions].each { |attrib| instance_variable_set("@#{attrib}", @result&.dig(attrib)) }
|
108
|
+
@result
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
metadata
ADDED
@@ -0,0 +1,52 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: deepstack
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Jimmy Tanagra
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2022-05-09 00:00:00.000000000 Z
|
12
|
+
dependencies: []
|
13
|
+
description:
|
14
|
+
email:
|
15
|
+
- jcode@tanagra.id.au
|
16
|
+
executables: []
|
17
|
+
extensions: []
|
18
|
+
extra_rdoc_files: []
|
19
|
+
files:
|
20
|
+
- lib/deepstack.rb
|
21
|
+
- lib/deepstack/custom.rb
|
22
|
+
- lib/deepstack/detection.rb
|
23
|
+
- lib/deepstack/face.rb
|
24
|
+
- lib/deepstack/scene.rb
|
25
|
+
- lib/deepstack/version.rb
|
26
|
+
homepage: https://github.com/jimtng/deepstack-ruby
|
27
|
+
licenses:
|
28
|
+
- EPL-2.0
|
29
|
+
metadata:
|
30
|
+
homepage_uri: https://github.com/jimtng/deepstack-ruby
|
31
|
+
source_code_uri: https://github.com/jimtng/deepstack-ruby
|
32
|
+
changelog_uri: https://github.com/jimtng/deepstack-ruby/blob/main/CHANGELOG.md
|
33
|
+
post_install_message:
|
34
|
+
rdoc_options: []
|
35
|
+
require_paths:
|
36
|
+
- lib
|
37
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
38
|
+
requirements:
|
39
|
+
- - ">="
|
40
|
+
- !ruby/object:Gem::Version
|
41
|
+
version: 2.6.0
|
42
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
43
|
+
requirements:
|
44
|
+
- - ">="
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: '0'
|
47
|
+
requirements: []
|
48
|
+
rubygems_version: 3.3.7
|
49
|
+
signing_key:
|
50
|
+
specification_version: 4
|
51
|
+
summary: A Ruby wrapper for Deepstack API
|
52
|
+
test_files: []
|