Home > Mobile >  Efficiently Read First Image for Large Stored Numpy Array Representing Video
Efficiently Read First Image for Large Stored Numpy Array Representing Video

Time:07-01

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)
  • Related