Обозначение окружности и рисование линий через окружности в одной вертикальной линии - PullRequest
0 голосов
/ 29 октября 2019

У меня есть простое изображение с примерно 15 случайно расположенными кругами. Моя задача - определить круги, а затем провести прямую линию через круги, лежащие на одной вертикальной линии. Я все еще новичок в OpenCV.

Сначала я попытался определить местоположение кругов и использовал этот код:

image = cv2.imread('circle', 0)
img = cv2.medianBlur(image,5)
cimg = cv2.cvtColor(img,cv2.COLOR_GRAY2BGR)

circles = cv2.HoughCircles(image,cv2.HOUGH_GRADIENT, 
1,20,param1=40,param2=20,minRadius=0,maxRadius=0)
circles = np.uint16(np.around(circles))
for i in circles[0,:]:
    # draw the outer circle
   cv2.circle(cimg,(i[0],i[1]),i[2],(0,255,0),2)
    # draw the center of the circle
    cv2.circle(cimg,(i[0],i[1]),2,(0,0,255),3)

cv2_imshow(cimg)
cv2.waitKey(0)
cv2.destroyAllWindows()`

Это вывод, который я получаю, который не имеет никакого смысла для меня:

enter image description here

Пожалуйста, помогите определить круги и провести прямую линию через круги.

РЕДАКТИРОВАТЬ: Входные изображения выглядят так:

Input

1 Ответ

1 голос
/ 30 октября 2019

Посмотрев на ваше входное изображение, я сомневаюсь, что любой из центров окружностей имеет одинаковую x координату. Поэтому в моем решении я установлю допуск tol, в пределах которого допускаются координаты x. Окончательная линия затем проводится через среднее значение этих x координат.

Общий подход заключается в следующем:

  1. Обратный двоичный порог изображения, см. cv2.threshold и ThresholdTypes, чтобы иметь белые кружки на черном фоне и избавиться от возможных артефактов JPG.
  2. Найти крайние внешние контуры, см. cv2.findContours и RetrievalModes.
  3. Найдите центры и радиусы окружностей минимальной охватывающей области, используя cv2.minEnclosingCircle.
  4. Найдите вертикальные линии, сопоставив x координаты в пределах допуска, как описано выше.

Вот код:

import cv2
import numpy as np
from skimage import io              # Only needed for web grabbing images, use cv2.imread for local images

# Read image from web
img = cv2.cvtColor(io.imread('https://i.imgur.com/VQ5Ri0W.jpg'), cv2.COLOR_RGB2BGR)

# Convert image to grayscale for further processing; inverse binary threshold (also to get rid of JPG artifacts)
_, gray = cv2.threshold(cv2.cvtColor(img, cv2.COLOR_BGR2GRAY), 240, 255, cv2.THRESH_BINARY_INV)

# Find only external contours
contours, _ = cv2.findContours(gray, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
n = len(contours)

# Get center coordinates and radii of all circles (converted to int)
circles = [cv2.minEnclosingCircle(cnt) for cnt in contours]
centers = np.array([np.int32(np.round(circ[0])) for circ in circles])

# Find vertical lines within tolerance; calculate mean
tol = 10
x_match = np.array([np.abs(centers[:, 0] - cent[0]) < tol for cent in centers])
lines_global = []
for i in np.arange(n):
    lines_local = []
    lines_local.append(i)
    for j in np.arange(i+1, n):
        if (x_match[i, j]):
            lines_local.append(j)
    if (len(lines_local) > 1):
        lines_global.append(np.int32(np.round(np.mean(centers[lines_local, 0]))))
        for j in lines_local:
            for k in lines_local:
                x_match[j, k] = False
                x_match[k, j] = False

# Draw lines
for line in lines_global:
    cv2.line(img, (line, 0), (line, img.shape[0]), (0, 255, 0), 2)

cv2.imshow('img', img)
cv2.waitKey(0)
cv2.destroyAllWindows()

Токовый выход выглядит следующим образом:

Output

Вы можете установить tol = 0, чтобы получать только точные x совпадения координат, но, как указано изначально, для данного изображения вы не найдете никаких двух окружностей. .

Надеюсь, это поможет!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...