0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

TesseractとSympyを使って画像から方程式を認識して解を求める

Posted at

概要

この記事では、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. 認識する画像

以下のサイトにある画像を使って、方程式の解を求めます。
equation1.png

コード

用意した画像を読みこんで、方程式の解を求める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の数式を比較演算子 = で分割し、左右の部分(lhsrhs)に分けます。
    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 = 53*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 = 解 の形式に整形しています。

実行結果

output_linearequation1.png
画像から一次方程式を認識し、方程式の解を求めることができました。

終わりに

今回、TesseractとPythonを使って数式を認識し、計算する方法について解説しました。WEBカメラで手書きの数式を読みこみや2次方程式の二乗も認識されるのか試してみたいと思います。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?