使用 Kmeans、Opencv 进行颜色分割 Python
Color segmentation using Kmeans, Opencv Python
我有一张图片,上面有一个字母和不同颜色的形状。我需要对它们执行 kmeans 聚类,然后提供两张不同的图像,一张仅重新生成形状,另一张仅重新生成字母颜色。
这是原始图像示例以及我需要实现的目标。 Original Image
Shape color regenerated
同样,另一个只有白色 R.
我已成功执行 kmeans 聚类算法,如何访问标签和聚类 idx 以重新生成所需的结果?有人可以用示例代码来说明。这是代码。提前致谢。
import numpy as np
import cv2
img = cv2.imread("/home/manohar/Outputs/Targets/m-0.PNG",1)
cv2.imshow("original",img)
Z = img.reshape((-1,3))
# convert to np.float32
Z = np.float32(Z)
# Here we are applying k-means clustering so that the pixels around a colour are consistent and gave same BGR/HSV values
# define criteria, number of clusters(K) and apply kmeans()
criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 10, 1.0)
# We are going to cluster with k = 2, because the image will have just two colours ,a white background and the colour of the patch
K = 3
attempts=10
ret,label,center=cv2.kmeans(Z,K,None,criteria,attempts,cv2.KMEANS_PP_CENTERS)
# Now convert back into uint8
#now we have to access the labels to regenerate the clustered image
center = np.uint8(center)
res = center[label.flatten()]
res2 = res.reshape((img.shape))
#res2 is the result of the frame which has undergone k-means clustering
cv2.imshow("res2",res2)
cv2.waitKey()
cv2.destroyAllWindows()
好的,所以如果你想把所有被K-Means
分类为"white"的像素都变成黑色,你需要先看看哪个标签对应于"white"类别。您可以通过查看白色 (255,255,255
) 属于 center
(其中包含生成的 k 个中心)中的哪个索引来实现此目的,如下所示:
white_index = 0
for b,g,r in center:
#check if it is white
if b == g == r == 255:
#then this is the white category
break
white_index = white_index + 1
请注意,由于 k-means
是一种无监督方法,您的类别可能不一定 完全 白色(它可能类似于 250,249,254
)。所以你在搜索索引时应该考虑到这一点,即你应该寻找更接近白色的颜色。您可以通过应用 color distance 公式比较您的颜色来实现此目的。
然而根据我的经验,我相信 center
已经以某种方式对结果中心进行排序(较大的像素值往往首先出现),并且我注意到靠近白色的中心具有较低的索引(因此白色 可能是 索引 0)。不过最好确认一下。
既然您知道什么索引对应于白色,您就可以在 label
变量中看到哪些像素被归类为白色。为此,您可以采用多种方法,并且肯定会比其他方法更有效,一种方法可能是:
#Copy image to modify it
img_copy = img[:]
#Reshape label to match the original image
new_label = label.reshape(img.shape)
#iterate over new_label, and if the category is white
#paint pixel corresponding to row,col black
row = 0
for i in new_label:
column = 0
for category in i:
if category == white_index:
#paint that pixel black
img_copy[row,column] = [0, 0, 0]
column = column + 1
row = row + 1
#now show edited image
cv2.imshow("Object Removed",img_copy)
cv2.waitKey()
cv2.destroyAllWindows()
Edit: 上面的代码得到了一张去除检测到的颜色(涂黑)的图像。为了获得它的补充,即只有检测到的对象可见的图像,您可以做几件事。一种方法是获取 img
的副本并涂黑不是该颜色的像素(没有 category == white_index
),例如:
#Obtain another copy of image to modify it
extract = img[:]
#Now do the opposite, iterate over new_label, and if the category is Not white
#paint pixel corresponding to row,col black
row = 0
for i in new_label:
column = 0
for category in i:
if category != white_index:
#paint that pixel black
extract[row,column] = [0, 0, 0]
column = column + 1
row = row + 1
#show or do whatever you want...
另一种更复杂的仅获取提取对象的方法是获取对象的 contour(通过阈值处理并使用 cv2.findContours()
),然后应用 cv2.boundingRect()
,这样您就可以获得带有对象的较小剪辑(通过使用给定矩形剪辑 img
)。您可以在详细说明的地方查看 link。
我有一张图片,上面有一个字母和不同颜色的形状。我需要对它们执行 kmeans 聚类,然后提供两张不同的图像,一张仅重新生成形状,另一张仅重新生成字母颜色。 这是原始图像示例以及我需要实现的目标。 Original Image
Shape color regenerated 同样,另一个只有白色 R.
我已成功执行 kmeans 聚类算法,如何访问标签和聚类 idx 以重新生成所需的结果?有人可以用示例代码来说明。这是代码。提前致谢。
import numpy as np
import cv2
img = cv2.imread("/home/manohar/Outputs/Targets/m-0.PNG",1)
cv2.imshow("original",img)
Z = img.reshape((-1,3))
# convert to np.float32
Z = np.float32(Z)
# Here we are applying k-means clustering so that the pixels around a colour are consistent and gave same BGR/HSV values
# define criteria, number of clusters(K) and apply kmeans()
criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 10, 1.0)
# We are going to cluster with k = 2, because the image will have just two colours ,a white background and the colour of the patch
K = 3
attempts=10
ret,label,center=cv2.kmeans(Z,K,None,criteria,attempts,cv2.KMEANS_PP_CENTERS)
# Now convert back into uint8
#now we have to access the labels to regenerate the clustered image
center = np.uint8(center)
res = center[label.flatten()]
res2 = res.reshape((img.shape))
#res2 is the result of the frame which has undergone k-means clustering
cv2.imshow("res2",res2)
cv2.waitKey()
cv2.destroyAllWindows()
好的,所以如果你想把所有被K-Means
分类为"white"的像素都变成黑色,你需要先看看哪个标签对应于"white"类别。您可以通过查看白色 (255,255,255
) 属于 center
(其中包含生成的 k 个中心)中的哪个索引来实现此目的,如下所示:
white_index = 0
for b,g,r in center:
#check if it is white
if b == g == r == 255:
#then this is the white category
break
white_index = white_index + 1
请注意,由于 k-means
是一种无监督方法,您的类别可能不一定 完全 白色(它可能类似于 250,249,254
)。所以你在搜索索引时应该考虑到这一点,即你应该寻找更接近白色的颜色。您可以通过应用 color distance 公式比较您的颜色来实现此目的。
然而根据我的经验,我相信 center
已经以某种方式对结果中心进行排序(较大的像素值往往首先出现),并且我注意到靠近白色的中心具有较低的索引(因此白色 可能是 索引 0)。不过最好确认一下。
既然您知道什么索引对应于白色,您就可以在 label
变量中看到哪些像素被归类为白色。为此,您可以采用多种方法,并且肯定会比其他方法更有效,一种方法可能是:
#Copy image to modify it
img_copy = img[:]
#Reshape label to match the original image
new_label = label.reshape(img.shape)
#iterate over new_label, and if the category is white
#paint pixel corresponding to row,col black
row = 0
for i in new_label:
column = 0
for category in i:
if category == white_index:
#paint that pixel black
img_copy[row,column] = [0, 0, 0]
column = column + 1
row = row + 1
#now show edited image
cv2.imshow("Object Removed",img_copy)
cv2.waitKey()
cv2.destroyAllWindows()
Edit: 上面的代码得到了一张去除检测到的颜色(涂黑)的图像。为了获得它的补充,即只有检测到的对象可见的图像,您可以做几件事。一种方法是获取 img
的副本并涂黑不是该颜色的像素(没有 category == white_index
),例如:
#Obtain another copy of image to modify it
extract = img[:]
#Now do the opposite, iterate over new_label, and if the category is Not white
#paint pixel corresponding to row,col black
row = 0
for i in new_label:
column = 0
for category in i:
if category != white_index:
#paint that pixel black
extract[row,column] = [0, 0, 0]
column = column + 1
row = row + 1
#show or do whatever you want...
另一种更复杂的仅获取提取对象的方法是获取对象的 contour(通过阈值处理并使用 cv2.findContours()
),然后应用 cv2.boundingRect()
,这样您就可以获得带有对象的较小剪辑(通过使用给定矩形剪辑 img
)。您可以在详细说明的地方查看 link。