2016-05-16 462 views
2

我想从opencv应用kmeans为了在HSV色彩空间中分割图像。Python + OpenCV颜色分割使用Kmeans

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) 

我现在能够在k均值算法应用于HSVImage [0] K = 2,我怎么能得到这样的阈值的图像根据结果呢?

感谢

要澄清一个问题: 我有基于颜色的验证码,我想每一个细分的数字。

的形象就像6

1

我将使用K-means法,找出主色和段内的数字。

+0

我不能完全理解这个问题。你能否通过加入图像来澄清? – tfv

+0

@tfv我已添加2个测试图像 – Mix

+0

您使用的是什么版本的opencv? –

回答

3

我可以提出一个传统的替代方案吗?我首先摆脱了非常黑暗和明亮的区域,您可能仅仅依靠从直方图计算出的色调分量的最频繁值。

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

此外,您可以选择仅限于最大斑点(根据大小)以抑制外部剩余的小斑点。

结果:

enter image description here

代码:

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() 
2

1)如果你只需要找到主色,为什么不找到每个颜色通道的直方图?找到主导通道,然后使用otsu分段该通道?例如,如果我仅限于色相,我可以得到很好的结果。 K-手段可能是承担这一任务的矫枉过正:

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的版本>为Python 3.0.0 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() 

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