【问题标题】:Python + OpenCV color segmentation using KmeansPython + OpenCV 使用 Kmeans 进行颜色分割
【发布时间】:2016-09-11 19:54:50
【问题描述】:

我正在尝试应用 opencv 中的 kmeans,以便在 HSV 颜色空间中分割图像。

def leftOffset(src, p_countours):
    height, width, size = src.shape

    p_width = width/p_countours
    o_left = src[0:height, 0:p_width]

    HSV_img = cv2.cvtColor(o_left, cv2.COLOR_BGR2HSV)
    hue = HSV_img[0]
    hue = np.float32(HSV_img)

    # Define criteria = ( type, max_iter = 10 , epsilon = 1.0 )
    criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 10, 1.0)

    # Set flags (Just to avoid line break in the code)
    flags = cv2.KMEANS_RANDOM_CENTERS

    # Apply KMeans
    compactness,labels,centers = cv2.kmeans(hue,2,criteria,10,flags)

    centers = np.uint8(centers)
    res = centers[labels.flatten()]
    res2 = res.reshape((hue.shape))
    cv2.imshow("o_left", hue)
    cv2.waitKey(0)

我现在可以将 kmeans 算法应用于 K=2 的 HSVImage[0],如何根据结果获得类似阈值的图像?

谢谢

为了澄清问题: 我有基于颜色的验证码,我想分割每个数字。

图片如

我将使用k-means方法找出主色并分割里面的数字。

【问题讨论】:

  • 我可能不完全理解这个问题。能否请您附上一张图片来澄清一下?
  • @tfv 我添加了 2 张测试图片
  • 你用的是什么版本的opencv?
  • 2.4.8 @YonatanSimson
  • 那么我下面答案中的代码应该适合你

标签: python opencv k-means


【解决方案1】:

1) 如果您只需要找到主色,为什么不找到每个颜色通道的直方图?找到主要频道,然后使用 otsu 仅分割该频道?例如,如果我只对色调进行阈值处理,我可以获得很好的结果。 K-means 对于这项任务来说可能是多余的:

import cv2
import numpy as np
import matplotlib.pylab as plt

## Simple Otsu over hue
six = cv2.imread('7zovC.jpg')

##convert to hsv
hsv = cv2.cvtColor(six, cv2.COLOR_BGR2HSV)
hue = hsv[:, :, 0]

binary_img = cv2.threshold(hue, 128, 255, cv2.THRESH_OTSU)

plt.figure()
plt.imshow(binary_img*255)
plt.show()

2) 为什么不使用所有通道进行聚类而不仅仅是色调?您需要的是聚类 -> 颜色量化,这 link 应该很有用。这是opencv版本> 3.0.0

注意 python 2.4.11,cv2.kmeans 的接口略有不同,您可以使用它来代替:

def color_quantize(img, K):
    Z = img.reshape((-1, 3))

    # convert to np.float32
    Z = np.float32(Z)

    # define criteria, number of clusters(K) and apply kmeans()
    criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 10, 1.0)
    ret, label, center = cv2.kmeans(Z, 2, criteria, 10, cv2.KMEANS_RANDOM_CENTERS)

    # Now convert back into uint8, and make original image
    center = np.uint8(center)
    res = center[label.flatten()]
    quantized_img = res.reshape((img.shape))

    label_img = label.reshape((img.shape[:2]))
    return label_img, quantized_img



six = cv2.imread('7zovC.jpg')


##convert to hsv
hsv = cv2.cvtColor(six, cv2.COLOR_BGR2HSV)

K = 2
label_img, six_q = color_quantize(hsv, K)



plt.figure()
plt.imshow(label_img)

plt.show()

我的颜色量化结果并不令人印象深刻。

【讨论】:

    【解决方案2】:

    我可以建议一个传统的替代方案吗?如果你先去掉非常暗和亮的区域,你也许可以简单地依赖从直方图中计算出的色调分量的最频繁值。

    请注意,数字的边界永远不会绝对准确,因为周围的颜色是相似的。

    此外,您可以仅选择最大 blob(根据大小)来抑制外部剩余的小 blob。

    结果:

    代码:

    import cv2
    import numpy as np
    from matplotlib import pyplot as plt
    
    
    img = cv2.imread('image1.jpg')
    
    #get rid of very bright and very dark regions
    delta=30
    lower_gray = np.array([delta, delta,delta])
    upper_gray = np.array([255-delta,255-delta,255-delta])
    # Threshold the image to get only selected
    mask = cv2.inRange(img, lower_gray, upper_gray)
    # Bitwise-AND mask and original image
    res = cv2.bitwise_and(img,img, mask= mask)
    
    #Convert to HSV space
    HSV_img = cv2.cvtColor(res, cv2.COLOR_BGR2HSV)
    hue = HSV_img[:, :, 0]
    
    #select maximum value of H component from histogram
    hist = cv2.calcHist([hue],[0],None,[256],[0,256])
    hist= hist[1:, :] #suppress black value
    elem = np.argmax(hist)
    print np.max(hist), np.argmax(hist)
    
    tolerance=10
    lower_gray = np.array([elem-tolerance, 0,0])
    upper_gray = np.array([elem+tolerance,255,255])
    # Threshold the image to get only selected
    mask = cv2.inRange(HSV_img, lower_gray, upper_gray)
    # Bitwise-AND mask and original image
    res2 = cv2.bitwise_and(img,img, mask= mask)
    
    
    titles = ['Original Image', 'Selected Gray Values', 'Hue', 'Result']
    images = [img, res, hue, res2]
    for i in xrange(4):
        plt.subplot(2,2,i+1),plt.imshow(images[i],'gray')
        plt.title(titles[i])
        plt.xticks([]),plt.yticks([])
    plt.show()
    

    【讨论】:

      猜你喜欢
      • 2017-12-15
      • 2019-03-19
      • 2016-05-11
      • 1970-01-01
      • 2022-07-06
      • 1970-01-01
      • 2021-12-25
      • 1970-01-01
      • 2021-11-24
      相关资源
      最近更新 更多