3

我开始在 MATLAB 中编程,但在创建缓冲矩阵时遇到了一些问题。我正在尝试执行以下操作:

我不断地从网络摄像头获取图像,分割后我获得了移动目标的质心。我需要存储质心数据进行处理,但我不希望它占用太多内存。例如,如果我是一个 time t=inf,我正在考虑将 10 个时间点的数据存储在一个矩阵中,就像一个循环缓冲区,然后写入和擦除旧数据,因为我需要同时处理这两个时间点的实际数据(t ) 和时间上的先前数据 (t-1)。

4

4 回答 4

7
buffSize = 10;
circBuff = nan(1,buffSize);
for newest = 1:1000;
    circBuff = [newest circBuff(1:end-1)]
end

我已经对此进行了测试,在 MATLAB 中运行不需要太多时间。探查器没有发现代码存在任何瓶颈。

于 2009-05-05T15:57:26.767 回答
2

更新:

由于我现在了解您需要一个循环缓冲区来存储数据,因此您可以使用以下解决方案。既然您说要在图像中存储对象的质心数据,我将为您提供一个存储任意数量测量值的一般情况(每个质心 1 个像素索引值,或者 x 和 y 坐标的 2 个值等) ...

首先,初始化缓冲区:

nBuffer = 10;  % You can set this to whatever number of time points
               %   you want to store data for
nSamples = 2;  % You can set this to the number of data values you
               %   need for each point in time
centroidBuffer = zeros(nSamples,nBuffer);  % Initialize the buffer to zeroes

接下来,您将拥有连续循环。您可以使用while 循环和最初值为TRUE的标志变量(您可以将其设置为FALSE以停止循环):

keepLooping = true;
while keepLooping,
  % Capture your image
  % Compute the centroid data and place it in the vector "centroidData"
  centroidBuffer = [centroidBuffer(:,2:end) centroidData(:)];
  % Do whatever processing you want to do on centroidBuffer
  % Choose to set keepLooping to false, if you want
end

这通过以下方式工作:在每个时间点,centroidBuffer中的第一列(即最旧的数据)被删除,并在末尾附加一个新列(即新数据)。这样,缓冲矩阵的大小总是相同的。

如果您不想在每个时间步执行处理,而是仅在每个nBuffer时间点之后执行,以便每次都对一组新数据进行操作,则将上述代码替换为以下代码:

keepLooping = true;
processTime = 0;
while keepLooping,
  % Capture your image
  % Compute the centroid data and place it in the vector "centroidData"
  centroidBuffer = [centroidBuffer(:,2:end) centroidData(:)];
  processTime = processTime+1;
  if (processTime == nBuffer),
    % Do whatever processing you want to do on centroidBuffer
    processTime = 0;
  end
  % Choose to set keepLooping to false, if you want
end

编辑:

您可以使用上述代码进行多种变体。例如,如果要存储两组数据,每组 10 个时间点,可以将nBuffer更改为 20,以将旧集存储在前 10 列中,将新集存储在后 10 列中。然后,将 if 语句更改为:

  ...
  if (processTime == nBuffer/2),
  ...

现在,您可以使用较旧的 10 个数据点集(在centroidBuffer(:,1:10)中)和较新的 10 个数据点集(在centroidBuffer(:,11:20)中)执行您的处理。

于 2009-05-04T20:00:45.240 回答
2

当您谈论每次迭代的大型数据集时,数据洗牌可能会开始占用一些时间。我处理大型数据集的方法是使用类似的东西:

circBuff(:,:,mod(counter,numFrames)) = newData; 这样您只覆盖一次数据,而不是在每个周期移动整个缓冲区中的每个数据点。您只需要更加了解如何访问您的数据。

HTH,丹

于 2009-05-05T16:31:30.570 回答
1
centroidBuffer = [centroidBuffer(:,2:end) centroidData(:)];

这是一个不错且简单的解决方案,但速度很慢。每次添加新向量时,matlab 都必须复制除第一个条目之外的整个旧数据。如果您考虑实时,这不是一个好主意。

circBuff(:,:,mod(counter,numFrames)) = newData

这个想法没有复制问题,但是现在您不再有一个好的子数组,它按时间顺序表示从第一个索引到最后一个索引的数据。

我刚刚上传了一个快速循环缓冲区的解决方案,它避免了两个问题

http://www.mathworks.com/matlabcentral/fileexchange/47025-circvbuf-m

这个循环缓冲区的主要思想是在程序中使用缓冲区时,性能恒定且快速,并且避免了复制操作:

% create a circular vector buffer
    bufferSz = 1000;
    vectorLen= 7;
    cvbuf = circVBuf(int64(bufferSz),int64(vectorLen));

% fill buffer with 99 vectors
    vecs = zeros(99,vectorLen,'double');
    cvbuf.append(vecs);

% loop over lastly appended vectors of the circVBuf:
    new = cvbuf.new;
    lst = cvbuf.lst;
    for ix=new:lst
       vec(:) = cvbuf.raw(:,ix);
    end

% or direct array operation on lastly appended vectors in the buffer (no copy => fast)
    new = cvbuf.new;
    lst = cvbuf.lst;
    mean = mean(cvbuf.raw(3:7,new:lst));

检查屏幕截图,如果缓冲区很大,这个循环缓冲区有优势,但每次追加的数据大小很小,因为与简单的复制缓冲区相比,circVBuf 的性能不依赖于缓冲区大小。

双缓冲根据在任何情况下要追加的数据来保证追加的预测时间。将来,本课程将为您提供双缓冲是或否的选择 - 如果您不需要保证时间,事情会加速。 在此处输入图像描述

于 2014-06-21T15:23:48.800 回答