Converting numpy array into an RGB image using PILLOW - python

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

Related

Scikit Image load binary image and convert to binary matrix

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'

How to find vertices of a polytope in python?

I want to find the vertices given the following:
`A = np.array([
[-1,2/3,0,0,0,0,0,0,0],
[1,-2/3,0,0,0,0,0,0,0],
[-1,0,0,2/3,0,0,0,0,0],
[-1,0,2/3,0,0,0,0,0,0],
[1,0,-2/3,0,0,0,0,0,0],
[-1,0,0,0,2/3,0,0,0,0],
[-1,0,0,0,2/3,0,0,0,0],
[1,0,0,-2/3,0,0,0,0,0],
[-1,2/3,0,0,0,0,0,0,0]])`
`b = np.array([-1/3, 1/3, -2/3, 1/3, -1/3, 0, -2/3, 2/3, -1/3])` .
I tried to compute the vertices by using the
vertices = pypoman.compute_polytope_vertices(A,b).
However, I get the following error:
raise Exception("Polyhedron is not a polytope")
Exception: Polyhedron is not a polytope".
Did anyone have a problem like this?
Use pycddlib:
# -*- coding: utf-8 -*-
import numpy as np
import cdd as pcdd
import fractions as frac
A = np.array([
[-1,frac.Fraction(2,3),0,0,0,0,0,0,0],
[1,-frac.Fraction(2,3),0,0,0,0,0,0,0],
[-1,0,0,frac.Fraction(2,3),0,0,0,0,0],
[-1,0,frac.Fraction(2,3),0,0,0,0,0,0],
[1,0,-frac.Fraction(2,3),0,0,0,0,0,0],
[-1,0,0,0,frac.Fraction(2,3),0,0,0,0],
[-1,0,0,0,frac.Fraction(2,3),0,0,0,0],
[1,0,0,-frac.Fraction(2,3),0,0,0,0,0],
[-1,frac.Fraction(2,3),0,0,0,0,0,0,0]])
b = np.array([
[-frac.Fraction(1,3)],
[frac.Fraction(1,3)],
[-frac.Fraction(2,3)],
[frac.Fraction(1,3)],
[-frac.Fraction(1,3)],
[0],
[-frac.Fraction(2,3)],
[frac.Fraction(2,3)],
[-frac.Fraction(1,3)]
])
M = np.hstack( (b, -A) )
mat = pcdd.Matrix(M, linear=False, number_type="fraction")
mat.rep_type = pcdd.RepType.INEQUALITY
poly = pcdd.Polyhedron(mat)
ext = poly.get_generators()
print(ext)
Giving:
1 2/3 1/2 3/2 0 0 0 0 0 0
0 1 3/2 3/2 3/2 0 0 0 0 0
0 2/3 1 1 1 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
Indeed, this is not a polytope. A "1" in the first column means it is an extreme point, and here there is only one.

Complex structure of int32_t and char array in python ctypes

I am trying to create a structure to use in a C library provided (DLL),
How the following structure (given in the documentation) can be defined?
#define A 10
#define B 20
typedef struct
{
int32_t size;
int32_t num;
char buf1[A][B];
char buf2[A][B];
char buf3[A][B];
} INSTRUCT;
My attempt to define it in python using ctypes was like so:
from ctypes import*
char_buff1 = ((c_char * 10) * 20)
char_buff2 = ((c_char * 10) * 20)
char_buff3 = ((c_char * 10) * 20)
class INSTRUCT(Structure):
_fields_=[("size",c_int32),("num",c_int32),("buf1",char_buff1),("buf2",char_buff2),("buf3",char_buff3)]
Can int32_t be replaced with c_int_32 in ctypes?
Is it correct way to define the structure?
Then I tried to feed the pointer of the structure to the DLL function and check what it returns as follows:
dlllib = CDLL("some.dll")
somefunction = dlllib.some_function
somefunction.argtypes = [POINTER(INSTRUCT)]
INSTRUCT().size
INSTRUCT().num
print(np.ctypeslib.as_array(INSTRUCT().buf1))
However, I can only the return is 0 and unmodified by the function -- equal to the one defined before the C function call.
I am not sure at which stage the problem occurs, however, there are no errors, the code executes normally.
Unfortunately, I don't have the C code available, only the input parameters for the function.
Best regards
The array definition is wrong. In ctypes, the array indices need to be reversed to index the array the way C does. For example, the equivalent of char buf[x][y] in Python with ctypes is buf = (c_char * y * x)(). Note that the bounds are reversed. Otherwise, your definition was correct.
Note that using c_char will return text characters for array values. If you want integers, use c_int8. I'll use the latter below.
Example:
from ctypes import *
import numpy as np
A,B = 10,20
ARRAY = c_int8 * B * A # build as B,A
class INSTRUCT(Structure):
_fields_=[("size",c_int32),
("num",c_int32),
("buf1",ARRAY),
("buf2",ARRAY),
("buf3",ARRAY)]
i = INSTRUCT()
i.buf1[9][19] = 1 # access indices as A,B
print(np.ctypeslib.as_array(i.buf1))
[[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 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 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 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 1]] # 1 in correct location
Your example of accessing used INSTRUCT() which creates a new, zeroed object each time. Create a single instance and pass it to a function like so:
dlllib = CDLL("some.dll")
somefunction = dlllib.some_function
somefunction.argtypes = [POINTER(INSTRUCT)]
i = INSTRUCT() # make an instance
somefunction(byref(i)) # byref() passes address of a ctypes object.

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')

rotate an nxnxn matrix in python

I have a binary array of size 64x64x64, where a volume of 40x40x40 is set to "1" and rest is "0". I have been trying to rotate this cube about its center around z-axis using skimage.transform.rotate and also Opencv as:
def rotateImage(image, angle):
row, col = image.shape
center = tuple(np.array([row, col]) / 2)
rot_mat = cv2.getRotationMatrix2D(center, angle, 1.0)
new_image = cv2.warpAffine(image, rot_mat, (col, row))
return new_image
In the case of openCV, I tried, 2D rotation of each idividual slices in a cube (Cube[:,:,n=1,2,3...p]).
After rotating, total sum of the values in the array changes. This may be caused by interpolation during rotation. How can I rotate 3D array of this kind without adding anything to the array?
Ok so I understand now what you are asking. The closest I can come up with is scipy.ndimage. But there is a way interface with imagej from python if which might be easier. But here is what I did with scipy.ndimage:
from scipy.ndimage import interpolation
angle = 25 #angle should be in degrees
Rotatedim = interpolation.rotate(yourimage, angle, reshape = False,output = np.int32, order = 5,prefilter = False)
This worked for some angles to preserve the some and not others, perhaps by playing around more with the parameters you might be able to get your desired outcome.
One option is to convert into sparse, and transform the coordinates using a matrix rotation. Then transform back into dense. In 2 dimensions, this looks like:
import numpy as np
import scipy.sparse
import math
N = 10
space = np.zeros((N, N), dtype=np.int8)
space[3:7, 3:7].fill(1)
print(space)
print(np.sum(space))
space_coo = scipy.sparse.coo_matrix(space)
Coords = np.array(space_coo.nonzero()) - 3
theta = 30 * 3.1416 / 180
R = np.array([[math.cos(theta), math.sin(theta)], [-math.sin(theta), math.cos(theta)]])
space2_coords = R.dot(Coords)
space2_coords = np.round(space2_coords)
space2_coords += 3
space2_sparse = scipy.sparse.coo_matrix(([1] * space2_coords.shape[1], (space2_coords[0], space2_coords[1])), shape=(N, N))
space2 = space2_sparse.todense()
print(space2)
print(np.sum(space2))
Output:
[[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 1 1 1 1 0 0 0]
[0 0 0 1 1 1 1 0 0 0]
[0 0 0 1 1 1 1 0 0 0]
[0 0 0 1 1 1 1 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]]
16
[[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 1 0 0 0 0 0 0]
[0 0 1 1 1 1 0 0 0 0]
[0 0 1 1 1 1 1 0 0 0]
[0 1 1 0 1 1 0 0 0 0]
[0 0 0 1 1 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]]
16
The advantage is that you'll get exactly as many 1 values before and after the transform. The downsides is that you might get 'holes', as above, and/or duplicate coordinates, giving values of '2' in the final dense matrix.

Categories

Resources