1
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?

画像に映っている物の長さを知りたい!

1
Posted at

撮影した写真に写っている物の長さを測る

1.任意の2点の長さを参考に,
2.知りたい2点間長さを表示する

Pythonプログラムを示す.

<実行手順>

1.VSCodeを起動して,measure_length_GUI.py を作成

2.VSCodeのpowershellにて,以下のコマンドを実行
  例:(base) PS C:/measure_pixel/measure_length_GUI.py

3.ダイアログボックスが表示されるので,任意の画像ファイルを選択

4.基準となる長さの定義
下の図で,右上の2点(長さが分かっている)を選択して,
VSCodeのターミナル欄に,例:100 cm と入力する.

5.測定したい長さの2点を選択
オープンされた画像の距離を知りたい2点を選択

すると,先の参考長さ100cmをベースにピクセル換算された
測定したい2点間長さが表示される.
(下図の例では,113.19cm)

画像内距離の算出.png

measure_length_GUI.py
import cv2
import numpy as np
import tkinter as tk
from tkinter import filedialog

def select_image_file():
    root = tk.Tk()
    root.withdraw()  # Tk ウィンドウを表示しない

    file_path = filedialog.askopenfilename(
        title="画像ファイルを選択してください",
        filetypes=[
            ("画像ファイル", "*.png;*.jpg;*.jpeg;*.bmp"),
            ("PNG", "*.png"),
            ("JPEG", "*.jpg;*.jpeg"),
            ("BMP", "*.bmp"),
            ("すべてのファイル", "*.*")
        ]
    )
    return file_path

def main():
    # --- 画像ファイル選択ダイアログ ---
    img_path = select_image_file()
    if not img_path:
        print("画像が選択されませんでした")
        return

    img = cv2.imread(img_path)
    if img is None:
        print("画像が読み込めませんでした")
        return

    disp = img.copy()
    points = []
    scale = None  # px → cm 換算係数

    def mouse_callback(event, x, y, flags, param):
        nonlocal points, disp, scale

        if event == cv2.EVENT_LBUTTONDOWN:
            points.append((x, y))
            cv2.circle(disp, (x, y), 4, (0, 0, 255), -1)

            # --- 1回目の2点:スケール測定 ---
            if len(points) == 2 and scale is None:
                (x1, y1), (x2, y2) = points
                px_len = ((x2 - x1)**2 + (y2 - y1)**2) ** 0.5
                print(f"基準寸法のピクセル長: {px_len:.2f} px")

                # 実寸(cm)をユーザーに入力させる
                real_cm = float(input("この長さは何 cm ですか? → "))

                scale = real_cm / px_len
                print(f"スケール設定完了: 1 px = {scale:.5f} cm")

                cv2.line(disp, (x1, y1), (x2, y2), (0, 255, 0), 2)
                cv2.putText(disp, f"{real_cm:.2f} cm",
                            (x1, y1 - 10), cv2.FONT_HERSHEY_SIMPLEX,
                            0.6, (255, 255, 255), 2)

                points = []

            # --- 2回目の2点:長さ測定 ---
            elif len(points) == 2 and scale is not None:
                (x1, y1), (x2, y2) = points
                px_len = ((x2 - x1)**2 + (y2 - y1)**2) ** 0.5
                cm_len = px_len * scale

                print(f"距離: {px_len:.2f} px  →  {cm_len:.2f} cm")

                cv2.line(disp, (x1, y1), (x2, y2), (0, 255, 255), 2)
                cv2.putText(disp, f"{cm_len:.2f} cm",
                            (x1, y1 - 10), cv2.FONT_HERSHEY_SIMPLEX,
                            0.6, (255, 255, 255), 2)

                points = []

    cv2.namedWindow("my_picture")
    cv2.setMouseCallback("my_picture", mouse_callback)

    while True:
        cv2.imshow("my_picture", disp)
        key = cv2.waitKey(20) & 0xFF

        # ウィンドウが閉じられたら終了
        if cv2.getWindowProperty("my_picture", cv2.WND_PROP_VISIBLE) < 1:
            break

        if key == ord('q'):
            break

        if key == ord('r'):
            disp = img.copy()
            points = []
            scale = None
            print("リセットしました")

    cv2.destroyAllWindows()

if __name__ == "__main__":
    main()
1
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
1
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?