このページの内容は最新ではありません。最新版の英語を参照するには、ここをクリックします。
ステレオ視差
この例では、2 つのイメージのステレオ視差を計算する MATLAB® 関数から CUDA® MEX 関数を生成する方法を説明します。
サードパーティの前提条件
必須
この例では、CUDA MEX を生成します。以下のサードパーティ要件が適用されます。
CUDA 対応 NVIDIA® GPU および互換性のあるドライバー。半精度コード生成の場合、GPU デバイスの Compute Capability は 6.0 以上でなければなりません。
オプション
スタティック ライブラリ、ダイナミック ライブラリ、または実行可能ファイルなどの MEX 以外のビルドについて、この例では以下の要件も適用されます。
NVIDIA Toolkit。
コンパイラおよびライブラリの環境変数。詳細については、サードパーティ ハードウェアと前提条件となる製品の設定を参照してください。
GPU 環境の検証
この例を実行するのに必要なコンパイラおよびライブラリが正しく設定されていることを検証するために、関数coder.checkGpuInstallを使用します。
envCfg = coder.gpuEnvConfig('host');
envCfg.BasicCodegen = 1;
envCfg.Quiet = 1;
coder.checkGpuInstall(envCfg);ステレオ視差の計算
エントリポイント関数 stereoDisparity.m は、2 つのイメージを受け取り、その 2 つのイメージから計算したステレオ視差マップを返します。
type stereoDisparity%% Modified Algorithm for Stereo Disparity Block Matching
% In this implementation, instead of finding shifted image, indices are
% mapped accordingly to save memory and some processing. RGBA column major
% packed data is used as input for compatibility with CUDA intrinsics.
% Convolution is performed using separable filters (horizontal and then
% vertical).
% Copyright 2017-2021 The MathWorks, Inc.
function [out_disp] = stereoDisparity(img0,img1) %#codegen
% Copyright 2017-2019 The MathWorks, Inc.
% GPU code generation pragma
coder.gpu.kernelfun;
%% Stereo Disparity Parameters
% |WIN_RAD| is the radius of the window to be operated. |min_disparity| is
% the minimum disparity level the search continues for. |max_disparity| is
% the maximum disparity level the search continues for.
WIN_RAD = 8;
min_disparity = -16;
max_disparity = 0;
%% Image Dimensions for Loop Control
% The number of channels packed are 4 (RGBA) so as nChannels are 4.
[imgHeight,imgWidth]=size(img0);
nChannels = 4;
imgHeight = imgHeight/nChannels;
%% Store the Raw Differences
diff_img = zeros([imgHeight+2*WIN_RAD,imgWidth+2*WIN_RAD],'int32');
% Store the minimum cost
min_cost = zeros([imgHeight,imgWidth],'int32');
min_cost(:,:) = 99999999;
% Store the final disparity
out_disp = zeros([imgHeight,imgWidth],'int16');
%% Filters for Aggregating the Differences
% |filter_h| is the horizontal filter used in separable convolution.
% |filter_v| is the vertical filter used in separable convolution which
% operates on the output of the row convolution.
filt_h = ones([1 17],'int32');
filt_v = ones([17 1],'int32');
% Main Loop that runs for all the disparity levels. This loop is
% expected to run on CPU.
for d=min_disparity:max_disparity
% Find the difference matrix for the current disparity level. Expect
% this to generate a Kernel function.
coder.gpu.kernel;
for colIdx=1:imgWidth+2*WIN_RAD
coder.gpu.kernel;
for rowIdx=1:imgHeight+2*WIN_RAD
% Row index calculation.
ind_h = rowIdx - WIN_RAD;
% Column indices calculation for left image.
ind_w1 = colIdx - WIN_RAD;
% Row indices calculation for right image.
ind_w2 = colIdx + d - WIN_RAD;
% Border clamping for row Indices.
if ind_h <= 0
ind_h = 1;
end
if ind_h > imgHeight
ind_h = imgHeight;
end
% Border clamping for column indices for left image.
if ind_w1 <= 0
ind_w1 = 1;
end
if ind_w1 > imgWidth
ind_w1 = imgWidth;
end
% Border clamping for column indices for right image.
if ind_w2 <= 0
ind_w2 = 1;
end
if ind_w2 > imgWidth
ind_w2 = imgWidth;
end
% In this step, Sum of absolute Differences is performed
% across tour channels.
tDiff = int32(0);
for chIdx = 1:nChannels
tDiff = tDiff + abs(int32(img0((ind_h-1)*(nChannels)+...
chIdx,ind_w1))-int32(img1((ind_h-1)*(nChannels)+...
chIdx,ind_w2)));
end
% Store the SAD cost into a matrix.
diff_img(rowIdx,colIdx) = tDiff;
end
end
% Aggregating the differences using separable convolution. Expect this
% to generate two kernels using shared memory.The first kernel is the
% convolution with the horizontal kernel and second kernel operates on
% its output the column wise convolution.
cost_v = conv2(diff_img,filt_h,'valid');
cost = conv2(cost_v,filt_v,'valid');
% This part updates the min_cost matrix with by comparing the values
% with current disparity level.
for ll=1:imgWidth
for kk=1:imgHeight
% load the cost
temp_cost = int32(cost(kk,ll));
% Compare against the minimum cost available and store the
% disparity value.
if min_cost(kk,ll) > temp_cost
min_cost(kk,ll) = temp_cost;
out_disp(kk,ll) = abs(d) + 8;
end
end
end
end
end
イメージの読み取りと RGBA パックされた列優先の順序へのデータのパック
img0 = imread('scene_left.png'); img1 = imread('scene_right.png'); [imgRGB0] = pack_rgbData(img0); [imgRGB1] = pack_rgbData(img1);
左のイメージ

右のイメージ

GPU コードの生成
cfg = coder.gpuConfig('mex'); codegen -config cfg -args {imgRGB0, imgRGB1} stereoDisparity;
Code generation successful: View report
生成された MEX の実行と出力視差の表示
out_disp = stereoDisparity_mex(imgRGB0,imgRGB1); imagesc(out_disp);

半精度
この例における計算は、エントリポイント関数 stereoDisparityHalfPrecision.m を使用して、半精度浮動小数点数で行うこともできます。半精度データ型を含むコードの生成と実行には、CUDA Compute Capability 6.0 以上が必要です。コード構成オブジェクトの ComputeCapability プロパティを '6.0' に設定します。半精度の場合、CUDA コードを生成するためのメモリ割り当て (malloc) モードは 'Discrete' に設定しなければなりません。
cfg.GpuConfig.ComputeCapability = '6.0'; cfg.GpuConfig.MallocMode = 'Discrete';
標準のimreadコマンドは、イメージの RGB チャネルをピクセルごとに 1 つの整数で表します。整数の範囲は 0 ~ 255 です。単純に入力を half 型にキャストするだけでは、畳み込み時にオーバーフローになる可能性があります。この場合、イメージを 0 ~ 1 の値にスケーリングできます。"imread" は、イメージの RGB チャネルをピクセルごとに 1 つの整数で表します。整数の範囲は 0 ~ 255 です。単純に入力を half 型にキャストするだけでは、畳み込み時にオーバーフローになる可能性があります。この場合、イメージを 0 ~ 1 の値にスケーリングできます。
img0 = imread('scene_left.png'); img1 = imread('scene_right.png'); [imgRGB0] = half(pack_rgbData(img0))/255; [imgRGB1] = half(pack_rgbData(img1))/255;
関数の CUDA MEX の生成
関数 stereo_disparity_half_precision.m でのコード生成。
codegen -config cfg -args {imgRGB0, imgRGB1} stereoDisparityHalfPrecision;
Code generation successful: View report
参考
関数
codegen|coder.gpu.kernel|coder.gpu.kernelfun|gpucoder.matrixMatrixKernel|coder.gpu.constantMemory|stencilfun|coder.checkGpuInstall