Web開発
Perspec 1.0
Perspec 1.0 (adriansieber.com)
要約
この記事は、9年間の開発を経てリリースされた画像補正デスクトップアプリ「Perspec 1.0」の発表です。Perspecは、特に書類やレシートの写真の歪んだパースペクティブを修正するために設計されており、モバイルのスキャナーアプリとは異なり、デスクトップでの編集の利便性と、より高品質な画像処理(PNG形式の利用など)を提供します。開発者は、既存アプリの欠点を克服し、独自のコーナー検出アルゴリズムを実装するために、HaskellとC言語を駆使して開発を進めました。
全文翻訳
Perspecの1.0リリースを発表できることを非常に嬉しく思います!
Perspecは、画像のパースペクティブを補正するためのデスクトップアプリです。これは主に書類やレシートの写真に役立ちますが、あらゆる種類の画像に使用できます。
これは、9年前にプロジェクトを開始したときに私が思い描いていたアプリがついに実現したものです。ここまで来るのにこんなに時間がかかるとは思いませんでしたが、結果には非常に満足しており、皆さんも気に入ってくれることを願っています!
初期の動機
Adobe Scan、vFlat、SwiftScanなど、モバイルフォンで利用できるスキャナーアプリにはおそらく慣れているでしょう。スキャン機能はDropboxにも統合されており、最近ではiOS自体にもネイティブで組み込まれています。
しかし、私は携帯電話で作業するのが好きではなく、書類やレシートの写真を撮って、後日コンピュータで整理やクリーンアップをしたいと考えています。そこには、大きな画面、キーボード、そして正確なマウスがあり、編集がより速く、より正確になります。
また、モバイルアプリは、ユーザーに馴染みのあるものを提供するために、いくつかの厄介な技術的決定を下しています。
例えば:
グレースケールPNGとしてドキュメントを保存すると、圧縮アーティファクトを導入せずにファイルサイズを小さくすることができます。しかし、すべての人気アプリは、JPEGが人々になじみがあるという理由だけで、はるかに大きなファイルサイズと悪い画質を持つグレースケールJPEG画像を提供します。あるいは、彼らが私に信用を与えすぎているのかもしれません。画像に大きな均一な色の領域が含まれている場合、PNGの方がJPEGよりも小さいことを彼らが知らないのかもしれません。一方、通常の写真では、JPEGはPNGよりも小さいです。そして、後でPNGに変換することは選択肢ではありません。なぜなら、その時点ですでに画像にはJPEG圧縮アーティファクトがすべて含まれているからです。
例えば、以下のドキュメントをスキャンした結果を比較してみましょう。
他のアプリはより大きなファイルを生成し、結果を劣化させる圧縮アーティファクトがはっきりと見えます。
アプリ | 結果 | プレビュー | メモ
---|---|---|---
Perspec | ~110 kB, PNG | [結果を見る] |
Scanner Pro | ~190 kB, JPEG | [結果を見る] |
iOS (PDFから抽出したJPEG) | ~300 kB, JPEG | [結果を見る] |
もう一つ、私を不必要に悩ませているのは、最近ほとんどのアプリに含まれている、ばかげた検出プレビューです。
写真を撮っている間、アプリはドキュメントを検出している場所のライブオーバーレイを表示します。しかし、これは全く役に立ちません。プレビュービデオフィードでドキュメントを正しく検出できたとしても、最終的な写真で正しく検出されるとは限りません。
解像度が高く、照明が異なり(露出時間、フラッシュなど)、コントラストが異なるため、最終的な写真では検出がかなり異なることがよくあります。
したがって、プレビューが教えてくれるのは、カメラの前にドキュメントがあるということだけです。あなたはそれをそこに置いたので、すでに知っています。🤦♂️
最後に、そして最も重要なことですが、私が撮っていた写真の種類のために、より良いドキュメント検出アルゴリズムを構築できると知っていました。
既存のアプリでの検出は、良い写真で、ドキュメントと背景のコントラストが良い場合でも、しばしばわずかにずれていました。
ほとんどのアプリは、Dropboxがここで説明しているように、パイプラインに何らかのエッジ検出ステップを使用しています。しかし、私はドキュメントやレシートがまっすぐなエッジではなく、しわくちゃまたは曲がったエッジを持っていることが多いことを知っていました。
わずかな曲線でさえ直線に合わせようとすると、端点はかなり離れてしまいます。
代わりに、アプリはコーナーを検出し、そこからドキュメントを構築しようとすべきです。
コンピュータビジョン技術の詳細な説明は、投稿の後半にあります。
1.0への長い道のり
Perspecに取り組み始めたとき、私はまだ学生で、学業のために多くのものをスキャンする必要があったので、このようなものを作るモチベーションは十分にありました。
確かに、Photoshop、Affinity Photo、またはGIMPでパースペクティブを修正することもできます。しかし、オーバーヘッドは相当なものです。
各写真を1つずつ開く、パースペクティブツールを見つける、コーナーをドラッグする、適切なエクスポート設定を選択する、次の写真のために繰り返す、などです。
これらのツールは、あらゆる画像で何でも行うように構築されており、50枚のレシートを可能な限り迅速に処理するように設計されていません。
私はこの1つのタスクに焦点を当てた、可能な限り合理化されたワークフローを持つアプリを求めていました。
私の最初のイテレーションは、Pythonとscikit-imageで実装された、Perspectraという完全に自動化されたCLIアプリでした。
画像を与えると、ドキュメントを検出して抽出しようとします。それだけです。
scikit-imageは気に入っていましたが、Pythonは絶対に好きではありませんでした。
しかし、より重要なことに、自動化されたCVパイプラインではすべてのドキュメントを100%正確にすることは決してないため、誤って検出されたドキュメントの境界を修正するためのGUIが必要であることに気づきました。
そして、GUIを備えたデスクトップアプリをどのように構築しますか?明らかにHaskellで。
😝 冗談はさておき、私は最近Haskellを学び始めており、それに完全に夢中になっていました。
したがって、自然に、デスクトップアプリの構築にそれを使用できるかどうかを確認したかったのです。
もうPythonを使いたくなかったので、次の本能は、画像操作とコンピュータビジョンタスクにImageMagickを使用することでした。その機能と能力についてはいくらか経験がありました。
既存のHaskellバインディングはかなり不足していたため、単にmagickを外部プロセスとして呼び出すことを選択しました。
これはほとんど機能しましたが、プラットフォーム間で正しくインストールしてリンクするのが常に面倒で、大きな画像ではパフォーマンスが驚くほど悪かったです。
もう1つの明らかな選択肢はOpenCVでしたが、大学で使用した際の悪い思い出があり(おそらくC++のコンテキストだったのでしょう…)、Haskellバインディングはかなり厄介に見えました。
そこで、次の実験はネイティブHaskell画像処理ライブラリHipを使用することでした。
その作者である@lehins自身と@HanStolpoの助けを借りて、ZuriHacで動作させることができました!(再び感謝します!)
しかし、それはまだ私が望んでいたいくつかの機能、例えば大津の方法による二値化が欠けていました。
Hipでこれを実装することは確かに可能でしたが、私は(今回ばかりは)Haskellの抽象化が、手元のタスクに本当に役立たず、物事を不必要に複雑にしていると感じました。
比較すると、C言語のforループは概念的に非常にシンプルで、Haskellコードと同じくらい高速です。
幸いなことに、C言語はHaskellでは第一級市民であり、HaskellのFFIを介して呼び出すCコードをバンドルするのは非常に簡単です。
残念ながら、Perspecに過剰なFFIの苦労なしにフックできる直接的なCライブラリは存在しないように見えたため、純粋なC言語のコンピュータビジョンおよび画像操作ライブラリであるFlatCVの開発を開始しました。
ここでヤクシャビング(不要な作業)をしすぎたかもしれませんが、プロジェクト全体が愛の労働である以上、最後までやり遂げるのはなぜでしょうか?😅
画像操作アルゴリズムにC言語を使用した経験には非常に満足しており、必要なHaskellバインディングを備えた完全に機能するバージョンを迅速に構築することができました。
つい最近、バージョン0.3.0をリリースしましたが、現在では画像操作ライブラリに期待されるほとんどの基本的な操作が含まれています。
Perspectraで最初に実装した適応二値化やコーナー検出などの、より高レベルのCV操作の一部も移植しました。
FlatCVのパフォーマンスを改善する機会はまだたくさんあります(SIMD、GPU使用、ストリーム処理など)。
しかし、FlatCVはリアルタイムコンテキスト(つまり60fps)で使用されないため、パフォーマンスはすでに十分以上です。
FlatCVを導入したことで、1.0の最後の欠けていたピース、Perspecでの自動コーナー検出を最終的に実装することができました。
エッジ検出対コーナー検出
ほとんどのスキャナーアプリは、Dropboxが説明しているパイプラインに沿ってドキュメントを検出します。
画像を縮小する
エッジ検出アルゴリズム(例:Canny)を実行する
Hough変換を使用して最も顕著な直線を見つける
それらの交点から四角形を構築し、スコアリングして最良のものを選ぶ
これは完璧なものにはうまく機能します