Kmean algorithm on high resolution images - python

I have an image with 22500x55000x3 shape and I want to apply kmean algorithm on this image. Unfortunatelly it takes so much time even if I run the algorithm in a server. What can be done for this situation ?
Here the code I used.
import os
os.environ["OPENCV_IO_MAX_IMAGE_PIXELS"] = pow(2,40).__str__()
import cv2
import numpy
import json
import matplotlib.pyplot as plt
image = cv2.imread("images/2021/true_color_08.jpg")
mask = cv2.imread("images/2021/09/all_08.jpg")
image = cv2.bitwise_and(image,mask, dst = image)
pixel_values = image.reshape((-1, 3))
# convert to float
pixel_values = numpy.float32(pixel_values)
criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 100, 0.2)
k = 4
_, labels, (centers) = cv2.kmeans(pixel_values, k, None, criteria, 10, cv2.KMEANS_RANDOM_CENTERS)
# convert back to 8 bit values
centers = numpy.uint8(centers)
centers[0] = [255,255,255]
centers[1] = [255,0,0]
centers[2] = [0,255,0]
centers[3] = [0,0,255]
# flatten the labels array
labels = labels.flatten()
segmented_image = centers[labels]
# reshape back to the original image dimension
segmented_image = segmented_image.reshape(image.shape)
# show the image
plt.imshow(segmented_image)
plt.show()

Related

How 2 reconstruct image after k-means segmentation in 5-dim feature space?

I use opencv for an image segmentation in 5 dimensional feature space {r,g,b,x,y} to get better result. The problem is after segmentation is done I can't reconstruct segmented clusters back into image. I don't understand how to do it. What I did is just deleted last 2 columns in segmentedData array to match original image shape. But this doesn't work. The opencv example shows how to do this in just 3-dimensional feature space {r,g,b}. Do you have any ideas?
Thanks.
Below is the code.
import numpy as np
import matplotlib.pyplot as plt
import cv2
img = cv2.imread("../images/segmentation/peppers_BlueHills.png")
x = np.arange(0, img.shape[0])
x = np.tile(x, img.shape[1]).reshape((-1,1))
x = np.float32(x)
y = np.arange(0, img.shape[1])
y = np.repeat(y, img.shape[0]).reshape((-1,1))
y = np.float32(y)
# Reshaping the image into a 2D array of pixels and 3 color values (RGB)
pixelVals = img.reshape((-1,3))
# Convert to float type only for supporting cv2.kmean
pixelVals = np.float32(pixelVals)
features = np.hstack((pixelVals,x,y))
criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 100, 0.85) #criteria 0.85
k = 16 # Number of cluster
ret, labels, centers = cv2.kmeans(features, k, None, criteria, 10, cv2.KMEANS_PP_CENTERS)
centers = np.uint8(centers) # convert data into 8-bit values
segmentedData = centers[labels.flatten()] # Mapping labels to center points( RGB Value)
#segmentedImg = segmentedData.reshape((img.shape)) # reshape data into the original image dimensions
segmentedImg = segmentedData.reshape((img.shape[0],img.shape[1],img.shape[2]+2))
segmentedImg = np.delete(segmentedImg, [3,4], axis=2)
cv2.imshow('segmentedImg', segmentedImg)
cv2.waitKey(0)

How to create mask using k means clustering?

I am using k means clustering on an image. I am finding 2 or 3 regions via k-means. Now I want to create a mask for each region so that I can separate them in my original image.
Following is the code I am using currently.
import numpy as np
import matplotlib.pyplot as plt
import cv2
%matplotlib inline
# Read in the image
image = cv2.imread('/content/istockphoto-1201224719-612x612.jpg')
# Change color to RGB (from BGR)
image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
pixel_vals = image.reshape((-1,3))
# Convert to float type
pixel_vals = np.float32(pixel_vals)
criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 100, 0.85)
# then perform k-means clustering wit h number of clusters defined as 3
#also random centres are initially choosed for k-means clustering
k = 2
retval, labels, centers = cv2.kmeans(pixel_vals, k, None, criteria, 10, cv2.KMEANS_RANDOM_CENTERS)
# convert data into 8-bit values
centers = np.uint8(centers)
segmented_data = centers[labels.flatten()]
# reshape data into the original image dimensions
segmented_image = segmented_data.reshape((image.shape))
plt.imshow(segmented_image)
Following is the image
Following is the output of the above image using k-means clustering (k=2)
How can I create a mask for that yellow part to segment it from original?

problem with getting each segment resulted through K means segmentation in seperate images using Python and Opencv

I am using python and openCv for a brain segmentation project. I have segmented the brain MRI image using K means segmentation. I want to get each segment resulted through k means segmentation in seperate images. please help me in this.
#k_means segmentation
epsilon = 0.01
number_of_iterations = 50
number_of_clusters = 4
print(criteria, 'Criteria K_means parameters')
#plt.imshow(criteria)
#k means segmentation
_, labels, centers =cv2.kmeans(kmeans_input, number_of_clusters, None,
flags)
print(labels.shape, 'k-means segmentation')
#plt.imshow(labels)
#Adopting the labels
labels = labels.flatten('F')
for x in range (number_of_clusters): labels[labels == x] = centers [x]
print(labels.shape, 'adopting the tables value')
#plt.imshow(labels)
I would do it using sklearn kmeans segmentation as follows. I show how to create the segmented image and then select one color to present. I create a mask from thresholding the one color and then apply the mask to blacken out the other colors in the segmented image. You can write a loop over each color to get them all. It is also possible to use the mask to make the non-color be transparent rather than black. But I do not show that here. Or you can just save the binary masks.
Input:
#!/bin/python3.7
from skimage import io
from sklearn import cluster
import sys
import cv2
# read input and convert to range 0-1
image = io.imread('barn.jpg')/255.0
h, w, c = image.shape
# reshape to 1D array
image_2d = image.reshape(h*w, c)
# set number of colors
numcolors = 6
# do kmeans processing
kmeans_cluster = cluster.KMeans(n_clusters=int(numcolors))
kmeans_cluster.fit(image_2d)
cluster_centers = kmeans_cluster.cluster_centers_
cluster_labels = kmeans_cluster.labels_
# need to scale result back to range 0-255
newimage = cluster_centers[cluster_labels].reshape(h, w, c)*255.0
newimage = newimage.astype('uint8')
io.imshow(newimage)
io.show()
# select cluster 3 (in range 1 to numcolors) and create mask
lower = cluster_centers[3]*255
upper = cluster_centers[3]*255
lower = lower.astype('uint8')
upper = upper.astype('uint8')
mask = cv2.inRange(newimage, lower, upper)
# apply mask to get layer 3
layer3 = newimage.copy()
layer3[mask == 0] = [0,0,0]
io.imshow(layer3)
io.show()
# save kmeans clustered image and layer 3
io.imsave('barn_kmeans.gif', newimage)
io.imsave('barn_kmeans_layer3.gif', layer3)
Clustered Image:
Result for color 3:
ADDITION:
For a grayscale image, the following works for me.
#!/bin/python3.7
from skimage import io
from sklearn import cluster
import sys
import cv2
# read input and convert to range 0-1
image = io.imread('barn_gray.jpg',as_gray=True)/255.0
h, w = image.shape
# reshape to 1D array
image_2d = image.reshape(h*w,1)
# set number of colors
numcolors = 6
# do kmeans processing
kmeans_cluster = cluster.KMeans(n_clusters=int(numcolors))
kmeans_cluster.fit(image_2d)
cluster_centers = kmeans_cluster.cluster_centers_
cluster_labels = kmeans_cluster.labels_
# need to scale result back to range 0-255
newimage = cluster_centers[cluster_labels].reshape(h, w)*255.0
newimage = newimage.astype('uint8')
io.imshow(newimage)
io.show()
# select cluster 3 (in range 1 to numcolors) and create mask
# note the cluster numbers and corresponding colors are not constant from run to run
lower = cluster_centers[3]*255
upper = cluster_centers[3]*255
lower = lower.astype('uint8')
upper = upper.astype('uint8')
print(lower)
print(upper)
mask = cv2.inRange(newimage, lower, upper)
# apply mask to get layer 3
layer3 = newimage.copy()
layer3[mask == 0] = [0]
io.imshow(layer3)
io.show()
# save kmeans clustered image and layer 3
io.imsave('barn_gray_kmeans.gif', newimage)
io.imsave('barn_gray_kmeans_layer3.gif', layer3)

How to do K-means clustering for multiple images in certain directory and save it to another directory? (on local)

import numpy as np
import cv2
img = cv2.imread('home.jpg')
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)
K = 8
ret,label,center=cv2.kmeans(Z,K,None,criteria,10,cv2.KMEANS_RANDOM_CENTERS)
# Now convert back into uint8, and make original image
center = np.uint8(center)
res = center[label.flatten()]
res2 = res.reshape((img.shape))
cv2.imshow('res2',res2)
cv2.waitKey(0)
cv2.destroyAllWindows()
Above code is simple,basic K-Means clustering code which works well for "single" image. However, I need a code for multiple images in directory.
So, I created code, but its not working with an error: 'PngImageFile' object has no attribute 'reshape' (solved problem)
But after that I have problem with error: 'numpy.ndarray' object has no attribute 'save'. I think this is because I changed code from
img = Image.open(fullpath)
#to
img = np.array(Image.open(fullpath))
Below is the code I am working on.
path = "Desktop/Gray/fmtial_gb/good_crop/"
sub_path = "Desktop/Gray/fmtial_gb/good_crop_result/"
dirs = os.listdir(path)
def kmean():
from os import listdir,makedirs
from os.path import isfile,join
import matplotlib.pylab as plt
import matplotlib.image as mpimg
import cv2
import numpy as np
from PIL import Image
import os.path, sys
for item in dirs:
fullpath = os.path.join(path,item)
pathos = os.path.join(sub_path,item)
if os.path.isfile(fullpath):
#img = Image.open(fullpath)
img = np.array(Image.open(fullpath))
f, e = os.path.splitext(pathos)
#img = cv2.imread('Desktop/Gray/fmtial_gb/good_crop/RD091090(80)Cropped.bmp')
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)
K = 2
ret,label,center=cv2.kmeans(Z,K,None,criteria,10,cv2.KMEANS_RANDOM_CENTERS)
# Now convert back into uint8, and make original image
center = np.uint8(center)
res = center[label.flatten()]
res2 = res.reshape((img.shape))
#cv2.imshow('res2',res2)
#cv2.waitKey(0)
#cv2.destroyAllWindows()
Image.fromarray(res2).save(f + 'kmeans.png', "png", quality=100)
kmean()
I believe it is because you are trying to reshape a PIL image object instead of a numpy array.
Try changing img = Image.open(fullpath) to img = np.array(Image.open(fullpath)) and it should work.

Using an image as a mask for another image

I've asked this question already, but I've given it a go since. Here's my
code, with a doc string to show what I'm trying to do.
"""
w1_w2_filter_mask2.py
Use xbulge-mask.fits image file as a mask for W1 and W2 bands
and compute the median in patches where the image is not masked
"""
import matplotlib.pyplot as plt
import numpy as np
from astropy.io import fits
from scipy.ndimage.filters import generic_filter as gf
# Open data files
hdulist = fits.open('xbulge-w1.fits')
w1data = hdulist[0].data
hdulist2 = fits.open('xbulge-w2.fits')
w2data = hdulist2[0].data
hdulistmask = fits.open('xbulge-mask.fits')
maskdata = hdulistmask[0].data
# Define physical shape of filter patch
def patch_filter(image_data, radius):
kernel = np.zeros((2*radius+1, 2*radius+1))
y, x = np.ogrid[-radius:radius+1, -radius:radius+1]
patch = x**2 + y**2 <= radius**2
kernel[patch] = 1
filtered_image = gf(image_data, np.median, footprint = kernel)
return filtered_image
# Apply mask to image files
mx1 = np.ma.masked_array(w1data, mask=maskdata)
mx2 = np.ma.masked_array(w2data, mask=maskdata)
# Pass median filtering patch across masked image
radius = 25
w1masked_filtered = patch_filter(mx1, radius)
w2masked_filtered = patch_filter(mx2, radius)
When I print or imshow the masked, filtered array, it has the same effect as when I don't apply the mask image, i.e. (load mask -> load image -> apply mask -> filter in patches) has the same effect as (load image -> filter in patches).
Can anyone see what I'm missing?

Categories