Pas encore de compte ?
Utilisation de l'algorithme d'apprentissage automatique non supervisé K-Means Clustering pour segmenter différentes parties d'une image à l'aide d'OpenCV en Python.
Testé sous Anaconda et Python 3.7
import cv2 import numpy as np import matplotlib.pyplot as plt def showimage(myimage, figsize=[10,10]): if (myimage.ndim>2): #This only applies to RGB or RGBA images (e.g. not to Black and White images) myimage = myimage[:,:,::-1] #OpenCV follows BGR order, while matplotlib likely follows RGB order fig, ax = plt.subplots(figsize=figsize) ax.imshow(myimage, cmap = 'gray', interpolation = 'bicubic') plt.xticks([]), plt.yticks([]) # to hide tick values on X and Y axis plt.show() # read the image image = cv2.imread("pexels-tobias-bjorkli-1559821.jpg") showimage(image) # convert to RGB image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB) # reshape the image to a 2D array of pixels and 3 color values (RGB) pixel_values = image.reshape((-1, 3)) # convert to float pixel_values = np.float32(pixel_values) # print(pixel_values.shape) # define stopping criteria criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 100, 0.2) # number of clusters (K) k = 3 _, labels, (centers) = cv2.kmeans(pixel_values, k, None, criteria, 10, cv2.KMEANS_RANDOM_CENTERS) # convert back to 8 bit values centers = np.uint8(centers) # flatten the labels array labels = labels.flatten() # convert all pixels to the color of the centroids segmented_image = centers[labels.flatten()] # reshape back to the original image dimension segmented_image = segmented_image.reshape(image.shape) # show the image showimage(segmented_image)
Image originale
Image segmentée
Image originale
Image segmentée
Image originale
Image segmentée
Image originale
Image segmentée
Testé sous Anaconda et Python 3.7
import click import numpy as np from copy import deepcopy from matplotlib import pyplot as plt def cost_function(x_true, x_em): """ :param x_true: The pixels of original image (normalized). Each row is an RGB vector. :param x_em: The image that comes from the training of em. :return: The error between the real and the segmented image. """ n = x_true.shape[0] # The The number of our examples (pixels) return 1/n * np.sum(np.linalg.norm(x_true - x_em)**2) def construct_image(height, width, g, m): """ :param height: The height of the image :param width: The width of the image :param g: Table (N x K). Contains the posterior probabilities of each example n belongs to each one of the K categories-segments. :param m: Table (K x 3). Contains an average vector (RGB color) from the data that belongs on the k-th category-segment :return: The normalized image which is needed to compute the error of the expectation maximisation algorithm and the colored image which is produced from the algorithm. """ new_image = np.zeros((height * width, 3)) for n in range(g.shape[0]): k = g[n].argmax() new_image[n] = m[k] flat = deepcopy(new_image) new_image = new_image.reshape((height, width, 3)) k = m.shape[0] plt.imshow(new_image) plt.savefig('em_{}'.format(k)) plt.show() return flat, new_image def gaussian_mixture(x, p, m, s, k): """ :param x: Our data (pixels). Each row is an RGB vector of a pixel :param p: Table (N x K). Contains the prior probabilities of each example n belongs to each category-segment k :param m: Table (K x 3). Contains an average vector(RGB) of the color from the data that belongs on category-segment k :param s: The covariance table S. :param k: The number of the categories. :return: Table of shape (N x K) that contains the probabilities (that comes for mixture of Gaussian distributions) for each example n (pixel) belongs to each one of the K categories """ probabilities = np.zeros((x.shape[0], k)) for k_i in range(k): first_part = 1 / np.sqrt(2 * np.pi * s[k_i]) second_part = np.exp(-(1 / (2 * s[k_i])) * (x - m[k_i, :]) ** 2) probabilities[:, k_i] = p[k_i] * np.prod(first_part * second_part, axis=1) return np.array(probabilities) def log_likelihood(probabilities): return np.sum(np.log(np.sum(probabilities, axis=1))) def maximization_step(x, g): """ Execute the maximization stem of the algorithm and update the parameters :param x: Our data (pixels). Each row is an RGB vector of a pixel :param g: Table (N x K). Contains the posterior probabilities of each example n belongs to each one of the K categories-segments :return: The updated parameters. p: Table (N x K). Contains the prior probabilities of each example n belongs to each category-segment k m: Table (K x 3). Contains an average vector(RGB) of the color from the data that belongs on category-segment k s: The covariance table S. """ k = g.shape[1] m = np.zeros((k, x.shape[1])) p = np.zeros(k) s = np.zeros(k) for k_i in range(k): g_k = g[:, k_i].reshape((-1, 1)) m[k_i, :] = np.sum(g_k * x, axis=0) / np.sum(g_k) s[k_i] = np.sum(np.sum(g_k * ((x - m[k_i]) ** 2), axis=1)) / (x.shape[1] * np.sum(g_k)) p[k_i] = np.sum(g_k) / x.shape[0] return p, m, s def expectation_step(probabilities): """ Execute the expectation step of the algorithm :param probabilities: Table (N x K). Contains the probabilities (that comes for Gaussian mixture) of each example n belongs to each category-segment k :return: Table (N x K). Contains the posterior probabilities of each example n belongs to each one of the K categories-segments """ denominator = np.sum(probabilities, axis=1) return probabilities / denominator.reshape((-1, 1)) def initialize_parameters(k, d): """ :param k: The number of categories-segments :param d: The dimension of each example-pixel (R, G, B) = 3 :return: The prior probabilities, the average_vectors and the covariance table """ # At the start, the prior probability of each category is the same and equal to 1/k prior = np.full(k, 1/k) # We have average_vector of d-dimension for each category and initialize # them with values from 0-1 because we have a normalized image. m = np.zeros((k, d)) for i in range(m.shape[0]): m[i, :] = np.random.uniform(0, 1, d) # Initialize the covariance of each category # with values between 0.2-0.8 -> 60% of the real values s = np.random.uniform(0.2, 0.8, k) return prior, m, s def expectation_maximization(x, k, iterations, tolerance): """ :param x: Table dimension (N x 3) with the pixels of th image :param k: The number o categories-segments :param tolerance: The tolerance you accept :param iterations: The number of iterations you want to run the algorithm :return: The probabilities of N example belongings on the k category and the average vectors of each category """ d = x.shape[1] # The dimension of each example-pixel (R G B) = 3 prior, m, s = initialize_parameters(k, d) prob = gaussian_mixture(x, prior, m, s, k) for t in range(iterations): log_likelihood_old = log_likelihood(prob) g = expectation_step(prob) prior, m, s = maximization_step(x, g) prob = gaussian_mixture(x, prior, m, s, k) log_likelihood_new = log_likelihood(prob) print('log_likelihood of {:<3} iteration: {}'.format(t, log_likelihood_new)) if log_likelihood_new - log_likelihood_old < 0: print('Error in coding') if np.abs(log_likelihood_new - log_likelihood_old) < tolerance: print('Converged') break return g, m @click.command() @click.option('--segments', default=8) @click.option('--path', default='woman-g3f1f3f8df_1920.jpg') @click.option('--iterations', default=100) @click.option('--tolerance', default=1e-6) def main(segments, path, iterations, tolerance): img = plt.imread(path) plt.imshow(img) plt.show() print('Image shape: {}'.format(img.shape)) # Calculate our N independent pixels number_of_pixels = img.shape[0] * img.shape[1] # Reshape the image in order to have a table (N x 3) data = img.reshape((number_of_pixels, 3)) # Normalize our data data = data / 255 post_probabilities, average_vectors = expectation_maximization(x=data, k=segments, iterations=iterations, tolerance=tolerance) flt, new_img = construct_image(img.shape[0], img.shape[1], post_probabilities, average_vectors) error = cost_function(data, flt) print('Total error: {}'.format(error)) if __name__ == '__main__': main()
Expectation-Maximization - GitHub
Image originale
Image segmentée
Segmentation d'images à l'aide d'opérations morphologiques
Testé sous Anaconda et Python 3.7
# Python program to transform an image using # threshold. import numpy as np import cv2 from matplotlib import pyplot as plt def showimage(myimage, figsize=[10,10]): if (myimage.ndim>2): #This only applies to RGB or RGBA images (e.g. not to Black and White images) myimage = myimage[:,:,::-1] #OpenCV follows BGR order, while matplotlib likely follows RGB order fig, ax = plt.subplots(figsize=figsize) ax.imshow(myimage, cmap = 'gray', interpolation = 'bicubic') plt.xticks([]), plt.yticks([]) # to hide tick values on X and Y axis plt.show() # Image operation using thresholding img = cv2.imread('inputCoins.jpg') showimage(img) gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) showimage(gray) ret, thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU) showimage(thresh) # Noise removal using Morphological # closing operation kernel = np.ones((3, 3), np.uint8) closing = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, kernel, iterations = 2) # Background area using Dilation bg = cv2.dilate(closing, kernel, iterations = 1) # Finding foreground area dist_transform = cv2.distanceTransform(closing, cv2.DIST_L2, 0) ret, fg = cv2.threshold(dist_transform, 0.02 * dist_transform.max(), 255, 0) showimage(fg)
Image originale
nuances de gris
Seuillage
Image segmentée
Testé sous Anaconda et Python 3.7
# -*- coding: utf-8 -*- """ Created on Tue Jun 28 20:40:45 2022 @author: https://pythonguides.com/scikit-learn-image-processing/ """ import numpy as num import matplotlib.pyplot as plot from sklearn.feature_extraction import image from sklearn.cluster import spectral_clustering l = 100 x, y = num.indices((l, l)) center1 = (27, 23) center2 = (39, 49) center3 = (66, 57) center4 = (23, 69) radius1, radius2, radius3, radius4 = 15, 13, 14, 13 circle1 = (x - center1[0]) ** 2 + (y - center1[1]) ** 2 < radius1 ** 2 circle2 = (x - center2[0]) ** 2 + (y - center2[1]) ** 2 < radius2 ** 2 circle3 = (x - center3[0]) ** 2 + (y - center3[1]) ** 2 < radius3 ** 2 circle4 = (x - center4[0]) ** 2 + (y - center4[1]) ** 2 < radius4 ** 2 imge = circle1 + circle2 + circle3 + circle4 mask = imge.astype(bool) imge = imge.astype(float) imge += 2 + 0.3 * num.random.randn(*imge.shape) graph = image.img_to_graph(imge, mask=mask) graph.data = num.exp(-graph.data / graph.data.std()) labels = spectral_clustering(graph, n_clusters=4, eigen_solver="arpack") label_im = num.full(mask.shape, -4.0) label_im[mask] = labels plot.matshow(imge) plot.matshow(label_im) imge = circle1 + circle2+circle3 mask = imge.astype(bool) imge = imge.astype(float) imge += 2 + 0.3 * num.random.randn(*imge.shape) graph = image.img_to_graph(imge, mask=mask) graph.data = num.exp(-graph.data / graph.data.std()) labels = spectral_clustering(graph, n_clusters=2, eigen_solver="arpack") label_im = num.full(mask.shape, -2.0) label_im[mask] = labels plot.matshow(imge) plot.matshow(label_im) plot.show()
Source : https://pythonguides.com/scikit-learn-image-processing/
unet pour la segmentation d'images
data.py
Testé sous Anaconda et Python 3.7
from __future__ import print_function from keras.preprocessing.image import ImageDataGenerator import numpy as np import os import glob import skimage.io as io import skimage.transform as trans Sky = [128,128,128] Building = [128,0,0] Pole = [192,192,128] Road = [128,64,128] Pavement = [60,40,222] Tree = [128,128,0] SignSymbol = [192,128,128] Fence = [64,64,128] Car = [64,0,128] Pedestrian = [64,64,0] Bicyclist = [0,128,192] Unlabelled = [0,0,0] COLOR_DICT = np.array([Sky, Building, Pole, Road, Pavement, Tree, SignSymbol, Fence, Car, Pedestrian, Bicyclist, Unlabelled]) def adjustData(img,mask,flag_multi_class,num_class): if(flag_multi_class): img = img / 255 mask = mask[:,:,:,0] if(len(mask.shape) == 4) else mask[:,:,0] new_mask = np.zeros(mask.shape + (num_class,)) for i in range(num_class): #for one pixel in the image, find the class in mask and convert it into one-hot vector #index = np.where(mask == i) #index_mask = (index[0],index[1],index[2],np.zeros(len(index[0]),dtype = np.int64) + i) if (len(mask.shape) == 4) else (index[0],index[1],np.zeros(len(index[0]),dtype = np.int64) + i) #new_mask[index_mask] = 1 new_mask[mask == i,i] = 1 new_mask = np.reshape(new_mask,(new_mask.shape[0],new_mask.shape[1]*new_mask.shape[2],new_mask.shape[3])) if flag_multi_class else np.reshape(new_mask,(new_mask.shape[0]*new_mask.shape[1],new_mask.shape[2])) mask = new_mask elif(np.max(img) > 1): img = img / 255 mask = mask /255 mask[mask > 0.5] = 1 mask[mask <= 0.5] = 0 return (img,mask) def trainGenerator(batch_size,train_path,image_folder,mask_folder,aug_dict,image_color_mode = "grayscale", mask_color_mode = "grayscale",image_save_prefix = "image",mask_save_prefix = "mask", flag_multi_class = False,num_class = 2,save_to_dir = None,target_size = (256,256),seed = 1): ''' can generate image and mask at the same time use the same seed for image_datagen and mask_datagen to ensure the transformation for image and mask is the same if you want to visualize the results of generator, set save_to_dir = "your path" ''' image_datagen = ImageDataGenerator(**aug_dict) mask_datagen = ImageDataGenerator(**aug_dict) image_generator = image_datagen.flow_from_directory( train_path, classes = [image_folder], class_mode = None, color_mode = image_color_mode, target_size = target_size, batch_size = batch_size, save_to_dir = save_to_dir, save_prefix = image_save_prefix, seed = seed) mask_generator = mask_datagen.flow_from_directory( train_path, classes = [mask_folder], class_mode = None, color_mode = mask_color_mode, target_size = target_size, batch_size = batch_size, save_to_dir = save_to_dir, save_prefix = mask_save_prefix, seed = seed) train_generator = zip(image_generator, mask_generator) for (img,mask) in train_generator: img,mask = adjustData(img,mask,flag_multi_class,num_class) yield (img,mask) def testGenerator(test_path,num_image = 30,target_size = (256,256),flag_multi_class = False,as_gray = True): for i in range(num_image): img = io.imread(os.path.join(test_path,"%d.png"%i),as_gray = as_gray) img = img / 255 img = trans.resize(img,target_size) img = np.reshape(img,img.shape+(1,)) if (not flag_multi_class) else img img = np.reshape(img,(1,)+img.shape) yield img def geneTrainNpy(image_path,mask_path,flag_multi_class = False,num_class = 2,image_prefix = "image",mask_prefix = "mask",image_as_gray = True,mask_as_gray = True): image_name_arr = glob.glob(os.path.join(image_path,"%s*.png"%image_prefix)) image_arr = [] mask_arr = [] for index,item in enumerate(image_name_arr): img = io.imread(item,as_gray = image_as_gray) img = np.reshape(img,img.shape + (1,)) if image_as_gray else img mask = io.imread(item.replace(image_path,mask_path).replace(image_prefix,mask_prefix),as_gray = mask_as_gray) mask = np.reshape(mask,mask.shape + (1,)) if mask_as_gray else mask img,mask = adjustData(img,mask,flag_multi_class,num_class) image_arr.append(img) mask_arr.append(mask) image_arr = np.array(image_arr) mask_arr = np.array(mask_arr) return image_arr,mask_arr def labelVisualize(num_class,color_dict,img): img = img[:,:,0] if len(img.shape) == 3 else img img_out = np.zeros(img.shape + (3,)) for i in range(num_class): img_out[img == i,:] = color_dict[i] return img_out / 255 def saveResult(save_path,npyfile,flag_multi_class = False,num_class = 2): for i,item in enumerate(npyfile): img = labelVisualize(num_class,COLOR_DICT,item) if flag_multi_class else item[:,:,0] io.imsave(os.path.join(save_path,"%d_predict.png"%i),img)
model.py
Testé sous Anaconda et Python 3.7
import numpy as np import os import skimage.io as io import skimage.transform as trans import numpy as np from keras.models import * from keras.layers import * from keras.optimizers import * from keras.callbacks import ModelCheckpoint, LearningRateScheduler from keras import backend as keras def unet(pretrained_weights = None,input_size = (256,256,1)): inputs = Input(input_size) conv1 = Conv2D(64, 3, activation = 'relu', padding = 'same', kernel_initializer = 'he_normal')(inputs) conv1 = Conv2D(64, 3, activation = 'relu', padding = 'same', kernel_initializer = 'he_normal')(conv1) pool1 = MaxPooling2D(pool_size=(2, 2))(conv1) conv2 = Conv2D(128, 3, activation = 'relu', padding = 'same', kernel_initializer = 'he_normal')(pool1) conv2 = Conv2D(128, 3, activation = 'relu', padding = 'same', kernel_initializer = 'he_normal')(conv2) pool2 = MaxPooling2D(pool_size=(2, 2))(conv2) conv3 = Conv2D(256, 3, activation = 'relu', padding = 'same', kernel_initializer = 'he_normal')(pool2) conv3 = Conv2D(256, 3, activation = 'relu', padding = 'same', kernel_initializer = 'he_normal')(conv3) pool3 = MaxPooling2D(pool_size=(2, 2))(conv3) conv4 = Conv2D(512, 3, activation = 'relu', padding = 'same', kernel_initializer = 'he_normal')(pool3) conv4 = Conv2D(512, 3, activation = 'relu', padding = 'same', kernel_initializer = 'he_normal')(conv4) drop4 = Dropout(0.5)(conv4) pool4 = MaxPooling2D(pool_size=(2, 2))(drop4) conv5 = Conv2D(1024, 3, activation = 'relu', padding = 'same', kernel_initializer = 'he_normal')(pool4) conv5 = Conv2D(1024, 3, activation = 'relu', padding = 'same', kernel_initializer = 'he_normal')(conv5) drop5 = Dropout(0.5)(conv5) up6 = Conv2D(512, 2, activation = 'relu', padding = 'same', kernel_initializer = 'he_normal')(UpSampling2D(size = (2,2))(drop5)) merge6 = concatenate([drop4,up6], axis = 3) conv6 = Conv2D(512, 3, activation = 'relu', padding = 'same', kernel_initializer = 'he_normal')(merge6) conv6 = Conv2D(512, 3, activation = 'relu', padding = 'same', kernel_initializer = 'he_normal')(conv6) up7 = Conv2D(256, 2, activation = 'relu', padding = 'same', kernel_initializer = 'he_normal')(UpSampling2D(size = (2,2))(conv6)) merge7 = concatenate([conv3,up7], axis = 3) conv7 = Conv2D(256, 3, activation = 'relu', padding = 'same', kernel_initializer = 'he_normal')(merge7) conv7 = Conv2D(256, 3, activation = 'relu', padding = 'same', kernel_initializer = 'he_normal')(conv7) up8 = Conv2D(128, 2, activation = 'relu', padding = 'same', kernel_initializer = 'he_normal')(UpSampling2D(size = (2,2))(conv7)) merge8 = concatenate([conv2,up8], axis = 3) conv8 = Conv2D(128, 3, activation = 'relu', padding = 'same', kernel_initializer = 'he_normal')(merge8) conv8 = Conv2D(128, 3, activation = 'relu', padding = 'same', kernel_initializer = 'he_normal')(conv8) up9 = Conv2D(64, 2, activation = 'relu', padding = 'same', kernel_initializer = 'he_normal')(UpSampling2D(size = (2,2))(conv8)) merge9 = concatenate([conv1,up9], axis = 3) conv9 = Conv2D(64, 3, activation = 'relu', padding = 'same', kernel_initializer = 'he_normal')(merge9) conv9 = Conv2D(64, 3, activation = 'relu', padding = 'same', kernel_initializer = 'he_normal')(conv9) conv9 = Conv2D(2, 3, activation = 'relu', padding = 'same', kernel_initializer = 'he_normal')(conv9) conv10 = Conv2D(1, 1, activation = 'sigmoid')(conv9) model = Model(input = inputs, output = conv10) model.compile(optimizer = Adam(lr = 1e-4), loss = 'binary_crossentropy', metrics = ['accuracy']) #model.summary() if(pretrained_weights): model.load_weights(pretrained_weights) return model
main.py
Testé sous Anaconda et Python 3.7
from model import * from data import * #os.environ["CUDA_VISIBLE_DEVICES"] = "0" data_gen_args = dict(rotation_range=0.2, width_shift_range=0.05, height_shift_range=0.05, shear_range=0.05, zoom_range=0.05, horizontal_flip=True, fill_mode='nearest') myGene = trainGenerator(2,'data/membrane/train','image','label',data_gen_args,save_to_dir = None) model = unet() model_checkpoint = ModelCheckpoint('unet_membrane.hdf5', monitor='loss',verbose=1, save_best_only=True) model.fit_generator(myGene,steps_per_epoch=300,epochs=1,callbacks=[model_checkpoint]) testGene = testGenerator("data/membrane/test") results = model.predict_generator(testGene,30,verbose=1) saveResult("data/membrane/test",results)
unet for image segmentation
Copyright (c) 2019 zhixuhao
Bienvenu, je m’appelle Eric Soupet et je suis l'administrateur du site elodees.com. elodees.com est un état de l'art de l'Intelligence Artificielle et se veut collaboratif, vous pouvez dès à présent proposer du contenu tels que des articles, des événements, des tutoriels, ... alors n'hésitez pas !
Crédit des images de la plate-forme : Pixabay - Pixabay License | Pexels - Pexels License