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

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

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

OpenCV(オープンソースコンピュータービジョン)は、1999年にインテルが開発・公開したオープンソースのコンピュータビジョン向けのクロスプラットフォームライブラリです。

Python

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

Q&A

解決済

2回答

1530閲覧

条件文での比較のエラー

uriuri

総合スコア47

OpenCV

OpenCV(オープンソースコンピュータービジョン)は、1999年にインテルが開発・公開したオープンソースのコンピュータビジョン向けのクロスプラットフォームライブラリです。

Python

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

0グッド

0クリップ

投稿2018/09/12 08:51

編集2018/09/13 11:09

イメージ説明
リスト

緑色の矩形内に赤い直線がある場合,白い線としたいと思っています

そこで矩形の頂点(a,b,c,d)の4点と直線の両端(X1,X2)の座標を求め、
条件文で矩形の座標間にX1,X2があった場合を行いたいのですが

頂点 a[170 113] b[167 57] c[317 50] d[319 105]
X1 (263.29733, 104.87856)
X2 (256.93668, 107.05521)
X1 (318.125, 104.85714)
X2 (264.37497, 104.85878)
X1 (256.87796, 107.75887)
X2 (224.3598, 107.49466)
X1 (241.82504, 109.3887)
X2 (318.10205, 106.30674)
X1 (225.59557, 110.03477)
X2 (239.43582, 109.34441)



Traceback (most recent call last):
File "○○○.py", line 101, in <module>
if a < X1 < b:
ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()

というエラーがでてしまいます
これは条件文に対してX1がどの値かが明確ではないため起こる問題であっていますでしょうか
この場合条件文で比較するためのアドバイスをいただけたら幸いです

python

1import cv2 2import math 3import numpy as np 4 5img_src = cv2.imread("./haku/sample/image1.ppm") 6 7gauss = cv2.GaussianBlur(img_src,(11,11),0)#9,9 8gray = cv2.cvtColor(gauss,cv2.COLOR_BGR2GRAY) 9ret,th1 = cv2.threshold(gray,200,255,cv2.THRESH_BINARY) 10edges = cv2.Canny(th1,50,150)#(100,150) 11 12#矩形検出 13img, contours, hierarchy = cv2.findContours(th1, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_TC89_L1) 14if len(contours) > 0: 15 for i in range(0, len(contours)): 16 cnt = contours[i] 17 M = cv2.moments(cnt) 18 #print(M) 19 area = cv2.contourArea(cnt) 20 print(area) 21 if 500 < area < 5000: 22 rect = cv2.minAreaRect(contours[i]) 23 box = cv2.boxPoints(rect) 24 box = np.int0(box) 25 x1,x2,x3,x4 = np.int0(box) 26 a = np.array(x1) 27 b = np.array(x2) 28 c = np.array(x3) 29 d = np.array(x4) 30 31 A = np.linalg.norm(a-b) 32 B = np.linalg.norm(a-c) 33 C = np.linalg.norm(a-d) 34 35 print("頂点",x1,x2,x3,x4) 36 #print("abcd", a,b,c,d) 37 #print("Aの長さ", A) 38 #print("Bの長さ",B) 39 #print("Cの長さ",C) 40 41 if A < B: 42 min = A 43 else: 44 min = B 45 if C < min: 46 min = C 47 print("最小",min) 48 if 5 < min < 25: 49 im = cv2.drawContours(img_src,[box],0,(0,255,0),2) 50 51#直線検出 52LSD = cv2.createLineSegmentDetector() 53lines, width, prec, nfa = LSD.detect(edges) 54if lines is not None: 55 for i in range(len(lines)): 56 57 for x1,y1,x2,y2 in lines[i] : 58 cv2.line(img_src,(x1,y1),(x2,y2),(0,0,255),2) 59 X1 = (x1, y1) 60 X2 = (x2, y2) 61 print("X1", X1) 62 print("X2", X2) 63 64jug1 = cv2.pointPolygonTest(rect, X1, False) 65jug2 = cv2.pointPolygonTest(rect, X2, False) 66print(jug1) 67print(jug2) 68. 69. 70.

コードが見づらくて申し訳ありません

python

1import cv2 2import math 3import numpy as np 4 5img_src = cv2.imread("./haku/sample/image1.ppm") 6 7gauss = cv2.GaussianBlur(img_src,(11,11),0)#9,9 8gray = cv2.cvtColor(gauss,cv2.COLOR_BGR2GRAY) 9ret,th1 = cv2.threshold(gray,200,255,cv2.THRESH_BINARY) 10edges = cv2.Canny(th1,50,150)#(100,150) 11 12 13img, contours, hierarchy = cv2.findContours(th1, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_TC89_L1) 14if len(contours) > 0: 15 for i in range(0, len(contours)): 16 cnt = contours[i] 17 M = cv2.moments(cnt) 18 #print(M) 19 area = cv2.contourArea(cnt) 20 print(area) 21 if 500 < area < 5000: 22 rect = cv2.minAreaRect(contours[i]) 23 box = cv2.boxPoints(rect) 24 box = np.int0(box) 25 x1,x2,x3,x4 = np.int0(box) 26 a = np.array(x1) 27 b = np.array(x2) 28 c = np.array(x3) 29 d = np.array(x4) 30 31 A = np.linalg.norm(a-b) 32 B = np.linalg.norm(a-c) 33 C = np.linalg.norm(a-d) 34 35 print("頂点",x1,x2,x3,x4) 36 #print("abcd", a,b,c,d) 37 #print("Aの長さ", A) 38 #print("Bの長さ",B) 39 #print("Cの長さ",C) 40 41 if A < B: 42 min = A 43 else: 44 min = B 45 if C < min: 46 min = C 47 print("最小",min) 48 if 5 < min < 25: 49 im = cv2.drawContours(img_src,[box],0,(0,255,0),2) 50 51 52def within(line, rect): 53 """line が rect に含まれるかどうか 54 """ 55 p1, p2 = tuple(line[:2]), tuple(line[2:]) 56 # 線の始点と終点が長方形内に含まれるかどうか 57 return cv2.pointPolygonTest(box, p1, False) >= 0 and \ 58 cv2.pointPolygonTest(box, p2, False) >= 0 59 60LSD = cv2.createLineSegmentDetector() 61lines, width, prec, nfa = LSD.detect(edges) 62print(lines.shape) 63lines = np.squeeze(lines) 64 65if lines is not None: 66 for i in range(len(lines)): 67 68 #for x1,y1,x2,y2 in lines[i] : 69 # cv2.line(img_src,(x1,y1),(x2,y2),(0,0,255),2) 70 # X1 = (x1, y1) 71 # X2 = (x2, y2) 72 # print("X1", X1) 73 #print("X2", X2) 74 for line in lines: 75 p1, p2 = tuple(lines[:2]), tuple(line[2:]) 76 if within(line, rect): 77 # 長方形に含まれる場合は赤色で描画 78 cv2.line(img_src, p1, p2, (0, 0, 255), 2) 79 else: 80 # 長方形に含まれない場合は赤色で描画 81 cv2.line(img_src, p1, p2, (255, 0, 0), 2) 82 83 84#cv2.imwrite("teratail.jpg", img_src) 85cv2.imshow('src', img_src) 86cv2.waitKey() 87cv2.destroyAllWindows() 88

修正後

python

1import cv2 2import math 3import numpy as np 4 5img_src = cv2.imread("test.jpg") 6 7gauss = cv2.GaussianBlur(img_src, (11, 11), 0) 8gray = cv2.cvtColor(gauss, cv2.COLOR_BGR2GRAY) 9ret,th1 = cv2.threshold(gray, 200, 255, cv2.THRESH_BINARY) 10edges = cv2.Canny(th1, 50, 150) 11 12img, contours, hierarchy = cv2.findContours(th1, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_TC89_L1) 13for i in range(0, len(contours)): 14#for cnt in contours: 15 cnt = contours[i] 16 area = cv2.contourArea(cnt) 17 #print(area) 18 19 if 500 < area < 5000: 20 rect = cv2.minAreaRect(cnt) 21 box = cv2.boxPoints(rect) 22 23 (cx, cy), (width, height), angle = rect 24 diag = np.linalg.norm([width, height]) 25 #print(width, height, diag) 26 # 161.91236877441406 16.144147872924805 162.715237986 27 28 # 29 A = width 30 B = height 31 C = diag 32 33 if A < B: 34 min = A 35 else: 36 min = B 37 if C < min: 38 min = C 39 print("min", min) 40 if 5 < min < 25: 41 # 42 cv2.drawContours(img_src, [box.astype(int)], -1, (0, 255, 0), 2) 43 44def within(line, rect): 45 46 p1, p2 = tuple(line[:2]), tuple(line[2:]) 47 #print("p1",p1) 48 #print("p2",p2) 49 #print("line",line) 50 return cv2.pointPolygonTest(box, p1, False) >= 0 and \ 51 cv2.pointPolygonTest(box, p2, False) >= 0 52 53LSD = cv2.createLineSegmentDetector() 54lines, width, prec, nfa = LSD.detect(edges) 55if lines is not None: 56 lines = np.squeeze(lines,axis=1) 57 #if lines.dims == 1: 58 # lines = np.expand_dims(lines, axis=0) 59 for line in lines: 60 p1, p2 = tuple(line[:2]), tuple(line[2:]) 61 print("line",line) 62 63 if within(line, rect): 64 65 cv2.line(img_src, p1, p2, (0, 0, 255), 2) 66 #else: 67 68 # cv2.line(img_src, p1, p2, (255, 0, 0), 2) 69 70 71 72cv2.imshow('src', img_src) 73cv2.waitKey() 74cv2.destroyAllWindows() 75

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

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

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

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

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

guest

回答2

0

ベストアンサー

回転してない長方形に点が含まれるかどうかを調べる。

  • 回転していない長方形であれば、点 (x, y) が長方形に含まれるかどうかは、left <= x <= rignt and top <= y <= bottom を満たすかどうかで判断します。
  • 線が含まれるかどうかは始点と終点が両方とも含まれるかどうかで判断します。

提示された四角形に点が含まれるかどうか

  • 上記を満たしていても、四角形内に点が含まれないケースが出てきます。
  • 四角形もポリゴンであるから、ポリゴン内に点が含まれるかどうかを判断するアルゴリズム必要になります。

OpenCV の pointPolygonTest() を使うと簡単にできます。

python

1retval = cv.pointPolygonTest(contour, pt, measureDist)
  • contour: 輪郭の点の一覧。(N, 2) の numpy 配列
  • pt: (x, y) のタプル
  • measureDist: 端点までの距離を計算するかどうか

返り値は、ポリゴンの内側にある場合は正の値、境界線上にある場合は0、外側にある場合は負の値を返します。

  • 線が含まれるかどうかは始点と終点が両方とも含まれるかどうかで判断します。今回の四角形は凸集合なので、始点と終点が含まれることが確認できれば、その間の点もすべてポリゴンに含まれることが保証されます。

サンプルコード

python

1import cv2 2import matplotlib.pyplot as plt 3import numpy as np 4from matplotlib.patches import Polygon 5from matplotlib.lines import Line2D 6 7# 線と長方形を定義 8line0 = np.array([[50, 50], [100, 100]]) 9line1 = np.array([[200, 20], [250, 150]]) 10line2 = np.array([[275, 75], [250, 100]]) 11rect = np.array([[170, 113], [167, 57], [317, 50], [319, 105]]) 12 13def within(line, rect): 14 """line が rect に含まれるかどうか 15 """ 16 p1 = tuple(line[0]) 17 p2 = tuple(line[1]) 18 # 線の始点と終点が長方形内に含まれるかどうか 19 return cv2.pointPolygonTest(rect, p1, False) >= 0 and \ 20 cv2.pointPolygonTest(rect, p2, False) >= 0 21 22 23fig, axes = plt.subplots() 24axes.set_xlim([0, 500]) 25axes.set_ylim([0, 200]) 26# 長方形を描画する。 27axes.add_patch(Polygon(rect, fill=False)) 28for i, line in enumerate([line0, line1, line2]): 29 # 線を描画する。 30 axes.add_line(Line2D(line[:, 0], line[:, 1], c=np.random.rand(3))) 31 axes.text(*line[0], 'line {}'.format(i), fontsize=12) 32 33 if within(line, rect): 34 print('rect contains line {}.'.format(i)) 35 else: 36 print('rect does not contains line {}.'.format(i)) 37 38plt.show()
rect does not contains line 0. rect does not contains line 1. rect contains line 2.

イメージ説明


追記

import cv2 import numpy as np def extract_contour(binary): """2値画像から輪郭を抽出する。 """ # 輪郭を抽出する。 _, contours, _ = cv2.findContours( binary, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_TC89_L1) if not contours: return # 輪郭がない場合 # 面積が最大の輪郭を抽出する。 cnt = max(contours, key=lambda cnt: cv2.contourArea(cnt)) # 輪郭を囲む回転した長方形を取得する。 rect = cv2.boxPoints(cv2.minAreaRect(cnt)) return rect # 画像を読み込む。 img = cv2.imread("test.jpg") # グレースケールにする。 gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # 2値化する。 _, binary = cv2.threshold(gray, 200, 255, cv2.THRESH_BINARY) # 長方形を取得する。 rect = extract_contour(binary) # 回転した長方形を描画する。 _img = img.copy() cv2.drawContours(_img, [rect.astype(int)], -1, (0, 255, 0), 2) def within(line, rect): """line が rect に含まれるかどうか """ p1, p2 = tuple(line[:2]), tuple(line[2:]) # 線の始点と終点が長方形内に含まれるかどうか return cv2.pointPolygonTest(rect, p1, False) >= 0 and \ cv2.pointPolygonTest(rect, p2, False) >= 0 # Canny エッジ検出を行う。 edges = cv2.Canny(binary, 50, 150) # 直線を検出する。 LSD = cv2.createLineSegmentDetector() lines, _, _, _ = LSD.detect(edges) print(lines.shape) # (18, 1, 4) lines = np.squeeze(lines) # 余分な次元削除 # 線が長方形内に含まれるかどうか調べる。 for line in lines: p1, p2 = tuple(line[:2]), tuple(line[2:]) if within(line, rect): # 長方形に含まれる場合は赤色で描画 cv2.line(_img, p1, p2, (0, 0, 255), 2) else: # 長方形に含まれない場合は赤色で描画 cv2.line(_img, p1, p2, (255, 0, 0), 2)

イメージ説明

TypeError: contour is not a numerical tuple について

cv2.pointPolygonTest() の第1引数 contour に渡された値がおかしいというエラーです。
OpenCV の Python ラッパーで contour というものが出てきたら、これは (NumPoints, 2) の numpy 配列です。

実際、値を見てみると、以下のようになっています。
cv2.minAreaRect() で輪郭を囲む回転した長方形の ((中心の x 座標, 中心の y 座標), (長方形の幅, 長方形の高さ), 回転角度) を返すので、これを cv2.boxPoints() で4点の座標からなる輪郭 (contour) に変換しているので、あなたのコード中の rect ではなく、boxを渡さないといけません。

print(rect) # ((177.51132202148438, 77.53165435791016), (161.91236877441406, 16.144147872924805), -19.653823852539062) print(box) # [[103 112] # [ 98 97] # [251 42] # [256 57]]

変更が必要な箇所

jug1 = cv2.pointPolygonTest(rect, X1, False) jug2 = cv2.pointPolygonTest(rect, X2, False)

jug1 = cv2.pointPolygonTest(box, X1, False) jug2 = cv2.pointPolygonTest(box, X2, False)

提示されたコードの修正バージョン

python

1import cv2 2import math 3import matplotlib.pyplot as plt 4import numpy as np 5 6img_src = cv2.imread("sample.jpg") 7 8gauss = cv2.GaussianBlur(img_src, (11, 11), 0) 9gray = cv2.cvtColor(gauss, cv2.COLOR_BGR2GRAY) 10ret,th1 = cv2.threshold(gray, 200, 255, cv2.THRESH_BINARY) 11edges = cv2.Canny(th1, 50, 150) 12img, contours, hierarchy = cv2.findContours(th1, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_TC89_L1) 13 14for cnt in contours: 15 cnt = contours[i] 16 area = cv2.contourArea(cnt) 17 print(area) 18 19 if 500 < area < 5000: 20 rect = cv2.minAreaRect(cnt) 21 box = cv2.boxPoints(rect) 22 23 (cx, cy), (width, height), angle = rect 24 diag = np.linalg.norm([width, height]) 25 print(width, height, diag) 26 # 161.91236877441406 16.144147872924805 162.715237986 27 28 # 長方形の幅、高さ、対角線の長さは cv2.minAreaRect() の返り値 29 # を見ればわかるので計算しなくてもよい。 30 x1, x2, x3, x4 = box 31 A = np.linalg.norm(x1 - x2) 32 B = np.linalg.norm(x1 - x3) 33 C = np.linalg.norm(x1 - x4) 34 print("頂点",x1, x2, x3, x4) 35 print("Aの長さ", A) # Aの長さ 16.1441 36 print("Bの長さ",B) # Bの長さ 162.715 37 print("Cの長さ",C) # Cの長さ 161.912 38 39 if A < B: 40 min = A 41 else: 42 min = B 43 if C < min: 44 min = C 45 print("最小", min) 46 if 5 < min < 25: 47 # drawContours() の contours 引数は int 型でないといけない。 48 cv2.drawContours(img_src, [box.astype(int)], -1, (0, 255, 0), 2) 49 50 51def within(line, rect): 52 """line が rect に含まれるかどうか 53 """ 54 p1, p2 = tuple(line[:2]), tuple(line[2:]) 55 # 線の始点と終点が長方形内に含まれるかどうか 56 return cv2.pointPolygonTest(box, p1, False) >= 0 and \ 57 cv2.pointPolygonTest(box, p2, False) >= 0 58 59LSD = cv2.createLineSegmentDetector() 60lines, width, prec, nfa = LSD.detect(edges) 61lines = np.squeeze(lines) 62 63for line in lines: 64 p1, p2 = tuple(line[:2]), tuple(line[2:]) 65 66 if within(line, rect): 67 # 長方形に含まれる場合は赤色で描画 68 cv2.line(img_src, p1, p2, (0, 0, 255), 2) 69 else: 70 # 長方形に含まれない場合は赤色で描画 71 cv2.line(img_src, p1, p2, (255, 0, 0), 2) 72 73# cv2.imwrite("teratail.jpg", img_src) 74cv2.imshow('src', img_src) 75cv2.waitKey() 76cv2.destroyAllWindows()

投稿2018/09/12 09:52

編集2018/09/13 05:17
tiitoi

総合スコア21956

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

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

uriuri

2018/09/12 11:37

とてもわかりやすい回答ありがとうございます 実際に試そうとしたのですが、エラーでひっかかってしまいました TypeError: contour is not a numerical tuple コードは質問の場所に載せました 今回、長方形は回転を考慮したものとなっています プログラミング初心者で理解が浅く申し訳ありません 指導していただけると幸いです
tiitoi

2018/09/12 11:57

元画像と輪郭抽出前の部分のコードも追記できますでしょうか?
uriuri

2018/09/12 12:20

追記させていただきました
uriuri

2018/09/12 12:20

お手数おかけして申し訳ありません
tiitoi

2018/09/12 13:29

検出された線分が長方形内に含まれるかどうかを判定するように書いたのですが、このような感じでいいのでしょうか。 長方形外と判定された線分が青、長方形内と判定された線分が赤になっています。
uriuri

2018/09/13 02:15

丁寧な回答ありがとうございます 長方形内に直線があるかどうかの判定とても参考になりました 自分のコードを書き換えて試したのですが TypeError: contour is not a numerical tuple というエラーがでてしまいます 追記できていなかったのでコードに追記しましたが、numpyを用いて線の幅を求め条件をつけ長方形をだしています 調べても解決策がわからず申し訳ありません
tiitoi

2018/09/13 03:10

TypeError: contour is not a numerical tuple について、回答の一番下に書きました。簡単にいうと、`rect`でなく、`box`を渡してください。 これで uriuri さんのコードがエラーなく動くことが確認できました。
uriuri

2018/09/13 04:33

お忙しい中ありがとうございます TypeError: contour is not a numerical tuple というエラーは解決できました しかしまだうまくいかず、 申し訳ないのですが、書き換えたコードについて添削をしてもらってもいいでしょうか for文を用いているのは各線分に対してカメラで写ったものを処理するためです コードを新しく追記します できる範囲で助けてもらえるとありがたいです
uriuri

2018/09/13 04:42

頼りすぎてしまいごめんなさい
tiitoi

2018/09/13 05:22

``` p1, p2 = tuple(lines[:2]), tuple(line[2:]) ``` ↓ ``` p1, p2 = tuple(line[:2]), tuple(line[2:]) ``` です。提示されたコードを修正したものを回答の一番下に書きました。 一部冗長な箇所は除いてあります。 ```` if lines is not None: if len(contours) > 0: ```` は、配列が空なら for 文が回らないのであえて書く必要はありません。 長方形の幅、高さを計算していますが、cv2.minAreaRect() の返り値にその情報があるので、 対角線だけ計算すればよいです。 ```` A = np.linalg.norm(x1 - x2) B = np.linalg.norm(x1 - x3) C = np.linalg.norm(x1 - x4) ``` ↓ ```` rect = cv2.minAreaRect(cnt) (cx, cy), (width, height), angle = rect diag = np.linalg.norm([width, height]) ````
uriuri

2018/09/13 07:34

ありがとうございます 本当に助かりました
uriuri

2018/09/13 08:04

独学でやっているため質問できる方もいず、今回は本当に頼りになりました。 今後、助言いただけると本当に助かります。 ありがとうございました
uriuri

2018/09/13 11:06

tiitoiさん、ごめんなさい 動かして気づいたのですが私のコードでは矩形内に直線があるかの判定を行っていず、別々に処理を行っていることに気づきました。 お時間がよろしければ教えてもらいながら修正したいと思っています。 甘えてしまってごめんなさい
tiitoi

2018/09/13 11:14

表題の件は解決されていると思うので、 * 今のコード全体 * 問題点 または 期待する処理、アウトプット を明確にして、新しく質問を作っていただけますか。
uriuri

2018/09/13 11:25

わかりました。 たびたび申し訳ありません。
guest

0

ちょっとダサいですが、次のように書いてみてください。

Python

1if np.all((a < X1) & (X1 < b)): 2 ...

投稿2018/09/12 08:56

編集2018/09/12 09:55
LouiS0616

総合スコア35660

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

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

uriuri

2018/09/12 09:54

if (a < X1) & (X1 < b): で試してみましたが同じエラーがでてしまいました
LouiS0616

2018/09/12 09:58

追記しておきました。 エラーは出なくなるはずですが、これではうまく判定できなさそうですね。 tiitoiさんの回答が参考になると思います。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問