提取图像的k均值聚类的特定成员

时间:2018-12-19 09:29:47

标签: python numpy opencv image-processing

我有一个图像(正面的人),具有4种不同的颜色(背景,头发,肤色和衣服)。我用k = 4的k-mean进行了图像分割。现在我要做的是从图像中拔出头发。

我使用canny边缘检测来检测边缘,这有助于检测头发区域中的点(由红点指出)。现在,我想提取头发区域,如红点所指出的k均值成员。有可能吗?

或者还有其他方法可以从一个人的图像中提取出头发区域?

到目前为止完成的代码是:

import cv2
import numpy as np

image1 = cv2.imread('Test1.jpg')

#Resizing Image for fixed width
def image_resize(image1, width = None, height = None, inter = 
cv2.INTER_AREA):
    # initialize the dimensions of the image to be resized and
    # grab the image size
    dim = None
    (h, w) = image1.shape[:2]

    # if both the width and height are None, then return the
    # original image
    if width is None and height is None:
        return image1

    # check to see if the width is None
    if width is None:
        # calculate the ratio of the height and construct the
        # dimensions
        r = height / float(h)
        dim = (int(w * r), height)

    # otherwise, the height is None
    else:
        # calculate the ratio of the width and construct the
        # dimensions
        r = width / float(w)
        dim = (width, int(h * r))

    # resize the image
    resized = cv2.resize(image1, dim, interpolation = inter)

    # return the resized image
    return resized


img1 = image_resize(image1, width = 500)

cv2.imshow("Resized", img1)
cv2.waitKey(0)

#Detecting Edge of image
canny = cv2.Canny(img1, 100, 150)

cv2.imshow("Edge", canny)
cv2.waitKey(0)

coords = np.nonzero(canny)

topmost_y = np.min(coords[0])


#Blurring effect

img2 = cv2.medianBlur(img1, 5)

cv2.imshow("Blurred", img2)
cv2.waitKey(0)

#K-mean approach
Z = img2.reshape((-1,3))
Z = np.float32(Z)

criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 10, 1.0)

K=4
ret, label1, center1 = cv2.kmeans(Z, K, None,
                                          criteria, 10, 
cv2.KMEANS_RANDOM_CENTERS)
center1 = np.uint8(center1)
res1 = center1[label1.flatten()]
output1 = res1.reshape((img2.shape))

cv2.circle(output1, (250, topmost_y + 20), 5, (0,0,255), -1)

cv2.imshow("k = 4", output1)
cv2.waitKey(0)
cv2.destroyAllWindows()

图片:

Original ImageResult after resizingCanny Edge detectionBlurredK-mean

2 个答案:

答案 0 :(得分:1)

给出已有的代码,只需几行即可获得头发所属簇的xy坐标。您还可以创建仅显示头发簇的图像:

# find the index of the cluster of the hair
mask = label1.reshape(output1.shape[:-1])
khair = mask[(topmost_y + 20, 250)]

# get a mask that's True at all of the indices of hair's group
hairmask = mask==khair

# get the hair's cluster's xy coordinates
xyhair = hairmask.nonzero()

# plot an image with only the hair's cluster on a white background
cv2.imwrite("khair.jpg", np.where(hairmask[..., None], img1, [255,255,255]))

这是头发簇的样子:

enter image description here

一旦有了头发簇,就可以找到代表“只是头发”的斑点。这是您的处理方式:

import scipy.ndimage as snd

# label all connected blobs in hairmask
bloblab = snd.label(hairmask, structure=np.ones((3,3)))[0]

# create a mask for only the hair
haironlymask = bloblab == bloblab[topmost_y + 20, 250]

# get an image with just the hair and then crop it
justhair = np.where(haironlymask[..., None], img1, [255,255,255])
nz = haironlymask.nonzero()
justhair = justhair[nz[0].min():nz[0].max(), nz[1].min():nz[1].max()]

# save the image of just the hair on a white background
cv2.imwrite("justhair.jpg", justhair)

这是你的头发本身的图像:

enter image description here

答案 1 :(得分:0)

现在在该头发区域中有一个点,将该点传播到所有其他点。

伪代码为:

set =红点    虽然头发不会改变:        将所有点(i-1,j)(i + 1,j)(i,j-1)(i,j + 1)添加到集合        将集合与棕色点的遮罩相交

最后,您的头发将带有面具。

您可以在numpy中轻松地做到这一点,方法是从一个布尔图像开始,在红色点处只有一个True元素,然后使用|=&=运算符。我怀疑OpenCV也有这种形态膨胀算子。