美好的一天,
网络摄像头类每秒大约有30帧,所有这些帧都将保存在矢量(如队列)中。然后3个异步线程将读取队列,并将尝试执行其工作(以保存这些图像)。为什么队列溢出?所以问题是这些线程比网络摄像头慢。
Procedure TSaveThread.Execute;
begin
while not terminated do
begin
elElement:=NIL;
EnterCriticalSection(CritSect);
if iElementsLength>=0 then
begin
elElement:=vElements[iElementsLength];
Dec(iElementsLength);
end;
LeaveCriticalSection(CritSect);
if elElement<>NIL then
begin
JpegImg.Assign(elElement.bmWebcam) ;
JpegImg.SaveToFile('Save\'+elElement.sTime+'.jpg') ;
elElement.Free;
end;
Sleep(20);
end;
end;
图片已添加到队列中。
//------------------------------------------------------------------------------
Procedure TWebcam.OnSave(Sender:TObject; bmWebcam:TBitmap);
begin
EnterCriticalSection(CritSect);
inc(iElementsLength);
vElements[iElementsLength]:=TElement.Create(bmWebcam);
LeaveCriticalSection(CritSect);
end;
创建线程。
for i:=0 to 2 do
TSaveThread.Create(false);
问题是,这些线程无法保存所有这些图像。为什么?如何改进我的线程?
Delphi版本:Delphi XE2
网络摄像头框架尺寸:1280x760或960x600 这里的整个源代码:http://pastebin.com/8SekN4TE
答案 0 :(得分:15)
我写了以下程序:
{$APPTYPE CONSOLE}
{$R *.res}
uses
System.SysUtils, Vcl.Graphics, Vcl.Imaging.jpeg,
System.IOUtils, System.Diagnostics;
var
i: Integer;
bmp: TBitmap;
jpeg: TJPEGImage;
Stopwatch: TStopwatch;
begin
bmp := TBitmap.Create;
bmp.SetSize(1280, 760);
jpeg := TJPEGImage.Create;
Stopwatch := TStopwatch.StartNew;
for i := 1 to 100 do begin
jpeg.Assign(bmp);
jpeg.SaveToFile('C:\desktop\temp\'+TPath.GetRandomFileName);
end;
Writeln(Stopwatch.ElapsedMilliseconds);
Readln;
end.
它将1280x760像素位图转换为JPEG图像,然后保存到磁盘。它这样做了100次。在我的机器上,这需要9秒。这是每秒11幅图像的吞吐量。如果我跳过转换为JPEG步骤并直接保存位图,我可以获得每秒150张图像的吞吐量。很明显,转换为JPEG是一个瓶颈。
您正在寻找每秒30张图片。虽然多线程有帮助,但我怀疑你有四核机器。一个用于网络摄像头的处理器,三个用于保存。因此,如果您只有三个线程可用,那么您可能很难达到每秒30帧所需的吞吐量。我机器上的理论峰值是33.如果你没有达到每秒30帧,那么你的队列显然会溢出。
显而易见的结论是,您需要找到更快的JPEG转换库。我很确定存在这样的库。例如,我认为libjpeg
应该快得多。
至于你现有的代码,有一些明显的缺陷:
Sleep
。在你的情况下,如果最后一次拉动图像的尝试成功,那么睡觉就是自杀。不要那样做。您应该使用真正的线程队列。允许正确阻塞的一个等待同步对象。实际上,使用事件对象和您最喜欢的非线程队列来制作一个非常简单。TElement.Create(bmWebcam)
时正握着锁。这将阻碍扩展。将TElement.Create(bmWebcam)
分配给锁外部的局部变量。然后分配给锁内的共享数据。因此,您可以首先删除对Sleep
的调用,以检查这些提示。然后将TWebcam.OnSave
更改为如下所示:
Procedure TWebcam.OnSave(Sender:TObject; bmWebcam:TBitmap);
var
NewElement: TElement;
begin
NewElement := TElement.Create(bmWebcam);
EnterCriticalSection(CritSect);
inc(iElementsLength);
vElements[iElementsLength] := NewElement;
LeaveCriticalSection(CritSect);
end;
这些建议会有所帮助,但我认为你需要解决基本问题,即JPEG转换。
答案 1 :(得分:4)
MultiThreadding不会加速您的媒体(HardDrive)。
事实上,它可以通过并行写访问来减慢。
首先,您必须测量您的媒体(硬盘)是否能够在不到33毫秒的时间内存储图像 - 因为每33.333毫秒您将从网络摄像头获得一个新图像。
如果没有,你不能期望这个运行。
你应该(和/或)
如果你需要快速,不要浪费时间
if elElement<>NIL then
begin
JpegImg.Assign(elElement.bmWebcam) ;
JpegImg.SaveToFile('Save\' + elElement.sTime + '.jpg' );
elElement.Free;
end
else
Sleep(20);
OTL无助于让您的媒体更快,但更清洁:o)
所以你应该看看