sqed 0.7.1 → 0.8.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/sqed/boundaries.rb +80 -80
- data/lib/sqed/boundary_finder/color_line_finder.rb +11 -1
- data/lib/sqed/boundary_finder/stage_finder.rb +3 -3
- data/lib/sqed/extractor.rb +8 -3
- data/lib/sqed/version.rb +1 -1
- data/lib/sqed.rb +104 -69
- data/lib/sqed_config.rb +29 -13
- data/spec/lib/sqed_config_spec.rb +2 -2
- data/spec/lib/sqed_spec.rb +1 -4
- data/spec/lib/stage_handling/left_t_stage_spec.rb +61 -0
- data/spec/lib/stage_handling/stage_spec.rb +55 -0
- data/spec/support/files/stage_images/left_t_stage.png +0 -0
- data/spec/support/files/stage_images/stage.png +0 -0
- data/spec/support/image_helpers.rb +8 -0
- metadata +11 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ecff3bc24d06653a25e90dd950faea277de23da61cdc7503e288d6098d8c4250
|
4
|
+
data.tar.gz: dd87d00a794d8edf2387c6d37d01382480ab0c161963f063764fadeee75a7f40
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 52aab726722c000e95af2e3e0de8e2ac584191972d74f6efa7e8127ee70404ebca0eb80493b2686f596e82a836a7302bcbc9f98b8d42759491d74313bd0f98f4
|
7
|
+
data.tar.gz: 2594a64f5b2f575515690314176aa00db01a69dfaef925aa5a1449c7e88b67373f20060f9f4fc172b5b07198c15636d3815a95d7d518e5380d45eda82924cefe
|
data/lib/sqed/boundaries.rb
CHANGED
@@ -6,108 +6,108 @@ class Sqed
|
|
6
6
|
# Layouts are Hashes defined in EXTRACTION_PATTERNS[<pattern>][<layout>]
|
7
7
|
#
|
8
8
|
class Boundaries
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
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
|
-
|
36
|
-
|
37
|
-
|
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
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
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
|
-
|
58
|
-
|
59
|
-
|
57
|
+
def for(section)
|
58
|
+
@coordinates[section]
|
59
|
+
end
|
60
60
|
|
61
|
-
|
62
|
-
|
63
|
-
|
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
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
67
|
+
# Overrides Enumerable
|
68
|
+
def count
|
69
|
+
@coordinates.length
|
70
|
+
end
|
71
71
|
|
72
|
-
|
73
|
-
|
74
|
-
|
72
|
+
def x_for(index)
|
73
|
+
@coordinates[index][0]
|
74
|
+
end
|
75
75
|
|
76
|
-
|
77
|
-
|
78
|
-
|
76
|
+
def y_for(index)
|
77
|
+
@coordinates[index][1]
|
78
|
+
end
|
79
79
|
|
80
|
-
|
81
|
-
|
82
|
-
|
80
|
+
def width_for(index)
|
81
|
+
@coordinates[index][2]
|
82
|
+
end
|
83
83
|
|
84
|
-
|
85
|
-
|
86
|
-
|
84
|
+
def height_for(index)
|
85
|
+
@coordinates[index][3]
|
86
|
+
end
|
87
87
|
|
88
|
-
|
89
|
-
|
90
|
-
|
88
|
+
def set(index, coordinates)
|
89
|
+
@coordinates[index] = coordinates
|
90
|
+
end
|
91
91
|
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
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
|
-
|
102
|
-
|
103
|
-
|
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 #
|
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?
|
data/lib/sqed/extractor.rb
CHANGED
@@ -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
|
-
|
27
|
-
raise Sqed::Error, '
|
28
|
-
raise Sqed::Error, '
|
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
data/lib/sqed.rb
CHANGED
@@ -23,9 +23,33 @@ class Sqed
|
|
23
23
|
require_relative 'sqed/result'
|
24
24
|
|
25
25
|
|
26
|
-
#
|
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
|
-
#
|
43
|
-
# !!
|
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
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
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 [
|
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
|
-
|
108
|
+
compute_stage_boundary if !@stage_boundary.populated?
|
113
109
|
@stage_boundary
|
114
110
|
end
|
115
111
|
|
116
112
|
def stage_image
|
117
|
-
|
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
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
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
|
165
|
+
return false unless extractable?
|
144
166
|
|
145
167
|
extractor = Sqed::Extractor.new(
|
146
168
|
boundaries: boundaries,
|
147
|
-
metadata_map: 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
|
-
|
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
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
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
|
269
|
+
def compute_stage_boundary
|
235
270
|
if has_border
|
236
271
|
boundary = Sqed::BoundaryFinder::StageFinder.new(image: image).boundaries
|
237
|
-
if boundary
|
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
|
-
# |
|
78
|
-
#
|
79
|
+
# 2 | 1
|
80
|
+
#
|
79
81
|
#
|
80
82
|
# 0 | 1 :inverted_t
|
81
83
|
# -----
|
82
84
|
# 2
|
83
85
|
#
|
84
|
-
#
|
85
|
-
#
|
86
|
-
#
|
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
|
14
|
+
expect(SqedConfig.metadata[:layouts].keys).to contain_exactly(*SqedConfig::EXTRACTION_PATTERNS.keys)
|
15
15
|
end
|
16
16
|
|
17
17
|
end
|
data/spec/lib/sqed_spec.rb
CHANGED
@@ -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
|
Binary file
|
Binary file
|
@@ -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.
|
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:
|
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.
|
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
|