ruby_marks 0.1.2 → 0.1.3
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +402 -0
- data/lib/ruby_marks/recognizer.rb +6 -1
- data/lib/ruby_marks/version.rb +1 -1
- metadata +3 -3
- data/README.rdoc +0 -4
data/README.md
ADDED
@@ -0,0 +1,402 @@
|
|
1
|
+
Ruby Marks
|
2
|
+
==========
|
3
|
+
|
4
|
+
[![Build Status](https://secure.travis-ci.org/andrerpbts/ruby_marks.png?branch=master)](http://travis-ci.org/andrerpbts/ruby_marks)
|
5
|
+
|
6
|
+
A simple OMR ([Optical Mark Recognition](http://en.wikipedia.org/wiki/Optical_mark_recognition)) gem for ruby 1.9.x.
|
7
|
+
|
8
|
+
|
9
|
+
Requirements
|
10
|
+
------------
|
11
|
+
|
12
|
+
This gem uses [ImageMagick](http://www.imagemagick.org) to manipulate the given images.
|
13
|
+
You can verify if this utility is installed by the command line `which convert`, which should return
|
14
|
+
the current ImageMagick path.
|
15
|
+
|
16
|
+
For example, `/usr/local/bin/convert`.
|
17
|
+
|
18
|
+
If not installed:
|
19
|
+
|
20
|
+
### MacOS X
|
21
|
+
|
22
|
+
If you're on Mac OS X, Homebrew may be your best option:
|
23
|
+
|
24
|
+
brew install imagemagick
|
25
|
+
|
26
|
+
|
27
|
+
### Ubuntu
|
28
|
+
|
29
|
+
On Ubuntu, the `apt-get` should be enough:
|
30
|
+
|
31
|
+
apt-get install imagemagick
|
32
|
+
|
33
|
+
|
34
|
+
Supported versions
|
35
|
+
------------------
|
36
|
+
|
37
|
+
* Ruby 1.9.2
|
38
|
+
* Ruby 1.9.3
|
39
|
+
|
40
|
+
|
41
|
+
Install
|
42
|
+
-------
|
43
|
+
|
44
|
+
If you are using `Bundler`, just put this line in your Gemfile:
|
45
|
+
|
46
|
+
```ruby
|
47
|
+
gem 'ruby_marks'
|
48
|
+
```
|
49
|
+
|
50
|
+
Then run bundle install command:
|
51
|
+
|
52
|
+
bundle
|
53
|
+
|
54
|
+
If not, you still can run a default gem installation method:
|
55
|
+
|
56
|
+
gem install ruby_marks
|
57
|
+
|
58
|
+
And require it in your ruby code:
|
59
|
+
|
60
|
+
```ruby
|
61
|
+
require 'ruby_marks'
|
62
|
+
```
|
63
|
+
|
64
|
+
|
65
|
+
How it Works
|
66
|
+
------------
|
67
|
+
|
68
|
+
The gem will scan a document column search for this small full-filled black rectangles **(clock marks)**.
|
69
|
+
For each clock mark found, it will perform a line scan in each group looking for a marked position.
|
70
|
+
In the end, returns a hash with each correspondent mark found in the group and the clock.
|
71
|
+
|
72
|
+
The gem will not perform deskew in your documents. If the document have skew, then you should apply your own
|
73
|
+
deskew method on the file before.
|
74
|
+
|
75
|
+
|
76
|
+
Usage
|
77
|
+
-----
|
78
|
+
|
79
|
+
Unfortunatelly, this gem will require a bit more configuration to work, since the implementation depends
|
80
|
+
a lot of your document sizes, positions, brightness, etc...
|
81
|
+
|
82
|
+
That said, lets describe it's basic structure. The example will assume a directory with some png images like this one:
|
83
|
+
|
84
|
+
[![Document Example](https://raw.github.com/andrerpbts/ruby_marks/master/assets/sheet_demo2.png)](https://github.com/andrerpbts/ruby_marks/blob/master/assets/sheet_demo2.png)
|
85
|
+
|
86
|
+
Then, we write a basic code to scan it and print result on console:
|
87
|
+
|
88
|
+
```ruby
|
89
|
+
recognizer = RubyMarks::Recognizer.new
|
90
|
+
recognizer.configure do |config|
|
91
|
+
|
92
|
+
config.clock_marks_scan_x = 42
|
93
|
+
config.clock_width = 29
|
94
|
+
config.clock_height = 12
|
95
|
+
|
96
|
+
config.define_group :one do |group|
|
97
|
+
group.clocks_range = 1..5
|
98
|
+
group.x_distance_from_clock = 89
|
99
|
+
end
|
100
|
+
|
101
|
+
config.define_group :two do |group|
|
102
|
+
group.clocks_range = 1..5
|
103
|
+
group.x_distance_from_clock = 315
|
104
|
+
end
|
105
|
+
|
106
|
+
config.define_group :three do |group|
|
107
|
+
group.clocks_range = 1..5
|
108
|
+
group.x_distance_from_clock = 542
|
109
|
+
end
|
110
|
+
|
111
|
+
config.define_group :four do |group|
|
112
|
+
group.clocks_range = 1..5
|
113
|
+
group.x_distance_from_clock = 769
|
114
|
+
end
|
115
|
+
|
116
|
+
config.define_group :five do |group|
|
117
|
+
group.clocks_range = 1..5
|
118
|
+
group.x_distance_from_clock = 996
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
Dir["./*.png"].each do |file|
|
123
|
+
recognizer.file = file
|
124
|
+
puts recognizer.scan
|
125
|
+
end
|
126
|
+
```
|
127
|
+
|
128
|
+
This should puts each scan in a hash, like this:
|
129
|
+
|
130
|
+
```
|
131
|
+
{
|
132
|
+
:clock_1 => {
|
133
|
+
:group_one => ['A'],
|
134
|
+
:group_two => ['E'],
|
135
|
+
:group_three => ['B'],
|
136
|
+
:group_four => ['B'],
|
137
|
+
:group_five => ['B']
|
138
|
+
},
|
139
|
+
:clock_2 => {
|
140
|
+
:group_one => ['C'],
|
141
|
+
:group_two => ['A'],
|
142
|
+
:group_three => ['B'],
|
143
|
+
:group_four => ['E'],
|
144
|
+
:group_five => ['A']
|
145
|
+
},
|
146
|
+
:clock_3 => {
|
147
|
+
:group_one => ['B'],
|
148
|
+
:group_two => ['B'],
|
149
|
+
:group_three => ['D'],
|
150
|
+
:group_four => ['A'],
|
151
|
+
:group_five => ['A']
|
152
|
+
},
|
153
|
+
:clock_4 => {
|
154
|
+
:group_one => ['B'],
|
155
|
+
:group_two => ['A'],
|
156
|
+
:group_three => ['B'],
|
157
|
+
:group_four => ['C'],
|
158
|
+
:group_five => ['C']
|
159
|
+
},
|
160
|
+
:clock_5 => {
|
161
|
+
:group_one => ['D'],
|
162
|
+
:group_two => ['B'],
|
163
|
+
:group_three => ['B'],
|
164
|
+
:group_four => ['D'],
|
165
|
+
:group_five => ['D']
|
166
|
+
}
|
167
|
+
}
|
168
|
+
```
|
169
|
+
|
170
|
+
|
171
|
+
General Configuration Options
|
172
|
+
-----------------------------
|
173
|
+
|
174
|
+
As you may see, it's necessary configure some document aspects to make this work properly. So, lets describe
|
175
|
+
each general configuration option available:
|
176
|
+
|
177
|
+
### Threshold level
|
178
|
+
|
179
|
+
```ruby
|
180
|
+
# Applies the given percentual in the image in order to get it back with only black and white pixels.
|
181
|
+
# Low percentuals will result in a bright image, as High percentuals will result in a more darken image.
|
182
|
+
# The default value is 60
|
183
|
+
|
184
|
+
config.threshold_level = 60
|
185
|
+
```
|
186
|
+
|
187
|
+
### Distance in axis X from margin to scan the clock marks
|
188
|
+
|
189
|
+
```ruby
|
190
|
+
# Defines the X distance from the left margin (in pixels) to look for the valids (black) pixels
|
191
|
+
# of the clock marks in this column. This configuration is very important because each type of document may
|
192
|
+
# have the clock marks in a specific and different column, and this configuration that will indicate
|
193
|
+
# a X pixel column that cross all the clocks.
|
194
|
+
# The default value is 62 but only for tests purposes. You SHOULD calculate this value and set
|
195
|
+
# a new one.
|
196
|
+
|
197
|
+
config.clock_marks_scan_x = 62
|
198
|
+
```
|
199
|
+
|
200
|
+
### Clock sizes
|
201
|
+
|
202
|
+
```ruby
|
203
|
+
# Defines the expected width and height of clock marks (in pixels). With the tolerance, if the first
|
204
|
+
# recognized clock exceeds or stricts those values, it will be ignored...
|
205
|
+
# The default values is 26 to width and 12 to height. Since the clock marks can be different, you SHOULD
|
206
|
+
# calculate those sizes for your documents.
|
207
|
+
|
208
|
+
config.clock_width = 26
|
209
|
+
config.clock_height = 12
|
210
|
+
```
|
211
|
+
|
212
|
+
### Tolerance on the size of clock mark
|
213
|
+
|
214
|
+
```ruby
|
215
|
+
# Indicates the actual tolerance (in pixels) for the clock mark found. That means the clock can be smaller or
|
216
|
+
# larger than expected, by the number of pixels set in this option.
|
217
|
+
# The default value is 2
|
218
|
+
|
219
|
+
config.clock_mark_size_tolerance = 2
|
220
|
+
```
|
221
|
+
|
222
|
+
### Expected clocks count
|
223
|
+
|
224
|
+
```ruby
|
225
|
+
# If this value is defined (above 0), the scan will perform a check if the clocks found on document
|
226
|
+
# is identical with this expected number. If different, the scan will be stopped.
|
227
|
+
# This config is mandatory if you want to raise the Clock Mark Difference Watcher.
|
228
|
+
# The default value is 0
|
229
|
+
|
230
|
+
config.expected_clocks_count = 0
|
231
|
+
```
|
232
|
+
|
233
|
+
### Default mark sizes
|
234
|
+
|
235
|
+
```ruby
|
236
|
+
# Defines the expected width and height of the marks (in pixels). With the tolerance, if the first recognized
|
237
|
+
# mark exceeds or stricts those values, it will be ignored.
|
238
|
+
# The default values is 20 to width and 20 to height. Since the marks can be different, you SHOULD
|
239
|
+
# calculate those sizes for your documents.
|
240
|
+
|
241
|
+
config.default_mark_width = 20
|
242
|
+
config.default_mark_height = 20
|
243
|
+
```
|
244
|
+
|
245
|
+
### Intensity percentual
|
246
|
+
|
247
|
+
```ruby
|
248
|
+
# Set the intensity sensitivity (in percentual) expected to recognize a mark as a marked one.
|
249
|
+
# When the scan find some potential marked area, then it will analyse if the count of valid pixels (black pixels)
|
250
|
+
# have this minimun percentage.
|
251
|
+
# Increasing this value, the recognition becomes more sensitive and can ignore valid weaker markings.
|
252
|
+
# Decreasing this value, recognition becomes less sensitive and can recognize false markings.
|
253
|
+
# The default value is 50.
|
254
|
+
|
255
|
+
config.intensity_percentual = 50
|
256
|
+
```
|
257
|
+
|
258
|
+
### Default marks options
|
259
|
+
|
260
|
+
```ruby
|
261
|
+
# Set the marks options that the groups represents. When the scan recognizes a mark in some position,
|
262
|
+
# it will return they value in the result hash.
|
263
|
+
# The default value is the [A, B, C, D, E] array.
|
264
|
+
|
265
|
+
config.default_marks_options = %w{A B C D E}
|
266
|
+
```
|
267
|
+
|
268
|
+
### Default distance between each mark in group
|
269
|
+
|
270
|
+
```ruby
|
271
|
+
# Defines the distance (in pixel) between the middle of a mark and the middle of the next mark in the same group.
|
272
|
+
# The scan will begin in the first mark, by the value in pixels it have from the right corner of the clock.
|
273
|
+
# After it, each mark option in the group will be checked based in this distance.
|
274
|
+
# The default value is 25
|
275
|
+
|
276
|
+
config.default_distance_between_marks = 25
|
277
|
+
```
|
278
|
+
|
279
|
+
|
280
|
+
Group Configuration Options
|
281
|
+
---------------------------
|
282
|
+
|
283
|
+
The General Configuration Options is more generic for the entire document. So, you can have some particularities
|
284
|
+
when defining a group. So:
|
285
|
+
|
286
|
+
### Mark sizes
|
287
|
+
|
288
|
+
```ruby
|
289
|
+
# It overwrites the default_mark_width and default_mark_height values for the group you configure it.
|
290
|
+
|
291
|
+
group.mark_width = RubyMarks.default_mark_width
|
292
|
+
group.mark_height = RubyMarks.default_mark_height
|
293
|
+
```
|
294
|
+
|
295
|
+
### Marks options
|
296
|
+
|
297
|
+
```ruby
|
298
|
+
# It overwrites the default_marks_options values for the group you configure it.
|
299
|
+
|
300
|
+
group.marks_options = RubyMarks.default_marks_options
|
301
|
+
```
|
302
|
+
|
303
|
+
### Distance in axis X from clock
|
304
|
+
|
305
|
+
```ruby
|
306
|
+
# Defines the distance from the right corner of the clock mark to the middle of the first mark in the group
|
307
|
+
# It don't have a default value, you MUST set this value for each group in your document
|
308
|
+
|
309
|
+
group.x_distance_from_clock = 89
|
310
|
+
```
|
311
|
+
|
312
|
+
### Distance Between Marks
|
313
|
+
|
314
|
+
```ruby
|
315
|
+
# It overwrites the default_distance_between_marks values for the group you configure it.
|
316
|
+
|
317
|
+
group.distance_between_marks = RubyMarks.default_distance_between_marks
|
318
|
+
```
|
319
|
+
|
320
|
+
### Clocks range
|
321
|
+
|
322
|
+
```ruby
|
323
|
+
# Defines the clock ranges this group belongs to. This range that will consider what clock mark
|
324
|
+
# should be returned in the result of the scan.
|
325
|
+
|
326
|
+
group.clocks_range = 1..5
|
327
|
+
```
|
328
|
+
|
329
|
+
|
330
|
+
Watchers
|
331
|
+
--------
|
332
|
+
|
333
|
+
Sometimes, due some image flaws, the scan can't recognize some clock mark, or a mark, or even recognize
|
334
|
+
more than one mark in a clock row in the same group when it is not expected. Then, you can place some
|
335
|
+
watchers, that will perform some custom code made by yourself in those cases. The available watchers are:
|
336
|
+
In the watchers you can, for example, apply a deskew in image and re-run the scan. But, be advised, if you
|
337
|
+
call the scan method again inside the watcher, you should make sure that you have a way to leave the watcher
|
338
|
+
to avoid a endless loop. You always can check how many times the watcher got raised by checking in
|
339
|
+
`recognizer.raised_watchers[:watcher_name]` hash.
|
340
|
+
|
341
|
+
|
342
|
+
### Scan Mark Watcher
|
343
|
+
|
344
|
+
```ruby
|
345
|
+
# Will execute your custom code if didn't recognizes some mark or recognizes more than one mark in a clock
|
346
|
+
# row and the same group.
|
347
|
+
# It returns the recognizer object, the result of scan hash, a boolean value if this watcher was raised by unmarked
|
348
|
+
# options and a boolean value if the watcher was raised by a multiple marks options
|
349
|
+
|
350
|
+
recognizer.add_watcher :scan_mark_watcher do |recognizer, result, unmarked_group_found, multiple_marked_found|
|
351
|
+
# place your custom code
|
352
|
+
end
|
353
|
+
```
|
354
|
+
|
355
|
+
### Scan Unmarked Watcher
|
356
|
+
|
357
|
+
```ruby
|
358
|
+
# Will execute your custom code if didn't recognizes some mark.
|
359
|
+
# It returns the recognizer object, the result of scan hash.
|
360
|
+
|
361
|
+
recognizer.add_watcher :scan_unmarked_watcher do |recognizer, result|
|
362
|
+
# place your custom code
|
363
|
+
end
|
364
|
+
```
|
365
|
+
|
366
|
+
### Scan Multiple Marked Watcher
|
367
|
+
|
368
|
+
```ruby
|
369
|
+
# Will execute your custom code if recognizes more than one mark in a clock row and the same group.
|
370
|
+
# It returns the recognizer object, the result of scan hash.
|
371
|
+
|
372
|
+
recognizer.add_watcher :scan_multiple_marked_watcher do |recognizer, result|
|
373
|
+
# place your custom code
|
374
|
+
end
|
375
|
+
```
|
376
|
+
|
377
|
+
### Clock Mark Difference Watcher
|
378
|
+
|
379
|
+
```ruby
|
380
|
+
# Will execute your custom code if didn't recognizes your expected clock marks count.
|
381
|
+
# In order to raise this watcher you must define the `config.expected_clocks_count`.
|
382
|
+
# It returns the recognizer object.
|
383
|
+
|
384
|
+
recognizer.add_watcher :clock_mark_difference_watcher do |recognizer|
|
385
|
+
# place your custom code
|
386
|
+
end
|
387
|
+
```
|
388
|
+
|
389
|
+
Contributing
|
390
|
+
------------
|
391
|
+
|
392
|
+
* Fork it
|
393
|
+
* Make your implementations
|
394
|
+
* Send me a pull request
|
395
|
+
|
396
|
+
Thank you!
|
397
|
+
|
398
|
+
|
399
|
+
License
|
400
|
+
-------
|
401
|
+
|
402
|
+
Copyright © 2012 André Rodrigues, Ronaldo Araújo, Rodrigo Virgilio, Lucas Correa. See MIT-LICENSE for further details.
|
@@ -216,7 +216,12 @@ module RubyMarks
|
|
216
216
|
|
217
217
|
file.tap do |file|
|
218
218
|
position_before = @current_position
|
219
|
-
|
219
|
+
|
220
|
+
dr = Magick::Draw.new
|
221
|
+
dr.fill(RubyMarks::COLORS[4])
|
222
|
+
dr.line(@config.clock_marks_scan_x, 0, @config.clock_marks_scan_x, file.page.height)
|
223
|
+
dr.draw(file)
|
224
|
+
|
220
225
|
scan_clock_marks unless clock_marks.any?
|
221
226
|
|
222
227
|
clock_marks.each_with_index do |clock, index|
|
data/lib/ruby_marks/version.rb
CHANGED
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.1.
|
4
|
+
version: 0.1.3
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -35,8 +35,9 @@ email:
|
|
35
35
|
executables: []
|
36
36
|
extensions: []
|
37
37
|
extra_rdoc_files:
|
38
|
-
- README.
|
38
|
+
- README.md
|
39
39
|
files:
|
40
|
+
- README.md
|
40
41
|
- lib/ruby_marks/clock_mark.rb
|
41
42
|
- lib/ruby_marks/config.rb
|
42
43
|
- lib/ruby_marks/group.rb
|
@@ -46,7 +47,6 @@ files:
|
|
46
47
|
- lib/ruby_marks/version.rb
|
47
48
|
- lib/ruby_marks/watcher.rb
|
48
49
|
- lib/ruby_marks.rb
|
49
|
-
- README.rdoc
|
50
50
|
- test/ruby_marks/clock_mark_test.rb
|
51
51
|
- test/ruby_marks/group_test.rb
|
52
52
|
- test/ruby_marks/image_utils_test.rb
|
data/README.rdoc
DELETED