2014/02/09

Arch Linuxでカーネルを更新したのにバージョンが古いままだった件 (環境の問題)

Arch Linuxのpacmanでアップデートを行ったところ、
linuxのアップデートがあったのですが...
再起動後、コンソールで表示が遅い、Xも起動しない、...という問題が。
(結論からいうと、環境の問題というか設定ミスでした m(_ _;)m)

lsmodすると...読み込まれているモジュールが明らかに少ない様子です。
$ lsmod
Module                  Size  Used by
ext4                  474251  3
crc16                   1367  1 ext4
mbcache                 6082  1 ext4
jbd2                   83504  1 ext4
dm_mod                 82469  9
sr_mod                 14898  0
cdrom                  34848  1 sr_mod
sd_mod                 30821  2
rtsx_pci_sdmmc         14332  0
ahci                   23056  1
libahci                21674  1 ahci
libata                170856  2 ahci,libahci
sdhci_pci              12146  0
sdhci                  29116  1 sdhci_pci
scsi_mod              130701  3 libata,sd_mod,sr_mod
mmc_core               95691  3 sdhci,rtsx_pci_sdmmc,sdhci_pci
rtsx_pci               32209  1 rtsx_pci_sdmmc
ehci_pci                4000  0
ehci_hcd               59220  1 ehci_pci
usbcore               180136  2 ehci_hcd,ehci_pci
usb_common              1656  1 usbcore
正常時は 116行なのに対して、22行しかありませんでした(笑)

mkinitcpioで確認してみようとしたところ...。
$ sudo mkinitcpio -M
 ==> ERROR: 'lib/modules/3.12.5-1.ARCH/' is not a valid kernel module directory.
カーネルモジュールのディレクトリが正しくないというエラーが。
しかも、バージョンが違うような?
(でも、アップデートでは何もエラーは表示されていませんでした。)

まずは、カーネルのバージョンを調べます。
$ uname -r
3.12.5-1-ARCH
アップデートされたはずのカーネルのバージョンがどうも古いままでした。

では、/lib/modulesは...というと...
$ ls /lib/modules/
合計 8
drwxr-xr-x 3 root root 4096  2月  9 13:25 3.12.9-2-ARCH
drwxr-xr-x 2 root root 4096  2月  9 13:25 extramodules-3.12-ARCH
こちらは新しいカーネルのバージョンでした。

さてここで原因が分かりました。
参照: [Solved] Uname doesn't changes after linux-3.9.5 upgrade

私のPCでは、/(ルート)や/homeはLVMボリュームであり
/boot は分割して通常のパーティションに割り当てています:
  • /(ルート) - LVMボリューム (/dev/sda8, /dev/VolGroup00/lvolroot)
  • /home - LVMボリューム (/dev/sda8, /dev/VolGroup00/lvolhome)
  • /boot - ext4 (/dev/sda10)

/bootパーティションがマウントされているか確認してみると...
$ mount -l | grep boot
空ということで、何も/bootにマウントされていないようです。

しかし、/bootには最新のイメージが書き込まれていました。
$ ls /boot -l
合計 xxxxx
-rw-r--r-- 1 root root 17758784  2月  9 13:25 initramfs-linux-fallback.img
-rw-r--r-- 1 root root  4344657  2月  9 13:25 initramfs-linux.img
-rw-r--r-- 1 root root  3867632  1月 31 18:24 vmlinuz-linux
※ でも、あるはずのgrubディレクトリが無いのです。

つまり...どういうことかと言いますと...
pacman -Syu でLinuxカーネルのアップデートがあった場合、
自動的にmkinitcpioが実行されますが、
この時、 /boot パーティションがマウントされていなかったため、
空の/bootディレクトリに最新のイメージファイルが書き込まれたようです。

GRUBから起動するときは /bootが/dev/sda10から起動されますが、
起動した後は、/bootがLVM上の/(ルート)下にあるものに置き換わっているため、
不整合となっていたようです。(そのため、必要なモジュールが読み込まれない。)

とりあえず、処置として...
コンソール上で /bootをマウントした上で
downgrade を使ってlinuxのカーネルを再インストールしました。
(pacman -Uでカーネルを再インストールしたり、mkinitcpioを手動実行してもいいはず。)

あとは再起動すれば正常に起動します。

さらに、fstabに/bootを追記しておきます。
$ sudo vi /etc/fstab
# /dev/sda10
/dev/sda10 /boot ext4 rw,relatime,data=ordered 0 2
これでOKです。たぶん(^^;)

とりあえず、一件落着です ε-(´∀`*)

2014/02/01

AndroidでTesseract-OCRを用いてカメラで光学文字認識をしてみた

AndroidでTesseract-OCRを使って、カメラで撮影した画像からOCR(光学文字認識)をしてみました。

"Tesseract-OCR"はOCRエンジンであり、元々HPによって開発され、OSS化されて今はGoogleがメインメンテナとなっています。
このTesseract-OCRをAndroidでNDKとして利用するためのライブラリが "tesseract-android-tools"です。

尚、本記事は Android SDK、GNU make、Awk、Gitがインストールされていることが前提です。また、OS環境としてLinux(Arch Linux x64)を使っています。

まずは、"Android NDK"をダウンロードします。
(すでにAndroid NDKをセットアップしていれば、この手順は不要です。)
今回は、Linux x64向けの最新版である "android-ndk-r9c-linux-x86_64.tar.bz2"を用いました。
さらにダウンロードしたアーカイブを展開し、これに含まれる"ndk-build"コマンドを利用できるようにPATHを通しておきます。
$ wget android-ndk-r9c-linux-x86_64.tar.bz2
$ tar jxf android-ndk-r9c-linux-x86_64.tar.bz2
$ sudo mv android-ndk-r9c/ /opt/
$ echo 'export PATH=$PATH:/opt/android-ndk-r9c' >> ~/.bashrc
$ echo 'export NDKROOT=$PATH:/opt/android-ndk-r9c' >> ~/.bashrc
$ source ~/.bashrc

次に、"tesseract-android-tools"を...
...のはずですが、執筆現在、Android NDK r9 でうまくビルドできませんでした。

代わりに、rmtheis 氏によってForkされたプロジェクトが公開されていますので、そちらを使わせていただくことにします。尚、このプロジェクトにはTesseract、Leptonica、その他の必要なファイルが同梱されています。
$ git clone  https://github.com/rmtheis/tess-two.git
$ cd tess-two/tess-two/

あとは READMEファイルのとおりにビルドを進めていきます。
但し、ここでAndroid SDKのAPI level 8がインストールされていないとエラーが発生しましたので、project.propertiesを書き換えることで対処しておきます。(自分のPCにインストールしておいたAPI levelに書き換えてください。)
--- project.properties
+++ project.properties
@@ -9,4 +9,4 @@
 android.library=true
 # Project target.
-target=android-8
+target=android-10
さらにコマンドを実行します。
$ ndk-build
$ android update project --path .
$ ant release

次に、Eclipseでプロジェクトをインポートします。
先ほどndk-build した "tess-two"プロジェクトを、Eclipse上で"Androidプロジェクト"としてインポートします。
インポートされたら、プロジェクトのプロパティで"ライブラリ"扱いになっているかを確認します。
Eclipse上でプロジェクト"tess-two"をインポートしたら、
プロジェクトのプロパティで"ライブラリー"にチェックが入っていることを確認する。

あとは、Androidアプリケーションを書きます。
今回は、最低限の簡単なサンプルアプリケーションを作ってみましたので、
一式をGitHubのリポジトリとして公開しておきました:
https://github.com/mugifly/android_tesseract-ocr_test
ご自由に git cloneして、動作を試したり改変したりしてご利用ください。

尚、このAndroidアプリケーションプロジェクトのほうでは、先ほどのライブラリプロジェクト"tess-two"をライブラリーとして追加しておきます。
Androidアプリケーションプロジェクトのプロパティで
使用するライブラリーとして先ほどの"tess-two"プロジェクトを追加する。
さらに、"tesseract-ocr"の学習データをダウンロードします。
日本語の学習データは http://tesseract-ocr.googlecode.com/files/tesseract-ocr-3.02.jpn.tar.gz です。
これをダウンロードして展開すると"jpn.traineddata"というファイルがあります。

このファイルを、先ほどのAndroidアプリケーションプロジェクト内の"assets"ディレクトリ内にコピーしておきます。
Androidアプリケーションプロジェクトに"assets"フォルダを作り、
そこに"jpn.traineddata "をコピーしておく。
※ assets内の学習データを直接Tesseract-OCRで読み込めるようにするには、
tess-two (tesseract-android-tools)を改変する必要がありそうでしたので、
代わりに私が作成したサンプルアプリケーションでは、起動時にassets内の学習データをSDカード上にコピーする処理を実装しておきました。

尚、学習データがないと当然ながらOCR処理でエラーが発生します。ご注意下さい。

あとはAndroidアプリケーションプロジェクトをビルドするだけです。
NDKを用いたアプリケーションなので、ビルドに少し時間がかかります。

さて、写真を撮って文字認識をしてみます...。
尚、今回は面倒くさかったので、実機ではなくAndroidの開発用エミュレータを用いました。カメラは適当にあったWebカメラ QCam S7500 で、解像度はVGAに落として撮影しています。


OCRをかける前に二値化処理を行い、さらに数字だけに絞ってOCRをかけています。
適当に写真を撮った割には、まあまあの認識精度だと思いますが、
やはり、前処理(傾き、歪みとか、二値化とか...)について改良する余地がありそうです。

また、手書きした文字についてはうまく読み取りできませんでしたが、手書きの文字ばかりを集めて学習データを生成すれば、不可能ではないようです。
(参照: tesseract for handwriting recognition)

それでは (^ ^)♪

参考にさせていただいたページ (感謝♪):