I am running this code
from PIL import Image
import numpy as np
im = Image.open("/Users/Hugo/green_leaves.jpg")
im.load()
height, widht = im.size
p = np.array([0,0,0])
for row in range(height):
for col in range(widht):
a = im.getpixel((row,col))
p = np.append(a.asarray())
But I am getting the following error
Traceback (most recent call last):
File "/Users/hugo/PycharmProjects/Meteo API/image.py", line 17, in <module>
p = np.append(a.asarray())
AttributeError: 'tuple' object has no attribute 'asarray'
Could you help me?
You mentioned numpy. If you want a numpy array of the image, don't iterate through it, just do data = np.array(im).
E.g.
from PIL import Image
import numpy as np
im = Image.open("/Users/Hugo/green_leaves.jpg")
p = np.array(im)
Building up a numpy array by repeatedly appending to it is very inefficient. Numpy arrays aren't like python lists (python lists serve that purpose very well!!). They're fixed-size, homogenous, memory-efficient arrays.
If you did want to build up a numpy array through appending, use a list (which can be efficiently appended to) and then convert that list to a numpy array.
However, in this case, PIL images support being converted to numpy arrays directly.
On one more note, the example I gave above isn't 100% equivalent to your code. p will be a height by width by numbands (3 or 4) array, instead of a numpixels by numbands array as it was in your original example.
If you want to reshape the array into numpixels by numbands, just do:
p = p.reshape(-1, p.shape[2])
(Or equivalently, p.shape = -1, p.shape[2])
This will reshape the array into width*height by numbands (either 3 or 4, depending on whether or not there's an alpha channel) array. In other words a sequence of the red,green,blue,alpha pixel values in the image. The -1 is a placeholder that tells numpy to calculate the appropriate shape for the first axes based on the other sizes that are specified.
Initialize p as a list, and convert it to a numpy array after the for-loop:
p=[]
for row in range(height):
for col in range(widht):
a = im.getpixel((row,col))
p.append(a)
p=np.asarray(p)
This will create a list of shape (*, 3), which is same as np.array(im).reshape(-1, 3). So if you need this, just use the latter form ;)
Related
I'm trying to create a multidimensional matrix with numpy, to describe a RGB image. Something like this does not work:
numpy.full(100, 100, [0,0,0])
This fails with TypeError: data type not understood. What I'm trying to get at is a pixel matrix with rgb values at every pixel.
Edit: this gets me halfway there:
n = numpy.empty((3,3,3))
n[:] = [0,0,0]
However, this gives a float array for every point, while a uint8 array would suffice. How would I fix that?
Apparently, this does the trick:
n = numpy.empty((3,3,3))
n[:] = numpy.array([0,0,0], dtype=numpy.uint8)
I have 1,000 RGB images (64X64) which I want to convert to an (m, n) array.
I use this:
import numpy as np
from skdata.mnist.views import OfficialImageClassification
from matplotlib import pyplot as plt
from PIL import Image
import glob
import cv2
x_data = np.array( [np.array(cv2.imread(imagePath[i])) for i in range(len(imagePath))] )
print x_data.shape
Which gives me: (1000, 64, 64, 3)
Now if I do:
pixels = x_data.flatten()
print pixels.shape
I get: (12288000,)
However, I require an array with these dimensions: (1000, 12288)
How can I achieve that?
Apply the numpy method reshape() after applying flatten() to the flattened array:
x_data = np.array( [np.array(cv2.imread(imagePath[i])) for i in range(len(imagePath))] )
pixels = x_data.flatten().reshape(1000, 12288)
print pixels.shape
Try this:
d1, d2, d3, d4 = x_data.shape
then using numpy.reshape()
x_data_reshaped = x_data.reshape((d1, d2*d3*d4))
or
x_data_reshaped = x_data.reshape((d1, -1))
(Numpy infers the the value instead of -1 from original length and defined dimension d1)
You can iterate over your images array and flatten each row independently.
numImages = x_data.shape[0]
flattened = np.array([x_data[i].flatten() for i in range(numImages)])
You could also use this:
X is your 2D picture with size 32x32 for example and the -1 it simply means that it is an unknown dimension and we want numpy to figure it out. And numpy will figure this by looking at the 'length of the array and remaining dimensions' and making sure it satisfies the above mentioned criteria (What does -1 mean in numpy reshape?). T means to invert the transposition of tensors when using the axes keyword argument (https://docs.scipy.org/doc/numpy/reference/generated/numpy.transpose.html).
X_flatten = X.reshape(X.shape[0], -1).T
Assuming you have an array image_array you can use the reshape() method.
image_array = image_array.reshape(1000, 12288)
I have the following code that works like expected, but I'm curious if the loop can be replaced by a native numpy function/method for better performance. What I have is one array holding RGB values that I use as a lookup table and two 2d arrays holding greyscale values (0-255). Each value of these two arrays corresponds to the value of one axis of the lookup table.
As mentioned, what would be really nice is getting rid of the (slow) loop in python and using a faster numpy method.
#!/usr/bin/env python3
from PIL import Image
import numpy as np
dim = (2000, 2000)
rows, cols = dim
# holding a 256x256 RGB color lookup table
color_map = np.random.random_integers(0, 255, (256,256,3))
# image 1 greyscale values
color_map_idx_row = np.random.randint(0, 255, dim)
# image 2 greyscale values
color_map_idx_col = np.random.randint(0, 255, dim)
# output image data
result_data = np.zeros((rows, cols, 3), dtype=np.uint8)
# is there any built in function in numpy that could
# replace this loop?
# -------------------------------------------------------
for i in range(rows):
for j in range(cols):
row_idx = color_map_idx_row.item(i, j)
col_idx = color_map_idx_col.item(i, j)
rgb_color = color_map[row_idx,col_idx]
result_data[i,j] = rgb_color
img = Image.fromarray(result_data, 'RGB')
img.save('result.png')
You can replace the double-for loop with fancy-indexing:
In [33]: result_alt = color_map[color_map_idx_row, color_map_idx_col]
This confirms the result is the same:
In [36]: np.allclose(result_data, result_alt)
Out[36]: True
You can reshape the 3D array into a 2D array with the axis=1 holding the three channels. Then, use row-slicing with the row indices being calculated as linear indices from the row and column indices arrays. Please note that the reshaped array being a view only, won't burden any of the workspace memory. Thus, we would have -
m = color_map.shape[0]
out = color_map.reshape(-1,3)[color_map_idx_row*m + color_map_idx_col]
I've been running into a TypeError: list indices must be integers, not tuple. However, I can't figure out how to fix it, as I'm apparently misunderstanding where the tuple is (wasn't even aware there would be one from what I understand). Shouldn't my index and the values that I'm passing in all be integers?
def videoVolume(images):
""" Create a video volume from the image list.
Note: Simple function to convert a list to a 4D numpy array.
Args:
images (list): A list of frames. Each element of the list contains a
numpy array of a colored image. You may assume that each
frame has the same shape, (rows, cols, 3).
Returns:
output (numpy.ndarray): A 4D numpy array. This array should have
dimensions (num_frames, rows, cols, 3) and
dtype np.uint8.
"""
output = np.zeros((len(images), images[0].shape[0], images[0].shape[1],
images[0].shape[2]), dtype=np.uint8)
# WRITE YOUR CODE HERE.
for x in range(len(images)):
output[:,:,:,:] = [x, images[x,:,3], images[:,x,3], 3]
# END OF FUNCTION.
return output
The tuple referred to in the error message is the x,:,3 in the index here:
images[x,:,3]
The reason this is happening is that images is passed in as a list of frames (each a 3d numpy array), but you are trying to access it as though it is itself a numpy array. (Try doing lst = [1, 2, 3]; lst[:,:] and you'll see you get the same error message).
Instead, you meant to access it as something like images[x][:,:,:], for instance
for x in range(len(images)):
output[x,:,:,:] = images[x][:,:,:]
I'm trying to find dominant colors in image and then treshold the most dominant one. However I'm having trouble with data types.
My formula gives the most dominant color as:
color=[10,10,10] # type=numpy.ndarray ,uint8
But it gives assertion error when I try to convert it:
color=cv2.cvtColor(color, cv2.COLOR_BGR2HSV) #gives assertion error
What cv2.cvtColor wants as an input is that:
color_ideal=[[[ 10, 10, 10 ]]] #type=numpy.ndarray, uint8
To obtain it, I managed to manipulate color as such:
color=np.uint8(np.atleast_3d(clr).astype(int).reshape(1,1,3))
This seems working, but know I cannot append multiple colors to numpy array.Somehow, after appending the dimension is reduced to 1. My code is:
color=np.uint8([[[]]])
for item in clt.cluster_centers_:
color=np.append(color,(np.uint8(np.atleast_3d(item).astype(int).reshape(1,1,3))))
#returns: color=[10,10,10] somehow its dimension is down to 1
My questions are:
1-How to properly append color data without loosing its dimension?
2-Is there easier way to handle this? I'm suprised how difficult it is to manipulate custom color pixel.
The full code is here in case it helps:
<!-- language: lang-py -->
import cv2
import numpy as np
from sklearn.cluster import KMeans
def find_kmean_colors(img,no_cluster=2):
clt = KMeans(no_cluster).fit(img)
return clt
def initialize(img='people_frontal.jpg'):
img=cv2.imread('people_frontal_close_body.jpg')
img=cv2.bilateralFilter(img,9,75,75)
return img
img=initialize()
img_hsv =cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
img_list= img.reshape((img.shape[0] * img_hsv.shape[1], 3))
clt=(find_kmean_colors(img_list,1))
color=np.uint8([[[]]])
for i in clt.cluster_centers_:
color=np.append(color,(np.uint8(np.atleast_3d(i).astype(int).reshape(1,1,3))))
#color=np.uint8(np.atleast_3d(clt.cluster_centers_).astype(int).reshape(1,1,3))
up=cv2.cvtColor(color,cv2.COLOR_BGR2HSV)
Without the cv2 code, I'm guessing about shapes here. But looks like img is a (n,m,3) array. img_list is (m1,3), and clt as list of m1 items, and clt.cluster_centers_ a list of m1 arrays of shape (3,).
For test sake lets make a list of lists (it could just as well be a list of arrays):
ctrs=[[10,10,10], [3,5,3], [20,10,10], [0,0,0]]
color = np.array(ctrs,dtype=np.uint8) # (4,3) array
color = color.reshape(len(ctrs),1,3)
Just wrap it in np.array, and reshape to 3d.
array([[[10, 10, 10]],
[[ 3, 5, 3]],
[[20, 10, 10]],
[[ 0, 0, 0]]], dtype=uint8)
Or it could be reshaped to (1,4,3) or (2,2,3).
Or closer to what you are trying:
np.concatenate([np.array(i,np.uint8).reshape(1,1,3) for i in ctrs])
You don't want to use atleast_3d here since it reshapes a (N,) array to (1,N,1) (see its docs). np.concatenate joins on the 1st axis, where as np.array adds a 1st dimension and then joins.
You probably could get append to work, but it just does a step by step concatenate, which is slower. In general if you need to append, do it with lists, and then convert to an array at the end.
There are various ways of preserving or restoring dimensions after slicing. If color is 3d and you need the i'th row also as 3d:
color[[i]]
color[i].reshape(1,...)
color[i][np.newaxis,...]
Reshaping operations like this do not add significant time to the processing, so don't be afraid to use them.