sqed 0.7.1 → 0.8.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0a10699c845a53421c6ea0446eac442be0470448d0c55c876bb849c2ec4a928e
4
- data.tar.gz: b15da56bbbd2146e8683c7c19bcf3df8712c9bdb43c4015f173992e111b52520
3
+ metadata.gz: ecff3bc24d06653a25e90dd950faea277de23da61cdc7503e288d6098d8c4250
4
+ data.tar.gz: dd87d00a794d8edf2387c6d37d01382480ab0c161963f063764fadeee75a7f40
5
5
  SHA512:
6
- metadata.gz: 1f7b7798e7e21145b3d46da2f68ff8b5bd83f341a7926d894d3f7253e5551eafa8297a26bd5fb0053707acca91c2fec2db42638bc27b54c13d58986b8ab6a051
7
- data.tar.gz: b5ba7f2552f5db764f9436c77b874e7c094369d554a6df44ac15342a40177a7a80531fe1c3d87d2a34b725deeef21adec53fab1a311e0de7bf55e4a3ced64194
6
+ metadata.gz: 52aab726722c000e95af2e3e0de8e2ac584191972d74f6efa7e8127ee70404ebca0eb80493b2686f596e82a836a7302bcbc9f98b8d42759491d74313bd0f98f4
7
+ data.tar.gz: 2594a64f5b2f575515690314176aa00db01a69dfaef925aa5a1449c7e88b67373f20060f9f4fc172b5b07198c15636d3815a95d7d518e5380d45eda82924cefe
@@ -6,108 +6,108 @@ class Sqed
6
6
  # Layouts are Hashes defined in EXTRACTION_PATTERNS[<pattern>][<layout>]
7
7
  #
8
8
  class Boundaries
9
- include Enumerable
10
-
11
- # stores a hash
12
- # References the section by integer index!
13
- # In the pattern integer => [x1,y1, width, height] (ImageMagick convention rectangle descriptors)
14
- # e.g.
15
- # 0 => [10,10,40,40]
16
- attr_reader :coordinates
17
-
18
- # A symbol from Sqed::Config::LAYOUTS.keys
19
- # :right_t
20
- attr_accessor :layout
21
-
22
- # @return [Boolean] whether or not the last method to populate this object
23
- # executed to completion
24
- attr_accessor :complete
25
-
26
- def initialize(layout = nil)
27
- raise Sqed::Error, 'unrecognized layout' if layout && !SqedConfig::LAYOUTS.include?(layout)
28
- @complete = false
29
-
30
- @layout = layout
31
- @coordinates = {}
32
- initialize_coordinates if !@layout.nil?
33
- end
9
+ include Enumerable
10
+
11
+ # stores a hash
12
+ # References the section by integer index!
13
+ # In the pattern integer => [x1,y1, width, height] (ImageMagick convention rectangle descriptors)
14
+ # e.g.
15
+ # 0 => [10,10,40,40]
16
+ attr_reader :coordinates
17
+
18
+ # A symbol from Sqed::Config::LAYOUTS.keys
19
+ # :right_t
20
+ attr_accessor :layout
21
+
22
+ # @return [Boolean] whether or not the last method to populate this object
23
+ # executed to completion
24
+ attr_accessor :complete
25
+
26
+ def initialize(layout = nil)
27
+ raise Sqed::Error, 'unrecognized layout' if layout && !SqedConfig::LAYOUTS.include?(layout)
28
+ @complete = false
29
+
30
+ @layout = layout
31
+ @coordinates = {}
32
+ initialize_coordinates if !@layout.nil?
33
+ end
34
34
 
35
- def initialize_coordinates
36
- SqedConfig::LAYOUTS[@layout].each do |k|
37
- @coordinates.merge!(k => [nil, nil, nil, nil] )
35
+ def initialize_coordinates
36
+ SqedConfig::LAYOUTS[@layout].each do |k|
37
+ @coordinates.merge!(k => [nil, nil, nil, nil] )
38
+ end
38
39
  end
39
- end
40
40
 
41
- # @return [Sqed::Boundaries instance]
42
- # the idea here is to create a deep copy of self, offsetting by boundary
43
- # as we go
44
- def offset(boundary)
45
- b = Sqed::Boundaries.new
46
- (0..coordinates.length - 1).each do |i|
47
- b.set(i,
48
- [(x_for(i) + boundary.x_for(0)),
49
- (y_for(i) + boundary.y_for(0)),
50
- width_for(i),
51
- height_for(i)])
41
+ # @return [Sqed::Boundaries instance]
42
+ # the idea here is to create a deep copy of self, offsetting by boundary
43
+ # as we go
44
+ def offset(boundary)
45
+ b = Sqed::Boundaries.new
46
+ (0..coordinates.length - 1).each do |i|
47
+ b.set(i,
48
+ [(x_for(i) + boundary.x_for(0)),
49
+ (y_for(i) + boundary.y_for(0)),
50
+ width_for(i),
51
+ height_for(i)])
52
+ end
53
+ b.complete = complete
54
+ b
52
55
  end
53
- b.complete = complete
54
- b
55
- end
56
56
 
57
- def for(section)
58
- @coordinates[section]
59
- end
57
+ def for(section)
58
+ @coordinates[section]
59
+ end
60
60
 
61
- def each(&block)
62
- @coordinates.each do |section_index, coords|
63
- block.call([section_index, coords])
61
+ def each(&block)
62
+ @coordinates.each do |section_index, coords|
63
+ block.call([section_index, coords])
64
+ end
64
65
  end
65
- end
66
66
 
67
- # Overrides Enumerable
68
- def count
69
- @coordinates.length
70
- end
67
+ # Overrides Enumerable
68
+ def count
69
+ @coordinates.length
70
+ end
71
71
 
72
- def x_for(index)
73
- @coordinates[index][0]
74
- end
72
+ def x_for(index)
73
+ @coordinates[index][0]
74
+ end
75
75
 
76
- def y_for(index)
77
- @coordinates[index][1]
78
- end
76
+ def y_for(index)
77
+ @coordinates[index][1]
78
+ end
79
79
 
80
- def width_for(index)
81
- @coordinates[index][2]
82
- end
80
+ def width_for(index)
81
+ @coordinates[index][2]
82
+ end
83
83
 
84
- def height_for(index)
85
- @coordinates[index][3]
86
- end
84
+ def height_for(index)
85
+ @coordinates[index][3]
86
+ end
87
87
 
88
- def set(index, coordinates)
89
- @coordinates[index] = coordinates
90
- end
88
+ def set(index, coordinates)
89
+ @coordinates[index] = coordinates
90
+ end
91
91
 
92
- def populated?
93
- each do |index, coords|
94
- coords.each do |c|
95
- return false if c.nil?
92
+ def populated?
93
+ each do |index, coords|
94
+ coords.each do |c|
95
+ return false if c.nil?
96
+ end
96
97
  end
98
+ true
97
99
  end
98
- true
99
- end
100
100
 
101
- def zoom(width_factor, height_factor)
102
- coordinates.keys.each do |i|
103
- set(i, [
101
+ def zoom(width_factor, height_factor)
102
+ coordinates.keys.each do |i|
103
+ set(i, [
104
104
  (x_for(i).to_f * width_factor).to_i,
105
105
  (y_for(i).to_f * height_factor).to_i,
106
106
  (width_for(i).to_f * width_factor).to_i,
107
107
  (height_for(i).to_f * height_factor).to_i
108
- ])
108
+ ])
109
+ end
109
110
  end
110
- end
111
111
 
112
112
  end
113
113
  end
@@ -201,6 +201,16 @@ class Sqed::BoundaryFinder::ColorLineFinder < Sqed::BoundaryFinder
201
201
  boundaries.set(1, [ vertical.x_for(1), 0, right.width_for(0), right.height_for(0) ] )
202
202
  boundaries.set(2, [ vertical.x_for(1), right.y_for(1), right.width_for(1), right.height_for(1)] )
203
203
 
204
+ when :left_t
205
+ vertical = self.class.new(image: @image, layout: :vertical_split, boundary_color: boundary_color, use_thumbnail: false ).boundaries
206
+
207
+ ilft = image.crop(*vertical.for(0), true)
208
+ left = self.class.new(image: ilft, layout: :horizontal_split, boundary_color: boundary_color, use_thumbnail: false ).boundaries
209
+
210
+ boundaries.set(0, vertical.for(1))
211
+ boundaries.set(1, [ vertical.x_for(0), 0, left.width_for(0), left.height_for(0) ] )
212
+ boundaries.set(2, [ vertical.x_for(0), left.y_for(1), left.width_for(1), left.height_for(1)] )
213
+
204
214
  when :seven_slot
205
215
  top_bottom_split = Sqed::BoundaryFinder.color_boundary_finder(image: image, scan: :columns, boundary_color: boundary_color) # detect vertical division [array]
206
216
  left_right_split = Sqed::BoundaryFinder.color_boundary_finder(image: image, sample_subdivision_size: 1, boundary_color: boundary_color) # detect horizontal division [array]
@@ -263,7 +273,7 @@ class Sqed::BoundaryFinder::ColorLineFinder < Sqed::BoundaryFinder
263
273
  boundaries.set(0, [0, 0, image.columns, t[0]]) # upper section of image
264
274
  boundaries.set(1, [0, t[2], image.columns, image.rows - t[2]]) # lower section of image
265
275
 
266
- else # no @layout provided !?
276
+ else # Hits :stage
267
277
  boundaries.set(0, [0, 0, image.columns, image.rows]) # totality of image as default
268
278
  end
269
279
 
@@ -46,11 +46,11 @@ class Sqed::BoundaryFinder::StageFinder < Sqed::BoundaryFinder
46
46
 
47
47
  # Returns a Proc that, given a set of pixels (an edge of the image) decides
48
48
  # whether that edge is a border or not.
49
- #
50
- # (img, samples = 5, threshold = 0.95, fuzz_factor = 0.5) # initially
49
+ #
50
+ # (img, samples = 5, threshold = 0.95, fuzz_factor = 0.5) # initially
51
51
  # (img, samples = 50, threshold = 0.9, fuzz_factor = 0.1) # semi-working on synthetic images 08-dec-2014 (x)
52
52
  # (img, samples = 20, threshold = 0.8, fuzz_factor = 0.2) # WORKS with synthetic images and changes to x0, y0, width, height
53
- #
53
+ #
54
54
  # appears to assume sharp transition will occur in 5 pixels x/y
55
55
  #
56
56
  # how is threshold defined?
@@ -4,6 +4,10 @@ class Sqed
4
4
 
5
5
  # An Extractor takes Boundaries object and a metadata_map and returns a Sqed::Result
6
6
  #
7
+ # Extract assumes a successful preprocessing (e.g. finding boundaries, cropping images)!
8
+ #
9
+ # Only Tesseract based raises errors should be occurring at this point.
10
+ #
7
11
  class Extractor
8
12
 
9
13
  class Error < StandardError; end;
@@ -23,9 +27,10 @@ class Sqed
23
27
  @boundaries = opts[:boundaries]
24
28
  @image = opts[:image]
25
29
 
26
- raise Sqed::Error, 'boundaries not provided or provided boundary is not a Sqed::Boundaries' if boundaries.nil? || !boundaries.class.name == 'Sqed::Boundaries'
27
- raise Sqed::Error, 'metadata_map not provided or metadata_map not a Hash' if metadata_map.nil? || !metadata_map.class.name == 'Hash'
28
- raise Sqed::Error, 'image not provided' if image.nil? || !image.class.name == 'Magick::Image'
30
+ # TODO: `.extractable?` catches the nil? case
31
+ raise Sqed::Error, 'boundaries not provided or provided boundary is not a Sqed::Boundaries' if boundaries.nil? || !boundaries.kind_of?(Sqed::Boundaries)
32
+ raise Sqed::Error, 'metadata_map not provided or metadata_map not a Hash' if metadata_map.nil? || !metadata_map.kind_of?(Hash)
33
+ raise Sqed::Error, 'image not provided' if image.nil? || !image.kind_of?(Magick::Image)
29
34
  end
30
35
 
31
36
  def result
data/lib/sqed/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  class Sqed
2
- VERSION = '0.7.1'.freeze
2
+ VERSION = '0.8.0'.freeze
3
3
  end
data/lib/sqed.rb CHANGED
@@ -23,9 +23,33 @@ class Sqed
23
23
  require_relative 'sqed/result'
24
24
 
25
25
 
26
- # initial image which is an instance of ImageMagick::Image, containing background and stage, or just stage
26
+ # @return [Sqed::Boundaries instance, nil]
27
+ # Contains the coordinates of the internal stage sections. Calculates when set.
28
+ attr_accessor :boundaries
29
+
30
+ # @return [Symbol] like `:red`, `:green`, `:blue`, defaults to `:green`
31
+ # describing the boundary color within the stage
32
+ attr_accessor :boundary_color
33
+
34
+ # @return [Sqed::BoundaryFinder::<Klass>]
35
+ # Provide a boundary_finder, overrides metadata taken from pattern
36
+ attr_accessor :boundary_finder
37
+
38
+ # @return [Boolean] defaults to `true`
39
+ # when true detects border on initialization
40
+ attr_accessor :has_border
41
+
42
+ # initial image which is an instance of Magick::Image, containing background and stage, or just stage
27
43
  attr_accessor :image
28
44
 
45
+ # @return [Symbol] like `:cross`
46
+ # !! Provide a specific layout, passed as option :layout, overrides layout metadata taken from :pattern, defaults to `:cross`
47
+ attr_accessor :layout
48
+
49
+ # Provide a metadata map, overrides metadata taken from pattern.
50
+ # No calculations are done here.
51
+ attr_accessor :metadata_map
52
+
29
53
  # !optional! A lookup macro that if provided sets boundary_finder, layout, and metadata_map.
30
54
  # These can be individually overwritten.
31
55
  # Legal values are symbols taken from SqedConfig::EXTRACTION_PATTERNS.
@@ -39,41 +63,20 @@ class Sqed
39
63
  # not required if layout, metadata_map, and boundary_finder are provided
40
64
  attr_accessor :pattern
41
65
 
42
- # @return [Symbol] like `:cross`
43
- # !! Provide a specific layout, passed as option :layout, overrides layout metadata taken from :pattern, defaults to `:cross`
44
- attr_accessor :layout
45
-
46
- # the image that is the cropped content for parsing
66
+ # The image that is the cropped content for parsing
67
+ # !! Does not require `metadata_map` or `layout`
47
68
  attr_accessor :stage_image
48
69
 
49
70
  # @return [Sqed::Boundaries instance]
50
71
  # stores the coordinates of the stage
72
+ # !! Does not require `metadata_map` or `layout`
51
73
  attr_accessor :stage_boundary
52
74
 
53
- # @return [Sqed::Boundaries instance]
54
- # contains the coordinates of the internal stage sections
55
- attr_accessor :boundaries
56
-
57
- # @return [Boolean] defaults to `true`
58
- # when true detects border on initialization
59
- attr_accessor :has_border
60
-
61
- # @return [Symbol] like `:red`, `:green`, `:blue`, defaults to `:green`
62
- # describing the boundary color within the stage
63
- attr_accessor :boundary_color
64
-
65
75
  # @return [Boolean] defaults to `true` (faster, less accurate)
66
76
  # if `true` do the boundary detection (not stage detection at present)
67
77
  # against a thumbnail version of the passed image
68
78
  attr_accessor :use_thumbnail
69
79
 
70
- # Provide a metadata map, overrides metadata taken from pattern
71
- attr_accessor :metadata_map
72
-
73
- # @return [Sqed::BoundaryFinder::<Klass>]
74
- # Provide a boundary_finder, overrides metadata taken from pattern
75
- attr_accessor :boundary_finder
76
-
77
80
  def initialize(**opts)
78
81
  # extraction metadata
79
82
  @image = opts[:image]
@@ -86,71 +89,102 @@ class Sqed
86
89
  # federate extraction options
87
90
  def extraction_metadata
88
91
  {
89
- boundary_finder: boundary_finder,
90
- layout: layout,
91
- metadata_map: metadata_map,
92
- boundary_color: boundary_color,
93
- has_border: has_border,
94
- use_thumbnail: use_thumbnail
92
+ boundary_finder: boundary_finder,
93
+ layout: layout,
94
+ metadata_map: metadata_map,
95
+ boundary_color: boundary_color,
96
+ has_border: has_border,
97
+ use_thumbnail: use_thumbnail
95
98
  }
96
99
  end
97
100
 
98
- # @return [ImageMagick::Image]
101
+ # @return [Magick::Image]
99
102
  # set the image if it's not set during initialize(), not commonly used
100
103
  def image=(value)
101
- @image = value
102
- set_stage_boundary
103
- @image
104
- end
105
-
106
- def boundaries(force = false)
107
- @boundaries = get_section_boundaries if @boundaries.nil? || force
108
- @boundaries
104
+ @image = value if value.kind_of?(::Magick::Image)
109
105
  end
110
106
 
111
107
  def stage_boundary
112
- set_stage_boundary if !@stage_boundary.populated?
108
+ compute_stage_boundary if !@stage_boundary.populated?
113
109
  @stage_boundary
114
110
  end
115
111
 
116
112
  def stage_image
117
- crop_image if @stage_image.nil?
118
- @stage_image
119
- end
120
-
121
- # @return [Sqed::Boundaries instance, nil]
122
- # a boundaries instance that has the original image (prior to cropping stage) coordinates
123
- def native_boundaries
124
- if @boundaries.complete
125
- @boundaries.offset(stage_boundary)
126
- else
127
- nil
128
- end
113
+ @stage_image ||= crop_image
129
114
  end
130
115
 
131
116
  # @return [Image]
132
117
  # crops the stage if not done, then sets/returns @stage_image
133
118
  def crop_image
134
- if has_border
135
- @stage_image = image.crop(*stage_boundary.for(SqedConfig.index_for_section_type(:stage, :stage)), true)
136
- else
137
- @stage_image = image
119
+
120
+ begin
121
+
122
+ if has_border && image
123
+ @stage_image = image.crop(*stage_boundary.for(SqedConfig.index_for_section_type(:stage, :stage)), true)
124
+ elsif image
125
+ @stage_image = image
126
+ end
127
+ @stage_image
128
+
129
+ rescue Sqed::Error
130
+ raise
131
+ rescue
132
+ raise Sqed::Error, 'error cropping image'
133
+ end
134
+
135
+ end
136
+
137
+ def boundaries(force = false)
138
+ begin
139
+
140
+ if force
141
+ @boundaries = get_section_boundaries
142
+ else
143
+ @boundaries ||= get_section_boundaries
144
+ end
145
+
146
+ @boundaries
147
+
148
+ rescue Sqed::Error
149
+ raise
150
+ rescue # XXXX
151
+ raise Sqed::Error, 'error processing boundaries'
138
152
  end
139
- @stage_image
140
153
  end
141
154
 
155
+ # @return [Boolean]
156
+ # `true` if all boundary detection and image processing
157
+ # has been calculated with error
158
+ #
159
+ def extractable?
160
+ stage_image && metadata_map && boundaries
161
+ end
162
+
163
+ # @return [Sqed::Result, false]
142
164
  def result
143
- return false if image.nil?
165
+ return false unless extractable?
144
166
 
145
167
  extractor = Sqed::Extractor.new(
146
168
  boundaries: boundaries,
147
- metadata_map: metadata_map, # extraction_metadata[:metadata_map],
169
+ metadata_map: metadata_map,
148
170
  image: stage_image
149
171
  )
150
172
 
151
173
  extractor.result
152
174
  end
153
175
 
176
+ private
177
+
178
+ # @return [Sqed::Boundaries instance, nil]
179
+ # a boundaries instance that has the original image (prior to cropping stage) coordinates
180
+ def native_boundaries
181
+ if @boundaries.complete
182
+ @boundaries.offset(stage_boundary)
183
+ else
184
+ nil
185
+ end
186
+ end
187
+
154
188
  # @return [Hash]
155
189
  # an overview of data/metadata, for debugging purposes only
156
190
  def attributes
@@ -160,8 +194,6 @@ class Sqed
160
194
  }.merge!(extraction_metadata)
161
195
  end
162
196
 
163
- protected
164
-
165
197
  def configure(opts)
166
198
  configure_from_pattern(opts[:pattern])
167
199
  configure_boundary_finder(opts)
@@ -213,28 +245,31 @@ class Sqed
213
245
  def stub_results
214
246
  @boundaries = nil
215
247
  @stage_boundary = Sqed::Boundaries.new(:internal_box)
216
- set_stage_boundary if @image
248
+ compute_stage_boundary if @image
217
249
  end
218
250
 
251
+ # @return [Boundaries, nil]
219
252
  def get_section_boundaries
253
+
220
254
  boundary_finder.new(**section_params).boundaries
255
+
221
256
  end
222
257
 
223
258
  # @return [Hash]
224
259
  # variables for the isolated stage image
225
260
  def section_params
226
261
  {
227
- image: stage_image,
228
- use_thumbnail: use_thumbnail,
229
- layout: layout,
230
- boundary_color: boundary_color
262
+ image: stage_image,
263
+ use_thumbnail: use_thumbnail,
264
+ layout: layout,
265
+ boundary_color: boundary_color
231
266
  }
232
267
  end
233
268
 
234
- def set_stage_boundary
269
+ def compute_stage_boundary
235
270
  if has_border
236
271
  boundary = Sqed::BoundaryFinder::StageFinder.new(image: image).boundaries
237
- if boundary.populated?
272
+ if boundary&.populated?
238
273
  @stage_boundary.set(0, boundary.for(0))
239
274
  else
240
275
  raise Sqed::Error, 'error detecting stage'
data/lib/sqed_config.rb CHANGED
@@ -50,12 +50,7 @@ module SqedConfig
50
50
  # 6 |---- 3
51
51
  # | 4 |
52
52
  #
53
- #
54
- # | 1
55
- # 0 |---- :right_t
56
- # | 2
57
- #
58
- #
53
+ # #
59
54
  # 0 | 1 | 2
60
55
  # ------------
61
56
  # | 5 | 3 :seven_slot
@@ -73,35 +68,50 @@ module SqedConfig
73
68
  # 0 | 1 :vertical_split
74
69
  # |
75
70
  #
71
+ # -------
72
+ # |-----|
73
+ # || 0 || :internal_box
74
+ # |-----|
75
+ # -------
76
+ #
77
+ # 0 :t
76
78
  # -----
77
- # | 0 | :internal_box
78
- # -----
79
+ # 2 | 1
80
+ #
79
81
  #
80
82
  # 0 | 1 :inverted_t
81
83
  # -----
82
84
  # 2
83
85
  #
84
- # 0 :t
85
- # -----
86
- # 2 | 1
86
+ # 0 |
87
+ # ---| 1 : left_t
88
+ # 2 |
87
89
  #
90
+ # | 1
91
+ # 0 |--- :right_t
92
+ # | 2
88
93
  #
94
+ # -----
95
+ # | 0 | :stage
96
+ # -----
89
97
  #
90
98
  # Hash values are used to stub out
91
99
  # the Sqed::Boundaries instance.
92
100
  LAYOUTS = {
93
101
  t: [0,1,2],
94
102
  inverted_t: [0, 1, 2],
103
+ right_t: [0, 1, 2],
104
+ left_t: [0, 1, 2],
95
105
  cross: [0, 1, 2, 3],
96
106
  horizontal_offset_cross: [0, 1, 2, 3],
97
107
  horizontal_split: [0, 1],
98
108
  lep_stage: [0, 1, 2, 3, 4, 5, 6],
99
109
  lep_stage2: [0, 1, 2, 3, 4, 5, 6],
100
- right_t: [0, 1, 2],
101
110
  seven_slot: [0, 1, 2, 3, 4, 5, 6],
102
111
  vertical_offset_cross: [0, 1, 2, 3],
103
112
  vertical_split: [0, 1],
104
- internal_box: [0]
113
+ internal_box: [0],
114
+ stage: [0]
105
115
  }.freeze
106
116
 
107
117
  # Each element of the layout is a "section".
@@ -177,6 +187,12 @@ module SqedConfig
177
187
  metadata_map: { 0 => :curator_metadata, 1 => :collecting_event_labels, 2 => :image_registration, 3 => :identifier, 4 => :other_labels, 5 => :determination_labels, 6 => :specimen }
178
188
  },
179
189
 
190
+ left_t: {
191
+ boundary_finder: Sqed::BoundaryFinder::ColorLineFinder,
192
+ layout: :right_t,
193
+ metadata_map: { 0 => :annotated_specimen, 1 => :identifier, 2 => :image_registration }
194
+ },
195
+
180
196
  right_t: {
181
197
  boundary_finder: Sqed::BoundaryFinder::ColorLineFinder,
182
198
  layout: :right_t,
@@ -7,11 +7,11 @@ describe SqedConfig do
7
7
  end
8
8
 
9
9
  specify 'layouts' do
10
- expect(SqedConfig.metadata[:layouts].keys).to contain_exactly(:t, :inverted_t, :cross, :horizontal_offset_cross, :horizontal_split, :lep_stage, :lep_stage2, :right_t, :seven_slot, :vertical_offset_cross, :vertical_split)
10
+ expect(SqedConfig.metadata[:layouts].keys).to contain_exactly(:stage, :t, :left_t, :inverted_t, :cross, :horizontal_offset_cross, :horizontal_split, :lep_stage, :lep_stage2, :right_t, :seven_slot, :vertical_offset_cross, :vertical_split)
11
11
  end
12
12
 
13
13
  specify 'layouts are in patterns' do
14
- expect(SqedConfig.metadata[:layouts].keys + [:stage]).to contain_exactly(*SqedConfig::EXTRACTION_PATTERNS.keys)
14
+ expect(SqedConfig.metadata[:layouts].keys).to contain_exactly(*SqedConfig::EXTRACTION_PATTERNS.keys)
15
15
  end
16
16
 
17
17
  end
@@ -2,10 +2,7 @@ require 'spec_helper'
2
2
 
3
3
  describe Sqed do
4
4
 
5
- let(:s) { Sqed.new(
6
- pattern: :cross
7
- )
8
- }
5
+ let(:s) { Sqed.new( pattern: :cross) }
9
6
 
10
7
  context 'attributes' do
11
8
 
@@ -0,0 +1,61 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'handling T stage images' do
4
+
5
+ let(:image) { ImageHelpers.left_t_stage }
6
+ let(:sqed) do
7
+ Sqed.new(
8
+ image: image,
9
+ pattern: :left_t,
10
+ boundary_color: :red,
11
+ has_border: false )
12
+ end
13
+
14
+ let(:m) do
15
+ { 0 => 'annotated_specimen',
16
+ 1 => 'identifier',
17
+ 2 => 'image_registration'
18
+ }
19
+ end
20
+
21
+ context 'simple boundaries - without thumbnail' do
22
+ let(:s) { Sqed.new(
23
+ image: image, metadata_map: m, use_thumbnail: false,
24
+ layout: :left_t,
25
+ boundary_finder: Sqed::BoundaryFinder::ColorLineFinder,
26
+ boundary_color: :red,
27
+ has_border: false ) }
28
+
29
+ specify 'boundaries are reasonable' do
30
+ s.result
31
+ c = s.boundaries.coordinates
32
+ c.each do |section, values|
33
+ c[section].each_with_index do |v, i|
34
+ msg = "section #{section}, index #{i} has a bad value '#{v}'"
35
+ expect(v > -1).to be_truthy, msg
36
+ end
37
+ end
38
+ end
39
+ end
40
+
41
+ context 'boundaries - with_thumbnail' do
42
+ let(:s) { Sqed.new(
43
+ image: image,
44
+ use_thumbnail: true,
45
+ pattern: :left_t,
46
+ boundary_color: :red,
47
+ has_border: false ) }
48
+
49
+ specify 'boundaries are reasonable' do
50
+ s.result
51
+ c = s.boundaries.coordinates
52
+ c.each do |section, values|
53
+ c[section].each_with_index do |v, i|
54
+ msg = "section #{section}, index #{i} has a bad value '#{v}'"
55
+ expect(v > -1).to be_truthy, msg
56
+ end
57
+ end
58
+ end
59
+ end
60
+
61
+ end
@@ -0,0 +1,55 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'handling stage images' do
4
+
5
+ let(:image) { ImageHelpers.stage }
6
+ let(:sqed) do
7
+ Sqed.new(
8
+ image: image,
9
+ pattern: :stage,
10
+ has_border: false )
11
+ end
12
+
13
+ let(:m) do
14
+ { 0 => 'stage' }
15
+ end
16
+
17
+ context 'simple boundaries - without thumbnail' do
18
+ let(:s) { Sqed.new(
19
+ image: image, metadata_map: m, use_thumbnail: false,
20
+ layout: :stage,
21
+ boundary_finder: Sqed::BoundaryFinder::ColorLineFinder,
22
+ has_border: false ) }
23
+
24
+ specify 'boundaries are reasonable' do
25
+ s.result
26
+ c = s.boundaries.coordinates
27
+ c.each do |section, values|
28
+ c[section].each_with_index do |v, i|
29
+ msg = "section #{section}, index #{i} has a bad value '#{v}'"
30
+ expect(v > -1).to be_truthy, msg
31
+ end
32
+ end
33
+ end
34
+ end
35
+
36
+ context 'boundaries - with_thumbnail' do
37
+ let(:s) { Sqed.new(
38
+ image: image,
39
+ use_thumbnail: true,
40
+ pattern: :stage,
41
+ has_border: false ) }
42
+
43
+ specify 'boundaries are reasonable' do
44
+ s.result
45
+ c = s.boundaries.coordinates
46
+ c.each do |section, values|
47
+ c[section].each_with_index do |v, i|
48
+ msg = "section #{section}, index #{i} has a bad value '#{v}'"
49
+ expect(v > -1).to be_truthy, msg
50
+ end
51
+ end
52
+ end
53
+ end
54
+
55
+ end
@@ -16,6 +16,10 @@ module ImageHelpers
16
16
 
17
17
  # Stage images
18
18
 
19
+ def stage
20
+ get_image 'stage_images/stage.png'
21
+ end
22
+
19
23
  def t_stage
20
24
  get_image 'stage_images/t_stage.png'
21
25
  end
@@ -24,6 +28,10 @@ module ImageHelpers
24
28
  get_image 'stage_images/inverted_t_stage.png'
25
29
  end
26
30
 
31
+ def left_t_stage
32
+ get_image 'stage_images/left_t_stage.png'
33
+ end
34
+
27
35
  def cross_green
28
36
  get_image 'stage_images/boundary_cross_green.jpg'
29
37
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sqed
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.7.1
4
+ version: 0.8.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Matt Yoder
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2022-06-01 00:00:00.000000000 Z
12
+ date: 2023-05-16 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rake
@@ -156,9 +156,11 @@ files:
156
156
  - spec/lib/sqed_utils_spec.rb
157
157
  - spec/lib/stage_handling/horizontal_offset_cross_spec.rb
158
158
  - spec/lib/stage_handling/inverted_t_stage_spec.rb
159
+ - spec/lib/stage_handling/left_t_stage_spec.rb
159
160
  - spec/lib/stage_handling/lep_stage2_spec.rb
160
161
  - spec/lib/stage_handling/lep_stage_spec.rb
161
162
  - spec/lib/stage_handling/seven_slot_spec.rb
163
+ - spec/lib/stage_handling/stage_spec.rb
162
164
  - spec/lib/stage_handling/t_stage_spec.rb
163
165
  - spec/spec_helper.rb
164
166
  - spec/support/files/barcode_images/code_128_barcode.png
@@ -188,9 +190,11 @@ files:
188
190
  - spec/support/files/stage_images/inhs_7_slot3.jpg
189
191
  - spec/support/files/stage_images/inhs_four_thirds.jpg
190
192
  - spec/support/files/stage_images/inverted_t_stage.png
193
+ - spec/support/files/stage_images/left_t_stage.png
191
194
  - spec/support/files/stage_images/lep_stage.jpg
192
195
  - spec/support/files/stage_images/lep_stage2.jpg
193
196
  - spec/support/files/stage_images/lep_stage3.jpg
197
+ - spec/support/files/stage_images/stage.png
194
198
  - spec/support/files/stage_images/t_stage.png
195
199
  - spec/support/files/test0.jpg
196
200
  - spec/support/files/test1.jpg
@@ -219,7 +223,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
219
223
  - !ruby/object:Gem::Version
220
224
  version: '0'
221
225
  requirements: []
222
- rubygems_version: 3.2.22
226
+ rubygems_version: 3.4.12
223
227
  signing_key:
224
228
  specification_version: 4
225
229
  summary: Specimens Quickly extracted and Digitized, or just "squid". A ruby gem for
@@ -240,9 +244,11 @@ test_files:
240
244
  - spec/lib/sqed_utils_spec.rb
241
245
  - spec/lib/stage_handling/horizontal_offset_cross_spec.rb
242
246
  - spec/lib/stage_handling/inverted_t_stage_spec.rb
247
+ - spec/lib/stage_handling/left_t_stage_spec.rb
243
248
  - spec/lib/stage_handling/lep_stage2_spec.rb
244
249
  - spec/lib/stage_handling/lep_stage_spec.rb
245
250
  - spec/lib/stage_handling/seven_slot_spec.rb
251
+ - spec/lib/stage_handling/stage_spec.rb
246
252
  - spec/lib/stage_handling/t_stage_spec.rb
247
253
  - spec/spec_helper.rb
248
254
  - spec/support/files/barcode_images/code_128_barcode.png
@@ -272,9 +278,11 @@ test_files:
272
278
  - spec/support/files/stage_images/inhs_7_slot3.jpg
273
279
  - spec/support/files/stage_images/inhs_four_thirds.jpg
274
280
  - spec/support/files/stage_images/inverted_t_stage.png
281
+ - spec/support/files/stage_images/left_t_stage.png
275
282
  - spec/support/files/stage_images/lep_stage.jpg
276
283
  - spec/support/files/stage_images/lep_stage2.jpg
277
284
  - spec/support/files/stage_images/lep_stage3.jpg
285
+ - spec/support/files/stage_images/stage.png
278
286
  - spec/support/files/stage_images/t_stage.png
279
287
  - spec/support/files/test0.jpg
280
288
  - spec/support/files/test1.jpg