【问题标题】:How to plot centroids on image after kmeans clustering?kmeans聚类后如何在图像上绘制质心?
【发布时间】:2019-11-20 06:33:03
【问题描述】:

我有一张彩色图像,想使用 OpenCV 对其进行 k-means 聚类。

这是我想要进行 k-means 聚类的图像。

这是我的代码:

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]]

这是输出图像

我的问题是我无法理解输出。我在center 变量中有两个列表,因为我想要两个类。但是为什么它们只有一个值呢?

不应该是这样的吗(这是有道理的,因为质心应该是点):

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

而不是这个:

[[x]
[y]]

如果我将图像读取为这样的彩色图像:

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

我得到这个输出:

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

彩色图像输出

有人可以向我解释如何获得 2d 点而不是线吗?另外,在使用彩色图像时,如何解释从center 变量得到的输出?

如果我在任何地方不清楚,请告诉我。谢谢!!

【问题讨论】:

  • 你为什么要做kmeans聚类来找到一个绿色三角形的质心?只需使用轮廓或斑点或图像时刻并从中获取质心统计信息。 kmeans 的质心位于色彩空间而非笛卡尔空间。
  • 其实这是一张测试图。我的实际图像看起来像这样pasteboard.co/IntLuRr.png

标签: python opencv k-means centroid


【解决方案1】:

K-Means-clustering 查找具有相似值的集群。您的输入是一组颜色值,因此您可以找到描述 2 个集群的颜色。 [255 255 255] 是白色,[ 89 173 1] 是绿色。灰度版本中的[112][255] 类似。你正在做的是color quantization

它们是正确的质心,但它们的维度是颜色,而不是位置。因此,您不能在任何地方绘制它。好吧,你可以,但我看起来像这样:


看看“颜色位置”如何确定每个像素属于哪个类别?

这不是您可以在图像中找到的东西。您可以做的是找到属于不同集群的像素,并使用找到的像素的位置来确定它们的质心或“平均”位置。

要获得每种颜色的“平均”位置,您必须根据它们所属的类/颜色分离出像素坐标。在下面的代码中,我使用了np.where( img <= 240),其中 240 是阈值。我出于方便而使用了 240,但您可以使用 K-Means 来确定阈值应该在哪里。 (inRange() 在某些时候可能有用))如果将坐标相加并除以找到的像素数,您将拥有我认为您正在寻找的东西:

结果:

代码:

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()

【讨论】:

  • 感谢您的回答。所以它们不是质心?如何获得两个集群的质心坐标?我想在图像上绘制这些坐标。
【解决方案2】:

这是一个 Imagemagick 解决方案,因为我不精通 OpenCV。

基本上,我将您的实际图像(来自 cmets 中的链接)转换为二进制,然后使用图像矩来提取质心和其他统计信息。

我怀疑您可以在基于 Imagemagick 的 OpenCV、Skimage 或 Python Wand 中执行类似的操作。 (例如:

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)


输入:

您的图像不只有两种颜色。也许这张图片没有只应用 2 种颜色的 kmeans 聚类。因此,我将使用自己构建的 Imagemagick 脚本来实现。

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

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


然后我通过简单的阈值化和将动态范围拉伸为全黑和白,将两种颜色转换为黑白。

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


然后我得到白色像素的所有图像矩统计信息,其中包括相对于图像左上角的 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)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-11-16
    • 2020-05-03
    • 2016-07-12
    • 2015-06-05
    • 2011-07-02
    • 2018-08-27
    • 1970-01-01
    • 2018-08-12
    相关资源
    最近更新 更多