#python #cluster-analysis #k-means
#python #кластерный анализ #k-означает
Вопрос:
У меня есть детектор, который возвращает центры ограничивающей рамки обнаруженных объектов, по большей части он работает нормально. Однако что я хочу сделать, так это рассмотреть 10 кадров, а не 1 кадр для проведения обнаружения, чтобы я мог исключить больше ложноположительных результатов.
Обычно мой детектор работает следующим образом:
1. Get a frame.
2. Conduct the algorithm.
3. Record the centers into a dictionary per each frame.
Способ, который, как я думал, поможет уменьшить количество ложных срабатываний, заключается в:
1. Set up a loop of 10:
1. Get a frame.
2. Conduct the algorithm.
3. Record the centers into a dictionary per each frame.
2. Loop over the recorded points after every 10 frames.
3. Use a clustering algorithm or simple distance averaging
4. Get the final centers.
Итак, я уже реализовал часть этой логики. Я на шаге 1.3, мне нужно найти способ сгруппировать координаты и завершить оценку.
После 10 кадров мой словарь содержит такие значения (не удается вставить все):
(4067.0, 527.0): ['torx8', 'screw8'],
(4053.0, 527.0): ['torx8', 'screw1'],
(2627.0, 707.0): ['torx8', 'screw12'],
(3453.0, 840.0): ['torx6', 'screw14'],
(3633.0, 1373.0): ['torx6', 'screw15'],
(3440.0, 840.0): ['torx6', 'screw14'],
(3447.0, 840.0): ['torx6', 'screw14'],
(1660.0, 1707.0): ['torx8', 'screw3'],
(2633.0, 700.0): ['torx8', 'screw7'],
(2627.0, 693.0): ['torx8', 'screw8'],
(4060.0, 533.0): ['torx8', 'screw6'],
(3627.0, 1367.0): ['torx6', 'screw13'],
(2600.0, 680.0): ['torx8', 'screw15'],
(2607.0, 680.0): ['torx8', 'screw7']
Как вы можете заметить, большинство из этих точек уже являются одинаковыми точками с небольшим сдвигом пикселей, вот почему я пытаюсь найти способ избавиться от так называемых дубликатов.
Существует ли интеллектуальный и эффективный способ решения этой проблемы? Первое, что пришло мне в голову, это кластеризация k-средних, но я не уверен, подходит ли это к этой проблеме.
Был ли у кого-нибудь подобный опыт?
РЕДАКТИРОВАТЬ: Итак, я добился некоторого прогресса, и я могу группировать точки, используя иерархическую кластеризацию, потому что в моем случае у меня нет априорных знаний о количестве кластеров. Следовательно, требуется аппроксимация.
# cluster now
points = StandardScaler().fit_transform(points)
db = self.dbscan.fit(points)
core_samples_mask = np.zeros_like(db.labels_, dtype=bool)
core_samples_mask[db.core_sample_indices_] = True
labels = db.labels_
# Number of clusters in labels, ignoring noise if present.
n_clusters_ = len(set(db.labels_)) - (1 if -1 in db.labels_ else 0)
n_noise_ = list(db.labels_).count(-1)
# Black removed and is used for noise instead.
unique_labels = set(labels)
colors = [plt.cm.Spectral(each)
for each in np.linspace(0, 1, len(unique_labels))]
for k, col in zip(unique_labels, colors):
if k == -1:
# Black used for noise.
col = [0, 0, 0, 1]
class_member_mask = (labels == k)
xy = points[class_member_mask amp; core_samples_mask]
plt.plot(xy[:, 0], xy[:, 1], 'o', markerfacecolor=tuple(col),
markeredgecolor='k', markersize=14)
xy = points[class_member_mask amp; ~core_samples_mask]
plt.plot(xy[:, 0], xy[:, 1], 'o', markerfacecolor=tuple(col),
markeredgecolor='k', markersize=6)
plt.title('Estimated number of clusters: %d' % n_clusters_)
plt.show()
который отлично работает. Я могу устранить ложные срабатывания (см. черную точку), однако я все еще не знаю, как я мог бы получить среднее значение для кластера. Например, после того, как я найду кластеры, как я могу перебрать каждый кластер и усреднить все значения X, Y? (До StandardScaler().fit_transform(points)
, очевидно, поскольку после этого я теряю координаты пикселей, они соответствуют значению от минус одного до единицы.)
Ответ №1:
Хорошо, наконец, я понял это. Поскольку мне также понадобились бы мои баллы в их первоначальном масштабе (не между -1 и 1), мне также пришлось выполнить масштабирование. В любом случае, вот полная магия:
def cluster_dbscan(self, points, visualize=False):
# scale the points between -1 and 1
scaler = StandardScaler()
scaled_points = scaler.fit_transform(points)
# cluster
db = DBSCAN(eps=self.clustering_epsilon, min_samples=self.clustering_min_samples, metric='euclidean')
db.fit(scaled_points)
core_samples_mask = np.zeros_like(db.labels_, dtype=bool)
core_samples_mask[db.core_sample_indices_] = True
# Number of clusters in labels, ignoring noise if present.
n_clusters_ = len(set(db.labels_)) - (1 if -1 in db.labels_ else 0)
n_noise_ = list(db.labels_).count(-1)
if (visualize == True):
# Black removed and is used for noise instead.
unique_labels = set(db.labels_)
colors = [plt.cm.Spectral(each)
for each in np.linspace(0, 1, len(unique_labels))]
for k, col in zip(unique_labels, colors):
if k == -1:
# Black used for noise.
col = [0, 0, 0, 1]
class_member_mask = (db.labels_ == k)
xy = scaled_points[class_member_mask amp; core_samples_mask]
plt.plot(xy[:, 0], xy[:, 1], 'o', markerfacecolor=tuple(col),
markeredgecolor='k', markersize=14)
xy = scaled_points[class_member_mask amp; ~core_samples_mask]
plt.plot(xy[:, 0], xy[:, 1], 'o', markerfacecolor=tuple(col),
markeredgecolor='k', markersize=6)
plt.title('Estimated number of clusters: %d' % n_clusters_)
plt.show()
# back to original scale
points = scaler.inverse_transform(scaled_points)
# loop over the clusters, get the centers
centers = np.zeros((n_clusters_, 2)) # for x and y
for i in range(0, n_clusters_):
cluster_points = points[db.labels_ == i]
cluster_mean = np.mean(cluster_points, axis=0)
centers[i, :] = cluster_mean
# we need the original points
return centers