使用Kmeans,Opencv Python进行颜色分割

时间:2017-07-11 18:48:14

标签: python opencv cluster-analysis k-means image-segmentation

我有一个带有字母和不同颜色形状的图像。我需要在它们上执行kmeans聚类,然后提供两个不同的图像,一个只重新生成的形状,另一个只重新生成Letter颜色。 这是一个原始图像示例以及我需要实现的目标。 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()

1 个答案:

答案 0 :(得分:1)

好的,所以如果你想把所有分类为" white"的像素改为黑色。通过K-Means您需要先看到哪个标签对应于" white"类别。您可以通过查看center(包含生成的k中心)中的白色(255,255,255)所属的索引来实现此目的,如下所示:

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已经以某种方式对得到的中心进行排序(更大的像素值往往首先出现),我注意到更靠近白色的中心有更低的索引(因此白色< strong>可能索引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()

编辑:上面的代码获取了检测到的颜色被删除(变黑)的图像。为了获得它的补充,即只有检测到的物体可见的图像,你可以做几件事。一种方法可能是获取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与给定的矩形)。您可以检查详细说明的链接。