Simple one line solution
You can do what you want in a single line like this:
new_img = (((image - color)**2).sum(axis=2)**.5 <= 10) * 255
Optimized two line solution
The above line isn't the most efficient way possible to perform all of the operations that the OP wants. Here's a significantly faster way (credit to Paul Panzer for suggesting the optimizations in the comments, readability not guaranteed):
d = image - color
new_img = (np.einsum('...i, ...i', d, d) <= 100) * 255
Timings:
Given some test data with 100x100 pixels:
import numpy as np
color = np.array([30, 70, 130])
# random data within [20,60,120]-[40,80,140] for demo purposes
image = np.random.randint(10*2 + 1, size=[100,100,3]) + color - 10
Here's a comparison of the timings of the OP's method and the solutions from this answer. The one-line solution is about 100x faster than than the OP's, whereas the fully optimized version is about 300x faster:
%%timeit
# OP's code
img_dim = image.shape
new_img = np.zeros((img_dim[0],img_dim[1])) # no alpha channel replica
for c in range(img_dim[0]):
for r in range(img_dim[1]):
pixel = image[r,c,:3]
new_img[r,c] = L2_dist(color,pixel)
43.8 ms ± 502 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
%%timeit
# one line solution
new_img = (((image - color)**2).sum(axis=2)**.5 <= 10) * 255
439 µs ± 13.7 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
%%timeit
# fully optimized solution
d = image - color
new_img = (np.einsum('...i, ...i', d, d) <= 100) * 255
145 µs ± 2.29 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)
Explanation of simple one line solution
The simple one-liner given as the first solution will:
Find the Euclidean distance between every pixel in image (which will be an array of shape (m, n, 3)) and color (which will be an array of shape (3)).
Check if any of those distances is within 10, and return a boolean array that is True wherever the condition is met and False otherwise.
A boolean array is really just an array of 0s and 1s, so we then multiply the boolean array by 255 to get the final result you wanted.
Explanation of optimized solution
Here's the list of optimizations used:
Uses einsum to calculate the sum of the squares required for the distance calculation. Under the hood, einsum makes use of the BLAS library that Numpy wraps to calculate the needed sum-product, so it should be faster.
Skips taking the square root by comparing the square of the distance to the square of the threshold.
I tried to find a way to minimize allocation/copying of arrays, but this actually made things slower. Here's a version of the optimized solution that allocates exactly two arrays (one for intermediate results and one for final result) and makes no other copies:
%%timeit
# fully optimized solution, makes as few array copies as possible
scr = image.astype(np.double)
new_img = np.zeros(image.shape[:2], dtype=np.uint8)
np.multiply(np.less_equal(np.einsum('...i,...i', np.subtract(image, color, out=scr), scr, out=scr[:,:,0]), 100, out=new_img), 255, out=new_img)
232 µs ± 7.72 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)