mikanim
mikanim

Reputation: 439

Getting pixels from an image using PIL

I would like to write a script that reads a bmp file and then notes the pixels on the x-y axes where the image is a color other than white. Then with this data, save it into a .txt file.

I have started using the Pillow library but haven't found how to solve this problem. I opened the bmp file with Pillow and tried to play around with the modules from Image but I couldn't find how to make this work.

Thanks in advance!

Upvotes: 3

Views: 9922

Answers (2)

SpghttCd
SpghttCd

Reputation: 10860

EDIT: Just realized, that the question was about finding the indices of all pixels which are different from white...
For this case just replace the calculation of the boolean array by its complement function:

white = (img[:, :, :3] != 255).any(2)

or

simply add a ~ in front of the boolean array in np.where:

coords = np.array(np.where(~white))[::-1].T

test result then would be consequently the opposite

enter image description here


Here I assume "using PIL" is not a strict requirement, but only a sign of how you tried to start.

That said, you can do the following, using imread from imageio:

import numpy as np
from imageio import imread

img = imread(filename)
white = (img[:, :, :3] == 255).all(2)
coords = np.array(np.where(white))[::-1].T

writing into an ascii file could be done like

with open('xycoordinates.txt', 'w') as f:
    for c in coords:
        f.write(f'{c[0]},{c[1]}\n')

Explanation
img is a 3D-array, of shape (nr, nc, c), i.e. number of rows, number of columns and RGBA-values.
img[:, :, :3] == 255 returns a boolean array of the same shape like img, indicating componentwise matching of the single RGB values (without respect to A. If A should be 255, too, just leave away the complete indexing brackets).
.all(2) reduces it to the desired array of shape (nr, nc) by setting only those indices to True, where the complete RGBA-array matches.

np.where(white) returns a tuple of the row- and column-indices.
np.array() casts it into a numpy array in order to apply numpy indexing and transformation to it.
As row/column is the opposite order of a x/y nomenclature, [::-1] reverses the order of the two index arrays. Transformation by .T is done to output not two arrays (x and y) of n indices, but n arrays of (x, y) indices.

Example

img = imread(samplefile)
plt.imshow(img)

enter image description here

white = (img == [255, 255, 255, 255]).all(2)

array([[False, False,  True, False, False, False],
       [False, False,  True,  True, False, False],
       [False,  True, False, False, False, False],
       [ True,  True, False, False, False, False],
       [False, False, False, False, False,  True]])

coords = np.array(np.where(white))[::-1].T

array([[2, 0],
       [2, 1],
       [3, 1],
       [1, 2],
       [0, 3],
       [1, 3],
       [5, 4]], dtype=int64)

plt.plot(*coords.T, 'ro')

enter image description here

Upvotes: 3

Aivaras Kazakevičius
Aivaras Kazakevičius

Reputation: 439

You can read pixels with Image.getpixel() from PIL.

The code below will give you all non-white pixels in the form of a 2D list.

from PIL import Image

im = Image.open('x.bmp')

imageSizeW, imageSizeH = im.size

nonWhitePixels = []

for i in range(1, imageSizeW):
    for j in range(1, imageSizeH):
        pixVal = im.getpixel((i, j))
        if pixVal != (255, 255, 255):
            nonWhitePixels.append([i, j])

print(nonWhitePixels)

Upvotes: 5

Related Questions