teratail header banner
teratail header banner
質問するログイン新規登録

回答編集履歴

4

追記

2018/09/13 05:17

投稿

tiitoi
tiitoi

スコア21960

answer CHANGED
@@ -172,4 +172,85 @@
172
172
  ```
173
173
  jug1 = cv2.pointPolygonTest(box, X1, False)
174
174
  jug2 = cv2.pointPolygonTest(box, X2, False)
175
+ ```
176
+
177
+ ## 提示されたコードの修正バージョン
178
+
179
+ ```python
180
+ import cv2
181
+ import math
182
+ import matplotlib.pyplot as plt
183
+ import numpy as np
184
+
185
+ img_src = cv2.imread("sample.jpg")
186
+
187
+ gauss = cv2.GaussianBlur(img_src, (11, 11), 0)
188
+ gray = cv2.cvtColor(gauss, cv2.COLOR_BGR2GRAY)
189
+ ret,th1 = cv2.threshold(gray, 200, 255, cv2.THRESH_BINARY)
190
+ edges = cv2.Canny(th1, 50, 150)
191
+ img, contours, hierarchy = cv2.findContours(th1, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_TC89_L1)
192
+
193
+ for cnt in contours:
194
+ cnt = contours[i]
195
+ area = cv2.contourArea(cnt)
196
+ print(area)
197
+
198
+ if 500 < area < 5000:
199
+ rect = cv2.minAreaRect(cnt)
200
+ box = cv2.boxPoints(rect)
201
+
202
+ (cx, cy), (width, height), angle = rect
203
+ diag = np.linalg.norm([width, height])
204
+ print(width, height, diag)
205
+ # 161.91236877441406 16.144147872924805 162.715237986
206
+
207
+ # 長方形の幅、高さ、対角線の長さは cv2.minAreaRect() の返り値
208
+ # を見ればわかるので計算しなくてもよい。
209
+ x1, x2, x3, x4 = box
210
+ A = np.linalg.norm(x1 - x2)
211
+ B = np.linalg.norm(x1 - x3)
212
+ C = np.linalg.norm(x1 - x4)
213
+ print("頂点",x1, x2, x3, x4)
214
+ print("Aの長さ", A) # Aの長さ 16.1441
215
+ print("Bの長さ",B) # Bの長さ 162.715
216
+ print("Cの長さ",C) # Cの長さ 161.912
217
+
218
+ if A < B:
219
+ min = A
220
+ else:
221
+ min = B
222
+ if C < min:
223
+ min = C
224
+ print("最小", min)
225
+ if 5 < min < 25:
226
+ # drawContours() の contours 引数は int 型でないといけない。
227
+ cv2.drawContours(img_src, [box.astype(int)], -1, (0, 255, 0), 2)
228
+
229
+
230
+ def within(line, rect):
231
+ """line が rect に含まれるかどうか
232
+ """
233
+ p1, p2 = tuple(line[:2]), tuple(line[2:])
234
+ # 線の始点と終点が長方形内に含まれるかどうか
235
+ return cv2.pointPolygonTest(box, p1, False) >= 0 and \
236
+ cv2.pointPolygonTest(box, p2, False) >= 0
237
+
238
+ LSD = cv2.createLineSegmentDetector()
239
+ lines, width, prec, nfa = LSD.detect(edges)
240
+ lines = np.squeeze(lines)
241
+
242
+ for line in lines:
243
+ p1, p2 = tuple(line[:2]), tuple(line[2:])
244
+
245
+ if within(line, rect):
246
+ # 長方形に含まれる場合は赤色で描画
247
+ cv2.line(img_src, p1, p2, (0, 0, 255), 2)
248
+ else:
249
+ # 長方形に含まれない場合は赤色で描画
250
+ cv2.line(img_src, p1, p2, (255, 0, 0), 2)
251
+
252
+ # cv2.imwrite("teratail.jpg", img_src)
253
+ cv2.imshow('src', img_src)
254
+ cv2.waitKey()
255
+ cv2.destroyAllWindows()
175
256
  ```

3

変更点提示

2018/09/13 05:17

投稿

tiitoi
tiitoi

スコア21960

answer CHANGED
@@ -142,4 +142,34 @@
142
142
  cv2.line(_img, p1, p2, (255, 0, 0), 2)
143
143
  ```
144
144
 
145
- ![イメージ説明](b61a0742043ca0376d6904864c186543.png)
145
+ ![イメージ説明](b61a0742043ca0376d6904864c186543.png)
146
+
147
+ ### TypeError: contour is not a numerical tuple について
148
+
149
+ cv2.pointPolygonTest() の第1引数 contour に渡された値がおかしいというエラーです。
150
+ OpenCV の Python ラッパーで contour というものが出てきたら、これは (NumPoints, 2) の numpy 配列です。
151
+
152
+ 実際、値を見てみると、以下のようになっています。
153
+ cv2.minAreaRect() で輪郭を囲む回転した長方形の `((中心の x 座標, 中心の y 座標), (長方形の幅, 長方形の高さ), 回転角度)` を返すので、これを cv2.boxPoints() で4点の座標からなる輪郭 (contour) に変換しているので、あなたのコード中の `rect` ではなく、`box`を渡さないといけません。
154
+
155
+ ```
156
+ print(rect)
157
+ # ((177.51132202148438, 77.53165435791016), (161.91236877441406, 16.144147872924805), -19.653823852539062)
158
+ print(box)
159
+ # [[103 112]
160
+ # [ 98 97]
161
+ # [251 42]
162
+ # [256 57]]
163
+ ```
164
+
165
+ 変更が必要な箇所
166
+
167
+ ```
168
+ jug1 = cv2.pointPolygonTest(rect, X1, False)
169
+ jug2 = cv2.pointPolygonTest(rect, X2, False)
170
+ ```
171
+
172
+ ```
173
+ jug1 = cv2.pointPolygonTest(box, X1, False)
174
+ jug2 = cv2.pointPolygonTest(box, X2, False)
175
+ ```

2

画像が間違っていたので修正

2018/09/13 03:08

投稿

tiitoi
tiitoi

スコア21960

answer CHANGED
@@ -142,4 +142,4 @@
142
142
  cv2.line(_img, p1, p2, (255, 0, 0), 2)
143
143
  ```
144
144
 
145
- ![イメージ説明](17bc6fa74aeb581904938c9f8d49f648.png)
145
+ ![イメージ説明](b61a0742043ca0376d6904864c186543.png)

1

コード追記

2018/09/12 13:27

投稿

tiitoi
tiitoi

スコア21960

answer CHANGED
@@ -71,4 +71,75 @@
71
71
  rect contains line 2.
72
72
  ```
73
73
 
74
- ![イメージ説明](528b9021f682c200d2cff52de2bbcbce.png)
74
+ ![イメージ説明](528b9021f682c200d2cff52de2bbcbce.png)
75
+
76
+ ----
77
+
78
+ ## 追記
79
+
80
+ ```
81
+ import cv2
82
+ import numpy as np
83
+
84
+ def extract_contour(binary):
85
+ """2値画像から輪郭を抽出する。
86
+ """
87
+ # 輪郭を抽出する。
88
+ _, contours, _ = cv2.findContours(
89
+ binary, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_TC89_L1)
90
+
91
+ if not contours:
92
+ return # 輪郭がない場合
93
+
94
+ # 面積が最大の輪郭を抽出する。
95
+ cnt = max(contours, key=lambda cnt: cv2.contourArea(cnt))
96
+ # 輪郭を囲む回転した長方形を取得する。
97
+ rect = cv2.boxPoints(cv2.minAreaRect(cnt))
98
+
99
+ return rect
100
+
101
+ # 画像を読み込む。
102
+ img = cv2.imread("test.jpg")
103
+ # グレースケールにする。
104
+ gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
105
+ # 2値化する。
106
+ _, binary = cv2.threshold(gray, 200, 255, cv2.THRESH_BINARY)
107
+
108
+ # 長方形を取得する。
109
+ rect = extract_contour(binary)
110
+
111
+ # 回転した長方形を描画する。
112
+ _img = img.copy()
113
+ cv2.drawContours(_img, [rect.astype(int)], -1, (0, 255, 0), 2)
114
+
115
+ def within(line, rect):
116
+ """line が rect に含まれるかどうか
117
+ """
118
+ p1, p2 = tuple(line[:2]), tuple(line[2:])
119
+ # 線の始点と終点が長方形内に含まれるかどうか
120
+ return cv2.pointPolygonTest(rect, p1, False) >= 0 and \
121
+ cv2.pointPolygonTest(rect, p2, False) >= 0
122
+
123
+ # Canny エッジ検出を行う。
124
+ edges = cv2.Canny(binary, 50, 150)
125
+
126
+ # 直線を検出する。
127
+ LSD = cv2.createLineSegmentDetector()
128
+ lines, _, _, _ = LSD.detect(edges)
129
+
130
+ print(lines.shape) # (18, 1, 4)
131
+ lines = np.squeeze(lines) # 余分な次元削除
132
+
133
+ # 線が長方形内に含まれるかどうか調べる。
134
+ for line in lines:
135
+ p1, p2 = tuple(line[:2]), tuple(line[2:])
136
+
137
+ if within(line, rect):
138
+ # 長方形に含まれる場合は赤色で描画
139
+ cv2.line(_img, p1, p2, (0, 0, 255), 2)
140
+ else:
141
+ # 長方形に含まれない場合は赤色で描画
142
+ cv2.line(_img, p1, p2, (255, 0, 0), 2)
143
+ ```
144
+
145
+ ![イメージ説明](17bc6fa74aeb581904938c9f8d49f648.png)