您面对的是connected component labeling,所以您可以使用的最佳功能正是您提到的connectedComponentsWithStats。
但是,它的使用一开始可能会有点混乱。在这里您可以找到一个工作示例。
import cv2
import numpy as np
# Load the image in grayscale
input_image = cv2.imread(r"satellite.png", cv2.IMREAD_GRAYSCALE)
# Threshold your image to make sure that is binary
thresh_type = cv2.THRESH_BINARY + cv2.THRESH_OTSU
_, binary_image = cv2.threshold(input_image, 0, 255, thresh_type)
# Perform connected component labeling
n_labels, labels, stats, centroids = cv2.connectedComponentsWithStats(binary_image,
connectivity=4)
# Create false color image
colors = np.random.randint(0, 255, size=(n_labels , 3), dtype=np.uint8)
colors[0] = [0, 0, 0] # for cosmetic reason we want the background black
false_colors = colors[labels]
cv2.imshow('binary', binary_image)
cv2.imshow('false_colors', false_colors)
cv2.waitKey(0)
二进制图像:
图像标记(假色):
centroids 变量已包含每个标记对象的质心 (x, y) 坐标。
false_colors_draw = false_colors.copy()
for centroid in centroids:
cv2.drawMarker(false_colors_draw, (int(centroid[0]), int(centroid[1])),
color=(255, 255, 255), markerType=cv2.MARKER_CROSS)
cv2.imshow('false_colors_centroids', false_colors_draw)
cv2.waitKey(0)
质心:
如您所见,它们非常多。如果您只想保留较大的对象,您可以 i) 在开始时对二值图像使用形态学运算,或者 ii) 使用 stats 中已包含的区域信息。
MIN_AREA = 50
false_colors_draw = false_colors.copy()
for i, centroid in enumerate(centroids[1:], start=1):
area = stats[i, 4]
if area > min_area:
cv2.drawMarker(false_colors_draw, (int(centroid[0]), int(centroid[1])),
color=(255, 255, 255), markerType=cv2.MARKER_CROSS)
质心(按区域过滤):