質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.35%
NumPy

NumPyはPythonのプログラミング言語の科学的と数学的なコンピューティングに関する拡張モジュールです。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

Q&A

解決済

2回答

1988閲覧

線分とその線分上の点から垂線をひき、曲線との長さを求める方法

totoro33

総合スコア1

NumPy

NumPyはPythonのプログラミング言語の科学的と数学的なコンピューティングに関する拡張モジュールです。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

0グッド

0クリップ

投稿2021/10/09 17:04

編集2021/10/10 01:24

前提・実現したいこと

下の画像の青い線の長さをそれぞれ求めたいです。
イメージ説明
知恵を貸していただけると幸いです。

ここに質問の内容を詳しく書いてください。
研究で心機能評価のための指標を算出しようとしています。その際、2値化された白い輪郭線をもとに青い線の長さを求める必要があります。
実際に手元にある画像は下のような画像で
①.一番下の直線の中点(点ABの中点)を求める
②.①で求めた中点から輪郭線上でもっとも離れた点(点C)を検出し、座標を求める。
③.①で求めた中点と点Cを結ぶ線分を20等分し、20個の領域に分ける。
④.20等分した点それぞれから線分に直交する線(青い線)を引きそれぞれの長さを求める。
イメージ説明

発生している問題・エラーメッセージ

現状、
①②③はできています。
具体的には
①.直線検出(cv2.HoughlinesP)し、端点AとBの座標を求めた上で中点の座標を整数値として求める
②.①で求めた点から各輪郭点までのユークリッド距離を求め最大のものを点Cとする
③.np.linspaceで分割
です。

分割後の各点から垂線を引く方法と垂線と輪郭線との交点の座標を取得する方法がわからず試行錯誤しています。

コード #モジュールのインポート import cv2 import matplotlib.pyplot as plt %matplotlib inline import numpy as np import math #最大輪郭を得る関数 def find_max_contour(img): contours, _ = cv2.findContours( img, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE ) max_contour = max(contours, key=lambda x:cv2.contourArea(x)) return max_contour # 画像の読み込み img = cv2.imread("opening2.png", 0) color = cv2.cvtColor(img, cv2.COLOR_GRAY2BGR) lines = cv2.HoughLinesP(img, rho=1, theta=np.pi/360, threshold=80, minLineLength=80, maxLineGap=10) # 複数の直線がある場合、y座標の和がもっとも大きいものを採用 # 中点(mid_x, mid_y) y_sum_dict = {} for i, pos in enumerate(lines.squeeze(1)): y1, y2 = pos[1], pos[3] y_sum_dict[i] = y1 + y2 index = 0 y_sum_max = 0 for i, y_sum in y_sum_dict.items(): if i == 0: index = i y_sum_max = y_sum else: if y_sum_max < y_sum: y_sum_max =y_sum index = i pos = lines.squeeze(1)[index] x1, y1, x2, y2 = pos[0], pos[1], pos[2], pos[3] print(x1, y1, x2, y2) mid_x, mid_y = int((x1+x2)/2), int((y1+y2)/2) print(mid_x, mid_y) # 全ての輪郭上の点に対してユークリッド距離を計算する方針 def get_distance(x1, y1, x2, y2): d = math.sqrt((x2 - x1) ** 2 + (y2 - y1) ** 2) return d # 中点から最大距離の点を見つける(api_x, api_y) dist_list = [] for point in max_cnt.squeeze(1): x, y = point[0], point[1] dist = get_distance(mid_x, mid_y, x, y) dist_list.append(dist) max(dist_list) max_dist_index = dist_list.index(max(dist_list)) apical = max_cnt.squeeze(1)[max_dist_index] api_x, api_y = apical[0], apical[1] # 20等分する lins = np.linspace((api_x, api_y), (mid_x, mid_y), 21)

試したこと

ベクトルの内積から垂線をひけるのではないかと考えましたが、その実装ができていません。

補足情報(FW/ツールのバージョンなど)

ここにより詳細な情報を記載してください。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2021/10/09 21:26

できているところまでのコードを掲載しないと「回答者が全部書け」というように見えてしまいますし、そうすると「丸投げしようとしている質問」扱いされてマイナス査定、結局Teratailから事実上「この質問は丸投げだから放っておいてくれ」扱いのコメントがつけられかねません。 できたところまでのコードを掲載してください。
guest

回答2

0

まずは、あなたが手でその線分の垂線を引く場合にどうするのかを考えましょう
その方法をきっちり言語化し、そのとおりにコードを組んでいけばいいです

投稿2021/10/10 01:51

y_waiwai

総合スコア88042

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

totoro33

2021/10/10 02:56

おっしゃる通りで、実際に自分が計算するならベクトル同士の内積=0だと気づけました。 ご指摘ありがとうございます。
guest

0

ベストアンサー

  • 分割後の各点から垂線を引く方法と垂線と輪郭線との交点の座標を取得する方法がわからず試行錯誤しています。

分割後の点の一つをPとします。また、cv2で検出した輪郭をcontoursをすると、要素は一つだけになるので、contours[0]が輪郭を示す多角形となります。
この多角形の各頂点Qについて、PCとPQの内積を全て取ると、Pが図形のない点であるために、内積は正の値から負の値まで変化します。ゼロになる点があれば、それが垂線と輪郭の多角形の交点です。0が見つからないときは、内積が負から正に変わる点か内積が負から正に変わる点がありますので、そこを線形補完して0になる座標を求めてください。
こうやって見つけた内積の値がゼロになる二つの点が求めるものです。

contoir[0]のshapeは(N,1,2)でNが頂点の数、2がx座標とy座標ですから、(N,2)にreshapeしておけば、内積の列を求めるのはfor文を使わずに高速にできます。

投稿2021/10/10 00:35

ppaul

総合スコア24670

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

totoro33

2021/10/10 02:54

dot = np.dot(array, line_array) で内積計算をした後に np.argmin(np.abs(dot)) で絶対値が最小となるインデックスを求めることができました! ありがとうございます。 今まで多くのデータの処理をしてこなかったのでfor文を書きまくっていたのですが、内積でやるということも教えていただきありがとうございます。本当に実力不足なのでもっと勉強していこうと思います。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.35%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問