Как нанести центроиды на изображение после кластеризации kmeans? - PullRequest
1 голос
/ 10 июля 2019

У меня есть цветное изображение, и я хотел сделать кластеризацию на нем с помощью OpenCV.

This is the image

Это изображение, на котором я хотел сделать кластеризацию k-средних.

Это мой код:

import numpy as np
import cv2
import matplotlib.pyplot as plt

image1 = cv2.imread("./triangle.jpg", 0)
Z1 = image1.reshape((-1))

Z1 = np.float32(Z1)

criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 10, 1.0)

K1 = 2

ret, mask, center =cv2.kmeans(Z1,K1,None,criteria,10,cv2.KMEANS_RANDOM_CENTERS)

center = np.uint8(center)
print(center)
res_image1 = center[mask.flatten()]
clustered_image1 = res_image1.reshape((image1.shape))

for c in center:
        plt.hlines(c, xmin=0, xmax=max(clustered_image1.shape[0], clustered_image1.shape[1]), lw=1.)

plt.imshow(clustered_image1)
plt.show()

Это то, что я получаю из переменной center.

[[112]
 [255]]

Это выходное изображение

This is the output image

Моя проблема в том, что я не могу понять вывод. У меня есть два списка в переменной center, потому что я хотел два класса. Но почему у них есть только одно значение?

Не должно ли быть что-то подобное (что имеет смысл, потому что центроиды должны быть точками):

[[x1, y1]
[x2, y2]]

вместо этого:

[[x]
[y]]

и если я читаю изображение как цветное изображение, вот так:

image1 = cv2.imread("./triangle.jpg")
Z1 = image1.reshape((-1, 3))

Я получаю этот вывод:

[[255 255 255]
 [ 89 173   1]]

Вывод цветного изображения

color_image_output

Может кто-нибудь объяснить мне, как я могу получить 2d очки вместо линий? Кроме того, как интерпретировать вывод, полученный из переменной center при использовании цветного изображения?

Пожалуйста, дайте мне знать, если мне где-то неясно. Спасибо !!

Ответы [ 2 ]

0 голосов
/ 11 июля 2019

Вот решение Imagemagick, так как я не разбираюсь в OpenCV.

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

Я подозреваю, что вы можете сделать что-то подобное в OpenCV, Skimage или Python Wand, основанном на Imagemagick.(См. Например:

https://docs.opencv.org/3.4/d3/dc0/group__imgproc__shape.html#ga556a180f43cab22649c23ada36a8a139

https://scikit-image.org/docs/dev/api/skimage.measure.html#skimage.measure.moments_coords_central

https://en.wikipedia.org/wiki/Image_moment)


Ввод:

enter image description here

Ваше изображение нетолько два цвета. Возможно, к этому изображению не применена кластеризация kmeans только с двумя цветами. Поэтому я сделаю это с помощью созданного мной сценария Imagemagick.

kmeans -n 2 -m 5 img.png img2.png

final colors:
count,hexcolor
99234,#65345DFF
36926,#27AD0EFF


enter image description here

Затем я преобразую два цвета в черный и белый, просто установив порог и расширив динамический диапазон до полного черного и белого.

convert img2.png -threshold 50% -auto-level img3.png


enter image description here

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

identify -verbose -moments img3.png
  Channel moments:
    Gray:
      --> Centroid: 208.523,196.302 <--
      Ellipse Semi-Major/Minor axis: 170.99,164.34
      Ellipse angle: 140.853
      Ellipse eccentricity: 0.197209
      Ellipse intensity: 106.661 (0.41828)
      I1: 0.00149333 (0.380798)
      I2: 3.50537e-09 (0.000227937)
      I3: 2.10942e-10 (0.00349771)
      I4: 7.75424e-13 (1.28576e-05)
      I5: 9.78445e-24 (2.69016e-09)
      I6: -4.20164e-17 (-1.77656e-07)
      I7: 1.61745e-24 (4.44704e-10)
      I8: 9.25127e-18 (3.91167e-08)
0 голосов
/ 11 июля 2019

K-Means-кластеризация находит кластеры с одинаковыми значениями.Ваш ввод представляет собой массив значений цвета, следовательно, вы найдете цвета, которые описывают 2 кластера.[255 255 255] - белый цвет, [ 89 173 1] - зеленый.Аналогично для [112] и [255] в версии в оттенках серого.То, что вы делаете, это цветовое квантование

Они правильно центроиды, но их размер - цвет, а не местоположение.Поэтому вы нигде не можете построить это.Ну, вы можете, но я выгляжу так:

enter image description here
Посмотрите, как «местоположение цвета» определяет, какому классу принадлежит каждый пиксель?

Это не то, что вы можете найти на своем изображении.Что вы можете сделать, так это найти пиксели, которые принадлежат различным кластерам, и использовать местоположения найденных пикселей, чтобы определить их центроид или «среднее» положение.

Чтобы получить «среднее» положение каждого цвета,Вы должны выделить пиксельные координаты в соответствии с классом / цветом, к которому они принадлежат.В приведенном ниже коде я использовал np.where( img <= 240), где 240 - порог.Я использовал 240 с легкостью, но вы можете использовать K-Means, чтобы определить, где должен быть порог.( inRange () может быть полезно в какой-то момент)) Если вы сложите координаты и поделите их на количество найденных пикселей, у вас будет то, что, я думаю, вы ищете:

Результат:

enter image description here

Код:

import cv2 

# load image as grayscale
img = cv2.imread('D21VU.jpg',0)

# get the positions of all pixels that are not full white (= triangle)
triangle_px = np.where( img <= 240)
# dividing the sum of the values by the number of pixels
# to get the average location
ty = int(sum(triangle_px[0])/len(triangle_px[0]))
tx = int(sum(triangle_px[1])/len(triangle_px[1]))
# print location and draw filled black circle
print("Triangle ({},{})".format(tx,ty))
cv2.circle(img, (tx,ty), 10,(0), -1)


# the same process, but now with only white pixels
white_px = np.where( img > 240)
wy = int(sum(white_px[0])/len(white_px[0]))
wx = int(sum(white_px[1])/len(white_px[1]))
# print location and draw white filled circle
print("White: ({},{})".format(wx,wy))
cv2.circle(img, (wx,wy), 10,(255), -1)

# display result
cv2.imshow('Result',img)
cv2.waitKey(0)
cv2.destroyAllWindows()
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...