回答編集履歴

4

追記

2018/09/13 05:17

投稿

tiitoi
tiitoi

スコア21956

test CHANGED
@@ -347,3 +347,165 @@
347
347
  jug2 = cv2.pointPolygonTest(box, X2, False)
348
348
 
349
349
  ```
350
+
351
+
352
+
353
+ ## 提示されたコードの修正バージョン
354
+
355
+
356
+
357
+ ```python
358
+
359
+ import cv2
360
+
361
+ import math
362
+
363
+ import matplotlib.pyplot as plt
364
+
365
+ import numpy as np
366
+
367
+
368
+
369
+ img_src = cv2.imread("sample.jpg")
370
+
371
+
372
+
373
+ gauss = cv2.GaussianBlur(img_src, (11, 11), 0)
374
+
375
+ gray = cv2.cvtColor(gauss, cv2.COLOR_BGR2GRAY)
376
+
377
+ ret,th1 = cv2.threshold(gray, 200, 255, cv2.THRESH_BINARY)
378
+
379
+ edges = cv2.Canny(th1, 50, 150)
380
+
381
+ img, contours, hierarchy = cv2.findContours(th1, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_TC89_L1)
382
+
383
+
384
+
385
+ for cnt in contours:
386
+
387
+ cnt = contours[i]
388
+
389
+ area = cv2.contourArea(cnt)
390
+
391
+ print(area)
392
+
393
+
394
+
395
+ if 500 < area < 5000:
396
+
397
+ rect = cv2.minAreaRect(cnt)
398
+
399
+ box = cv2.boxPoints(rect)
400
+
401
+
402
+
403
+ (cx, cy), (width, height), angle = rect
404
+
405
+ diag = np.linalg.norm([width, height])
406
+
407
+ print(width, height, diag)
408
+
409
+ # 161.91236877441406 16.144147872924805 162.715237986
410
+
411
+
412
+
413
+ # 長方形の幅、高さ、対角線の長さは cv2.minAreaRect() の返り値
414
+
415
+ # を見ればわかるので計算しなくてもよい。
416
+
417
+ x1, x2, x3, x4 = box
418
+
419
+ A = np.linalg.norm(x1 - x2)
420
+
421
+ B = np.linalg.norm(x1 - x3)
422
+
423
+ C = np.linalg.norm(x1 - x4)
424
+
425
+ print("頂点",x1, x2, x3, x4)
426
+
427
+ print("Aの長さ", A) # Aの長さ 16.1441
428
+
429
+ print("Bの長さ",B) # Bの長さ 162.715
430
+
431
+ print("Cの長さ",C) # Cの長さ 161.912
432
+
433
+
434
+
435
+ if A < B:
436
+
437
+ min = A
438
+
439
+ else:
440
+
441
+ min = B
442
+
443
+ if C < min:
444
+
445
+ min = C
446
+
447
+ print("最小", min)
448
+
449
+ if 5 < min < 25:
450
+
451
+ # drawContours() の contours 引数は int 型でないといけない。
452
+
453
+ cv2.drawContours(img_src, [box.astype(int)], -1, (0, 255, 0), 2)
454
+
455
+
456
+
457
+
458
+
459
+ def within(line, rect):
460
+
461
+ """line が rect に含まれるかどうか
462
+
463
+ """
464
+
465
+ p1, p2 = tuple(line[:2]), tuple(line[2:])
466
+
467
+ # 線の始点と終点が長方形内に含まれるかどうか
468
+
469
+ return cv2.pointPolygonTest(box, p1, False) >= 0 and \
470
+
471
+ cv2.pointPolygonTest(box, p2, False) >= 0
472
+
473
+
474
+
475
+ LSD = cv2.createLineSegmentDetector()
476
+
477
+ lines, width, prec, nfa = LSD.detect(edges)
478
+
479
+ lines = np.squeeze(lines)
480
+
481
+
482
+
483
+ for line in lines:
484
+
485
+ p1, p2 = tuple(line[:2]), tuple(line[2:])
486
+
487
+
488
+
489
+ if within(line, rect):
490
+
491
+ # 長方形に含まれる場合は赤色で描画
492
+
493
+ cv2.line(img_src, p1, p2, (0, 0, 255), 2)
494
+
495
+ else:
496
+
497
+ # 長方形に含まれない場合は赤色で描画
498
+
499
+ cv2.line(img_src, p1, p2, (255, 0, 0), 2)
500
+
501
+
502
+
503
+ # cv2.imwrite("teratail.jpg", img_src)
504
+
505
+ cv2.imshow('src', img_src)
506
+
507
+ cv2.waitKey()
508
+
509
+ cv2.destroyAllWindows()
510
+
511
+ ```

3

変更点提示

2018/09/13 05:17

投稿

tiitoi
tiitoi

スコア21956

test CHANGED
@@ -287,3 +287,63 @@
287
287
 
288
288
 
289
289
  ![イメージ説明](b61a0742043ca0376d6904864c186543.png)
290
+
291
+
292
+
293
+ ### TypeError: contour is not a numerical tuple について
294
+
295
+
296
+
297
+ cv2.pointPolygonTest() の第1引数 contour に渡された値がおかしいというエラーです。
298
+
299
+ OpenCV の Python ラッパーで contour というものが出てきたら、これは (NumPoints, 2) の numpy 配列です。
300
+
301
+
302
+
303
+ 実際、値を見てみると、以下のようになっています。
304
+
305
+ cv2.minAreaRect() で輪郭を囲む回転した長方形の `((中心の x 座標, 中心の y 座標), (長方形の幅, 長方形の高さ), 回転角度)` を返すので、これを cv2.boxPoints() で4点の座標からなる輪郭 (contour) に変換しているので、あなたのコード中の `rect` ではなく、`box`を渡さないといけません。
306
+
307
+
308
+
309
+ ```
310
+
311
+ print(rect)
312
+
313
+ # ((177.51132202148438, 77.53165435791016), (161.91236877441406, 16.144147872924805), -19.653823852539062)
314
+
315
+ print(box)
316
+
317
+ # [[103 112]
318
+
319
+ # [ 98 97]
320
+
321
+ # [251 42]
322
+
323
+ # [256 57]]
324
+
325
+ ```
326
+
327
+
328
+
329
+ 変更が必要な箇所
330
+
331
+
332
+
333
+ ```
334
+
335
+ jug1 = cv2.pointPolygonTest(rect, X1, False)
336
+
337
+ jug2 = cv2.pointPolygonTest(rect, X2, False)
338
+
339
+ ```
340
+
341
+
342
+
343
+ ```
344
+
345
+ jug1 = cv2.pointPolygonTest(box, X1, False)
346
+
347
+ jug2 = cv2.pointPolygonTest(box, X2, False)
348
+
349
+ ```

2

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

2018/09/13 03:08

投稿

tiitoi
tiitoi

スコア21956

test CHANGED
@@ -286,4 +286,4 @@
286
286
 
287
287
 
288
288
 
289
- ![イメージ説明](17bc6fa74aeb581904938c9f8d49f648.png)
289
+ ![イメージ説明](b61a0742043ca0376d6904864c186543.png)

1

コード追記

2018/09/12 13:27

投稿

tiitoi
tiitoi

スコア21956

test CHANGED
@@ -145,3 +145,145 @@
145
145
 
146
146
 
147
147
  ![イメージ説明](528b9021f682c200d2cff52de2bbcbce.png)
148
+
149
+
150
+
151
+ ----
152
+
153
+
154
+
155
+ ## 追記
156
+
157
+
158
+
159
+ ```
160
+
161
+ import cv2
162
+
163
+ import numpy as np
164
+
165
+
166
+
167
+ def extract_contour(binary):
168
+
169
+ """2値画像から輪郭を抽出する。
170
+
171
+ """
172
+
173
+ # 輪郭を抽出する。
174
+
175
+ _, contours, _ = cv2.findContours(
176
+
177
+ binary, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_TC89_L1)
178
+
179
+
180
+
181
+ if not contours:
182
+
183
+ return # 輪郭がない場合
184
+
185
+
186
+
187
+ # 面積が最大の輪郭を抽出する。
188
+
189
+ cnt = max(contours, key=lambda cnt: cv2.contourArea(cnt))
190
+
191
+ # 輪郭を囲む回転した長方形を取得する。
192
+
193
+ rect = cv2.boxPoints(cv2.minAreaRect(cnt))
194
+
195
+
196
+
197
+ return rect
198
+
199
+
200
+
201
+ # 画像を読み込む。
202
+
203
+ img = cv2.imread("test.jpg")
204
+
205
+ # グレースケールにする。
206
+
207
+ gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
208
+
209
+ # 2値化する。
210
+
211
+ _, binary = cv2.threshold(gray, 200, 255, cv2.THRESH_BINARY)
212
+
213
+
214
+
215
+ # 長方形を取得する。
216
+
217
+ rect = extract_contour(binary)
218
+
219
+
220
+
221
+ # 回転した長方形を描画する。
222
+
223
+ _img = img.copy()
224
+
225
+ cv2.drawContours(_img, [rect.astype(int)], -1, (0, 255, 0), 2)
226
+
227
+
228
+
229
+ def within(line, rect):
230
+
231
+ """line が rect に含まれるかどうか
232
+
233
+ """
234
+
235
+ p1, p2 = tuple(line[:2]), tuple(line[2:])
236
+
237
+ # 線の始点と終点が長方形内に含まれるかどうか
238
+
239
+ return cv2.pointPolygonTest(rect, p1, False) >= 0 and \
240
+
241
+ cv2.pointPolygonTest(rect, p2, False) >= 0
242
+
243
+
244
+
245
+ # Canny エッジ検出を行う。
246
+
247
+ edges = cv2.Canny(binary, 50, 150)
248
+
249
+
250
+
251
+ # 直線を検出する。
252
+
253
+ LSD = cv2.createLineSegmentDetector()
254
+
255
+ lines, _, _, _ = LSD.detect(edges)
256
+
257
+
258
+
259
+ print(lines.shape) # (18, 1, 4)
260
+
261
+ lines = np.squeeze(lines) # 余分な次元削除
262
+
263
+
264
+
265
+ # 線が長方形内に含まれるかどうか調べる。
266
+
267
+ for line in lines:
268
+
269
+ p1, p2 = tuple(line[:2]), tuple(line[2:])
270
+
271
+
272
+
273
+ if within(line, rect):
274
+
275
+ # 長方形に含まれる場合は赤色で描画
276
+
277
+ cv2.line(_img, p1, p2, (0, 0, 255), 2)
278
+
279
+ else:
280
+
281
+ # 長方形に含まれない場合は赤色で描画
282
+
283
+ cv2.line(_img, p1, p2, (255, 0, 0), 2)
284
+
285
+ ```
286
+
287
+
288
+
289
+ ![イメージ説明](17bc6fa74aeb581904938c9f8d49f648.png)