マスク画像が既に手に入っているなら、重心を求めればいいかと。
Python
1import cv2
2
3color = {
4 'gray': (128, 128, 128),
5}
6
7img = cv2.imread('object.jpg', cv2.IMREAD_GRAYSCALE)
8assert img is not None
9
10m = cv2.moments(img)
11cx = int(m['m10'] // m['m00'])
12cy = int(m['m01'] // m['m00'])
13
14cv2.drawMarker(img, (cx, cy), color['gray'])
15cv2.imshow('img', img)
16cv2.waitKey()
17cv2.destroyAllWindows()
テスト画像での実行結果はこんな感じです。
『良い感じに赤色の物体が写っている画像』を用意するのはなかなか大変です。
どれくらいの大きさ、どれくらいの数を想定しているのかわからないですから。
適当にテスト画像を用意してくださると回答しやすいので、次回以降は気にかけてみてください。
そもそもブイを正しく抽出できてなさそう
次のコードで実験しました、が...
Python
1import cv2
2import numpy as np
3
4
5def main():
6 img = cv2.imread('sea.jpg')
7
8 hsv_img = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
9 lower_red = np.array([170,100,190])
10 upper_red = np.array([200,255,255])
11 mask = cv2.inRange(hsv_img, lower_red, upper_red)
12
13 #
14 # Write points
15 points = np.vstack(
16 np.where(mask==255)
17 ).T
18
19 RED = (0, 0, 255)
20 for pt in map(tuple, points):
21 cv2.circle(img, pt, radius=20, color=RED, thickness=-1)
22
23 cv2.imwrite('result.jpg', img)
24 #
25 #
26
27if __name__ == "__main__":
28 main()
期待
実際
『ブイ候補』を正しく認識できたなら...
前述の理由により正しく動作しませんが... (make_buoy_mask関数に相当)
その部分さえ修正できれば、充分実用できるかと。
find_buoy.py
Python
1import sys
2
3import numpy as np
4import cv2
5
6from partition import partition
7
8
9# 質問のブイマスク抽出の流用
10def make_buoy_mask(img):
11 return cv2.inRange(
12 cv2.cvtColor(img, cv2.COLOR_BGR2HSV),
13 lowerb=np.array([170,100,190]),
14 upperb=np.array([200,255,255])
15 )
16
17# マスク画像を生成してから、ブイの座標のnp.arrayを返す
18def find_buoy(img):
19 return np.vstack(
20 np.where(make_buoy_mask(img)==255)
21 ).T
22
23def main(img_file):
24 img = cv2.imread(img_file)
25
26 # Find buoy pixels
27 buoy_pts = find_buoy(img)
28 buoy_ids = partition(
29 buoy_pts,
30 lambda x, y: np.linalg.norm(x-y) <= 10
31 )
32
33 # Get center of buoys
34 num_of_buoy = max(buoy_ids) + 1
35 typical_buoy_pts = [
36 buoy_pts[buoy_ids.index(i)]
37 for i in range(num_of_buoy)
38 ]
39
40 # Check buoy position
41 RED = (0, 0, 255)
42 for buoy in typical_buoy_pts:
43 cv2.circle(img, tuple(buoy), radius=10, color=RED, thickness=5)
44
45 # Show result
46 cv2.imshow('result', img)
47 cv2.waitKey()
48 cv2.destroyAllWindows()
49
50if __name__ == '__main__':
51 if len(sys.argv) != 2:
52 print('Usage: find_buoy.py img_file')
53 exit()
54
55 main(img_file=sys.argv[1])
partition.py OpenCV内部実装の焼き直し
Python
1from itertools import product
2from UnionFind import UnionFind
3
4# 番号を振りなおす e.g. [0, 0, 3, 5, 3, 2] -> [0, 0, 2, 3, 2, 1]
5def renumber(id_list):
6 id_set = set(id_list)
7 replace_dict = dict(zip(
8 sorted(list(id_set)),
9 [i for i, _ in enumerate(id_set)]
10 ))
11 return [replace_dict[elem] for elem in id_list]
12
13# UnionFind法を用いて、データを分類していく
14# 同一のクラスタであるとの判断基準はpredicate_funcで与える
15def partition(src_list, predicate_func):
16 src_len = len(src_list)
17 uf = UnionFind(src_len)
18
19 loop_obj = product(src_list, src_list)
20 for ij, (ei, ej) in enumerate(loop_obj):
21 i, j = divmod(ij, src_len)
22
23 if ei is ej:
24 continue
25 if not predicate_func(ei, ej):
26 continue
27
28 uf.union(i, j)
29
30 return renumber(uf._id)
test_partition.py
Python
1import unittest
2from partition import partition
3
4class TestPartition(unittest.TestCase):
5 def test_partition(self):
6 self.assertEqual(
7 partition([1, 2, 3, 7, 8, 9, 2], lambda x, y: abs(x-y) <= 1),
8 [0, 0, 0, 1, 1, 1, 0]
9 )
10 self.assertEqual(
11 partition([1, 1, 1, 3, 4, 4, 5, 6], lambda x, y: x % 2 == y % 2),
12 [0, 0, 0, 0, 1, 1, 0, 1]
13 )
14
15if __name__ == '__main__':
16 unittest.main()
UnionFind.pyは、既にあるものを利用。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2018/01/11 09:00
2018/01/11 09:15 編集
2018/01/11 09:24
2018/01/11 09:44
2018/01/11 10:28
2018/01/11 10:33
2018/01/11 10:38
2018/01/11 10:57
2018/01/11 11:08
2018/01/11 11:17
2018/01/11 15:34