OpenCV подсчитывает перекрывающиеся круги, используя морфологическую операцию - PullRequest
1 голос
/ 01 октября 2019

Вот изображение, из которого я пытаюсь получить круги.

enter image description here

Я использовал разницу серого изображения и эрозию, чтобы получить границы.

img_path= 'input_data/coins.jpg'
img = cv2.imread(img_path)
rgb,gray=getColorSpaces(img)
a,b=0,255
plt.figure(figsize=(12, 12))

erosion_se=cv2.getStructuringElement(cv2.MORPH_ELLIPSE,(5,5))
erosion = cv2.erode(gray,erosion_se,iterations = 1)
boundary=gray-erosion
image, contours, hierarchy = cv2.findContours(boundary,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)    
plt.imshow(boundary,'gray')

Я мог бы получить круги для большинства кругов, границы которых относительно различны. Я хочу сделать две вещи

  • Получить количество перекрывающихся кругов.

  • Найти круги, которые касаются границы изображения. Я могу определить, сравнивая радиус круга с границей изображения. Проблема состоит в том, что 2 определенных капли не обнаруживаются в виде кружков.

    circles = cv2.HoughCircles(boundary, cv2.HOUGH_GRADIENT, 1, 20,
                  param1=30,
                  param2=15,
                  minRadius=5,
                  maxRadius=20)

    if circles is not None: 
        circles = np.uint16(np.around(circles))
        for i in circles[0,:]:
            cv2.circle(img,(i[0],i[2]),i[3],(0,255,0),2)
            cv2.circle(img,(i[0],i[2]),2,(0,0,255),3)

        cv2.imshow('circles', img)

        k = cv2.waitKey(0)
        if k == 27:
            cv2.destroyAllWindows()

Ниже приведен вывод после HoughCircles из изображения границы окружности. Большой зеленый кружок, который выделяется, нежелателен. Я не уверен, почему для некоторых перекрывающихся областей круги не обнаружены.

1 Ответ

2 голосов
/ 02 октября 2019

Вместо использования HoughCircles, который требует, чтобы круги были "идеальными" кругами и был неточным на связанных каплях, должен работать простой подход к фильтрации контуров. Вот основная идея:

Для подсчета количества перекрывающихся кругов

  • Приблизительная площадь контура одного круга, равная ~375
  • Поиск контуров, итерацияСквозные контуры и фильтр с использованием области контура
  • Сумма перекрывающихся кругов

Чтобы найти круги, соприкасающиеся с границей изображения, мы ограничиваем область обнаружения только внешними 10 пикселями на изображении. Мы находим контуры на этом новом изображении, а затем фильтруем, используя область контура, чтобы определить соприкасающиеся круги


Подсчитать количество перекрывающихся кругов

После преобразования в оттенки серого и установки порогового значения вПолучив бинарное изображение, мы приближаем площадь контура одного шарика / круга как ~375. Далее мы находим контуры на изображении и фильтруем, используя cv2.contourArea(). Чтобы определить, есть ли перекрытие, мы делим площадь каждого контура на площадь одного круга, а затем находим потолок, используя math.ceil(). Если мы получим значение потолка больше 1, это означает, что BLOB-объект был подключен, и мы просто добавляем значение потолка к нашему счетчику

Вот обнаруженные перекрывающиеся круги

image

Наложение: 213

Найти круги, соприкасающиеся с границей изображения

Идея заключается в создании черного ящика для маскировки внутренней частиизображение, которое не на границе. Мы можем сделать это с cv2.fillPoly(). Отсюда мы находим контуры и фильтруем, используя область контура. Идея состоит в том, что если капля является относительно большой по сравнению с некоторой пороговой областью, это означает, что капля, скорее всего, касается края

Вот заполненный черный ящик и обнаруженные соприкасающиеся круги

image image

Касание: 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()
...