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.
We can probably solve it using scipy.ndimage.find_objects
, but I prefer using cv2.connectedComponentsWithStats:
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()
average_distance_between_neighbors = 21.858534029025055