I have a mat extension data which I want to separate every seconds values. My matrix is (7,5,2500) time series 3 dimensional matrix which want to get the values of (7,5,1) ...(7,5,2500) separately and save it
for example
array([155, 33, 129,167,189,63,35
161, 218, 6,58,36,25,3
89,63,36,25,78,95,21
78,52,36,56,25,15,68
]],
[215, 142, 235,
143, 249, 164],
[221, 71, 229,
56, 91, 120],
[236, 4, 177,
171, 105, 40])
for getting every part of this data for example this matrix
[215, 142, 235,
143, 249, 164]
what should I do?
a = [[155, 33, 129, 161, 218, 6],
[215, 142, 235, 143, 249, 164],
[221, 71, 229, 56, 91, 120],
[236, 4, 177, 171, 105, 40]]
print(a[1])
Assuming you have your data saved in a numpy array you could use slicing to extract the sub-matrices you need. Here is an example with a (3,5,3) matrix (but the example could be applied to any dimension):
A = numpy.array([[[1,1,1],
[2,2,2],
[3,3,3],
[4,4,4],
[5,5,5]],
[[11,11,11],
[21,21,21],
[31,31,31],
[41,41,41],
[51,51,51]],
[[12,12,12],
[22,22,22],
[32,32,32],
[42,42,42],
[52,52,52]]]
sub_matrix_1 = A[:,:,0]
print (sub_matrix_1)
Will produce:
[[ 1 2 3 4 5]
[11 21 31 41 51]
[12 22 32 42 52]]
EDIT: it is also possible to iterate over the array to get the 3rd dimension array:
for i in range(A.shape[-1]):
print (A[:,:,i])
# Your submatrix is A[:,:,i], you can directly manipulate it
Related
I would like to ask a question related to the color detection in an image in Python 3.9. I would like to detect black color at the specific x axis in the image and extract the location of the black area in the image. Could you help me how to extract the location of the black area in an image?
I can load the image and visualize it by the following code.
from PIL import Image
im =Image.open('c97dae05fd9244d4d10305b8066246psXmnlRxU59D0kJ0-0.jpeg')
im.show()
import numpy
imarray = numpy.array(im)
print(imarray)
Image.fromarray(imarray)
Some background context before I give you a solution.
Images are 3D arrays meaning the index 1 for example will be 2 arrays deep so something like this: [[[]]].
For example using numpy you can check the shape of such array using imarray.shape which should return something like (3888, 5184, 3). With this information you can see that there are 3888 arrays that contain 5184 arrays that contain 3 values.
You can maybe see a pattern occur. RGB is red, green, blue (3 values) and the third array is 3 values long which is where you will find your RGB values.
Lets take a image I had in my computer as example. I loaded it using pillow and made it into a numpy array, just like you did.
from Pill import Image
import numpy
im = Image.open('G0626494.jpg')
imarray = numpy.array(im)
Lets now print imarray:
This should print some columns and rows and RGB values, normally some from the beginning, middle and end.
array([[[ 66, 143, 185],
[ 64, 141, 183],
[ 60, 137, 179],
...,
[ 58, 96, 75],
[ 56, 94, 73],
[ 57, 95, 74]],
[[ 65, 142, 184],
[ 63, 140, 182],
[ 60, 137, 179],
...,
[ 57, 95, 74],
[ 56, 94, 73],
[ 57, 95, 74]],
[[ 63, 140, 182],
[ 62, 139, 181],
[ 59, 136, 178],
...,
[ 57, 95, 74],
[ 57, 95, 74],
[ 58, 96, 75]],
...,
[[ 80, 167, 195],
[ 80, 167, 195],
[ 82, 167, 196],
...,
[130, 190, 162],
[129, 189, 161],
[129, 189, 161]],
[[ 82, 169, 197],
[ 81, 168, 196],
[ 83, 168, 197],
...,
[128, 188, 160],
[128, 188, 160],
[128, 188, 160]],
[[ 82, 169, 197],
[ 81, 168, 196],
[ 83, 168, 197],
...,
[127, 187, 159],
[127, 187, 159],
[127, 187, 159]]], dtype=uint8)
As you can see those 3 values on the 3rd array are the RGB values of the image. How do you get them?
Lets take the first pixel as example. If you know basic array manipulation in python you probably will know this but since we know the shape is 3 this means the first pixel will be under imarray[0][0].
If we print this value we indeed get the RGB of the first pixel:
array([ 66, 143, 185], dtype=uint8)
Now how do you cycle through them. I challenge you to try this based on the past knowledge or try along this tutorial.
So if we have 2 arrays to get the RGB of the first pixel we need 2 loops right? So we can do it like this:
for row in imarray:
for column in row:
print(column)
You will now be able to see a bunch of RGB values get printed.
So lets check for black pixels now. We know black is 0, 0, 0 so we can check if any pixel is 0, 0, 0 and print it.
for row in imarray:
for column in row:
if column[0] == 0 and column[1] == 0 and column[2] == 0:
print(column)
You can also check for colors next to black but not 0, 0, 0 if you check if the column values are all the same but less then 50 for example.
This question already has answers here:
Vectorized NumPy linspace for multiple start and stop values
(4 answers)
Closed 5 years ago.
I have a dataset that contains a multidimensional array of shape (2400, 2).
I want to be able to take each of these 2400 rows, and modify them to be a range from the start and end points (the two elements in each of the 2400 rows). The range is always the same length (in my case, a length of 60).
For example, if I have something like this:
array([[ 78, 82],
[ 90, 94],
[ 102, 106]])
My output should be something like this:
array([[ 78, 79, 80, 81, 82],
[ 90, 91, 92, 93, 94],
[ 102, 103, 104, 105, 106]])
The only way I have been able to do this is with a for loop, but I am trying to avoid looping through each row as the dataset can get very large.
Thanks!
Since by necessity all of the aranges need to be equally long, we can create an arange along the first entry and then replicate it for the others.
For example:
x = np.array([[78, 82],
[90, 94],
[102, 106]])
>>> x[:, :1] + np.arange(0, 1 + x[0, 1] - x[0, 0])
# array([[ 78, 79, 80, 81],
# [ 90, 91, 92, 93],
# [102, 103, 104, 105]])
If the difference between the second column and first column is always 4, then you can extract the first column and add an array of [0,1,2,3,4] to it:
arr = np.array([[ 78, 82],
[ 90, 94],
[ 102, 106]])
arr[:,:1] + np.arange(5)
Out[331]:
array([[ 78, 79, 80, 81, 82],
[ 90, 91, 92, 93, 94],
[102, 103, 104, 105, 106]])
I have a list which needs to be split into multiple lists of differing size. The values in the original list randomly increase in size until the split point, where the value drops before continuing to increase. The values must remain in order after being split.
E.g.
Original list
[100, 564, 572, 578, 584, 590, 596, 602, 608, 614, 620, 625, 631, 70, 119,
125, 130, 134, 139, 144, 149, 154, 159, 614, 669, 100, 136, 144, 149, 153,
158, 163, 167, 173, 179, 62, 72, 78, 82, 87, 92, 97, 100, 107, 112, 117,
124, 426, 100, 129, 135, 140, 145, 151]
After split:
[100, 564, 572, 578, 584, 590, 596, 602, 608, 614, 620, 625, 631]
[70, 119, 125, 130, 134, 139, 144, 149, 154, 159, 614, 669]
[100, 136, 144, 149, 153, 158, 163, 167, 173, 179]
[62, 72, 78, 82, 87, 92, 97, 100, 107, 112, 117, 124, 426]
[100, 129, 135, 140, 145, 151]
I have searched for a solution, finding numpy.where and numpy.diff as likely candidates, but I'm unsure how to implement.
Thanks for the help!
Approach #1
Using NumPy's numpy.split to have list of arrays as output -
import numpy as np
arr = np.array(a) # a is input list
out = np.split(arr,np.flatnonzero(arr[1:] < arr[:-1])+1)
Approach #2
Using loop comrehension to split the list directly and thus avoid numpy.split for efficiency purposes -
idx = np.r_[0, np.flatnonzero(np.diff(a)<0)+1, len(a)]
out = [a[idx[i]:idx[i+1]] for i in range(len(idx)-1)]
Output for given sample -
In [52]: idx = np.r_[0, np.flatnonzero(np.diff(a)<0)+1, len(a)]
In [53]: [a[idx[i]:idx[i+1]] for i in range(len(idx)-1)]
Out[53]:
[[100, 564, 572, 578, 584, 590, 596, 602, 608, 614, 620, 625, 631],
[70, 119, 125, 130, 134, 139, 144, 149, 154, 159, 614, 669],
[100, 136, 144, 149, 153, 158, 163, 167, 173, 179],
[62, 72, 78, 82, 87, 92, 97, 100, 107, 112, 117, 124, 426],
[100, 129, 135, 140, 145, 151]]
We are using np.diff here, which feeds in a list in this case and then computes the differentiation. So, a better alternative would be with converting to array and then using comparison between shifted slices of it instead of actually computing the differentiation values. Thus, we could get idx like this as well -
arr = np.asarray(a)
idx = np.r_[0, np.flatnonzero(arr[1:] < arr[:-1])+1, len(arr)]
Let's time it and see if there's any improvement -
In [84]: a = np.random.randint(0,100,(1000,100)).cumsum(1).ravel().tolist()
In [85]: %timeit np.r_[0, np.flatnonzero(np.diff(a)<0)+1, len(a)]
100 loops, best of 3: 3.24 ms per loop
In [86]: arr = np.asarray(a)
In [87]: %timeit np.asarray(a)
100 loops, best of 3: 3.05 ms per loop
In [88]: %timeit np.r_[0, np.flatnonzero(arr[1:] < arr[:-1])+1, len(arr)]
10000 loops, best of 3: 77 µs per loop
In [89]: 3.05+0.077
Out[89]: 3.127
So, a marginal improvement there with the shifting and comparing method with the conversion : np.asarray(a) eating-up most of the runtime.
I know you tagged numpy. But here's a implementation without any dependencies too:
lst = [100, 564, 572, 578, 584, 590, 596, 602, 608, 614, 620, 625, 631, 70, 119,
125, 130, 134, 139, 144, 149, 154, 159, 614, 669, 100, 136, 144, 149, 153,
158, 163, 167, 173, 179, 62, 72, 78, 82, 87, 92, 97, 100, 107, 112, 117,
124, 426, 100, 129, 135, 140, 145, 151]
def split(lst):
last_pos = 0
for i in range(1, len(lst)):
if lst[i] < lst[i-1]:
yield lst[last_pos:i]
last_pos = i
if(last_pos <= len(lst)-1):
yield lst[last_pos:]
print([x for x in split(lst)])
If you want to use numpy.diff and numpy.where, you can try
a = numpy.array(your original list)
numpy.split(a, numpy.where(numpy.diff(a) < 0)[0] + 1)
Explanation:
numpy.diff(a) calculates the difference of each item and its preceding one, and returns an array.
numpy.diff(a) < 0 returns a boolean array, where each element is replaced by whether it satisfies the predicate, in this case less than zero. This is the result of numpy.ndarray overloading the comparison operators.
numpy.where takes this boolean array and returns the indices where the element is not zero. In this context False evaluates to zero, so you take the indices of True.
[0] takes the first (and only) axis
+ 1 You want to break off from after the indices, not before
Finally, numpy.split breaks them off at the given indices.
Suppose I have an array like this:
a = array([[[ 29, 29, 27],
[ 36, 38, 40],
[ 86, 88, 89]],
[[200, 200, 198],
[199, 199, 197]
[194, 194, 194]]])
and I want to flip the 3rd element from left to right in the list-of-lists so it will become like this:
b = array([[[ 29, 29, 89], # 27 became 89
[ 36, 38, 40],
[ 86, 88, 27]], # 89 became 27
[[200, 200, 194], # 198 became 194
[199, 199, 197],
[194, 194, 198]]]) # 194 became 198
I looked up the NumPy manual but I still cannot figure out a solution. .flip and .fliplr look suitable in this case, but how do I use them?
Index the array to select the sub-array, using:
> a[:,:,-1]
array([[198, 197, 194],
[ 27, 40, 89]])
This selects the last element along the 3rd dimension of a. The sub-array is of shape (2,3). Then reverse the selection using:
a[:,:,-1][:,::-1]
The second slice, [:,::-1], takes everything along the first dimension as-is ([:]), and all of the elements along the second dimension, but reversed ([::-1]). The slice syntax is basically saying start at the first element, go the last element ([:]), but do it in the reverse order ([::-1]). You could pseudo-code write it as [start here : end here : use this step size]. The the -1 tells it walk backwards.
And assign it to the first slice of the original array. This updates/overwrites the original value of a
a[:,:,-1] = a[:,:,-1][:,::-1]
> a
array([[[ 29, 29, 89],
[ 36, 38, 40],
[ 86, 88, 27]],
[[200, 200, 194],
[199, 199, 197],
[194, 194, 198]]])
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 6 years ago.
Improve this question
I have a numpy array - from an image - in this shape:
Arr =
array([[[ 61, 61, 61],
[ 60, 60, 60],
[ 60, 60, 60],
...,
[203, 203, 203],
[201, 201, 201],
[199, 199, 199]],
.
.
.
[[204, 204, 204],
[204, 204, 204],
[204, 204, 204],
...,
[205, 205, 205],
[206, 206, 206],
[207, 207, 207]]], dtype=uint8)
I want to work with this array in "tuples" of varying length e.g. 5 (and not just the current 3):
array([[[ 61, 61, 61, 60, 60],
[ 60, 60, 60, 60, 60],
.
.
.
Function tuple() seem to be for lists and in any case it does not offer the option to determine the length of a group of pixels. I have also tried using zip(), thus:
newArr = zip(*[Arr[i::n] for i in range(n)]). For n=5, it gives:
newArr =
[(array([[ 61, 61, 61],
[ 60, 60, 60],
[ 60, 60, 60],
...,
[203, 203, 203],
[201, 201, 201],
[199, 199, 199]], dtype=uint8), array([[ 63, 63, 63],
[ 62, 62, 62],
[ 62, 62, 62],
.
.
.
[207, 207, 207],
[209, 209, 209],
[210, 210, 210]], dtype=uint8), array([[204, 204, 204],
[204, 204, 204],
[205, 205, 205],
...,
[206, 206, 206],
[207, 207, 207],
[208, 208, 208]], dtype=uint8))]
Any way out of this? Here is the image:
The reason the values are grouped in threes is because those are the values of the color channels, either RGB, HSV or whatever the format is. Each pixel has three values, that is why you cant group them any other way. You could convert the image to grayscale with:
from PIL import Image
import numpy as np
img = Image.open('imagename')
img2 = img.convert('L')
img2_array = np.asarray(img2).copy()
That will change the value of each pixel to a single integer (0-255) and leave you with an array with the dimensions of the image itself.
EDIT:
To segment the image into five pixel groups:
seg = 5
img2_array = img2_array.tolist()
img_grouped = np.array([img2_array[0][x:x+seg] for x in range(0,len(img2_array),seg)])