Class: Matroid::Detector

Inherits:
Object
  • Object
show all
Defined in:
lib/matroid/detector.rb

Overview

Represents a Matroid detector

Constant Summary collapse

@@instances =

HASH { <id> => Detector }

{}
@@ids =
[]

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(params) ⇒ Detector

Returns a new instance of Detector.



125
126
127
# File 'lib/matroid/detector.rb', line 125

def initialize(params)
  update_params(params)
end

Instance Attribute Details

#idString

Detector id

Returns:

  • (String)

    the current value of id



16
17
18
# File 'lib/matroid/detector.rb', line 16

def id
  @id
end

#label_idsObject (readonly)

Returns the value of attribute label_ids.



21
22
23
# File 'lib/matroid/detector.rb', line 21

def label_ids
  @label_ids
end

#labelsArray<Hash><String>

Returns the current value of labels.

Returns:

  • (Array<Hash><String>)

    the current value of labels



16
17
18
# File 'lib/matroid/detector.rb', line 16

def labels
  @labels
end

#nameString

Detector name

Returns:

  • (String)

    the current value of name



16
17
18
# File 'lib/matroid/detector.rb', line 16

def name
  @name
end

#ownerBool

is the current authicated user the owner

Returns:

  • (Bool)

    the current value of owner



16
17
18
# File 'lib/matroid/detector.rb', line 16

def owner
  @owner
end

#permission_levelString

‘private’, ‘readonly’, ‘open’, ‘stock’

Returns:

  • (String)

    the current value of permission_level



16
17
18
# File 'lib/matroid/detector.rb', line 16

def permission_level
  @permission_level
end

#stateObject (readonly)

Returns the value of attribute state.



21
22
23
# File 'lib/matroid/detector.rb', line 21

def state
  @state
end

#trainingObject (readonly)

Returns the value of attribute training.



21
22
23
# File 'lib/matroid/detector.rb', line 21

def training
  @training
end

#typeObject (readonly)

Returns the value of attribute type.



21
22
23
# File 'lib/matroid/detector.rb', line 21

def type
  @type
end

Class Method Details

.cached(type = 'instance') ⇒ Array<Hash, Detector>

List of cached detectors that have been returned by search requests as hashes or Detector instances.

Parameters:

  • type (String) (defaults to: 'instance')

    Indicate how you want the response

Returns:



76
77
78
79
80
81
82
83
# File 'lib/matroid/detector.rb', line 76

def self.cached(type = 'instance')
  case type
  when 'hash'
    @@ids.map{|id| find_by_id(id).to_hash }
  when 'instance'
    @@ids.map{|id| find_by_id(id) }
  end
end

.create(zip_file, name, detector_type = 'general') ⇒ Detector

Note:

Max 1 GB zip file upload.

Creates a new detector with the contents of a zip file. The root folder should contain only directories which will become the labels for detection. Each of these directories should contain only a images corresponding to that label. Zip file structure example:

cat/
  garfield.jpg
  nermal.png
dog/
  odie.tiff

Parameters:

  • zip_file (String)

    Path to zip file containing the images to be used in the detector creation

  • name (String)

    The detector’s display name

  • detector_type (String) (defaults to: 'general')

    Options: “general”, “face_detector”, or “facial_characteristics”

Returns:



105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
# File 'lib/matroid/detector.rb', line 105

def self.create(zip_file, name, detector_type='general')
  case zip_file
  when String
    file = File.new(zip_file, 'rb')
  when File
    file = zip_file
  else
    err_msg = 'First argument must be a zip file of the image folders, or a string of the path to the file'
    raise Error::InvalidQueryError.new(err_msg)
  end
  params = {
    file: file,
    name: name,
    detector_type: detector_type
  }
  response = Matroid.post('detectors', params)
  id = response['detector_id']
  find_by_id(id)
end

.find(args) ⇒ Array<Hash><Detector>

Note:

The detector must either be created by the current authenticated user or published for general use.

Looks up the detector by matching fields. :label and :name get matched according the the regular expression /b(<word>)/i

Examples:

Matroid::Detector.find(label: 'cat', state: 'trained')
Matroid::Detector.find(name: 'cat')
Matroid::Detector.find(name: 'cat', published: true)
Matroid::Detector.find(label: 'puppy').first.id

Returns:

  • (Array<Hash><Detector>)

    Returns the detector instances that match the query.

Raises:



36
37
38
39
40
41
# File 'lib/matroid/detector.rb', line 36

def self.find(args)
  raise Error::InvalidQueryError.new('Argument must be a hash.') unless args.class == Hash
  query = args.keys.map{|key| key.to_s + '=' + args[key].to_s }.join('&')
  detectors = Matroid.get('detectors/search?' + query)
  detectors.map{|params| register(params) }
end

.find_by_id(id, args = {}) ⇒ Object

Finds a single document based on the id



50
51
52
53
54
55
56
57
# File 'lib/matroid/detector.rb', line 50

def self.find_by_id(id, args = {})
  detector = @@instances[id]
  is_trained =  detector.class == Detector && detector.is_trained?
  return detector if is_trained

  args[:id] = id
  find_one(args)
end

.find_one(args) ⇒ Object

Chooses first occurence of the results from #find



44
45
46
47
# File 'lib/matroid/detector.rb', line 44

def self.find_one(args)
  args['limit'] = 1
  find(args).first
end

.resetObject

Removes all cached detector instances



86
87
88
89
# File 'lib/matroid/detector.rb', line 86

def self.reset
  @@instances = {}
  @@ids = []
end

Instance Method Details

#classify_image_file(file_path) ⇒ Object

Submits an image file via url to be classified with the detector

Examples:

det = Matroid::Detector.find_by_id "5893f98530c1c00d0063835b"
det.classify_image_file "path/to/file.jpg"

Parameters:

  • url (String)

    Url for image file

Returns:

  • Hash containing the classification data see {#classify_image_url }

Raises:



220
221
222
223
224
# File 'lib/matroid/detector.rb', line 220

def classify_image_file(file_path)
  size_err = "Individual file size must be under #{IMAGE_FILE_SIZE_LIMIT / 1024 / 1024}MB"
  raise Error::InvalidQueryError.new(size_err) if File.size(file_path) > IMAGE_FILE_SIZE_LIMIT
  classify('image', file: File.new(file_path, 'rb'))
end

#classify_image_files(file_paths) ⇒ Object

The plural of #classify_image_file

Parameters:

  • file_paths (Array<String>)

    An array of images in the form of paths from the current directory

Returns:

  • Hash containing the classification data



229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
# File 'lib/matroid/detector.rb', line 229

def classify_image_files(file_paths)
  arg_err = "Error: Argument must be an array of image file paths"
  size_err = "Error: Total batch size must be under #{BATCH_FILE_SIZE_LIMIT / 1024 / 1024}MB"
  raise arg_err unless file_paths.is_a?(Array)
  batch_size = file_paths.inject(0){ |sum, file| sum + File.size(file) }
  raise size_err unless batch_size < BATCH_FILE_SIZE_LIMIT
  files = file_paths.map{ |file_path| ['file', File.new(file_path, 'rb')] }

  url = "#{Matroid.base_api_uri}detectors/#{@id}/classify_image"

  client = HTTPClient.new
  response = client.post(url, body: files, header: {'Authorization' => Matroid.token.authorization_header})
  Matroid.parse_response(response)
  # Matroid.post("detectors/#{@id}/classify_image", files) # responds with 'request entity too large' for some reason
end

#classify_image_url(url) ⇒ Object

Submits an image file via url to be classified with the detector

Examples:

det = Matroid::Detector.find_by_id "5893f98530c1c00d0063835b"
det.classify_image_url "https://www.allaboutbirds.org/guide/PHOTO/LARGE/common_tern_donnalynn.jpg"
### returns hash of results ###
# {
#   "results": [
#     {
#       "file": {
#         "name": "image1.png",
#         "url": "https://myimages.1.png",
#         "thumbUrl": "https://myimages.1_t.png",
#         "filetype": "image/png"
#       },
#       "predictions": [
#         {
#           "bbox": {
#             "left": 0.7533333333333333,
#             "top": 0.4504347826086956,
#             "height": 0.21565217391304348,
#             "aspectRatio": 1.0434782608695652
#           },
#           "labels": {
#             "cat face": 0.7078468322753906,
#             "dog face": 0.29215322732925415
#           }
#         },
#         {
#           "bbox": {
#             "left": 0.4533333333333333,
#             "top": 0.6417391304347826,
#             "width": 0.20833333333333334,
#             "height": 0.21739130434782608,
#             "aspectRatio": 1.0434782608695652
#           },
#           "labels": {
#             "cat face": 0.75759859402753906,
#             "dog face": 0.45895322732925415
#           }
#         }, {
#           ...
#         }
#       ]
#     }
#   ]
# }

Parameters:

  • url (String)

    Url for image file

Returns:

  • Hash containing the classification data.



210
211
212
# File 'lib/matroid/detector.rb', line 210

def classify_image_url(url)
  classify('image', url: url)
end

#classify_video_file(file_path) ⇒ Object

Submits a local video file to be classified with the detector

Parameters:

  • file_path (String)

    Path to file

Returns:

  • Hash containing the registered video’s id ex: { “video_id” => “58489472ff22bb2d3f95728c” }. Needed for Matroid.get_video_results(video_id)

Raises:



255
256
257
258
259
# File 'lib/matroid/detector.rb', line 255

def classify_video_file(file_path)
  size_err = "Video file size must be under #{VIDEO_FILE_SIZE_LIMIT / 1024 / 1024}MB"
  raise Error::InvalidQueryError.new(size_err) if File.size(file_path) > VIDEO_FILE_SIZE_LIMIT
  classify('video', file: File.new(file_path, 'rb'))
end

#classify_video_url(url) ⇒ Object

Submits a video file via url to be classified with the detector

Parameters:

  • url (String)

    Url for video file

Returns:

  • Hash containing the registered video’s id; ex: { “video_id” => “58489472ff22bb2d3f95728c” }. Needed for Matroid.get_video_results(video_id)



248
249
250
# File 'lib/matroid/detector.rb', line 248

def classify_video_url(url)
  classify('video', url: url)
end

#infoObject

Detector attributes in a nicely printed format for viewing



130
131
132
# File 'lib/matroid/detector.rb', line 130

def info
  puts JSON.pretty_generate(to_hash)
end

#is_trained?Boolean

Returns:

  • (Boolean)


152
153
154
# File 'lib/matroid/detector.rb', line 152

def is_trained?
  @state == 'trained'
end

#monitor_stream(stream_id, thresholds, options = {}) ⇒ Object

Monitor an existing stream on Matroid with your detector

Parameters:

  • stream_id (String)

    the id for the stream to monitor with the detector

  • thresholds (Hash)

    contains the keys for each label and the score cutoff for a notification. Example: { cat: 0.6, dog: 0.9 }

  • options (Hash) (defaults to: {})

    contains startTime, endTime [ISO strings], and endpoint [String]. The HTTP endpoint is called whenever there is a detection

Returns:

  • Hash containing the stream_id and monitoring_id

Raises:



266
267
268
269
270
271
272
273
274
# File 'lib/matroid/detector.rb', line 266

def monitor_stream(stream_id, thresholds, options = {})
  monitor_err = "Must include stream id"
  raise Error::InvalidQueryError.new(monitor_err) unless stream_id
  params = {
    thresholds: thresholds.to_json
  }
  params = params.merge(options)
  Matroid.post("feeds/#{stream_id}/monitor/#{@id}", params)
end

#to_hashHash

Detector attributes as a hash

Returns:

  • (Hash)


136
137
138
139
140
# File 'lib/matroid/detector.rb', line 136

def to_hash
  instance_variables.each_with_object(Hash.new(0)) do |element, hash|
    hash["#{element}".delete("@").to_sym] = instance_variable_get(element)
  end
end

#trainObject

Note:

Fails if detector is not qualified to be trained.

Submits detector instance for training

Raises:



145
146
147
148
149
# File 'lib/matroid/detector.rb', line 145

def train
  raise Error::APIError.new("This detector is already trained.") if is_trained?
  response = Matroid.post("detectors/#{@id}/finalize")
  response['detector']
end

#updateDetector

Updates the the detector data. Used when training to see the detector training progress.

Returns:



158
159
160
# File 'lib/matroid/detector.rb', line 158

def update
  self.class.find_by_id(@id)
end

#update_params(params) ⇒ Object



276
277
278
279
280
281
282
283
284
285
286
287
# File 'lib/matroid/detector.rb', line 276

def update_params(params)
  @id = params['id'] if params['id']
  @name = params['name'] if params['name']
  @labels = params['labels'] if params['labels']
  @label_ids = params['label_ids'] if params['label_ids']
  @permission_level = params['permission_level'] if params['permission_level']
  @owner = params['owner'] if params['owner']
  @type = params['type'] if params['type']
  @training = params['training'] if params['training']
  @state = params['state'] if params['state']
  self
end