deepstack 1.6.0 → 1.6.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 830f650f0001d9ace30cbcf6758aa58cae9d4bf7089300f0e22261e58274e1cb
4
- data.tar.gz: 2a9b1c9d03f3c04d6f159f9216b85791904f8c279155c9142bf5248eb719769a
3
+ metadata.gz: 8894b856fe894840f7b0178501000f4bd3c05dc0f8e5d3199f3782ac3bfbff86
4
+ data.tar.gz: 4e42c6f313e00d6c909de463c7a5a3874861d48a06a73c62970c5a064beedf7c
5
5
  SHA512:
6
- metadata.gz: fc573a46b62325ef299af50d25a7c9c760df25025f87f1c8c1eb588a3ee148fceb38ace946d3d39e92236d48c96da4f474a239ecfc2821660886e6f020b77ea4
7
- data.tar.gz: '08e0a71c109b87a81ef475aa85e8ea2750ed615adf65a03299b4b3df805911fac898597f94a4cdb5aa597fa03fab6367ccf04004c7545980e3a6b2261ff86d1d'
6
+ metadata.gz: 6eff77cc8ea43965ba5ba60aaccc2eea39839d7986ff5c88304f7a09dd12487d758b83b62743a216b6bb98a1f1f27807815b3c0dcef085573b6878809c6eea89
7
+ data.tar.gz: aa7f18c4fbfb6e1cac966f315c540bcbb08e9d52d391283d264df849b78ad0a1b442ea0217d8ced45e888882b0260f156cd4a8768aaeec21cf5f744bc62669cc
data/README.md ADDED
@@ -0,0 +1,78 @@
1
+ # DeepStack Ruby Wrapper
2
+
3
+ A Ruby wrapper for [DeepStack](https://www.deepstack.cc/) HTTP API
4
+
5
+ ## Usage
6
+
7
+ Install the gem with `gem install deepstack`
8
+
9
+ ~~~ ruby
10
+ require 'deepstack'
11
+
12
+ deepstack = DeepStack.new('http://192.168.1.10:2000')
13
+ image = File.read('image.jpg')
14
+
15
+ # Find bounding rects for objects
16
+ predictions = deepstack.detect_objects(image)
17
+ # => [{"confidence"=>0.86599416, "label"=>"dog", "y_min"=>355, "x_min"=>648, "y_max"=>540, "x_max"=>797},
18
+ # {"confidence"=>0.918332, "label"=>"person", "y_min"=>113, "x_min"=>442, "y_max"=>524, "x_max"=>601},
19
+ # {"confidence"=>0.9292374, "label"=>"person", "y_min"=>83, "x_min"=>294, "y_max"=>521, "x_max"=>447}]
20
+
21
+ # Find bounding rects for faces
22
+ faces = deepstack.detect_faces(image)
23
+ # => [{"confidence"=>0.86419886, "y_min"=>236, "x_min"=>876, "y_max"=>730, "x_max"=>1203},
24
+ # {"confidence"=>0.8811783, "y_min"=>164, "x_min"=>1617, "y_max"=>692, "x_max"=>1985}]
25
+
26
+ # Register a face for face recognition
27
+ deepstack.register_face('face1', image)
28
+
29
+ # List all the registered faces in the system
30
+ face_list = deepstack.face_list
31
+ # => ["face1", "face2"]
32
+
33
+ # Perform a face recognition, return identified userids
34
+ faces = deepstack.recognize_face(image)
35
+ # => [{"confidence"=>0, "userid"=>"unknown", "y_min"=>236, "x_min"=>876, "y_max"=>730, "x_max"=>1203},
36
+ # {"confidence"=>0.9824197, "userid"=>"face1", "y_min"=>164, "x_min"=>1617, "y_max"=>692, "x_max"=>1985}]
37
+
38
+ # Delete a face from the system
39
+ deepstack.delete_face('face1')
40
+
41
+ # Detect similarities between two face images
42
+ image2 = File.read('image2.jpg')
43
+ similarity = deepstack.face_match(image, image2)
44
+ # => 0.3333
45
+
46
+ # Perform Scene recognition
47
+ scene = deepstack.identify_scene(image)
48
+ # => {"success"=>true, "confidence"=>0.27867314, "label"=>"archive", "duration"=>0}
49
+ ~~~
50
+
51
+ ### Error Handling
52
+
53
+ The methods will:
54
+
55
+ * Raise an exception on a connection error.
56
+ * Return nil when DeepStack reports failure (`success=false`)
57
+
58
+ See the [documentation](https://www.rubydoc.info/gems/deepstack) for more details.
59
+
60
+ ## Development
61
+
62
+ A Linux development machine is needed in order to run the tests. The test will launch DeepStack docker instances
63
+ to test against. By default, the deepstack docker will listen on ports `8001`-`8004`.
64
+ To change this, copy `rakelib/deepstack.yml.sample` to `rakelib/deepstack.yml` and change the port numbers as required.
65
+
66
+ To run the tests run `rake`.
67
+
68
+ To manually stop the DeepStack docker instance, run `rake deepstack:stop`
69
+
70
+ To install this gem onto your local machine, run `bundle exec rake install`.
71
+
72
+ ## Contributing
73
+
74
+ Bug reports and pull requests are welcome on [GitHub](https://github.com/jimtng/deepstack-ruby).
75
+
76
+ ## License
77
+
78
+ The gem is available as open source under the terms of the EPL 2.0 License
@@ -9,7 +9,12 @@ require_relative 'custom_model'
9
9
  require_relative 'image'
10
10
  require_relative 'version'
11
11
 
12
- # DeepStack API
12
+ #
13
+ # DeepStack API wrapper
14
+ #
15
+ # All the methods that communicate with the server can raise an +Errno::ECONNREFUSED+ exception
16
+ # if the server is down or the connection details are incorrect.
17
+ #
13
18
  class DeepStack
14
19
  include DeepStack::Face
15
20
  include DeepStack::Detection
@@ -18,31 +23,36 @@ class DeepStack
18
23
  include DeepStack::CustomModel
19
24
 
20
25
  #
21
- # Create a deepstack object connected to the given URL
26
+ # Create a deepstack object for the given server URL. HTTP connections are not made within the constructor
27
+ # so the deepstack object can be created against a server that's currently down without
28
+ # raising an exception.
29
+ #
30
+ # A persistent HTTP connection will be initiated on the first method request.
22
31
  #
23
32
  # @param [String] base_url the url to DeepStack's server:port
24
- # @param [String] api_key an optional API-KEY to use when connecting to DeepStack
25
- # @param [String] api_key an optional API-KEY to use when connecting to DeepStack
33
+ # @param [String] api_key an optional +API-KEY+ to use when connecting to DeepStack
34
+ # @param [String] admin_key an optional +ADMIN-KEY+ to use when connecting to DeepStack
26
35
  # @param [Integer] verify_mode sets the flags for server the certification verification at
27
- # beginning of SSL/TLS session.
36
+ # beginning of an SSL/TLS session.
28
37
  # +OpenSSL::SSL::VERIFY_NONE+ or +OpenSSL::SSL::VERIFY_PEER+ are acceptable.
38
+ # The default is +OpenSSL::SSL::VERIFY_PEER+.
29
39
  #
30
40
  # @example
31
41
  # DeepStack.new('http://127.0.0.1:5000')
32
42
  #
33
- # # Using API KEY:
43
+ # # Using an API KEY
34
44
  # DeepStack.new('http://127.0.0.1:5000', api_key: 'secret', admin_key: 'supersecret')
35
45
  #
36
- # # Connect to SSL with a self-signed certificate
46
+ # # SSL connection with a self-signed certificate
37
47
  # DeepStack.new('https://localhost:443', verify_mode: OpenSSL::SSL::VERIFY_NONE)
38
48
  #
39
49
  def initialize(base_url, api_key: nil, admin_key: nil, verify_mode: nil)
40
50
  @base_url = base_url
41
51
  @auth = { api_key: api_key, admin_key: admin_key }.select { |_k, v| v } # remove nil values
42
52
  uri = URI(base_url)
43
- http_options = {}
44
- http_options[:verify_mode] = verify_mode if verify_mode
45
- @http = Net::HTTP.start(uri.hostname, uri.port, use_ssl: uri.instance_of?(URI::HTTPS), **http_options)
53
+ @http = Net::HTTP.new(uri.hostname, uri.port)
54
+ @http.use_ssl = uri.instance_of?(URI::HTTPS)
55
+ @http.verify_mode = verify_mode if verify_mode
46
56
  end
47
57
 
48
58
  #
@@ -71,7 +81,9 @@ class DeepStack
71
81
  end
72
82
 
73
83
  #
74
- # Close the HTTP connection to DeepStack server
84
+ # Close the persistent HTTP connection to DeepStack server. This should be called after
85
+ # a period of inactivity to close the TCP connection. Subsequent API calls will
86
+ # re-open the connection automatically.
75
87
  #
76
88
  def close
77
89
  @http.finish if @http&.started?
@@ -86,8 +86,8 @@ class DeepStack
86
86
  # image2 = File.read('obama2.jpg')
87
87
  # puts deepstack.face_match(image1, image2) > 0.6 ? 'similar' : 'different'
88
88
  #
89
- # @param [Array] *images two images to compare
90
- # @param [kwargs] **args optional arguments to the API call
89
+ # @param [Array] images two images to compare
90
+ # @param [kwargs] args optional arguments to the API call
91
91
  #
92
92
  # @return [Float] The similarity score (0-1)
93
93
  # @return [nil] if failed
@@ -5,5 +5,5 @@
5
5
  #
6
6
  class DeepStack
7
7
  # @return [String] Version of DeepStack helper libraries
8
- VERSION = '1.6.0'
8
+ VERSION = '1.6.1'
9
9
  end
@@ -0,0 +1,217 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rake'
4
+ require 'pp'
5
+ require 'deepstack'
6
+
7
+ Rake.application.rake_require 'docker_support', ['rakelib']
8
+ Rake.application.rake_require 'deepstack', ['rakelib']
9
+
10
+ # http is used in persistence check below
11
+ class DeepStack
12
+ attr_reader :http
13
+ end
14
+
15
+ def deepstack
16
+ @deepstack ||= DeepStack.new("http://localhost:#{port[:no_auth][:http]}")
17
+ end
18
+
19
+ def auth_deepstack
20
+ @auth_deepstack ||= DeepStack.new("http://localhost:#{port[:auth][:http]}", api_key: 'myapikey',
21
+ admin_key: 'myadminkey')
22
+ end
23
+
24
+ def deepstack_ssl
25
+ @deepstack_ssl ||= DeepStack.new("https://localhost:#{port[:no_auth][:https]}",
26
+ verify_mode: OpenSSL::SSL::VERIFY_NONE)
27
+ end
28
+
29
+ def restart_deepstack_server
30
+ Rake::Task['deepstack:stop1'].execute
31
+ Rake::Task['deepstack:stop2'].execute
32
+ Rake::Task['deepstack:stop3'].execute
33
+ Rake::Task['deepstack:start'].execute
34
+ end
35
+
36
+ # rubocop:disable Metrics/BlockLength
37
+ RSpec.describe DeepStack do
38
+ image = File.read('spec/test_images/person-dog.jpg')
39
+
40
+ context 'Basic Usage' do
41
+ it 'can be initialized with a url' do
42
+ expect(deepstack).not_to be_nil
43
+ end
44
+
45
+ it 'can close and reopen its http connection' do
46
+ result = deepstack.face_list
47
+ expect(result).to be_an Array
48
+ expect(deepstack.http.started?).to be true
49
+ deepstack.close
50
+ expect(deepstack.http.started?).to be false
51
+ result = deepstack.face_list
52
+ expect(deepstack.http.started?).to be true
53
+ expect(result).to be_an Array
54
+ expect(deepstack.http.started?).to be true
55
+ end
56
+
57
+ it 'can recover from a server restart' do
58
+ result = deepstack.face_list
59
+ expect(result).to be_an Array
60
+
61
+ Rake::Task['deepstack:stop1'].execute
62
+ expect { deepstack.face_list }.to raise_exception(Errno::ECONNREFUSED)
63
+ Rake::Task['deepstack:start'].execute
64
+ sleep 1
65
+
66
+ result = deepstack.face_list
67
+ expect(result).to be_an Array
68
+ end
69
+
70
+ it 'can work with an api key' do
71
+ result = auth_deepstack.detect_objects(image)
72
+ expect(result).to be_an Array
73
+ end
74
+
75
+ it 'can use ssl' do
76
+ result = deepstack_ssl.face_list
77
+ expect(result).to be_an Array
78
+ end
79
+
80
+ it 'does not raise an exception in its constructor' do
81
+ result = DeepStack.new('http://192.168.254.254')
82
+ expect(result).to be_truthy
83
+ end
84
+ end
85
+
86
+ context 'Object Detection' do
87
+ it 'can detect objects' do
88
+ result = deepstack.detect_objects(image)
89
+ # pp result
90
+ expect(result).to be_an Array
91
+ expect(result.size).to be > 0
92
+ expect(result.first).to be_a Hash
93
+ expect(result.first.keys).to include(*%w[confidence label x_max x_min y_max y_min])
94
+ end
95
+ end
96
+
97
+ context 'Face Detection' do
98
+ it 'can detect faces' do
99
+ result = deepstack.detect_faces(image)
100
+ # pp result
101
+ expect(result).to be_an Array
102
+ expect(result.first).to be_a Hash
103
+ expect(result.first.keys).to include(*%w[confidence x_min y_min x_max y_max])
104
+ end
105
+ end
106
+
107
+ context 'Face Recognition' do
108
+ it 'can return a list of registered faces' do
109
+ faces = deepstack.face_list
110
+ expect(faces).to be_an Array
111
+ end
112
+
113
+ it 'can register a face with one image object' do
114
+ # image = File.read('spec/test_images/idriselba3.jpeg')
115
+ result = deepstack.register_face('user1', image)
116
+ expect(result).to be true
117
+
118
+ faces = deepstack.face_list
119
+ expect(faces).to include 'user1'
120
+ end
121
+
122
+ it 'can register a face given a File object of an image file' do
123
+ result = File.open('spec/test_images/person-dog.jpg') do |img|
124
+ deepstack.register_face('user2', img)
125
+ end
126
+ expect(result).to be true
127
+
128
+ faces = deepstack.face_list
129
+ expect(faces).to include 'user2'
130
+ end
131
+
132
+ it 'can register a face with multiple image objects' do
133
+ face_count_before = deepstack.face_list.size
134
+ images = []
135
+ images << File.read('spec/test_images/person-dog.jpg')
136
+ images << File.read('spec/test_images/person-dog.jpg')
137
+ images << File.read('spec/test_images/person-dog.jpg')
138
+
139
+ result = deepstack.register_face('user3', images)
140
+ expect(result).to be true
141
+
142
+ faces = deepstack.face_list
143
+ expect(faces).to include 'user3'
144
+ expect(faces.size).to be > face_count_before
145
+ end
146
+
147
+ it 'can register multiple faces/users' do
148
+ deepstack.delete_faces(deepstack.face_list)
149
+ faces = deepstack.face_list
150
+ expect(faces.size).to be 0
151
+
152
+ 3.times do |i|
153
+ deepstack.register_face("user#{i}", image)
154
+ end
155
+ faces = deepstack.face_list
156
+ expect(faces.size).to be 3
157
+
158
+ 3.times do |i|
159
+ expect(faces).to include "user#{i}"
160
+ end
161
+ end
162
+
163
+ it 'can recognize faces from an image' do
164
+ result = deepstack.recognize_faces(image)
165
+ # pp result
166
+ expect(result).to be_an Array
167
+ expect(result.first.keys).to include(*%w[confidence userid x_min y_min x_max y_max])
168
+ end
169
+
170
+ it 'can delete a registered face' do
171
+ face_count_before = deepstack.face_list.size
172
+ result = deepstack.delete_face('user1')
173
+ expect(result).to be true
174
+ expect(deepstack.face_list.size).to be < face_count_before
175
+ end
176
+
177
+ it 'can delete all registered faces' do
178
+ faces = deepstack.face_list
179
+ expect(faces.size).to be > 0
180
+ result = deepstack.delete_faces(faces)
181
+ expect(result).to be_a Hash
182
+ faces = deepstack.face_list
183
+ expect(faces.size).to eq 0
184
+ end
185
+
186
+ it 'can perform face matching' do
187
+ image2 = image
188
+ result = deepstack.face_match(image, image2)
189
+ expect(result).to be_a_kind_of(Numeric)
190
+ end
191
+ end
192
+
193
+ context 'Scene Recognition' do
194
+ it 'can detect scene' do
195
+ result = deepstack.identify_scene(image)
196
+ expect(result).to be_a Hash
197
+ # pp result
198
+ expect(result.keys).to include(*%w[confidence label])
199
+ end
200
+ end
201
+
202
+ # context 'Image Enhancer' do
203
+ # # before { skip('Skipping because this test is slow') }
204
+ # it 'can enhance image' do
205
+ # result = deepstack.enhance_image(image)
206
+ # expect(result).to be_truthy
207
+ # end
208
+ # end
209
+
210
+ context 'Custom Model' do
211
+ it 'can use a custom model' do
212
+ result = deepstack.custom_model('combined', image)
213
+ expect(result).to be_an Array
214
+ end
215
+ end
216
+ end
217
+ # rubocop:enable Metrics/BlockLength
metadata CHANGED
@@ -1,15 +1,99 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: deepstack
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.6.0
4
+ version: 1.6.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jimmy Tanagra
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-05-12 00:00:00.000000000 Z
12
- dependencies: []
11
+ date: 2022-05-14 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rake
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '13.0'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '13.0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rspec
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '3.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '3.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rubocop
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '1.21'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '1.21'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rubocop-rake
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '0.6'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '0.6'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rubocop-rspec
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: yard
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
13
97
  description:
14
98
  email:
15
99
  - jcode@tanagra.id.au
@@ -17,6 +101,7 @@ executables: []
17
101
  extensions: []
18
102
  extra_rdoc_files: []
19
103
  files:
104
+ - README.md
20
105
  - lib/deep_stack/custom_model.rb
21
106
  - lib/deep_stack/deep_stack.rb
22
107
  - lib/deep_stack/detection.rb
@@ -25,6 +110,7 @@ files:
25
110
  - lib/deep_stack/scene.rb
26
111
  - lib/deep_stack/version.rb
27
112
  - lib/deepstack.rb
113
+ - spec/deepstack_spec.rb
28
114
  homepage: https://github.com/jimtng/deepstack-ruby
29
115
  licenses:
30
116
  - EPL-2.0
@@ -52,4 +138,5 @@ rubygems_version: 3.0.3.1
52
138
  signing_key:
53
139
  specification_version: 4
54
140
  summary: A Ruby wrapper for DeepStack API
55
- test_files: []
141
+ test_files:
142
+ - spec/deepstack_spec.rb