Как нарисовать контуры вокруг круглого объекта и найти его рентабельность с помощью OpenCV Python?

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

введите здесь описание изображения

Ожидаемый результат:

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

Ниже прилагается код.

Код:

import cv2
import numpy as np
import imutils

cap = cv2.VideoCapture(0)

cap.set(3,640)
cap.set(4,480)

while True:
    _,frame = cap.read()
    hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)

    lower_blue = np.array([90,60,0])
    upper_blue = np.array([121,255,255])

    mask = cv2.inRange(hsv, lower_blue, upper_blue)
    cnts = cv2.findContours(mask, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
    cnts= imutils.grab_contours(cnts)

    for c in cnts:
        area = cv2.contourArea(c)
        if area > 1500:
            cv2.drawContours(frame, [c], -1, (0,255,0), 3)
            M = cv2.moments(c)
            cx = int(M["m10"] / M["m00"])
            cy = int(M["m01"] / M["m00"])

            cv2.circle(frame, (cx, cy), 7, (255, 255, 255), -1)
            cv2.putText(frame, "Centre", (cx - 20, cy - 20), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 255, 0), 1)

            cv2.imshow("frame", frame)


            print("area is ...", area)
            print("centroid is at ...", cx, cy)

    k=cv2.waitKey(1000)
    if k ==27:
        break
cap.release()
cv2.destroyAllWindows()

Любая помощь будет оценена по достоинству. Заранее спасибо.


person shantmanu    schedule 07.01.2020    source источник
comment
Возможно, вам следует отфильтровать контуры по функциям анализа формы, которые измеряют округлость или используют обнаружение HoughCircle. См. www2.humusoft.cz/www/papers/tcb10/040_horejs.pdf или opencvpython.blogspot.com/2012/04/contour-features.html   -  person fmw42    schedule 07.01.2020
comment
Можно использовать снимки экрана с синими рамками вокруг них и зелеными аннотациями внутри для отображения результатов, но также предоставьте исходное изображение без аннотаций и рамок, чтобы люди могли попробовать свои собственные алгоритмы.   -  person Mark Setchell    schedule 07.01.2020
comment
Почему бы вам не использовать методы на основе цвета, такие как пороговое значение?   -  person MH304    schedule 07.01.2020


Ответы (1)


Это можно сделать разными способами в зависимости от необходимости. Один простой способ может быть:

Во-первых, отфильтруйте ROI. Итак, мы знаем 3 вещи: ROI белого цвета, представляет собой круг, и мы знаем его приблизительную площадь.

Для белого цвета:

def detect_white(img):
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    _, thresh = cv2.threshold(gray, 220, 255, cv2.THRESH_BINARY)
    return thresh

Хотя вам нужно будет поиграть с алгоритмом обнаружения белого в соответствии с вашими потребностями. Некоторыми хорошими способами обнаружения белого цвета могут быть пороговое значение (как указано выше), использование цветового пространства HSL, поскольку белизна тесно зависит от яркости (cv2.cvtColor(img, cv2.COLOR_BGR2HLS) и т. д.


Итак, в приведенном ниже коде сначала мы отфильтровываем ROI по белому цвету, а затем по форме и площади этих белых контуров.

image = cv2.imread("path/to/your/image")

white_only = detect_white(image)

contours, hierarchy = cv2.findContours(white_only, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)

circles = []

for contour in contours:
    epsilon = 0.01 * cv2.arcLength(contour, True)
    approx = cv2.approxPolyDP(contour, epsilon, True)
    area = cv2.contourArea(contour)
    if len(approx) > 12 and area > 1000 and area < 3000:
        circles.append(contour)

# Now the list circles would have all such
# contours satisfying the above conditions
# If len(circles) != 1 or isn't the circle you
# desire, more filtering is required

cv2.drawContours(image, circles, -1, (0, 255, 0), 3)

Выбор контура зависит от площади и вершин (как возвращается cv2. approxPolyDP()).

Как и на вашем изображении, большой белый круг имеет большую площадь и очень близок к кругу, я проверил его, например: len(approx) > 12 and area > 1000 and area < 3000:. Настройте эту строку в соответствии со своим сценарием и скажите, решит ли это вашу проблему. Если это не так, мы можем обсудить другие способы или поэкспериментировать с этим, чтобы сделать его более точным.

person Mihir Luthra    schedule 08.01.2020
comment
Спасибо @Михир. Я думаю, что это относится к файлам изображений. В приведенном выше коде я имею дело с видеокадрами Opencv. cap = cv2.VideoCapture(0) Как этого добиться с помощью видео в реальном времени? - person shantmanu; 09.01.2020
comment
@shantmanu Видите ли, видео — это последовательность изображений или кадров. См., например, эту ссылку (cap.read() извлекает кадр или назовите это изображением). Если в вашем видео движущиеся объекты, рассмотрите возможность удаления размытия движения из захваченный кадр. Если вы не получаете хороших результатов от определенного кадра, примените свой алгоритм к следующему кадру. - person Mihir Luthra; 09.01.2020
comment
Вы можете изменить частоту извлечения кадров с помощью cap.set() - person Mihir Luthra; 09.01.2020
comment
Вот несколько полезных приемов работы с видео. Также основные сведения см. в этом ссылка. - person Mihir Luthra; 09.01.2020
comment
Я использовал cap.set(3,640) и cap.set(4,480) для установки частоты. - person shantmanu; 09.01.2020
comment
@shantmanu, посмотрите флаги для cap.set() здесь: docs.opencv.org/2.4/modules/highgui/doc/. 3 и 4 предназначены для ширины и высоты или захваченного кадра, а не для частоты. - person Mihir Luthra; 09.01.2020
comment
Извиняюсь. Я получил ваше предложение. Спасибо. Я постараюсь реализовать вашу логику и сообщу вам, если у меня возникнут какие-либо проблемы. - person shantmanu; 09.01.2020