Intelが開発元のオープンソースのコンピュータビジョンソフトウェアOpenCVで物体検出、エッジ検出など前処理、ヒューレットパッカードが開発元、オープンソースになった後、Googleが後援しているとされる光学式文字認識ソフトTesseract OCRとPythonスクリプトで7セグ表示LCDを解読してみた話。
7セグの読み取りには、英語や日本語などと同様、デジタル文字用の学習(済み)データが必要となり、自作する手もありますが、今回は、[letsgodigital.traineddata]を入手(どこが正規の入手先か不明...)、これを[/usr/share/tesseract-ocr/4.00/tessdata/]以下に配置して検証してみました。
ビギナーズラックで、たまたま、最初に撮影・投入したデジタル時計の盤面を読めてしまったのですが、その後の画像投入では一向にうまく行かず、入力画像というか、編集画像に求められる条件がかなり厳しいものであることを思い知らされました。
が、最初に成功体験できたのは、かなりラッキーで、以後のモチベーション維持のためにも、かなり、ありがたかったです。
とは言え、背景のある中に置いた遠巻きのデジタル時計から始め、続いてアップ、限りなく盤面、かつ、限りなく正面、かつ、照明具合の調整、かつ、できる限り映り込みを避けるべく...といったような自ずと芽生えて意識していった試行錯誤は、当然ながらありましたし、それを知って以後も、2度めの成功体験はできないままに試行錯誤していますが。
今のところ、唯一、成功したのは、デジタル時計(時:分)、年月の数値、曜日アイコン、温度、湿度、タイマー時間などを一覧できるダイソーで550円の温湿度計付デジタル時計のデジタル時計部分の「時」と「分」の値の読み取り。
ダイソーでこの置き時計を買った翌日、時計表示(1-12)通り、2022年12月01日の当日、確か1時間程度で成功したのですが、記事を書くのが億劫で塩漬け、ページ立てをどうしようか思案、ようやく重い腰を上げたのが今日という次第。
ちなみに、なぜ、ダイソーの時計かというと電子工作・IoT関連商品としての100円ショップグッズというページのくくりが崩れつつある中、関係ないじゃん的な商品を無理矢理にでも、そのくくりに収められないか...これは、その一環になるのではと思った末の衝動。
最終的には、
か、
といったカメラサーバ+USBカメラやIPカメラで
のように保存した画像内の一部である時計などからOCRで読み取るのが目標。
夜間は別としても、高性能なカメラでないと厳しいのか、そこそこのカメラでもアングルを固定し、ライティングなどを工夫すればいけるのか...。
さておき、Tesseract OCRでは日本語用学習済みデータもリポジトリから(Raspberry Pi 400パソコン/Raspberry Pi OSなのでaptで)インストールしましたが、数値しか扱わないので、ここではデフォルトが英語のtesseract-ocrパッケージのみインストール。
また、pipでopencv-python、pyocr、pytesseractもインストールしました。
尚、Pythonのバージョンは3.9.2、pipバージョンは20.3.4(Python3.9)、opencv-pythonバージョンは4.6.0.66です。
which -a tesseractしてバイナリがあれば、pythonインタプリタでimport cv2してプロンプトが返ってくれば、OpenCV、Tesseract OCRのインストールはできています。
また、7セグ解析のベースとなるデジタル数字やデジタル記号を含む学習済みデータ[letsgodigital.traineddata]を[/usr/share/tesseract-ocr/4.00/tessdata/](4.00はバージョン)以下に移動なりコピーなりしておきます。
今にして思えば、よくこれを使おうと思ったなって感じで、結構歪みがありますが、オリジナル画像として使った写真はこれ。
今の知識では微調整しきれず、僅かなノイズも含めれば、時刻の他に温湿度の[18]や[55]、月日の[1]、[12]も取れたのですが、ここでは、ノイズなしで取得できた時刻[14:31]の内の[1431]を取得する前提で話を進めます。
pythonスクリプトがこれ。
グレースケールとガウシアンぼかし、二値化(にもthreshold()の他、adaptiveThreshold()や大津の二値化などもありますが)あたりは、ノイズを低減させる、処理を軽くするといった効果も含め、下準備として基本中の基本っぽいです。
最初、何をしても常に"No OCR tool found"となるのはなんでだろ?と思ったら、なんのことはない、tesseract-ocrをインストールしていなかったというオチでした。
エッジ検出に照明の当たり具合の影響を受けにくいとされるCanny()を使ったり、認識文字を線で囲うべく、findContours()やdrawContours()を使うこともできますが、ここでは使っていません。
tool.image_to_string()に対象画像ファイル、言語としてletsgodigital(.traineddata)、どのように認識するかの値を指定したpyocr.builders.TextBuilder(tesseract_layout=6)を渡すと取得した値を返してくれます。
結果、当該pythonスクリプトを実行すると時・分の値[1431]と読み取ることができました。
最後に、このpythonスクリプトにおける各処理後の画像を掲載しておきます。
再掲ですがオリジナル。
グレースケール・グレー化・白黒化後。
ガウシアンぼかし後。
threshold()による二値化後。
ノイズ処理としてモルフォロジー変換後。
ビット反転後。
これで認識できるんですね、人間の見た目による認識とTesseract OCRの認識における判断基準は、必ずしも一致しないようです。
むしろ、他をできるだけ排除できたから、残りを検出できたみたいな感じでしょうか?
今回は、こんな傾いた写真でいけましたが、きっと台形補正など、他にも前処理をしておかないと数字・文字認識できないケースの方が多いことでしょう。
今後、もっと極められたらと思います。