今天我们完成一个需求:给不同图片打上一个量化的标签,将图像作为输入,量化标签(浮点数)作为输出。我们的例子为:一个柔性视觉力度传感器:随着力的大小变化,弹性体发生形变,输出即为力的大小。
本文只提供部分技术的解决方案。
我们相机拍摄的图片为1280x760。我们这里需要裁剪并缩小为56x56,并将其变为灰阶和二值化。
function preprocessed = preprocess(img)
tmp = img(0:720, 240:960);
tmp = imresize(tmp, [56, 56]);
tmp = im2gray(tmp);
preprocessed = imbinarize(tmp);
end
按照80%和20%的分组将数据集分为训练集和测试集。
function [XTrain, YTrain, XValidation, YValidation] = generateTrainData(sourcePath)
imds = imageDatastore(sourcePath, 'IncludeSubfolders', true, 'LabelSource', 'foldernames');
[dsTrain, dsVal] = splitEachLabel(imds, 0.8, 0.2, 'randomized');
[XTrain, YTrain] = imds2array(dsTrain);
[XValidation, YValidation] = imds2array(dsVal);
end
由于Matlab的回归任务需要将四维数组作为输入,我们还需要一个函数将图片集转换为4-D double数组。
function [X, T] = imds2array(imds)
% imds2array Convert an image datastore into a 4-D array
%
% X - Input data as an H-by-W-by-C-by-N array, where H is the
% height and W is the width of the images, C is the number of
% channels, and N is the number of images.
% T - Categorical vector containing the labels for each
% observation.
imagesCellArray = imds.readall();
numImages = numel(imagesCellArray);
[h, w, c] = size(imagesCellArray{1});
X = zeros(h, w, c, numImages);
for i = 1:numImages
X(:, :, :, i) = im2double(imagesCellArray{i});
end
T = double(string(imds.Labels));
end
layers = [
imageInputLayer([56 56 1])
convolution2dLayer(3,8,'Padding','same')
batchNormalizationLayer
reluLayer
averagePooling2dLayer(2,'Stride',2)
convolution2dLayer(3,16,'Padding','same')
batchNormalizationLayer
reluLayer
averagePooling2dLayer(2,'Stride',2)
convolution2dLayer(3,32,'Padding','same')
batchNormalizationLayer
reluLayer
convolution2dLayer(3,32,'Padding','same')
batchNormalizationLayer
reluLayer
dropoutLayer(0.2)
fullyConnectedLayer(1)
regressionLayer];
miniBatchSize = 128;
validationFrequency = floor(numel(YTrain) / miniBatchSize);
options = trainingOptions('sgdm', ...
'MiniBatchSize', miniBatchSize, ...
'MaxEpochs', 100, ...
'InitialLearnRate', 1e-4, ...
'LearnRateSchedule', 'piecewise', ...
'LearnRateDropFactor', 0.1, ...
'LearnRateDropPeriod', 20, ...
'Shuffle', 'every-epoch', ...
'ValidationData', {XValidation, YValidation}, ...
'ValidationFrequency', 10, ...
'Plots', 'training-progress', ...
'Verbose', false);
net = trainNetwork(XTrain, YTrain, layers, options);
这里我们使用摄像头实时获取图片,需要Matlab的Image Acquisition Toolbox。
首先查询摄像机Adapter:imaqInfo = imaqhwinfo
,输出:
InstalledAdaptors: {'winvideo'}
MATLABVersion: '9.11 (R2021b)'
ToolboxName: 'Image Acquisition Toolbox'
ToolboxVersion: '6.5 (R2021b)'
可以看到,存在的Adaptor只有winvideo
,继续查看winvideo
的信息:winvideoinfo = imaqhwinfo('winvideo')
,找到DeviceInfo
,并找到USB Camera的ID。我这里为1。
接下来调用相机:
vid = videoinput('winvideo', 1, 'MJPG_1280x720');
vid.TriggerRepeat = 100;
vid.FrameGrabInterval = 5;
% 加载训练好的网络
load("network.mat");
figure
hold on
i = 0;
start(vid)
while i < 2000
if vid.FramesAvailable >= 1
i = i + 1;
img = getdata(vid, 1);
img = preprocess2(img);
inp = img2array(img);
out = predict(net, inp);
plot(i, double(out)/10, 'o');
double(out) / 10
end
end
stop(vid)
随着按下的力度变化,采集到的力度数据变化曲线如图所示: