代码之家  ›  专栏  ›  技术社区  ›  Manohar

使用Kmeans、Opencv-Python进行颜色分割

  •  2
  • Manohar  · 技术社区  · 8 年前

    我有一个带有字母和不同颜色形状的图像。我需要对它们执行kmeans聚类,然后提供两个不同的图像,一个仅再生形状,另一个仅再生字母颜色。 Original Image

    Shape color regenerated 类似地,另一个只有白色R。

    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 回复  |  直到 8 年前
        1
  •  2
  •   DarkCygnus    8 年前

    好的,如果你想把所有被分类为“白色”的像素都改成黑色 K-Means 您需要首先查看哪个标签对应于“白色”类别。您可以通过查看中的索引来实现这一点 center 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

    居中 已经以某种方式对结果中心进行了排序(较大的像素值往往首先出现),我注意到靠近白色的中心具有较低的索引(因此为白色) 索引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() 因此,您可以使用对象获得较小的剪辑(通过剪辑