【问题标题】:Color segmentation using Kmeans, Opencv Python使用 Kmeans、Opencv Python 进行颜色分割
【发布时间】:2017-12-15 23:32:25
【问题描述】:

我有一个带有字母和不同颜色形状的图像。我需要对它们执行 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()

【问题讨论】:

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


    【解决方案1】:

    好的,所以如果您想将所有被K-Means 归类为“白色”的像素都变为黑色,您需要首先查看哪个标签对应于“白色”类别。您可以通过查看白色 (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()
    

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

    【讨论】:

    • 感谢您的回复先生,但这不是我想要实现的。当我传递任何带有形状和字母的图像时,我只想重新生成两个新图像,一个只有形状,另一个只有字母颜色。先生,我该怎么做?在 c++ 中我们使用 cluster_idx,我如何在 python 中执行此操作?
    • 您的问题还问如何访问中心和标签。你能澄清一下你的意思吗?如果我理解正确,您想要一张去除检测到的物体的图像(就像我在回答中已经通过涂黑形状解释的那样)和还有一张只有提取的物体(字母)的图像?
    • 根据您的评论编辑了我的答案
    • 您能尝试我的解决方案吗,或者它有用吗?
    猜你喜欢
    • 2016-09-11
    • 2019-03-19
    • 2016-05-11
    • 1970-01-01
    • 2022-07-06
    • 1970-01-01
    • 2021-12-25
    • 1970-01-01
    • 2021-11-24
    相关资源
    最近更新 更多