Медленная обработка изображений на Python с помощью PIL и numpy

Я пытаюсь реализовать некоторую обработку изображений (поиск областей аналогичного цвета) в Python с помощью PIL и Numpy. Не могу понять, как ускорить этот код. Не могли бы вы помочь?

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 и другие библиотеки изображений имеют множество функций фильтрации и обработки, которые действительно бывают быстрыми. Но каков наилучший способ реализовать собственные функции обработки изображений?

Вместо того, чтобы перебирать каждую строку и столбец, вы можете переместить массив влево, вправо, вверх и вниз для соответствующего количества элементов. При каждой смене вы накапливаете свои значения в базовом массиве. После смены и накопления вы вычисляете среднее значение и применяете свой порог для возврата маски. См. Это сообщение, в котором есть общая дискуссия по этой теме. Идея заключается в использовании широковещательной передачи numpy, которая будет применять функцию или оператор ко всем элементам массива в C, а не Python.

Я адаптировал код из связанного сообщения в соответствии с тем, что, как я считаю, вы пытаетесь выполнить. В любом случае общая картина должна ускорить процесс. Вы должны решить, что делать с краями в маске возврата. Здесь я просто устанавливаю маску возврата в False, но вы также можете устранить края, расширяя входные данные на один пиксель в каждом направлении и заполняя ближайший пиксель, нули, серый и т. Д.

 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's # four cardinal neighbors for dx,dy in shifts: xstop = -1+dx or None ystop = -1+dy or None #per @Bago's 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 

Существуют лучшие алгоритмы сегментации, включенные в http://scikits-image.org , но если вы хотите создать свои собственные, вы можете посмотреть на этот пример, основываясь на кластеризации, называемой сегментацией ICM. Укажите N = 4 для идентификации четырех регионов.

 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)