I want to change elements to be [0,0,0] if the pixel at that color is blue. The code below works, but is extremely slow:
for row in range(w):
for col in range(h):
if np.array_equal(image[row][col], [255,0,0]):
image[row][col] = (0,0,0)
else:
image[row][col] = (255,255,255)
I know np.where works for single dimensional arrays, but how can I use that function to replace stuff for a 3 dimensional object?
Since you brought up numpy.where, this is how you'd do it using nupmy.where:
import numpy as np
# Make an example image
image = np.random.randint(0, 255, (10, 10, 3))
image[2, 2, :] = [255, 0, 0]
# Define the color you're looking for
pattern = np.array([255, 0, 0])
# Make a mask to use with where
mask = (image == pattern).all(axis=2)
newshape = mask.shape + (1,)
mask = mask.reshape(newshape)
# Finish it off
image = np.where(mask, [0, 0, 0], [255, 255, 255])
The reshape is in there so that numpy will apply broadcasting, more here also.
The simplest thing you could do is just multiply the element you want to set to a zero array by zero. An example of this array property for a three dimensional array is shown below.
x = array([ [ [ 1,2,3 ] , [ 2 , 3 , 4 ] ] , [ [ 1, 2, 3, ] , [ 2 , 3 , 4 ] ] , [ [ 1,2,3 ] , [ 2 , 3 , 4 ] ] , [ [ 1, 2, 3, ] , [ 2 , 3 , 4 ] ] ])
print x
if 1:
x[0] = x[0] * 0
print x
This will yield two printouts:
[[[1 2 3]
[2 3 4]]
[[1 2 3]
[2 3 4]]...
and
[[[0 0 0]
[0 0 0]]
[[1 2 3]
[2 3 4]]...
This method will work for both image[row], and image[row][column] in your example. Your example reworked would look like:
for row in range(w):
for col in range(h):
if np.array_equal(image[row][col], [255,0,0]):
image[row][col] = 0
else:
image[row][col] = 255
Related
So I have a 2d array
X = [[ 7.3571296 0.49626 ]
[-0.7747436 3.14599 ]
[ 3.7817762 4.1808457 ]
[ 4.5332413 6.8228664 ]
[ 7.4655724 -0.11392868]
[ 2.416418 4.692072 ]]
and a cluster label array.
y = [1 3 2 2 1 3]
Then I have an algorithm that can predict the label of the 2d array.
Z = {1: array([[ 7.3571296 0.49626 ],
[ 7.4655724 -0.11392868]]),
2: array([[ 3.7817762 4.1808457 ]
[ 2.416418 4.692072 ]]),
3: array([[-0.7747436 3.14599 ],
[ 4.5332413 6.8228664 ]])}
I want to match my predicted label with original label to know my algorithm's accuracy. But how can I extract the dictionary format into label array format? (i.e. y_pred = [1 3 2 3 1 2])
You can use the keys() method of the dictionary and cast it to list.
import numpy as np
Z = {1: np.asarray([[7.3571296, 0.49626], [7.4655724, 0.11392868]]),
2: np.asarray([[3.7817762, 4.1808457], [2.416418, 4.692072]]),
3: np.asarray([[-0.7747436, 3.14599], [4.5332413, 6.8228664]])}
print(list(Z.keys())) #[1, 2, 3]
I have an image saved as numpy array of shape [Height, Width, 3] and I want to replace every pixel with another value based on the color of pixel, so the final array will have a shape [Height, Weight].
My solution with for loop works but it's pretty slow. How can I use Numpy vectorization to make it more efficient?
image = cv2.imread("myimage.png")
result = np.zeros(shape=(image.shape[0], image.shape[1],))
for h in range(0, result.shape[0]):
for w in range(0, result.shape[1]):
result[h, w] = get_new_value(image[h, w])
Here is get_new_value function:
def get_new_value(array: np.ndarray) -> int:
mapping = {
(0, 0, 0): 0,
(0, 0, 255): 5,
(0, 100, 200): 8,
# ...
}
return mapping[tuple(array)]
you can use np.select() as shown below:
img=np.array(
[[[123 123 123]
[130 130 130]]
[[129 128 128]
[162 162 162]]])
condlist = [img==[123,123,123], img==[130, 130, 130], img==[129, 129, 129], img==[162, 162, 162]]
choicelist = [0, 5, 8, 9]
img_replaced = np.select(condlist, choicelist)
final = img_replaced[:, :, 0]
print('img_replaced')
print(img_replaced)
print('final')
print(final)
condlist is your list of colour values and choicelist is the list of replacements.
np.select then returns three channels and you just need to take one channel from that to give the array 'final' which is the format you want I believe
output is:
img_replaced
[[[0 0 0]
[5 5 5]]
[[0 0 0]
[9 9 9]]]
final
[[0 5]
[0 9]]
so code specific to your example and shown colour mappings would be:
image = cv2.imread("myimage.png")
condlist = [image==[0, 0, 0], image==[0, 0, 255], image==[0, 100, 200]]
choicelist = [0, 5, 8]
img_replaced = np.select(condlist, choicelist)
result = img_replaced[:, :, 0]
Here is a 3-dimensional numpy array:
import numpy as np
m = np.array([
[
[1,2,3,2], [4,5,6,3]
],
[
[7,8,9,4], [1,2,3,5]
]
])
For each tuple, I need to multiply the first three values by the last one (divided by 10 and rounded), and then to keep only the 3 results. For example in [1,2,3,2]:
The 1 becomes: round(1 * 2 / 10) = 0
The 2 becomes: round(2 * 2 / 10) = 0
The 3 becomes: round(3 * 2 / 10) = 1
So, [1,2,3,2] becomes: [0,0,1].
And the complete result will be:
[
[
[0,0,1], [1,2,2]
],
[
[3,3,4], [1,1,2]
]
]
I tried to separate the last value of each tuple in a alpha variable, and the 3 first values in a rgb variable.
alpha = m[:, :, 3] / 10
rgb = m[:, :, :3]
But after that I'm a beginner in Python and I really don't know how to process these arrays.
A little help from an experienced Python-guy will be most welcome.
Try this
n = np.rint(m[:,:,:3] * m[:,:,[-1]] / 10).astype(int)
Out[192]:
array([[[0, 0, 1],
[1, 2, 2]],
[[3, 3, 4],
[0, 1, 2]]])
how can I combine a binary mask image array (this_mask - shape:4,4) with a predefined color array (mask_color, shape:3)
this_mask = np.array([
[0,1,0,0],
[0,0,0,0],
[0,0,0,0],
[0,0,0,0],
])
this_mask.shape # (4,4)
mask_color = np.array([128, 128, 64])
mask_color.shape # (3)
to get a new color mask image array (this_mask_colored, shape:4,4,3)?
this_mask_colored = # do something with `this_mask` and `mask_color`
# [
# [
# [0,128,0],
# [0,0,0],
# [0,0,0],
# [0,0,0]
# ],
# [
# [0,128,0],
# [0,0,0],
# [0,0,0],
# [0,0,0]
# ],
# [
# [0,64,0],
# [0,0,0],
# [0,0,0],
# [0,0,0]
# ],
# ]
this_mask_colored.shape # (4,4,3)
I tried for loop through pixel by pixel, is it slow when when image is 225x225, what is best way to do this?
For each image, I have multiple layers of mask, and each mask layer needs to have a different predefine color.
This might work:
this_mask = np.array([
[0,1,0,0],
[0,0,0,0],
[0,0,0,0],
[0,0,0,0],
])
mask_color = np.array([128, 128, 64])
res = []
for row in new:
tmp = []
for col in row:
tmp.append(np.array([1,1,1]) * col)
res.append(np.array(tmp))
res = res * mask_color
For each entry, 1 will be converted to [1, 1, 1] and 0 is [0, 0, 0]
I do this because I want to use the benefit of the operation * (element-wise multiplication)
This works:
test = np.array([[0, 0, 0],
[1, 1, 1],
[0, 0, 0],
[0, 0, 0]])
test * np.array([128, 128, 64])
We'll get
array([[ 0, 0, 0],
[128, 128, 64],
[ 0, 0, 0],
[ 0, 0, 0]])
And we want to put all the calculation to the numpy's side. So we loop through the array just for conversion and the rest is for numpy.
This takes 0.2 secs for 255x255 of 1 with one mask_color and 2 secs for 1000x1000
The following function should do what you want.
def apply_mask_color(mask, mask_color):
return np.concatenate(([mask[ ... , np.newaxis] * color for color in mask_color]), axis=2)
Given the following code:
this_mask = np.array([
[0,1,0,0],
[0,0,0,0],
[0,0,0,0],
[0,0,0,0],
])
mask_color = np.array([128, 128, 64])
applied = apply_mask_color(this_mask, mask_color)
print(applied.shape) #(4, 4, 3)
It is important to note that the output isn't QUITE what you expected. Rather, every element inside is now a 3 dimensional array housing the R G B values detailed in mask_color
print(applied)
Output:
[[[ 0 0 0]
[128 128 64]
[ 0 0 0]
[ 0 0 0]]
[[ 0 0 0]
[ 0 0 0]
[ 0 0 0]
[ 0 0 0]]
[[ 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 think is is more what you're looking for.
I want to do some forces calculations between vertices and because the forces are symmetrical I have a list of vertice-pairs that need those forces added. I am sure it's possible with fancy indexing, but I really just can get it to work with a slow python for-loop. for symmetric reasons, the right-hand side of the index array needs a negative sign when adding the forces.
consider you have the vertice index array:
>>> I = np.array([[0,1],[1,2],[2,0]])
I = [[0 1]
[1 2]
[2 0]]
and the x,y forces array for each pair:
>>> F = np.array([[3,6],[4,7],[5,8]])
F = [[3 6]
[4 7]
[5 8]]
the wanted operation could be described as:
"vertice #0 sums the force vectors (3,6) and (-5,-8),
vertice #1 sums the force vectors (-3,-6) and (4,7),
vertice #2 sums the force vectors (-4,-7) and (5,8)"
Desired results:
[ 3 6 ] [ 0 0 ] [-5 -8 ] [-2 -2 ] //resulting force Vertice #0
A = [-3 -6 ] + [ 4 7 ] + [ 0 0 ] = [ 1 1 ] //resulting force Vertice #1
[ 0 0 ] [-4 -7 ] [ 5 8 ] [ 1 1 ] //resulting force Vertice #2
edit:
my ugly for-loop solution:
import numpy as np
I = np.array([[0,1],[1,2],[2,0]])
F = np.array([[3,6],[4,7],[5,8]])
A = np.zeros((3,2))
A_x = np.zeros((3,2))
A_y = np.zeros((3,2))
for row in range(0,len(F)):
A_x[I[row][0],0]= F[row][0]
A_x[I[row][1],1]= -F[row][0]
A_y[I[row][0],0]= F[row][1]
A_y[I[row][1],1]= -F[row][1]
A = np.hstack((np.sum(A_x,axis=1).reshape((3,1)),np.sum(A_y,axis=1).reshape((3,1))))
print(A)
A= [[-2. -2.]
[ 1. 1.]
[ 1. 1.]]
Your current "push-style" interpretation of I is
For row-index k in I, take the forces from F[k] and add/subtract them to out[I[k], :]
I = np.array([[0,1],[1,2],[2,0]])
out = numpy.zeros_like(F)
for k, d in enumerate(I):
out[d[0], :] += F[k]
out[d[1], :] -= F[k]
out
# array([[-2, -2],
# [ 1, 1],
# [ 1, 1]])
However you can also change the meaning of I on its head and make it "pull-style", so it says
For row-index k in I, set vertex out[k] to be the difference of F[I[k]]
I = np.array([[0,2],[1,0],[2,1]])
out = numpy.zeros_like(F)
for k, d in enumerate(I):
out[k, :] = F[d[0], :] - F[d[1], :]
out
# array([[-2, -2],
# [ 1, 1],
# [ 1, 1]])
In which case the operation simplifies quite easily to mere fancy indexing:
out = F[I[:, 0], :] - F[I[:, 1], :]
# array([[-2, -2],
# [ 1, 1],
# [ 1, 1]])
You can preallocate an array to hold the shuffled forces and then use the index like so:
>>> N = I.max() + 1
>>> out = np.zeros((N, 2, 2), F.dtype)
>>> out[I, [1, 0]] = F[:, None, :]
>>> np.diff(out, axis=1).squeeze()
array([[-2, -2],
[ 1, 1],
[ 1, 1]])
or, equivalently,
>>> out = np.zeros((2, N, 2), F.dtype)
>>> out[[[1], [0]], I.T] = F
>>> np.diff(out, axis=0).squeeze()
array([[-2, -2],
[ 1, 1],
[ 1, 1]])
The way I understand the question, the values in the I array represent the vortex number, or the name of the vortex. They are not an actual positional index. Based on this thought, I have a different solution that uses the original I array. It does not quite come without loops, but should be OK for a reasonable number of vertices:
I = np.array([[0,1],[1,2],[2,0]])
F = np.array([[3,6],[4,7],[5,8]])
pos = I[:, 0]
neg = I[:, 1]
A = np.zeros_like(F)
unique = np.unique(I)
for i, vortex_number in enumerate(unique):
A[i] = F[np.where(pos==vortex_number)] - F[np.where(neg==vortex_number)]
# produces the expected result
# [[-2 -2]
# [ 1 1]
# [ 1 1]]
Maybe this loop can also be replaced by some numpy magic.