1

I have a RGB image stored as a numpy array. I have a color array and these colors I will search in the image and replace those RGB values with a same scalar value. The rest of the RGB values that do not match shall simply be replaced by 0.

The colors I'm searching could be like the following,

colors = []
colors.append((69, 0, 9, 17))
colors.append((196, 127, 128,1))
colors.append((199, 5, 126, 19))
colors.append((55, 127, 126, 4))
colors.append((0, 127, 29, 2))
colors.append((68, 6, 124, 18))

The 4th values on each color is the value that will replace the corresponding RGB values.

I tried using np.asin but it doesn't search for arrays. It only searches for scalars. Right now I am using for loop but its extremely slow.

for i in range(image.shape[0]):
   for j in range(image.shape[1]):
      match = -1
      for k in range(len(colors)):  
         match = k       
         for l in range(3):
            if image[i,j,l] != colors[k][l]:
               match=-1
               break
         if match >=0 :
            break

      val = [0,0,0]
      if match >= 0:
         val = [colors[match][3],colors[match][3],colors[match][3]]
      for l in range(3):
         image[i,j,l] = val[l]

Any efficient approach will be very appreciated.

3
  • This should not be working: colors[k,l], right? Commented Oct 25, 2018 at 6:18
  • @b-fg you are right. Its a pseudo code to express what I am trying. Can have some errors. Commented Oct 25, 2018 at 6:25
  • Always post minimal complete and verified code please. Commented Oct 25, 2018 at 11:39

3 Answers 3

3

@Gabriel M

A great approach. But I think that it should be

for r,g,b, replace in colors:

    colors_match = np.where( np.all([image[:,:,0] == r, image[:,:,1] == g, image[:,:,2] == b], axis=0))
    image[colors_match] = replace
    print(colors_match)

or more simply

for r,g,b, replace in colors:

    colors_match = np.all([image[:,:,0] == r, image[:,:,1] == g, image[:,:,2] == b], axis=0)
    image[colors_match] = replace
    print(colors_match)

edited

To replace values that were not converted, keeping the conversion history in another array could be a choice.

converted = np.zeros((image.shape[0], image.shape[1]), dtype=bool)
for r,g,b, replace in colors:

    colors_match = np.all([image[:,:,0] == r, image[:,:,1] == g, image[:,:,2] == b], axis=0)
    image[colors_match] = replace
    converted[colors_match] = True
image[~converted] = 0
Sign up to request clarification or add additional context in comments.

1 Comment

Thanks very much it works. But how to replace the other positions that do not match to 0?
2

why not simplify your loop like this?:

for r,g,b, replace in colors:

    colors_match = np.where( np.all([image[:,:,0] == r, image[:,:,1] == g, image[:,:,2] == b], axis=0))
    image[colors_match,:] = replace
    print colors_match

Comments

2

For ints, here's one way based on dimensionality-reduction discussed in more detail here -

# Based on https://stackoverflow.com/a/38674038/ @Divakar
def matching_index(X, searched_values, invalid_val=-1):
    dims = np.maximum(X.max(0),searched_values.max(0))+1
    X1D = np.ravel_multi_index(X.T,dims)
    searched_valuesID = np.ravel_multi_index(searched_values.T,dims)
    sidx = X1D.argsort()
    sorted_index = np.searchsorted(X1D,searched_valuesID,sorter=sidx)
    sorted_index[sorted_index==len(X1D)] = len(X1D)-1
    idx = sidx[sorted_index]
    valid = X1D[idx] == searched_valuesID
    idx[~valid] = invalid_val
    return valid, idx

# Convert to array
colors = np.asarray(colors)

# Get matching indices and corresponding valid mask
v, idx = matching_index(colors[:,:3],image.reshape(-1,3))
image2D = np.where(v,colors[:,-1][idx],0).reshape(image.shape[:-1])

# If you need a 3D image output
image3D = np.broadcast_to(image2D[...,None], image2D.shape + (3,))

We can also use views to implement equivalent version of matching_index for generic dtype data -

# https://stackoverflow.com/a/45313353/ @Divakar
def view1D(a, b): # a, b are arrays
    a = np.ascontiguousarray(a)
    b = np.ascontiguousarray(b)
    void_dt = np.dtype((np.void, a.dtype.itemsize * a.shape[1]))
    return a.view(void_dt).ravel(),  b.view(void_dt).ravel()

# Based on https://stackoverflow.com/a/38674038/ @Divakar
def matching_index_view(X, searched_values, invalid_val=-1):
    X1D,searched_valuesID = view1D(X,searched_values)
    sidx = X1D.argsort()
    sorted_index = np.searchsorted(X1D,searched_valuesID,sorter=sidx)
    sorted_index[sorted_index==len(X1D)] = len(X1D)-1
    idx = sidx[sorted_index]
    valid = X1D[idx] == searched_valuesID
    idx[~valid] = invalid_val
    return valid, idx

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.