找到许多明亮圆圈的质心

发布于 2025-01-16 04:06:35 字数 324 浏览 2 评论 0原文

我正在使用 Python 找到下图中每个亮点的质心,以计算邻居之间的平均距离。 scipy.ndimage.find_objects 和 scipy.ndimage.center_of_mass 似乎很有希望,但我不知道如何将所有内容放在一起。 我在哪里可以找到一些参考资料? 我已经使用 Tracker “手动”完成了该任务,但我想自动化该过程。 谢谢。

输入图片此处描述

I'm using Python to find the centroid of each bright point in the following image, to calculate the average distance between neighbours.
scipy.ndimage.find_objects and scipy.ndimage.center_of_mass seem promising, but I don't see how to put everything together.
Where can I find some references?
I've done the task "manually" with Tracker, but I'd like to automate the process.
Thank you.

enter image description here

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

尝蛊 2025-01-23 04:06:35

我们可能可以使用 scipy.ndimage.find_objects 来解决它,但我更喜欢使用 cv2.connectedComponentsWithStats

  • 将图像读取为灰度。
  • 应用二进制阈值。
  • 通过统计数据查找连接的组件。
  • 过滤面积小于 4 的组件,并构建 (x, y) 质心列表。 (排除非常小的组件,因为可能存在拆分组件)。
  • 画小十字进行测试。
  • 获得 (x, y) 质心列表后,计算邻居之间的平均距离。使用 scipy.spatial.distance 中的 cdist 开始计算。

这是一个代码示例:

import numpy as np
import cv2
from scipy.spatial.distance import cdist

img = cv2.imread('spots.png', cv2.IMREAD_GRAYSCALE)  # Load image in Grayscale format.

# Convert to binary - use manual threshold
#_, thresh = cv2.threshold(img, 0, 255, cv2.THRESH_OTSU) # Try automatic threshold
_, thresh = cv2.threshold(img, 10, 255, cv2.THRESH_BINARY) # Try manual threshold

# Find connected components with statistics
nlabel, labels, stats, centroids = cv2.connectedComponentsWithStats(thresh, connectivity=8)

test_img = cv2.cvtColor(img, cv2.COLOR_GRAY2BGR)

coords = []  # List of filtered centroieds

# Draw a cross at the coordinates of the centroieds, for testing
for i in range(1, nlabel):
    if (stats[i, cv2.CC_STAT_AREA] > 4):    # Only if area is grater than 4 pixels
        coords.append(centroids[i])  # Create new list of centroids
        x, y = centroids[i]  # Get the coordinate of the centroied
        x, y = int(round(x)), int(round(y))  # Round and cast to int
        cv2.drawMarker(test_img, (x, y), (120, 157, 187), markerType=cv2.MARKER_CROSS, markerSize=5, thickness=1, line_type=cv2.LINE_8)  # Draw cross at the centroied


# Compute average distance between neighbors
################################################################################
# https://stackoverflow.com/questions/51305370/calculating-average-distance-of-nearest-neighbours-in-pandas-dataframe
# Find euclidean distance from every centroied to every other centroied.
dist = cdist(coords, coords)

dist[dist == 0] = 1.0e9  # Exclude the distance from centroied to itself (replace with large number).

dist = np.sort(dist.ravel())  # Sort the distances

# Each distance is the sorted list is duplicated twice - for point A to point B and from point B to point A.
n_min_dists = len(coords)*2

# Average of centroid to its nearest neighbor.
avg_min_dist = np.average(dist[0:n_min_dists])

# Assume distance to all neighbors is no more than 1.2*"distance to nearest neighbor" (we also want to exclude diagonals)
neighbors_dists = dist[dist < avg_min_dist*1.2]

average_distance_between_neighbors = np.average(neighbors_dists)

print('average_distance_between_neighbors = ' + str(average_distance_between_neighbors))
################################################################################

# Show images for testing
cv2.imshow('thresh', thresh)
cv2.imshow('test_img', test_img)
cv2.waitKey()
cv2.destroyAllWindows()

测试图像:
输入图片此处描述


average_distance_ Between_neighbors = 21.858534029025055

We can probably solve it using scipy.ndimage.find_objects, but I prefer using cv2.connectedComponentsWithStats:

  • Read image as Grayscale.
  • Apply binary threshold.
  • Find connected components with statistics.
  • Filter components with area below 4, and build a list of (x, y) centroids. (exclude very small components because there may be split components).
  • Draw small crosses for testing.
  • After having a list of (x, y) centroids, compute average distance between neighbors. Start the computation with cdist from scipy.spatial.distance.

Here is a code sample:

import numpy as np
import cv2
from scipy.spatial.distance import cdist

img = cv2.imread('spots.png', cv2.IMREAD_GRAYSCALE)  # Load image in Grayscale format.

# Convert to binary - use manual threshold
#_, thresh = cv2.threshold(img, 0, 255, cv2.THRESH_OTSU) # Try automatic threshold
_, thresh = cv2.threshold(img, 10, 255, cv2.THRESH_BINARY) # Try manual threshold

# Find connected components with statistics
nlabel, labels, stats, centroids = cv2.connectedComponentsWithStats(thresh, connectivity=8)

test_img = cv2.cvtColor(img, cv2.COLOR_GRAY2BGR)

coords = []  # List of filtered centroieds

# Draw a cross at the coordinates of the centroieds, for testing
for i in range(1, nlabel):
    if (stats[i, cv2.CC_STAT_AREA] > 4):    # Only if area is grater than 4 pixels
        coords.append(centroids[i])  # Create new list of centroids
        x, y = centroids[i]  # Get the coordinate of the centroied
        x, y = int(round(x)), int(round(y))  # Round and cast to int
        cv2.drawMarker(test_img, (x, y), (120, 157, 187), markerType=cv2.MARKER_CROSS, markerSize=5, thickness=1, line_type=cv2.LINE_8)  # Draw cross at the centroied


# Compute average distance between neighbors
################################################################################
# https://stackoverflow.com/questions/51305370/calculating-average-distance-of-nearest-neighbours-in-pandas-dataframe
# Find euclidean distance from every centroied to every other centroied.
dist = cdist(coords, coords)

dist[dist == 0] = 1.0e9  # Exclude the distance from centroied to itself (replace with large number).

dist = np.sort(dist.ravel())  # Sort the distances

# Each distance is the sorted list is duplicated twice - for point A to point B and from point B to point A.
n_min_dists = len(coords)*2

# Average of centroid to its nearest neighbor.
avg_min_dist = np.average(dist[0:n_min_dists])

# Assume distance to all neighbors is no more than 1.2*"distance to nearest neighbor" (we also want to exclude diagonals)
neighbors_dists = dist[dist < avg_min_dist*1.2]

average_distance_between_neighbors = np.average(neighbors_dists)

print('average_distance_between_neighbors = ' + str(average_distance_between_neighbors))
################################################################################

# Show images for testing
cv2.imshow('thresh', thresh)
cv2.imshow('test_img', test_img)
cv2.waitKey()
cv2.destroyAllWindows()

Test image:
enter image description here


average_distance_between_neighbors = 21.858534029025055

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文