回答編集履歴

4

2018/10/07 04:21

投稿

tiitoi
tiitoi

スコア21956

test CHANGED
@@ -258,12 +258,12 @@
258
258
 
259
259
 
260
260
 
261
+ ```
262
+
261
263
  flag に cv::FLOODFILL_FIXED_RANGE を指定した場合
262
264
 
263
265
 
264
266
 
265
- ```
266
-
267
267
  隣接する画素値 - loDiff <= 走査中の画素 <= 隣接する画素値 + upDiff
268
268
 
269
269
 

3

2018/10/07 04:21

投稿

tiitoi
tiitoi

スコア21956

test CHANGED
@@ -243,3 +243,81 @@
243
243
  Utils.bitmapToMat(bitmap_toumei, mat_original);
244
244
 
245
245
  ```
246
+
247
+
248
+
249
+ ## 連結成分と扱う基準について
250
+
251
+
252
+
253
+ 完全に一致した画素でなく、ある程度似た色は同じ連結成分にしたいという幅を持たせるために loDiff, upDiff という引数があります。
254
+
255
+
256
+
257
+ 同じ連結成分と判定する基準は [floodFill()](https://docs.opencv.org/3.4.3/d7/d1b/group__imgproc__misc.html#ga366aae45a6c1289b341d140839f18717) のリファレンスに記載があります。
258
+
259
+
260
+
261
+ flag に cv::FLOODFILL_FIXED_RANGE を指定した場合
262
+
263
+
264
+
265
+ ```
266
+
267
+ 隣接する画素値 - loDiff <= 走査中の画素 <= 隣接する画素値 + upDiff
268
+
269
+
270
+
271
+ flag に cv::FLOODFILL_FIXED_RANGE を指定していない場合
272
+
273
+
274
+
275
+ 隣接する画素値 - loDiff <= seed の画素値 <= 隣接する画素値 + upDiff
276
+
277
+ ```
278
+
279
+ loDiff, upDiff はグレースケールの場合は、cv::Scalar(s1), カラー画像の場合は cv::Scalar(s1, s2, s3) と指定します。
280
+
281
+
282
+
283
+ cv::FLOODFILL_FIXED_RANGE をつけるかどうかの違いは、似ているかどうか判断する際の比較する画素が seed の点なのか、隣接する点なのかの違いです。
284
+
285
+ 以下のグラデーションの画像に各引数で試した結果です。
286
+
287
+
288
+
289
+ ![イメージ説明](e51bbcd0b091f862b23db08142926811.jpeg)
290
+
291
+ オリジナル画像
292
+
293
+
294
+
295
+ ![イメージ説明](4b2efe25c9f4d1a4020039247aabdeeb.jpeg)
296
+
297
+ cv::FLOODFILL_FIXED_RANGE, loDiff=cv::Scalr(0, 0, 0), upDiff=cv::Scalr(0, 0, 0)
298
+
299
+
300
+
301
+ ![イメージ説明](4b2efe25c9f4d1a4020039247aabdeeb.jpeg)
302
+
303
+ loDiff=cv::Scalr(0, 0, 0), upDiff=cv::Scalr(0, 0, 0)
304
+
305
+
306
+
307
+ ![イメージ説明](271739f11bd66aaa045012c2de632c6f.jpeg)
308
+
309
+ cv::FLOODFILL_FIXED_RANGE, loDiff=cv::Scalr(10, 10, 10), upDiff=cv::Scalr(10, 10, 10)
310
+
311
+
312
+
313
+ ![イメージ説明](34e11779ac0398b31caddee5cd1663ca.jpeg)
314
+
315
+ loDiff=cv::Scalr(10, 10, 10), upDiff=cv::Scalr(10, 10, 10)
316
+
317
+
318
+
319
+ このパラメータをうまく調整することで精度を上げることができるかもしれません。
320
+
321
+ また似た色を同じ色として塗りつぶしたい場合は、第1引数 image の入力を RGB ではなく、cvtColor() で HSV に変換したほうがいいかもしれません。
322
+
323
+ [OpenCVでのHSV色空間lower,upperの取り扱い](https://qiita.com/miyamotok0105/items/ce6f44064f128a580640)

2

2018/10/07 04:17

投稿

tiitoi
tiitoi

スコア21956

test CHANGED
@@ -225,3 +225,21 @@
225
225
 
226
226
 
227
227
  チャンネルの並び順を確認するには、cv::imwrite() で書き出すとわかります。(チャンネルが反転してたらRGB、反転してなかったらBGR)
228
+
229
+
230
+
231
+ ## 他に気になる点
232
+
233
+
234
+
235
+ BGR から BGRA に変換する処理が見当たりませんが、
236
+
237
+ mat_original は以下の関数で変換すると、すでに BGRA になっているのでしょうか?
238
+
239
+
240
+
241
+ ```
242
+
243
+ Utils.bitmapToMat(bitmap_toumei, mat_original);
244
+
245
+ ```

1

2018/10/07 03:24

投稿

tiitoi
tiitoi

スコア21956

test CHANGED
@@ -97,3 +97,131 @@
97
97
  ![イメージ説明](5a9b8ed307f0ad21f8a07a1f8a1c86f5.png)
98
98
 
99
99
  結果画像
100
+
101
+
102
+
103
+ ## 追記
104
+
105
+
106
+
107
+ ### グレースケール画像に変換している部分について
108
+
109
+
110
+
111
+ ```
112
+
113
+ //■チャネルの変更(floodfillは透明を扱えないため)
114
+
115
+ Imgproc.cvtColor(mat, mat, Imgproc.COLOR_RGBA2GRAY)
116
+
117
+ ```
118
+
119
+
120
+
121
+ グレースケールに変換すると RGB の情報量は落ちてしまうので、同じ色を塗りつぶしたいのであれば、グレースケールにする必要はないと思います。
122
+
123
+
124
+
125
+ ![イメージ説明](90cb0c13b3cba73e82881094ef364eba.jpeg)
126
+
127
+ カラー画像
128
+
129
+
130
+
131
+ ![イメージ説明](105ac552fd539a3a5fd43ed0bb205248.jpeg)
132
+
133
+ グレースケールに変換した画像
134
+
135
+
136
+
137
+ ## mask を初期化していない。
138
+
139
+
140
+
141
+ ```
142
+
143
+ Mat mat2 = new Mat(mat.height() + 2 , mat.width() + 2, CV_8UC1);
144
+
145
+ ```
146
+
147
+
148
+
149
+ [floodFill()](https://docs.opencv.org/3.4.3/d7/d1b/group__imgproc__misc.html#ga366aae45a6c1289b341d140839f18717) のリファレンスを見ると、次のように書いてあります。
150
+
151
+
152
+
153
+ ```
154
+
155
+ Since this is both an input and output parameter, you must take responsibility of initializing it.
156
+
157
+ ```
158
+
159
+
160
+
161
+ floodFill() は、指定した点 seed の連結成分を走査する際、mask が0の画素だけ探します。mask が非0の画素は色が同じでも走査しません。名前通り、マスクとして機能するわけです。
162
+
163
+ また、floodFill() で見つけた連結成分には、mask に値が書き込まれます。この値は flag 引数の 8 ~ 16 ビット目で指定します。(255 << 8 としている部分です。この場合、連結成分に 255 が書き込まれます。)
164
+
165
+
166
+
167
+ このように入力または出力の両方で利用される引数であるため、mask の値を初期化するのは呼び出し側の責任になります。
168
+
169
+
170
+
171
+ 今回は、mask はマスクとしては利用せず、走査した結果を受け取るためだけに利用します。走査はすべての画素を対象に行ってほしいので、mask の全要素は 0 で初期化します。
172
+
173
+
174
+
175
+ そのため、次のようにしていたのですが
176
+
177
+ ```
178
+
179
+ //■Maskデータ作成 cv::Mat mask = cv::Mat::zeros(image.rows + 2, image.cols + 2, CV_8UC1);
180
+
181
+ ```
182
+
183
+ このようにしてしまうと、mat2 の各値は未定義になってしまうので、floodFill() の結果もおかしくなると思われます。
184
+
185
+ ```
186
+
187
+ Mat mat2 = new Mat(mat.height() + 2 , mat.width() + 2, CV_8UC1);
188
+
189
+ ```
190
+
191
+
192
+
193
+ C++ 版には全部0で初期化した行列の作成には、cv::Mat::zeros() の他に、以下のものがありますが、Java ではどうでしょうか。
194
+
195
+
196
+
197
+ ```
198
+
199
+ Mat(int rows, int cols, int type, const Scalar &s)
200
+
201
+ Mat(Size size, int type, const Scalar &s)
202
+
203
+ ```
204
+
205
+
206
+
207
+ ## チャンネルの並び順
208
+
209
+
210
+
211
+ チャンネルの並び順には RGB と BGR があり、imread() で読み込んだ場合は、並び順は BGR になります。
212
+
213
+ 他のライブラリで読み込んだ画像の場合は RGB が多いです。
214
+
215
+ そのため、`COLOR_RGBA2GRAY` と `COLOR_BGRA2GRAY` では意味がかわってきますので、注意が必要です。
216
+
217
+
218
+
219
+ ```
220
+
221
+ Imgproc.cvtColor(mat, mat, Imgproc.COLOR_RGBA2GRAY);
222
+
223
+ ```
224
+
225
+
226
+
227
+ チャンネルの並び順を確認するには、cv::imwrite() で書き出すとわかります。(チャンネルが反転してたらRGB、反転してなかったらBGR)