Add co-ordinates to each pixel in python - python

I am trying to add coordinates to each pixel of an image for this I am doing the following
import cv2
import numpy as np
img = cv2.imread('images/0001.jpg')
grayscale = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
np_grayscale = np.array(grayscale)
# make the array 3d
processed_image = np_grayscale[:, :, np.newaxis]
x = 0
y = 0
for pixel_line in reversed(processed_image):
for pixel in pixel_line:
pixel = np.append(pixel, [x, y])
x += 1
y += 1
print(processed_image)
But this does not seem to work because I am still getting the original array that is in the form
[[[255]
[255]
[255]
...
[255]
[255]
[255]]
...
...
...
[255]
[255]
[255]]]
Moreover I don't think this is the most efficient way of doing this because I read that append creates a new copy of the array, can someone please help

You can create a mesh of indices using meshgrid() and stack() them with the original image:
import numpy as np
x = np.asarray([
[0, 0, 0, 0],
[0, 0, 0, 0],
[0, 255, 0, 0],
[0, 0, 0, 0],
])
indices = np.meshgrid(
np.arange(x.shape[0]),
np.arange(x.shape[1]),
sparse=False
)
x = np.stack((x, *indices)).T
# array([[[ 0, 0, 0],
# [ 0, 0, 1],
# [ 0, 0, 2],
# [ 0, 0, 3]],
# [[ 0, 1, 0],
# [ 0, 1, 1],
# [255, 1, 2],
# [ 0, 1, 3]],
# [[ 0, 2, 0],
# [ 0, 2, 1],
# [ 0, 2, 2],
# [ 0, 2, 3]],
# [[ 0, 3, 0],
# [ 0, 3, 1],
# [ 0, 3, 2],
# [ 0, 3, 3]]])
x[0, 0, :] # 0, 0, 0
x[1, 2, :] # 255, 1, 2
x[-1, -1, :] # 0, 3, 3

Use xarray.
The easiest way, by far, to add coordinates to a NumPy array is with an xarray.DataArray. For example, here's how you can add coordinates that are just row and column index:
import xarray as xr
data = np.arange(25).reshape(5, 5)
rows, cols = data.shape
xs = np.arange(cols)
ys = np.arange(rows)
da = xr.DataArray(data, name="mydata", coords=[ys, xs], dims=['y', 'x'])
This da thing is a DataArray, which is essentially an indexed array ('indexed' in a pandas sense: the indices can be integers, floats, dates, etc). It has some nice features (try da.plot()). Otherwise, it basically behaves like a NumPy array. For example, you can slice it like a normal array:
>>> da[:, 3:]
<xarray.DataArray 'mydata' (y: 5, x: 2)>
array([[ 3, 4],
[ 8, 9],
[13, 14],
[18, 19],
[23, 24]])
Coordinates:
* y (y) int64 0 1 2 3 4
* x (x) int64 3 4
As you can see, this subarray 'knows' its own coordinates. What's more, you can have as many dimensions as you want, and each axis can have multiple coordinates. It's very useful.
As others pointed out, you can probably achieve what you want with careful indexing alone, but if you really want coordinates this is how I'd do it.

As you have a grayscale image, you can convert it to the 3-channeled image in which the first channel will contain the pixel values, and the other 2 channels will contain the coordinates. So, if you split your image into two or more, you will still have the coordinates of the original image in the other two channels, and also to visualize the image, you can simply use only the first channel. Here's how you can do this.
processed_image = np.zeros((grayscale.shape[0], grayscale.shape[1], 3), dtype=np.uint64)
processed_image[:, :, 0] = np.asarray(grayscale, dtype=np.uint64)
for i in range(processed_image.shape[0]):
for j in range(processed_image.shape[1]):
processed_image[i][j][1] = i
processed_image[i][j][2] = j
print(processed_image)
# Displaying the image
cv2.imshow("img", np.array(processed_image[:, :, [0]], dtype=np.uint8))
cv2.waitKey(0)
Note: Take care of the datatypes of the numpy arrays. You cannot store the coordinates of the complete image in the np.uint8 array as it will only contain values from 0-255. Also, while displaying, you'll have to convert the first channel back to the np.uint8 datatype as OpenCV only understands images in this format (for integer pixel values). That is why I have used an array of np.uint64 datatype to store pixel values.

Related

How to do a kernel with horizontal stripes fast

I wanna do a kernel of zeros and ones. I have a list with pairs of heights (e.g. [[191.0, 243.0], [578.0, 632.0]]. What I want to do is set ones in the kernel on those rows with height between the values of a pair of heights.
Example image about what I want to do (in this case 2 pairs, the values above):
enter image description here
My method makes a double loop but takes minutes to execute. Is there any faster way to do this? Here is the code:
mascara = numpy.zeros((height, width),numpy.uint8)
#print(mascara)
for i in range(height):
for j in range(width): #For each element of the kernel (kernel=mascara)
indice_parejas = 0
while indice_parejas < numero_de_parejas: #indice_parejas: index that indicates the pair we are checking
#print(i,j) #numero_de_parejas: how many pairs we have
if i > vector_mascara[indice_parejas][0] and i < vector_mascara[indice_parejas][1]: #If it is between a pair
mascara[i][j] = 1
break #we don't have to check the others pairs because we know it is in this pair (get out of the loop)
else:
indice_parejas = indice_parejas + 1
IIUC, it is quite simple:
for h0, h1 in hpairs:
mask[h0:h1, :] = 1
Reproducible example
w, h = 8, 4
mask = np.zeros((w, h), dtype=np.uint8)
hpairs = [
[1,3],
[5,6],
]
for h0, h1 in hpairs:
mask[h0:h1, :] = 1
>>> mask
array([[0, 0, 0, 0],
[1, 1, 1, 1],
[1, 1, 1, 1],
[0, 0, 0, 0],
[0, 0, 0, 0],
[1, 1, 1, 1],
[0, 0, 0, 0],
[0, 0, 0, 0]], dtype=uint8)

Is it possible to mask tensor pixels in graph mode using a 2D array?

I want to mask an array of pixels with an array of ones and zeros.
I'm using Keras in graph mode, so only using operations that can be performed on tensors.
Most symbolic operators seem to work in graph mode, and there is a subset of numpy operations in keras.backend. But there is no support for no iterating or enumerating.
So for example I have:
arr = [[(1,2,3),(2,3,4),(4,5,6)],[(5,6,7),(6,7,8),(7,8,9)]]
mask = [[1, 0, 1],[0, 0, 1]]
# and I want
arr * mask == [[(1,2,3),(0,0,0),(4,5,6)],[(0,0,0),(0,0,0),(7,8,9)]]
The actual arrays are images, so much bigger than this example.
Is there a reasonable way to mask points like this?
From the code your provide, one of easiest way to do is using broadcasting, like #user1318499 mentioned in the comments. Since mask is in shape of (2,3), and arr is in shape of (2,3,3), mask can be expanded one dim to do broadcast with arr.
import tensorflow as tf
arr = tf.reshape(tf.range(2*3*3), [2,3,3])
# array([[[ 0, 1, 2],
# [ 3, 4, 5],
# [ 6, 7, 8]],
# [[ 9, 10, 11],
# [12, 13, 14],
# [15, 16, 17]]], dtype=int32)
mask = tf.constant([[1, 0, 1],[0, 0, 1]])
res = arr * tf.expand_dims(mask, axis=-1)
# array([[[ 0, 1, 2],
# [ 0, 0, 0],
# [ 6, 7, 8]],
# [[ 0, 0, 0],
# [ 0, 0, 0],
# [15, 16, 17]]], dtype=int32)

Efficient way to substitute repeating np.vstack in python?

I am trying to implement this post in python.
import numpy as np
x = np.array([0,0,0])
for r in range(3):
x = np.vstack((x, np.array([-r, r, -r])))
x gets this value
array([[ 0, 0, 0],
[ 0, 0, 0],
[-1, 1, -1],
[-2, 2, -2]])
I am concerned the runtime efficiency about the repeating np.vstack. Is there a more efficient way to do this?
Build a list of arrays or lists, and apply np.array (or vstack) to that once:
In [598]: np.array([[-r,r,-r] for r in [0,0,1,2]])
Out[598]:
array([[ 0, 0, 0],
[ 0, 0, 0],
[-1, 1, -1],
[-2, 2, -2]])
But if the column pattern is consistent, broadcasting two arrays against each other will be faster
In [599]: np.array([-1,1,-1])*np.array([0,0,1,2])[:,None]
Out[599]:
array([[ 0, 0, 0],
[ 0, 0, 0],
[-1, 1, -1],
[-2, 2, -2]])
Would it be useful to use numpy.tile?
N = 3
A = np.array([[0, *range(0, -N, -1)]]).T
B = np.tile(A, (1, N))
B[:,1] = -B[:,1]
The first line sets the expected number of rows after the first row of zeroes. The second creates a NumPy array by creating an initial value of 0, followed by the linear sequence of 0, -1, -2, up to -N + 1. Note the use of the splat operator which unpacks the range object and creates elements in an individual list. These are concatenated with the first value of 0, and we create a 2D NumPy array that is a column vector. The third line tiles this vector N times horizontally to get the desired output. Finally the fourth line negates the second column to get your desired output
Example Run
In [175]: N = 3
In [176]: A = np.array([[0, *range(0, -N, -1)]]).T
In [177]: B = np.tile(A, (1, N))
In [178]: B[:,1] = -B[:,1]
In [178]: B
Out[178]:
array([[ 0, 0, 0],
[ 0, 0, 0],
[-1, 1, -1],
[-2, 2, -2]])
You can use np.block as following:
First create a block which you are currently doing inside the for loop
Finally, vertically stack a row of zeros using np.vstack to get the final desired answer
import numpy as np
size = 3
sign = np.ones(3)*((-1)**np.arange(1, size+1)) # General sign array of repeating -1, 1
A = np.ones((size, size), int)
B = np.arange(0, size) * A
B = sign * np.block([B.T])
# array([[ 0, 0, 0],
# [ -1, 1, -1],
# [ -2, 2, -2]])
answer = np.vstack([B[0], B])
# array([[ 0, 0, 0],
# [ 0, 0, 0],
# [ -1, 1, -1],
# [ -2, 2, -2]])

Zero pad ndarray along axis

I want to pad:
[[1, 2]
[3, 4]]
to
[[0, 0, 0]
[0, 1, 2]
[0, 3, 4]]
I have no problem in doing so when input is 2D by vstack & hsrack
However, when I add 1 dim to represent the dim of number, such as:
img = np.random.randint(-10, 10, size=(2, 2, 2))
I cannot do so if I would not like to use for loop.
Is there any way to avoid for but only numpy's stack to make it?
ps: for this example I should get (2,3,3) array by each 2 img instance is pad by zero at 1st column & 1st row.
Thanks
You can use np.pad, which allows you to specify the number of values padded to the edges of each axis.
So for the first example 2D array you could do:
a = np.array([[1, 2],[3, 4]])
np.pad(a,((1, 0), (1, 0)), mode = 'constant')
array([[0, 0, 0],
[0, 1, 2],
[0, 3, 4]])
So here each tuple is representing the side which to pad with zeros along each axis, i.e. ((before_1, after_1), … (before_N, after_N)).
And for a 3D array the same applies, but in this case we must specify that we only want to zero pad the two last dimensions:
img = np.random.randint(-10, 10, size=(2, 2, 2))
np.pad(img, ((0,0), (1,0), (1,0)), 'constant')
array([[[ 0, 0, 0],
[ 0, -3, -2],
[ 0, 9, -5]],
[[ 0, 0, 0],
[ 0, 1, -9],
[ 0, -1, -3]]])
You can use np.pad and remove the last row/column:
import numpy as np
a = np.array([[1, 2], [3, 4]])
result = np.pad(a, 1, mode='constant', constant_values=0)[:-1, :-1]
print(result)
Output:
[[0 0 0]
[0 1 2]
[0 3 4]]
If you want to pad only the column
import numpy as np
max_length =20
a = np.random.randint(1,size=(1, 10))
print(a.shape)
print(a.shape[1])
a =np.pad(a, [(0, 0), (0, max_length - a.shape[1])], mode='constant')
print(a.shape)
Output
(1, 10)
10
(1, 20)

Elements arrangement in a numpy array

import numpy as np
data = np.array([[0, 0, 1, 1, 2, 2],
[1, 0, 0, 1, 2, 2],
[1, 0, 1, 0, 0, 0],
[1, 1, 0, 0, 2, 0]])
How can I do the followings?
Within 2 by 2 patch:
if any element is 2: put 2
if any element is 1: put 1
if all elements are 0: put 0
The expected result is:
np.array([[1, 1, 2],
[1, 1, 2]])
Using extract_patches from scikit-learn you can write this as follows (copy and paste-able code):
import numpy as np
from sklearn.feature_extraction.image import extract_patches
data = np.array([[0, 0, 1, 1, 2, 2],
[1, 0, 0, 1, 2, 2],
[1, 0, 1, 0, 0, 0],
[1, 1, 0, 0, 2, 0]])
patches = extract_patches(data, patch_shape=(2, 2), extraction_step=(2, 2))
output = patches.max(axis=-1).max(axis=-1)
Explanation: extract_patches gives you a view on patches of your array, of size patch_shape and lying on a grid of extraction_step. The result is a 4D array where the first two axes index the patch and the last two axes index the pixels within the patch. We then evaluate the maximum over the last two axes to obtain the maximum per patch.
EDIT This is actually very much related to this question
I'm not sure where you get your input from or where you are supposed to leave the output, but you can adapt this.
import numpy as np
data = np.array([[0, 0, 1, 1, 2, 2],
[1, 0, 0, 1, 2, 2],
[1, 0, 1, 0, 0, 0],
[1, 1, 0, 0, 2, 0]])
def patchValue(i,j):
return max([data[i][j],
data[i][j+1],
data[i+1][j],
data[i+1][j+1]])
result = np.array([[0, 0, 0],
[0, 0, 0]])
for (v,i) in enumerate(range(0,4,2)):
for (w,j) in enumerate(range(0,6,2)):
result[v][w] = patchValue(i,j)
print(result)
Here's a rather lengthy one-liner that relies solely on reshaping, transposes, and taking maximums along different axes. It is fairly fast too.
data.reshape((-1,2)).max(axis=1).reshape((data.shape[0],-1)).T.reshape((-1,2)).max(axis=1).reshape((data.shape[1]/2,data.shape[0]/2)).T
Essentially what this does is reshape to take the maximum in pairs of two horizontally, then shuffle things around again and take the maximum in pairs of two vertically, ultimately giving the maximum of each block of 4, matching your desired output.
If the original array is large, and performance is an issue, the loops can be pushed down to numpy C code by manipulating the shape and strides of the original array to create the windows that you are acting on:
import numpy as np
from numpy.lib.stride_tricks import as_strided
data = np.array([[0, 0, 1, 1, 2, 2],
[1, 0, 0, 1, 2, 2],
[1, 0, 1, 0, 0, 0],
[1, 1, 0, 0, 2, 0]])
patch_shape = (2,2)
data_shape = np.array(data.shape)
# transform data to a 2x3 array of 2x2 patches/windows
# final shape of the computation on the windows can be calculated with:
# tuple(((data_shape-patch_shape) // patch_shape) + 1)
final_shape = (2,3)
# the shape of the windowed array can be calculated with:
# final_shape + patch_shape
newshape = (2, 3, 2, 2)
# the strides of the windowed array can be calculated with:
# tuple(np.array(data.strides) * patch_shape) + data.strides
newstrides = (48, 8, 24, 4)
# use as_strided to 'transform' the array
patch_array = as_strided(data, shape = newshape, strides = newstrides)
# flatten the windowed array for iteration - dim of 6x2x2
# the number of windows is the product of the 'first' dimensions of the array
# which can be calculated with:
# (np.product(newshape[:-len(patch_shape)])) + (newshape[-len(patch_array):])
dim = (6,2,2)
patch_array = patch_array.reshape(dim)
# perfom computations on the windows and reshape to final dimensions
result = [2 if np.any(patch == 2) else
1 if np.any(patch == 1) else
0 for patch in patch_array]
result = np.array(result).reshape(final_shape)
A generalized 1-d function for creating the windowed array can be found at Efficient rolling statistics with NumPy
A generalised multi-dimension function and a nice explanation can be found at Efficient Overlapping Windows with Numpy

Categories