Slow image processing in Python using PIL and numpy

I am trying to implement some image processing (searching for areas of a similar color) in Python using PIL and Numpy. I can’t figure out how to speed up this code. Could you help me?

def findRegions(self, data): #data is numpy.array ret = [[False for _ in range(self.width)] for _ in range(self.heigth)] for i in range(self.heigth): for j in range(self.width): k = 0 acc = 0 for x,y in [(-1,0),(0,-1),(0,1),(1,0)]: if (self.heigth>i+x>=0 and self.width>j+y>=0): k = k+1 acc += math.sqrt(sum((data[i][j][c]-data[i+x][j+y][c])**2 for c in range(3))) if (acc/k<self.threshold): ret[i][j]= True return ret 

PIL and other image libraries have many filtering and processing functions that are really fast. But what is the best way to implement your own image processing functions?

+4
source share
2 answers

Instead of iterating over each row and column, you can move the array left, right, up and down for the appropriate number of elements. With each shift, you accumulate your values ​​in the base array. After changing and accumulating, you calculate the average value and use your threshold to return the mask. See this post for a general discussion on this topic. The idea is to use numpy translation, which will apply a function or operator to all elements of the array in C, not Python.

I adapted the code from the linked message according to what I think you are trying to execute. In any case, the overall picture should speed up the process. You must decide what to do with the edges in the return mask. Here, I just set the return mask to False, but you can also eliminate the edges by expanding the input by one pixel in each direction and filling the nearest pixel, zeros, gray, etc.

 def findRegions(self,data): #define the shifts for the kernel window shifts = [(-1,0),(0,-1),(0,1),(1,0)] #make the base array of zeros # array size by 2 in both dimensions acc = numpy.zeros(data.shape[:2]) #compute the square root of the sum of squared color # differences between a pixel and it # four cardinal neighbors for dx,dy in shifts: xstop = -1+dx or None ystop = -1+dy or None #per @Bago comment, use the sum method to add up the color dimension # instead of the list comprehension acc += ((data[1:-1,1:-1] - data[1+dx:xstop, 1+dy:ystop])**2).sum(-1)**.5 #compute the average acc /= (len(shifts) + 1) #build a mask array the same size as the original ret = numpy.zeros(data.shape[:2],dtype=numpy.bool) #apply the threshold # note that the edges will be False ret[1:-1,1:-1] acc < self.threshold return ret 
+4
source

There are better segmentation algorithms included at http://scikits-image.org , but if you want to build your own, you can look at this example based on clustering called ICM segmentation. Indicate N = 4 to identify the four areas.

 import numpy as np from scipy.cluster.vq import kmeans2 def ICM(data, N, beta): print "Performing ICM segmentation..." # Initialise segmentation using kmeans print "K-means initialisation..." clusters, labels = kmeans2(np.ravel(data), N) print "Iterative segmentation..." f = data.copy() def _minimise_cluster_distance(data, labels, N, beta): data_flat = np.ravel(data) cluster_means = np.array( [np.mean(data_flat[labels == k]) for k in range(N)] ) variance = np.sum((data_flat - cluster_means[labels])**2) \ / data_flat.size # How many of the 8-connected neighbouring pixels are in the # same cluster? count = np.zeros(data.shape + (N,), dtype=int) count_inside = count[1:-1, 1:-1, :] labels_img = labels.reshape(data.shape) for k in range(N): count_inside[..., k] += (k == labels_img[1:-1:, 2:]) count_inside[..., k] += (k == labels_img[2:, 1:-1]) count_inside[..., k] += (k == labels_img[:-2, 1:-1]) count_inside[..., k] += (k == labels_img[1:-1, :-2]) count_inside[..., k] += (k == labels_img[:-2, :-2]) count_inside[..., k] += (k == labels_img[2:, 2:]) count_inside[..., k] += (k == labels_img[:-2, 2:]) count_inside[..., k] += (k == labels_img[2:, :-2]) count = count.reshape((len(labels), N)) cluster_measure = (data_flat[:, None] - cluster_means)**2 \ - beta * variance * count labels = np.argmin(cluster_measure, axis=1) return cluster_means, labels # Initialise segmentation cluster_means, labels = _minimise_cluster_distance(f, labels, N, 0) stable_counter = 0 old_label_diff = 0 i = 0 while stable_counter < 3: i += 1 cluster_means, labels_ = \ _minimise_cluster_distance(f, labels, N, beta) new_label_diff = np.sum(labels_ != labels) if new_label_diff != old_label_diff: stable_counter = 0 else: stable_counter += 1 old_label_diff = new_label_diff labels = labels_ print "Clustering converged after %d steps." % i return labels.reshape(data.shape) 
+1
source

Source: https://habr.com/ru/post/1394304/


All Articles