For my work I need to replace the pseudo-color RGB values in a JPG into gray-scale for processing. The 'color' image has a specific range of RGB colors (either 20 or 255, depending of the origin) that need to be linked to a gray-scale value in order to do some measurement on the output image.
Working with the raw RGB values has been quite difficult, as the specified range is only working fine in PNG or tiff format, but conversion to JPG creates some RGB values that are a bit off from the intended RGB value and this renders my existing analysis useless.

I have found this nice piece of code in one of the answers as a solution to round the color of a certain point to its nearest similar color in a dictionary.

```
def distance(c1, c2):
   (r1,g1,b1) = c1
   (r2,g2,b2) = c2
   return math.sqrt((r1 - r2)**2 + (g1 - g2) ** 2 + (b1 - b2) **2)

colors = list(rgb_code_dictionary.keys())
closest_colors = sorted(colors, key=lambda color: distance(color, point))
closest_color = closest_colors[0]
code = rgb_code_dictionary[closest_color]

```

[Python PIL - Finding Nearest Color (Rounding Colors)](https://stackoverflow.com/questions/34366981/python-pil-finding-nearest-color-rounding-colors) 

rgb\_code\_dictionary is replaced with a dictionary of rgb values with he corresponding grayvalue that I would like to apply.

This works really great, it produces the output I need.
This code is however quite slow if applied to a full image (it only takes 18sec per image, but I have a few thousand images to process), as I need to feed each pixel to the function in order to get the closest match.

i have found another piece of code that works very fast in replacing colours:

[Replacing RGB values in numpy array by integer is extremely slow](https://stackoverflow.com/questions/33196130/replacing-rgb-values-in-numpy-array-by-integer-is-extremely-slow)

```
# Extract color codes and their IDs from input dict
colors = np.array(_color_codes.keys())
color_ids = np.array(_color_codes.values())

# Initialize output array
result = np.empty((img_arr.shape[0],img_arr.shape[1]),dtype=int)
result[:] = -1

# Finally get the matches and accordingly set result locations
# to their respective color IDs
R,C,D = np.where((img_arr == colors[:,None,None,:]).all(3))
result[C,D] = color_ids[R]

```

But this one only works if the RGB values in the dictionary are a perfect match to the RGB values in the image. Ideally I would merge the two together in order to get a fast and reliable function to replace the colors.
But i have problems to translate the first piece of code into a "where" statement in numpy, in order to speed up the whole process of exchanging RGB values with a gray scale value.

As I'm not a programmer by education (and really new to python), I have troubles to see how to fix this. Searching on many fora has not helped in finding a good solution (that I understand and can implement myself), hence my question.

Is there a function available to do what I intend? Or is there a way to merge the 2 functions into one, so the conversion goes both fast and correct?

Any help is really appreciated (but keep it a bit simple if possible :-) )

Thanks

EDITED:
I ended up with another solution altogether, as I had some difficulties to install the solution proposed by Mark Setchell.
I am pretty convinced that using ImageMAgick is the best solution for my specific problem, sadly enough I couldn't install the solution due to safety settings on my PC.

The solution I came up with is basically converting the colour image to grayscale and then applying another grayscale value to each pixel, where the new grayscale will span +/- 6 grayscale values from the old grayscale value. (Eg everything from 242 to 255 will be replaced with 255)
This solution doesn't really work fast, nor does it give the best results, but for now this is all that seems to be feasible in the short future.

thanks for the answers, it helped me to rethink the process.