Main Content

このページの内容は最新ではありません。最新版の英語を参照するには、ここをクリックします。

イメージ取得と並列イメージ処理を実行

この例では、Web カメラからのイメージ取得とデータの後処理を並行して実行する方法を示します。

この例では、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 オブジェクトを作成して、ワーカー内にノイズ除去ネットワークを 1 回だけ作成し、それを使用してフレームからノイズを除去します。

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);

プレビュー ウィンドウを作成します。Figure ハンドル hPreviewFigwaitfor を使用して、プレビューを手動で閉じるとすぐにビデオを停止することができます。この例では、2 秒後にビデオ取得を停止します。

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

後処理関数により、future 変数がビデオ オブジェクトの UserData プロパティに格納されます。この変数は、ビデオの書き込み操作の将来の実行を表します。すべてのデータを出力ファイルに書き込んだ後にビデオ ライターを閉じるには、この future 変数で 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);

future 変数を待機することにより、書き込みが完了するまでクライアント セッションの実行をブロックします。

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) | FramesAcquiredFcn | | | | (Image Processing Toolbox)

関連する例

詳細