ruby_marks 0.1.5 → 0.2.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.
- data/README.md +168 -139
- data/lib/ruby_marks/config.rb +14 -35
- data/lib/ruby_marks/group.rb +43 -13
- data/lib/ruby_marks/image_utils.rb +109 -1
- data/lib/ruby_marks/mark.rb +42 -0
- data/lib/ruby_marks/recognizer.rb +304 -315
- data/lib/ruby_marks/scan_area.rb +11 -0
- data/lib/ruby_marks/version.rb +1 -1
- data/lib/ruby_marks.rb +28 -19
- data/test/ruby_marks/image_utils_test.rb +17 -1
- data/test/ruby_marks/recognizer_test.rb +51 -55
- metadata +10 -10
- data/lib/ruby_marks/clock_mark.rb +0 -65
- data/test/ruby_marks/clock_mark_test.rb +0 -44
- data/test/ruby_marks/group_test.rb +0 -26
data/lib/ruby_marks/version.rb
CHANGED
data/lib/ruby_marks.rb
CHANGED
@@ -5,26 +5,20 @@ require 'ruby_marks/support'
|
|
5
5
|
|
6
6
|
|
7
7
|
module RubyMarks
|
8
|
+
mattr_accessor :edge_level
|
9
|
+
@@edge_level = 4
|
10
|
+
|
8
11
|
mattr_accessor :threshold_level
|
9
12
|
@@threshold_level = 60
|
10
13
|
|
11
|
-
mattr_accessor :
|
12
|
-
@@
|
13
|
-
|
14
|
-
mattr_accessor :expected_clocks_count
|
15
|
-
@@expected_clocks_count = 0
|
16
|
-
|
17
|
-
mattr_accessor :clock_marks_scan_x
|
18
|
-
@@clock_marks_scan_x = 62
|
19
|
-
|
20
|
-
mattr_accessor :clock_width
|
21
|
-
@@clock_width = 26
|
14
|
+
mattr_accessor :adjust_inconsistent_bubbles
|
15
|
+
@@adjust_inconsistent_bubbles = true
|
22
16
|
|
23
|
-
mattr_accessor :
|
24
|
-
@@
|
17
|
+
mattr_accessor :default_mark_width_tolerance
|
18
|
+
@@default_mark_width_tolerance = 4
|
25
19
|
|
26
|
-
mattr_accessor :
|
27
|
-
@@
|
20
|
+
mattr_accessor :default_mark_height_tolerance
|
21
|
+
@@default_mark_height_tolerance = 4
|
28
22
|
|
29
23
|
mattr_accessor :default_mark_width
|
30
24
|
@@default_mark_width = 20
|
@@ -41,20 +35,35 @@ module RubyMarks
|
|
41
35
|
mattr_accessor :default_distance_between_marks
|
42
36
|
@@default_distance_between_marks = 25
|
43
37
|
|
44
|
-
|
45
|
-
|
38
|
+
mattr_accessor :default_expected_lines
|
39
|
+
@@default_expected_lines = 20
|
40
|
+
|
41
|
+
COLORS = %w{ #d80000
|
42
|
+
#00d8d8
|
43
|
+
#d8006c
|
44
|
+
#d86c00
|
45
|
+
#006cd8
|
46
|
+
#00d86c
|
47
|
+
#d8d800
|
48
|
+
#00d86c
|
49
|
+
#6c00d8
|
50
|
+
#a5a500
|
51
|
+
#a27b18
|
52
|
+
#18a236
|
53
|
+
#df4f27 }
|
46
54
|
|
47
55
|
AVAILABLE_WATCHERS = [
|
48
56
|
:scan_mark_watcher,
|
49
57
|
:scan_unmarked_watcher,
|
50
58
|
:scan_multiple_marked_watcher,
|
51
|
-
:
|
59
|
+
:incorrect_group_watcher
|
52
60
|
]
|
53
61
|
end
|
54
62
|
|
55
|
-
require 'ruby_marks/clock_mark'
|
56
63
|
require 'ruby_marks/config'
|
57
64
|
require 'ruby_marks/group'
|
58
65
|
require 'ruby_marks/image_utils'
|
66
|
+
require 'ruby_marks/mark'
|
59
67
|
require 'ruby_marks/recognizer'
|
68
|
+
require 'ruby_marks/scan_area'
|
60
69
|
require 'ruby_marks/watcher'
|
@@ -1,7 +1,23 @@
|
|
1
1
|
require "test_helper"
|
2
2
|
|
3
3
|
class RubyMarks::ImageUtilsTest < Test::Unit::TestCase
|
4
|
-
|
4
|
+
|
5
|
+
def test_should_calculate_the_correct_width_of_given_coordinates
|
6
|
+
assert_equal 11, RubyMarks::ImageUtils.calc_width(10, 20)
|
7
|
+
end
|
8
|
+
|
9
|
+
def test_should_calculate_the_correct_height_of_given_coordinates
|
10
|
+
assert_equal 11, RubyMarks::ImageUtils.calc_height(10, 20)
|
11
|
+
end
|
12
|
+
|
13
|
+
def test_should_calculate_the_correct_middle_horizontal_of_given_coordinates
|
14
|
+
assert_equal 15, RubyMarks::ImageUtils.calc_middle_horizontal(10, 11)
|
15
|
+
end
|
16
|
+
|
17
|
+
def test_should_calculate_the_correct_middle_vertical_of_given_coordinates
|
18
|
+
assert_equal 15, RubyMarks::ImageUtils.calc_middle_vertical(10, 11)
|
19
|
+
end
|
20
|
+
|
5
21
|
def test_should_return_the_white_color_in_hexa_receiving_8bits
|
6
22
|
color = RubyMarks::ImageUtils.to_hex(255, 255, 255)
|
7
23
|
assert_equal "#FFFFFF", color
|
@@ -8,38 +8,37 @@ class RubyMarks::RecognizerTest < Test::Unit::TestCase
|
|
8
8
|
@positions = {}
|
9
9
|
@positions[:marked_position] = {x: 161, y: 794}
|
10
10
|
@positions[:unmarked_position] = {x: 161, y: 994}
|
11
|
-
@positions[:first_clock_position] = {x: 62, y: 794}
|
12
|
-
@positions[:invalid_clock] = {x: 62, y: 1032}
|
13
11
|
|
14
|
-
@recognizer.configure do |config|
|
15
|
-
config.expected_clocks_count = 20
|
12
|
+
@recognizer.configure do |config|
|
16
13
|
config.define_group :first do |group|
|
17
|
-
group.
|
18
|
-
group.x_distance_from_clock = 87
|
14
|
+
group.expected_coordinates = {x1: 145, y1: 780, x2: 270, y2: 1290}
|
19
15
|
end
|
20
16
|
|
21
17
|
config.define_group :second do |group|
|
22
|
-
group.
|
23
|
-
group.x_distance_from_clock = 310
|
18
|
+
group.expected_coordinates = {x1: 370, y1: 780, x2: 500, y2: 1290}
|
24
19
|
end
|
25
20
|
|
26
21
|
config.define_group :third do |group|
|
27
|
-
group.
|
28
|
-
group.x_distance_from_clock = 535
|
22
|
+
group.expected_coordinates = {x1: 595, y1: 780, x2: 720, y2: 1290}
|
29
23
|
end
|
30
24
|
|
31
25
|
config.define_group :fourth do |group|
|
32
|
-
group.
|
33
|
-
group.x_distance_from_clock = 760
|
26
|
+
group.expected_coordinates = {x1: 820, y1: 780, x2: 950, y2: 1290}
|
34
27
|
end
|
35
28
|
|
36
29
|
config.define_group :fifth do |group|
|
37
|
-
group.
|
38
|
-
group.x_distance_from_clock = 985
|
30
|
+
group.expected_coordinates = {x1: 1045, y1: 780, x2: 1170, y2: 1290}
|
39
31
|
end
|
32
|
+
|
40
33
|
end
|
41
34
|
|
42
35
|
@recognizer.file = @file
|
36
|
+
|
37
|
+
# file = @recognizer.file
|
38
|
+
# temp_filename = "ttemp_sheet_demo1.png"
|
39
|
+
# File.delete(temp_filename) if File.exist?(temp_filename)
|
40
|
+
# file.write(temp_filename)
|
41
|
+
|
43
42
|
end
|
44
43
|
|
45
44
|
def test_should_initialize_a_recognizer_with_a_valid_file
|
@@ -48,9 +47,9 @@ class RubyMarks::RecognizerTest < Test::Unit::TestCase
|
|
48
47
|
|
49
48
|
def test_should_pass_the_configuration_to_recognizer_config
|
50
49
|
@recognizer.configure do |config|
|
51
|
-
config.
|
50
|
+
config.threshold_level = 70
|
52
51
|
end
|
53
|
-
assert_equal
|
52
|
+
assert_equal 70, @recognizer.config.threshold_level
|
54
53
|
end
|
55
54
|
|
56
55
|
def test_should_get_the_default_configuration_of_config_in_group
|
@@ -74,8 +73,7 @@ class RubyMarks::RecognizerTest < Test::Unit::TestCase
|
|
74
73
|
|
75
74
|
|
76
75
|
def test_should_return_a_file_with_a_position_flagged
|
77
|
-
@recognizer.
|
78
|
-
flagged_document = @recognizer.flag_position
|
76
|
+
flagged_document = @recognizer.flag_position @positions[:marked_position]
|
79
77
|
assert_equal Magick::Image, flagged_document.class
|
80
78
|
|
81
79
|
# temp_filename = "temp_sheet_demo1.png"
|
@@ -84,19 +82,21 @@ class RubyMarks::RecognizerTest < Test::Unit::TestCase
|
|
84
82
|
end
|
85
83
|
|
86
84
|
def test_should_recognize_marked_position
|
87
|
-
@recognizer.
|
88
|
-
|
85
|
+
@recognizer.detect_groups
|
86
|
+
group = @recognizer.groups[:first]
|
87
|
+
line = group.marks[1]
|
88
|
+
mark = line.first
|
89
|
+
assert mark.marked?, "The position wasn't recognized as marked"
|
89
90
|
end
|
90
91
|
|
91
92
|
def test_should_recognize_not_marked_position
|
92
|
-
@recognizer.
|
93
|
-
|
93
|
+
@recognizer.detect_groups
|
94
|
+
group = @recognizer.groups[:first]
|
95
|
+
line = group.marks[2]
|
96
|
+
mark = line.first
|
97
|
+
assert mark.unmarked?, "The position wasn't recognized as unmarked"
|
94
98
|
end
|
95
99
|
|
96
|
-
def test_should_recognize_the_recognizer_clock_marks
|
97
|
-
@recognizer.scan_clock_marks
|
98
|
-
assert_equal 20, @recognizer.clock_marks.count
|
99
|
-
end
|
100
100
|
|
101
101
|
def test_should_return_the_recognizer_with_all_marks_flagged
|
102
102
|
flagged_recognizer = @recognizer.flag_all_marks
|
@@ -107,47 +107,43 @@ class RubyMarks::RecognizerTest < Test::Unit::TestCase
|
|
107
107
|
flagged_recognizer.write(temp_filename)
|
108
108
|
end
|
109
109
|
|
110
|
-
def test_should_move_the_current_position_in_10_and_20_pixels
|
111
|
-
@recognizer.current_position = @positions[:marked_position]
|
112
|
-
expected_position = {x: 171, y: 814}
|
113
|
-
|
114
|
-
assert_equal expected_position, @recognizer.move_to(10, 20)
|
115
|
-
end
|
116
110
|
|
117
111
|
def test_should_scan_the_recognizer_and_get_a_hash_of_marked_marks
|
118
112
|
expected_hash = {
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
group_second: ['B'],
|
126
|
-
group_third: ['B']
|
113
|
+
first: {
|
114
|
+
1 => ['A'],
|
115
|
+
2 => ['B'],
|
116
|
+
3 => ['C'],
|
117
|
+
4 => ['D'],
|
118
|
+
5 => ['E']
|
127
119
|
},
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
120
|
+
second: {
|
121
|
+
1 => ['A'],
|
122
|
+
2 => ['B'],
|
123
|
+
3 => ['C'],
|
124
|
+
4 => ['D'],
|
125
|
+
5 => ['E']
|
132
126
|
},
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
},
|
138
|
-
clock_5: {
|
139
|
-
group_first: ['E'],
|
140
|
-
group_second: ['E']
|
127
|
+
third: {
|
128
|
+
2 => ['B'],
|
129
|
+
3 => ['D'],
|
130
|
+
4 => ['D']
|
141
131
|
}
|
142
132
|
}
|
143
133
|
assert_equal expected_hash, @recognizer.scan
|
144
134
|
end
|
145
135
|
|
146
|
-
|
147
|
-
|
136
|
+
|
137
|
+
def test_should_make_watcher_raise_up
|
138
|
+
@file = 'assets/sheet_demo1_invalid.png'
|
139
|
+
@recognizer.file = @file
|
140
|
+
|
141
|
+
@recognizer.add_watcher :incorrect_group_watcher
|
148
142
|
|
149
143
|
@recognizer.scan
|
150
|
-
assert @recognizer.raised_watchers.include?(:
|
144
|
+
assert @recognizer.raised_watchers.include?(:incorrect_group_watcher)
|
151
145
|
end
|
146
|
+
|
147
|
+
|
152
148
|
end
|
153
149
|
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ruby_marks
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -37,17 +37,16 @@ extensions: []
|
|
37
37
|
extra_rdoc_files: []
|
38
38
|
files:
|
39
39
|
- README.md
|
40
|
-
- lib/ruby_marks/clock_mark.rb
|
41
40
|
- lib/ruby_marks/config.rb
|
42
41
|
- lib/ruby_marks/group.rb
|
43
42
|
- lib/ruby_marks/image_utils.rb
|
43
|
+
- lib/ruby_marks/mark.rb
|
44
44
|
- lib/ruby_marks/recognizer.rb
|
45
|
+
- lib/ruby_marks/scan_area.rb
|
45
46
|
- lib/ruby_marks/support.rb
|
46
47
|
- lib/ruby_marks/version.rb
|
47
48
|
- lib/ruby_marks/watcher.rb
|
48
49
|
- lib/ruby_marks.rb
|
49
|
-
- test/ruby_marks/clock_mark_test.rb
|
50
|
-
- test/ruby_marks/group_test.rb
|
51
50
|
- test/ruby_marks/image_utils_test.rb
|
52
51
|
- test/ruby_marks/recognizer_test.rb
|
53
52
|
- test/ruby_marks/watcher_test.rb
|
@@ -55,10 +54,13 @@ files:
|
|
55
54
|
homepage: https://github.com/andrerpbts/ruby_marks.git
|
56
55
|
licenses:
|
57
56
|
- MIT
|
58
|
-
post_install_message: ! "\n ***
|
59
|
-
|
60
|
-
|
61
|
-
***\n
|
57
|
+
post_install_message: ! "\n *** NOTE: You are running the ImageMagick under 16bits
|
58
|
+
quantum depth. This configuration is used\n in very specific cases and
|
59
|
+
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
|
60
|
+
***\n\n We changed the way it recognizes the marks. It's not based on clocks
|
61
|
+
anymore. If you are updating the gem \n from 0.1.4 version, you should refactor
|
62
|
+
your code to eliminate the clocks parameters and adjust \n some new configurations.
|
63
|
+
More information can be obtained on README file.\n "
|
62
64
|
rdoc_options: []
|
63
65
|
require_paths:
|
64
66
|
- lib
|
@@ -81,8 +83,6 @@ signing_key:
|
|
81
83
|
specification_version: 3
|
82
84
|
summary: A simple OMR tool
|
83
85
|
test_files:
|
84
|
-
- test/ruby_marks/clock_mark_test.rb
|
85
|
-
- test/ruby_marks/group_test.rb
|
86
86
|
- test/ruby_marks/image_utils_test.rb
|
87
87
|
- test/ruby_marks/recognizer_test.rb
|
88
88
|
- test/ruby_marks/watcher_test.rb
|
@@ -1,65 +0,0 @@
|
|
1
|
-
#encoding: utf-8
|
2
|
-
module RubyMarks
|
3
|
-
|
4
|
-
class ClockMark
|
5
|
-
|
6
|
-
attr_accessor :recognizer, :coordinates
|
7
|
-
|
8
|
-
def initialize(params={})
|
9
|
-
params.each do |k, v|
|
10
|
-
self.send("#{k}=", v) if self.respond_to?("#{k}=")
|
11
|
-
end
|
12
|
-
end
|
13
|
-
|
14
|
-
def valid?
|
15
|
-
|
16
|
-
return false if !self.recognizer.config.clock_width_tolerance_range.include?(self.width) ||
|
17
|
-
!self.recognizer.config.clock_height_tolerance_range.include?(self.height)
|
18
|
-
|
19
|
-
|
20
|
-
self.recognizer.export_file_to_str if self.recognizer.file_str.nil?
|
21
|
-
|
22
|
-
x_pos = coordinates[:x1]..coordinates[:x2]
|
23
|
-
y_pos = coordinates[:y1]..coordinates[:y2]
|
24
|
-
|
25
|
-
colors = []
|
26
|
-
|
27
|
-
y_pos.each do |y|
|
28
|
-
x_pos.each do |x|
|
29
|
-
|
30
|
-
color = self.recognizer.file_str[y][x]
|
31
|
-
|
32
|
-
colors << color
|
33
|
-
end
|
34
|
-
end
|
35
|
-
|
36
|
-
intensity = colors.count(".") * 100 / colors.size
|
37
|
-
return intensity >= 70 ? true : false
|
38
|
-
end
|
39
|
-
|
40
|
-
def invalid?
|
41
|
-
!valid?
|
42
|
-
end
|
43
|
-
|
44
|
-
def width
|
45
|
-
RubyMarks::ImageUtils.calc_width(@coordinates[:x1], @coordinates[:x2])
|
46
|
-
end
|
47
|
-
|
48
|
-
def height
|
49
|
-
RubyMarks::ImageUtils.calc_height(@coordinates[:y1], @coordinates[:y2])
|
50
|
-
end
|
51
|
-
|
52
|
-
def horizontal_middle_position
|
53
|
-
RubyMarks::ImageUtils.calc_middle_horizontal(@coordinates[:x1], self.width)
|
54
|
-
end
|
55
|
-
|
56
|
-
def vertical_middle_position
|
57
|
-
RubyMarks::ImageUtils.calc_middle_vertical(@coordinates[:y1], self.height)
|
58
|
-
end
|
59
|
-
|
60
|
-
def to_s
|
61
|
-
self.coordinates
|
62
|
-
end
|
63
|
-
|
64
|
-
end
|
65
|
-
end
|
@@ -1,44 +0,0 @@
|
|
1
|
-
require "test_helper"
|
2
|
-
|
3
|
-
class RubyMarks::ClockMarkTest < Test::Unit::TestCase
|
4
|
-
|
5
|
-
def setup
|
6
|
-
@file = 'assets/sheet_demo1.png'
|
7
|
-
@recognizer = RubyMarks::Recognizer.new
|
8
|
-
@recognizer.file = @file
|
9
|
-
@positions = {}
|
10
|
-
@positions[:first_clock_position] = {x1: 49, x2: 74, y1: 790, y2: 801}
|
11
|
-
@positions[:not_a_clock] = {x1: 62, x2: 63, y1: 859, y2: 860}
|
12
|
-
end
|
13
|
-
|
14
|
-
def test_should_obtain_the_clock_mark_width
|
15
|
-
clock = RubyMarks::ClockMark.new(recognizer: @recognizer, coordinates: @positions[:first_clock_position])
|
16
|
-
assert_equal 26, clock.width
|
17
|
-
end
|
18
|
-
|
19
|
-
def test_should_obtain_the_clock_mark_height
|
20
|
-
clock = RubyMarks::ClockMark.new(recognizer: @recognizer, coordinates: @positions[:first_clock_position])
|
21
|
-
assert_equal 12, clock.height
|
22
|
-
end
|
23
|
-
|
24
|
-
def test_should_obtain_the_horizontal_middle_position
|
25
|
-
clock = RubyMarks::ClockMark.new(recognizer: @recognizer, coordinates: @positions[:first_clock_position])
|
26
|
-
assert_equal 62, clock.horizontal_middle_position
|
27
|
-
end
|
28
|
-
|
29
|
-
def test_should_obtain_the_vertical_middle_position
|
30
|
-
clock = RubyMarks::ClockMark.new(recognizer: @recognizer, coordinates: @positions[:first_clock_position])
|
31
|
-
assert_equal 796, clock.vertical_middle_position
|
32
|
-
end
|
33
|
-
|
34
|
-
def test_should_recognize_a_valid_clock
|
35
|
-
clock = RubyMarks::ClockMark.new(recognizer: @recognizer, coordinates: @positions[:first_clock_position])
|
36
|
-
assert clock.valid?, "Not recognized a valid clock"
|
37
|
-
end
|
38
|
-
|
39
|
-
def test_should_recognize_a_invalid_clock
|
40
|
-
clock = RubyMarks::ClockMark.new(recognizer: @recognizer, coordinates: @positions[:not_a_clock])
|
41
|
-
assert clock.invalid?, "Recognized a invalid clock as a valid one"
|
42
|
-
end
|
43
|
-
|
44
|
-
end
|
@@ -1,26 +0,0 @@
|
|
1
|
-
require "test_helper"
|
2
|
-
|
3
|
-
class RubyMarks::GroupTest < Test::Unit::TestCase
|
4
|
-
|
5
|
-
def setup
|
6
|
-
@file = 'assets/sheet_demo1.png'
|
7
|
-
@recognizer = RubyMarks::Recognizer.new
|
8
|
-
@recognizer.file = @file
|
9
|
-
@group = RubyMarks::Group.new(:test, @recognizer)
|
10
|
-
end
|
11
|
-
|
12
|
-
def test_should_convert_fixnum_into_range_in_clocks_range
|
13
|
-
@group.clocks_range = 1
|
14
|
-
assert_equal 1..1, @group.clocks_range
|
15
|
-
end
|
16
|
-
|
17
|
-
def test_should_return_that_group_belongs_to_a_clock
|
18
|
-
@group.clocks_range = 1..10
|
19
|
-
assert @group.belongs_to_clock?(1), "Not recognized that group belongs to group 1"
|
20
|
-
end
|
21
|
-
|
22
|
-
def test_should_not_return_that_group_belongs_to_a_clock
|
23
|
-
@group.clocks_range = 1..10
|
24
|
-
assert !@group.belongs_to_clock?(11), "Recognized that group belongs to group 11"
|
25
|
-
end
|
26
|
-
end
|