回答編集履歴

3

f

2018/12/10 09:58

投稿

tiitoi
tiitoi

スコア21956

test CHANGED
@@ -126,7 +126,7 @@
126
126
 
127
127
 
128
128
 
129
- 2つの矩形が共通部分を持たないのは以下の場合
129
+ 2つの矩形が共通部分を持たないのは以下の場合なので、それ以外の場合は交わると判断する。
130
130
 
131
131
 
132
132
 
@@ -176,6 +176,8 @@
176
176
 
177
177
  if are_close(rect1, rect2, margin_x=15, margin_y=0):
178
178
 
179
+ # rect1 が rect2 に隣接するなら、rect1 は rect2 と同じグループと判断する。
180
+
179
181
  find_union.union(i, j)
180
182
 
181
183
  break
@@ -202,6 +204,8 @@
202
204
 
203
205
  for label in np.unique(classes):
204
206
 
207
+ # 同じグループ内のすべての矩形を含む外接矩形を計算する。
208
+
205
209
  xmin, ymin, xmax, ymax = np.split(rects[classes == label], 4, axis=-1)
206
210
 
207
211
  bounding_rect = [xmin.min(), ymin.min(), xmax.max(), ymax.max()]

2

dd

2018/12/10 09:58

投稿

tiitoi
tiitoi

スコア21956

test CHANGED
@@ -17,3 +17,253 @@
17
17
 
18
18
 
19
19
  ![イメージ説明](0ededc070b5c5e3d1488551e038b8556.png)
20
+
21
+
22
+
23
+ ## 追記
24
+
25
+
26
+
27
+ y 座標を見て Mean-Shift でクラスタリングする方法では、以下のようにあまりうまくいかなかったので、隣接する矩形を調べて、[find-union アルゴリズム](https://www.slideshare.net/chokudai/union-find-49066733) でグループ分けする方法を試してみました。
28
+
29
+
30
+
31
+ ![イメージ説明](a182c9a595f041315671e89838c4da81.png)
32
+
33
+
34
+
35
+ ### 1. データ読み込み
36
+
37
+
38
+
39
+ test.txt に (N行、8列) でスペース区切りの矩形の座標値が入っているものとする。
40
+
41
+
42
+
43
+ ```python
44
+
45
+ import numpy as np
46
+
47
+ import matplotlib.pyplot as plt
48
+
49
+ from matplotlib.patches import Rectangle
50
+
51
+
52
+
53
+ # 矩形のデータを読み込む。
54
+
55
+ data = np.loadtxt('test.txt')
56
+
57
+
58
+
59
+ # 矩形の表現方法を4点の座標値から (xmin, ymin, xmax, ymax) という形式に直す。
60
+
61
+ xs, ys = data[:, ::2], data[:, 1::2]
62
+
63
+ rects = np.c_[xs.min(axis=1), ys.min(axis=1), xs.max(axis=1), ys.max(axis=1)]
64
+
65
+ ```
66
+
67
+
68
+
69
+ ### 2. Find-Union
70
+
71
+
72
+
73
+ ```python
74
+
75
+ class UnionFind:
76
+
77
+ def __init__(self, size):
78
+
79
+ self.parent = np.arange(size) # 各ノードのルートノード一覧
80
+
81
+ self.rank = np.full(size, 1) # 木の高さ一覧
82
+
83
+
84
+
85
+ def find(self, x):
86
+
87
+ if self.parent[x] == x:
88
+
89
+ return x
90
+
91
+ self.parent[x] = self.find(self.parent[x]) # ルートに繋ぎ直す。
92
+
93
+ return self.parent[x]
94
+
95
+
96
+
97
+ def union(self, x, y):
98
+
99
+ rx = self.find(x)
100
+
101
+ ry = self.find(y)
102
+
103
+ if rx == ry:
104
+
105
+ return # ルートが同じ場合
106
+
107
+ self.parent[rx] = self.parent[ry] # x のルートを y のルートに繋ぐ。
108
+
109
+
110
+
111
+ def are_same(self, x, y):
112
+
113
+ return self.find(x) == self.find(y)
114
+
115
+ ```
116
+
117
+
118
+
119
+ ## 3. 2つの矩形が近いかどうかを判断する関数
120
+
121
+
122
+
123
+ 1. 2つの矩形をそれぞれ少し大きくする。
124
+
125
+ 2. 大きくした矩形が共通部分をとるかどうか判断する。
126
+
127
+
128
+
129
+ 2つの矩形が共通部分を持たないのは以下の場合
130
+
131
+
132
+
133
+ ![イメージ説明](9e38476cda14570b3d5b199b72e0b5c4.png)
134
+
135
+
136
+
137
+ ```python
138
+
139
+ def are_close(rect1, rect2, margin_x, margin_y):
140
+
141
+ # マージンだけ大きくした矩形を考え、それが共通部分を持つなら
142
+
143
+ # 2つの長方形は近いと判断する。
144
+
145
+ xmin1, ymin1, xmax1, ymax1 = \
146
+
147
+ rect1 + np.array([-margin_x, -margin_y, margin_x, margin_y])
148
+
149
+ xmin2, ymin2, xmax2, ymax2 = \
150
+
151
+ rect2 + np.array([-margin_x, -margin_y, margin_x, margin_y])
152
+
153
+
154
+
155
+ return not (xmin1 > xmax2 or xmax1 < xmin2 or
156
+
157
+ ymin1 > ymax2 or ymax1 < ymin2)
158
+
159
+ ```
160
+
161
+
162
+
163
+ ### 4. find-union で近い矩形同士をグループ分けする。
164
+
165
+
166
+
167
+ ```python
168
+
169
+ # find-union アルゴリズムで近い矩形同士をグループ分けする。
170
+
171
+ find_union = UnionFind(len(rects))
172
+
173
+ for i, rect1 in enumerate(rects):
174
+
175
+ for j, rect2 in enumerate(rects):
176
+
177
+ if are_close(rect1, rect2, margin_x=15, margin_y=0):
178
+
179
+ find_union.union(i, j)
180
+
181
+ break
182
+
183
+
184
+
185
+ classes = find_union.parent
186
+
187
+ print(find_union.parent)
188
+
189
+ ```
190
+
191
+
192
+
193
+ ### 5. グループごとの外接矩形を求める。
194
+
195
+
196
+
197
+ ```python
198
+
199
+ # 各クラスの外接矩形を求める。
200
+
201
+ bounding_rects = []
202
+
203
+ for label in np.unique(classes):
204
+
205
+ xmin, ymin, xmax, ymax = np.split(rects[classes == label], 4, axis=-1)
206
+
207
+ bounding_rect = [xmin.min(), ymin.min(), xmax.max(), ymax.max()]
208
+
209
+ bounding_rects.append(bounding_rect)
210
+
211
+ ```
212
+
213
+
214
+
215
+ ### 6. 結果を描画する。
216
+
217
+
218
+
219
+ ```python
220
+
221
+ # 描画する。
222
+
223
+ fig, ax = plt.subplots(figsize=(8, 8))
224
+
225
+ ax.set_xlim(xs.min() - 20, xs.max() + 20)
226
+
227
+ ax.set_ylim(ys.min() - 20, ys.max() + 20)
228
+
229
+ # 元の矩形を描画する。
230
+
231
+ colors = np.random.rand(len(classes), 3)
232
+
233
+ for (xmin, ymin, xmax, ymax), class_, color in zip(rects, classes, colors):
234
+
235
+ w, h = xmax - xmin, ymax - ymin
236
+
237
+ ax.add_patch(Rectangle(xy=(xmin, ymin), width=w, height=h,
238
+
239
+ color=colors[class_], fill=False, lw=2))
240
+
241
+ # 外接する矩形を描画する。
242
+
243
+ for xmin, ymin, xmax, ymax in bounding_rects:
244
+
245
+ w, h = xmax - xmin, ymax - ymin
246
+
247
+ ax.add_patch(Rectangle(xy=(xmin, ymin), width=w,
248
+
249
+ height=h, lw=2, alpha=0.5, fill=False))
250
+
251
+
252
+
253
+ plt.show()
254
+
255
+ ```
256
+
257
+
258
+
259
+ ### 結果
260
+
261
+
262
+
263
+ ![イメージ説明](1e20bc492ee1cc201e00c8c18ccb422f.png)
264
+
265
+
266
+
267
+ 右側の細長い矩形が他のと同じグループになっているのは、矩形同士が隣接しているかどうかを見ているからです。
268
+
269
+ 望むグループ分けができるように、同じグループと判断する条件を増やしたりして、調整してみてください。(`are_close()` 関数の中身)

1

d

2018/12/10 09:47

投稿

tiitoi
tiitoi

スコア21956

test CHANGED
@@ -8,4 +8,12 @@
8
8
 
9
9
 
10
10
 
11
+ ## 追記
12
+
13
+
14
+
11
- 具体的な矩形のデータあればサンプドを提示ます。
15
+ コメント欄の矩形をプロットしたら以下ようになったのですが、ループ分けする基準はなんでょうか?
16
+
17
+
18
+
19
+ ![イメージ説明](0ededc070b5c5e3d1488551e038b8556.png)