kvg_character_recognition 0.1.0 → 0.1.2
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 +4 -4
- data/Gemfile +0 -3
- data/README.md +13 -10
- data/kvg_character_recognition.gemspec +3 -3
- data/lib/kvg_character_recognition.rb +0 -19
- data/lib/kvg_character_recognition/datastore.rb +35 -0
- data/lib/kvg_character_recognition/preprocessor.rb +1 -12
- data/lib/kvg_character_recognition/recognizer.rb +22 -16
- data/lib/kvg_character_recognition/{database.rb → trainer.rb} +10 -45
- data/lib/kvg_character_recognition/utils.rb +14 -0
- data/lib/kvg_character_recognition/version.rb +1 -1
- metadata +20 -19
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2f5bd00df050f48f3ee955daaa966fd04b10a5f3
|
4
|
+
data.tar.gz: bb45a8db8023fb37f4f929a673f1f811756540fa
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ae3a13b9370276c1714f19acebcf856cff091c27725514ae8f0a75f43ef754576d46bc69b7804d1203db5216524d0841e82b2deac7f29729ad5ebfe55441d080
|
7
|
+
data.tar.gz: 057e9896548709b6fd4187ffcf8d576b2d49fa0fb19f6b1cc3909e75befde49149aa934d54ea9c6bbab48d394f4fdf708404287ec6eae6857dab3b53b7a09650
|
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -4,21 +4,27 @@ A stroke is an array of points in the format [[x1, y1], [x2, y2], ...].
|
|
4
4
|
For templates, we use svg data from the [KanjiVG project](http://kanjivg.tagaini.net/)
|
5
5
|
|
6
6
|
The engine takes 3 steps to perform the recognition of an input pattern.
|
7
|
+
|
7
8
|
1. Preprocessing
|
9
|
+
|
8
10
|
The preprocessing step consists of smoothing, normalizing, interpolating and downsampling of the data points.
|
11
|
+
|
9
12
|
2. Feature Extraction
|
13
|
+
|
10
14
|
Smoothed heatmap, significant points and directional feature densities are used as features.
|
11
15
|
A heatmap divides the input pattern in small grids and stores the number of data points in each grid.
|
12
16
|
Significant points are defined as start and end point of a stroke, points on curve or edge.
|
13
17
|
Directional feature densities are introduced in the paper "On-line Recognition of Freely Handwritten Japanese Character Using Directional Feature Density"
|
18
|
+
|
14
19
|
3. Matching
|
20
|
+
|
15
21
|
We use the significant points to perform a coarse recognition of the input pattern, that filters out template patterns with great distance to the input pattern. Next, a mixed distance score of directional feature density and smoothed heatmap is calculated.
|
16
22
|
## Installation
|
17
23
|
|
18
24
|
Add this line to your application's Gemfile:
|
19
25
|
|
20
26
|
```ruby
|
21
|
-
gem 'kvg_character_recognition'
|
27
|
+
gem 'kvg_character_recognition', '~>0.1.1'
|
22
28
|
```
|
23
29
|
|
24
30
|
And then execute:
|
@@ -31,15 +37,14 @@ Or install it yourself as:
|
|
31
37
|
|
32
38
|
## Usage
|
33
39
|
|
34
|
-
1.
|
35
|
-
|
36
|
-
2. Setup the characters table in the database and populate it with kanjivg templates from the [xml release](https://github.com/KanjiVG/kanjivg/releases)
|
40
|
+
1. Setup a json datastore and populate it with kanjivg templates from the [xml release](https://github.com/KanjiVG/kanjivg/releases)
|
37
41
|
```ruby
|
38
42
|
require 'kvg_character_recognition'
|
39
43
|
|
40
|
-
KvgCharacterRecognition::
|
44
|
+
datastore = KvgCharacterRecognition::JSONDatastore.new("characters.json")
|
45
|
+
#ignore the warning
|
41
46
|
|
42
|
-
KvgCharacterRecognition::
|
47
|
+
KvgCharacterRecognition::Trainer.populate_from_xml "kanjivg-20150615-2.xml", datastore
|
43
48
|
```
|
44
49
|
|
45
50
|
3. Recognition
|
@@ -48,7 +53,8 @@ Use an input field of size 300x300 for the best recognition accuracy. The input
|
|
48
53
|
```ruby
|
49
54
|
strokes = [[[99.0, 108.0], [100.0, 108.0], [101.0, 108.0], [101.0, 108.0], [103.0, 108.0], [105.0, 107.0], [107.0, 107.0], [108.0, 107.0], [111.0, 106.0], [111.0, 106.0], [112.0, 106.0], [113.0, 106.0], [114.0, 106.0], [115.0, 105.0], [116.0, 105.0], [118.0, 105.0], [120.0, 105.0], [121.0, 104.0], [122.0, 104.0], [122.0, 104.0], [123.0, 104.0], [124.0, 103.0], [125.0, 103.0], [126.0, 103.0], [127.0, 103.0], [129.0, 102.0], [130.0, 102.0], [132.0, 102.0], [132.0, 101.0], [133.0, 101.0], [135.0, 101.0], [136.0, 101.0], [137.0, 101.0], [138.0, 101.0], [140.0, 101.0], [141.0, 100.0], [142.0, 100.0], [143.0, 100.0], [144.0, 100.0], [145.0, 99.0], [148.0, 99.0], [150.0, 99.0], [151.0, 98.0], [152.0, 98.0], [153.0, 98.0], [154.0, 98.0], [156.0, 97.0], [157.0, 97.0], [158.0, 97.0], [159.0, 97.0], [161.0, 97.0], [162.0, 96.0], [162.0, 96.0], [164.0, 96.0], [165.0, 96.0], [166.0, 96.0], [167.0, 96.0], [169.0, 95.0], [170.0, 95.0], [171.0, 95.0], [172.0, 95.0], [173.0, 95.0], [174.0, 95.0]], [[53.0, 190.0], [54.0, 190.0], [56.0, 190.0], [57.0, 190.0], [59.0, 190.0], [61.0, 190.0], [63.0, 189.0], [66.0, 189.0], [67.0, 189.0], [68.0, 189.0], [69.0, 189.0], [71.0, 189.0], [72.0, 188.0], [72.0, 188.0], [74.0, 188.0], [76.0, 187.0], [78.0, 187.0], [80.0, 187.0], [81.0, 187.0], [82.0, 186.0], [84.0, 186.0], [87.0, 186.0], [89.0, 185.0], [91.0, 185.0], [93.0, 185.0], [95.0, 184.0], [98.0, 184.0], [100.0, 183.0], [102.0, 183.0], [104.0, 183.0], [106.0, 183.0], [110.0, 182.0], [111.0, 182.0], [112.0, 182.0], [115.0, 182.0], [118.0, 182.0], [120.0, 182.0], [122.0, 182.0], [125.0, 182.0], [128.0, 181.0], [130.0, 181.0], [133.0, 180.0], [136.0, 180.0], [141.0, 180.0], [143.0, 179.0], [146.0, 179.0], [150.0, 179.0], [152.0, 178.0], [155.0, 178.0], [158.0, 178.0], [159.0, 178.0], [162.0, 177.0], [164.0, 177.0], [167.0, 177.0], [170.0, 177.0], [173.0, 176.0], [176.0, 176.0], [179.0, 176.0], [182.0, 175.0], [187.0, 175.0], [189.0, 174.0], [192.0, 174.0], [194.0, 174.0], [196.0, 173.0], [199.0, 173.0], [202.0, 173.0], [204.0, 172.0], [206.0, 172.0], [209.0, 172.0], [211.0, 172.0], [212.0, 172.0], [215.0, 172.0], [217.0, 172.0], [219.0, 171.0], [221.0, 171.0], [221.0, 172.0]]]
|
50
55
|
|
51
|
-
|
56
|
+
datastore = KvgCharacterRecognition::JSONDatastore.new("characters.json") #this will initialize datastore once for the entire usage
|
57
|
+
scores = KvgCharacterRecognition::Recognizer.scores strokes, datastore
|
52
58
|
|
53
59
|
irb(main):004:0> scores.take 10
|
54
60
|
=> [[1.524079282599697, 60, "二"], [2.8346163809971143, 1373, "工"], [3.0987422100694757, 7, "上"], [3.127346308294038, 365, "冫"], [3.439293212191952, 6, "三"], [3.4890481845638304, 3770, "立"], [3.541524904953307, 2721, "江"], [3.641178875851016, 569, "厂"], [3.6447144433336294, 72, "亠"], [3.7498483818966353, 2706, "氵"]]
|
@@ -73,9 +79,6 @@ Don't forget to redo the whole database step after changing the configuration.
|
|
73
79
|
#from yaml file
|
74
80
|
Kvgcharacterrecognition.configure_with(path_to_yml)
|
75
81
|
|
76
|
-
#configure database with yml
|
77
|
-
#TODO why is postgres slower than sqlite?
|
78
|
-
Kvgcharacterrecognition.configure_database(path_to_yml)
|
79
82
|
```
|
80
83
|
|
81
84
|
|
@@ -26,15 +26,15 @@ Gem::Specification.new do |spec|
|
|
26
26
|
raise "RubyGems 2.0 or newer is required to protect against public gem pushes."
|
27
27
|
end
|
28
28
|
|
29
|
-
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
29
|
+
spec.files = `git ls-files -z`.split("\x0").reject { |f| f == 'kvg_character_recognition-0.1.1.gem' || f.match(%r{^(test|spec|features)/}) }
|
30
30
|
spec.bindir = "exe"
|
31
31
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
32
32
|
spec.require_paths = ["lib"]
|
33
33
|
|
34
|
+
spec.add_dependency "parallel"
|
34
35
|
spec.add_dependency "nokogiri"
|
35
|
-
spec.add_dependency "sequel"
|
36
|
-
spec.add_dependency "sqlite3"
|
37
36
|
spec.add_dependency "bundler", "~> 1.10"
|
38
37
|
spec.add_development_dependency "rake", "~> 10.0"
|
39
38
|
spec.add_development_dependency "rspec"
|
39
|
+
spec.add_development_dependency "pry"
|
40
40
|
end
|
@@ -6,7 +6,6 @@ Dir[File.join(File.dirname(__FILE__), '/kvg_character_recognition/*.rb')].each {
|
|
6
6
|
|
7
7
|
module KvgCharacterRecognition
|
8
8
|
|
9
|
-
@db = Sequel.connect('sqlite://characters.db')
|
10
9
|
CONFIG = {
|
11
10
|
size: 109, #fixed canvas size of kanjivg data
|
12
11
|
downsample_interval: 4,
|
@@ -34,22 +33,4 @@ module KvgCharacterRecognition
|
|
34
33
|
|
35
34
|
configure(config)
|
36
35
|
end
|
37
|
-
|
38
|
-
#Configure database
|
39
|
-
def self.configure_database(yml)
|
40
|
-
begin
|
41
|
-
db_config = YAML::load(IO.read(yml))
|
42
|
-
rescue Errno::ENOENT
|
43
|
-
log(:warning, "YAML configuration file couldn't be found. Using defaults."); return
|
44
|
-
rescue Psych::SyntaxError
|
45
|
-
log(:warning, "YAML configuration file contains invalid syntax. Using defaults."); return
|
46
|
-
end
|
47
|
-
@db = Sequel.connect(yml)
|
48
|
-
end
|
49
|
-
|
50
|
-
#getter
|
51
|
-
def self.db
|
52
|
-
@db
|
53
|
-
end
|
54
|
-
|
55
36
|
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'json'
|
2
|
+
|
3
|
+
module KvgCharacterRecognition
|
4
|
+
class JSONDatastore
|
5
|
+
def initialize filename = 'characters.json'
|
6
|
+
@data = load_file(filename)
|
7
|
+
@filename = filename
|
8
|
+
end
|
9
|
+
|
10
|
+
def load_file filename
|
11
|
+
begin
|
12
|
+
JSON.parse(File.read(filename, encoding: 'utf-8'), symbolize_names: true)
|
13
|
+
rescue
|
14
|
+
puts "WARNING: Can't load file, returning empty character collection."
|
15
|
+
[]
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def characters_in_stroke_range range
|
20
|
+
@data.select { |character| range === character[:number_of_strokes] }
|
21
|
+
end
|
22
|
+
|
23
|
+
def store character
|
24
|
+
@data.push character
|
25
|
+
end
|
26
|
+
|
27
|
+
def persist!
|
28
|
+
dump @filename
|
29
|
+
end
|
30
|
+
|
31
|
+
def dump filename
|
32
|
+
File.write(filename, @data.to_json)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -148,17 +148,6 @@ module KvgCharacterRecognition
|
|
148
148
|
points
|
149
149
|
end
|
150
150
|
|
151
|
-
#This methods calculates the euclidean distance between 2 points
|
152
|
-
#Params:
|
153
|
-
#- p1, p2: [x, y]
|
154
|
-
def self.euclidean_distance(p1, p2)
|
155
|
-
sum_of_squares = 0
|
156
|
-
p1.each_with_index do |p1_coord,index|
|
157
|
-
sum_of_squares += (p1_coord - p2[index]) ** 2
|
158
|
-
end
|
159
|
-
Math.sqrt( sum_of_squares )
|
160
|
-
end
|
161
|
-
|
162
151
|
#This method interpolates points into a stroke with given distance
|
163
152
|
#The algorithm is taken from the paper preprocessing techniques for online character recognition
|
164
153
|
def self.interpolate stroke, d=0.5
|
@@ -171,7 +160,7 @@ module KvgCharacterRecognition
|
|
171
160
|
point = stroke[index]
|
172
161
|
|
173
162
|
#only consider point with greater than d distance to current point
|
174
|
-
if euclidean_distance(current, point) < d
|
163
|
+
if Math.euclidean_distance(current, point) < d
|
175
164
|
index += 1
|
176
165
|
else
|
177
166
|
|
@@ -1,27 +1,32 @@
|
|
1
1
|
require 'matrix'
|
2
|
+
require 'parallel'
|
2
3
|
module KvgCharacterRecognition
|
3
4
|
#This class contains methods calculating similarity scores between input pattern and template patterns
|
4
|
-
|
5
|
+
module Recognizer
|
6
|
+
@thread_count = 10
|
5
7
|
|
6
8
|
#This method selects all templates from the database which should be further examined
|
7
9
|
#It filtered out those characters with a too great difference in number of strokes to the input character
|
8
|
-
def self.select_templates strokes
|
10
|
+
def self.select_templates strokes, datastore
|
9
11
|
min = strokes.count <= 5 ? strokes.count : strokes.count - 5
|
10
12
|
max = strokes.count + 10
|
11
|
-
|
13
|
+
datastore.characters_in_stroke_range(min..max)
|
12
14
|
end
|
13
15
|
|
14
16
|
#This method uses heatmap of significant points to coarse recognize the input pattern
|
15
17
|
#Params:
|
16
18
|
#+strokes+:: strokes should be preprocessed
|
17
|
-
|
19
|
+
#+datastore+:: JSONDatastore or custom datastore type having method characters_in_stroke_range(min..max)
|
20
|
+
def self.coarse_recognize strokes, datastore
|
18
21
|
heatmap = FeatureExtractor.heatmap(Preprocessor.significant_points(strokes), CONFIG[:significant_points_heatmap_grid], CONFIG[:size]).to_a
|
19
22
|
|
20
|
-
templates = select_templates strokes
|
21
|
-
|
23
|
+
templates = select_templates strokes, datastore
|
24
|
+
|
25
|
+
# Use threads to accelerate the process
|
26
|
+
Parallel.map(templates, in_threads: @thread_count) do |candidate|
|
22
27
|
candidate_heatmap = candidate[:heatmap_significant_points].split(",").map(&:to_f)
|
23
28
|
|
24
|
-
score =
|
29
|
+
score = Math.euclidean_distance(heatmap, candidate_heatmap)
|
25
30
|
[score.round(3), candidate]
|
26
31
|
end
|
27
32
|
end
|
@@ -31,7 +36,8 @@ module KvgCharacterRecognition
|
|
31
36
|
#2. euclidean distance of directional feature densities in average
|
32
37
|
#Params:
|
33
38
|
#+strokes+:: strokes are not preprocessed
|
34
|
-
|
39
|
+
#+datastore+:: JSONDatastore or custom datastore type having method characters_in_stroke_range(min..max)
|
40
|
+
def self.scores strokes, datastore
|
35
41
|
#preprocess strokes
|
36
42
|
#with smoothing
|
37
43
|
strokes = Preprocessor.preprocess(strokes, CONFIG[:interpolate_distance], CONFIG[:downsample_interval], true)
|
@@ -42,18 +48,18 @@ module KvgCharacterRecognition
|
|
42
48
|
|
43
49
|
#dump half of the templates after coarse recognition
|
44
50
|
#collection is in the form [[score, c1], [score, c2] ...]
|
45
|
-
collection = coarse_recognize(strokes).sort{ |a, b| a[0] <=> b[0] }
|
51
|
+
collection = coarse_recognize(strokes, datastore).sort{ |a, b| a[0] <=> b[0] }
|
46
52
|
|
47
|
-
scores = collection.take(collection.count / 2)
|
48
|
-
direction_score = (
|
49
|
-
|
50
|
-
|
51
|
-
|
53
|
+
scores = Parallel.map(collection.take(collection.count / 2)) do |cand|
|
54
|
+
direction_score = (Math.euclidean_distance(directions[0], cand[1][:direction_e1].split(",").map(&:to_f)) +
|
55
|
+
Math.euclidean_distance(directions[1], cand[1][:direction_e2].split(",").map(&:to_f)) +
|
56
|
+
Math.euclidean_distance(directions[2], cand[1][:direction_e3].split(",").map(&:to_f)) +
|
57
|
+
Math.euclidean_distance(directions[3], cand[1][:direction_e4].split(",").map(&:to_f)) ) / 4
|
52
58
|
|
53
|
-
heatmap_score =
|
59
|
+
heatmap_score = Math.euclidean_distance(heatmap_smoothed, cand[1][:heatmap_smoothed].split(",").map(&:to_f))
|
54
60
|
|
55
61
|
mix = (direction_score / 100) + heatmap_score
|
56
|
-
[mix/2, cand[1]
|
62
|
+
[mix/2, cand[1]]
|
57
63
|
end
|
58
64
|
|
59
65
|
scores.sort{ |a, b| a[0] <=> b[0] }
|
@@ -1,49 +1,10 @@
|
|
1
|
-
require 'matrix'
|
2
|
-
require 'nokogiri'
|
3
|
-
|
4
1
|
module KvgCharacterRecognition
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
#This method creates a database table for storing the extracted features of the templates
|
9
|
-
#Arrays of points will be serialized and stored as string
|
10
|
-
#Following fields are created:
|
11
|
-
# - primary_key :id
|
12
|
-
# - String :value
|
13
|
-
# - Integer :codepoint
|
14
|
-
# - String :serialized_strokes i.e. [stroke, x, y]
|
15
|
-
# - String :direction_e1
|
16
|
-
# - String :direction_e2
|
17
|
-
# - String :direction_e3
|
18
|
-
# - String :direction_e4
|
19
|
-
# - String :heatmap_smoothed
|
20
|
-
# - String :heatmap_significant_points
|
21
|
-
def self.setup
|
22
|
-
KvgCharacterRecognition.db.create_table :characters do
|
23
|
-
primary_key :id
|
24
|
-
String :value
|
25
|
-
Integer :codepoint
|
26
|
-
Integer :number_of_strokes
|
27
|
-
String :serialized_strokes
|
28
|
-
String :direction_e1
|
29
|
-
String :direction_e2
|
30
|
-
String :direction_e3
|
31
|
-
String :direction_e4
|
32
|
-
String :heatmap_smoothed
|
33
|
-
String :heatmap_significant_points
|
34
|
-
end
|
35
|
-
|
36
|
-
end
|
37
|
-
|
38
|
-
#Drop created table
|
39
|
-
def self.drop
|
40
|
-
KvgCharacterRecognition.db.drop_table(:characters) if KvgCharacterRecognition.db.table_exists?(:characters)
|
41
|
-
end
|
42
|
-
|
43
|
-
#This method populates the database table with parsed template patterns from the kanjivg file in xml format
|
2
|
+
module Trainer
|
3
|
+
#This method populates the datastore with parsed template patterns from the kanjivg file in xml format
|
44
4
|
#Params:
|
45
5
|
#+xml+:: download the latest xml release from https://github.com/KanjiVG/kanjivg/releases
|
46
|
-
|
6
|
+
#+datastore+:: JSONDatastore or custom datastore type having methods store, persist!
|
7
|
+
def self.populate_from_xml xml, datastore
|
47
8
|
file = File.open(xml) { |f| Nokogiri::XML(f) }
|
48
9
|
|
49
10
|
file.xpath("//kanji").each do |kanji|
|
@@ -85,7 +46,8 @@ module KvgCharacterRecognition
|
|
85
46
|
|
86
47
|
#Store to database
|
87
48
|
#--------------
|
88
|
-
|
49
|
+
character = {
|
50
|
+
value: value,
|
89
51
|
codepoint: codepoint.hex,
|
90
52
|
number_of_strokes: strokes.count,
|
91
53
|
serialized_strokes: serialized.join(","),
|
@@ -95,9 +57,12 @@ module KvgCharacterRecognition
|
|
95
57
|
direction_e4: direction[3].join(","),
|
96
58
|
heatmap_smoothed: heatmap_smoothed.to_a.join(","),
|
97
59
|
heatmap_significant_points: heatmap_significant_points.to_a.join(",")
|
60
|
+
}
|
61
|
+
|
62
|
+
datastore.store character
|
98
63
|
end
|
99
64
|
|
65
|
+
datastore.persist!
|
100
66
|
end
|
101
|
-
|
102
67
|
end
|
103
68
|
end
|
@@ -1,3 +1,17 @@
|
|
1
|
+
module Math
|
2
|
+
#Add euclidean distance method to ruby Math module
|
3
|
+
#This methods calculates the euclidean distance between 2 points
|
4
|
+
#Params:
|
5
|
+
#- p1, p2: [x, y]
|
6
|
+
def self.euclidean_distance(p1, p2)
|
7
|
+
sum_of_squares = 0
|
8
|
+
p1.each_with_index do |p1_coord,index|
|
9
|
+
sum_of_squares += (p1_coord - p2[index]) ** 2
|
10
|
+
end
|
11
|
+
Math.sqrt( sum_of_squares )
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
1
15
|
module KvgCharacterRecognition
|
2
16
|
|
3
17
|
#This class can be used for storing heatmap count and directional feature densities
|
metadata
CHANGED
@@ -1,31 +1,17 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: kvg_character_recognition
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jiayi Zheng
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-01-
|
11
|
+
date: 2016-01-17 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
|
-
name:
|
15
|
-
requirement: !ruby/object:Gem::Requirement
|
16
|
-
requirements:
|
17
|
-
- - ">="
|
18
|
-
- !ruby/object:Gem::Version
|
19
|
-
version: '0'
|
20
|
-
type: :runtime
|
21
|
-
prerelease: false
|
22
|
-
version_requirements: !ruby/object:Gem::Requirement
|
23
|
-
requirements:
|
24
|
-
- - ">="
|
25
|
-
- !ruby/object:Gem::Version
|
26
|
-
version: '0'
|
27
|
-
- !ruby/object:Gem::Dependency
|
28
|
-
name: sequel
|
14
|
+
name: parallel
|
29
15
|
requirement: !ruby/object:Gem::Requirement
|
30
16
|
requirements:
|
31
17
|
- - ">="
|
@@ -39,7 +25,7 @@ dependencies:
|
|
39
25
|
- !ruby/object:Gem::Version
|
40
26
|
version: '0'
|
41
27
|
- !ruby/object:Gem::Dependency
|
42
|
-
name:
|
28
|
+
name: nokogiri
|
43
29
|
requirement: !ruby/object:Gem::Requirement
|
44
30
|
requirements:
|
45
31
|
- - ">="
|
@@ -94,6 +80,20 @@ dependencies:
|
|
94
80
|
- - ">="
|
95
81
|
- !ruby/object:Gem::Version
|
96
82
|
version: '0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: pry
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ">="
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ">="
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
97
97
|
description: "This gem contains a CJK-character recognition engine using pattern/template
|
98
98
|
matching techniques.\n It can recognize stroke-order and stroke-number free handwritten
|
99
99
|
character patterns in the format [stroke1, stroke2 ...].\n A stroke is an array
|
@@ -117,10 +117,11 @@ files:
|
|
117
117
|
- bin/setup
|
118
118
|
- kvg_character_recognition.gemspec
|
119
119
|
- lib/kvg_character_recognition.rb
|
120
|
-
- lib/kvg_character_recognition/
|
120
|
+
- lib/kvg_character_recognition/datastore.rb
|
121
121
|
- lib/kvg_character_recognition/feature_extractor.rb
|
122
122
|
- lib/kvg_character_recognition/preprocessor.rb
|
123
123
|
- lib/kvg_character_recognition/recognizer.rb
|
124
|
+
- lib/kvg_character_recognition/trainer.rb
|
124
125
|
- lib/kvg_character_recognition/utils.rb
|
125
126
|
- lib/kvg_character_recognition/version.rb
|
126
127
|
homepage: https://github.com/thebluber/kvg_character_recognition
|