Scikit Image load binary image and convert to binary matrix - python

I have created a numpy array shape(11 x 11) with all pixels 0 excluding one column filled with 1.
[[ 0 0 0 0 0 1 0 0 0 0 0 ]
[ 0 0 0 0 0 1 0 0 0 0 0 ]
[ 0 0 0 0 0 1 0 0 0 0 0 ]
[ 0 0 0 0 0 1 0 0 0 0 0 ]
[ 0 0 0 0 0 1 0 0 0 0 0 ]
[ 0 0 0 0 0 1 0 0 0 0 0 ]
[ 0 0 0 0 0 1 0 0 0 0 0 ]
[ 0 0 0 0 0 1 0 0 0 0 0 ]
[ 0 0 0 0 0 1 0 0 0 0 0 ]
[ 0 0 0 0 0 1 0 0 0 0 0 ]
[ 0 0 0 0 0 1 0 0 0 0 0 ]]
The array was saved as a png image using matplotlib.imsave yielding the expected image - black background with a white line in the middle.
When trying to reimport the saved png image
skipy.imread and Pil.Image.Open yield an array of the form
[[[ 68 1 84 255]
[ 68 1 84 255]
[ 68 1 84 255]
[ 68 1 84 255]
[ 68 1 84 255]
[253 231 36 255]
[ 68 1 84 255]
[ 68 1 84 255]
[ 68 1 84 255]
[ 68 1 84 255]
[ 68 1 84 255]]
...
]
What does this file format mean (could not find an explanation in the scikit image documentation) ?
And how do I convert it back to the binary input image?

What you see is explained thusly:
your data was grayscale
then you plotted that with a colormap
-- the line looks yellow and the background looks dark blue/violet?
then you told matplotlib to save that false-color picture
then you read that false-color picture back
now you have RGBA pixel data. you see the first pixel row, and each value of each color pixel
If you wanted to maintain the grayscale appearance of your data, you'd have some choices.
Use plt.imshow(arr, cmap="gray"), which uses a gray color map rather than a colorful one.
When reading the image, and also converting any color to grayscale, you can choose scikit-image or OpenCV. OpenCV has cv.imread(fname, cv.IMREAD_GRAYSCALE). scikit-image offers skimage.io.imread(fname, as_gray=True).
And really you should use scikit-image or OpenCV for writing your picture in the first place. Matplotlib is for plotting, not for storing data authentically. Matplotlib took your data and rescaled it so the maximum and minimum value become 0 and 1, which is black and white for the gray cmap.

On grayscale, a pixel with value 1 doesn't appear white - this simply happens because matplotlib normalizes the image before displaying it.
Choose either:
a) Keep the original binary values, then the saved image won't have a white line in the middle
b) Have a white line in the middle, but then you'll have to modify the array before saving and after loading it.
Ad b)
import cv2 as cv
import matplotlib.pyplot as plt
import numpy as np
# This is the array you have
arr = np.zeros((11, 11), dtype=np.uint8)
arr[:, 5] = 1
plt.figure()
plt.imshow(arr, cmap='gray')
plt.show()
# This will ensure that the line appears white in the .png
arr_png = arr * 255 # 2**8 - 1
# Write to disk
cv.imwrite('line.png', arr_png)
# Load from disk
arr_from_disk = np.array(cv.imread('line.png', 0), dtype=np.uint8)
# Rescale
arr_from_disk = np.divide(arr_from_disk, 255)
assert np.array_equal(arr, arr_from_disk), 'Oops'

Related

Rasterio grayscale .tif image is empty

I'm facing an issue when opening a .tif using rasterio using the code below.
fp = 'image.tif'
image = rasterio.open(fp)
print(image.read())
When printing the content of the image, I get this
[[[0 0 0 ... 0 0 0]
[0 0 0 ... 0 0 0]
[0 0 0 ... 0 0 0]
...
[0 0 0 ... 0 0 0]
[0 0 0 ... 0 0 0]
[0 0 0 ... 0 0 0]]]
I verified all values and they are all 0. However, when dragging the image in QGIS, I can view it and confirm that the image contains values ranging from 101 to 122.
QGIS image
Any idea on how to read the image and get these 101 to 122 values as a numpy array ?
Here's a link to the image in question

Converting numpy array into an RGB image using PILLOW

I have a numpy array of dimension 11*11 that I want to convert into an RGB image so I'm using this code :
import matplotlib.pyplot as plt
from PIL import Image as im
n_images = 1
train_data_np = train_data.to_numpy()
train_images = train_data_np[:n_images]
for i in range(n_images):
image_train = np.reshape(train_images[i], [11, 11])
image = im.fromarray(np.uint8(image_train))
plt.imshow(image)
plt.show()
My problem is that the image displayed is not all RGB because for this value :
[[ 0 0 0 0 0 0 0 0 0 0 0]
[ 0 0 0 0 0 0 0 0 0 0 0]
[ 0 0 255 0 0 150 25 43 7 43 0]
[ 0 0 12 0 0 255 0 0 0 0 0]
[ 0 0 0 0 0 0 0 0 0 0 0]
[ 0 0 0 0 0 255 0 0 0 0 0]
[ 0 0 0 0 0 0 0 0 0 0 0]
[ 0 0 0 0 0 0 0 0 0 0 0]
[ 0 0 0 0 0 0 0 0 0 0 0]
[ 0 0 0 0 0 0 0 0 0 0 0]
[ 0 0 0 0 0 0 0 0 0 255 0]]
it displayed this image
which doesn't respect RGB format as you can see where 0 it should be black instead
of purple and 255 should be white instead of yellow.
I tried to convert the numpy array of [11,11] into [11,11,3] to support RGB channels but it gave in the end a grayscale image only white and black. but it is not what I want. Here is the code that I used :
n_images = 1
train_data_np = train_data.to_numpy()
train_images = train_data_np[:n_images]
for i in range(n_images):
image_res = np.reshape(train_images[i],[11,11])
img2 = np.zeros( ( image_res.shape[0], image_res.shape[1], 3 ) )
img2[:,:,0] = image_res # same value in each channel
img2[:,:,1] = image_res
img2[:,:,2] = image_res
image_train = np.reshape(img2,[11,11,3])
image = im.fromarray(np.uint8(image_train),'RGB')
plt.imshow(image)
plt.show()
can someone explain to me how to implement or use a python function to transform the NumPy array 11x11 into an array of 11x11x3 using a colormap ?
This link contains an example of what i want really to do :
https://www.mathworks.com/help/matlab/ref/ind2rgb.html
Thank you in advance

Python OpenCV: Why does fillPoly() only draw grey polygons, regardless of its color argument?

I am trying to write a white mask on a black, two-dimensional NumPy array — an image with one channel — in OpenCV using Python:
mask = np.zeros(shape=(100, 100), dtype=np.int8)
cv2.fillPoly(mask, np.array([[[0,0], [89, 0], [99,50], [33,96], [0,47]]], dtype=np.int32), color=255)
print(mask)
However, the polygon has a grey color when I print the mask:
[[127 127 127 ... 0 0 0]
[127 127 127 ... 0 0 0]
[127 127 127 ... 0 0 0]
...
[ 0 0 0 ... 0 0 0]
[ 0 0 0 ... 0 0 0]
[ 0 0 0 ... 0 0 0]]
I tried a 3D NumPy array with color=(255,255,255), I tried different colours, all to no avail. Why is it ignoring the color argument?
The problem comes from the initialization of your mask:
mask = np.zeros(shape=(100, 100), dtype=np.int8)
The value range of the int8 data type is -128 ... 127, thus any value above 127 will be "truncated" to 127.
Try your code with color=100, you'll get the expected output:
[[100 100 100 ... 0 0 0]
[100 100 100 ... 0 0 0]
[100 100 100 ... 0 0 0]
...
[ 0 0 0 ... 0 0 0]
[ 0 0 0 ... 0 0 0]
[ 0 0 0 ... 0 0 0]]
I guess, you wanted to use uint8 instead of int8, so maybe it's just a simple typo!?
Changing your code accordingly to
mask = np.zeros(shape=(100, 100), dtype=np.uint8)
then gives the expected result, also for color=255:
[[255 255 255 ... 0 0 0]
[255 255 255 ... 0 0 0]
[255 255 255 ... 0 0 0]
...
[ 0 0 0 ... 0 0 0]
[ 0 0 0 ... 0 0 0]
[ 0 0 0 ... 0 0 0]]
The problem lies in the datatype selection when initializing the numpy array. In your example code you are using np.int8 , which has a range from -128 ... 127.. Instead of np.int8 you should consider using np.uint8, which has a range of 0 ... 255, whixh you are looking for.
mask = np.zeros(shape=(100, 100), dtype=np.int8)
should be
mask = np.zeros(shape=(100, 100), dtype=np.uint8)
[[255 255 255 ... 0 0 0]
[255 255 255 ... 0 0 0]
[255 255 255 ... 0 0 0]
...
[ 0 0 0 ... 0 0 0]
[ 0 0 0 ... 0 0 0]
[ 0 0 0 ... 0 0 0]]
For me the problem was not initializing the mask with depth.
mask = np.zeros(shape = (MASK_WIDTH, MASK_HEIGHT), dtype=np.uint8)
Solved with this code
mask = np.zeros(shape = (MASK_WIDTH, MASK_HEIGHT, 3), dtype=np.uint8)
rcolor = list(np.random.random(size=3) * 256)
cv2.fillPoly(mask, [arr], color=rcolor)
cv2.imwrite(os.path.join(mask_folder, itr + ".jpg") , cv2.cvtColor(mask, cv2.COLOR_RGB2BGR))

convert image into pixel dataframe into csv file using python

i have folder with pictures ("C:\Users\Admin\Downloads\mypicture")
here example of it
8
and2
i want convert it to pixel dataframe like this
pixel1 pixel. pixel158 pixel159 pixel160 pixel161 pixel162 pixel163 pixel164 pixel165 pixel166 pixel167 pixel168 pixel169 pixel170 pixel171 pixel172
1 0 … 0 191 250 253 93 0 0 0 0 0 0 0 0 0 0
2 0 … 32 0 0 0 0 0 0 0 0 0 0 0 0 0 0
pixel173 pixel174 pixel175 pixel176
1 0 0 0 0
2 0 0 16 179
Every image is represented as a single row . The greyscale of each image falls in the range [0, 255].
i do so
img = mpimg.imread("C:\Users\Admin\Downloads\mypicture")
img = np.ravel(img)
df = pd.DataFrame([img])
but i get this error
SyntaxError: (unicode error) 'unicodeescape' codec can't decode bytes in position 2-3: truncated \UXXXXXXXX escape
How can i get desired data frame in csv file?
You could Use PIL library to convert the image to a pixel dataframe, by getting the pixel's list from an image like this
from PIL import Image
im = Image.open('image.png')
pixels = list(im.getdata())
this will return a list of pixels with the (r,g,b) values, so if you just want to get the grayscale of each pixel, just iterate the list in the second element of each value, like this
result = []
counter = 0
for pixel in pixels:
counter += 1
result.append(['pixel'+ str(counter), pixel[1]])
return (result)
Output:
['pixel1', 72], ['pixel2', 50], ['pixel3', 0], ['pixel4', 11], ['pixel5', 30], ['pixel6', 42], ['pixel7', 107], ['pixel8', 123], ['pixel9', 124], ['pixel10', 130]

Error when transforming numpy array to PIL Image

I have a variable img which is a int64 numpy.array with sizes 28x28. Its content looks like this:
[...]
[ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0]
[ 0 0 0 0 0 0 0 0 0 68 154 188 176 254 254 254 254 254
227 106 17 0 0 0 0 0 0 0]
[...]
I want to convert the array to a PIL image. To do so I call img = Image.fromarray(img, mode='L') but the output I get is only 0s while it is obvious that it shouldn't be like that. I have checked the mode options and seems like L is correct. Also checked other answers inside stackoverflow and couldn't find something that reproduces this particular problem.
L (8-bit pixels, black and white)
Why is this "simple" piece of code given an unexpected behaviour?
Thanks in advance!
As #Divakar pointed out, the data types were not coherent.
Just by adding np.uint8() it works:
img = Image.fromarray(np.uint8(img), mode='L')

Categories

Resources