sqed 0.5.8 → 0.6.0

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: 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