Вместо использования HoughCircles, который требует, чтобы круги были "идеальными" кругами и был неточным на связанных каплях, должен работать простой подход к фильтрации контуров. Вот основная идея:
Для подсчета количества перекрывающихся кругов
- Приблизительная площадь контура одного круга, равная
~375
- Поиск контуров, итерацияСквозные контуры и фильтр с использованием области контура
- Сумма перекрывающихся кругов
Чтобы найти круги, соприкасающиеся с границей изображения, мы ограничиваем область обнаружения только внешними 10 пикселями на изображении. Мы находим контуры на этом новом изображении, а затем фильтруем, используя область контура, чтобы определить соприкасающиеся круги
Подсчитать количество перекрывающихся кругов
После преобразования в оттенки серого и установки порогового значения вПолучив бинарное изображение, мы приближаем площадь контура одного шарика / круга как ~375
. Далее мы находим контуры на изображении и фильтруем, используя cv2.contourArea()
. Чтобы определить, есть ли перекрытие, мы делим площадь каждого контура на площадь одного круга, а затем находим потолок, используя math.ceil()
. Если мы получим значение потолка больше 1, это означает, что BLOB-объект был подключен, и мы просто добавляем значение потолка к нашему счетчику
Вот обнаруженные перекрывающиеся круги
Наложение: 213
Найти круги, соприкасающиеся с границей изображения
Идея заключается в создании черного ящика для маскировки внутренней частиизображение, которое не на границе. Мы можем сделать это с cv2.fillPoly()
. Отсюда мы находим контуры и фильтруем, используя область контура. Идея состоит в том, что если капля является относительно большой по сравнению с некоторой пороговой областью, это означает, что капля, скорее всего, касается края
Вот заполненный черный ящик и обнаруженные соприкасающиеся круги
Касание: 10
import cv2
import numpy as np
import math
image = cv2.imread('1.jpg')
black_box = image.copy()
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)[1]
# Count overlapping circles
single_area = 375
overlapping = 0
cnts = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]
for c in cnts:
area = cv2.contourArea(c)
blob_area = math.ceil(area/single_area)
if blob_area > 1:
overlapping += blob_area
cv2.drawContours(image, [c], -1, (36,255,12), 2)
# Find circles touching image boundary
h, w, _ = image.shape
boundary = 10
touching = 0
box = np.array(([boundary,boundary],
[w-boundary,boundary],
[w-boundary, h-boundary],
[boundary, h-boundary]))
cv2.fillPoly(black_box, [box], [0,0,0])
copy = black_box.copy()
copy = cv2.cvtColor(copy, cv2.COLOR_BGR2GRAY)
copy = cv2.threshold(copy, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)[1]
cnts = cv2.findContours(copy, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]
for c in cnts:
area = cv2.contourArea(c)
if area > 100:
touching += 1
cv2.drawContours(black_box, [c], -1, (36,255,12), 2)
print('Overlapping:', overlapping)
print('Touching:', touching)
cv2.imshow('image', image)
cv2.imshow('black_box', black_box)
cv2.waitKey()