mork 0.1.3 → 0.2.1

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
  SHA1:
3
- metadata.gz: f334aa5882675284d8700705af5fe1015045234f
4
- data.tar.gz: 5d516e96fe0453f29179b08ded1d3d9786c27bff
3
+ metadata.gz: 023acadd6339d125a7764a4af516d86b7da951c3
4
+ data.tar.gz: fffbcdd3a134b60d02f46a380ba5192812c13b76
5
5
  SHA512:
6
- metadata.gz: fafa8bd3db5eb7a0c5f0c15274daf62046e2285bfee46704cf849eca984eb59edb0866b85d1fc489d44f2b3c6a452cfc166ffd06674b2c7242550a32d216097b
7
- data.tar.gz: 6b9244e99322ee533905329240618e0ed52bc729e313d99cb03078e3c63554d7194ab8956894f1c4917ff5ba0d72fad85e2f1bb3d1a15e94606a5597593dcd75
6
+ metadata.gz: 8bb3ec4c6ec605ce6d7866550ab7d66025520d99961a388ae303b513a2a5f57252818725ae8d8d64f891eab54f55d0f7c3d61cae3c16cea873612f53344ac31a
7
+ data.tar.gz: ad6e6df8e2ce80126e270760bc2909a2810555d1f68196e919f635feec29d55974444b98bda28e93dfdd510d938566289e4882ce4f96cb04460e0b385f2f3f59
data/Gemfile CHANGED
@@ -1,3 +1,2 @@
1
1
  source "http://rubygems.org"
2
- # gem 'prawn', git: 'git://github.com/prawnpdf/prawn', submodules: true
3
2
  gemspec
data/auto.txt ADDED
File without changes
data/lib/mork/grid_omr.rb CHANGED
@@ -2,14 +2,21 @@ require 'mork/grid'
2
2
 
3
3
  module Mork
4
4
  class GridOMR < Grid
5
- def initialize(page_width, page_height, options=nil)
5
+ def initialize(options=nil)
6
6
  super options
7
- @px = page_width.to_f
8
- @py = page_height.to_f
9
7
  end
10
8
 
11
- def barcode_bit_areas(code = 2**barcode_bits-1)
12
- barcode_bits.times.collect { |b| barcode_bit_area b }
9
+ def set_page_size(width, height)
10
+ @px = width.to_f
11
+ @py = height.to_f
12
+ end
13
+
14
+ def barcode_bit_areas(bitstring = '1' * barcode_bits)
15
+ areas = []
16
+ bitstring.reverse.each_char.with_index do |c, i|
17
+ areas << barcode_bit_area(i+1) if c=='1'
18
+ end
19
+ areas
13
20
  end
14
21
 
15
22
  # ====================================================
data/lib/mork/mimage.rb CHANGED
@@ -1,67 +1,103 @@
1
- require 'RMagick'
1
+ require 'mini_magick'
2
+ require 'mork/npatch'
2
3
 
3
4
  module Mork
4
- # The class Mimage is a wrapper for the core image library, currently RMagick
5
+ # The class Mimage is a wrapper for the core image library, currently mini_magick
5
6
  class Mimage
6
- def initialize(img, page=0)
7
- if img.class == String
8
- if File.extname(img) == '.pdf'
9
- @image = Magick::Image.read(img) { self.density = 200 }[page]
10
- else
11
- @image = Magick::ImageList.new(img)[page]
12
- end
13
- elsif img.class == Magick::ImageList
14
- @image = img[page]
15
- elsif img.class == Magick::Image
16
- @image = img
17
- else
18
- raise "Invalid initialization argument"
19
- end
7
+ def initialize(path, grom, page=0)
8
+ raise "File '#{path}' not found" unless File.exists? path
9
+ @path = path
10
+ @grom = grom
11
+ @grom.set_page_size width, height
12
+ @status = register
13
+ @cmd = []
14
+ end
15
+
16
+ def status
17
+ @status
18
+ end
19
+
20
+ def ink_black
21
+ reg_pixels.average @grom.ink_black_area
22
+ end
23
+
24
+ def paper_white
25
+ reg_pixels.average @grom.paper_white_area
26
+ end
27
+
28
+ def cal_cell_mean
29
+ @grom.calibration_cell_areas.collect { |c| reg_pixels.average c }.mean
30
+ end
31
+
32
+ def shade_of_barcode_bit(i)
33
+ reg_pixels.average @grom.barcode_bit_area i+1
34
+ end
35
+
36
+ def shade_of(q,c)
37
+ reg_pixels.average @grom.choice_cell_area(q, c)
38
+ end
39
+
40
+ def width
41
+ img_size[0].to_i
20
42
  end
21
43
 
22
- # outline!(cells, roundedness)
44
+ def height
45
+ img_size[1].to_i
46
+ end
47
+
48
+ # outline(cells, roundedness)
23
49
  #
24
50
  # draws on the Mimage a set of cell outlines
25
51
  # typically used to highlight the expected responses
26
- def outline!(cells, roundedness=nil)
27
- cells = [cells] if cells.is_a? Hash
52
+ def outline(cells, roundedness=nil)
28
53
  return if cells.empty?
29
- roundedness ||= [cells[0][:h], cells[0][:w]].min / 2
30
- out = Magick::Draw.new
31
- out.stroke 'green'
32
- out.stroke_width 4
33
- out.fill_opacity 0
34
- cells.each do |c|
35
- out.roundrectangle c[:x], c[:y], c[:x]+c[:w], c[:y]+c[:h], roundedness, roundedness
36
- out.draw @image
54
+ @cmd << [:stroke, 'green']
55
+ @cmd << [:strokewidth, '4']
56
+ @cmd << [:fill, 'none']
57
+ array_of(cells).each do |c|
58
+ roundedness ||= [c[:h], c[:w]].min / 2
59
+ pts = [c[:x], c[:y], c[:x]+c[:w], c[:y]+c[:h], roundedness, roundedness].join ' '
60
+ @cmd << [:draw, "roundrectangle #{pts}"]
37
61
  end
38
62
  end
39
63
 
40
- # =============
41
- # = Highlight =
42
- # =============
43
- def highlight_cells!(cells, roundedness=nil)
44
- cells = [cells] if cells.is_a? Hash
64
+ def highlight_all_choices
65
+ cells = (0...@grom.max_questions).collect { |i| (0...@grom.max_choices_per_question).to_a }
66
+ highlight_cells cells
67
+ end
68
+
69
+ # highlight_cells(cells, roundedness)
70
+ #
71
+ # partially transparent yellow on top of choice cells
72
+ def highlight_cells(cells, roundedness=nil)
45
73
  return if cells.empty?
46
- roundedness ||= [cells[0][:h], cells[0][:w]].min / 2
47
- cells.each do |c|
48
- out = Magick::Draw.new
49
- out.fill 'yellow'
50
- out.opacity '40%'
51
- out.roundrectangle c[:x], c[:y], c[:x]+c[:w], c[:y]+c[:h], roundedness, roundedness
52
- out.draw @image
74
+ @cmd << [:stroke, 'none']
75
+ @cmd << [:fill, 'rgba(255, 255, 0, 0.3)']
76
+ array_of(cells).each do |c|
77
+ roundedness ||= [c[:h], c[:w]].min / 2
78
+ pts = [c[:x], c[:y], c[:x]+c[:w], c[:y]+c[:h], roundedness, roundedness].join ' '
79
+ @cmd << [:draw, "roundrectangle #{pts}"]
53
80
  end
54
81
  end
55
82
 
56
- def highlight_rect!(areas)
57
- areas = [areas] if areas.is_a? Hash
83
+ def highlight_reg_area
84
+ highlight_rect [@rmsa[:tl], @rmsa[:tr], @rmsa[:br], @rmsa[:bl]]
85
+ return unless @status
86
+ join [@rm[:tl], @rm[:tr], @rm[:br], @rm[:bl]]
87
+ end
88
+
89
+ def highlight_barcode(bitstring)
90
+ highlight_rect @grom.barcode_bit_areas bitstring
91
+ end
92
+
93
+ def highlight_rect(areas)
94
+ return if areas.empty?
95
+ @cmd << [:fill, 'none']
96
+ @cmd << [:stroke, 'yellow']
97
+ @cmd << [:strokewidth, 3]
58
98
  areas.each do |c|
59
- out = Magick::Draw.new
60
- out.fill_opacity 0
61
- out.stroke 'yellow'
62
- out.stroke_width 3
63
- out.rectangle c[:x], c[:y], c[:x]+c[:w], c[:y]+c[:h]
64
- out.draw @image
99
+ pts = [c[:x], c[:y], c[:x]+c[:w], c[:y]+c[:h]].join ' '
100
+ @cmd << [:draw, "rectangle #{pts}"]
65
101
  end
66
102
  end
67
103
 
@@ -75,69 +111,98 @@ module Mork
75
111
  end
76
112
  end
77
113
 
78
- def join!(p)
79
- poly = Magick::Draw.new
80
- poly.fill_opacity 0
81
- poly.stroke 'green'
82
- poly.stroke_width 3
83
- poly.polygon p[0][:x], p[0][:y], p[1][:x], p[1][:y], p[2][:x], p[2][:y], p[3][:x], p[3][:y]
84
- poly.draw @image
114
+ # write the underlying MiniMagick::Image to disk;
115
+ # if the 2nd arg is false, then stretching is not applied
116
+ def write(fname, reg=true)
117
+ img = MiniMagick::Image.open @path
118
+ img.combine_options do |c|
119
+ c.distort(:perspective, perspective_points) if reg
120
+ @cmd.each do |cmd|
121
+ c.send *cmd
122
+ end
123
+ end
124
+ img.write fname
85
125
  end
86
126
 
87
- # ============
88
- # = Cropping =
89
- # ============
90
- def crop(c)
91
- Mimage.new @image.crop(c[:x], c[:y], c[:w], c[:h])
92
- end
127
+ # ============================================================#
128
+ private #
129
+ # ============================================================#
93
130
 
94
- def crop!(c)
95
- @image.crop!(c[:x], c[:y], c[:w], c[:h])
96
- self
97
- end
98
-
99
- # ============
100
- # = Blurring =
101
- # ============
102
- def blur(a, b)
103
- Mimage.new @image.blur_image(a, b)
104
- end
105
-
106
- def blur!(a, b)
107
- @image = @image.blur_image(a, b)
108
- self
131
+ def img_size
132
+ @img_size ||= IO.read("|identify -format '%w,%h' #{@path}").split ','
109
133
  end
110
134
 
111
- # ==============
112
- # = Stretching =
113
- # ==============
114
- def stretch(points)
115
- Mimage.new @image.distort(Magick::PerspectiveDistortion, points)
135
+ def raw_pixels
136
+ @raw_pixels ||= begin
137
+ bytes = IO.read("|convert #{@path} gray:-").unpack 'C*'
138
+ NPatch.new bytes, width, height
139
+ end
116
140
  end
117
141
 
118
- def stretch!(points)
119
- @image = @image.distort(Magick::PerspectiveDistortion, points)
120
- self
142
+ def reg_pixels
143
+ @reg_pixels ||= begin
144
+ bytes = IO.read("|convert #{@path} -distort Perspective '#{perspective_points}' gray:-").unpack 'C*'
145
+ NPatch.new bytes, width, height
146
+ end
121
147
  end
122
148
 
123
- # returns the raw pixels from the entire image or from the area
124
- # defined in opts
125
- def pixels(opts = {})
126
- c = {x: 0, y: 0, w: width, h: height}.merge(opts)
127
- @image.export_pixels(c[:x], c[:y], c[:w], c[:h], "I")
149
+ def perspective_points
150
+ [
151
+ @rm[:tl][:x], @rm[:tl][:y], 0, 0,
152
+ @rm[:tr][:x], @rm[:tr][:y], width, 0,
153
+ @rm[:br][:x], @rm[:br][:y], width, height,
154
+ @rm[:bl][:x], @rm[:bl][:y], 0, height
155
+ ].join ' '
128
156
  end
129
-
130
- def width
131
- @image.columns
157
+
158
+ def join(p)
159
+ @cmd << [:fill, 'none']
160
+ @cmd << [:stroke, 'green']
161
+ @cmd << [:strokewidth, 3]
162
+ pts = [p[0][:x], p[0][:y], p[1][:x], p[1][:y], p[2][:x], p[2][:y], p[3][:x], p[3][:y]].join ' '
163
+ @cmd << [:draw, "polygon #{pts}"]
164
+ end
165
+
166
+ def array_of(cells)
167
+ out = []
168
+ cells.each_with_index do |q, i|
169
+ q.each do |c|
170
+ out << @grom.choice_cell_area(i, c)
171
+ end
172
+ end
173
+ out
132
174
  end
133
-
134
- def height
135
- @image.rows
175
+
176
+ def register
177
+ # find the XY coordinates of the 4 registration marks
178
+ @rm = {} # registration mark centers
179
+ @rmsa = {} # registration mark search area
180
+ @rm[:tl] = reg_centroid_on(:tl)
181
+ @rm[:tr] = reg_centroid_on(:tr)
182
+ @rm[:br] = reg_centroid_on(:br)
183
+ @rm[:bl] = reg_centroid_on(:bl)
184
+ # return the status
185
+ @rm.all? { |k,v| v[:status] == :ok }
136
186
  end
137
187
 
138
- # write the underlying Magick::Image to disk
139
- def write(fname)
140
- @image.write fname
188
+ # returns the centroid of the dark region within the given area
189
+ # in the XY coordinates of the entire image
190
+ def reg_centroid_on(corner)
191
+ 1000.times do |i|
192
+ @rmsa[corner] = @grom.rm_search_area(corner, i)
193
+ cx, cy = raw_pixels.dark_centroid @rmsa[corner]
194
+ if cx.nil?
195
+ status = :insufficient_contrast
196
+ elsif (cx < @grom.rm_edgy_x) or
197
+ (cy < @grom.rm_edgy_y) or
198
+ (cy > @rmsa[corner][:h] - @grom.rm_edgy_y) or
199
+ (cx > @rmsa[corner][:w] - @grom.rm_edgy_x)
200
+ status = :edgy
201
+ else
202
+ return {status: :ok, x: cx + @rmsa[corner][:x], y: cy + @rmsa[corner][:y]}
203
+ end
204
+ return {status: status, x: nil, y: nil} if @rmsa[corner][:w] > @grom.rm_max_search_area_side
205
+ end
141
206
  end
142
207
  end
143
- end
208
+ end
@@ -1,4 +1,4 @@
1
- require 'RMagick'
1
+ # require 'RMagick'
2
2
 
3
3
  module Mork
4
4
  # The class MimageList
data/lib/mork/npatch.rb CHANGED
@@ -1,51 +1,75 @@
1
1
  require 'narray'
2
2
 
3
3
  module Mork
4
- # Handles low-level computations on a Mimage
5
- # Typically used on smaller patches
4
+ # NPatch handles low-level computations on pixels
5
+ # it is basically a wrapper around NArray
6
6
  class NPatch
7
- def initialize(mim)
8
- @mim = mim
9
- @width = mim.width
10
- @height = mim.height
7
+ def initialize(source, width, height)
8
+ @patch = NArray.byte(width, height)
9
+ @patch[true] = case source
10
+ when Array
11
+ source
12
+ when String
13
+ IO.read("|convert #{source} gray:-").unpack 'C*'
14
+ else
15
+ raise 'Invalid NPatch init param'
16
+ end
17
+ @width = width
18
+ @height = height
11
19
  end
12
20
 
13
- def average
14
- narr.mean
21
+ def average(c=nil)
22
+ crop(c).mean
15
23
  end
16
24
 
17
- def dark_centroid
18
- sufficient_contrast? or return
19
- xp = patch.sum(1).to_a
20
- yp = patch.sum(0).to_a
25
+ def length
26
+ @patch.length
27
+ end
28
+
29
+ def dark_centroid(c = nil)
30
+ p = crop c
31
+ sufficient_contrast?(p) or return
32
+ xp = p.sum(1).to_a
33
+ yp = p.sum(0).to_a
21
34
  # find the intensity trough
22
35
  ctr_x = xp.find_index(xp.min)
23
36
  ctr_y = yp.find_index(yp.min)
24
- # return :edgy if edgy?(ctr_x, ctr_y)
25
37
  return ctr_x, ctr_y
26
38
  end
27
39
 
28
- private
29
- def patch
30
- @the_npatch ||= blurry_narr.reshape!(@width, @height)
31
- end
40
+ private
32
41
 
33
- def narr
34
- NArray[@mim.pixels]
42
+ def crop(c)
43
+ c = {x: 0, y: 0, w: @width, h: @height} if c.nil?
44
+ x = c[:x]...c[:x]+c[:w]
45
+ y = c[:y]...c[:y]+c[:h]
46
+ p = NArray.float c[:w], c[:h]
47
+ p[true,true] = @patch[x, y]
48
+ p
35
49
  end
36
50
 
37
- def blurry_narr
38
- @blurry_narr ||= NArray[@mim.blur!(10,5).pixels]
39
- end
40
-
41
- def sufficient_contrast?
42
- # just a wild guess for now
43
- blurry_narr.stddev > 5000
44
- end
45
-
46
- def edgy?(x, y)
47
- tol = 5
48
- (x < tol) or (y < tol) or (y > @height - tol) or (x > @width - tol)
51
+ def sufficient_contrast?(p)
52
+ # tested with the few examples: spec/samples/rm0x.jpeg
53
+ p.stddev > 20
49
54
  end
50
55
  end
51
- end
56
+ end
57
+
58
+
59
+ # def edgy?(x, y)
60
+ # tol = 5
61
+ # (x < tol) or (y < tol) or (y > @height - tol) or (x > @width - tol)
62
+ # end
63
+ #
64
+ # def patch
65
+ # @the_npatch ||= blurry_narr.reshape!(@width, @height)
66
+ # end
67
+ #
68
+ # def narr
69
+ # NArray[@mim.pixels]
70
+ # end
71
+ #
72
+ # def blurry_narr
73
+ # @blurry_narr ||= NArray[@mim.blur!(10,5).pixels]
74
+ # end
75
+ #
@@ -1,28 +1,13 @@
1
1
  require 'mork/grid_omr'
2
2
  require 'mork/mimage'
3
3
  require 'mork/mimage_list'
4
- require 'mork/npatch'
5
4
 
6
5
  module Mork
7
6
  class SheetOMR
8
- def initialize(im, grom=nil)
9
- @raw = case im
10
- when String
11
- Mimage.new im
12
- when Mork::Mimage
13
- im
14
- else
15
- raise "A new sheet requires either a Mimage or the name of the source image file, but it was a: #{im.class}"
16
- end
17
- @grom = case grom
18
- when String, Hash, NilClass
19
- GridOMR.new @raw.width, @raw.height, grom
20
- else
21
- raise 'Invalid argument in SheetOMR initialization'
22
- end
23
- @rm = {}
24
- @rmsa = {}
25
- @ok_reg = register @raw
7
+ def initialize(path, grom=nil)
8
+ @grom = GridOMR.new grom
9
+ @mim = Mimage.new path, @grom
10
+ @ok_reg = @mim.status
26
11
  end
27
12
 
28
13
  def valid?
@@ -53,7 +38,7 @@ module Mork
53
38
  # false otherwise
54
39
  def marked?(q, c)
55
40
  return if not_registered
56
- shade_of(q, c) < choice_threshold
41
+ @mim.shade_of(q, c) < choice_threshold
57
42
  end
58
43
 
59
44
  # TODO: define method ‘mark’ to retrieve the choice array for a single item
@@ -88,65 +73,41 @@ module Mork
88
73
 
89
74
  def outline(cells)
90
75
  return if not_registered
91
- @crop.outline! array_of cells
76
+ raise "Invalid cells’ argument" unless cells.kind_of? Array
77
+ @mim.outline cells
92
78
  end
93
79
 
94
- def highlight_all
80
+ def highlight_marked
95
81
  return if not_registered
96
- cells = (0...@grom.max_questions).collect { |i| (0...@grom.max_choices_per_question).to_a }
97
- @crop.highlight_cells! array_of cells
98
- @crop.highlight_cells! @grom.calibration_cell_areas
99
- @crop.highlight_rect! [@grom.ink_black_area, @grom.paper_white_area]
100
- @crop.highlight_rect! @grom.barcode_bit_areas
82
+ @mim.highlight_cells mark_array
101
83
  end
102
84
 
103
- def highlight_marked
85
+ def highlight_all_choices
104
86
  return if not_registered
105
- @crop.highlight_cells! array_of mark_array
87
+ @mim.highlight_all_choices
106
88
  end
107
89
 
108
90
  def highlight_barcode
109
91
  return if not_registered
110
- @grom.barcode_bits.times do |bit|
111
- if barcode_string.reverse[bit] == '1'
112
- @crop.highlight_rect! @grom.barcode_bit_area bit+1
113
- end
114
- end
92
+ @mim.highlight_barcode barcode_string
115
93
  end
116
94
 
117
- def highlight_reg_area
118
- @raw.highlight_rect! [@rmsa[:tl], @rmsa[:tr], @rmsa[:br], @rmsa[:bl]]
119
- return if not_registered
120
- @raw.join! [@rm[:tl],@rm[:tr],@rm[:br],@rm[:bl]]
95
+ def highlight_registration
96
+ @mim.highlight_reg_area
121
97
  end
122
98
 
123
99
  def write(fname)
124
100
  return if not_registered
125
- @crop.write(fname)
101
+ @mim.write(fname)
126
102
  end
127
103
 
128
104
  def write_raw(fname)
129
- @raw.write(fname)
130
- end
131
-
132
- # =================================
133
- # = compute shading with NPatches =
134
- # =================================
135
- def shade_of(q, c)
136
- naverage @grom.choice_cell_area(q, c)
105
+ @mim.write(fname, false)
137
106
  end
138
107
 
139
- private
140
-
141
- def array_of(cells)
142
- out = []
143
- cells.each_with_index do |q, i|
144
- q.each do |c|
145
- out << @grom.choice_cell_area(i, c)
146
- end
147
- end
148
- out
149
- end
108
+ # ============================================================#
109
+ private #
110
+ # ============================================================#
150
111
 
151
112
  def question_range(r)
152
113
  if r.nil?
@@ -161,82 +122,19 @@ module Mork
161
122
  end
162
123
 
163
124
  def barcode_bit_value(i)
164
- shade_of_barcode_bit(i) < barcode_threshold ? "1" : "0"
125
+ @mim.shade_of_barcode_bit(i) < barcode_threshold ? "1" : "0"
165
126
  end
166
127
 
167
- def shade_of_barcode_bit(i)
168
- naverage @grom.barcode_bit_area i+1
169
- end
170
-
171
128
  def barcode_threshold
172
- @barcode_threshold ||= (paper_white + ink_black) / 2
129
+ @barcode_threshold ||= (@mim.paper_white + ink_black) / 2
173
130
  end
174
131
 
175
132
  def choice_threshold
176
- @choice_threshold ||= (ccmeans.mean - ink_black) * 0.9 + ink_black
177
- end
178
-
179
- def ccmeans
180
- @calcmeans ||= @grom.calibration_cell_areas.collect { |c| naverage c }
181
- end
182
-
183
- def paper_white
184
- @paper_white ||= naverage @grom.paper_white_area
133
+ @choice_threshold ||= (@mim.cal_cell_mean - ink_black) * 0.9 + ink_black
185
134
  end
186
135
 
187
136
  def ink_black
188
- @ink_black ||= naverage @grom.ink_black_area
189
- end
190
-
191
- def shade_of_blank_cells
192
- # @grom.
193
- end
194
-
195
- # ================
196
- # = Registration =
197
- # ================
198
-
199
- # this method uses a 'stretch' strategy, i.e. where the image after
200
- # registration has the same size in pixels as the original scanned file
201
- def register(img)
202
- # find the XY coordinates of the 4 registration marks
203
- @rm[:tl] = reg_centroid_on(img, :tl)
204
- @rm[:tr] = reg_centroid_on(img, :tr)
205
- @rm[:br] = reg_centroid_on(img, :br)
206
- @rm[:bl] = reg_centroid_on(img, :bl)
207
- return false if @rm.any? { |k,v| v[:status] != :ok }
208
- # stretch the 4 points to fit the original size and return the resulting image
209
- @crop = img.stretch [
210
- @rm[:tl][:x], @rm[:tl][:y], 0, 0,
211
- @rm[:tr][:x], @rm[:tr][:y], img.width, 0,
212
- @rm[:br][:x], @rm[:br][:y], img.width, img.height,
213
- @rm[:bl][:x], @rm[:bl][:y], 0, img.height
214
- ]
215
- true
216
- end
217
-
218
- # returns the centroid of the dark region within the given area
219
- # in the XY coordinates of the entire image
220
- def reg_centroid_on(img, corner)
221
- 1000.times do |i|
222
- @rmsa[corner] = @grom.rm_search_area(corner, i)
223
- cx, cy = NPatch.new(img.crop(@rmsa[corner])).dark_centroid
224
- if cx.nil?
225
- status = :insufficient_contrast
226
- elsif (cx < @grom.rm_edgy_x) or
227
- (cy < @grom.rm_edgy_y) or
228
- (cy > @rmsa[corner][:h] - @grom.rm_edgy_y) or
229
- (cx > @rmsa[corner][:w] - @grom.rm_edgy_x)
230
- status = :edgy
231
- else
232
- return {status: :ok, x: cx + @rmsa[corner][:x], y: cy + @rmsa[corner][:y]}
233
- end
234
- return {status: status, x: nil, y: nil} if @rmsa[corner][:w] > @grom.rm_max_search_area_side
235
- end
236
- end
237
-
238
- def naverage(where)
239
- NPatch.new(@crop.crop where).average
137
+ @ink_black ||= @mim.ink_black
240
138
  end
241
139
 
242
140
  def not_registered
data/lib/mork/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Mork
2
- VERSION = "0.1.3"
2
+ VERSION = "0.2.1"
3
3
  end