sqed 0.5.8 → 0.6.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: 189f2b34c7f74be111c238f7b8ebc5afdbe9f271defe7fe28eba2fa20fc1a11b
4
- data.tar.gz: f45e49206f74d86f6367969010056161af9d3a17e105a786c5279a3c7b3b4529
3
+ metadata.gz: ff31f97d4d846b9112badb1fad358118d858e028cb2835050f49ca767dbfdfba
4
+ data.tar.gz: 36d2dadf1291dff04b60d596b239cbbf484cf4c180182b694b103b244f8bba15
5
5
  SHA512:
6
- metadata.gz: 8f7bf2d0a0a89bb0f4ceaf9bb9348a3cd0e29ee146ece899dfb68f784c3b7f838d368b3f1bd25287e55a27b7e090f1ba311160e9e1cd7cc3a22ae40c713fa2af
7
- data.tar.gz: 6f1b250541ff6b4ac24a94b529e3bc73df53fd5c6ac8ebf2043d9b6e5ff9b3fa40c7b586dd9bbafb732c688d396071cfa43f77c9a4fe78362e503bdb9e21c523
6
+ metadata.gz: 51724aa1c870b25bcfa88bb8d7954a72226e9080f64cc83e41a8263940ccf61c46d72242887b4c42adeb5f96ef3b12bf88b3c2ebdd816b0128f6839febf34ca5
7
+ data.tar.gz: b6f5201476f18b8ba5ad9444f6ac63f8b9d86ff1eb0a089da55521566cf3a8b57a25a5b70eb0478b8121582c5c88b34dab05cab45630b339a8649ed23855b015
@@ -1 +1 @@
1
- 2.5.1
1
+ 2.7.1
@@ -12,6 +12,8 @@ rvm:
12
12
  before_install:
13
13
  - sudo apt-get update -qq
14
14
  - sudo apt-get install -qq tesseract-ocr tesseract-ocr-nld
15
+ - sudo sed -i 's/name="disk" value="1GiB"/name="disk" value="8GiB"/' /etc/ImageMagick-6/policy.xml
16
+ - identify -list resource | grep Disk | grep 8GiB # Check ImageMagick setting is actually working.
15
17
  branches:
16
18
  only:
17
19
  - master
@@ -17,10 +17,12 @@ require 'sqed_utils'
17
17
  #
18
18
  class Sqed
19
19
 
20
+ require_relative 'sqed/error'
20
21
  require_relative 'sqed_config'
21
22
  require_relative 'sqed/extractor'
22
23
  require_relative 'sqed/result'
23
24
 
25
+
24
26
  # initial image which is an instance of ImageMagick::Image, containing background and stage, or just stage
25
27
  attr_accessor :image
26
28
 
@@ -68,6 +70,7 @@ class Sqed
68
70
  # Provide a metadata map, overrides metadata taken from pattern
69
71
  attr_accessor :metadata_map
70
72
 
73
+ # @return [Sqed::BoundaryFinder::<Klass>]
71
74
  # Provide a boundary_finder, overrides metadata taken from pattern
72
75
  attr_accessor :boundary_finder
73
76
 
@@ -165,6 +168,8 @@ class Sqed
165
168
  configure_layout(opts)
166
169
  configure_metadata_map(opts)
167
170
 
171
+ raise Sqed::Error, 'boundary_finder not provided' if @boundary_finder.nil?
172
+
168
173
  @has_border = opts[:has_border]
169
174
  @has_border = true if @has_border.nil?
170
175
 
@@ -184,12 +189,12 @@ class Sqed
184
189
  @boundary_finder = a[:boundary_finder]
185
190
  @layout = a[:layout]
186
191
  @metadata_map = a[:metadata_map]
192
+
187
193
  true
188
194
  end
189
195
 
190
196
  def configure_boundary_finder(opts)
191
- @boundary_finder = opts[:boundary_finder].constantize if !opts[:boundary_finder].nil?
192
- @boundary_finder ||= Sqed::BoundaryFinder::CrossFinder
197
+ @boundary_finder = opts[:boundary_finder] if !opts[:boundary_finder].nil?
193
198
  end
194
199
 
195
200
  def configure_layout(opts)
@@ -212,7 +217,7 @@ class Sqed
212
217
  end
213
218
 
214
219
  def get_section_boundaries
215
- boundary_finder.new(section_params).boundaries
220
+ boundary_finder.new(**section_params).boundaries
216
221
  end
217
222
 
218
223
  # @return [Hash]
@@ -6,6 +6,7 @@ class Sqed
6
6
  #
7
7
  class BoundaryFinder
8
8
 
9
+ # Problemantic (e.g. seven slot) seem to resolve at ~360
9
10
  THUMB_SIZE = 100
10
11
  COLOR_DELTA = 1.3 # color (e.g. red) must be this much be *COLOR_DELTA > than other values (e.g. blue/green)
11
12
 
@@ -18,7 +19,8 @@ class Sqed
18
19
  # A Sqed::Boundaries instance, stores the coordinates of all of the layout sections
19
20
  attr_reader :boundaries
20
21
 
21
- # Whether to compress the original image to a thumbnail when finding boundaries
22
+ # @return Boolean
23
+ # Whether to compress the original image to a thumbnail when finding boundaries at certain steps of the processing
22
24
  attr_reader :use_thumbnail
23
25
 
24
26
  # when we compute using a derived thumbnail we temporarily store the full size image here
@@ -135,7 +137,7 @@ class Sqed
135
137
  while attempts < 5 do
136
138
  samples_to_take = (image_width / sample_subdivision_size).to_i - 1
137
139
  border_hits = sample_border(image, boundary_color, samples_to_take, sample_subdivision_size, scan)
138
-
140
+
139
141
  break if border_hits.select{|k,v| v > 1}.size > 2 || sample_subdivision_size == 1
140
142
 
141
143
  sample_subdivision_size = (sample_subdivision_size.to_f / 2.0).to_i
@@ -207,7 +209,7 @@ class Sqed
207
209
  # the start, mid, endpoint position of all (pixel) positions that have a count greater than the cutoff
208
210
  def self.frequency_stats(frequency_hash, sample_cutoff = 0)
209
211
 
210
- return nil if sample_cutoff.nil? || sample_cutoff < 1
212
+ return nil if sample_cutoff.nil? || sample_cutoff < 1
211
213
  hit_ranges = []
212
214
 
213
215
  frequency_hash.each do |position, count|
@@ -236,6 +238,11 @@ class Sqed
236
238
  [hit_ranges.first, hit_ranges[(hit_ranges.length / 2).to_i], hit_ranges.last]
237
239
  end
238
240
 
241
+ def self.max_difference(array)
242
+ array.max - array.min
243
+ end
244
+
245
+ # Usused
239
246
 
240
247
  # Returns an Integer, the maximum of the pairwise differences of the values in the array
241
248
  # For example, given
@@ -248,10 +255,6 @@ class Sqed
248
255
  (0..array.length - 2).map{|i| (array[i] - array[i + 1]).abs }.max
249
256
  end
250
257
 
251
- def self.max_difference(array)
252
- array.max - array.min
253
- end
254
-
255
258
  def self.derivative_signs(array)
256
259
  (0..array.length - 2).map { |i| (array[i + 1] - array[i]) <=> 0 }
257
260
  end
@@ -29,34 +29,39 @@ class Sqed::BoundaryFinder::ColorLineFinder < Sqed::BoundaryFinder
29
29
 
30
30
  private
31
31
 
32
+ # boundaries.coordinates are referenced from stage image
33
+ #
34
+ # A reminder that boundaries are x1,y1, width, height
32
35
  def find_bands
33
- case layout # boundaries.coordinates are referenced from stage image
36
+
37
+ # see config/sqed_config.rb
38
+ case layout
34
39
 
35
40
  when :cross # 4 zones, with perfectly intersected horizontal and vertical division
36
41
  v = self.class.new(image: @image, layout: :vertical_split, boundary_color: boundary_color, use_thumbnail: false ).boundaries
37
- h = self.class.new(image: @image, layout: :horizontal_split, boundary_color: boundary_color, use_thumbnail: false).boundaries
42
+ h = self.class.new(image: @image, layout: :horizontal_split, boundary_color: boundary_color, use_thumbnail: false).boundaries
38
43
 
39
44
  return if v.nil? || h.nil?
40
45
 
41
- boundaries.set(0, [0,0, v.width_for(0), h.height_for(0) ])
42
- boundaries.set(1, [ v.x_for(1), 0, v.width_for(1), h.height_for(0) ])
43
- boundaries.set(2, [ v.x_for(1), h.y_for(1), v.width_for(1), h.height_for(1) ])
44
- boundaries.set(3, [0, h.y_for(1), v.width_for(0), h.height_for(1) ])
46
+ boundaries.set(0, [0,0, v.width_for(0), h.height_for(0) ])
47
+ boundaries.set(1, [ v.x_for(1), 0, v.width_for(1), h.height_for(0) ])
48
+ boundaries.set(2, [ v.x_for(1), h.y_for(1), v.width_for(1), h.height_for(1) ])
49
+ boundaries.set(3, [0, h.y_for(1), v.width_for(0), h.height_for(1) ])
45
50
 
46
51
  # No specs for this yet
47
52
  when :horizontal_offset_cross
48
53
  horizontal = self.class.new(image: @image, layout: :horizontal_split, boundary_color: boundary_color, use_thumbnail: false ).boundaries
49
54
 
50
- itop = image.crop(*horizontal.for(0), true)
55
+ itop = image.crop(*horizontal.for(0), true)
51
56
  ibottom = image.crop(*horizontal.for(1), true)
52
57
 
53
58
  top = self.class.new(image: itop, layout: :vertical_split, boundary_color: boundary_color, use_thumbnail: false ).boundaries
54
59
  bottom = self.class.new(image: ibottom, layout: :vertical_split, boundary_color: boundary_color, use_thumbnail: false ).boundaries
55
60
 
56
- boundaries.set(0, [0, 0, top.width_for(0), top.height_for(0) ])
57
- boundaries.set(1, [top.x_for(1), 0, top.width_for(1), top.height_for(1) ])
58
- boundaries.set(2, [bottom.x_for(1), horizontal.y_for(1), bottom.width_for(1), bottom.height_for(1) ])
59
- boundaries.set(3, [0, horizontal.y_for(1), bottom.width_for(0), bottom.height_for(0) ])
61
+ boundaries.set(0, [0, 0, top.width_for(0), top.height_for(0) ])
62
+ boundaries.set(1, [top.x_for(1), 0, top.width_for(1), top.height_for(1) ])
63
+ boundaries.set(2, [bottom.x_for(1), horizontal.y_for(1), bottom.width_for(1), bottom.height_for(1) ])
64
+ boundaries.set(3, [0, horizontal.y_for(1), bottom.width_for(0), bottom.height_for(0) ])
60
65
 
61
66
  when :lep_stage
62
67
  top_bottom_split = Sqed::BoundaryFinder.color_boundary_finder(image: image, scan: :columns, boundary_color: boundary_color) # detect vertical division [array]
@@ -64,9 +69,9 @@ class Sqed::BoundaryFinder::ColorLineFinder < Sqed::BoundaryFinder
64
69
 
65
70
  boundaries.set(6, [0, top_bottom_split[2], left_right_split[0], image.rows - top_bottom_split[2]] )
66
71
 
67
- left_top_image = image.crop( 0, 0, left_right_split[0], top_bottom_split[0], true)
72
+ left_top_image = image.crop( 0, 0, left_right_split[0], top_bottom_split[0], true)
68
73
 
69
- left_top_split =
74
+ left_top_split =
70
75
  SqedUtils.corrected_frequency(
71
76
  Sqed::BoundaryFinder.color_boundary_finder(image: left_top_image, boundary_color: boundary_color),
72
77
  max_width: left_top_image.columns,
@@ -74,8 +79,8 @@ class Sqed::BoundaryFinder::ColorLineFinder < Sqed::BoundaryFinder
74
79
  )
75
80
 
76
81
  boundaries.set(0, [0, 0, left_top_split[1], top_bottom_split[0]] ) # keep as 1 for safety
77
-
78
- boundaries.set(1, [left_top_split[2], 0, left_top_image.columns - left_top_split[2], top_bottom_split[0]] )
82
+
83
+ boundaries.set(1, [left_top_split[2], 0, left_top_image.columns - left_top_split[2], top_bottom_split[0]] )
79
84
  boundaries.set(2, [left_right_split[2], 0, image.columns - left_right_split[0], top_bottom_split[0]] )
80
85
 
81
86
  bottom_right_image = image.crop(left_right_split[2], top_bottom_split[2], image.columns - left_right_split[2], image.rows - top_bottom_split[2], true)
@@ -89,7 +94,7 @@ class Sqed::BoundaryFinder::ColorLineFinder < Sqed::BoundaryFinder
89
94
 
90
95
  boundaries.set(3, [left_right_split[2] + bottom_right_split[2], top_bottom_split[2], image.columns - bottom_right_split[2], image.rows - top_bottom_split[2] ] )
91
96
 
92
- bottom_right_left_image = image.crop(left_right_split[2], top_bottom_split[2], bottom_right_split[0], image.rows - top_bottom_split[2], true)
97
+ bottom_right_left_image = image.crop(left_right_split[2], top_bottom_split[2], bottom_right_split[0], image.rows - top_bottom_split[2], true)
93
98
 
94
99
  bottom_right_left_split =
95
100
  SqedUtils.corrected_frequency(
@@ -101,10 +106,69 @@ class Sqed::BoundaryFinder::ColorLineFinder < Sqed::BoundaryFinder
101
106
  boundaries.set(4, [left_right_split[2], top_bottom_split[2], bottom_right_image.columns - bottom_right_left_image.columns, bottom_right_left_split[0] ] )
102
107
 
103
108
  boundaries.set(5, [
104
- left_right_split[2],
109
+ left_right_split[2],
105
110
  top_bottom_split[2] + bottom_right_left_split[2],
106
111
  bottom_right_image.columns - bottom_right_left_image.columns,
107
- bottom_right_left_image.rows - bottom_right_left_split[2]
112
+ bottom_right_left_image.rows - bottom_right_left_split[2]
113
+ ])
114
+
115
+ when :lep_stage2
116
+ top_bottom_split = Sqed::BoundaryFinder.color_boundary_finder(image: image, scan: :columns, boundary_color: boundary_color) # detect vertical division [array]
117
+ left_right_split = Sqed::BoundaryFinder.color_boundary_finder(image: image, sample_subdivision_size: 2, boundary_color: boundary_color) # detect horizontal division [array]
118
+
119
+ boundaries.set(6, [0, top_bottom_split[2], left_right_split[0], image.rows - top_bottom_split[2]] ) # OK
120
+
121
+ left_top_image = image.crop( 0, 0, left_right_split[0], top_bottom_split[0], true)
122
+
123
+ left_top_split =
124
+ SqedUtils.corrected_frequency(
125
+ Sqed::BoundaryFinder.color_boundary_finder(image: left_top_image, boundary_color: boundary_color),
126
+ max_width: left_top_image.columns,
127
+ width_factor: 1.8
128
+ )
129
+
130
+ boundaries.set(0, [0, 0, left_top_split[1], top_bottom_split[0]] ) # OK
131
+
132
+ boundaries.set(1, [left_top_split[2], 0, left_top_image.columns - left_top_split[2], top_bottom_split[0]] )
133
+ boundaries.set(2, [left_right_split[2], 0, image.columns - left_right_split[0], top_bottom_split[0]] )
134
+
135
+ bottom_right_image = image.crop(left_right_split[2], top_bottom_split[2], image.columns - left_right_split[2], image.rows - top_bottom_split[2], true)
136
+
137
+ bottom_right_split =
138
+ SqedUtils.corrected_frequency(
139
+ Sqed::BoundaryFinder.color_boundary_finder(image: bottom_right_image, boundary_color: boundary_color, scan: :rows),
140
+ max_width: bottom_right_image.columns,
141
+ width_factor: 1.8
142
+ )
143
+
144
+ boundaries.set(3, [
145
+ left_right_split[2] + bottom_right_split[2],
146
+ top_bottom_split[2],
147
+ image.columns - bottom_right_split[2],
148
+ top_bottom_split[0] ])
149
+
150
+ bottom_right_left_image = image.crop(left_right_split[2], top_bottom_split[2], bottom_right_split[0], image.rows - top_bottom_split[2], true)
151
+
152
+ bottom_right_left_top_bottom_split =
153
+ SqedUtils.corrected_frequency(
154
+ Sqed::BoundaryFinder.color_boundary_finder(image: bottom_right_left_image, scan: :columns, boundary_color: boundary_color),
155
+ max_width: bottom_right_left_image.columns,
156
+ width_factor: 1.8
157
+ )
158
+
159
+ boundaries.set(4, [
160
+ left_right_split[2],
161
+ top_bottom_split[2] + bottom_right_left_top_bottom_split[2],
162
+ bottom_right_left_image.columns,
163
+ bottom_right_left_top_bottom_split[2]
164
+ ])
165
+
166
+
167
+ boundaries.set(5, [
168
+ left_right_split[2],
169
+ top_bottom_split[2],
170
+ bottom_right_left_image.columns,
171
+ bottom_right_left_top_bottom_split[0],
108
172
  ])
109
173
 
110
174
  when :right_t
@@ -113,13 +177,13 @@ class Sqed::BoundaryFinder::ColorLineFinder < Sqed::BoundaryFinder
113
177
  irt = image.crop(*vertical.for(1), true)
114
178
  right = self.class.new(image: irt, layout: :horizontal_split, boundary_color: boundary_color, use_thumbnail: false ).boundaries
115
179
 
116
- boundaries.set(0, vertical.for(0))
117
- boundaries.set(1, [ vertical.x_for(1), 0, right.width_for(0), right.height_for(0) ] )
118
- boundaries.set(2, [ vertical.x_for(1), right.y_for(1), right.width_for(1), right.height_for(1)] )
180
+ boundaries.set(0, vertical.for(0))
181
+ boundaries.set(1, [ vertical.x_for(1), 0, right.width_for(0), right.height_for(0) ] )
182
+ boundaries.set(2, [ vertical.x_for(1), right.y_for(1), right.width_for(1), right.height_for(1)] )
119
183
 
120
184
  when :seven_slot
121
185
  top_bottom_split = Sqed::BoundaryFinder.color_boundary_finder(image: image, scan: :columns, boundary_color: boundary_color) # detect vertical division [array]
122
- left_right_split = Sqed::BoundaryFinder.color_boundary_finder(image: image, sample_subdivision_size: 2, boundary_color: boundary_color) # detect horizontal division [array]
186
+ left_right_split = Sqed::BoundaryFinder.color_boundary_finder(image: image, sample_subdivision_size: 1, boundary_color: boundary_color) # detect horizontal division [array]
123
187
 
124
188
  boundaries.set(0, [0, 0, left_right_split[0], top_bottom_split[0]])
125
189
  boundaries.set(6, [0, top_bottom_split[2], left_right_split[0], image.rows - top_bottom_split[2]] )
@@ -128,18 +192,22 @@ class Sqed::BoundaryFinder::ColorLineFinder < Sqed::BoundaryFinder
128
192
  right_bottom_image = image.crop(left_right_split[2], top_bottom_split[2], image.columns - left_right_split[2], image.rows - top_bottom_split[2], true) # sections 3,4,5
129
193
 
130
194
  right_top_split = ::SqedUtils.corrected_frequency(
131
- Sqed::BoundaryFinder.color_boundary_finder(image: right_top_image, boundary_color: boundary_color, scan: :rows),
132
- width_factor: 1.8,
133
- max_width: right_top_image.columns
195
+ Sqed::BoundaryFinder.color_boundary_finder(
196
+ image: right_top_image, boundary_color: boundary_color, scan: :rows),
197
+ width_factor: 1.8,
198
+ max_width: right_top_image.columns
134
199
  ) # vertical line b/w 1 & 2, use "corrected_frequency" to account for color bleed from previous crop
135
200
 
136
201
  boundaries.set(1, [left_right_split[2], 0, right_top_split[0], top_bottom_split[0]] )
137
202
  boundaries.set(2, [left_right_split[2] + right_top_split[2], 0, right_top_image.columns - right_top_split[2], top_bottom_split[0]])
138
203
 
139
204
  right_bottom_split = SqedUtils.corrected_frequency(
140
- Sqed::BoundaryFinder.color_boundary_finder(image: right_bottom_image, scan: :columns, sample_subdivision_size: 2, boundary_color: boundary_color),
141
- width_factor: 1.8,
142
- max_width: right_bottom_image.rows) # horizontal line b/w (5,3) & 4, use "corrected_frequency" to account for color bleed from previous crop
205
+ Sqed::BoundaryFinder.color_boundary_finder(
206
+ image: right_bottom_image,
207
+ scan: :columns,
208
+ sample_subdivision_size: 2, boundary_color: boundary_color),
209
+ width_factor: 1.8,
210
+ max_width: right_bottom_image.rows) # horizontal line b/w (5,3) & 4, use "corrected_frequency" to account for color bleed from previous crop
143
211
 
144
212
  bottom_right_top_image = right_bottom_image.crop(0,0, image.columns - left_right_split[2], right_bottom_split[0], true) # 3,5
145
213
 
@@ -151,18 +219,18 @@ class Sqed::BoundaryFinder::ColorLineFinder < Sqed::BoundaryFinder
151
219
  when :vertical_offset_cross # 4 zones expected, with (varying) horizontal division in left- and right- sides of vertical division
152
220
  vertical = self.class.new(image: @image, layout: :vertical_split, boundary_color: boundary_color, use_thumbnail: false).boundaries
153
221
 
154
- ilt = image.crop(*vertical.for(0), true)
222
+ ilt = image.crop(*vertical.for(0), true)
155
223
  irt = image.crop(*vertical.for(1), true)
156
224
 
157
225
  left = self.class.new(image: ilt, layout: :horizontal_split, boundary_color: boundary_color, use_thumbnail: false).boundaries # fails
158
226
  right = self.class.new(image: irt, layout: :horizontal_split, boundary_color: boundary_color, use_thumbnail: false ).boundaries # OK
159
227
 
160
- boundaries.set(0, [0, 0, left.width_for(0), left.height_for(0) ])
161
- boundaries.set(1, [vertical.x_for(1), 0, right.width_for(0), right.height_for(0) ])
162
- boundaries.set(2, [vertical.x_for(1), right.y_for(1), right.width_for(1), right.height_for(1) ])
163
- boundaries.set(3, [0, left.y_for(1), left.width_for(1), left.height_for(1) ])
228
+ boundaries.set(0, [0, 0, left.width_for(0), left.height_for(0) ])
229
+ boundaries.set(1, [vertical.x_for(1), 0, right.width_for(0), right.height_for(0) ])
230
+ boundaries.set(2, [vertical.x_for(1), right.y_for(1), right.width_for(1), right.height_for(1) ])
231
+ boundaries.set(3, [0, left.y_for(1), left.width_for(1), left.height_for(1) ])
164
232
 
165
- when :vertical_split
233
+ when :vertical_split
166
234
  t = Sqed::BoundaryFinder.color_boundary_finder(image: image, boundary_color: boundary_color) #detect vertical division
167
235
  return if t.nil?
168
236
  boundaries.set(0, [0, 0, t[0], image.rows]) # left section of image
@@ -175,10 +243,7 @@ class Sqed::BoundaryFinder::ColorLineFinder < Sqed::BoundaryFinder
175
243
  boundaries.set(0, [0, 0, image.columns, t[0]]) # upper section of image
176
244
  boundaries.set(1, [0, t[2], image.columns, image.rows - t[2]]) # lower section of image
177
245
 
178
-
179
-
180
246
  else # no @layout provided !?
181
-
182
247
  boundaries.set(0, [0, 0, image.columns, image.rows]) # totality of image as default
183
248
  end
184
249
 
@@ -0,0 +1,2 @@
1
+ class Sqed::Error < StandardError
2
+ end
@@ -23,8 +23,8 @@ class Sqed
23
23
  @boundaries = opts[:boundaries]
24
24
  @image = opts[:image]
25
25
 
26
- raise Error, 'boundaries not provided or provided boundary is not a Sqed::Boundaries' if boundaries.nil? || !boundaries.class == Sqed::Boundaries
27
- raise Error, 'metadata_map not provided or metadata_map not a Hash' if metadata_map.nil? || !metadata_map.class == Hash
26
+ raise Error, 'boundaries not provided or provided boundary is not a Sqed::Boundaries' if boundaries.nil? || !boundaries.class.name == 'Sqed::Boundaries'
27
+ raise Error, 'metadata_map not provided or metadata_map not a Hash' if metadata_map.nil? || !metadata_map.class.name == 'Hash'
28
28
  raise Error, 'image not provided' if image.nil? || !image.class.name == 'Magick::Image'
29
29
  end
30
30
 
@@ -9,8 +9,9 @@ class Sqed::Parser
9
9
  attr_accessor :extracted_text
10
10
 
11
11
  def initialize(image)
12
+ raise Sqed::Error, 'no image passed to parser' if image.nil?
13
+ raise Sqed::Error, 'image is not a Magick::Image' if !(image.class.name == 'Magick::Image')
12
14
  @image = image
13
- raise 'no image provided to parser' if @image && !(@image.class.name == 'Magick::Image')
14
15
  end
15
16
 
16
17
  end
@@ -1,3 +1,3 @@
1
1
  class Sqed
2
- VERSION = '0.5.8'.freeze
2
+ VERSION = '0.6.0'.freeze
3
3
  end
@@ -17,33 +17,40 @@ require_relative 'sqed/boundary_finder/color_line_finder'
17
17
  module SqedConfig
18
18
 
19
19
  # Layouts refer to the arrangement of the divided stage.
20
- # Windows are enumerated from the top left, moving around the border
20
+ # Windows are enumerated from the top left, moving around the border
21
21
  # in a clockwise position. For example:
22
22
  #
23
23
  # 0 | 1
24
24
  # ----|---- :cross (any cross pattern)
25
25
  # |
26
26
  # 3 | 2
27
- #
27
+ #
28
28
  #
29
29
  # 0 | 1
30
30
  # |
31
- # --------- :horizontal_offset_cross
31
+ # --------- :horizontal_offset_cross
32
32
  # 3 | 2
33
- #
33
+ #
34
34
  #
35
35
  # 0
36
36
  # -------- :horizontal_split
37
37
  # 1
38
- #
38
+ #
39
39
  #
40
40
  # 0 | 1 | 2
41
41
  # ------------
42
42
  # | 5 | :lep_stage
43
- # 6 |---- 3
43
+ # 6 |---- 3
44
44
  # | 4 |
45
45
  #
46
46
  #
47
+ # 0 | 1 | 2
48
+ # --------------
49
+ # | 5 | :lep_stage2
50
+ # 6 |---- 3
51
+ # | 4 |
52
+ #
53
+ #
47
54
  # | 1
48
55
  # 0 |---- :right_t
49
56
  # | 2
@@ -55,21 +62,21 @@ module SqedConfig
55
62
  # 6 |--------
56
63
  # | 4
57
64
  #
58
- #
65
+ #
59
66
  # 0 | 1
60
67
  # |____
61
- # ----| :vertical_offset_cross
68
+ # ----| :vertical_offset_cross
62
69
  # 3 | 2
63
- #
64
70
  #
65
- # |
66
- # 0 | 1 :vertical_split
67
- # |
71
+ #
72
+ # |
73
+ # 0 | 1 :vertical_split
74
+ # |
68
75
  #
69
76
  # -----
70
77
  # | 0 | :internal_box
71
78
  # -----
72
- #
79
+ #
73
80
  # Hash values are used to stub out
74
81
  # the Sqed::Boundaries instance.
75
82
  LAYOUTS = {
@@ -77,6 +84,7 @@ module SqedConfig
77
84
  horizontal_offset_cross: [0, 1, 2, 3],
78
85
  horizontal_split: [0, 1],
79
86
  lep_stage: [0, 1, 2, 3, 4, 5, 6],
87
+ lep_stage2: [0, 1, 2, 3, 4, 5, 6],
80
88
  right_t: [0, 1, 2],
81
89
  seven_slot: [0, 1, 2, 3, 4, 5, 6],
82
90
  vertical_offset_cross: [0, 1, 2, 3],
@@ -93,7 +101,7 @@ module SqedConfig
93
101
  :identifier, # the section contains an identifier (e.g. barcode or unique number)
94
102
  :image_registration, # the section contains only image registration information,
95
103
  :labels, # the section contains collecting event and other non-determination labels
96
- :nothing, # section is empty
104
+ :nothing, # section is empty
97
105
  :other_labels, # the section that contains text that misc.
98
106
  :specimen, # the specimen only, no metadata should be present
99
107
  :stage, # the image contains the full stage
@@ -139,6 +147,12 @@ module SqedConfig
139
147
  metadata_map: { 0 => :curator_metadata, 1 => :collecting_event_labels, 2 => :image_registration, 3 => :identifier, 4 => :other_labels, 5 => :determination_labels, 6 => :specimen }
140
148
  },
141
149
 
150
+ lep_stage2: {
151
+ boundary_finder: Sqed::BoundaryFinder::ColorLineFinder,
152
+ layout: :lep_stage2,
153
+ metadata_map: { 0 => :curator_metadata, 1 => :collecting_event_labels, 2 => :image_registration, 3 => :identifier, 4 => :other_labels, 5 => :determination_labels, 6 => :specimen }
154
+ },
155
+
142
156
  right_t: {
143
157
  boundary_finder: Sqed::BoundaryFinder::ColorLineFinder,
144
158
  layout: :right_t,
@@ -7,7 +7,7 @@ describe SqedConfig do
7
7
  end
8
8
 
9
9
  specify 'layouts' do
10
- expect(SqedConfig.metadata[:layouts].keys).to contain_exactly(:cross, :horizontal_offset_cross, :horizontal_split, :lep_stage, :right_t, :seven_slot, :vertical_offset_cross, :vertical_split)
10
+ expect(SqedConfig.metadata[:layouts].keys).to contain_exactly(: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
@@ -2,7 +2,10 @@ require 'spec_helper'
2
2
 
3
3
  describe Sqed do
4
4
 
5
- let(:s) { Sqed.new }
5
+ let(:s) { Sqed.new(
6
+ pattern: :cross
7
+ )
8
+ }
6
9
 
7
10
  context 'attributes' do
8
11
 
@@ -41,19 +44,14 @@ describe Sqed do
41
44
  specify '#use_thumbnail defaults to `true`' do
42
45
  expect(s.use_thumbnail).to eq(true)
43
46
  end
44
-
45
47
  end
46
48
 
47
- context 'initialization' do
48
- specify 'without providing a pattern assigns nil' do
49
- expect(s.pattern).to eq(nil)
50
- end
49
+ specify 'raises without pattern or boundary_finder provided' do
50
+ expect{Sqed.new}.to raise_error Sqed::Error
51
51
  end
52
52
 
53
- context '#result' do
54
- specify 'without providing an image returns false' do
55
- expect(s.result).to eq(false)
56
- end
53
+ specify '#result without image returns false' do
54
+ expect(s.result).to eq(false)
57
55
  end
58
56
 
59
57
  # Intent is to just test wrapping functionality, see
@@ -30,7 +30,9 @@ describe 'handling 7 slot stages' do
30
30
  end
31
31
 
32
32
  context 'simple boundaries - without thumbnail' do
33
- let(:s) { Sqed.new(image: image, metadata_map: m, use_thumbnail: false, layout: :horizontal_offset_cross, boundary_color: :red, has_border: false ) }
33
+ let(:s) { Sqed.new(image: image, metadata_map: m, use_thumbnail: false, layout: :horizontal_offset_cross,
34
+ boundary_finder: Sqed::BoundaryFinder::ColorLineFinder,
35
+ boundary_color: :red, has_border: false ) }
34
36
 
35
37
  specify 'boundaries are reasonable' do
36
38
  s.result
@@ -0,0 +1,64 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'handling lep stage images' do
4
+
5
+ let(:image) { ImageHelpers.lep_stage2 }
6
+ let(:sqed) do
7
+ Sqed.new(
8
+ image: image,
9
+ pattern: :lep_stage,
10
+ boundary_color: :red,
11
+ has_border: false )
12
+ end
13
+
14
+ let(:m) do
15
+ { 0 => :curator_metadata,
16
+ 1 => :collecting_event_labels,
17
+ 2 => :image_registration,
18
+ 3 => :identifier,
19
+ 4 => :other_labels,
20
+ 5 => :determination_labels,
21
+ 6 => :specimen
22
+ }
23
+ end
24
+
25
+ context 'parses' do
26
+ specify 'new() without errors' do
27
+ expect(sqed).to be_truthy
28
+ end
29
+
30
+ specify 'get result without errors' do
31
+ expect(sqed.result).to be_truthy
32
+ end
33
+ end
34
+
35
+ context 'trickier boundaries - without thumbnail' do
36
+ let(:s) { Sqed.new(image: ImageHelpers.lep_stage2, use_thumbnail: false, pattern: :lep_stage2, boundary_color: :red, has_border: false ) }
37
+
38
+ specify 'boundaries are reasonable' do
39
+ s.result
40
+ c = s.boundaries.coordinates
41
+ c.each do |section, values|
42
+ c[section].each_with_index do |v, i|
43
+ msg = "section #{section}, index #{i} has a bad value '#{v}'"
44
+ expect(v > -1).to be_truthy, msg
45
+ end
46
+ end
47
+ end
48
+ end
49
+
50
+ context 'trickier boundaries - with_thumbnail' do
51
+ let(:s) { Sqed.new(image: ImageHelpers.lep_stage2, use_thumbnail: true, pattern: :lep_stage2, boundary_color: :red, has_border: false ) }
52
+
53
+ specify 'boundaries are reasonable' do
54
+ s.result
55
+ c = s.boundaries.coordinates
56
+ c.each do |section, values|
57
+ c[section].each_with_index do |v, i|
58
+ msg = "section #{section}, index #{i} has a bad value '#{v}'"
59
+ expect(v > -1).to be_truthy, msg
60
+ end
61
+ end
62
+ end
63
+ end
64
+ end
@@ -12,15 +12,65 @@ describe 'handling 7 slot stages' do
12
12
  end
13
13
 
14
14
  let(:m) do
15
- { 0 => 'collecting_event_labels',
16
- 1 => 'determination_labels',
17
- 2 => 'other_labels',
18
- 3 => 'image_registration',
19
- 4 => 'curator_metadata',
20
- 5 => 'identifier',
21
- 6 => 'specimen' }
15
+ { 0 => :collecting_event_labels,
16
+ 1 => :determination_labels,
17
+ 2 => :other_labels,
18
+ 3 => :image_registration,
19
+ 4 => :curator_metadata,
20
+ 5 => :identifier,
21
+ 6 => :specimen }
22
22
  end
23
23
 
24
+
25
+ let(:w) {22.5} # 1/2 width red "tape"
26
+
27
+ let(:coords) {
28
+ {
29
+ 0 => [
30
+ 0,
31
+ 0,
32
+ 1674,
33
+ 1280
34
+ ],
35
+ 1 => [
36
+ 1820,
37
+ 0,
38
+ 1773,
39
+ 1280
40
+ ],
41
+ 2 => [
42
+ 3746,
43
+ 0,
44
+ 1726,
45
+ 1280
46
+ ],
47
+ 3 => [
48
+ 3746,
49
+ 1422,
50
+ 3746,
51
+ 836
52
+ ],
53
+ 4 => [
54
+ 1820,
55
+ 2382,
56
+ 3652,
57
+ 2226
58
+ ],
59
+ 5 => [
60
+ 1820,
61
+ 1422,
62
+ 1773,
63
+ 836
64
+ ],
65
+ 6 => [
66
+ 0,
67
+ 1422,
68
+ 1674,
69
+ 2226
70
+ ]
71
+ }
72
+ }
73
+
24
74
  context 'parses' do
25
75
  specify 'new() without errors' do
26
76
  expect(sqed).to be_truthy
@@ -32,33 +82,58 @@ describe 'handling 7 slot stages' do
32
82
  end
33
83
 
34
84
  context 'trickier boundaries - without thumbnail' do
35
- let(:s) { Sqed.new(image: ImageHelpers.inhs_stage_7_slot2, metadata_map: m, use_thumbnail: false, layout: :seven_slot, boundary_color: :red, has_border: false ) }
85
+ # perfect parsing currently
86
+ let(:s) { Sqed.new(
87
+ image: ImageHelpers.inhs_stage_7_slot2,
88
+ layout: :seven_slot, # layout + metadata map + boundary_finder signature
89
+ metadata_map: m,
90
+ boundary_finder: Sqed::BoundaryFinder::ColorLineFinder,
91
+ use_thumbnail: false,
92
+ boundary_color: :red,
93
+ has_border: false ) }
36
94
 
37
95
  specify 'boundaries are reasonable' do
38
96
  s.result
39
97
  c = s.boundaries.coordinates
98
+
40
99
  c.each do |section, values|
41
100
  c[section].each_with_index do |v, i|
42
- msg = "section #{section}, index #{i} has a bad value '#{v}'"
43
- expect(v > -1).to be_truthy, msg
101
+ min = coords[section][i] - w
102
+ max = coords[section][i] + w
103
+ msg = "section #{section}, index #{i}, '#{v}' is out of range #{min}-#{max} "
104
+ expect((v > min) && (v < max)).to be_truthy, msg
44
105
  end
45
106
  end
46
107
  end
47
108
  end
48
109
 
110
+ # image size is a failure here
49
111
  context 'trickier boundaries - with_thumbnail' do
50
- let(:s) { Sqed.new(image: ImageHelpers.inhs_stage_7_slot2, use_thumbnail: true, pattern: :seven_slot, boundary_color: :red, has_border: false ) }
112
+ let(:s) { Sqed.new(
113
+ image: ImageHelpers.inhs_stage_7_slot2,
114
+ use_thumbnail: true,
115
+ pattern: :seven_slot, # pattern signature
116
+ boundary_color: :red, has_border: false ) }
51
117
 
52
-
53
- specify 'boundaries are reasonable' do
118
+ xspecify 'boundaries are reasonable' do
54
119
  s.result
55
120
  c = s.boundaries.coordinates
121
+ errors = []
122
+
56
123
  c.each do |section, values|
57
124
  c[section].each_with_index do |v, i|
58
- msg = "section #{section}, index #{i} has a bad value '#{v}'"
59
- expect(v > -1).to be_truthy, msg
125
+ min = coords[section][i] - w
126
+ max = coords[section][i] + w
127
+
128
+ msg = "section #{section}, index #{i}, '#{v}' is #{(v - coords[section][i]).abs } out of range #{min}-#{max}"
129
+ if !((v > min) && (v < max))
130
+ errors.push msg
131
+ else
132
+ errors.push "section #{section} (#{v}) is OK"
133
+ end
60
134
  end
61
135
  end
136
+ expect(errors).to be_empty, errors.join("\n")
62
137
  end
63
138
  end
64
139
 
@@ -68,6 +143,6 @@ describe 'handling 7 slot stages' do
68
143
  specify '#result' do
69
144
  expect(s.result).to be_truthy
70
145
  end
71
- end
146
+ end
72
147
 
73
148
  end
@@ -5,7 +5,7 @@ Bundler.setup
5
5
  require 'sqed'
6
6
  require 'support/image_helpers'
7
7
  require 'byebug'
8
- require 'awesome_print'
8
+ require 'amazing_print'
9
9
  require 'fileutils'
10
10
  require 'rmagick'
11
11
 
@@ -36,15 +36,19 @@ module ImageHelpers
36
36
  end
37
37
 
38
38
  def inhs_stage_7_slot
39
- get_image 'stage_images/inhs_7_slot.jpg'
39
+ get_image 'stage_images/inhs_7_slot3.jpg'
40
+ end
41
+
42
+ def inhs_stage_7_slot2
43
+ get_image 'stage_images/inhs_7_slot2.jpg'
40
44
  end
41
45
 
42
46
  def lep_stage
43
47
  get_image 'stage_images/lep_stage.jpg'
44
48
  end
45
49
 
46
- def inhs_stage_7_slot2
47
- get_image 'stage_images/inhs_7_slot2.jpg'
50
+ def lep_stage2
51
+ get_image 'stage_images/lep_stage2.jpg'
48
52
  end
49
53
 
50
54
  def crossy_green_line_specimen
@@ -19,8 +19,8 @@ Gem::Specification.new do |spec|
19
19
  spec.require_paths = ["lib"]
20
20
 
21
21
  spec.add_dependency 'rake', '~> 13.0'
22
- spec.add_dependency 'rmagick', '~> 4.0'
23
- spec.add_dependency 'rtesseract', '~> 3.0.4'
22
+ spec.add_dependency 'rmagick', '~> 4.1'
23
+ spec.add_dependency 'rtesseract', '~> 3.1'
24
24
 
25
25
  # A qrcode reader, too many problems with compiling, dependencies
26
26
  # spec.add_dependency 'zxing_cpp', '~> 0.1.0'
@@ -28,6 +28,6 @@ Gem::Specification.new do |spec|
28
28
  spec.add_development_dependency 'rspec', '~> 3.9'
29
29
  spec.add_development_dependency 'bundler', '~> 2.0'
30
30
  spec.add_development_dependency 'byebug', '~> 11.0'
31
- spec.add_development_dependency 'awesome_print', '~> 1.8'
31
+ spec.add_development_dependency 'amazing_print', '~> 1.2.1'
32
32
  end
33
33
 
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.5.8
4
+ version: 0.6.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: 2019-11-18 00:00:00.000000000 Z
12
+ date: 2020-08-05 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rake
@@ -31,28 +31,28 @@ dependencies:
31
31
  requirements:
32
32
  - - "~>"
33
33
  - !ruby/object:Gem::Version
34
- version: '4.0'
34
+ version: '4.1'
35
35
  type: :runtime
36
36
  prerelease: false
37
37
  version_requirements: !ruby/object:Gem::Requirement
38
38
  requirements:
39
39
  - - "~>"
40
40
  - !ruby/object:Gem::Version
41
- version: '4.0'
41
+ version: '4.1'
42
42
  - !ruby/object:Gem::Dependency
43
43
  name: rtesseract
44
44
  requirement: !ruby/object:Gem::Requirement
45
45
  requirements:
46
46
  - - "~>"
47
47
  - !ruby/object:Gem::Version
48
- version: 3.0.4
48
+ version: '3.1'
49
49
  type: :runtime
50
50
  prerelease: false
51
51
  version_requirements: !ruby/object:Gem::Requirement
52
52
  requirements:
53
53
  - - "~>"
54
54
  - !ruby/object:Gem::Version
55
- version: 3.0.4
55
+ version: '3.1'
56
56
  - !ruby/object:Gem::Dependency
57
57
  name: rspec
58
58
  requirement: !ruby/object:Gem::Requirement
@@ -96,19 +96,19 @@ dependencies:
96
96
  - !ruby/object:Gem::Version
97
97
  version: '11.0'
98
98
  - !ruby/object:Gem::Dependency
99
- name: awesome_print
99
+ name: amazing_print
100
100
  requirement: !ruby/object:Gem::Requirement
101
101
  requirements:
102
102
  - - "~>"
103
103
  - !ruby/object:Gem::Version
104
- version: '1.8'
104
+ version: 1.2.1
105
105
  type: :development
106
106
  prerelease: false
107
107
  version_requirements: !ruby/object:Gem::Requirement
108
108
  requirements:
109
109
  - - "~>"
110
110
  - !ruby/object:Gem::Version
111
- version: '1.8'
111
+ version: 1.2.1
112
112
  description: A utility gem to aid in the processing of images taken in the process
113
113
  of digitizing natural history collections.
114
114
  email:
@@ -132,6 +132,7 @@ files:
132
132
  - lib/sqed/boundary_finder/color_line_finder.rb
133
133
  - lib/sqed/boundary_finder/cross_finder.rb
134
134
  - lib/sqed/boundary_finder/stage_finder.rb
135
+ - lib/sqed/error.rb
135
136
  - lib/sqed/extractor.rb
136
137
  - lib/sqed/parser.rb
137
138
  - lib/sqed/parser/barcode_parser.rb
@@ -154,6 +155,7 @@ files:
154
155
  - spec/lib/sqed_spec.rb
155
156
  - spec/lib/sqed_utils_spec.rb
156
157
  - spec/lib/stage_handling/horizontal_offset_cross_spec.rb
158
+ - spec/lib/stage_handling/lep_stage2_spec.rb
157
159
  - spec/lib/stage_handling/lep_stage_spec.rb
158
160
  - spec/lib/stage_handling/seven_slot_spec.rb
159
161
  - spec/spec_helper.rb
@@ -181,8 +183,10 @@ files:
181
183
  - spec/support/files/stage_images/horizontal_offset_cross.png
182
184
  - spec/support/files/stage_images/inhs_7_slot.jpg
183
185
  - spec/support/files/stage_images/inhs_7_slot2.jpg
186
+ - spec/support/files/stage_images/inhs_7_slot3.jpg
184
187
  - spec/support/files/stage_images/inhs_four_thirds.jpg
185
188
  - spec/support/files/stage_images/lep_stage.jpg
189
+ - spec/support/files/stage_images/lep_stage2.jpg
186
190
  - spec/support/files/test0.jpg
187
191
  - spec/support/files/test1.jpg
188
192
  - spec/support/files/test2.jpg
@@ -210,7 +214,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
210
214
  - !ruby/object:Gem::Version
211
215
  version: '0'
212
216
  requirements: []
213
- rubygems_version: 3.0.6
217
+ rubygems_version: 3.1.2
214
218
  signing_key:
215
219
  specification_version: 4
216
220
  summary: Specimens Quickly extracted and Digitized, or just "squid". A ruby gem for
@@ -230,6 +234,7 @@ test_files:
230
234
  - spec/lib/sqed_spec.rb
231
235
  - spec/lib/sqed_utils_spec.rb
232
236
  - spec/lib/stage_handling/horizontal_offset_cross_spec.rb
237
+ - spec/lib/stage_handling/lep_stage2_spec.rb
233
238
  - spec/lib/stage_handling/lep_stage_spec.rb
234
239
  - spec/lib/stage_handling/seven_slot_spec.rb
235
240
  - spec/spec_helper.rb
@@ -257,8 +262,10 @@ test_files:
257
262
  - spec/support/files/stage_images/horizontal_offset_cross.png
258
263
  - spec/support/files/stage_images/inhs_7_slot.jpg
259
264
  - spec/support/files/stage_images/inhs_7_slot2.jpg
265
+ - spec/support/files/stage_images/inhs_7_slot3.jpg
260
266
  - spec/support/files/stage_images/inhs_four_thirds.jpg
261
267
  - spec/support/files/stage_images/lep_stage.jpg
268
+ - spec/support/files/stage_images/lep_stage2.jpg
262
269
  - spec/support/files/test0.jpg
263
270
  - spec/support/files/test1.jpg
264
271
  - spec/support/files/test2.jpg