-3

I have an image (I have it in both NumPy and PIL format), and I want to change where RGB values are [0.4, 0.4, 0.4] to [0.54, 0.27, 0.07].

By doing this, I want to change the road color from gray to brown:

road

HansHirse
  • 18,010
  • 10
  • 38
  • 67
Mshz
  • 17
  • 4

3 Answers3

1

You can try this numpy approach:

img[np.where(img == (0.4,0.4,0.4))] = (0.54,0.27,0.27)
Quang Hoang
  • 146,074
  • 10
  • 56
  • 74
  • 2
    thanks, but it gave me this error: shape mismatch: value array of shape (3,) could not be broadcast to indexing result of shape (13481,) – Mshz Dec 04 '19 at 20:11
0

The image you have loaded is represented as a three dimensional array. The shape of it should be height, width, color channel. Ie. if it only has RGB channels (some may have RGBA etc), the matrix properties would look like height, width, 3

The rest of it should be just as you treat a normal array. You can see it as this way:

pixel = image[height][width][colorchannel]

Quang Hoang's answer has a simple solution to your problem.

John
  • 1
  • 1
  • 1
  • Thanks, but it gave me this error: shape mismatch: value array of shape (3,) could not be broadcast to indexing result of shape (13481,) – Mshz Dec 04 '19 at 20:10
  • Check the shape of your image through `image.shape`. It should have three elements as I described. What does it return? – John Dec 04 '19 at 20:17
  • what did you do to get that error? I just tested on a 1600x1200 rgb image. The shape gives me `(1600, 1200, 3)` and I could access the last pixel, `image[1599][1199][2]` without any problems – John Dec 04 '19 at 20:23
  • my image is 96x96 rgb image and I just typed : test[np.where(test ==(0.4,0.4,0.4))] = (0.54,0.27,0.27). then i got that error – Mshz Dec 04 '19 at 20:35
0

I have to agree with Majid Shirazi regarding the proposed solution by Quang Hong. Let's have a look at:

idx = np.where(img == (0.4, 0.4, 0.4))

Then, idx is a 3-tuple containing each a ndarray for all x-coordinates, y-coordinates, and "channel"-coordinates. From NumPy's indexing, I can't see a possibility to properly access/manipulate the values in img in the desired way using the proposed command. I can rather reproduce the exact error stated in the comment.

To get a proper integer array indexing, the x- and y-coordinates need to be extracted. The following code will show that. Alternatively, boolean array indexing might also be used. I added that as an add-on:

import cv2
import numpy as np

# Some artificial image
img = np.swapaxes(np.tile(np.linspace(0, 1, 201), 603).reshape((201, 3, 201)), 1, 2)
cv2.imshow('before', img)

# Proposed solution
img1 = img.copy()
idx = np.where(img1 == (0.4, 0.4, 0.4))
try:
    img1[idx] = (0.54, 0.27, 0.27)
except ValueError as e:
    print(e)

# Corrected solution for proper integer array indexing: Extract x and y coordinates
img1[idx[0], idx[1]] = (0.54, 0.27, 0.27)
cv2.imshow('after: corrected solution', img1)

# Alternative solution using boolean array indexing
img2 = img.copy()
img2[np.all(img2 == (0.4, 0.4, 0.4), axis=2), :] = (0.54, 0.27, 0.27)
cv2.imshow('after: alternative solution', img2)

cv2.waitKey(0)
cv2.destroyAllWindows()

Hope that helps and clarifies!

HansHirse
  • 18,010
  • 10
  • 38
  • 67