How to insert numpy asanyarray value to asanyarray? - python

I have some problems in numpy array code.
I am coding a program to take a frame while photographing with a camera.
I want to save the image values ​​that are fetched for each frame in a list or numpy array, and then I want to take all the pictures and save them all at once.
However, if I try to save it in an array, it will still fail.
Ah, Image's size is 640*480 and fps is 30.
This is Windows 10, pyrealsense, numpy, python 3.6 , cv2 and realsense camera D415.
Example code
color = []<br>
color_image = frame.get_color_frame()<br>
color_array = np.asanyarray(color_image.get_data())<br>
color.append(color_array)<br>
If I put this code in it, I will get a few frames, and after 15 frames, the camera frame keeps getting the same frame.
Example code
test = np.zeros((480,640,3))<br>
color_image = frame.get_color_frame()<br>
color_array = np.asanyarray(color_image.get_data())<br>
np.insert(test, frame_count, color_array)<br>
ValueError: could not broadcast input array from shape (480,640,3) into shape (480)... why..? :(
In case of 1, different frames must be stored after 15th frame.
In the case of 2, insert the value into the array well. There is no example that should be like this.

Related

How to assign data to a multi-dimensional numpy array?

I have a numpy array batch initialized as follows:
batch = np.zeros((50, 60, 1920, 1080, 3))
Its supposed to be an array of 50 different, 60FPS videos of dimension 1920x1080, and the 3 represents three channels - red, green, blue. Each video is of exactly 1 second.
I iterate through all videos in my video folder and perform image processing on each frame of every video. Then, I write the transformed video in to the batch array. How do I properly index the batch array to save each video conforming with the dimension of batch array?
So far I have tried the following:
batch[:batches_produced, :idx, :] = frame[:]
where batches_produced is the current batch item index, idx is the current frame's index and frame is the actual frame of dimension (1920x1080x3).
When I
print(batch_data[1,2,:,:,:].shape), it throws
IndexError: index 1 is out of bounds for axis 0 with size 1.
Needless to say, this isn't working at all. I have spent most of my day trying to figure this out.
Any help would be greatly appreciated!

cv2 convert Range and copyTo functions of c++ to python

I'm writing a python video stabilizer and in some part of the code i need to copy 2 images into a canvas.
I tried to convert this c++ code to python but i wasn't able.
Mat cur2;
warpAffine(cur, cur2, T, cur.size());
cur2 = cur2(Range(vert_border, cur2.rows-vert_border),
Range(HORIZONTAL_BORDER_CROP, cur2.cols-HORIZONTAL_BORDER_CROP));
// Resize cur2 back to cur size, for better side by side comparison
resize(cur2, cur2, cur.size());
// Now draw the original and stablised side by side for coolness
Mat canvas = Mat::zeros(cur.rows, cur.cols*2+10, cur.type());
cur.copyTo(canvas(Range::all(), Range(0, cur2.cols)));
cur2.copyTo(canvas(Range::all(), Range(cur2.cols+10, cur2.cols*2+10)));
I wrote this code but i got error:
ret, frame = cap.read()
new_frame = transform(frame,data[counter]) #some kind of low pass filter
canvas = np.zeros ((frame_height, frame_width*2+10,3))
np.copyto (canvas[:frame_width], frame)
np.copyto (canvas[frame_width+10:frame_width*2+10], new_frame)
I got
"couldnt boradcast from shape into shape"
err. But i think i used canvas in wrong way. in cpp code there is canvas(Range::all(), Range(0, cur2.cols)) which i dont know how to use it in python
How can i use Range function and copyTo function in python?
And how should i copy an image to a specific part of canvas?
Any help?
cv::Mat are actually numpy arrays in python. And in this case, you should use numpy functions and not OpenCV ones.
For the copyTo as clone, use copy() as in:
a = np.zeros((10,10,3), dtype=np.uint8)
b = a.copy()
For ranges, in numpy is easier... just use:
a[y1:y2, x1:x2,:]
which means from row y1 to row y2 and from column x1 to column x2. In case you need all, just leave the : alone like all rows:
a[:, x1:x2,:]
The last colon is for channels, in this case all channels, but you can also limit it. And if you need only 1 column, or channel you can put the number directly instead of using a "range" like
a[4, x1:x2, 0]
You can also drop the last colon of the channels, and it will use all of them. Like:
a[1:3, 4:8]
Finally, to copy a value to a place in the image you can do something like:
bigImage[y1:y2, x1:x2] = image
You have to make sure that image fits in this place (channels included). That means, if image is of size 640x480 you can not do this:
bigImage[10:20, 20:30] = image
but you can do something like
bigImage[10:20, 20:30] = image[10:20, 10:20]
assuming both have the same number of channels

Concatenating Numpy arrays for OpenCV imshow

Using OpenCV and Python, I want to display the left hand half of one image concatenated with the right-hand half of another image, both of the same size - 512x512 pixels. I have identified several ways of doing this, but I am confused about the behaviour of one method. In the following code, assume that only one of the methods is used at any one time and the rest are commented out:
import cv2
import numpy as np
image1 = cv2.imread('img1.png',0)
image2 = cv2.imread('img2.png',0)
#Method 1 - works
image3 = np.concatenate([image1[:,0:256], image2[:,256:512]], axis=1)
#Method 2 - works
image3 = image1[:,:]
image3[:,256:512] = image2[:,256:512]
#Method 3 - works if I don't create image3 with np.zeros first.
#Otherwise displays black image - all zeros - but print displays correct values
image3 = np.zeros(shape=(512,512), dtype=int)
image3[:,0:256] = image1[:,0:256]
image3[:,256:512] = image2[:,256:512]
print(image3)
cv2.imshow("IMAGE", image3)
cv2.waitKey(0)
cv2.destroyAllWindows()
In method 3, I at first mistakenly thought that the new numpy array image 3 would need to be created first and so created an array filled with zeros and then seemingly overwrote that array with the correct values. When I print that array it displays the correct values, but when I show it as an image using cv2.imshow it is all black (i.e. all zeros). Why the difference? I understand that slicing creates a view, not a copy, but can someone please explain what is happening in method 3 and why cv2.imshow displays the underlying array but print doesn't.
Your problem is in:
np.zeros(shape=(512,512), dtype=int)
imshow will show images coded as float(32 bit) with a range of 0.-1. or 8bit(1-4 channels) with a range of 0-255. You are using int, which is 32 bit (in most cases) and it is not a floating point. What you should do to fix it, is to use np.uint8.
np.zeros(shape=(512,512), dtype=np.uint8)
I think also it can be displayed using matplotlib if you want to keep the int, but I am not 100% sure about it.

Right way to share opencv video frame as Numpy array between multiprocessing processes

I want to share my captured frame in OpenVC with my multiprocessing subprocess but video_capture.read() creates a new object and doesnt write in to my numpy array that iam going to share by wrapping it with multiprocessing.Array()
Here is the code:
ret, frame = video_capture.read()
shared_array = mp.Array(ctypes.c_uint16, frame.shape[0] * frame.shape[1], lock=False)
while True:
b = np.frombuffer(shared_array)
ret, b = video_capture.read()
But the buffer b gets overridden by the read() function. So i dont write in to my buffer/shared array.
In subprocess i do following:
img = np.frombuffer(shared_array)
cv2.imshow('Video', img)
The shared array only containing the first frame of the video. How can i correctly write into the shared array to be able to read every frame in subprocess?
I dont want to use queues or pipes. Shared memory is the way to go coz more processes will consume the frames.
There are a couple of issues, one is the size and shape of the shared array and another is how you access it. To solve the first problem, first you need to make sure that the size of the created array corresponds to the size of a video frame. You have read a frame and use its width and height (although you can do it without reading any frame), but did not account for its number of channels.
ret, frame = video_capture.read()
shape = frame.shape
shared_array = mp.Array(ctypes.c_uint16, shape[0] * shape[1] * shape[2], lock=False)
You chose uint16 as data type, which is fine (again, you can use the video_capture.get(cv2.CAP_PROP_FORMAT) to get the exact data type of the frames, but you can choose whatever you want, since NumPy will convert the values to the array data type). However, when you create the NumPy array you must specify that is the data type you want to use, otherwise it will use float64 by default:
b = np.frombuffer(shared_array, dtype=np.uint16)
And then you have to reshape it to have the shape of a frame (note that this does not create a new NumPy array, it's just a view, so it still uses the shared buffer):
b = b.reshape(shape)
Finally, when you read the frame, you don't want to overwrite the b variable, but rather write to the array. Also, you should only do that when a frame was actually read:
while True:
ret, frame = video_capture.read()
if ret:
b[:] = frame

Storing an image dataset into 4D array then showing each image leads to distorted colors

I am trying to store an image dataset into a 4D ndarray then plot each image as follows:
i=0
for j in imagelist:
imageall[i] = misc.imread(j) ##(36, 570, 760, 3)
plt.imshow(imageall[i])
plt.show()
i=i+1
However, showing the image from the 4D ndarray gives a bluish image whereas simply reading the image and plotting it shows the image in its normal coloring.
I have compared channels (visually and by computing means in the 2 cases and they are exactly the same).
Can anyone explain the reason for change in displayed image coloration when reading single image and when reading to a 4D ndarray?
Your images have the same channel values as you noted in the question, so the difference in the result suggests that your values are being interpreted differently by plt.imshow. There's some magic to how plt.imshow interprets images based on type, so the most likely reason is that your original array is initialized with the wrong dtype.
Assuming that your pre-allocation is just something like
import numpy as np
imageall = np.empty((n_img,width,height,3))
# or imageall = np.zeros((n_img,width,height,3))
the resulting array will automatically have double type, i.e. dtype=np.float64. When you mutate this array with each image, the input dtype=np.uint8 (as returned from plt.imread) is converted to double, effectively doing
imageall[i] = misc.imread(j).astype(np.float64)
So your channel values ranging from 0 to 255 are stored as floats, which is then misinterpreted by plt.imshow.
You just need to pre-allocate with the right dtype:
imageall = np.empty((n_img,width,height,3),dtype=np.uint8)

Categories