Main Content

本页采用了机器翻译。点击此处可查看英文原文。

执行图像采集和并行图像处理

此示例展示了如何从网络摄像头执行图像采集并并行进行数据并行处理。

在这个例子中,MATLAB 客户端从视频设备获取帧,然后将后期处理卸载到并行工作进程,并行工作进程使用去噪神经网络滤除每个帧中的噪声。然后将这些帧写入视频。

在此示例中,您使用 parfeval 在工作进程中执行后处理,使用 parallel.pool.Constant 在工作进程中实例化要在后处理期间使用的去噪网络。为了从工作进程发回帧并确保它们按顺序写入,此示例使用了 OrderedDataQueue 对象。

提取设备信息并设置视频输出

清除以前的图像采集对象,并提取当前连接到机器的视频设备的信息。

objects = imaqfind;
delete(objects);
imaqreset;
deviceInfo = imaqhwinfo('winvideo')
deviceInfo = struct with fields:
       AdaptorDllName: 'adaptor.dll'
    AdaptorDllVersion: '6.1 (R2019b)'
          AdaptorName: 'winvideo'
            DeviceIDs: {[1]}
           DeviceInfo: [1×1 struct]

检查当前目录中是否已存在输出视频的文件夹。如果不存在用于输出视频的文件夹,请创建一个。

if ~isfolder('OutputFolder')
    mkdir OutputFolder
end 

要将视频数据写入输出文件夹中的 AVI 文件,请创建一个 VideoWriter 对象。

videoOut = VideoWriter('OutputFolder/myVideo.avi');

设置并行环境

为了能够将后处理任务卸载到工作进程中,首先要启动一个并行池。

p = parpool('Processes');
Starting parallel pool (parpool) using the 'Processes' profile ...
Connected to parallel pool with 6 workers.

创建一个 parallel.pool.Constant 对象,在工作进程中仅创建一次去噪网络,并使用它来从帧中滤除噪音。

C = parallel.pool.Constant(@() denoisingNetwork('dncnn'));

要从工作进程发回后处理后的帧并按顺序写入,请使用 OrderedDataQueue。设置回调以使用 afterEach 将帧写入磁盘。

Q = OrderedDataQueue;
afterEach(Q,@(frame) writeVideo(videoOut,frame));

OrderedDataQueue 对象在此示例的支持文件中定义。如果您想在自己的代码中使用它,请将其复制并放在其余文件中。

设置视频输入对象

创建视频输入对象。设置对象在客户端逐帧进行采集。

videoIn = videoinput('winvideo',1,'YUY2_800x600')
Summary of Video Input Object Using 'Microsoft® LifeCam Cinema(TM)'.

   Acquisition Source(s):  input1 is available.

  Acquisition Parameters:  'input1' is the current selected source.
                           10 frames per trigger using the selected source.
                           'YUY2_800x600' video data to be logged upon START.
                           Grabbing first of every 1 frame(s).
                           Log data to 'memory' on trigger.

      Trigger Parameters:  1 'immediate' trigger(s) on START.

                  Status:  Waiting for START.
                           0 frames acquired since starting.
                           0 frames available for GETDATA.
videoIn.ReturnedColorSpace = 'RGB';
videoIn.FramesPerTrigger = Inf;
videoIn.FramesAcquiredFcnCount = 1;

将视频写入帧速率设置为与视频读取相同的速率,并打开视频输出对象。

src = videoIn.Source;
videoOut.FrameRate = str2double(src.FrameRate);
open(videoOut);

为了在获取每一帧后启动后处理操作,为视频输入对象定义一个 FramesAcquiredFcn 回调并开始获取。

videoIn.FramesAcquiredFcn = {@postProcessAndWrite,C,Q};
start(videoIn);

创建预览窗口。您可以在预览手动关闭后立即通过使用图形句柄 hPreviewFig 上的 waitfor 来停止视频。对于此示例,2 秒后停止视频采集。

hPreviewImg = preview(videoIn);
hPreviewFig = ancestor(hPreviewImg,'figure');
pause(2);
stop(videoIn);

后处理函数将未来变量存储在视频对象的 UserData 属性中。该变量代表视频写入操作的未来执行。要在所有数据写入输出文件后关闭视频写入器,请在此未来变量上使用 afterAll

postProcessFutures = videoIn.UserData;
closeVideoFuture = afterAll(postProcessFutures,@() close(videoOut),0);

此示例中的后处理操作可能需要几分钟。在 Windows 10、Intel® Xeon® W-2133 3.60 GHz CPU(6 核)上,后处理需要 4 分钟。

您可以使用等待栏来跟踪后处理进度。要在每个后处理操作完成后更新等待栏,请使用 afterEach。要在所有操作完成后关闭等待栏,请使用 afterAll。有关详细信息,请参阅使用 afterEach 和 afterAll 异步更新用户界面

h = waitbar(0,'Postprocessing...');
updateWaitbarFuture = afterEach(postProcessFutures, ...
    @(~) waitbar(sum(strcmp('finished',{postProcessFutures.State}))/numel(postProcessFutures),h), 1);
afterAll(closeVideoFuture, @() close(h),0);

通过等待未来变量来阻止客户端会话中的执行,直到写入完成。

wait(closeVideoFuture);

完成后删除视频输入对象。

delete(videoIn);

可视化结果

创建视频文件后,您可以看到结果。

使用 VideoReader 对象读取视频文件。

vidObj = VideoReader('OutputFolder/MyVideo.avi');

使用 readFrame 函数读取一些帧。

images = cell(1,5);
times = .4:.4:2;
for ii = 1:numel(times)
    vidObj.CurrentTime = times(ii);
    images{ii} = readFrame(vidObj);
end

要可视化框架,请使用 montage 函数。

montage(images,'Size',[1 5])

定义辅助函数

定义主要的后处理例程,该例程在每次采集帧后执行。此函数 postProcessAndWrite 从视频输入对象中获取数据,并调用 parfeval 在并行工作进程中启动帧去噪。

function postProcessAndWrite(videoIn,~,C,Q)
    [frame,~,metadata] = getdata(videoIn,1); 
    postProcessFuture = parfeval(@postProcess,0,frame,C,Q,metadata.FrameNumber);
    videoIn.UserData = [videoIn.UserData postProcessFuture];
end

定义要在工作进程中执行的后处理函数。对于此示例,为了简化计算,将每一帧转换为灰度,然后使用 denoiseImage 函数对其进行去噪。函数 postProcess 将帧和 parallel.pool.Constant 对象的 Value 字段中存储的去噪网络对象作为输入。有关使用去噪神经网络对图像进行去噪的更多信息,请参阅 获得预训练的图像去噪网络 (Image Processing Toolbox)

function postProcess(frame,C,Q,frameNumber)
    grayFrame = im2double(rgb2gray(frame));
    denoisedGrayFrame = denoiseImage(grayFrame,C.Value);
    denoisedGrayFrame = im2uint8(denoisedGrayFrame);
    send(Q,frameNumber,denoisedGrayFrame)
end

另请参阅

| | (Image Acquisition Toolbox) | (Image Acquisition Toolbox) | | | | (Image Processing Toolbox)

相关示例

详细信息