気の向くままに辿るIT/ICT
ソフトウェア

OpenCV/Tesseractで7セグLCD値を読んでみる

ホーム前へ次へ
フリーソフト・オープンソースを活用しよう。

OpenCV/Tesseractで7セグLCD値を読んでみる

OpenCV/Tesseractで7セグLCD値を読んでみる

2022/12/11

 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で読み取るのが目標。

 夜間は別としても、高性能なカメラでないと厳しいのか、そこそこのカメラでもアングルを固定し、ライティングなどを工夫すればいけるのか...。

debian~:$ sudo apt install tesseract-ocr
debian~:$ pip install opencv-python pyocr pytesseract
...
debian~:$ python -V
Python 3.9.2
debian~:$ pip -V
pip 20.3.4 from /usr/lib/python3/dist-packages/pip (python 3.9)
debian~:$ pip list | grep opencv-python
opencv-python 4.6.0.66
debian~:$

 さておき、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です。

debian~:$ which -a tesseract
/usr/bin/tesseract
/bin/tesseract
debian~:$ python
Python 3.9.2 (default, Feb 28 2021, 17:03:44)
[GCC 10.2.1 20210110] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import cv2
>>>
(Ctrl + D)
debian~:$

 which -a tesseractしてバイナリがあれば、pythonインタプリタでimport cv2してプロンプトが返ってくれば、OpenCV、Tesseract OCRのインストールはできています。

debian~:$ sudo mv ~/Downloads/letsgodigital.traineddata /usr/share/tesseract-ocr/4.00/tessdata/
debian~:$

 また、7セグ解析のベースとなるデジタル数字やデジタル記号を含む学習済みデータ[letsgodigital.traineddata]を[/usr/share/tesseract-ocr/4.00/tessdata/](4.00はバージョン)以下に移動なりコピーなりしておきます。

デジタル時計盤面

 今にして思えば、よくこれを使おうと思ったなって感じで、結構歪みがありますが、オリジナル画像として使った写真はこれ。

 今の知識では微調整しきれず、僅かなノイズも含めれば、時刻の他に温湿度の[18]や[55]、月日の[1]、[12]も取れたのですが、ここでは、ノイズなしで取得できた時刻[14:31]の内の[1431]を取得する前提で話を進めます。

debian~:$ cat ~/ocr/cv_ocr_test.py
#!/usr/bin/python3
 
from pytesseract import pytesseract
import sys
import cv2
import pyocr
import numpy as np
from PIL import Image
 
pytesseract.tesseract_cmd = "/usr/bin/tesseract"
 
image = "orig/clock.png"
name = "clock"
 
# オリジナル画像
img = cv2.imread(image)
 
# 白黒画像(グレー)化
img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
cv2.imwrite(f"1_{name}_gray.png",img)
 
# ガウシアンぼかしフィルタ
img = cv2.GaussianBlur(img, (5, 5), 0)
cv2.imwrite(f"2_{name}_gaussian.png",img)
 
# しきい値による二値(バイナリ)化
th = 97
img = cv2.threshold(
  img
  , th
  , 255
  , cv2.THRESH_BINARY
)[1]
cv2.imwrite(f"3_{name}_threshold_{th}.png",img)
 
# ノイズ処理(モルフォロジー変換)
kernel = np.ones((5,5),np.uint8)
img = cv2.morphologyEx(img, cv2.MORPH_OPEN, kernel)
cv2.imwrite(f"4_{name}_kernel.png",img)
 
# ビット反転
img = cv2.bitwise_not(img)
cv2.imwrite(f"5_{name}_bitwise.png",img)
 
# 一応別名でも保存
cv2.imwrite("target.png",img)
 
# OCRツール存在確認
tools = pyocr.get_available_tools()
if len(tools) == 0:
  print("No OCR tool found")
  sys.exit(1)
 
# 1つめのOCRツールを使用
tool = tools[0]
 
# イメージ-文字列変換
res = tool.image_to_string(Image.open("target.png"),lang="letsgodigital", builder=pyocr.builders.TextBuilder(tesseract_layout=6))
 
# 結果出力
print(res)

 pythonスクリプトがこれ。

 グレースケールとガウシアンぼかし、二値化(にもthreshold()の他、adaptiveThreshold()や大津の二値化などもありますが)あたりは、ノイズを低減させる、処理を軽くするといった効果も含め、下準備として基本中の基本っぽいです。

 最初、何をしても常に"No OCR tool found"となるのはなんでだろ?と思ったら、なんのことはない、tesseract-ocrをインストールしていなかったというオチでした。

 エッジ検出に照明の当たり具合の影響を受けにくいとされるCanny()を使ったり、認識文字を線で囲うべく、findContours()やdrawContours()を使うこともできますが、ここでは使っていません。

 tool.image_to_string()に対象画像ファイル、言語としてletsgodigital(.traineddata)、どのように認識するかの値を指定したpyocr.builders.TextBuilder(tesseract_layout=6)を渡すと取得した値を返してくれます。

debian~:$ chmod +x ~/ocr/cv_ocr_test.py
debian~:$ cd ~/ocr
debian~:$ ./cv_ocr_test.py
1431
debian~:$

 結果、当該pythonスクリプトを実行すると時・分の値[1431]と読み取ることができました。

 最後に、このpythonスクリプトにおける各処理後の画像を掲載しておきます。

デジタル時計盤面

 再掲ですがオリジナル。

デジタル時計盤面のグレー・白黒化後

 グレースケール・グレー化・白黒化後。

デジタル時計盤面のガウシアンぼかし後

 ガウシアンぼかし後。

デジタル時計盤面のthreshold()による二値化後

 threshold()による二値化後。

デジタル時計盤面のグレー・白黒化後

 ノイズ処理としてモルフォロジー変換後。

デジタル時計盤面のビット反転後

 ビット反転後。

 これで認識できるんですね、人間の見た目による認識とTesseract OCRの認識における判断基準は、必ずしも一致しないようです。

 むしろ、他をできるだけ排除できたから、残りを検出できたみたいな感じでしょうか?

 今回は、こんな傾いた写真でいけましたが、きっと台形補正など、他にも前処理をしておかないと数字・文字認識できないケースの方が多いことでしょう。

 今後、もっと極められたらと思います。

ホーム前へ次へ