Вместо использования алгоритма HED другой подход заключается в использовании маркировки подключенного компонента , уже реализованной как cv2.connectedComponentsWithStats
. Мы можем использовать это для разделения объектов и маркировки кластера пикселей на отдельные сегменты.
Бинарное изображение
import cv2
import numpy as np
# Load image, grayscale, Gaussian Blur, Otsu's threshold
image = cv2.imread('1.jpg')
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
blur = cv2.GaussianBlur(gray, (3,3), 0)
thresh = cv2.threshold(blur, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)[1]
Маркировка подключенного компонента для создания ложного цветного изображения
# Perform connected component labeling
n_labels, labels, stats, centroids = cv2.connectedComponentsWithStats(thresh, connectivity=4)
# Create false color image and color background black
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]
Теперь, когда у нас есть сегментированные кластеры пикселей, мы можем найти центр тяжести каждого помеченного объекта. Эта информация уже содержится в переменной centroid
, возвращаемой из cv2.connectedComponentsWithStats
# Obtain centroids
false_colors_centroid = false_colors.copy()
for centroid in centroids:
cv2.drawMarker(false_colors_centroid, (int(centroid[0]), int(centroid[1])),
color=(255, 255, 255), markerType=cv2.MARKER_CROSS)
Там много центроидов. Мы можем фильтровать, используя область контура, чтобы сохранить только более крупные объекты, используя информацию, содержащуюся в stats
.
# Only keep larger objects by filtering using area
MIN_AREA = 50
false_color_centroid_filter = false_colors.copy()
for i, centroid in enumerate(centroids[1:], start=1):
area = stats[i, 4]
if area > MIN_AREA:
cv2.drawMarker(false_color_centroid_filter, (int(centroid[0]), int(centroid[1])),
color=(255, 255, 255), markerType=cv2.MARKER_CROSS)
Полный код
import cv2
import numpy as np
# Load image, grayscale, Gaussian Blur, Otsu's threshold
image = cv2.imread('1.jpg')
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
blur = cv2.GaussianBlur(gray, (3,3), 0)
thresh = cv2.threshold(blur, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)[1]
# Perform connected component labeling
n_labels, labels, stats, centroids = cv2.connectedComponentsWithStats(thresh, connectivity=4)
# Create false color image and color background black
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]
# Obtain centroids
false_colors_centroid = false_colors.copy()
for centroid in centroids:
cv2.drawMarker(false_colors_centroid, (int(centroid[0]), int(centroid[1])),
color=(255, 255, 255), markerType=cv2.MARKER_CROSS)
# Only keep larger objects by filtering using area
MIN_AREA = 50
false_color_centroid_filter = false_colors.copy()
for i, centroid in enumerate(centroids[1:], start=1):
area = stats[i, 4]
if area > MIN_AREA:
cv2.drawMarker(false_color_centroid_filter, (int(centroid[0]), int(centroid[1])),
color=(255, 255, 255), markerType=cv2.MARKER_CROSS)
cv2.imshow('binary', thresh)
cv2.imshow('false_colors', false_colors)
cv2.imshow('false_colors_centroids', false_colors_centroid)
cv2.imshow('false_color_centroid_filter', false_color_centroid_filter)
cv2.waitKey()