ocarina 0.0.1

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.
Files changed (153) hide show
  1. data/.gitignore +23 -0
  2. data/Gemfile +4 -0
  3. data/LICENSE +204 -0
  4. data/NOTICE +13 -0
  5. data/README.md +83 -0
  6. data/Rakefile +146 -0
  7. data/data/.gitkeep +0 -0
  8. data/data/images/letterpress/board1.png +0 -0
  9. data/data/images/letterpress/board2.png +0 -0
  10. data/data/images/letterpress/board3.png +0 -0
  11. data/data/images/letterpress/board4.png +0 -0
  12. data/data/images/letterpress/board5.png +0 -0
  13. data/data/images/noise/.gitkeep +0 -0
  14. data/data/images/noise/0.gif +0 -0
  15. data/data/images/noise/1.gif +0 -0
  16. data/data/images/noise/2.gif +0 -0
  17. data/data/images/noise/3.gif +0 -0
  18. data/data/images/noise/4.gif +0 -0
  19. data/data/images/noise/5.gif +0 -0
  20. data/data/images/noise/6.gif +0 -0
  21. data/data/images/noise/7.gif +0 -0
  22. data/data/images/noise/8.gif +0 -0
  23. data/data/images/noise/9.gif +0 -0
  24. data/data/images/noise/A.gif +0 -0
  25. data/data/images/noise/B.gif +0 -0
  26. data/data/images/noise/C.gif +0 -0
  27. data/data/images/noise/D.gif +0 -0
  28. data/data/images/noise/E.gif +0 -0
  29. data/data/images/noise/F.gif +0 -0
  30. data/data/images/noise/G.gif +0 -0
  31. data/data/images/noise/H.gif +0 -0
  32. data/data/images/noise/I.gif +0 -0
  33. data/data/images/noise/J.gif +0 -0
  34. data/data/images/noise/K.gif +0 -0
  35. data/data/images/noise/L.gif +0 -0
  36. data/data/images/noise/M.gif +0 -0
  37. data/data/images/noise/N.gif +0 -0
  38. data/data/images/noise/O.gif +0 -0
  39. data/data/images/noise/P.gif +0 -0
  40. data/data/images/noise/Q.gif +0 -0
  41. data/data/images/noise/R.gif +0 -0
  42. data/data/images/noise/S.gif +0 -0
  43. data/data/images/noise/T.gif +0 -0
  44. data/data/images/noise/U.gif +0 -0
  45. data/data/images/noise/V.gif +0 -0
  46. data/data/images/noise/W.gif +0 -0
  47. data/data/images/noise/X.gif +0 -0
  48. data/data/images/noise/Y.gif +0 -0
  49. data/data/images/noise/Z.gif +0 -0
  50. data/data/images/noise/a_lower.gif +0 -0
  51. data/data/images/noise/b_lower.gif +0 -0
  52. data/data/images/noise/c_lower.gif +0 -0
  53. data/data/images/noise/d_lower.gif +0 -0
  54. data/data/images/noise/e_lower.gif +0 -0
  55. data/data/images/noise/f_lower.gif +0 -0
  56. data/data/images/noise/g_lower.gif +0 -0
  57. data/data/images/noise/h_lower.gif +0 -0
  58. data/data/images/noise/i_lower.gif +0 -0
  59. data/data/images/noise/j_lower.gif +0 -0
  60. data/data/images/noise/k_lower.gif +0 -0
  61. data/data/images/noise/l_lower.gif +0 -0
  62. data/data/images/noise/m_lower.gif +0 -0
  63. data/data/images/noise/n_lower.gif +0 -0
  64. data/data/images/noise/o_lower.gif +0 -0
  65. data/data/images/noise/p_lower.gif +0 -0
  66. data/data/images/noise/q_lower.gif +0 -0
  67. data/data/images/noise/r_lower.gif +0 -0
  68. data/data/images/noise/s_lower.gif +0 -0
  69. data/data/images/noise/t_lower.gif +0 -0
  70. data/data/images/noise/u_lower.gif +0 -0
  71. data/data/images/noise/v_lower.gif +0 -0
  72. data/data/images/noise/w_lower.gif +0 -0
  73. data/data/images/noise/x_lower.gif +0 -0
  74. data/data/images/noise/y_lower.gif +0 -0
  75. data/data/images/noise/z_lower.gif +0 -0
  76. data/data/images/reference/.gitkeep +0 -0
  77. data/data/images/reference/0.gif +0 -0
  78. data/data/images/reference/1.gif +0 -0
  79. data/data/images/reference/2.gif +0 -0
  80. data/data/images/reference/3.gif +0 -0
  81. data/data/images/reference/4.gif +0 -0
  82. data/data/images/reference/5.gif +0 -0
  83. data/data/images/reference/6.gif +0 -0
  84. data/data/images/reference/7.gif +0 -0
  85. data/data/images/reference/8.gif +0 -0
  86. data/data/images/reference/9.gif +0 -0
  87. data/data/images/reference/A.gif +0 -0
  88. data/data/images/reference/B.gif +0 -0
  89. data/data/images/reference/C.gif +0 -0
  90. data/data/images/reference/D.gif +0 -0
  91. data/data/images/reference/E.gif +0 -0
  92. data/data/images/reference/F.gif +0 -0
  93. data/data/images/reference/G.gif +0 -0
  94. data/data/images/reference/H.gif +0 -0
  95. data/data/images/reference/I.gif +0 -0
  96. data/data/images/reference/J.gif +0 -0
  97. data/data/images/reference/K.gif +0 -0
  98. data/data/images/reference/L.gif +0 -0
  99. data/data/images/reference/M.gif +0 -0
  100. data/data/images/reference/N.gif +0 -0
  101. data/data/images/reference/O.gif +0 -0
  102. data/data/images/reference/P.gif +0 -0
  103. data/data/images/reference/Q.gif +0 -0
  104. data/data/images/reference/R.gif +0 -0
  105. data/data/images/reference/S.gif +0 -0
  106. data/data/images/reference/T.gif +0 -0
  107. data/data/images/reference/U.gif +0 -0
  108. data/data/images/reference/V.gif +0 -0
  109. data/data/images/reference/W.gif +0 -0
  110. data/data/images/reference/X.gif +0 -0
  111. data/data/images/reference/Y.gif +0 -0
  112. data/data/images/reference/Z.gif +0 -0
  113. data/data/images/reference/a_lower.gif +0 -0
  114. data/data/images/reference/b_lower.gif +0 -0
  115. data/data/images/reference/c_lower.gif +0 -0
  116. data/data/images/reference/d_lower.gif +0 -0
  117. data/data/images/reference/e_lower.gif +0 -0
  118. data/data/images/reference/f_lower.gif +0 -0
  119. data/data/images/reference/g_lower.gif +0 -0
  120. data/data/images/reference/h_lower.gif +0 -0
  121. data/data/images/reference/i_lower.gif +0 -0
  122. data/data/images/reference/j_lower.gif +0 -0
  123. data/data/images/reference/k_lower.gif +0 -0
  124. data/data/images/reference/l_lower.gif +0 -0
  125. data/data/images/reference/m_lower.gif +0 -0
  126. data/data/images/reference/n_lower.gif +0 -0
  127. data/data/images/reference/o_lower.gif +0 -0
  128. data/data/images/reference/p_lower.gif +0 -0
  129. data/data/images/reference/q_lower.gif +0 -0
  130. data/data/images/reference/r_lower.gif +0 -0
  131. data/data/images/reference/s_lower.gif +0 -0
  132. data/data/images/reference/t_lower.gif +0 -0
  133. data/data/images/reference/u_lower.gif +0 -0
  134. data/data/images/reference/v_lower.gif +0 -0
  135. data/data/images/reference/w_lower.gif +0 -0
  136. data/data/images/reference/x_lower.gif +0 -0
  137. data/data/images/reference/y_lower.gif +0 -0
  138. data/data/images/reference/z_lower.gif +0 -0
  139. data/data/letterpress-train.bin +0 -0
  140. data/data/train.bin +0 -0
  141. data/lib/ocarina.rb +12 -0
  142. data/lib/ocarina/character_generator.rb +87 -0
  143. data/lib/ocarina/config.rb +35 -0
  144. data/lib/ocarina/error_stats.rb +62 -0
  145. data/lib/ocarina/letterpress_character_generator.rb +93 -0
  146. data/lib/ocarina/letterpress_cropper.rb +84 -0
  147. data/lib/ocarina/network.rb +264 -0
  148. data/lib/ocarina/util.rb +92 -0
  149. data/lib/ocarina/version.rb +3 -0
  150. data/ocarina.gemspec +20 -0
  151. data/ocarina.png +0 -0
  152. data/test/test_letterpress.rb +60 -0
  153. metadata +231 -0
@@ -0,0 +1,92 @@
1
+ require 'RMagick'
2
+
3
+ module Ocarina
4
+
5
+ DATA_DIR = "#{File.dirname(__FILE__)}/../../data"
6
+ IMAGES_DIR = "#{DATA_DIR}/images"
7
+
8
+ module Util
9
+
10
+ def int_to_binary_string(i)
11
+ i.to_s(2).rjust(config.num_outputs, '0')
12
+ end
13
+
14
+ def char_to_binary_string(target_char)
15
+ int_to_binary_string target_char.ord
16
+ end
17
+
18
+ # function that maps its input to a range between 0..1
19
+ # mathematically it's supposed to be asymptotic, but large values of x will round up to 1
20
+ def sigma(x)
21
+ 1.0/(1.0+Math.exp(-x))
22
+ end
23
+
24
+ def pixel_number_to_col(n, image)
25
+ n % image.columns
26
+ end
27
+
28
+ def pixel_number_to_row(n, image)
29
+ n / image.columns
30
+ end
31
+
32
+ def pixel_to_bit(pixel)
33
+ pixel.red | pixel.green | pixel.black > 0 ? 1 : 0
34
+ end
35
+
36
+
37
+ # returns a Magick::Image, constructed from the reference gif file for the given character
38
+ #
39
+ def reference_image_for_char(char)
40
+ Magick::Image.read(filename_for_training_image char, "gif").first
41
+ end
42
+
43
+ # returns a Magick::Image, constructed from the noise gif file for the given character
44
+ #
45
+ def noise_image_for_char(char)
46
+ Magick::Image.read(filename_for_noise_image char, "gif").first
47
+ end
48
+
49
+ # returns filepath for the image for a given character
50
+ #
51
+ def filename_for_training_image(c, suffix)
52
+
53
+ # the default OSX file system is case preserving, meaning that you cannot have
54
+ # both "A.bitmap" and "a.bitmap" at the same time. So we map lowercase letters to
55
+ # a special name.
56
+ #
57
+ is_lower?(c) ? "#{IMAGES_DIR}/reference/#{c}_lower.#{suffix}" : "#{IMAGES_DIR}/reference/#{c}.#{suffix}"
58
+ end
59
+
60
+ # returns filepath for the "noise" image for a given character
61
+ #
62
+ def filename_for_noise_image(c, suffix)
63
+
64
+ # the default OSX file system is case preserving, meaning that you cannot have
65
+ # both "A.bitmap" and "a.bitmap" at the same time. So we map lowercase letters to
66
+ # a special name.
67
+ #
68
+ is_lower?(c) ? "#{IMAGES_DIR}/noise/#{c}_lower.#{suffix}" : "#{IMAGES_DIR}/noise/#{c}.#{suffix}"
69
+ end
70
+
71
+ def filename_for_quantized_image(c, suffix)
72
+
73
+ is_lower?(c) ? "#{IMAGES_DIR}/quantized/#{c}_lower.#{suffix}" : "#{IMAGES_DIR}/quantized/#{c}.#{suffix}"
74
+ end
75
+
76
+ # kind of sad that this is not built into Ruby
77
+ def is_lower?(c)
78
+ !! /[[:lower:]]/.match(c)
79
+ end
80
+
81
+ def is_upper?(c)
82
+ !! /[[:upper:]]/.match(c)
83
+ end
84
+
85
+ def quantize_image(image)
86
+ image.white_threshold(Magick::MaxRGB * 0.35).quantize(2, Magick::GRAYColorspace)
87
+ end
88
+
89
+ end
90
+
91
+ end
92
+
@@ -0,0 +1,3 @@
1
+ module Ocarina
2
+ VERSION = "0.0.1"
3
+ end
data/ocarina.gemspec ADDED
@@ -0,0 +1,20 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require File.expand_path('../lib/ocarina/version', __FILE__)
3
+
4
+ Gem::Specification.new do |gem|
5
+ gem.authors = ["George Armhold"]
6
+ gem.email = ["armhold@gmail.com"]
7
+ gem.description = %q{A Ruby project that uses machine learning to perform Optical Character Recognition}
8
+ gem.summary = %q{A Ruby project that uses machine learning to perform Optical Character Recognition}
9
+ gem.homepage = "https://github.com/armhold/ocarina"
10
+
11
+ gem.files = `git ls-files`.split($\)
12
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
13
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
14
+ gem.name = "ocarina"
15
+ gem.require_paths = ["lib"]
16
+ gem.version = Ocarina::VERSION
17
+
18
+ gem.add_runtime_dependency 'rmagick'
19
+ gem.add_runtime_dependency 'powerbar'
20
+ end
data/ocarina.png ADDED
Binary file
@@ -0,0 +1,60 @@
1
+ require 'test/unit'
2
+ require 'ocarina'
3
+
4
+ class LetterpressTest < Test::Unit::TestCase
5
+
6
+
7
+ def setup
8
+ @network = Ocarina::Network.load_network_from_file "#{Ocarina::DATA_DIR}/letterpress-train.bin"
9
+ @cropper = Ocarina::LetterpressCropper.new(@network.config)
10
+ end
11
+
12
+ def test_boards
13
+
14
+ assert_equal [
15
+ %w(P R B R Z),
16
+ %w(T A V Z R),
17
+ %w(B D A K Y),
18
+ %w(G I G K F),
19
+ %w(R Y S J V)
20
+ ], @cropper.decipher_board(@network, read_board("board1.png"))
21
+
22
+ assert_equal [
23
+ %w(Q D F P M),
24
+ %w(N E E S I),
25
+ %w(A W F M L),
26
+ %w(F R P T T),
27
+ %w(K C S S Y)
28
+ ], @cropper.decipher_board(@network, read_board("board2.png"))
29
+
30
+ assert_equal [
31
+ %w(L H F L M),
32
+ %w(R V P U K),
33
+ %w(V O E E X),
34
+ %w(I N R I T),
35
+ %w(V N S I Q)
36
+ ], @cropper.decipher_board(@network, read_board("board3.png"))
37
+
38
+ assert_equal [
39
+ %w(C U H S Z),
40
+ %w(N T V K I),
41
+ %w(E X K O S),
42
+ %w(B C U P N),
43
+ %w(W E E V E)
44
+ ], @cropper.decipher_board(@network, read_board("board4.png"))
45
+
46
+ assert_equal [
47
+ %w(C Y M T I),
48
+ %w(P Z Y L Y),
49
+ %w(D W O H S),
50
+ %w(D W H A S),
51
+ %w(O Z X G K)
52
+ ], @cropper.decipher_board(@network, read_board("board5.png"))
53
+ end
54
+
55
+ def read_board(file)
56
+ Magick::Image.read("#{Ocarina::DATA_DIR}/images/letterpress/#{file}").first
57
+ end
58
+
59
+
60
+ end
metadata ADDED
@@ -0,0 +1,231 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ocarina
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - George Armhold
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-11-01 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rmagick
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: '0'
30
+ - !ruby/object:Gem::Dependency
31
+ name: powerbar
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ! '>='
36
+ - !ruby/object:Gem::Version
37
+ version: '0'
38
+ type: :runtime
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: '0'
46
+ description: A Ruby project that uses machine learning to perform Optical Character
47
+ Recognition
48
+ email:
49
+ - armhold@gmail.com
50
+ executables: []
51
+ extensions: []
52
+ extra_rdoc_files: []
53
+ files:
54
+ - .gitignore
55
+ - Gemfile
56
+ - LICENSE
57
+ - NOTICE
58
+ - README.md
59
+ - Rakefile
60
+ - data/.gitkeep
61
+ - data/images/letterpress/board1.png
62
+ - data/images/letterpress/board2.png
63
+ - data/images/letterpress/board3.png
64
+ - data/images/letterpress/board4.png
65
+ - data/images/letterpress/board5.png
66
+ - data/images/noise/.gitkeep
67
+ - data/images/noise/0.gif
68
+ - data/images/noise/1.gif
69
+ - data/images/noise/2.gif
70
+ - data/images/noise/3.gif
71
+ - data/images/noise/4.gif
72
+ - data/images/noise/5.gif
73
+ - data/images/noise/6.gif
74
+ - data/images/noise/7.gif
75
+ - data/images/noise/8.gif
76
+ - data/images/noise/9.gif
77
+ - data/images/noise/A.gif
78
+ - data/images/noise/B.gif
79
+ - data/images/noise/C.gif
80
+ - data/images/noise/D.gif
81
+ - data/images/noise/E.gif
82
+ - data/images/noise/F.gif
83
+ - data/images/noise/G.gif
84
+ - data/images/noise/H.gif
85
+ - data/images/noise/I.gif
86
+ - data/images/noise/J.gif
87
+ - data/images/noise/K.gif
88
+ - data/images/noise/L.gif
89
+ - data/images/noise/M.gif
90
+ - data/images/noise/N.gif
91
+ - data/images/noise/O.gif
92
+ - data/images/noise/P.gif
93
+ - data/images/noise/Q.gif
94
+ - data/images/noise/R.gif
95
+ - data/images/noise/S.gif
96
+ - data/images/noise/T.gif
97
+ - data/images/noise/U.gif
98
+ - data/images/noise/V.gif
99
+ - data/images/noise/W.gif
100
+ - data/images/noise/X.gif
101
+ - data/images/noise/Y.gif
102
+ - data/images/noise/Z.gif
103
+ - data/images/noise/a_lower.gif
104
+ - data/images/noise/b_lower.gif
105
+ - data/images/noise/c_lower.gif
106
+ - data/images/noise/d_lower.gif
107
+ - data/images/noise/e_lower.gif
108
+ - data/images/noise/f_lower.gif
109
+ - data/images/noise/g_lower.gif
110
+ - data/images/noise/h_lower.gif
111
+ - data/images/noise/i_lower.gif
112
+ - data/images/noise/j_lower.gif
113
+ - data/images/noise/k_lower.gif
114
+ - data/images/noise/l_lower.gif
115
+ - data/images/noise/m_lower.gif
116
+ - data/images/noise/n_lower.gif
117
+ - data/images/noise/o_lower.gif
118
+ - data/images/noise/p_lower.gif
119
+ - data/images/noise/q_lower.gif
120
+ - data/images/noise/r_lower.gif
121
+ - data/images/noise/s_lower.gif
122
+ - data/images/noise/t_lower.gif
123
+ - data/images/noise/u_lower.gif
124
+ - data/images/noise/v_lower.gif
125
+ - data/images/noise/w_lower.gif
126
+ - data/images/noise/x_lower.gif
127
+ - data/images/noise/y_lower.gif
128
+ - data/images/noise/z_lower.gif
129
+ - data/images/reference/.gitkeep
130
+ - data/images/reference/0.gif
131
+ - data/images/reference/1.gif
132
+ - data/images/reference/2.gif
133
+ - data/images/reference/3.gif
134
+ - data/images/reference/4.gif
135
+ - data/images/reference/5.gif
136
+ - data/images/reference/6.gif
137
+ - data/images/reference/7.gif
138
+ - data/images/reference/8.gif
139
+ - data/images/reference/9.gif
140
+ - data/images/reference/A.gif
141
+ - data/images/reference/B.gif
142
+ - data/images/reference/C.gif
143
+ - data/images/reference/D.gif
144
+ - data/images/reference/E.gif
145
+ - data/images/reference/F.gif
146
+ - data/images/reference/G.gif
147
+ - data/images/reference/H.gif
148
+ - data/images/reference/I.gif
149
+ - data/images/reference/J.gif
150
+ - data/images/reference/K.gif
151
+ - data/images/reference/L.gif
152
+ - data/images/reference/M.gif
153
+ - data/images/reference/N.gif
154
+ - data/images/reference/O.gif
155
+ - data/images/reference/P.gif
156
+ - data/images/reference/Q.gif
157
+ - data/images/reference/R.gif
158
+ - data/images/reference/S.gif
159
+ - data/images/reference/T.gif
160
+ - data/images/reference/U.gif
161
+ - data/images/reference/V.gif
162
+ - data/images/reference/W.gif
163
+ - data/images/reference/X.gif
164
+ - data/images/reference/Y.gif
165
+ - data/images/reference/Z.gif
166
+ - data/images/reference/a_lower.gif
167
+ - data/images/reference/b_lower.gif
168
+ - data/images/reference/c_lower.gif
169
+ - data/images/reference/d_lower.gif
170
+ - data/images/reference/e_lower.gif
171
+ - data/images/reference/f_lower.gif
172
+ - data/images/reference/g_lower.gif
173
+ - data/images/reference/h_lower.gif
174
+ - data/images/reference/i_lower.gif
175
+ - data/images/reference/j_lower.gif
176
+ - data/images/reference/k_lower.gif
177
+ - data/images/reference/l_lower.gif
178
+ - data/images/reference/m_lower.gif
179
+ - data/images/reference/n_lower.gif
180
+ - data/images/reference/o_lower.gif
181
+ - data/images/reference/p_lower.gif
182
+ - data/images/reference/q_lower.gif
183
+ - data/images/reference/r_lower.gif
184
+ - data/images/reference/s_lower.gif
185
+ - data/images/reference/t_lower.gif
186
+ - data/images/reference/u_lower.gif
187
+ - data/images/reference/v_lower.gif
188
+ - data/images/reference/w_lower.gif
189
+ - data/images/reference/x_lower.gif
190
+ - data/images/reference/y_lower.gif
191
+ - data/images/reference/z_lower.gif
192
+ - data/letterpress-train.bin
193
+ - data/train.bin
194
+ - lib/ocarina.rb
195
+ - lib/ocarina/character_generator.rb
196
+ - lib/ocarina/config.rb
197
+ - lib/ocarina/error_stats.rb
198
+ - lib/ocarina/letterpress_character_generator.rb
199
+ - lib/ocarina/letterpress_cropper.rb
200
+ - lib/ocarina/network.rb
201
+ - lib/ocarina/util.rb
202
+ - lib/ocarina/version.rb
203
+ - ocarina.gemspec
204
+ - ocarina.png
205
+ - test/test_letterpress.rb
206
+ homepage: https://github.com/armhold/ocarina
207
+ licenses: []
208
+ post_install_message:
209
+ rdoc_options: []
210
+ require_paths:
211
+ - lib
212
+ required_ruby_version: !ruby/object:Gem::Requirement
213
+ none: false
214
+ requirements:
215
+ - - ! '>='
216
+ - !ruby/object:Gem::Version
217
+ version: '0'
218
+ required_rubygems_version: !ruby/object:Gem::Requirement
219
+ none: false
220
+ requirements:
221
+ - - ! '>='
222
+ - !ruby/object:Gem::Version
223
+ version: '0'
224
+ requirements: []
225
+ rubyforge_project:
226
+ rubygems_version: 1.8.24
227
+ signing_key:
228
+ specification_version: 3
229
+ summary: A Ruby project that uses machine learning to perform Optical Character Recognition
230
+ test_files:
231
+ - test/test_letterpress.rb