回答編集履歴

4

追記

2018/01/11 15:51

投稿

LouiS0616
LouiS0616

スコア35660

test CHANGED
@@ -268,7 +268,7 @@
268
268
 
269
269
 
270
270
 
271
- **partition.py**
271
+ **partition.py** [OpenCV内部実装](https://github.com/opencv/opencv/blob/c7049ca627f47fece7adb2c132ba118209d517e6/modules/core/include/opencv2/core/operations.hpp#L440)の焼き直し
272
272
 
273
273
  ```Python
274
274
 

3

説明追記

2018/01/11 15:51

投稿

LouiS0616
LouiS0616

スコア35660

test CHANGED
@@ -148,6 +148,8 @@
148
148
 
149
149
  その部分さえ修正できれば、充分実用できるかと。
150
150
 
151
+
152
+
151
153
  **find_buoy.py**
152
154
 
153
155
  ```Python
@@ -168,6 +170,8 @@
168
170
 
169
171
 
170
172
 
173
+ # 質問のブイマスク抽出の流用
174
+
171
175
  def make_buoy_mask(img):
172
176
 
173
177
  return cv2.inRange(
@@ -182,6 +186,8 @@
182
186
 
183
187
 
184
188
 
189
+ # マスク画像を生成してから、ブイの座標のnp.arrayを返す
190
+
185
191
  def find_buoy(img):
186
192
 
187
193
  return np.vstack(
@@ -272,6 +278,8 @@
272
278
 
273
279
 
274
280
 
281
+ # 番号を振りなおす e.g. [0, 0, 3, 5, 3, 2] -> [0, 0, 2, 3, 2, 1]
282
+
275
283
  def renumber(id_list):
276
284
 
277
285
  id_set = set(id_list)
@@ -288,6 +296,10 @@
288
296
 
289
297
 
290
298
 
299
+ # UnionFind法を用いて、データを分類していく
300
+
301
+ # 同一のクラスタであるとの判断基準はpredicate_funcで与える
302
+
291
303
  def partition(src_list, predicate_func):
292
304
 
293
305
  src_len = len(src_list)

2

追記

2018/01/11 15:48

投稿

LouiS0616
LouiS0616

スコア35660

test CHANGED
@@ -137,3 +137,231 @@
137
137
  **実際**
138
138
 
139
139
  ![実際](46dea120c1c96f487f5d957307d1bae6.jpeg)
140
+
141
+
142
+
143
+ 『ブイ候補』を正しく認識できたなら...
144
+
145
+ ---
146
+
147
+ 前述の理由により正しく動作しませんが... (make_buoy_mask関数に相当)
148
+
149
+ その部分さえ修正できれば、充分実用できるかと。
150
+
151
+ **find_buoy.py**
152
+
153
+ ```Python
154
+
155
+ import sys
156
+
157
+
158
+
159
+ import numpy as np
160
+
161
+ import cv2
162
+
163
+
164
+
165
+ from partition import partition
166
+
167
+
168
+
169
+
170
+
171
+ def make_buoy_mask(img):
172
+
173
+ return cv2.inRange(
174
+
175
+ cv2.cvtColor(img, cv2.COLOR_BGR2HSV),
176
+
177
+ lowerb=np.array([170,100,190]),
178
+
179
+ upperb=np.array([200,255,255])
180
+
181
+ )
182
+
183
+
184
+
185
+ def find_buoy(img):
186
+
187
+ return np.vstack(
188
+
189
+ np.where(make_buoy_mask(img)==255)
190
+
191
+ ).T
192
+
193
+
194
+
195
+ def main(img_file):
196
+
197
+ img = cv2.imread(img_file)
198
+
199
+
200
+
201
+ # Find buoy pixels
202
+
203
+ buoy_pts = find_buoy(img)
204
+
205
+ buoy_ids = partition(
206
+
207
+ buoy_pts,
208
+
209
+ lambda x, y: np.linalg.norm(x-y) <= 10
210
+
211
+ )
212
+
213
+
214
+
215
+ # Get center of buoys
216
+
217
+ num_of_buoy = max(buoy_ids) + 1
218
+
219
+ typical_buoy_pts = [
220
+
221
+ buoy_pts[buoy_ids.index(i)]
222
+
223
+ for i in range(num_of_buoy)
224
+
225
+ ]
226
+
227
+
228
+
229
+ # Check buoy position
230
+
231
+ RED = (0, 0, 255)
232
+
233
+ for buoy in typical_buoy_pts:
234
+
235
+ cv2.circle(img, tuple(buoy), radius=10, color=RED, thickness=5)
236
+
237
+
238
+
239
+ # Show result
240
+
241
+ cv2.imshow('result', img)
242
+
243
+ cv2.waitKey()
244
+
245
+ cv2.destroyAllWindows()
246
+
247
+
248
+
249
+ if __name__ == '__main__':
250
+
251
+ if len(sys.argv) != 2:
252
+
253
+ print('Usage: find_buoy.py img_file')
254
+
255
+ exit()
256
+
257
+
258
+
259
+ main(img_file=sys.argv[1])
260
+
261
+ ```
262
+
263
+
264
+
265
+ **partition.py**
266
+
267
+ ```Python
268
+
269
+ from itertools import product
270
+
271
+ from UnionFind import UnionFind
272
+
273
+
274
+
275
+ def renumber(id_list):
276
+
277
+ id_set = set(id_list)
278
+
279
+ replace_dict = dict(zip(
280
+
281
+ sorted(list(id_set)),
282
+
283
+ [i for i, _ in enumerate(id_set)]
284
+
285
+ ))
286
+
287
+ return [replace_dict[elem] for elem in id_list]
288
+
289
+
290
+
291
+ def partition(src_list, predicate_func):
292
+
293
+ src_len = len(src_list)
294
+
295
+ uf = UnionFind(src_len)
296
+
297
+
298
+
299
+ loop_obj = product(src_list, src_list)
300
+
301
+ for ij, (ei, ej) in enumerate(loop_obj):
302
+
303
+ i, j = divmod(ij, src_len)
304
+
305
+
306
+
307
+ if ei is ej:
308
+
309
+ continue
310
+
311
+ if not predicate_func(ei, ej):
312
+
313
+ continue
314
+
315
+
316
+
317
+ uf.union(i, j)
318
+
319
+
320
+
321
+ return renumber(uf._id)
322
+
323
+ ```
324
+
325
+
326
+
327
+ **test_partition.py**
328
+
329
+ ```Python
330
+
331
+ import unittest
332
+
333
+ from partition import partition
334
+
335
+
336
+
337
+ class TestPartition(unittest.TestCase):
338
+
339
+ def test_partition(self):
340
+
341
+ self.assertEqual(
342
+
343
+ partition([1, 2, 3, 7, 8, 9, 2], lambda x, y: abs(x-y) <= 1),
344
+
345
+ [0, 0, 0, 1, 1, 1, 0]
346
+
347
+ )
348
+
349
+ self.assertEqual(
350
+
351
+ partition([1, 1, 1, 3, 4, 4, 5, 6], lambda x, y: x % 2 == y % 2),
352
+
353
+ [0, 0, 0, 0, 1, 1, 0, 1]
354
+
355
+ )
356
+
357
+
358
+
359
+ if __name__ == '__main__':
360
+
361
+ unittest.main()
362
+
363
+ ```
364
+
365
+
366
+
367
+ UnionFind.pyは、[既にあるもの](https://gist.github.com/SonechkaGodovykh/18f60a3b9b3e6812c071456f61f9c5a6)を利用。

1

追記

2018/01/11 15:42

投稿

LouiS0616
LouiS0616

スコア35660

test CHANGED
@@ -55,3 +55,85 @@
55
55
 
56
56
 
57
57
  適当にテスト画像を用意してくださると回答しやすいので、次回以降は気にかけてみてください。
58
+
59
+
60
+
61
+ そもそもブイを正しく抽出できてなさそう
62
+
63
+ ---
64
+
65
+ 次のコードで実験しました、が...
66
+
67
+ ```Python
68
+
69
+ import cv2
70
+
71
+ import numpy as np
72
+
73
+
74
+
75
+
76
+
77
+ def main():
78
+
79
+ img = cv2.imread('sea.jpg')
80
+
81
+
82
+
83
+ hsv_img = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
84
+
85
+ lower_red = np.array([170,100,190])
86
+
87
+ upper_red = np.array([200,255,255])
88
+
89
+ mask = cv2.inRange(hsv_img, lower_red, upper_red)
90
+
91
+
92
+
93
+ #
94
+
95
+ # Write points
96
+
97
+ points = np.vstack(
98
+
99
+ np.where(mask==255)
100
+
101
+ ).T
102
+
103
+
104
+
105
+ RED = (0, 0, 255)
106
+
107
+ for pt in map(tuple, points):
108
+
109
+ cv2.circle(img, pt, radius=20, color=RED, thickness=-1)
110
+
111
+
112
+
113
+ cv2.imwrite('result.jpg', img)
114
+
115
+ #
116
+
117
+ #
118
+
119
+
120
+
121
+ if __name__ == "__main__":
122
+
123
+ main()
124
+
125
+ ```
126
+
127
+
128
+
129
+ **期待**
130
+
131
+ ![期待](714fa0fa145802b955c0111eb97ab977.jpeg)
132
+
133
+
134
+
135
+ ---
136
+
137
+ **実際**
138
+
139
+ ![実際](46dea120c1c96f487f5d957307d1bae6.jpeg)