Make an array like numpy.array() without numpy - python

I've an image processing task and we're prohibited to use NumPy so we need to code from scratch. I've done the logic image transformation but now I'm stuck on creating an array without numpy.
So here's my last output code :
Output :
new_log =
[[236,
232,
226,
.
.
.
198,
204]]
I need to convert this to an array so I can write the image like this (with Numpy)
new_log =
array([[236, 232, 226, ..., 208, 209, 212],
[202, 197, 187, ..., 198, 200, 203],
[192, 188, 180, ..., 205, 206, 207],
...,
[233, 226, 227, ..., 172, 189, 199],
[235, 233, 228, ..., 175, 182, 192],
[235, 232, 228, ..., 195, 198, 204]], dtype=uint8)
cv.imwrite('log_transformed.jpg', new_log)
# new_log must be shaped like the second output

You can make a straightforward function to take your list and reshape it in a similar way to NumPy's np.reshape(). But it's not going to be fast, and it doesn't know anything about data types (NumPy's dtype) so... my advice is to challenge whoever it is that doesn't like NumPy. Especially if you're using OpenCV — it depends on NumPy!
Here's an example of what you could do in pure Python:
def reshape(l, shape):
"""Reshape a list.
Example
-------
>>> l = [1,2,3,4,5,6,7,8,9]
>>> reshape(l, shape=(3, -1))
[[1, 2, 3], [4, 5, 6], [7, 8, 9]]
"""
nrows, ncols = shape
if ncols == -1:
ncols = len(l) // nrows
if nrows == -1:
nrows = len(l) // ncols
array = []
for r in range(nrows):
row = []
for c in range(ncols):
row.append(l[ncols*r + c])
array.append(row)
return array

Related

Image-processing convolution kernels are calculated dynamically

Using standard numpy and cv2.filter2D solutions I can apply static convolutions to an image:
import numpy as np
convolution_kernel = np.array([[-2, -1, 0],
[-1, 1, 1],
[0, 1, 2]])
import cv2
image = cv2.imread('1.png') result = cv2.filter2D(image, -1, convolution_kernel)
(example from https://stackoverflow.com/a/58383803/3310334)
Every pixel at [i, j] in the output image has a value calculated by centering a 3x3 "window" onto [i, j] in the input image, and then multiplying each value in the window by the corresponding value in the convolution kernel (Hadamard product) and finally summing the 9 products to get the value for [i, j] in the output image (for each color channel).
(image from: https://github.com/ashushekar/image-convolution-from-scratch#convolution)
In my case, the function to perform to calculate for each output pixel is not as simple as sum of Hadamard product. It is for each pixel calculated from operations performed on known-size windows into two input matrices centered around that pixel.
I have two input matrixes ("images"), like
A = [[179, 97, 77, 118, 144, 105],
[ 68, 56, 184, 210, 141, 230],
[178, 166, 218, 47, 106, 172],
[ 38, 183, 50, 185, 48, 87],
[ 60, 200, 228, 232, 6, 190],
[253, 75, 231, 166, 117, 134]]
B = [[116, 95, 94, 220, 80, 223],
[135, 9, 166, 78, 5, 129],
[102, 167, 120, 81, 141, 29],
[ 83, 117, 81, 129, 255, 48],
[130, 231, 165, 7, 187, 169],
[ 44, 137, 16, 50, 229, 202]]
And in the output matrix, each [i, j] pixel should be calculated as the sum of all of A[u,v] ** 2 - B[u,v] ** 2 values for [u, v] coordinates within 3x3 "windows" onto the two (same-sized) input matrixes.
How can I calculate this output matrix quickly in Python?
Using numpy, it seems to be the 3x3 sums of A * A - B * B, but how to do those sums? Or is there another "2d map" process I could be using?
I've written a loop-based solution to calculate the expected output for these two examples:
W = 3 # size of kernel is WxW
out = np.zeros(A.shape)
difference_of_squares = A * A - B * B
for i, j in np.ndindex(out.shape):
starti = max(i - W//2, 0) # use smaller kernels at input's boundaries, output will have same dimension as input
stopi = min(i - W//2 + W, np.shape(out)[0]) # I'm not worried at this point about what happens at boundaries
startj = max(j - W//2, 0) # standard convolution solutions are often just reducing output size or padding input with zeroes
stopj = min(j - W//2 + W, np.shape(out)[1])
out[i, j] = np.sum(difference_of_squares[starti:stopi, startj:stopj])
print(out)
[[ 8423. 11816. 10372. 41125. 35287. 31747.]
[ 29370. 65887. 38811. 61252. 51033. 51845.]
[ 24756. 60119. 109133. 35101. 70005. 18757.]
[ 8641. 62463. 126935. 14530. 2255. -64752.]
[ 36623. 110426. 163513. 33812. -50035. -146450.]
[ 22268. 100132. 130190. 83010. -10163. -88994.]]
You can use scipy.signal.convolve2d:
from scipy.signal import convolve2d
# Same shape as original (6x6)
>>> convolve2d(A**2-B**2, np.ones((3, 3), dtype=int), mode='same')
array([[ 8423, 11816, 10372, 41125, 35287, 31747],
[ 29370, 65887, 38811, 61252, 51033, 51845],
[ 24756, 60119, 109133, 35101, 70005, 18757],
[ 8641, 62463, 126935, 14530, 2255, -64752],
[ 36623, 110426, 163513, 33812, -50035, -146450],
[ 22268, 100132, 130190, 83010, -10163, -88994]])
# Shape reduce by 1 (5x5)
>>> convolve2d(A**2-B**2, np.ones((3, 3), dtype=int), mode='valid')
array([[ 65887, 38811, 61252, 51033],
[ 60119, 109133, 35101, 70005],
[ 62463, 126935, 14530, 2255],
[110426, 163513, 33812, -50035]])
Note: You have to play around with the "mode" and "limit" parameters until you get what you want.
Update
If the border is not a problem at this point, you can use sliding_window_view:
from numpy.lib.stride_tricks import sliding_window_view
>>> np.sum(sliding_window_view(A**2-B**2, (3, 3)), axis=(2, 3))
array([[ 65887, 38811, 61252, 51033],
[ 60119, 109133, 35101, 70005],
[ 62463, 126935, 14530, 2255],
[110426, 163513, 33812, -50035]])

How to get a list of doc name from numpy array

I have a 2d numpy array:
dataset_tr = 'data/20news_clean/train.txt.npy'
data_tr = np.load(dataset_tr)
thedata_tr looks like this: It is a 3*10 numpy array:
[array([ 700, 152, 572, 572, 619, 724, 326, 1571, 572, 99])
array([ 331, 152, 397, 1273, 89, 228, 0, 0, 0, 0])
array([ 6, 1, 26, 174, 216, 135, 1060, 259, 75, 7])]
Each row here is a representation for a document in the 20newsgroup dataset.
All I want to do is to create a key out of this 2d array. The result will be 1 * 3 because I had 3 row in my 2d aaray.
Actually what I am doing here is that I am trying to assign a name to each row of that array. So the result will look like this:
['doc1', 'doc2', 'doc3']
I am able to get this but by looping through the 2d array.
Is there any better numpy way of doing this?
You can get the desired result with a list comprehension:
result = ['doc%i' % i for i in range(len(data_tr))]
docs = ['doc'+str(i+1) for i in range(len(data_tr)]

python add multiple arrays together

I have multiple 5x5 arrays which are contained within one large array - the overarching shape is: 5 x 5 x 29. I want to sum every 5 x 5 array to produce one single array, instead of 29 single arrays.
I know that you can do something along the lines of:
new_data = data1[:,:,0] + data1[:,:,1] + ... + data1[:,:,29]
However, this gets very cumbersome for large arrays. Is there an easier way to do this?
Assuming you are using NumPy, you should be able to do this with:
In [13]: data1 = np.arange(100).reshape(5, 5, 4) # For example
In [14]: data1[:,:,0] + data1[:,:,1] + data1[:,:,2] + data1[:,:,3] # Bad way
Out[14]:
array([[ 6, 22, 38, 54, 70],
[ 86, 102, 118, 134, 150],
[166, 182, 198, 214, 230],
[246, 262, 278, 294, 310],
[326, 342, 358, 374, 390]])
In [15]: data1.sum(axis=2) # Good way
Out[15]:
array([[ 6, 22, 38, 54, 70],
[ 86, 102, 118, 134, 150],
[166, 182, 198, 214, 230],
[246, 262, 278, 294, 310],
[326, 342, 358, 374, 390]])
If you are saying you have a list of arrays, then use a for loop.
for i in range(29):
new_data+= data1[:,:,i]
If you are saying you have a tensor or some ND array you should review and research numpy's ND array docs.
You can use a for loop. Like this:
import numpy as np
new_data = np.zeros((5, 5))
for i in range(29):
new_data += data1[:,:,i]

How can I change the dimension of an array?

How to change this array into a 5*2 matrix?
This is my array:
[[ ([[315, 327, 333, 334, 339]], [[146, 143, 145, 145, 146]])]]
how to change the array into a 5*2 matrix
I'm really not sure what you meant by that, but if you want to rotate it (2*5 --> 5*2) you can try this
arrays = [[315, 327, 333, 334, 339], [146, 143, 145, 145, 146]]
newArrays = [[] for _ in range(len(arrays[0]))] # initialise this list first
for arr in arrays:
for i,item in enumerate(arr):
newArrays[i].append(item)
print(newArrays)
# [[315, 146], [327, 143], [333, 145], [334, 145], [339, 146]]
Numpy provides reshape method to reshape an array into array of any dimension with the same number of elements. You can use the method to reshape array of any shape into another shape as long as the product of the original array dimension(s) is/are equal to the product of new array dimension(s).
import numpy as np
a=[[ ([[315, 327, 333, 334, 339]], [[146, 143, 145, 145, 146]])]]
b=np.array(a).reshape((5,2))
list_b=b.tolist();
print list_b
# [[315, 327], [333, 334], [339, 146], [143, 145], [145, 146]]

Convert an image array to a binarized image

I have an Image array Indice which is like this:
array([[158, 0, 252, ..., 185, 186, 187],
[254, 253, 252, ..., 188, 188, 189],
[247, 249, 252, ..., 188, 187, 186],
...,
[176, 172, 168, ..., 204, 205, 205],
[178, 175, 172, ..., 206, 205, 206],
[180, 177, 174, ..., 206, 207, 207]], dtype=uint8)
I want to convert Indice to a binarized image (values between 0 and 1) with a threshehold near 0 (0.1 or 0.2). how can I do it in Python ?
You can use np.where to binarize the data after converting it to the range from 0 to 1 by dividing by 255
threshold = 0.2
new_indice = np.where(Indice/255>=threshold, 1, 0)
If a boolean binary array is fine for you, you can simply use numpy's element-wise comparison:
new_indice = (Indice/255 > threshold)
In fact, for random test arrays this seemed to be slightly faster than the np.where solution. In case you need an integer binary array you can simply add a 1* in front of the parentheses, but then the speed advantage seems to be gone.
An easy way to do this kind of task is by using list comprehensions.
In your case:
array([[1 if x>threshold else 0 for x in line] for line in Indice])
Where threshold would be set to the value you want.

Categories

Resources