画像ファイルのグラフをPythonで数値として読み取りたい
何かDIYなどで工作する時,部品カタログを見ますよね.
そのpdfファイルは容易にWebからダウンロードできたりします.
ドキュメントの中に,製品の仕様を示すグラフが掲載されていたりするのですが,性能などを計算するのに数値データとして欲しい場面がたくさんあります.
<グラフサンプル>
この画像ファイル(graph.jpg)から,数値データとしてゲットできないかなと思って,Pythonプログラムを試してみることにしました.
残念ながら,このプログラムでは,グラフの数値をうまく取得することができなかった.
引き続き,別のやり方を探っていこうと思っているので,今後のために,うまく取得できなかったプログラムや結果も残しておこうと思い,記事にしました.
強調
read_graph.py
# -*- coding: utf-8 -*-
import cv2
import numpy as np
from matplotlib import pyplot as plt
import japanize_matplotlib



# 画像の読み込み
image_path = 'graph.jpg'
image = cv2.imread(image_path, cv2.IMREAD_GRAYSCALE)
if image is None:
print("Error: 画像が見つかりません。パスを確認してください。")
else:
print("画像が正常に読み込まれました。")
# エッジ検出を使用してグリッド線と外枠を検出
edges = cv2.Canny(image, 50, 150)
# 垂直線と水平線を検出
lines = cv2.HoughLinesP(edges, 1, np.pi / 180, threshold=100, minLineLength=100, maxLineGap=10)
mask = np.ones_like(image) * 255
if lines is not None:
for line in lines:
x1, y1, x2, y2 = line[0]
cv2.line(mask, (x1, y1), (x2, y2), 0, 2) # グリッド線と外枠を黒で描画
# グリッド線と外枠を削除した画像を作成
image_without_grid = cv2.bitwise_and(image, mask)
# 画像の前処理(ノイズ除去)
blurred = cv2.GaussianBlur(image_without_grid, (3, 3), 0)
_, threshold = cv2.threshold(blurred, 150, 255, cv2.THRESH_BINARY_INV)
# 輪郭の検出
contours, _ = cv2.findContours(threshold, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
# トルク曲線部分のデータポイントの抽出
torque_points = []
for contour in contours:
# 輪郭の周囲の長さを計算
perimeter = cv2.arcLength(contour, True)
approx = cv2.approxPolyDP(contour, 0.02 * perimeter, True)
# 曲線部分を判定するために頂点数が多いものを選択
if len(approx) > 5 and cv2.contourArea(contour) < 1000: # 閾値を調整
# 指定されたx軸、y軸範囲内の点のみを抽出
for point in contour:
x, y = point[0]
if 500 <= x <= 6500 and 95 <= y <= 155:
# 赤色の曲線を無視(色判定は実装が難しいため、位置情報で判定)
if (x + y) % 2 != 0: # 例として偶数座標を無視
torque_points.append((x, y))
# x, y座標のリストとして表示
torque_x_coords = [point[0] for point in torque_points]
torque_y_coords = [point[1] for point in torque_points]
print("Torque Curve X座標:", torque_x_coords)
print("Torque Curve Y座標:", torque_y_coords)
# オリジナルの画像を表示
plt.figure(figsize=(10, 6))
plt.imshow(image, cmap='gray')
plt.title('Original Image')
plt.grid(False)
plt.show()
# 抽出したトルク曲線を表示
plt.figure(figsize=(10, 6))
plt.scatter(torque_x_coords, torque_y_coords, color='blue', marker='o', label='Torque Curve')
plt.title('Scatter Plot of Extracted Torque Curve (Ignoring Grid Lines and Outline)')
plt.xlabel('X座標')
plt.ylabel('Y座標')
plt.legend()
plt.grid(True)
plt.show()
noteの記事に書きましたが,
やはり,こういった自分でグラフをなぞるといった一手間をかまさないと
OCR的に値を取得するのは難しいのでしょうか...
今後も,細々と改良を検討していこうと思っています...