pain
pain

Reputation: 27

Converting image to grayscale returned a weird image

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:

Output picture

Upvotes: 0

Views: 200

Answers (2)

Reti43
Reti43

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

abe
abe

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

Related Questions