Fastest way to select 7 * 7 adjacent pixels for every pixel in an image in Python
need to read the image as an array, and for each pixel select 7 * 7 adjacent pixels, then change it and put it as the first row of the workout set:
import numpy as np
from scipy import misc
face1=misc.imread('face1.jpg')
face1
sizes (288, 352, 3)
, you need to find 7 * 7 adjacent pixels for each pixel, so the color 49 * 3 will then change it as an array (1,147)
and put it in an array for all pixels, I took the following approach:
X_training=np.zeros([1,147] ,dtype=np.uint8)
for i in range(3, face1.shape[0]-3):
for j in range(3, face1.shape[1]-3):
block=face1[i-3:i+4,j-3:j+4]
pxl=np.reshape(block,(1,147))
X_training=np.vstack((pxl,X_training))
final form X_training
(97572, 147)
and the last line contains all zeros:
a = len(X_training)-1
X_training = X_training[:a]
the above code works well for one image, but since Wall time: 5min 19s
I have 2000 images, so it will take quite a while for all images. I'm looking for a faster way to iterate over each pixel and accomplish the above task.
Edit:
this is what I mean by neighboring pixels, for each pixelface1[i-3 : i+4 ,j-3:j+4]
source to share
An efficient way is to use stride_tricks
to create a 2d rolling window over the image, then flatten it:
import numpy as np
face1 = np.arange(288*352*3).reshape(288, 352, 3) # toy data
n = 7 # neighborhood size
h, w, d = face1.shape
s = face1.strides
tmp = np.lib.stride_tricks.as_strided(face1, strides=s[:2] + s,
shape=(h - n + 1, w - n + 1, n, n, d))
X_training = tmp.reshape(-1, n**2 * d)
X_training = X_training[::-1] # to get the rows into same order as in the question
tmp
is a 5D representation in an image, where it is tmp[x, y, :, :, c]
equivalent to a neighborhood face1[x:x+n, y:y+n, c]
in a color channel c
.
source to share
Below is <1 s on my laptop:
import scipy as sp im = sp.rand(300, 300, 3) size = 3 ij = sp.meshgrid(range(size, im.shape[0]-size), range(size, im.shape[1]-size)) i = ij[0].T.flatten() j = ij[1].T.flatten() N = len(i) L = (2*size + 1)**2 X_training = sp.empty(shape=[N, 3*L]) for pixel in range(N): si = (slice(i[pixel]-size, i[pixel]+size+1)) sj = (slice(j[pixel]-size, j[pixel]+size+1)) X_training[pixel, :] = im[si, sj, :].flatten() X_training = X_training[-1::-1, :]
I'm always sad when I can't think of a one-line vector version, but at least it's faster for you.
source to share