# fastet way to calculate mean of each rgb channel of specific coordinates

Solution for fastet way to calculate mean of each rgb channel of specific coordinates
is Given Below:

I’ve build a lot of functions for this purpose and the fastest one is:

``````meanRGB[:] = sum([img[i,j,:] for i,j in args])/len(args)
``````

but this is still so slow for large images.
it takes like 40 seconds for a 4700×3100 image.(it’s running on an old cpu(4th generation) but it doesn’t really matter)

args contains 2d coordinates of specific x,y

``````[[0 0] [1 0] [2 1] ...]
``````

UPDATE

thanks to all of you kind guys who sent these great methods. I think joostblack’s way is the fastest one.
here you can simulate the situation(shortened):

``````clusterMap = [[1,4,2],[1,2,3],[3,1,4]]
np.random.seed(2)
img = np.random.randint(low = 0, high = 255, size = (4700, 3100, 3))
segments = np.unique(clusterMap)

meanRGB = np.zeros((len(segments),3))

for k, segment in enumerate(segments.ravel()):
args = np.argwhere(clusterMap==segment)
meanRGB[k,:] = sum([img[i,j,:] for i,j in args])/len(args)

print(f"n{meanRGB}")
``````

One way using `numba`:

``````import numpy as np
from numba import njit, prange

img = np.random.randint(0, 256, (4700, 3100, 3))
args = np.random.randint(0, 1000, (100000, 2))

@njit(parallel=True, fastmath=True)
def average(array, indices):
n = len(indices)
sum_ = np.zeros(3)
for i in prange(n):
sum_ += array[indices[i], indices[i], :]
return sum_/n
``````

Validation:

``````op = sum(img[i,j,:] for i,j in args)/len(args)
numba_ = average(img, args)
np.isclose(op, numba_)

# array([ True,  True,  True])
``````

Benchmark (it’s about few hundred times faster):

``````%%timeit
meanRGB = sum(img[i,j,:] for i,j in args)/len(args)

# 124 ms ± 704 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)

%timeit average(img, args)

# 136 µs ± 12.1 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)
``````

I gave it a shot. I think this is faster but I do not have your image or your `args` array so I am not sure.

``````import numpy as np

# Trying to recreate your situation
img = np.random.rand(4700,3100,3)
args = np.array([[2,3],[0,1],[2,4],[5,5]])

# my attempt
meanRGB = np.mean(img[args[:,0],args[:,1],:],axis=0)
print(meanRGB)
``````

(example) output:

``````[0.68078292 0.4485302  0.46863616]
``````

split by channels and then use the builtin mean

``````r = np.mean(img[:,:,0])
g = np.mean(img[:,:,1])
b = np.mean(img[:,:,2])
``````

if your list is not the full image youd want to mask it using

``````mask = np.zeros_like(test[:,:,0])
x_coords = [c for c in args]
y_coords = [c for c in args]
``````

You can do it in the following manner:

``````red_channel_mean = img[:, :, 0].mean()

green_channel_mean = img[:, :, 1].mean()

blue_channel_mean = img[:, :, 2].mean()
``````

Cheers

You can zip the indices together, mask the input and compute the mean:

``````>>> img[tuple(zip(*args))].mean(0)
``````

For instance, given `args` as:

``````>>> args
[[1, 0], [2, 1], [1, 4], [0, 2]]

>>> tuple(zip(*args))
((1, 2, 1, 0), (0, 1, 4, 2))
``````