紙の英単語帳をAnkiに入れた~い!
これはKCS Advent Calendar2020 24日目の記事です
←23日目 | 25日目→
大学生ともなるとなんとなくTOEICとかのために英語を勉強しなきゃ…という気持ちになってとりあえず単語帳を買う。そんな経験はありませんか?
僕はあります。
「よ~し、単語帳買ったから通学中のスキマ時間にパラパラやっていくぞ!」
こう考えていても単語帳が微妙に邪魔だから持ち運びたくないし、電車の中とかで鞄から取り出すのが億劫。そう思ったことはありませんか?
僕はあります。
そしてスマホアプリの単語帳やればいいじゃん!と気づいたものの既に買ってしまった単語帳がもったいない…。そう後悔したことはありませんか?
僕はあります。
そんな僕が英単語帳を頑張ってスマホアプリのAnkiに取り込んだ話です。
ちなみに、スマホアプリ(mik○n等)なら読み上げ音声も一緒に流れてくれたりするのは流れません。
当時僕はAndroidを使っていてAnkidroidが無料だったんですが、iPhoneに変更したところAnkiアプリに数千円払うことになってしまったことに加え、僕が購入した英単語帳をそれ以下の金額で学習できるアプリも見つけるなど踏んだり蹴ったりでした。
あまりオススメしません Ankiは忘却曲線とかほにゃららで評判がいいのでみんなやりましょう!
この記事の目標は、それぞれの単語ごとに英単語部分と日本語の意味部分を切り出してAnkiに取り込むことです。
英単語帳の処理
英単語帳の処理とAnkiに取り込む部分の2段階あるので、まず英単語帳の処理から行います。まずは適当な手段で自炊して各ページを画像データにしましょう。
今回は『TOEFLテスト英単語3800』で行いました。
Rank1とRank2~4で形式が異なるので次の2種類のページを例にして処理を行っていきます。


明らかに見た目が違うなあということがとりあえずわかります。
基本的な方針としては、少し太い上端と下端の線を見つければ英単語が含まれる領域がわかりそうです。また、Rank1は真ん中の縦線で切った後、英単語部分と日本語部分の比率は同じように見えます。Rank2以降は真ん中の縦線で切るだけなので楽そうです。
その後は単語ごとに分けていく必要がありますが、いい感じに赤い横線があるのでこれを見つければ良さそうです。
ここまでのことを考えると、線分検出すれば勝ちっぽく見えます。実際ほとんど勝ちなのでやっていきましょう。
とりあえず二値化
自炊時に縁が少し黒くなってしまうのでそこをちょっと切り取った後、とりあえず2値化します。
当時は若かったのと、線分の色が殆ど決まっていたのでcv2のinRangeを使って黒部分と赤部分を抽出することでゴリ押ししています。
inRangeは2頂点を指定した直方体内に色が入っているピクセルについては255を、残りについては0を返すので適当にorしてnotで反転させると線の部分が黒い次のような二値化画像が手に入ります。
実際のコードは次みたいな感じで、この色の範囲は職人の暖かみのある手作業で調整されました。
</p> def binarize(img): black = cv2.inRange(img, (00, 00, 00), (160, 160, 160)) red = cv2.inRange(img, (150, 100, 100), (255, 220, 220)) line = cv2.bitwise_or(black, red) line = cv2.bitwise_not(line) return line <p>


適当に線分抽出
じゃあ線分抽出はどうやるんだ?という話になるんですが、これはハフ変換を使います。
まずガウスフィルターで適当にぼかした後、色を反転して黒背景に白線にします。そしたらHoughLinePで線分抽出を行います。大体上のURLのサンプルと同じなんですが、minLineLengthという抽出する線分の最低限の長さは丁度いい値に手調整しています。
次の画像は抽出された線分を表示したものです。


</p> def get_line(img): img2 = cv2.GaussianBlur(img, (5, 5), 5) img2 = cv2.bitwise_not(img2) lines = cv2.HoughLinesP(img2, rho=1, theta=np.pi/360, threshold=200, minLineLength=1000, maxLineGap=10) return lines <p>
ゴリ押しの後処理
もうほとんど終わったと思うかもしれませんが、ここからが本当に面倒です。まず、各線分は綺麗に端から端まで伸びているわけではなく途切れている場合があることに注意しましょう。
あとRank2以降は右にあるチェックボックスみたいなのが明らかに邪魔なのでそこらへんの対処も必要です。
ただ、明らかに本質じゃないのと大分長くなってしまっているのでここではコード自体は載せません!君だけのゴリゴリ処理で頑張って各行各列のx座標とy座標を手に入れよう!
適当に横線か判定する関数を用意した後、横線のx座標の最小最大を使って英単語メイン部分のx座標の範囲を手に入れます。その後は横線についてy座標の差が一定以内のものは全部一つにまとめて、縦線についてもメイン部分に含まれている線分についてx座標の差が一定以内のものを一つにまとめます。僕は一つにまとめたらそこにまとめたものの中で平均を取りました。ここはそこまでブレはなさそうなので自由だと思います。
ちなみに横線についてもメイン部分に含まれる縦線のy座標の範囲内に含まれているものだけに絞ります。そしたら横線の各y座標が各行の上端か下端になっていて、縦線の各x座標と英単語メイン部分の範囲の左端と右端のx座標をまとめたものが各列の左端か右端になっています。
英単語メイン部分の左端と右端に縦線がないので横線から導いたx座標を適当に追加しています。
こうすると各行を切り取れるようになり、Rank2以降であれば左から3つ目のx座標で切り取れば英単語と日本語に分けられます。左から1つ目がメイン部分の左端、2つ目が単語番号と英単語の間の縦線、3つ目が英単語と日本語の間の縦線のx座標です。
Rank1だったら1つ目と3つ目か、2つ目の3つ目のx座標の間を適当な比率で分けて英語と日本語の間のx座標を求めます。この比率はずっと一緒でした。
こうして手に入れた列のx座標と行のy座標に線を引くと次のような感じになります。明らかにいい感じなのでこれをもとに切り取れば大丈夫です。


切り取った画像は単語番号をいい感じに割り振って英単語部分と日本語の意味部分を別々に保存しましょう。
これで画像処理はおしまいです。後はAnkiに取り込めば終わりです。
Ankiへ取り込む
Ankiに取り込みます。Ankiを適当にパソコンへインストールしてください。
Ankiの良いところは所有しているPCとスマホで簡単に同期ができることなので、取り込むのもPCで行った後にスマホで同期すれば大丈夫です。
正直こっちは探せば結構出てくるので好きにやってくださいという気持ちなんですが、やり方を一つ紹介します。うまく行かなかったら頑張ってください。
まず、適当なテキストファイルを用意して各行を次のようにしてやりましょう。AnkiはHTMLが使えるので自由度が高くて、すごい!
これはセミコロンで区切っていて、1つ目が英単語の画像の表示、2つ目が意味の画像の表示、3つ目がタグです。今回はRankでタグ付けをしました。
先程切り出した画像は、英単語部分の画像は単語番号にwordを付加し、意味部分は単語番号にmeanを付加しています。
<img src="TOEFL3800_0001_word.jpg">; <img src="TOEFL3800_0001_mean.jpg">; Rank1
単語の画像たちは全部Ankiのcollection.mediaというフォルダに入れる必要があります。僕の場合はWindowsで、C:\ユーザー\(ユーザー名)\AppData\Roaming\Anki2\ユーザー1\collection.media
にありました。ここになければPC内を適当にAnkiで検索かけてやるかネットで調べるかしてやりましょう。
そしたらAnkiを起動して、ファイルを読み込むを押して先程作ったテキストファイルを読み込みます。するとx番目のフィールドをほにゃららに割り当てるみたいなのがあるので、自分の好きなように割り当ててください。Rankタグみたいなのは用意しなくても大丈夫だと思います。『フィールドにHTMLを使う』はしっかりチェックしておきましょう。
おわり
正直このアプローチが通用する単語帳、あまりないと思います
色の変化する場所を適当にどうにかすればうまくいくやつが増えるかも
例えばちゃんとした例文付けます!みたいな単語帳は途中で改ページしがちなので厳しかったりと、ほぼ駄目なので最初から良い感じの英単語のアプリを使おうな
これでAnkiに購入した単語帳を取り込めたと思います!みんなiPhoneで3060円するAnkiアプリを買おう!
←23日目 | 25日目→
Posted on: 2020年12月24日, by : ぱじぇ