kmeans聚类后如何在图像上绘制质心?
How to plot centroids on image after kmeans clustering?
我有一张彩色图像,想使用 OpenCV 对其进行 k 均值聚类。
这是我要对其进行 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]]
这是输出图像
我的问题是我无法理解输出。我在 center
变量中有两个列表,因为我想要两个 类。但是为什么它们只有一个值呢?
不应该是这样的吗(这是有道理的,因为质心应该是点):
[[x1, y1]
[x2, y2]]
而不是这个:
[[x]
[y]]
如果我像这样将图像读取为彩色图像:
image1 = cv2.imread("./triangle.jpg")
Z1 = image1.reshape((-1, 3))
我得到这个输出:
[[255 255 255]
[ 89 173 1]]
彩色图像输出
有人可以向我解释如何获得二维点而不是线吗?另外,如何解释使用彩色图像时从 center
变量获得的输出?
如果我有任何不清楚的地方,请告诉我。谢谢!!
K-Means-clustering 查找相似值的聚类。您的输入是一组颜色值,因此您可以找到描述这 2 个簇的颜色。 [255 255 255]
是白色,[ 89 173 1]
是绿色。与灰度版本中的 [112]
和 [255]
类似。你正在做的是 color quantization
它们是正确的质心,但它们的尺寸是颜色,而不是位置。因此你不能在任何地方绘制它。你可以,但我看起来像这样:
看看 'color location' 如何确定每个像素属于哪个 class?
这不是您可以在图片中找到的东西。您可以做的是找到属于不同簇的像素,并使用找到的像素的位置来确定它们的质心或 'average' 位置。
要得到每种颜色的'average'位置,就得根据它们所属的class/color分离出像素坐标。在下面的代码中,我使用了 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()
这是一个 Imagemagick 解决方案,因为我不精通 OpenCV。
基本上,我将您的实际图像(来自评论中的 link)转换为二进制,然后使用图像矩提取质心和其他统计信息。
我怀疑您可以在基于 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)
我有一张彩色图像,想使用 OpenCV 对其进行 k 均值聚类。
这是我要对其进行 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]]
这是输出图像
我的问题是我无法理解输出。我在 center
变量中有两个列表,因为我想要两个 类。但是为什么它们只有一个值呢?
不应该是这样的吗(这是有道理的,因为质心应该是点):
[[x1, y1]
[x2, y2]]
而不是这个:
[[x]
[y]]
如果我像这样将图像读取为彩色图像:
image1 = cv2.imread("./triangle.jpg")
Z1 = image1.reshape((-1, 3))
我得到这个输出:
[[255 255 255]
[ 89 173 1]]
彩色图像输出
有人可以向我解释如何获得二维点而不是线吗?另外,如何解释使用彩色图像时从 center
变量获得的输出?
如果我有任何不清楚的地方,请告诉我。谢谢!!
K-Means-clustering 查找相似值的聚类。您的输入是一组颜色值,因此您可以找到描述这 2 个簇的颜色。 [255 255 255]
是白色,[ 89 173 1]
是绿色。与灰度版本中的 [112]
和 [255]
类似。你正在做的是 color quantization
它们是正确的质心,但它们的尺寸是颜色,而不是位置。因此你不能在任何地方绘制它。你可以,但我看起来像这样:
看看 'color location' 如何确定每个像素属于哪个 class?
这不是您可以在图片中找到的东西。您可以做的是找到属于不同簇的像素,并使用找到的像素的位置来确定它们的质心或 'average' 位置。
要得到每种颜色的'average'位置,就得根据它们所属的class/color分离出像素坐标。在下面的代码中,我使用了 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()
这是一个 Imagemagick 解决方案,因为我不精通 OpenCV。
基本上,我将您的实际图像(来自评论中的 link)转换为二进制,然后使用图像矩提取质心和其他统计信息。
我怀疑您可以在基于 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)