Suppose a numpy nd-array representing a video is stored in the computer. What is the most efficient way to load the first image?
More precisely, consider the following pseudocode:
class MyArray():
self.array
def function():
#some manipulations
return an object of class MyArray with video.array being a numpy array of shape say (100000,100,100,3)
video = function()
Here we assume that video.array
is an array representing a video. That is, for each t = 0,1,...,99999
, video.array[t,:,:,:]
is an RGB image.
Suppose now that we have finished the execution of the above code. Namely, we already have video
being an object of class MyArray
. By writing first_image = video.array[0,:,:,:]
, we can get the first image of the video. But it seems the computer will first read video.array
(which is slow) and then call the first image.
Question: What is the fastest equivalent of first_image = video.array[0,:,:,:]
? Is there any sort of, for example, partial read mechanisms in numpy or opencv or any other library?
Clarification: If, right after the above pseudocode, I write:
result = video.array #Line 1
first_image = result[0] #Line 2
It turns out that, usually, line 1 takes like 10 seconds and line 2 takes like a fraction of second. On the other hand, the command first_image = video.array[0]
mentionned in the post takes also like 10 seconds. Therefore:
The command first_image = video.array[0] always reads the whole video.array and then takes the first image
I am asking whether it is possible to not read the entire video. All I need is for it to stop after reading the first image.
CodePudding user response:
It seems like you have answered your own question: If you want to index the first image frame in your numpy array you can just use the index position in the first dimension.
import numpy as np
# frames, bands, rows, cols
shape = (50, 3, 128, 128)
# Random test data of the requested shape.
video_array = np.random.randint(0, 255, size=shape)
first_frame = video_array[0]
first_frame.shape
# (3, 128, 128)
It sounds like maybe you are using another library or program that reads the entire array from inside an object, video
, and upon calling the property video.array
you are executing a load from disk function?
CodePudding user response:
It's very simple; method to get nth image from the video:
class MyArray():
self.array = ...
def getframe(self, n):
return self.array[n]
To get first image just call myarray.getframe(0)
on the object myarray
.
And if you want to read from file, use count in np.fromfile
:
import time
import numpy as np
W, H, CH = 1920, 1080, 3
N = 1000
random_video = np.random.randint(0, 256, (N, H, W, CH), np.uint8)
print(f"size of video ={random_video.size / 2 ** 30} GB")
FILE = "d:/1.npy"
t0 = time.monotonic()
random_video.tofile(FILE)
t1 = time.monotonic()
print(f"save time={t1 - t0:.3g} s")
## read first frame
FRAMES_TO_READ = 1
SINGLE_FRAME_SIZE = FRAMES_TO_READ * W * H * CH
t0 = time.monotonic()
video = np.fromfile(FILE, np.uint8, count=SINGLE_FRAME_SIZE, offset=0).reshape(FRAMES_TO_READ, H, W, CH)
t1 = time.monotonic()
print(f"read time(single frame)={t1 - t0:.6f} s")
np.array_equal(random_video[0:FRAMES_TO_READ], video)