OpenCV фильтр изображения, сегментация, кластеризация

Есть вот такая картинка(см. цветную) История происхождения картинки, есть 3D камера, она предаёт массив с координатами и расстояниями до каждой точки, чем число больше тем пиксель ближе к камере (на картинке чем больше пиксель тем он краснее) введите сюда описание изображения С помощью фильтров я её преобразовываю в черно берую:

@dataclass
class Root:
    lower_ = 510
    upper_ = 530
    se1 = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (9, 9))
    se2 = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (13, 13))

    def new_data(self):
        for frame in glob.glob('\*npy'):

            frame = np.load(frame)
            frame2 = plt.cm.jet(norm(frame))
            cv2.imshow('test', frame2)

            threshold1 = cv2.threshold(frame, self.lower_, 65535, cv2.THRESH_BINARY_INV)[1]
            threshold2 = cv2.threshold(frame, self.upper_, 65535, cv2.THRESH_BINARY)[1]
            threshold = cv2.bitwise_or(threshold1, threshold2)

            mask = cv2.morphologyEx(threshold, cv2.MORPH_OPEN, self.se1)
            mask = cv2.morphologyEx(mask, cv2.MORPH_CLOSE, self.se2)


Root().new_data()

Далее с помощью opencv(connected Components With Stats) нахожу центры объектов:

out_img =np.uint8(cv2.threshold(mask, 0, 65535, cv2.THRESH_BINARY_INV)[1])

output = cv2.connectedComponentsWithStats(out_img, 4, cv2.CV_32S)
(numLabels, labels, stats, centroids) = output

for i in centroids:
    cv2.circle(out_img, (int(i[0]), int(i[1])), 7, (0, 0, 255), -1)

cv2.imshow('test3', out_img)

Но некоторые объекты(обвел красным) сливаются в один, чем я могу разделить их
Может быть есть аналоги connectedComponentsWithStats, или какие ещё фильтры можно добавить чтобы разделить объекты.
Сейчас как видно из кода использую перевод изображения в бинарный вид, морфологическое открытие и закрытие

На выходе хочу получить такую картинку чтобы opencv(connected Components With Stats) смог разделить объекты.


Ответы (1 шт):

Автор решения: 0dminnimda

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

import numpy as np
import cv2 as cv

def nothing(x):
    pass

cv.namedWindow("Tracking")
cv.createTrackbar("LH", "Tracking", 0, 255, nothing)
cv.createTrackbar("LS", "Tracking", 0, 255, nothing)
cv.createTrackbar("LV", "Tracking", 0, 255, nothing)
cv.createTrackbar("UH", "Tracking", 255, 255, nothing)
cv.createTrackbar("US", "Tracking", 255, 255, nothing)
cv.createTrackbar("UV", "Tracking", 255, 255, nothing)

cv.setTrackbarPos("LH", "Tracking", 0)
cv.setTrackbarPos("LS", "Tracking", 255)
cv.setTrackbarPos("LV", "Tracking", 129)
cv.setTrackbarPos("LH", "Tracking", 15)
cv.setTrackbarPos("LS", "Tracking", 255)
cv.setTrackbarPos("LV", "Tracking", 255)

path = ...
frame = np.array(cv.imread(path))
hsv = cv.cvtColor(frame, cv.COLOR_BGR2HSV)

while 1:
    l_h = cv.getTrackbarPos("LH", "Tracking")
    l_s = cv.getTrackbarPos("LS", "Tracking")
    l_v = cv.getTrackbarPos("LV", "Tracking")

    u_h = cv.getTrackbarPos("UH", "Tracking")
    u_s = cv.getTrackbarPos("US", "Tracking")
    u_v = cv.getTrackbarPos("UV", "Tracking")

    l_b = np.array([l_h, l_s, l_v])
    u_b = np.array([u_h, u_s, u_v])

    mask = cv.inRange(hsv, l_b, u_b)
    res = cv.bitwise_and(frame, frame, mask=mask)

    cv.imshow("frame", frame)
    cv.imshow("mask", mask)
    cv.imshow("res", res)

    if cv.waitKey(1) & 0xFF == ord("q"):
        cv.destroyAllWindows()
        break

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

Дополнение с точками:

...

se1 = cv.getStructuringElement(cv.MORPH_ELLIPSE, (9, 9))
se2 = cv.getStructuringElement(cv.MORPH_ELLIPSE, (13, 13))

while 1:
    ...
    mask = cv.morphologyEx(mask, cv.MORPH_OPEN, se1)
    mask = cv.morphologyEx(mask, cv.MORPH_CLOSE, se2)

    out_img = np.uint8(cv.threshold(mask, 0, 65535, 0)[1])

    output = cv.connectedComponentsWithStats(out_img, 4, cv.CV_32S)
    (numLabels, labels, stats, centroids) = output

    for i in centroids:
        cv.circle(out_img, (int(i[0]), int(i[1])), 7, (0, 0, 255), -1)

    cv.imshow('dots', out_img)

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

Я бы ещё подумал о нормализации интенсивности пикселей на результате применении маски и вторичном применении inRange

Напмриер

...

cv.createTrackbar("alpha", "Tracking", 511, 511, nothing)
cv.createTrackbar("beta", "Tracking", 0, 511, nothing)

...

original_frame = np.array(cv.imread(path))

...

while 1:
   ...

    frame = cv.convertScaleAbs(original_frame,
                               alpha=cv.getTrackbarPos("alpha", "Tracking") / 100,
                               beta=cv.getTrackbarPos("beta", "Tracking") / 10)
    hsv = cv.cvtColor(frame, cv.COLOR_BGR2HSV)

И если поиграться, можно получить такое, например: введите сюда описание изображения или такое введите сюда описание изображения

→ Ссылка