« Twitterのアイコンを福本顔にする | main | Greasemonkeyまとめをソート »

漢字を類似度検索可能にする

アイデアとしては単純で、画像情報に落としたあとで全漢字pairに対して全pixelの一致数をカウントするだけ。
これの時にはリアルに全漢字でやろうとしてたんだけど、2万字=>4億ペアなので断念した。常用漢字1945文字を対象とする。
ActiveRecordやら何やら使いたかったけど、普通にやると結構面倒だったのでrailsでプロジェクト作ってscript/runnerした。

ファイル


rake db:migrateで

    create_table :chars do |t|
t.column :char, :string
t.column :byte, :integer
end
add_index :chars, :char
add_index :chars, :byte
こんなのと
    create_table :similarities do |t|
t.column :char1_byte, :integer
t.column :char2_byte, :integer
t.column :similarity, :integer
end
add_index :similarities, [:char1_byte, :similarity]
add_index :similarities, :similarity
こんなの作った後、
#!/usr/bin/env /path/to/yours/kanji_rails/script/runner
$KCODE = "u"
require 'jcode'
require 'RMagick'

def diff_a(a1, a2)
result = 0
(0..399).to_a.each{|i| result +=1 if a1[i] == a2[i]}
result
end

chars_a = []
open("kanji.txt").each_line do |line|
line.chomp
chars_a << line.split(/\s/)
end
chars_a.flatten!

puts "chars retrieved"

chars_h = Hash.new {|h, k| h[k] = {}}
chars_q = []
chars_a.each do |char|
i = eval("0x#{char.unpack('C*').map{|i| i.to_s(16)}.join}")
chars_h[char][:byte] = i
chars_q << {
:byte => i,
:char => char
}
end

puts "chars analyzed"

chars_a = chars_a.sort_by{|c| chars_h[c][:byte]}

Char.create(chars_q)
puts "chars created"

pos = 0
chars_a.each do |char|
img = Magick::ImageList.new()
img.new_image(20,20)
text = Magick::Draw.new
text.gravity(Magick::CenterGravity)
text.stroke('transparent')
text.fill("black")
text.font("mincho.ttf")
text.font_size(20)
text.text(0,0,char)
text.draw(img)

px_a = []
20.times do |x|
20.times do |y|
px_a << (img.pixel_color(x,y).intensity.to_i != 255)
end
end
chars_h[char][:px_a] = px_a
pos += 1
puts "#{pos} chars pixel analyzed" if pos % 100 == 0
end
puts "chars pixel analyzed"

pos = 0
similarity_q = []
chars_a.each do |char1|
chars_a.each do |char2|
next if char1 == char2
similarity_q << {
:char1_byte => chars_h[char1][:byte],
:char2_byte => chars_h[char2][:byte],
:similarity => diff_a(chars_h[char1][:px_a], chars_h[char2][:px_a])
}
pos += 1
if pos % 1000 == 0
Similarities.create(similarity_q)
similarity_q = []
puts "#{pos} char pairs analyzed"
end
end
end

こんな感じ。20x20の画像オブジェクトを明朝体のtrue type fontとRMagickを用いて全漢字分生成し、色情報を配列に入れた後、各ピクセルの一致をそれぞれカウントしてDBに流し込む。
今一こういうデータのバッチ生成をどこに置くのかを分かってないです。ひょっとしたらmigrationにしちゃった方がよいのかもしれません。
で、会社に行ってる間にある程度検索可能な状態になったところで、適当なSQLを書いて上位ペアを500件抽出し、Cytoscapeで可視化してみる。
出来上がったのがこちら。

クリックで全体表示

とりあえずのびのび犬がちゃんと抽出できて良かった。

トラックバック

このエントリーのトラックバックURL:
http://polog.org/mt-tb.cgi/401

この一覧は、次のエントリーを参照しています: 漢字を類似度検索可能にする:

» 誤字ェネレータを作った 送信元 polog
誤字ェネレータ Rubyで全ての漢字を列挙する 漢字を類似度検索可能にする この... [詳しくはこちら]

» Fioricet online. 送信元 Fioricet online.
Fioricet online. [詳しくはこちら]

コメント (5)

わおう。。すごいですね。

人間が認識できるフォント全部でやってみたりしたら、ネットワークから漢字認識に必要なものが...とかならないですかね。

openCVとかで画像認識ってことかなあ。それも確かに面白そうだね。
このデータの別の使い方そのうち示すから、要チェキよろ。

うまい。
最近RNA二次構造とかで、二次元boolean alignmentについてひとつアイディアがあるから今度教える。
エントロピーを使った非常に簡単なやつ。
そもそもWindowsとかに漢字の絵を書くと検索してくれるやつあるけど、あれはどうやっているんだろう?
ってか何やるつもり?

RNA二次構造とか最早懐かしいな。是非教えてほしい。

手書き文字認識はまたちょっと違う手法らしいよ。筆を置いた位置からの軌跡の集合でマッチングだってこないだきょうたに聞いた。よくわからないけど。
やりたいのは文章にノイズをのせること。面白いかどうかはわからん。

ぼーっと眺めてたら右上に六-本-木があるのを発見したwww

コメントを投稿

Powered by
Movable Type 3.34