ruby_marks 0.4.4 → 1.0.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 +15 -0
- data/README.md +3 -1
- data/lib/ruby_marks/flood_scan.rb +5 -27
- data/lib/ruby_marks/group.rb +0 -0
- data/lib/ruby_marks/recognizer.rb +90 -82
- data/lib/ruby_marks/version.rb +2 -2
- data/test/ruby_marks/recognizer_grid_test.rb +2 -2
- metadata +5 -11
- data/test/ruby_marks/new_grid_test.rb +0 -63
checksums.yaml
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
---
|
2
|
+
!binary "U0hBMQ==":
|
3
|
+
metadata.gz: !binary |-
|
4
|
+
NzVhNmU3N2IwMmQ5ZmIzMGUwNTJjNTY3ODU0NzBlMzYwMjU4NjZkNg==
|
5
|
+
data.tar.gz: !binary |-
|
6
|
+
N2NmNGI1OGYwZmFkZWY3OWI2ZmFiMzkwNjkzN2IwNDQ5NjliYzJkYw==
|
7
|
+
SHA512:
|
8
|
+
metadata.gz: !binary |-
|
9
|
+
MjMwYzAxMjkwYjg2NDIxZTU5NDE5YzMzMmM0ZTJkOGVjZDIzOGZlYWY1OWYy
|
10
|
+
N2U2OWZlYzNlZDM4ZGU1YmJjYjEzODA1NGM4OTliZjEwMzJjMzIxNDUzMDY2
|
11
|
+
YjY4NDVlYmE1NDQ3ZGE1NzNiZDI0YTEzMDhlZDM1NDhlNjRhNjk=
|
12
|
+
data.tar.gz: !binary |-
|
13
|
+
ZWIxYmRiNzYyMDcxOGM5YWFmZGYzZTFiMDk3Nzk3YzY0MTMwMzExODAxYjQx
|
14
|
+
YzNhN2E3ZGFjODE0MDVhZWFmMWVjZWU5YWQxY2NlMzhmMDQzMGY0MWMwMjVj
|
15
|
+
YjA2ODJlOTU1MjA3NjM3YjI5ZmExYTBlMjg1ZTQ1MThmYzVlNzk=
|
data/README.md
CHANGED
@@ -2,6 +2,8 @@ Ruby Marks
|
|
2
2
|
==========
|
3
3
|
|
4
4
|
[](http://travis-ci.org/andrerpbts/ruby_marks)
|
5
|
+
[](https://codeclimate.com/github/andrerpbts/ruby_marks)
|
6
|
+
[](https://codeclimate.com/github/andrerpbts/ruby_marks)
|
5
7
|
|
6
8
|
A simple OMR ([Optical Mark Recognition](http://en.wikipedia.org/wiki/Optical_mark_recognition)) gem for ruby 1.9.x.
|
7
9
|
|
@@ -489,4 +491,4 @@ Thank you!
|
|
489
491
|
License
|
490
492
|
-------
|
491
493
|
|
492
|
-
Copyright © 2012 André Rodrigues, Ronaldo Araújo, Rodrigo Virgilio, Lucas Correa. See MIT-LICENSE for further details.
|
494
|
+
Copyright © 2012 André Rodrigues, Ronaldo Araújo, Rodrigo Virgilio, Lucas Correa. See MIT-LICENSE for further details.
|
@@ -2,32 +2,11 @@ module RubyMarks
|
|
2
2
|
|
3
3
|
class FloodScan
|
4
4
|
|
5
|
-
def scan_mark(image, width, height)
|
6
|
-
target = Magick::Pixel.new(0, 0, 0, 0)
|
7
|
-
vx = Hash.new { |hash, key| hash[key] = [] }
|
8
|
-
vy = Hash.new { |hash, key| hash[key] = [] }
|
9
|
-
(1..image.rows).each do |y|
|
10
|
-
(1..image.columns).each do |x|
|
11
|
-
if image.get_pixels(x-1, y-1, 1, 1)[0] == target
|
12
|
-
vx[y] << x
|
13
|
-
vy[x] << y
|
14
|
-
end
|
15
|
-
end
|
16
|
-
end
|
17
|
-
vx = vx.find_mesure(width, 5).max_frequency
|
18
|
-
vy = vy.find_mesure(height, 5).max_frequency
|
19
|
-
if vx && vy
|
20
|
-
{x1: vx[0][0], y1: vy[0][0], x2: vx[0][1], y2: vy[0][1]}
|
21
|
-
else
|
22
|
-
{}
|
23
|
-
end
|
24
|
-
end
|
25
|
-
|
26
5
|
def scan(image, node, width, height)
|
27
|
-
target = Magick::Pixel.new(65535, 65535, 65535, 0)
|
6
|
+
target = Magick::Pixel.new(65535, 65535, 65535, 0)
|
28
7
|
replacement = Magick::Pixel.new(0, 0, 0, 0)
|
29
8
|
queue = Array.new
|
30
|
-
queue.push(node)
|
9
|
+
queue.push(node)
|
31
10
|
vx = Hash.new { |hash, key| hash[key] = [] }
|
32
11
|
vy = Hash.new { |hash, key| hash[key] = [] }
|
33
12
|
steps = 0
|
@@ -38,11 +17,10 @@ module RubyMarks
|
|
38
17
|
span_up = false;
|
39
18
|
span_down = false;
|
40
19
|
while x > 0 && image.get_pixels(x - 1, y, 1, 1)[0] == target
|
41
|
-
p
|
42
20
|
x -= 1
|
43
21
|
end
|
44
22
|
while x < image.columns && image.get_pixels(x, y, 1, 1)[0] == target
|
45
|
-
image.store_pixels(x, y, 1, 1, [replacement])
|
23
|
+
image.store_pixels(x, y, 1, 1, [replacement])
|
46
24
|
if !span_up && y > 0 && image.get_pixels(x, y - 1, 1, 1)[0] == target
|
47
25
|
queue.push(Magick::Point.new(x, y - 1))
|
48
26
|
span_up = true
|
@@ -55,12 +33,12 @@ module RubyMarks
|
|
55
33
|
elsif span_down && y < image.rows - 1 && image.get_pixels(x, y + 1, 1, 1)[0] != target
|
56
34
|
span_down = false
|
57
35
|
end
|
58
|
-
vx[y] << x
|
36
|
+
vx[y] << x
|
59
37
|
vy[x] << y
|
60
38
|
x += 1
|
61
39
|
steps += 1
|
62
40
|
end
|
63
|
-
queue.push(Magick::Point.new(x, y - 1)) if queue.empty? && steps < 100
|
41
|
+
queue.push(Magick::Point.new(x, y - 1)) if queue.empty? && steps < 100
|
64
42
|
end
|
65
43
|
vx = vx.find_mesure(width, 5).max_frequency
|
66
44
|
vy = vy.find_mesure(height, 5).max_frequency
|
data/lib/ruby_marks/group.rb
CHANGED
File without changes
|
@@ -1,8 +1,8 @@
|
|
1
1
|
#encoding: utf-8
|
2
2
|
module RubyMarks
|
3
|
-
|
3
|
+
|
4
4
|
class Recognizer
|
5
|
-
|
5
|
+
|
6
6
|
attr_reader :file, :raised_watchers, :groups, :watchers, :file_str, :original_file_str
|
7
7
|
attr_accessor :config, :groups_detected, :groups_not_detected
|
8
8
|
|
@@ -23,8 +23,8 @@ module RubyMarks
|
|
23
23
|
@original_file_str = nil
|
24
24
|
|
25
25
|
@file = Magick::Image.read(file).first
|
26
|
-
@file = @file.quantize(256, Magick::GRAYColorspace)
|
27
|
-
@file = @file.threshold(@config.calculated_threshold_level)
|
26
|
+
@file = @file.quantize(256, Magick::GRAYColorspace)
|
27
|
+
@file = @file.threshold(@config.calculated_threshold_level)
|
28
28
|
@original_file = @file
|
29
29
|
@file = @file.edge(@config.edge_level)
|
30
30
|
@groups_detected = false
|
@@ -32,15 +32,15 @@ module RubyMarks
|
|
32
32
|
@groups.each_pair do |label, group|
|
33
33
|
group.marks = nil
|
34
34
|
group.marks = Hash.new { |hash, key| hash[key] = [] }
|
35
|
-
end
|
35
|
+
end
|
36
36
|
end
|
37
|
-
|
37
|
+
|
38
38
|
|
39
39
|
def reset_document
|
40
40
|
@current_position = {x: 0, y: 0}
|
41
41
|
@clock_marks = []
|
42
42
|
@raised_watchers = {}
|
43
|
-
@watchers = {}
|
43
|
+
@watchers = {}
|
44
44
|
end
|
45
45
|
|
46
46
|
|
@@ -56,7 +56,7 @@ module RubyMarks
|
|
56
56
|
|
57
57
|
def configure(&block)
|
58
58
|
self.create_config
|
59
|
-
@config.configure(&block)
|
59
|
+
@config.configure(&block)
|
60
60
|
end
|
61
61
|
|
62
62
|
|
@@ -75,7 +75,7 @@ module RubyMarks
|
|
75
75
|
watcher = @watchers[name]
|
76
76
|
if watcher
|
77
77
|
@raised_watchers[watcher.name] ||= 0
|
78
|
-
@raised_watchers[watcher.name] += 1
|
78
|
+
@raised_watchers[watcher.name] += 1
|
79
79
|
watcher.run(*args)
|
80
80
|
end
|
81
81
|
end
|
@@ -83,39 +83,39 @@ module RubyMarks
|
|
83
83
|
|
84
84
|
def scan
|
85
85
|
raise IOError, "There's a invalid or missing file" if @file.nil?
|
86
|
-
|
86
|
+
|
87
87
|
unmarked_group_found = false
|
88
88
|
multiple_marked_found = false
|
89
89
|
|
90
90
|
result = Hash.new { |hash, key| hash[key] = [] }
|
91
91
|
result.tap do |result|
|
92
|
-
|
93
|
-
begin
|
92
|
+
|
93
|
+
begin
|
94
94
|
Timeout.timeout(@config.scan_timeout) do
|
95
|
-
self.detect_groups unless @groups_detected
|
96
|
-
end
|
95
|
+
self.detect_groups unless @groups_detected
|
96
|
+
end
|
97
97
|
rescue Timeout::Error
|
98
98
|
raise_watcher :timed_out_watcher
|
99
99
|
return result
|
100
|
-
end
|
100
|
+
end
|
101
101
|
|
102
|
-
@groups.each_pair do |label, group|
|
102
|
+
@groups.each_pair do |label, group|
|
103
103
|
marks = Hash.new { |hash, key| hash[key] = [] }
|
104
104
|
group.marks.each_pair do |line, value|
|
105
105
|
value.each do |mark|
|
106
106
|
marks[line] << mark.value if mark.marked? && mark.value
|
107
107
|
end
|
108
108
|
|
109
|
-
multiple_marked_found = true if marks[line].size > 1
|
109
|
+
multiple_marked_found = true if marks[line].size > 1
|
110
110
|
unmarked_group_found = true if marks[line].empty?
|
111
111
|
end
|
112
112
|
|
113
|
-
result[group.label.to_sym] = marks
|
113
|
+
result[group.label.to_sym] = marks
|
114
114
|
end
|
115
115
|
|
116
116
|
raise_watcher :scan_unmarked_watcher, result if unmarked_group_found
|
117
|
-
raise_watcher :scan_multiple_marked_watcher, result if multiple_marked_found
|
118
|
-
raise_watcher :scan_mark_watcher, result, unmarked_group_found, multiple_marked_found if unmarked_group_found || multiple_marked_found
|
117
|
+
raise_watcher :scan_multiple_marked_watcher, result if multiple_marked_found
|
118
|
+
raise_watcher :scan_mark_watcher, result, unmarked_group_found, multiple_marked_found if unmarked_group_found || multiple_marked_found
|
119
119
|
end
|
120
120
|
end
|
121
121
|
|
@@ -129,18 +129,16 @@ module RubyMarks
|
|
129
129
|
y = group_center[:y]
|
130
130
|
width = RubyMarks::ImageUtils.calc_width(group.expected_coordinates[:x1], group.expected_coordinates[:x2])
|
131
131
|
height = RubyMarks::ImageUtils.calc_height(group.expected_coordinates[:y1], group.expected_coordinates[:y2])
|
132
|
-
|
133
|
-
|
134
|
-
block = scaner.scan(@file.dup, Magick::Point.new(x += 10, y), width, height)
|
135
|
-
end
|
132
|
+
|
133
|
+
block = scaner.scan(@file.dup, Magick::Point.new(x, y), width, height)
|
136
134
|
if !block.empty?
|
137
135
|
group.coordinates = {x1: block[:x1], x2: block[:x2], y1: block[:y1], y2: block[:y2]}
|
138
136
|
marks_blocks = find_marks_grid(group)
|
139
137
|
marks_blocks.each do |mark|
|
140
138
|
mark_width = RubyMarks::ImageUtils.calc_width(mark[:x1], mark[:x2])
|
141
139
|
mark_height = RubyMarks::ImageUtils.calc_height(mark[:y1], mark[:y2])
|
142
|
-
mark_file
|
143
|
-
o_mark
|
140
|
+
mark_file = @original_file.crop(mark[:x1], mark[:y1], mark_width, mark_height)
|
141
|
+
o_mark = RubyMarks::Mark.new group: group,
|
144
142
|
coordinates: {x1: mark[:x1], y1: mark[:y1], x2: mark[:x2], y2: mark[:y2]},
|
145
143
|
image_str: RubyMarks::ImageUtils.export_file_to_str(mark_file),
|
146
144
|
line: mark[:line]
|
@@ -173,12 +171,12 @@ module RubyMarks
|
|
173
171
|
mark_width = RubyMarks::ImageUtils.calc_width(mark[:x1], mark[:x2])
|
174
172
|
mark_height = RubyMarks::ImageUtils.calc_height(mark[:y1], mark[:y2])
|
175
173
|
|
176
|
-
if mark_width >= group.mark_width_with_down_tolerance &&
|
174
|
+
if mark_width >= group.mark_width_with_down_tolerance &&
|
177
175
|
mark_height >= group.mark_height_with_down_tolerance
|
178
176
|
|
179
177
|
mark_positions = mark[:y1]-10..mark[:y1]+10
|
180
178
|
line += 1 unless mark_ant && mark_positions.include?(mark_ant[:y1])
|
181
|
-
mark[:line] = line
|
179
|
+
mark[:line] = line
|
182
180
|
mark_ant = mark
|
183
181
|
end
|
184
182
|
end
|
@@ -195,10 +193,10 @@ module RubyMarks
|
|
195
193
|
mark[:conflict] = true
|
196
194
|
mark[:conflicting_mark] = mark_ant
|
197
195
|
else
|
198
|
-
mark_ant = mark
|
196
|
+
mark_ant = mark
|
199
197
|
end
|
200
198
|
else
|
201
|
-
mark_ant = mark
|
199
|
+
mark_ant = mark
|
202
200
|
end
|
203
201
|
end
|
204
202
|
marks_blocks.delete_if { |m| m[:conflict] }
|
@@ -243,9 +241,9 @@ module RubyMarks
|
|
243
241
|
next_mark = marks[index + 1]
|
244
242
|
distance = 0
|
245
243
|
distance = next_mark[:x1] - current_mark[:x1] if next_mark
|
246
|
-
if distance > group.distance_between_marks + 10 ||
|
247
|
-
next_mark.nil? && index + 1 < group.marks_options.count
|
248
|
-
|
244
|
+
if distance > group.distance_between_marks + 10 ||
|
245
|
+
next_mark.nil? && index + 1 < group.marks_options.count
|
246
|
+
|
249
247
|
new_x1 = current_mark[:x1] + group.distance_between_marks
|
250
248
|
new_mark = {x1: new_x1,
|
251
249
|
x2: new_x1 + group.mark_width,
|
@@ -257,60 +255,62 @@ module RubyMarks
|
|
257
255
|
bubbles_adjusted << new_mark
|
258
256
|
reprocess = true
|
259
257
|
break
|
260
|
-
end
|
258
|
+
end
|
261
259
|
end
|
262
260
|
break unless reprocess
|
263
261
|
end
|
264
262
|
end
|
263
|
+
|
265
264
|
end
|
266
265
|
|
267
266
|
marks_blocks.each do |mark|
|
268
267
|
mark_width = RubyMarks::ImageUtils.calc_width(mark[:x1], mark[:x2])
|
269
268
|
mark_height = RubyMarks::ImageUtils.calc_height(mark[:y1], mark[:y2])
|
270
269
|
mark_file = @original_file.crop(mark[:x1], mark[:y1], mark_width, mark_height)
|
271
|
-
o_mark = RubyMarks::Mark.new group: group,
|
270
|
+
o_mark = RubyMarks::Mark.new group: group,
|
272
271
|
coordinates: {x1: mark[:x1], y1: mark[:y1], x2: mark[:x2], y2: mark[:y2]},
|
273
272
|
image_str: RubyMarks::ImageUtils.export_file_to_str(mark_file),
|
274
273
|
line: mark[:line]
|
275
|
-
group.marks[mark[:line]] << o_mark
|
274
|
+
group.marks[mark[:line]] << o_mark if mark[:line] <= group.expected_lines
|
276
275
|
end
|
277
276
|
|
278
277
|
incorrect_expected_lines = group.incorrect_expected_lines
|
279
278
|
|
280
279
|
group.marks.each_pair do |line, marks|
|
281
|
-
if marks.count != group.marks_options.count
|
280
|
+
if marks.count != group.marks_options.count
|
282
281
|
incorrect_bubble_line_found[group.label.to_sym] << line
|
283
282
|
end
|
284
|
-
end
|
283
|
+
end
|
285
284
|
end
|
286
|
-
end
|
285
|
+
end
|
287
286
|
@groups_detected = true
|
288
|
-
if incorrect_bubble_line_found.any? || bubbles_adjusted.any? || incorrect_expected_lines
|
289
|
-
raise_watcher :incorrect_group_watcher, incorrect_expected_lines, incorrect_bubble_line_found, bubbles_adjusted.flatten
|
287
|
+
if incorrect_bubble_line_found.any? || bubbles_adjusted.any? || incorrect_expected_lines
|
288
|
+
raise_watcher :incorrect_group_watcher, incorrect_expected_lines, incorrect_bubble_line_found, bubbles_adjusted.flatten
|
290
289
|
end
|
291
290
|
end
|
292
291
|
end
|
293
292
|
|
293
|
+
|
294
294
|
def find_block_marks(image, x, y, group)
|
295
295
|
expected_coordinates = group.expected_coordinates
|
296
296
|
found_blocks = []
|
297
297
|
expected_width = RubyMarks::ImageUtils.calc_width(expected_coordinates[:x1], expected_coordinates[:x2])
|
298
|
-
expected_height = RubyMarks::ImageUtils.calc_height(expected_coordinates[:y1], expected_coordinates[:y2])
|
298
|
+
expected_height = RubyMarks::ImageUtils.calc_height(expected_coordinates[:y1], expected_coordinates[:y2])
|
299
299
|
block = nil
|
300
300
|
while x <= expected_coordinates[:x2] && y <= expected_coordinates[:y2]
|
301
301
|
if image[y] && image[y][x] == " "
|
302
302
|
block = find_in_blocks(found_blocks, x, y)
|
303
|
-
unless block
|
303
|
+
unless block
|
304
304
|
block = find_block(image, x, y)
|
305
305
|
found_blocks << block
|
306
|
-
|
307
|
-
block[:width] = RubyMarks::ImageUtils.calc_width(block[:x1], block[:x2])
|
308
|
-
block[:height] = RubyMarks::ImageUtils.calc_height(block[:y1], block[:y2])
|
306
|
+
|
307
|
+
block[:width] = RubyMarks::ImageUtils.calc_width(block[:x1], block[:x2])
|
308
|
+
block[:height] = RubyMarks::ImageUtils.calc_height(block[:y1], block[:y2])
|
309
309
|
|
310
310
|
if @config.scan_mode == :grid
|
311
311
|
unless block[:width] <= (expected_width + group.block_width_tolerance) && block[:width] >= (expected_width - group.block_width_tolerance)
|
312
312
|
if block[:width] > expected_width + group.block_width_tolerance
|
313
|
-
ajust_width = block[:width] - expected_width
|
313
|
+
ajust_width = block[:width] - expected_width
|
314
314
|
if @config.auto_ajust_block_width == :left
|
315
315
|
block[:x2] = (block[:x2] - ajust_width) + @config.edge_level
|
316
316
|
block[:width] = expected_width + @config.edge_level
|
@@ -341,12 +341,12 @@ module RubyMarks
|
|
341
341
|
block_width_with_tolerance = block[:width] + group.block_width_tolerance
|
342
342
|
block_height_with_tolerance = block[:height] + group.block_height_tolerance
|
343
343
|
|
344
|
-
return block if block_width_with_tolerance >= expected_width &&
|
344
|
+
return block if block_width_with_tolerance >= expected_width &&
|
345
345
|
block_height_with_tolerance >= expected_height
|
346
346
|
end
|
347
347
|
end
|
348
348
|
|
349
|
-
x += 1
|
349
|
+
x += 1
|
350
350
|
y += 1
|
351
351
|
end
|
352
352
|
end
|
@@ -364,14 +364,14 @@ module RubyMarks
|
|
364
364
|
lines.times do |lin|
|
365
365
|
columns.times do |col|
|
366
366
|
|
367
|
-
blocks << { :x1 => block[:x1] + (col * distance_col),
|
368
|
-
:y1 => block[:y1] + (lin * distance_lin),
|
367
|
+
blocks << { :x1 => block[:x1] + (col * distance_col),
|
368
|
+
:y1 => block[:y1] + (lin * distance_lin),
|
369
369
|
:x2 => block[:x1] + (col * distance_col) + distance_col,
|
370
370
|
:y2 => block[:y1] + (lin * distance_lin) + distance_lin,
|
371
371
|
:line => lin + 1 }
|
372
372
|
end
|
373
373
|
end
|
374
|
-
end
|
374
|
+
end
|
375
375
|
end
|
376
376
|
|
377
377
|
def find_marks(image, group)
|
@@ -381,10 +381,10 @@ module RubyMarks
|
|
381
381
|
blocks.tap do |blocks|
|
382
382
|
while y < block[:y2]
|
383
383
|
x = block[:x1]
|
384
|
-
while x < block[:x2] do
|
384
|
+
while x < block[:x2] do
|
385
385
|
if image[y][x] == " "
|
386
386
|
x += 1
|
387
|
-
next
|
387
|
+
next
|
388
388
|
end
|
389
389
|
|
390
390
|
result = find_in_blocks(blocks, x, y)
|
@@ -395,7 +395,7 @@ module RubyMarks
|
|
395
395
|
mark_height = RubyMarks::ImageUtils.calc_height(result[:y1], result[:y2])
|
396
396
|
|
397
397
|
|
398
|
-
if mark_width > group.mark_width_with_up_tolerance
|
398
|
+
if mark_width > group.mark_width_with_up_tolerance
|
399
399
|
distance_x1 = x - result[:x1]
|
400
400
|
distance_x2 = result[:x2] - x
|
401
401
|
if distance_x1 <= distance_x2
|
@@ -403,16 +403,16 @@ module RubyMarks
|
|
403
403
|
else
|
404
404
|
result[:x1] = result[:x2] - group.mark_width
|
405
405
|
end
|
406
|
-
end
|
407
|
-
|
408
|
-
if mark_height > group.mark_height_with_up_tolerance
|
406
|
+
end
|
407
|
+
|
408
|
+
if mark_height > group.mark_height_with_up_tolerance
|
409
409
|
distance_y1 = y - result[:y1]
|
410
410
|
distance_y2 = result[:y2] - y
|
411
411
|
if distance_y1 <= distance_y2
|
412
412
|
result[:y2] = result[:y1] + group.mark_height
|
413
413
|
else
|
414
414
|
result[:y1] = result[:y2] - group.mark_height
|
415
|
-
end
|
415
|
+
end
|
416
416
|
end
|
417
417
|
|
418
418
|
blocks << result unless blocks.any? { |b| b == result }
|
@@ -439,49 +439,57 @@ module RubyMarks
|
|
439
439
|
|
440
440
|
def flag_all_marks
|
441
441
|
raise IOError, "There's a invalid or missing file" if @file.nil?
|
442
|
-
|
442
|
+
|
443
443
|
file = @original_file.dup
|
444
444
|
|
445
445
|
file.tap do |file|
|
446
446
|
|
447
|
-
begin
|
447
|
+
begin
|
448
448
|
Timeout.timeout(@config.scan_timeout) do
|
449
|
-
self.detect_groups unless @groups_detected
|
450
|
-
end
|
449
|
+
self.detect_groups unless @groups_detected
|
450
|
+
end
|
451
451
|
rescue Timeout::Error
|
452
452
|
raise_watcher :timed_out_watcher
|
453
453
|
return file
|
454
|
-
end
|
454
|
+
end
|
455
455
|
|
456
|
-
@groups.each_pair do |label, group|
|
456
|
+
@groups.each_pair do |label, group|
|
457
457
|
|
458
458
|
dr = Magick::Draw.new
|
459
459
|
dr.stroke_width = 5
|
460
460
|
dr.stroke(RubyMarks::COLORS[3])
|
461
461
|
dr.line(group.expected_coordinates[:x1], group.expected_coordinates[:y1], group.expected_coordinates[:x2], group.expected_coordinates[:y1])
|
462
462
|
dr.line(group.expected_coordinates[:x2], group.expected_coordinates[:y1], group.expected_coordinates[:x2], group.expected_coordinates[:y2])
|
463
|
-
dr.line(group.expected_coordinates[:x2], group.expected_coordinates[:y2], group.expected_coordinates[:x1], group.expected_coordinates[:y2])
|
464
|
-
dr.line(group.expected_coordinates[:x1], group.expected_coordinates[:y2], group.expected_coordinates[:x1], group.expected_coordinates[:y1])
|
463
|
+
dr.line(group.expected_coordinates[:x2], group.expected_coordinates[:y2], group.expected_coordinates[:x1], group.expected_coordinates[:y2])
|
464
|
+
dr.line(group.expected_coordinates[:x1], group.expected_coordinates[:y2], group.expected_coordinates[:x1], group.expected_coordinates[:y1])
|
465
465
|
dr.draw(file)
|
466
466
|
|
467
|
-
if group.coordinates
|
467
|
+
if group.coordinates
|
468
468
|
dr = Magick::Draw.new
|
469
469
|
dr.stroke_width = 5
|
470
|
-
dr.stroke(RubyMarks::COLORS[5])
|
470
|
+
dr.stroke(RubyMarks::COLORS[5])
|
471
471
|
dr.line(group.coordinates[:x1], group.coordinates[:y1], group.coordinates[:x2], group.coordinates[:y1])
|
472
472
|
dr.line(group.coordinates[:x2], group.coordinates[:y1], group.coordinates[:x2], group.coordinates[:y2])
|
473
|
-
dr.line(group.coordinates[:x2], group.coordinates[:y2], group.coordinates[:x1], group.coordinates[:y2])
|
474
|
-
dr.line(group.coordinates[:x1], group.coordinates[:y2], group.coordinates[:x1], group.coordinates[:y1])
|
473
|
+
dr.line(group.coordinates[:x2], group.coordinates[:y2], group.coordinates[:x1], group.coordinates[:y2])
|
474
|
+
dr.line(group.coordinates[:x1], group.coordinates[:y2], group.coordinates[:x1], group.coordinates[:y1])
|
475
475
|
dr.draw(file)
|
476
476
|
end
|
477
477
|
|
478
478
|
marks = Hash.new { |hash, key| hash[key] = [] }
|
479
479
|
group.marks.each_pair do |line, value|
|
480
480
|
value.each do |mark|
|
481
|
+
mark_width = RubyMarks::ImageUtils.calc_width(mark.coordinates[:x1], mark.coordinates[:x2])
|
482
|
+
mark_height = RubyMarks::ImageUtils.calc_height(mark.coordinates[:y1], mark.coordinates[:y2])
|
483
|
+
mark_file = @original_file.crop(mark.coordinates[:x1], mark.coordinates[:y1], mark_width, mark_height)
|
484
|
+
o_mark = RubyMarks::Mark.new group: group,
|
485
|
+
coordinates: {x1: mark.coordinates[:x1], y1: mark.coordinates[:y1], x2: mark.coordinates[:x2], y2: mark.coordinates[:y2]},
|
486
|
+
image_str: RubyMarks::ImageUtils.export_file_to_str(mark_file),
|
487
|
+
line: line
|
488
|
+
|
481
489
|
add_mark file, RubyMarks::ImageUtils.image_center(mark.coordinates), mark
|
482
490
|
end
|
483
491
|
end
|
484
|
-
end
|
492
|
+
end
|
485
493
|
end
|
486
494
|
end
|
487
495
|
|
@@ -511,8 +519,8 @@ module RubyMarks
|
|
511
519
|
|
512
520
|
def find_in_blocks(blocks, x, y)
|
513
521
|
blocks.find do |result|
|
514
|
-
result[:x1] <= x && result[:x2] >= x &&
|
515
|
-
result[:y1] <= y && result[:y2] >= y
|
522
|
+
result[:x1] <= x && result[:x2] >= x &&
|
523
|
+
result[:y1] <= y && result[:y2] >= y
|
516
524
|
end
|
517
525
|
end
|
518
526
|
|
@@ -526,26 +534,26 @@ module RubyMarks
|
|
526
534
|
|
527
535
|
dr = Magick::Draw.new
|
528
536
|
dr.stroke_width = 2
|
529
|
-
dr.stroke(RubyMarks::COLORS[1])
|
537
|
+
dr.stroke(RubyMarks::COLORS[1])
|
530
538
|
dr.line(mark.coordinates[:x1], mark.coordinates[:y1], mark.coordinates[:x2], mark.coordinates[:y1])
|
531
539
|
dr.line(mark.coordinates[:x2], mark.coordinates[:y1], mark.coordinates[:x2], mark.coordinates[:y2])
|
532
|
-
dr.line(mark.coordinates[:x2], mark.coordinates[:y2], mark.coordinates[:x1], mark.coordinates[:y2])
|
533
|
-
dr.line(mark.coordinates[:x1], mark.coordinates[:y2], mark.coordinates[:x1], mark.coordinates[:y1])
|
540
|
+
dr.line(mark.coordinates[:x2], mark.coordinates[:y2], mark.coordinates[:x1], mark.coordinates[:y2])
|
541
|
+
dr.line(mark.coordinates[:x1], mark.coordinates[:y2], mark.coordinates[:x1], mark.coordinates[:y1])
|
534
542
|
dr.draw(file)
|
535
543
|
else
|
536
544
|
dr.annotate(file, 0, 0, position[:x]-9, position[:y]+11, "+") do
|
537
545
|
self.pointsize = 30
|
538
546
|
self.fill = '#900000'
|
539
547
|
end
|
540
|
-
|
548
|
+
|
541
549
|
dr = Magick::Draw.new
|
542
550
|
dr.fill = '#FF0000'
|
543
551
|
dr.point(position[:x], position[:y])
|
544
|
-
dr.point(position[:x], position[:y] + 1)
|
545
|
-
dr.point(position[:x] + 1, position[:y])
|
546
|
-
dr.point(position[:x] + 1, position[:y] + 1)
|
552
|
+
dr.point(position[:x], position[:y] + 1)
|
553
|
+
dr.point(position[:x] + 1, position[:y])
|
554
|
+
dr.point(position[:x] + 1, position[:y] + 1)
|
547
555
|
dr.draw(file)
|
548
|
-
end
|
556
|
+
end
|
549
557
|
end
|
550
558
|
|
551
559
|
end
|
data/lib/ruby_marks/version.rb
CHANGED
@@ -1,3 +1,3 @@
|
|
1
1
|
module RubyMarks
|
2
|
-
VERSION = "0.
|
3
|
-
end
|
2
|
+
VERSION = "1.0.0".freeze
|
3
|
+
end
|
@@ -1,7 +1,7 @@
|
|
1
1
|
require "test_helper"
|
2
2
|
|
3
3
|
class RubyMarks::RecognizerGridTest < Test::Unit::TestCase
|
4
|
-
|
4
|
+
|
5
5
|
def setup
|
6
6
|
@file = 'assets/sheet_demo_grid.png'
|
7
7
|
@recognizer = RubyMarks::Recognizer.new
|
@@ -98,5 +98,5 @@ class RubyMarks::RecognizerGridTest < Test::Unit::TestCase
|
|
98
98
|
result.delete_if { |group, lines| lines.empty? }
|
99
99
|
assert_equal expected_hash, result
|
100
100
|
end
|
101
|
-
|
101
|
+
|
102
102
|
end
|
metadata
CHANGED
@@ -1,8 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ruby_marks
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
5
|
-
prerelease:
|
4
|
+
version: 1.0.0
|
6
5
|
platform: ruby
|
7
6
|
authors:
|
8
7
|
- André Rodrigues
|
@@ -15,7 +14,6 @@ dependencies:
|
|
15
14
|
- !ruby/object:Gem::Dependency
|
16
15
|
name: rmagick
|
17
16
|
requirement: !ruby/object:Gem::Requirement
|
18
|
-
none: false
|
19
17
|
requirements:
|
20
18
|
- - '='
|
21
19
|
- !ruby/object:Gem::Version
|
@@ -23,7 +21,6 @@ dependencies:
|
|
23
21
|
type: :runtime
|
24
22
|
prerelease: false
|
25
23
|
version_requirements: !ruby/object:Gem::Requirement
|
26
|
-
none: false
|
27
24
|
requirements:
|
28
25
|
- - '='
|
29
26
|
- !ruby/object:Gem::Version
|
@@ -37,6 +34,7 @@ extensions: []
|
|
37
34
|
extra_rdoc_files: []
|
38
35
|
files:
|
39
36
|
- README.md
|
37
|
+
- lib/ruby_marks.rb
|
40
38
|
- lib/ruby_marks/config.rb
|
41
39
|
- lib/ruby_marks/flood_scan.rb
|
42
40
|
- lib/ruby_marks/group.rb
|
@@ -46,9 +44,7 @@ files:
|
|
46
44
|
- lib/ruby_marks/support.rb
|
47
45
|
- lib/ruby_marks/version.rb
|
48
46
|
- lib/ruby_marks/watcher.rb
|
49
|
-
- lib/ruby_marks.rb
|
50
47
|
- test/ruby_marks/image_utils_test.rb
|
51
|
-
- test/ruby_marks/new_grid_test.rb
|
52
48
|
- test/ruby_marks/recognizer_grid_test.rb
|
53
49
|
- test/ruby_marks/recognizer_test.rb
|
54
50
|
- test/ruby_marks/watcher_test.rb
|
@@ -56,6 +52,7 @@ files:
|
|
56
52
|
homepage: https://github.com/andrerpbts/ruby_marks.git
|
57
53
|
licenses:
|
58
54
|
- MIT
|
55
|
+
metadata: {}
|
59
56
|
post_install_message: ! "\n *** NOTE: You are running the ImageMagick under 16bits
|
60
57
|
quantum depth. This configuration is used\n in very specific cases and
|
61
58
|
can cause RMagick work a bit slow. See more details in this forum post\n http://rubyforge.org/forum/forum.php?thread_id=10975&forum_id=1618
|
@@ -67,26 +64,23 @@ rdoc_options: []
|
|
67
64
|
require_paths:
|
68
65
|
- lib
|
69
66
|
required_ruby_version: !ruby/object:Gem::Requirement
|
70
|
-
none: false
|
71
67
|
requirements:
|
72
68
|
- - ! '>='
|
73
69
|
- !ruby/object:Gem::Version
|
74
70
|
version: '0'
|
75
71
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
76
|
-
none: false
|
77
72
|
requirements:
|
78
73
|
- - ! '>='
|
79
74
|
- !ruby/object:Gem::Version
|
80
75
|
version: '0'
|
81
76
|
requirements: []
|
82
77
|
rubyforge_project: ruby_marks
|
83
|
-
rubygems_version:
|
78
|
+
rubygems_version: 2.2.2
|
84
79
|
signing_key:
|
85
|
-
specification_version:
|
80
|
+
specification_version: 4
|
86
81
|
summary: A simple OMR tool
|
87
82
|
test_files:
|
88
83
|
- test/ruby_marks/image_utils_test.rb
|
89
|
-
- test/ruby_marks/new_grid_test.rb
|
90
84
|
- test/ruby_marks/recognizer_grid_test.rb
|
91
85
|
- test/ruby_marks/recognizer_test.rb
|
92
86
|
- test/ruby_marks/watcher_test.rb
|
@@ -1,63 +0,0 @@
|
|
1
|
-
require "test_helper"
|
2
|
-
|
3
|
-
class RubyMarks::NewTestGrid < Test::Unit::TestCase
|
4
|
-
|
5
|
-
def setup
|
6
|
-
arquivo = Magick::Image.read('assets/demo2.png').first
|
7
|
-
arquivo = arquivo.deskew 1
|
8
|
-
arquivo.write("temp.jpg")
|
9
|
-
@prova = 'temp.jpg'
|
10
|
-
@recognizer = RubyMarks::Recognizer.new
|
11
|
-
@recognizer.configure do |config|
|
12
|
-
config.scan_mode = :grid
|
13
|
-
config.edge_level = 6
|
14
|
-
config.default_expected_lines = 25
|
15
|
-
config.intensity_percentual = 40
|
16
|
-
config.default_mark_height = 34
|
17
|
-
config.default_mark_width = 34
|
18
|
-
config.default_block_width_tolerance = 10
|
19
|
-
config.scan_timeout = 30
|
20
|
-
|
21
|
-
config.define_group :um do |group|
|
22
|
-
group.expected_coordinates = {x1: 155, y1: 830, x2: 330, y2: 1685}
|
23
|
-
group.expected_lines = 25
|
24
|
-
end
|
25
|
-
|
26
|
-
config.define_group :dois do |group|
|
27
|
-
group.expected_coordinates = {x1: 460, y1: 830, x2: 635, y2: 1685}
|
28
|
-
group.expected_lines = 20
|
29
|
-
end
|
30
|
-
|
31
|
-
config.define_group :tres do |group|
|
32
|
-
group.expected_coordinates = {x1: 765, y1: 830, x2: 940, y2: 1685}
|
33
|
-
group.expected_lines = 25
|
34
|
-
end
|
35
|
-
|
36
|
-
config.define_group :quatro do |group|
|
37
|
-
group.expected_coordinates = {x1: 1070, y1: 830, x2: 1245, y2: 1685}
|
38
|
-
group.expected_lines = 25
|
39
|
-
end
|
40
|
-
|
41
|
-
config.define_group :cinco do |group|
|
42
|
-
group.expected_coordinates = {x1: 1375, y1: 830, x2: 1550, y2: 1685}
|
43
|
-
group.expected_lines = 25
|
44
|
-
end
|
45
|
-
end
|
46
|
-
@recognizer.file = @prova
|
47
|
-
file = @recognizer.flag_all_marks
|
48
|
-
file.write("demo_grid3.png")
|
49
|
-
File.delete("temp.jpg")
|
50
|
-
end
|
51
|
-
|
52
|
-
def test_should_return_correct_marks
|
53
|
-
expected_hash = {
|
54
|
-
um: { 1 => ['E'], 2 => ['E'], 3 => ['B'], 4 => ['D'], 5 => ['E'], 6 => ['E'], 7 => [], 8 => [], 9 => [], 10 => [], 11 => [], 12 => [], 13 => [], 14 => [], 15 => [], 16 => [], 17 => [], 18 => [], 19 => [], 20 => [], 21 => [], 22 => [], 23 => [], 24 => [], 25 => [] },
|
55
|
-
dois: { 1 => [], 2 => [], 3 => [], 4 => [], 5 => [], 6 => [], 7 => [], 8 => [], 9 => [], 10 => [], 11 => [], 12 => [], 13 => [], 14 => [], 15 => [], 16 => [], 17 => [], 18 => [], 19 => [], 20 => [] },
|
56
|
-
tres: { 1 => [], 2 => [], 3 => [], 4 => [], 5 => [], 6 => [], 7 => [], 8 => [], 9 => [], 10 => [], 11 => [], 12 => [], 13 => [], 14 => [], 15 => [], 16 => [], 17 => [], 18 => [], 19 => [], 20 => [], 21 => [], 22 => [], 23 => [], 24 => [], 25 => [] },
|
57
|
-
quatro: { 1 => [], 2 => [], 3 => [], 4 => [], 5 => [], 6 => [], 7 => [], 8 => [], 9 => [], 10 => [], 11 => [], 12 => [], 13 => [], 14 => [], 15 => [], 16 => [], 17 => [], 18 => [], 19 => [], 20 => [], 21 => [], 22 => [], 23 => [], 24 => [], 25 => [] },
|
58
|
-
cinco: { 1 => [], 2 => [], 3 => [], 4 => [], 5 => [], 6 => [], 7 => [], 8 => [], 9 => [], 10 => [], 11 => [], 12 => [], 13 => [], 14 => [], 15 => [], 16 => [], 17 => [], 18 => [], 19 => [], 20 => [], 21 => [], 22 => [], 23 => [], 24 => [], 25 => [] }
|
59
|
-
}
|
60
|
-
result = @recognizer.scan
|
61
|
-
assert_equal expected_hash, result
|
62
|
-
end
|
63
|
-
end
|