近デジ画像の余白の除去をネタにAForge.NETを使ってみた。

 近デジネタの続きと言えば続きなのだが。

 近デジのPDFの画像形式がJPEG 2000からJPEGになったので、拙作のKinDigDLでもJPEGファイルで出力する機能を付けてみたわけだが、そもそもこれは何に使うのかという話である。

 言うまでもなく、近デジ生のPDFだと満足できない場合にはソース画像を自分でバンバンする(この懐かCM、いったい何人に通じるのか)ためのものだ。
 近デジ生画像の問題点は、ざっと挙げると;
  1. 白黒のマイクロフィルムから起こしたものは、かなり余分な「余白」が付いている。
    余分な余白というのは馬から落ちて落馬した的であるが、つまり、本来の「本の余白」の外に、本を置いた「台」の部分が映り込んでいる為、その部分が「余分」ということである。

  2. 殆どが「見開き」の状態(1画像で左右2ページ)なので、環境によっては読みにくい。やはりホントのページ単位にしたい。

  3. 画像のコントラストがまちまちで、読みにくいものも散見される。

  4. ノイズ・リダクションくらい掛けたいじゃない。

あたりだろうか。

 この分野に関しては、既に実装されている方がおられる。
 hitode909さんの記事、「近デジの画像の余白を取って左右に分割する」が嚆矢だろうか。

 ちゃんとした処理に関してはhitode909さんや、ultraistさんが公開されているソースなどを参照して欲しい。

 俺は「画像処理?何それうまいの」な人なので、こーゆー分野には手を出さないようにしてる。確かに以前、画像処理用のコンポーネントを作ったことはあるが、テメエの必要に応じた極めてプリミティブなもので、いわゆる「イメージ処理」的な機能は殆ど無い。

 ただ、興味はあるわけで、勉強方々ちと自分でも試してみようと思ったわけだ。

 先人の実装では、ImageMagikやOpenCVといった定番ソフトでバンバンしている例が多いように見受けられた。同じ事をやっても仕方がないので、ちょっと探してみると、AForge.NETというイイ感じのフレームワークを見つけた。
  1. LGPLのオープンソース、しかもC#での実装なので自分の勉強になる。

  2. イメージ処理、動画処理、ニューラルネットにファジー処理…など、その筋なネタで構成されており、「実験」という男のロマンが感じられるw
つーあたりが魅力である。

 おまけに、名前が良い
 恵方寺と訓じればなにやら縁起が良さそうだし、個人的にはもう、アフォ毛としか読めないわけで、これは萌えるではないかw

 というわけで(どんなわけだ)、ちょっと試してみた。
 いきなりhitode909さんレベルは俺にとってはあまりに敷居が高いので、簡単なところで、余白の除去から。



 さて、近デジの生画像から余白を除去するとしたら、、大体こんな流れになるはずだと考えた。
  1. 処理を速くする為に元画像を縮小したコピーを作る。

  2. 後処理しやすいようにコピー画像を綺麗にする。

  3. コピー画像の外枠(余分な余白と本体との境目)を見つける為に、エッジを際だたせる。

  4. モノが四角形の本なんだから、エッジの頂点は四つになるはずなので、その座標を求め、元画像からその座標の内側を取得する。


 アフォ毛のよいところは、ドキュメントがかなり整備されていて、使用例もそこそこある、というところだ。まあ、残念な事に敵性言語英語ばっかりで、国内の事例が余り見あたらないのが難といえば難だが。

 で、アフォ毛のドキュメントを斜め読みしてたら(つーか英語なんてナナメ読みしかできないが)、「お、こりゃコピペだけでかなりイケるんじゃね?」と思ったわけである。
 で、やおらVisual studioを立ち上げて、ドキュメントのサンプルコードをペタペタ貼るという暴挙に打って出たw

 最初に断っておくが、以下は試したことをズラズラと並べているだけで、処理の要不要とか効率とかそーゆーものは一切考慮していない。

 まずは、処理を速くする為に小さな画像を作るわけだが、アフォ毛ではこんな感じ。

const int gPower = 6; // 縮め係数. 適当
Bitmap OrgBitmap = new Bitmap(OrgBitmapName); // オリジナル画像を読み込む

// 処理を速くする為、小さな検出用bitmapを作成する。
AForge.Imaging.Filters.ResizeNearestNeighbor sfilter
= new AForge.Imaging.Filters.ResizeNearestNeighbor
(OrgBitmap.Width / gPower, OrgBitmap.Height / gPower);
Bitmap bitmap = sfilter.Apply(OrgBitmap);

 とりあえず近接で縮小してみた。他にバイリニアとかキュービック法のフィルタもあるので、色々試してみるといいかも。

 境界線(エッジ)を検出する為には、なるべく画像を単純化した方がよいだろうということで、この縮小画像に下ごしらえのフィルタをかけてみた。


// エッジ検出しやすくする為に画像を単純化する
FiltersSequence seq = new FiltersSequence();

if (bitmap.PixelFormat != System.Drawing.Imaging.PixelFormat.Format8bppIndexed) {
seq.Add(Grayscale.CommonAlgorithms.BT709); // GrayScaling filter
}
seq.Add(new ContrastStretch()); // コントラストを強くする
seq.Add(new ConservativeSmoothing()); // Conservative スムージング
seq.Add(new OtsuThreshold()); // Otsu thresholding
bitmap = seq.Apply(bitmap);


 AForgeの画像フィルタは、8bppだけ対応というのがけっこうある。近デジの画像はほとんどがグレースケールのモノクロ画像なのだが、必要に応じてグレースケールに変換する。
 OtsuThresholdは「大津の手法」というヤツ、グレイ画像を二値化(白黒)にするためのフィルタである。
 実は当初、コントラスト強化とスムージングだけ行っていたのだが、大津フィルタを掛けた方がイイ感じだったので、いきあたりばったりにw追加した。
 このあたりは色々調整の余地がありそうだ。

 さて、画像のエッジを際だたせる為に使ったのは Canny edge フィルタ である。
 これもAForgeだとわずか数行で済む。

// Canny edge filter でエッジ際だたせる
CannyEdgeDetector cfilter = new CannyEdgeDetector();
cfilter.ApplyInPlace(bitmap);


CannyEdgeDetector には閾値の最大・最小値、ガウスのサイズなんかがプロパティで設定できるが、ここでは全部デフォルト。

 次に、画像の傾きを補正する。いわゆる"deskew"処理というヤツだが、AForgeではハフ変換ベースのDocumentSkewCheckerという、この処理を自動的にやってくれるメンバが用意されている。



// 傾き補正(Hough trans)
DocumentSkewChecker skewChecker = new DocumentSkewChecker();
// ドキュメントのスキュー角を求める
double angle = skewChecker.GetSkewAngle(bitmap);
RotateBilinear rotationFilter = new RotateBilinear(-angle);
rotationFilter.FillColor = Color.Black;
bitmap = rotationFilter.Apply(bitmap);
//オリジナル側も同じ角度で補正しておく
OrgBitmap = rotationFilter.Apply(OrgBitmap);


 そもそも近デジ画像は見開きなので、一枚の画像で左と右のページの傾きがそれぞれ異なる。実際には傾き補正は右・左別々に行うべきだろう。

 で、いよいよ境界の四隅の座標を座標を取得するわけだが、AForgeにはこれまたQuadrilateralFinderというそれらしき汎用メンバがあるではないか。コピペコピペっと。



// QuadrilateralFinder で四隅のコーナーの座標を取得する
QuadrilateralFinder qf = new QuadrilateralFinder();
List corners = qf.ProcessImage(bitmap);


 なんとこれだけで、画像の大外のエッジの頂点を検出してリストに積んでくれるのである。
 あとは、得られた四隅の座標の最大値と最小値を求め、縮小した座標を係数を掛けて元の画像の座標に戻し、その最大・最少座標で囲われる四角形を元画像からコピーする。コードは略。

 つーことで、いきあたりばったりのコピペだけで作ったモノなので結果はあまり期待してなかったのだが、これが中々イイ感じに切り出してくれる場合もあるのである。すげぇなアフォ毛


c0071416_14481285.jpg


c0071416_14475694.jpg



 「場合もある」というのはダメな場合も多いわけである。
 要するに「台紙」の部分が白いもの、である。
 例えば、こういう、本の外側が黒いのはかなり良い感じだが、こういう、本自体のエッジが判然としないモノはうまくいかなかった。


c0071416_14482844.jpg


c0071416_14484099.jpg



 これは、元々そういう風に作ってないのだから、当然と言えば当然の結果である。
 実際に使い物にするには、やはりきちんと左右のページを分けて、テキストの書いてある領域を判別して(極端なことを言えば活字一文字ずつに切り分けて)…という処理が必要だろう。

 とはいえ、何ら知識のない人間がコピペだけで作ったものでも、そこそこ動くというのは、つくづく良い世の中になってきたなぁ…というのが今日の感想。
[PR]
by SIGNAL-9 | 2013-01-30 13:56 | TIPSとかKludgeとか | Comments(0)
<< 【じょしらくBパート風】新木場 【じょしらくBパート風】 銅像 >>