Reputation: 27
I tried to convert an rgb image to grayscale using the weighted sum formula
Y' = 0.299 R' + 0.587 G' + .114 B'
It didn't give any errors but I am unable to understand the output. Here's the code:
img = Image.open("dog.jpg")
img = img.resize((256, 256), resample=Image.BILINEAR)
img = np.array(img)
bw = np.zeros((256,256))
for i in range(256):
for j in range(256):
bw[i,j] = (.299*img[i,j,0])+(.587*img[i,j,1])+(.114*img[i,j,2])
i = Image.fromarray(bw,'L')
Here is the output picture that I got:
Upvotes: 0
Views: 200
Reputation: 9796
Your computation in bw[i,j]
results in a float. Images expect a uint8 type, i.e., integers in the range 0-255. To fix this change
bw = np.zeros((256,256))
to
bw = np.zeros((256,256), dtype=np.uint8)
This will clip every number in 0-0.999... to 0.
>>> bw[0,0] = 0.3
>>> bw[0,0]
0
>>> bw[0,0] = 0.6
>>> bw[0,0]
0
If you care more about rounding to the nearest integer than always rounding down, then you can also wrap that computation in np.round()
.
>>> bw[0,0] = np.round(0.3)
>>> bw[0,0]
0
>>> bw[0,0] = np.round(0.6)
>>> bw[0,0]
1
Numpy supports vectorisation, so you don't need to write explicit loops (which are also slower).
img = np.array(img)
bw = np.round(.299 * img[...,0] + .587 * img[...,1] + .114 * img[...,2]).astype(np.uint8)
Upvotes: 1
Reputation: 987
As far as I understood, PIL images are stored in uint8
format, so you can just replace i = Image.fromarray(bw,'L')
with i = Image.fromarray(np.uint8(bw),'L')
Upvotes: 0