Reputation: 994
I have two images loaded in to two numpy array. I want to get the difference of them and remove the values less than 50 and set the rest of it to 255 with a final result of back and white image.
def count(base, image):
x, y, z = base.shape
sheet = np.zeros(base.shape)
for i in range(x):
for j in range(y):
temp = 0
for k in range(z):
if base[i, j, k] > image[i, j, k]:
t = base[i, j, k] - image[i, j, k]
if t > 50:
temp = 255
else:
t = image[i, j, k] - base[i, j, k]
if t > 50:
temp = 255
sheet[i, j] = [temp, temp, temp]
array = sheet[:, :, 0]
this code does what i need it to do. but as you see i have used the most simplest for loop for this function and with the images being in the size of 2000*2000, it takes a long time to process. i need a way to rewrite this in a faster way.
thank you
Upvotes: 0
Views: 65
Reputation: 53119
Vectorizing your code looks straight-forward, except for one gotcha: Your data appear to be unsigned ints (uint8
by the look of it) which require a bit of extra attention since they frequently underflow with unexpected results. For example, the obvious np.abs(image-base)>50
to detect differences greater than 50 does not work, in fact np.abs
is a nop on unsigned data. A careful translation would look more like
sheet = np.array([[0,0,0],[255,255,255]], 'u1')[((np.maximum(base, image)-np.minimum(base, image))>50).any(2).view('u1')]
or
sheet = np.array([[0,0,0],[255,255,255]], 'u1')[(np.abs(np.subtract(image, base, dtype='i2'))>50).any(2).view('u1')]
This
correctly computes the subpixel wise difference,
the first version mimics your if/else clause
the second forces a signed result type 'i2'
or int16
for the difference
detects those greater 50,
marks pixels with at least one such subpixel (any(2)
),
converts the resulting boolean mask into indices (.view('u1')
) 0 and 1
and uses those to index into a template array.
Upvotes: 3
Reputation: 119
Most of the operations work just as they would on scalars on NumPy arrays of the same size. I re-wrote the function as,
def count_new(base, image, thresh=50):
# these are the pixel absolute value differences
differences = np.abs(base - image)
# whether the difference exceeds the threshold
big_difference = differences > thresh
# whether each pixel has at least one big difference
big_difference = big_difference.any(axis=2)
# return 255 where big differences, and 0 everywhere else
return 255 * big_difference.astype(int)
Hopefully the comments make the intent of each line clear. Also checked this gives the same as the previous out-put
x = np.random.randint(256, size=(10, 11, 3))
y = np.random.randint(256, size=(10, 11, 3))
assert((count(x,y) == count_new(x,y)).all())
which shows it does.
Upvotes: 1