近デジネタの続きと言えば続きなのだが。
近デジのPDFの画像形式がJPEG 2000からJPEGになったので、拙作のKinDigDLでもJPEGファイルで出力する機能を付けてみたわけだが、そもそもこれは何に使うのかという話である。 言うまでもなく、近デジ生のPDFだと満足できない場合にはソース画像を自分でバンバンする(この懐かCM、いったい何人に通じるのか)ためのものだ。 近デジ生画像の問題点は、ざっと挙げると;
あたりだろうか。 この分野に関しては、既に実装されている方がおられる。 hitode909さんの記事、「近デジの画像の余白を取って左右に分割する」が嚆矢だろうか。 ちゃんとした処理に関してはhitode909さんや、ultraistさんが公開されているソースなどを参照して欲しい。 俺は「画像処理?何それうまいの」な人なので、こーゆー分野には手を出さないようにしてる。確かに以前、画像処理用のコンポーネントを作ったことはあるが、テメエの必要に応じた極めてプリミティブなもので、いわゆる「イメージ処理」的な機能は殆ど無い。 ただ、興味はあるわけで、勉強方々ちと自分でも試してみようと思ったわけだ。 先人の実装では、ImageMagikやOpenCVといった定番ソフトでバンバンしている例が多いように見受けられた。同じ事をやっても仕方がないので、ちょっと探してみると、AForge.NETというイイ感じのフレームワークを見つけた。
おまけに、名前が良い。 恵方寺と訓じればなにやら縁起が良さそうだし、個人的にはもう、アフォ毛としか読めないわけで、これは萌えるではないかw というわけで(どんなわけだ)、ちょっと試してみた。 いきなりhitode909さんレベルは俺にとってはあまりに敷居が高いので、簡単なところで、余白の除去から。 さて、近デジの生画像から余白を除去するとしたら、、大体こんな流れになるはずだと考えた。
アフォ毛のよいところは、ドキュメントがかなり整備されていて、使用例もそこそこある、というところだ。まあ、残念な事に で、アフォ毛のドキュメントを斜め読みしてたら(つーか英語なんてナナメ読みしかできないが)、「お、こりゃコピペだけでかなりイケるんじゃね?」と思ったわけである。 で、やおら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 なんとこれだけで、画像の大外のエッジの頂点を検出してリストに積んでくれるのである。 あとは、得られた四隅の座標の最大値と最小値を求め、縮小した座標を係数を掛けて元の画像の座標に戻し、その最大・最少座標で囲われる四角形を元画像からコピーする。コードは略。 つーことで、いきあたりばったりのコピペだけで作ったモノなので結果はあまり期待してなかったのだが、これが中々イイ感じに切り出してくれる場合もあるのである。すげぇなアフォ毛。 「場合もある」というのはダメな場合も多いわけである。 要するに「台紙」の部分が白いもの、である。 例えば、こういう、本の外側が黒いのはかなり良い感じだが、こういう、本自体のエッジが判然としないモノはうまくいかなかった。 これは、元々そういう風に作ってないのだから、当然と言えば当然の結果である。 実際に使い物にするには、やはりきちんと左右のページを分けて、テキストの書いてある領域を判別して(極端なことを言えば活字一文字ずつに切り分けて)…という処理が必要だろう。 とはいえ、何ら知識のない人間がコピペだけで作ったものでも、そこそこ動くというのは、つくづく良い世の中になってきたなぁ…というのが今日の感想。
by SIGNAL-9
| 2013-01-30 13:56
| TIPSとかKludgeとか
|
カテゴリ
全体 一般の話題 奇妙な論理 奇談・異聞 秋葉原 研究(笑) 町歩き 古い話 東電災害 電算機関係の話題 情報保護・セキュリティ 読んだり見たり TIPSとかKludgeとか 拙作ソフトウェア 未分類 最新の記事
記事ランキング
以前の記事
最新のトラックバック
その他のジャンル
ブログジャンル
画像一覧
|
ファン申請 |
||