我开始在 MATLAB 中编程,但在创建缓冲矩阵时遇到了一些问题。我正在尝试执行以下操作:
我不断地从网络摄像头获取图像,分割后我获得了移动目标的质心。我需要存储质心数据进行处理,但我不希望它占用太多内存。例如,如果我是一个 time t=inf
,我正在考虑将 10 个时间点的数据存储在一个矩阵中,就像一个循环缓冲区,然后写入和擦除旧数据,因为我需要同时处理这两个时间点的实际数据(t ) 和时间上的先前数据 (t-1)。
buffSize = 10;
circBuff = nan(1,buffSize);
for newest = 1:1000;
circBuff = [newest circBuff(1:end-1)]
end
我已经对此进行了测试,在 MATLAB 中运行不需要太多时间。探查器没有发现代码存在任何瓶颈。
更新:
由于我现在了解您需要一个循环缓冲区来存储数据,因此您可以使用以下解决方案。既然您说要在图像中存储对象的质心数据,我将为您提供一个存储任意数量测量值的一般情况(每个质心 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)中)执行您的处理。
当您谈论每次迭代的大型数据集时,数据洗牌可能会开始占用一些时间。我处理大型数据集的方法是使用类似的东西:
circBuff(:,:,mod(counter,numFrames)) = newData; 这样您只覆盖一次数据,而不是在每个周期移动整个缓冲区中的每个数据点。您只需要更加了解如何访问您的数据。
HTH,丹
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 的性能不依赖于缓冲区大小。
双缓冲根据在任何情况下要追加的数据来保证追加的预测时间。将来,本课程将为您提供双缓冲是或否的选择 - 如果您不需要保证时间,事情会加速。