본문 바로가기

MATLAB/ㄴ 영상 딥러닝

예제_YOLO v4 딥러닝을 사용한 객체 검출

0. 참고 문서

: https://kr.mathworks.com/help/vision/ug/object-detection-using-yolov4-deep-learning.html

 

YOLO v4 딥러닝을 사용한 객체 검출 - MATLAB & Simulink - MathWorks 한국

이 예제의 수정된 버전이 있습니다. 사용자가 편집한 내용을 반영하여 이 예제를 여시겠습니까?

kr.mathworks.com

 

이 예제에서는 YOLO v4(You Only Look Once Version 4) 딥러닝 신경망을 사용하여 영상에서 객체를 검출하는 방법을 

보여줍니다. 이 예제에서는 다음을 수행합니다


1) YOLO v4 객체 검출 신경망의 훈련, 검증, 테스트를 위한 데이터셋을 구성합니다. 또한 신경망 효율성을 향상하기 위해

훈련 데이터셋에 대한 데이터 증대를 수행합니다.
2) YOLO v4 객체 검출 신경망을 훈련시키는 데 사용할 앵커 상자를 훈련 데이터로부터 계산합니다.
3) yolov4ObjectDetector 함수를 사용하여 YOLO v4 객체 검출기를 만들고 trainYOLOv4ObjectDetector 함수를 사용하여

검출기를 훈련시킵니다.

 

이 예제에서는 또한 영상에서 차량을 검출하는 데 사용할 사전 훈련된 YOLO v4 객체 검출기를 제공합니다. 
사전 훈련된 신경망은 백본 신경망으로 CSPDarkNet-53을 사용하고 차량 데이터셋에 대해 훈련됩니다. 

YOLO v4 객체 검출 신경망에 대한 자세한 내용은 Getting Started with YOLO v4 항목을 참조하십시오

 

 

1. 데이터셋 불러오기

 


unzip vehicleDatasetImages.zip
data = load('vehicleDatasetGroundTruth.mat')
vehicleDataset = data.vehicleDataset;


% 데이터셋의 1열 몇개만 보여주기
vehicleDataset(1:4,:)

% 전체 경로를 연결하기
vehicleDataset.imageFilename = fullfile(pwd, vehicleDataset.imageFilename)

 

 


% 데이터셋을 훈련, 검증, 테스트로 분할. (6:1:3)
rng('default');
shuffledIndices = randperm(height(vehicleDataset));
idx = floor(0.6 * length(shuffledIndices));

 
trainingIdx = 1:idx;
trainingDataTbl = vehicleDataset(shuffledIndices(trainingIdx),:);

 
validationIdx = idx+1 : idx+1+floor(0.1*length(shuffledIndices));
validationDataTbl = vehicleDataset(shuffledIndices(validationIdx),:);

 
testIdx = validationIdx(end)+1 : length(shuffledIndices);
testDataTbl = vehicleDataset(shuffledIndices(testIdx),:);

 
% 데이터저장소를 생성
imdsTrain = imageDatastore(trainingDataTbl{:,"imageFilename"});
bldsTrain = boxLabelDatastore(trainingDataTbl(:,"vehicle"));

 
imdsValidation = imageDatastore(validationDataTbl{:,"imageFilename"});
bldsValidation = boxLabelDatastore(validationDataTbl(:,"vehicle"));

 
imdsTest = imageDatastore(testDataTbl{:,"imageFilename"});
bldsTest = boxLabelDatastore(testDataTbl(:,"vehicle"));

 
% 영상 데이터저장소와 상자 레이블 데이터저장소를 결합
trainingData = combine(imdsTrain, bldsTrain)
validationData = combine(imdsValidation, bldsValidation)
testData = combine(imdsTest, bldsTest)
%
% validateInputData(trainingData);
% validateInputData(validationData);
% validateInputData(testData);

 
% 상자 레이블과 함께 훈련 영상 중 하나를 표시
data = read(trainingData);
I = data{1};
bbox = data{2};
annotatedImage = insertShape(I, 'Rectangle', bbox);
annotatedImage = imresize(annotatedImage, 2);
figure
imshow(annotatedImage)

 

 

2. YOLO v4 객체 검출기 신경망 만들기

 

preprocesData 함수는 맨 하단의 지원함수 부분 참고

 


% 훈련에 사용할 신경망의 크기를 지정
inputSize = [608 608 3];

 
% 검출할 객체 클래스의 이름을 지정
className = "vehicle";

 
% 데이터 사물크기를 기반으로 앵커상자를 추정
rng("default")
trainingDataForEstimation = transform(trainingData, @(data)preprocessData(data,inputSize)); % trainingData에서 inputSize로 데이터를 전처리
numAnchors = 9; % 9개의 앵커상자를 추정
[anchors, meanIoU] = estimateAnchorBoxes(trainingDataForEstimation, numAnchors);

 
area = anchors(:, 1) .* anchors(:,2); % 각 앵커상자의 면적을 계산
[~, idx] = sort(area, 'descend'); % 앵커상자를 내림차순으로 정렬하여 크기가 큰 앵커상자가 앞쪽에 오도록 함
anchors = anchors(idx, :);

 
% 앵커상자를 3개의 그룹으로 나누어 anchorBoxes 셀 배열에 저장함.
anchorBoxes = {anchors(1:3, :)
anchors(4:6, :)
anchors(7:9, :)};

 
% YOLO v4 객체검출기를 만듦.
detector = yolov4ObjectDetector("csp-darknet53-coco", className, anchorBoxes, InputSize=inputSize);

 

 

3. 데이터 증강 수행

 

augmentData 함수는 맨 하단의 지원함수 부분 참고
 

augmentedTrainingData = transform(trainingData, @augmentData); % valid와 test 데이터는 증강이 적용되지 않음.

 
augmentedData = cell(4:1);
for k = 1:4
data = read(augmentedTrainingData);
augmentedData{k} = insertShape(data{1}, "rectangle", data{2});
reset(augmentedTrainingData);
end
figure
montage(augmentedData, BorderSize=10)

 

 

 

4. 훈련 옵션 지정

 


options = trainingOptions("adam", ...
GradientDecayFactor=0.9, ...
SquaredGradientDecayFactor=0.999, ...
InitialLearnRate=0.001, ...
LearnRateSchedule="none", ...
MiniBatchSize=4, ...
L2Regularization=0.0005, ...
MaxEpochs=1, ...
BatchNormalizationStatistics="moving", ...
DispatchInBackground=true, ...
ResetInputNormalization=false, ...
Shuffle="every-epoch", ...
VerboseFrequency=20, ...
ValidationFrequency=1000, ...
CheckpointPath=tempdir, ...
ValidationData=validationData);

 

 

5. YOLO v4 객체 검출기 훈련

 

doTraining = True 변경 시, Pretrained된 모델을 다운로드 받는 것이 아닌, 직접 train을 시키게 됨.

이 과정은 70 epoch 기준 6시간이 소요되며 상당한 메모리를 잡아먹음.

 


doTraining = false;
if doTraining
[detect, info] = trainYOLOv4ObjectDetector(augmentedTrainingData, detector, options);
else
detector = downloadPretrainedYOLOv4Detector();
end

 
% 테스트 영상에 대해 검출기를 실행
I = imread('highway.png');
[bboxes, scores, labels] = detect(detector, I);

 
% 결과 표시
I = insertObjectAnnotation(I, 'rectangle', bboxes, scores);
figure
imshow(I)

 

 

 

6. test 세트를 사용하여 검출기 평가

 


% 모든 테스트 영상에 대해 검출기 실행
detectionResults = detect(detector, testData);

 
% 평균정밀도를 멭트릭으로 사용하여 객체 검출기를 평가
[ap, recall, precision] = evaluateDetectionPrecision(detectionResults, testData);

 
% PR 곡선(정밀도/재현율) 플로팅
figure
plot(recall, precision)
xlabel('Recall')
ylabel('Precision')
grid on
title(sprintf("Average Precision = %.2f", ap))

 

 

7. 지원함수

 


function data = augmentData(A)
% Apply random horizontal flipping, and random X/Y scaling. Boxes that get
% scaled outside the bounds are clipped if the overlap is above 0.25. Also,
% jitter image color.

 
data = cell(size(A));
for ii = 1:size(A,1)
I = A{ii,1};
bboxes = A{ii,2};
labels = A{ii,3};
sz = size(I);

 
if numel(sz) == 3 && sz(3) == 3
I = jitterColorHSV(I,...
contrast=0.0,...
Hue=0.1,...
Saturation=0.2,...
Brightness=0.2);
end
 
% Randomly flip image.
tform = randomAffine2d(XReflection=true,Scale=[1 1.1]);
rout = affineOutputView(sz,tform,BoundsStyle="centerOutput");
I = imwarp(I,tform,OutputView=rout);
 
% Apply same transform to boxes.
[bboxes,indices] = bboxwarp(bboxes,tform,rout,OverlapThreshold=0.25);
labels = labels(indices);
 
% Return original data only when all boxes are removed by warping.
if isempty(indices)
data(ii,:) = A(ii,:);
else
data(ii,:) = {I,bboxes,labels};
end
end
end


function data = preprocessData(data,targetSize)
% Resize the images and scale the pixels to between 0 and 1. Also scale the
% corresponding bounding boxes.

 
for ii = 1:size(data,1)
I = data{ii,1};
imgSize = size(I);
 
bboxes = data{ii,2};

 
I = im2single(imresize(I,targetSize(1:2)));
scale = targetSize(1:2)./imgSize(1:2);
bboxes = bboxresize(bboxes,scale);
 
data(ii,1:2) = {I,bboxes};
end
end


function detector = downloadPretrainedYOLOv4Detector()
% Download a pretrained yolov4 detector.
if ~exist("yolov4CSPDarknet53VehicleExample_22a.mat", "file")
if ~exist("yolov4CSPDarknet53VehicleExample_22a.zip", "file")
disp("Downloading pretrained detector...");
websave("yolov4CSPDarknet53VehicleExample_22a.zip", pretrainedURL);
end
unzip("yolov4CSPDarknet53VehicleExample_22a.zip");
end
pretrained = load("yolov4CSPDarknet53VehicleExample_22a.mat");
detector = pretrained.detector;
end