Extracting pixel values using Pillow - every coordinate I use gives the same value - image

I am attempting to use the Pillow library in Python 2.7 to extract pixel values at given coordinates on PNG and JPG images. I don't get an errors but I always get the same value irrespective of the coordinates I have used on an image where the values do vary.
This is an extract from my script where I print all the values (its a small test image):
from PIL import Image
box = Image.open("col_grad.jpg")
pixels = list(box.getdata())
print(pixels)
And from when I try to extract a single value:
from PIL import Image, ImageFilter
box = Image.open("col_grad.jpg")
value = box.load()
print(value[10,10])
I have been using these previous questions on this topic for guidance including:
Getting list of pixel values from PIL
How can I read the RGB value of a given pixel in Python?
Thanks for any help with this,
Alex

I'm not sure if you can access it the way you want, because of the complexity of images data.
Just get the pixel:
Image.getpixel(xy)
Returns the pixel value at a given position.
Parameters: xy – The coordinate, given as (x, y).
Returns: The pixel value. If the image is a multi-layer image, this method returns a tuple.:

You should consider doing one of the following:
FIRST convert your image to grayscale and then find the pixel values present.
img_grey= img.convert('1') # convert image to black and white
SECOND If you want the pixel values of RGB channels, you have to split your color image. Then find the pixel values in all the channels at a particular coordinate.
Image.split(img)

Related

A proper way to convert 2D Array into RGB or GrayScale image for precision difference

I have a 2D CNN model where I perform a classification task. My images are all coming from a sensor data after conversion.
So, normally, my way is to convert them into images using the following approach
newsize = (9, 1000)
pic = acc_normalized[0]
img = Image.fromarray(np.uint8(pic*255), 'L')
img = img.resize(newsize)
image_path = "Images_Accel"
image_name = "D1." + str(2)
img.save(f"{image_path}/{image_name}.jpeg")
This is what I obtain:
However, their precision is sort of important. For instance, some of the numerical values are like:
117.79348187327987 or 117.76568758022673.
As you see in the above line, their difference is the digits, when I use uint8, it only takes 117 to when converting it into image pixels and it looks the same, right? But, I'd like to make them different. In some cases, the difference is even at the 8th or 10th digit.
So, when I try to use mode F and save them .jpeg in Image.fromarray line it gives me error and says that PIL cannot write mode F to jpeg.
Then, I tried to first convert them RGB like following;
img = Image.fromarray(pic, 'RGB')
I am not including np.float32 just before pic or not multiplying it by 255 as it is. Then, I convert this image to grayscale. This is what I got for RGB image;
After converting RGB into grayscale:
As you see, it seems that there is a critical different between the first pic and the last pic. So, what should be the proper way to use them in 2D CNN classification? or, should I convert them into RGB and choose grayscale in CNN implementation and a channel of 1? My image dimensions 1000x9. I can even change this dimension like 250x36 or 100x90. It doesn't matter too much. By the way, in the CNN network, I am able to get more than 90% test accuracy when I use the first-type of image.
The main problem here is using which image conversion method I'll be able to take into account those precision differences across the pixels. Would you give me some idea?
---- EDIT -----
Using .tiff format I made some quick comparisons.
First of all, my data looks like the following;
So, if I convert this first reading into an image using the following code where I use np.float64 and L gives me a grayscale image;
newsize = (9, 1000)
pic = acc_normalized[0]
img = Image.fromarray(np.float64(pic), 'L')
img = img.resize(newsize)
image_path = "Images_Accel"
image_name = "D1." + str(2)
img.save(f"{image_path}/{image_name}.tiff")
It gives me this image;
Then, the first 15x9 matrix seems like following image; The contradiction is that if you take a closer look at the numerical array, for instance (1,4) member, it's a complete black where the numerical array is equal to 0.4326132099074307. For grayscale images, black means that it's close to 0 cause it makes white if it's close to 1. However, if it's making a row operation, there is another value closer to 0 and I was expecting to see it black at (1,5) location. If it does a column operation, there is again something wrong. As I said, this data has been already normalized and varies within 0 and 1. So, what's the logic that it converts the array into an image? What kind of operation it does?
Secondly, if I first get an RGB image of the data and then convert it into a grayscale image, why I am not having exactly the same image as what I obtained first? Should the image coming from direct grayscale conversion (L method, np.float64) and the one coming from RGB-based (first I get RGB then convert it to grayscale) be the same? There is a difference in black-white pixels in those images. I do not know why we have it.
---- EDIT 2 ----
.tiff image with F mode and np.float32 gives the following;
I don't really understand your question, but you seem to want to store image differences that are less than 1, i.e. less than the resolution of integer values.
To do so, you need to use an image format that can store floats. JPEG, PNG, GIF, TGA and BMP cannot store floats. Instead, use TIFF, EXR or PFM formats which can handle floats.
Alternatively, you can create 16-bit PNG images wherein each pixel can store values in range 0..65535. So, say the maximum difference you wanted to store was 60 you could calculate the difference and multiply it by 1000 and round it to make an integer in range 0..60000 and store as 16-bit PNG.
You could record the scale factor as a comment within the image if it is variable.

How to draw single pixels in python Pillow from Numpy arrays without producing pixel noise?

I am stuck with a basic problem to which I was not able to find any answer nor solution no matter what I tried. Please help me out and enlighten me, what I am doing wrong :-)
Task:
Make a Numpy array of Pixels, manipulate them by an algorithm and then print an image from that array.
Occuring Problem:
When I manipulate single pixels this way, there is noise artifacts appearing next to manipulated pixels (see example pictures)
Details - What I want to do:
I have a numpy array to create an image from.
The array is created as black:
shape = np.zeros((100, 100, 3), dtype=np.uint8)
Now I want to manipulate single pixels by an algorithm, for instance:
color = (255, 255, 255)
shape[50, 50] = color
There will be 100s and 1000s of pixels manipulated in color this way.
At the end, I want to make an image from that shape array and print it to the screen:
arr_image = Image.fromarray(shape, 'RGB')
arr_image.save('test.jpg')
Details - What I tried:
No matter, what I do, I get pixel noise next to created pixels in images created using the example code!
I tried:
Searching the Internet/Stackoverflow: No such problem described/found
Taking working code from other examples and manipulate to my needs: Same artifacts occuring after manipulation
Drawing pixels in the created image after making a black-only (0,0,0) image from a numpy array by using Image method putpixel: Same artifacts appearing
Changing up syntax: Same artifacts appearing
Checking the underlying numpy arrays for grey values at the position of the artifacts: THERE IS NO SUCH GREY VALUES IN THE ARRAYS!!
When using Pillow method show(), the pixel noise is gone (!) in the windows popup, however (!!!), when I open the image from outside python, the pixel noise is in the exact same image visible (!!!!!!!!!!!!!)
Example code that produces this problem:
import numpy as np
from PIL import Image
shape = np.zeros((100, 100, 3), dtype=np.uint8)
white = (255, 255, 255)
shape[50][50] = white
arr_image = Image.fromarray(shape, 'RGB')
# arr_image.putpixel((50, 50), white)
arr_image.save('test.jpg')
Example images:
Black Array
[Same Array, but point 50][50] is set to white
[Same Array, but 100 random points were placed at x][y] and set to white
The solution to this is: Do not use .jpg data, the compression of this format causes observed pattern.
When using .png, the bug was instantly solved! In this image (.png), you can now see that there is 0 pixel noise nor strange artifact patterns, when generating an array-based image as described above: enter image description here
Thank you #dantechguy and #Mark Setchell, you guys saved me! :-))

binary matrix to image in octave

I have a 2D binary matrix and I would like to get a grayscale image from it. Someone suggested using imwrite but the problem is that instead of black and white the colors I get are black and red. The matrix contains only zeros and ones. Any idea why this is happening or how I could get the result I want. I'm running it on OS X. This is the line where I try to create the image. Thank you.
imwrite(matrix, "image.bmp");
You have to convert your matrix to a boolean matrix.
img = logical (matrix);
imwrite (img, "image.bmp");
and for the future: A Code snippet which create some sample image would be better. See https://stackoverflow.com/help/mcve

Converting to 8-bit image causes white spots where black was. Why is this?

Img is a dtype=float64 numpy data type. When I run this code:
Img2 = np.array(Img, np.uint8)
the background of my images turns white. How can I avoid this and still get an 8-bit image?
Edit:
Sure, I can give more info. The single image is compiled from a stack of 400 images. They are each coming from an .avi video file, and each image is converted into a NumPy array like this:
gray_img = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
A more complicated operation is performed on this whole stack, but does not involve creating new images. It's simply performing calculations on each 1D array to yield a single pixel.
The interpolation is most likely linear (the default in plotting images with matplotlib. The images were saved as .PNGs.
You probably see overflow. If you cast 257 to np.uint8, you will get 1. According to a google search, avi files contain images with a color depth of 15 - 24 bit. When you cast this depth to np.uint8, you will see white regions getting darkened and (if a normalization takes place somewhere) also dark regions getting white (-5 -> 251). For the regions that become bright, you could check whether you have negative pixel values in the original image Img.
The Docs say that sometimes you have to do some scaling to get a proper cast, and to rather use higher depth whenever possible to avoid artefacts.
The solution seems to be either working at higher depth, i.e. casting to np.uint16 or np.uint32, or to scale the pixel values before reducing the depth, i.e. with Img2 already being a numpy matrix
# make sure that values are between 0 and 255, i.e. within 8bit range
Img2 *= 255/Img2.max()
# cast to 8bit
Img2 = np.array(Img, np.uint8)

Matlab - How to obtain values of pixels?

If I have an image, how can I obtain the values of each pixel in that image using matlab
Thanks.
Images are matrices (2D if grayscale, 3D if colored) in MATLAB.
You can use x(i,j) to access a pixel at location (i,j) in a grayscale image.
If the image is colored, you can use x(i,j,:) to access the r, g, b values in a 3-vector, respectively. If you need individual channels, then, you can use x(i,j,1) for red for example.
You may read this page to learn more.
You can use reshape to extract all the pixel values of the image into a vector with pixel values:
frame = imread('picture.jpg');
frame_size = size(frame);
allpixels = reshape(frame, frame_size(1)*frame_size(2), frame_size(3))
This can be useful when you want to vectorize your Matlab code (to avoid a for loop that goes through every pixel). To get back the original image representation:
frame2 = reshape(allpixels, frame_size);
to get the values at pixel(1,1) we simply write image(1,1).

Resources