回答編集履歴
4
d
answer
CHANGED
@@ -138,4 +138,26 @@
|
|
138
138
|
|
139
139
|

|
140
140
|
|
141
|
-
実際、取り組んでくうちにいろいろ課題が出てくるとは思いますが、基本的な方針については回答に記載されていると思いますので、あとは宿題とします。
|
141
|
+
実際、取り組んでくうちにいろいろ課題が出てくるとは思いますが、基本的な方針については回答に記載されていると思いますので、あとは宿題とします。
|
142
|
+
|
143
|
+
## 追記
|
144
|
+
|
145
|
+
> 実際のケースに近い画像で試してみたところ、赤ペンやマッキーで囲んだ枠をしっかり認識していました。また赤鉛筆では薄いためか厳しく、
|
146
|
+
|
147
|
+
原因は以下です。
|
148
|
+
|
149
|
+
線が細いため、2値化した時点で枠線に隙間が空いてしまっています。
|
150
|
+
|
151
|
+

|
152
|
+
|
153
|
+
これに対して、 findcontours() を行うと以下のようにそれぞれ別の輪郭あると検出されてしまいます。
|
154
|
+
そのため、複数に分割されてしまっている輪郭を1つの輪郭として統合するような処理が必要となると思います。
|
155
|
+
|
156
|
+

|
157
|
+
|
158
|
+
> こちらの環境のためかエラーメッセージが出る箇所もあったので追記しました。
|
159
|
+
|
160
|
+
おそらく、質問者さんの環境の OpenCV はバージョン3 なのだと思います。
|
161
|
+
findcontours() の返り値が OpenCV 3 はタプル3つだったのが、OpenCV 4 ではタプル2つに変更されました。
|
162
|
+
|
163
|
+
[OpenCV - findContours() による輪郭抽出](http://pynote.hatenablog.com/entry/opencv-findcontours)
|
3
d
answer
CHANGED
@@ -88,4 +88,54 @@
|
|
88
88
|
|
89
89
|

|
90
90
|
|
91
|
-
結果
|
91
|
+
結果
|
92
|
+
|
93
|
+
## funa さんのアドバイスを受けて追記
|
94
|
+
|
95
|
+
> 簡便な方法として,drawContoursの直前で凸包に変えてしまえば,とりあえず「一部切れたけども連続はしている(=1つのContourではある)」的なパターンに関しては救えそうな気もしますが…
|
96
|
+
|
97
|
+
囲った線が一箇所途切れている場合は、funa さんのアドバイス通りに輪郭を cv2.convexHull() で凸包にすることで対応できたので、参考までに追記しておきます。
|
98
|
+
|
99
|
+
```python
|
100
|
+
import cv2
|
101
|
+
|
102
|
+
# 画像を読み込む。
|
103
|
+
img = cv2.imread("sample.png")
|
104
|
+
|
105
|
+
# HSV 色空間に変換する。
|
106
|
+
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
|
107
|
+
|
108
|
+
# 2値化で赤の枠線を抽出する。
|
109
|
+
binary = cv2.inRange(hsv, (170, 0, 0), (180, 255, 255))
|
110
|
+
|
111
|
+
# OPENING でノイズを消す。
|
112
|
+
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (3, 3))
|
113
|
+
eroded = cv2.morphologyEx(binary, cv2.MORPH_OPEN, kernel)
|
114
|
+
|
115
|
+
# 輪郭を抽出する。
|
116
|
+
contours, hierarchy = cv2.findContours(
|
117
|
+
eroded, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE
|
118
|
+
)
|
119
|
+
|
120
|
+
# 誤検出の輪郭を消す。
|
121
|
+
contours = list(filter(lambda x: cv2.contourArea(x) > 100, contours))
|
122
|
+
|
123
|
+
# 輪郭の凸包に置き換える。
|
124
|
+
convex_hulls = list(map(cv2.convexHull, contours))
|
125
|
+
|
126
|
+
# 検出された輪郭内部を (255, 255, 255) で塗りつぶす。
|
127
|
+
mask = np.zeros_like(img)
|
128
|
+
cv2.drawContours(mask, convex_hulls, -1, color=(255, 255, 255), thickness=-1)
|
129
|
+
|
130
|
+
# 元画像でマスクの値が (255, 255, 255) の画素以外を白に置換する。
|
131
|
+
img = np.where(mask == 255, img, 255)
|
132
|
+
|
133
|
+
# 結果を保存する。
|
134
|
+
cv2.imwrite("test.png", img)
|
135
|
+
```
|
136
|
+
|
137
|
+
2箇所以上途切れていたりする場合は findContours() の輪郭が分割されてしまうので、統合する処理を入れる必要がありそうです。
|
138
|
+
|
139
|
+

|
140
|
+
|
141
|
+
実際、取り組んでくうちにいろいろ課題が出てくるとは思いますが、基本的な方針については回答に記載されていると思いますので、あとは宿題とします。
|
2
d
answer
CHANGED
@@ -9,7 +9,7 @@
|
|
9
9
|
* 1. 画像を読み込む。
|
10
10
|
* 2. 枠線部分のみを2値化で抽出する。
|
11
11
|
* 2.1. HSV 色空間に変換する。
|
12
|
-
* 2.2. 赤色とそれ以外を cv2.inRange() で2値化する。
|
12
|
+
* 2.2. 赤色とそれ以外を cv2.inRange() で2値化する。(赤以外の場合は要パラメータ調整)
|
13
13
|
[OpenCV - inRange による範囲指定で2値化する方法について](http://pynote.hatenablog.com/entry/opencv-inrange)
|
14
14
|
|
15
15
|
* 2.3. ノイズをモルフォロジー変換で消す。
|
1
d
answer
CHANGED
@@ -30,6 +30,11 @@
|
|
30
30
|
|
31
31
|
## サンプルコード
|
32
32
|
|
33
|
+
以下の環境で確認
|
34
|
+
|
35
|
+
* OpenCV 4
|
36
|
+
* Python 3.7
|
37
|
+
|
33
38
|
```python
|
34
39
|
import cv2
|
35
40
|
|