Friday, May 11, 2018

Image segmentation and compression by K-means

Abstract

On this article, I'll try image segmentation and compression by K-means.
This is shown on the popular book, Pattern Recognition And Machine Learning, as an example of K-means. I've never used K-means with setting the segmentation and compression of images as a main purpose, because it is not practical way. But it looks fun on the book. So, I'll try.

Here, for experiment, the code is written in Julia.



K-means code


This time, I’ll use the K-means I made on the article below.
From my GitHub repository, you can clone the codes.

Detail


On image data, each pixel is composed of three factors, R, G and B. We can regard each pixel as a data point. So, for example, the color image with can be expressed as matrix(dataframe). We can adapt K-means to that. By this, each data point will belong to a cluster. By replacing the data point with the corresponding cluster’s centroid, we can do segmentation and compression of image.

Code


The image I’m using is the header image of this blog.
enter image description here

After the image is downloaded on the directory, we can load the image.

using Images

dog = load("dog.jpg")
display(dog)

enter image description here

At first, I'll convert the image data to the appropriate form for K-means. On the code below, the variables, r, g and b are responding to image’s R, G and B’s values.

r = convert(Array{Float64}, vec(red(dog)))
g = convert(Array{Float64}, vec(green(dog)))
b = convert(Array{Float64}, vec(blue(dog)))

Make DataFrame.

using DataFrames

dogImg = DataFrame(r=r, g=g, b=g)

After cloning Cluster repository, I'll include the source code for K-means.

include("./Clustering/src/kmeans.jl")

As a first trial, by setting three as a cluster number, I'll execute K-means to the data.

srand(1234)
k3 = kMeans(dogImg, 3)

To replace the pixels with the cluster’s centroids and to convert the DataFrame to image form, I'll write the functions. There are three functions, splitImg(), dataFrame2Matrix() and updateImg(). By the function splitImg(), the pixels are replaced with corresponding cluster’s centroid. By the function dataFrame2Matrix(), the DataFrame is converted to Matrix. The function updateImg() execute those two functions and make the reshaped output image.

function splitImg(img, kMeansResult)
    k = kMeansResult.k

    splitedImg = deepcopy(img)
    for cluster in 1:k
        indices = find(cluster .== kMeansResult.estimatedClass)

        for index in indices

            splitedImg[index, :] = DataFrame(kMeansResult.centroids[end][cluster])
        end
    end
    return splitedImg
end

function dataFrame2Matrix(data::DataFrame)
  r,c = size(data)
  matrix = zeros(r, c)
  for i in 1:r
      matrix[i, :] = vec(Array(data[i, :]))
  end
  return matrix
end

function updateImg(imgData, kmeansResult, img)

    splitedImg = splitImg(imgData, kmeansResult)
    splitedImgMatrix = dataFrame2Matrix(splitedImg)

    r = reshape(splitedImgMatrix[:, 1], size(img))
    g = reshape(splitedImgMatrix[:, 2], size(img))
    b = reshape(splitedImgMatrix[:, 3], size(img))

    original = rand(RGB, size(img)[1], size(img)[2])

    for row in 1:size(img)[1]
        for col in 1:size(img)[2]
            original[row, col] = RGB(r[row, col], g[row, col], b[row, col])
        end
    end
    return original
end

By executing the function, the output is as following. As you can see, the image is expressed by three colors.

updatedImg = updateImg(dogImg, k3, dog)
display(updatedImg)

enter image description here

Let's check the outcomes of other cluster numbers.

imgs = []
srand(12345)
for k in 2:10
    result = kMeans(dogImg, k; initializer="kmeans++")
    updatedImg = updateImg(dogImg, result, dog)
    push!(imgs, updatedImg)
end

for img in imgs
    display(img)
end

enter image description here
enter image description here
enter image description here
enter image description here
enter image description here
enter image description here
enter image description here
enter image description here
enter image description here

It is fun.