将Numpy数组列表转换为单个Numpy数组而无需复制数据

3
我正在使用Python OpenCV读取视频数据,并希望存储K个帧。目前,我有一个循环执行以下操作(伪代码):
frame_list = 1:K
frame_buffer = list(map(ReadFrameNumber, frame_list))

我现在有一个名为frame_buffer的列表,其中包含K个帧,数据是一个NxMx3的numpy数组。这一切都很好,但现在我想重新组织数据,以便我可以有效地使用scikit-learn尝试一些模型。为了做到这一点,我需要创建一个可以结构化为((N*M*3) x (K))或((K) x (N*M*3)矩阵的numpy数组。我可以成功地做到这一点,但数据正在被复制,这使得该函数非常缓慢。我使用numpy.ravelnumpy.asarraynumpy.transpose的组合来完成我的缓慢方法。我基本上只想要一个新的数据视图。
这是我现在正在做的事情,但这并不起作用(它太慢了):
def RearrangeData(data): 
   b = list(map(np.ravel, data))
   b = np.asarray(b, dtype=np.float32)
   return b

更新: 这是我从OpenCV读取帧的方法:
import numpy as np
import cv2 

K= 10
num_frames = K
cap = cv2.VideoCapture(filename)
    def PopulateBuffer(num):
        cap.set(cv2.CAP_PROP_POS_FRAMES, num)
        ret, frame = cap.read()
        if not ret:
            print("Fatal Error: Could not read/decode frame %d" % num)
            exit(-1)
        return frame
frame_nums = list(range(0, int(num_frames)))
return (list(map(PopulateBuffer, frame_nums)))

有没有办法使用NumPy数组创建类似于软引用或指针的对象? - hpaulj
1
@hpaulj 我不确定这是否完全是重复的,因为我不一定需要有单独的数组。我可以预分配一个numpy数组,并相应地从opencv中读取获取的值。 - user985030
np.array([arr1,arr2,...,arrK]) 会生成一个 (K,N,M,3) 的数组。是的,每个 arr_i.data 缓冲区都将被复制到目标缓冲区。在列表中,它们分散在内存中,在目标位置它们是在一起的。但是,由于这种形状,复制将按块进行。 - hpaulj
1个回答

1
所以我相信我弄清楚了。
  • First mistake: using a list to copy in frames. I ended up preallocating a numpy array:

     #Preallocate frame buffer                              
     frame_buffer = np.zeros((num_frames,) + frame.shape)
     # Copy frames
     for i in range(0, num_frames):                    
         frame_buffer[i, :, :, :] = PopulateBuffer(i)
    
  • Second mistake: I didn't realize that numpy.reshape() would create a new view (in most cases I think). So it was as simple as doing the following once I had my initial array setup correctly.

    buf_s = frame_buffer.shape
    K = buf_s[0] # Number of frames
    M = buf_s[1] # Number of rows
    N = buf_s[2] # Number of cols
    chan = buf_s[3] # Color channel
    
    # If this copies data, I'm screwed. 
    %time scikit_buffer = frame_buffer.reshape([K, M*N*chan])
    
我确定它不是在复制数据,因为reshape命令运行的时间是微秒级别的:

CPU时间:用户17微秒,系统1微秒,总计:18微秒 墙上时间:21.9微秒

现在我可以在scikit-learn中分析我的帧!太酷了!

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接