概要
この記事では、OCRエンジン「Tesseract」を使って、画像から数式を認識し、数式計算ライブラリであるSympyを使って方程式の解を解く方法について紹介します。Pythonを使った手順も含め、数式認識から計算までの流れを詳しく説明します。
動作環境
Ubuntu 22.04 LTS
Python 3.10
pytesseract 0.3.13
事前準備
1. Tesseractのインストール
Tesseractとは、Googleが開発したオープンソースの光学文字認識OCR(Optical Character Recognition)ライブラリです。
参考サイト
https://pypi.org/project/pytesseract/
pip install pytesseract
2. 関連のライブラリのインストール
Pythonで画像処理を行うためのパッケージであるOpenCVとPillowをインストールします。
sudo apt-get install python3-opencv
pip install pillow
数式計算を行うライブラリSympyもインストールします。画像から数字と演算子を認識したあとに、Sympyを使って方程式を計算します。
pip install sympy
3. 認識する画像
コード
用意した画像を読みこんで、方程式の解を求めるPythonプログラムです。
全体コードのあとに、それぞれのコードの役割について解説します。
import pytesseract
from PIL import Image
import cv2
import sympy as sp
import re
# 画像を読み込む
image_path = '/home/folder/equation1.png' # ここを画像のパスに変更
image = cv2.imread(image_path)
# 画像をRGBに変換(OpenCVはBGRを使用するため)
image_rgb = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
# Tesseractを使用して画像内の数式をOCRで読み取る(数式設定を使用)
text = pytesseract.image_to_string(image_rgb, config='--psm 7', lang='eng+equ')
# 認識したテキストを整形
equation = text.strip().replace(' ', '') # スペースを除去
print(f"認識された数式: {equation}")
# 必要に応じて掛け算記号(*)を挿入(例: '2x'を '2*x'に変更)
equation = re.sub(r'(\d)([a-zA-Z])', r'\1*\2', equation)
print(f"修正された数式: {equation}")
# 解の変数を初期化
solution_text = ""
# 数式に'x'が含まれているかチェック(含まれている場合は1次方程式とみなす)
if 'x' in equation:
# SymPyで使用するシンボル'x'を定義
x = sp.symbols('x')
# SymPyは数式を '左辺 = 右辺' の形式で扱うため、数式を分割
lhs, rhs = equation.split('=')
# 左辺と右辺をSymPy式に変換
lhs_expr = sp.sympify(lhs)
rhs_expr = sp.sympify(rhs)
# 方程式を解き、'x'の解を得る
solution = sp.solve(lhs_expr - rhs_expr, x)
# 画像に重ねるための解のテキストを準備
solution_text = f"x = {solution[0]}"
print(f"xの解: {solution}")
else:
print("方程式に変数'x'が見つかりません。")
# 認識した数式と解を画像に重ねる
output_image = image.copy()
# フォント、サイズ、色、位置の設定
font = cv2.FONT_HERSHEY_SIMPLEX
font_scale = 0.7 # 小さめのフォントサイズ
font_color = (255, 0, 0) # 青色(BGR形式)
font_thickness = 1 # 細めのフォント太さ
line_type = cv2.LINE_AA
# テキストの位置(座標を調整可能)
equation_position = (50, 50)
solution_position = (50, 100)
# 認識した数式と解を画像に重ねる
cv2.putText(output_image, f"認識された数式: {equation}",
equation_position, font, font_scale, font_color, font_thickness, line_type)
cv2.putText(output_image, f"解: {solution_text}",
solution_position, font, font_scale, font_color, font_thickness, line_type)
# 出力画像を保存
output_path = 'output_linearequation1.png'
cv2.imwrite(output_path, output_image)
print(f"出力画像が {output_path} として保存されました")
コードの解説
ライブラリのインポート
import pytesseract
from PIL import Image
import cv2
import sympy as sp
import re
画像の読み込み
image = cv2.imread(image_path)
指定したディレクトリから画像を読み込みます
OCRによる数字と演算子の認識
text = pytesseract.image_to_string(image_rgb, config='--psm 7', lang='eng+equ')
pytesseract
で画像から文字(数字や記号等)抽出し、英語(eng
)と数字(equ
)を認識します。
数式の整形
equation = text.strip().replace(' ', '')
strip()
を用いて 文字列の前後にある空白や改行文字を取り除き、.replace(' ', '')
を用いて文字列内のすべてのスペース(半角スペース)を取り除きます。
例えば、OCRで読み取った数式が 3 x + 2 = 5
だった場合、余計なスペースが除去され、数式は 3x+2=5
という形式に変換されます。
演算子(掛け算記号)の挿入
equation = re.sub(r'(\d)([a-zA-Z])', r'\1*\2', equation)
OCRで読み取った3x+2=5
をSympyを用いて方程式の解を求めるとエラーが発生します。そこで3とxの間に掛け算を明示することで、計算可能な形式に変換します。
方程式の解の算出
if 'x' in equation: # 読みこんだ数式に変数 `x` が含まれているかをチェック
x = sp.symbols('x') #変数xとして定義
lhs, rhs = equation.split('=') #左辺、右辺の定義
lhs_expr = sp.sympify(lhs)
rhs_expr = sp.sympify(rhs)
solution = sp.solve(lhs_expr - rhs_expr, x)
solution_text = f"x = {solution[0]}"
各行で何を行っているか解説します。
- 変数xの定義
数式に が含まれていれば、SymPy のsymbols
関数を使って、変数を x として定義します。
2x = sp.symbols('x')
- 左辺、右辺の分割
equationの数式を比較演算子=
で分割し、左右の部分(lhs
とrhs
)に分けます。
lhs
は左辺(left-hand side)、rhs
は右辺(right-hand side)を表しています。
lhs, rhs = equation.split('=')
- 文字列から数式オブジェクトの変換
sympify
関数を使って、文字列lhs
を SymPy の数式(式)オブジェクトに変換します。
これにより、数式をPythonの文字列ではなく、数式としての操作が可能な SymPy のオブジェクトとして扱えるようになります。rhs(右辺)も同様に SymPy の数式オブジェクトに変換します。
これで、左右の辺が数式として扱えるようになり、演算や計算が可能になります。
lhs_expr = sp.sympify(lhs)
rhs_expr = sp.sympify(rhs)
- 方程式の計算
solution = sp.solve(lhs_expr - rhs_expr, x)
lhs_expr - rhs_expr
は、等式を lhs = rhs
から lhs - rhs = 0
の形に変形しています。例えば、3*x + 2 = 5
は 3*x + 2 - 5 = 0
と変形できます。
sp.solve
関数を使用して、この方程式を x
について解きます。
solution
には、x の解がリスト形式で返されます。たとえば、解が x = 1 なら、solution には [1] が格納されます。
solution_text = f"x = {solution[0]}"
solution の最初の解を solution[0]
で取得し、solution_text という文字列にフォーマットして代入します。
f"x = {solution[0]}"
では、解が見やすい形式で出力されるように、文字列として x = 解 の形式に整形しています。
実行結果
画像から一次方程式を認識し、方程式の解を求めることができました。
終わりに
今回、TesseractとPythonを使って数式を認識し、計算する方法について解説しました。WEBカメラで手書きの数式を読みこみや2次方程式の二乗も認識されるのか試してみたいと思います。