Converting an image to grayscale using numpy
Question:
I have an image represented by a numpy.array
matrix nxm of triples (r,g,b)
and I want to convert it into grayscale, , using my own function.
My attempts fail converting the matrix nxmx3 to a matrix of single values nxm, meaning that starting from an array [r,g,b]
I get [gray, gray, gray]
but I need gray
.
i.e. Initial colour channel : [150 246 98]
.
After converting to gray : [134 134 134]
.
What I need : 134
How can I achieve that?
My code:
def grayConversion(image):
height, width, channel = image.shape
for i in range(0, height):
for j in range(0, width):
blueComponent = image[i][j][0]
greenComponent = image[i][j][1]
redComponent = image[i][j][2]
grayValue = 0.07 * blueComponent + 0.72 * greenComponent + 0.21 * redComponent
image[i][j] = grayValue
cv2.imshow("GrayScale",image)
return image
Answers:
Solution using apply_along_axis
A solution can be achieved by using apply_along_axis
:
import numpy as np
def grayscale(colors):
"""Return grayscale of given color."""
r, g, b = colors
return 0.21 * r + 0.72 * g + 0.07 * b
image = np.random.uniform(255, size=(10,10,3))
result = np.apply_along_axis(grayscale, 2, image)
Examples
10×10 image
We can now proceed to visualise the results:
from matplotlib import pyplot as plt
plt.subplot(1,2,1)
plt.imshow(image)
plt.subplot(1,2,2)
plt.imshow(result, cmap='gray')
Textual example (2×2 image)
To visualise the actual results in text I will use a smaller array, just a 2×2 image:
image = np.random.uniform(250, size=(2,2,3))
The content is:
array([[[205.02229826, 109.56089703, 163.74868594],
[ 11.13557763, 160.98463727, 195.0294515 ]],
[[218.15273335, 84.94373737, 197.70228018],
[ 75.8992683 , 224.49258788, 146.74468294]]])
Let’s convert it to grayscale, using our custom function:
result = np.apply_along_axis(grayscale, 2, image)
And the output of the conversion is:
array([[127.62263079, 157.64461409],
[117.94766108, 197.76399547]])
We can visualise this simple example too, using the same code as above:
Further suggestions
If you want to apply your own custom function, then apply_along_axis
is the way to go, but you should consider using purer numpy approaches such as the one suggested by Eric or, if possible, just load the black and white image using cv2
option:
cv2.imread('smalltext.jpg',0)
You can use a dot product:
gray_image = image.dot([0.07, 0.72, 0.21])
Or even just do the whole operation manually:
b = image[..., 0]
g = image[..., 1]
r = image[..., 2]
gray_image = 0.21 * r + 0.72 * g + 0.07 * b
Don’t forget to convert back to 0-255:
gray_image = np.min(gray_image, 255).astype(np.uint8)
Here is a working code:
def grayConversion(image):
grayValue = 0.07 * image[:,:,2] + 0.72 * image[:,:,1] + 0.21 * image[:,:,0]
gray_img = grayValue.astype(np.uint8)
return gray_img
orig = cv2.imread(r'C:UsersJacksonDesktopdrum.png', 1)
g = grayConversion(orig)
cv2.imshow("Original", orig)
cv2.imshow("GrayScale", g)
cv2.waitKey(0)
cv2.destroyAllWindows()
I have an image represented by a numpy.array
matrix nxm of triples (r,g,b)
and I want to convert it into grayscale, , using my own function.
My attempts fail converting the matrix nxmx3 to a matrix of single values nxm, meaning that starting from an array [r,g,b]
I get [gray, gray, gray]
but I need gray
.
i.e. Initial colour channel : [150 246 98]
.
After converting to gray : [134 134 134]
.
What I need : 134
How can I achieve that?
My code:
def grayConversion(image):
height, width, channel = image.shape
for i in range(0, height):
for j in range(0, width):
blueComponent = image[i][j][0]
greenComponent = image[i][j][1]
redComponent = image[i][j][2]
grayValue = 0.07 * blueComponent + 0.72 * greenComponent + 0.21 * redComponent
image[i][j] = grayValue
cv2.imshow("GrayScale",image)
return image
Solution using apply_along_axis
A solution can be achieved by using apply_along_axis
:
import numpy as np
def grayscale(colors):
"""Return grayscale of given color."""
r, g, b = colors
return 0.21 * r + 0.72 * g + 0.07 * b
image = np.random.uniform(255, size=(10,10,3))
result = np.apply_along_axis(grayscale, 2, image)
Examples
10×10 image
We can now proceed to visualise the results:
from matplotlib import pyplot as plt
plt.subplot(1,2,1)
plt.imshow(image)
plt.subplot(1,2,2)
plt.imshow(result, cmap='gray')
Textual example (2×2 image)
To visualise the actual results in text I will use a smaller array, just a 2×2 image:
image = np.random.uniform(250, size=(2,2,3))
The content is:
array([[[205.02229826, 109.56089703, 163.74868594],
[ 11.13557763, 160.98463727, 195.0294515 ]],
[[218.15273335, 84.94373737, 197.70228018],
[ 75.8992683 , 224.49258788, 146.74468294]]])
Let’s convert it to grayscale, using our custom function:
result = np.apply_along_axis(grayscale, 2, image)
And the output of the conversion is:
array([[127.62263079, 157.64461409],
[117.94766108, 197.76399547]])
We can visualise this simple example too, using the same code as above:
Further suggestions
If you want to apply your own custom function, then apply_along_axis
is the way to go, but you should consider using purer numpy approaches such as the one suggested by Eric or, if possible, just load the black and white image using cv2
option:
cv2.imread('smalltext.jpg',0)
You can use a dot product:
gray_image = image.dot([0.07, 0.72, 0.21])
Or even just do the whole operation manually:
b = image[..., 0]
g = image[..., 1]
r = image[..., 2]
gray_image = 0.21 * r + 0.72 * g + 0.07 * b
Don’t forget to convert back to 0-255:
gray_image = np.min(gray_image, 255).astype(np.uint8)
Here is a working code:
def grayConversion(image):
grayValue = 0.07 * image[:,:,2] + 0.72 * image[:,:,1] + 0.21 * image[:,:,0]
gray_img = grayValue.astype(np.uint8)
return gray_img
orig = cv2.imread(r'C:UsersJacksonDesktopdrum.png', 1)
g = grayConversion(orig)
cv2.imshow("Original", orig)
cv2.imshow("GrayScale", g)
cv2.waitKey(0)
cv2.destroyAllWindows()