main
Vigoleis Hühn 1 year ago
parent 2097f55bb9
commit 32fa7ffa9a

Binary file not shown.

After

Width:  |  Height:  |  Size: 824 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 157 KiB

@ -0,0 +1,237 @@
% 2022-12-29
% script for training/evalutaing faster- RCNN for Traficsign discovery
% with data provided in PicturesResizedLabelsResizedSignsCutted.zip
% based on script from the lecture
% Requirements:
% data has to be provided as PicturesResizedLabelsResizedSignsCutted.zip
% in script location
% (this script unzips data and renames two files, but there is unlabeled
% image-material, that has to be removed by hand after unzipping)
% additional scriptfiles:
% - func_setupData.m
% unpack data etc.
% - func_groundTruthFromLabelPic.m
% (generate groundtruthtablle from image-data)
% - augmentData.m
% (dataaugmentation für RCNN)
% - helperSanitizeBoxes.m
% (part of augmentation)
% - preprocessData.m
% (Resize image and bounding boxes to targetSize.
%
% required add-on(s):
% - 'Deep Learning Toolbox Model for ResNet-50 Network'
% - 'image processing toolbox'
% - 'Computer Vision Toolbox '
% recommended add-on(s) - if gpu is apt for the job....
% - 'Parallel Computing Toolbox'
% adjustable parameters
% - if there is no trained net, it can be trained with this script:
% set doTraining to true
% - the training can use augmentation or not:
% set doAugmentation accordingly
close all;
clear;
doTraining = false;
doAugmentation = false;
% first we need the data...
dataDir = 'Picturedata'; % Destination-Folder for provided (img) Data
zippedDataFile = 'PicturesResizedLabelsResizedSignsCutted.zip'; %Data provided by TA
grDataFile = 'signDatasetGroundTruth.mat';
func_setupData(dataDir, zippedDataFile, grDataFile);
%load data
data = load(grDataFile);
traficSignDataset = data.DataSet;
% ----- split the dataset into training, validation, and test sets.
% Select 60% of the data for training, 10% for validation, and the
% rest for testing the trained detector
rng(0)
shuffledIndices = randperm(height(traficSignDataset));
idx = floor(0.6 * height(traficSignDataset));
trainingIdx = 1:idx;
trainingDataTbl = traficSignDataset(shuffledIndices(trainingIdx),:);
validationIdx = idx+1 : idx + 1 + floor(0.1 * length(shuffledIndices) );
validationDataTbl = traficSignDataset(shuffledIndices(validationIdx),:);
testIdx = validationIdx(end)+1 : length(shuffledIndices);
testDataTbl = traficSignDataset(shuffledIndices(testIdx),:);
% ----- use imageDatastore and boxLabelDatastore to create datastores
% for loading the image and label data during training and evaluation.
imdsTrain = imageDatastore(trainingDataTbl{:,'imageFilename'});
bldsTrain = boxLabelDatastore(trainingDataTbl(:,'sign'));
imdsValidation = imageDatastore(validationDataTbl{:,'imageFilename'});
bldsValidation = boxLabelDatastore(validationDataTbl(:,'sign'));
imdsTest = imageDatastore(testDataTbl{:,'imageFilename'});
bldsTest = boxLabelDatastore(testDataTbl(:,'sign'));
% combine image and box label datastores.
trainingData = combine(imdsTrain,bldsTrain); % erzeugt 'CombinedDatastore
validationData = combine(imdsValidation,bldsValidation);
testData = combine(imdsTest,bldsTest);
% display one of the training images and box labels.
data = read(trainingData);
I = data{1};
bbox = data{2};
annotatedImage = insertShape(I,'Rectangle',bbox);
annotatedImage = imresize(annotatedImage,4); % nur fuer Darstellung
figure
imshow(annotatedImage)
% ----- Create Faster R-CNN Detection Network
inputSize = [224 224 3];
preprocessedTrainingData = transform(trainingData, @(data)preprocessData(data,inputSize));
% Achtung: dieser DS wird nur zur Ermittlung der BoundingBoxes verwendet
% display one of the training images and box labels.
while 1==0 %hasdata(preprocessedTrainingData)
data = read(preprocessedTrainingData);
I = data{1};
bbox = data{2};
annotatedImage = insertShape(I,'Rectangle',bbox);
annotatedImage = imresize(annotatedImage,4); % nur fuer Darstellung
figure(1)
imshow(annotatedImage)
pause(0.100)
end
% Auswahl der anchor boxes
% Infos dazu: https://de.mathworks.com/help/vision/ug/estimate-anchor-boxes-from-training-data.html
numAnchors = 3;
anchorBoxes = estimateAnchorBoxes(preprocessedTrainingData,numAnchors);
% und das feature CNN
featureExtractionNetwork = resnet50;
featureLayer = 'activation_40_relu';
numClasses = width(traficSignDataset)-1; % also hier: 1, es sollen nur Verkehrsschilder erkannt werden
lgraph = fasterRCNNLayers(inputSize,numClasses,anchorBoxes,featureExtractionNetwork,featureLayer);
% Netzwerk ansehen
% analyzeNetwork(lgraph)
if doAugmentation
augmentedTrainingData = transform(trainingData,@augmentData);
trainingData = transform(augmentedTrainingData,@(data)preprocessData(data,inputSize));
validationData = transform(validationData,@(data)preprocessData(data,inputSize));
end
options = trainingOptions('sgdm',...
'MaxEpochs',10,...
'MiniBatchSize',2,...
'InitialLearnRate',1e-3,...
'CheckpointPath',tempdir,...
'ValidationData',validationData);
netname = "netDetectorResNet50.mat"
if doAugmentation
netname = "netDetectorResNet50_2.mat"
end
if doTraining
% Train the Faster R-CNN detector.
% * Adjust NegativeOverlapRange and PositiveOverlapRange to ensure
% that training samples tightly overlap with ground truth.
[detector, info] = trainFasterRCNNObjectDetector(trainingData,lgraph,options, ...
'NegativeOverlapRange',[0 0.3], ...
'PositiveOverlapRange',[0.6 1]);
save netname detector;
else
% Load pretrained detector for the example.
load netname detector;
end
% ----- quick check/test
I = imresize(I,inputSize(1:2));
[bboxes,scores] = detect(detector,I);
% Display the results.
sfigTitle = ""
if height(bboxes) > 0
I = insertObjectAnnotation(I,'rectangle',bboxes,scores);
sfigTitle = "Detected";
else
sfigTitle = "Not Detected";
end
figure;
imshow(I);
annotation('textbox', [0.5, 0.2, 0.1, 0.1], 'String', sfigTitle)
% ----- Testing
testData = transform(testData,@(data)preprocessData(data,inputSize));
% Run the detector on all the test images.
detectionResults = detect(detector,testData,'MinibatchSize',4);
% Evaluate the object detector using the average precision metric.
[ap, recall, precision] = evaluateDetectionPrecision(detectionResults,testData);
% The precision/recall (PR) curve highlights how precise a detector is at varying levels of recall. The ideal precision is 1 at all recall levels. The use of more data can help improve the average precision but might require more training time. Plot the PR curve.
figure
plot(recall,precision)
xlabel('Recall')
ylabel('Precision')
grid on
title(sprintf('Average Precision = %.2f', ap))
% ----- Helper functions
% function data = augmentData(data)
% % Randomly flip images and bounding boxes horizontally.
% tform = randomAffine2d('XReflection',true);
% sz = size(data{1});
% rout = affineOutputView(sz,tform);
% data{1} = imwarp(data{1},tform,'OutputView',rout);
%
% % Sanitize box data, if needed.
% data{2} = helperSanitizeBoxes(data{2}, sz);
%
% % Warp boxes.
% data{2} = bboxwarp(data{2},tform,rout);
% end
%
% function data = preprocessData(data,targetSize)
% % Resize image and bounding boxes to targetSize.
% sz = size(data{1},[1 2]);
% scale = targetSize(1:2)./sz;
% data{1} = imresize(data{1},targetSize(1:2));
%
% % Sanitize box data, if needed.
% data{2} = helperSanitizeBoxes(data{2}, sz);
%
% % Resize boxes.
% data{2} = bboxresize(data{2},scale);
% end

@ -1,2 +1,9 @@
# HA_DIGSIG
## Hauptscriptfiles:
- RCNN_for_traficsigns.m
(kann über parameter `dotraining` zum trainieren oder nur analysieren des RCNN-Netzes verwendet werden)
- test.m
(liest ein image ein und wendet das Netz darauf an)

@ -0,0 +1,13 @@
function data = augmentData(data)
% Randomly flip images and bounding boxes horizontally.
tform = randomAffine2d('XReflection',true);
sz = size(data{1});
rout = affineOutputView(sz,tform);
data{1} = imwarp(data{1},tform,'OutputView',rout);
% Sanitize box data, if needed.
data{2} = helperSanitizeBoxes(data{2}, sz);
% Warp boxes.
data{2} = bboxwarp(data{2},tform,rout);
end

@ -0,0 +1,120 @@
function [ ] = func_groundTruthFromLabelPic( dataStorePicturePath, dataStoreLabelPath, outFile )
%
% erstellt us einem Picture-Datastore und einem Label-Datastore
% eine Groundtruth-Tabelle, wie sie z.B. in FasterRCNN.m
% benoetigt wird
%
% file von tas
% adaptiert als func 2022/12/28 vh
%
labelDS = imageDatastore(dataStoreLabelPath, 'IncludeSubfolders', true);
pictureDS = imageDatastore(dataStorePicturePath, 'IncludeSubfolders', true);
labelCount = numel(labelDS.Files)
pictureCount = numel(pictureDS.Files)
if labelCount ~= pictureCount
fprintf("!!!! Error: Die Anzahl der Bilder und Anzahl der LabelPicture sind ungleich -> Abbruch");
return
end
fprintf("-----------------------------------------------------------\n");
fprintf("Picture-Verzeichnis: %s\n", dataStorePicturePath)
fprintf("Anzahl Images: %d\n", pictureCount)
fprintf("Label-Verzeichnis: %s\n", dataStoreLabelPath)
fprintf("Anzahl Images: %d\n", labelCount)
fprintf("BE PATIENT.... \n")
fprintf("-----------------------------------------------------------\n");
% table anlegen
sz = [pictureCount 3];
varTypes = ["cellstr","cell","logical"];
varNames = ["imageFilename","sign","valid"];
DataSet = table('Size',sz,'VariableTypes',varTypes,'VariableNames',varNames);
rng(0)
shuffledIndices = randperm(pictureCount);
% los gehts
for i = 1:pictureCount
shuffeldIndex = shuffledIndices(i);
[imPic imPic_INFO]= readimage(pictureDS, shuffeldIndex);
[im_path imPic_name im_ext]=fileparts(imPic_INFO.Filename);
[imLabel imLabel_INFO]= readimage(labelDS, shuffeldIndex);
[im_path imLabel_name im_ext]=fileparts(imLabel_INFO.Filename);
% fprintf("picture: %s label: %s\n", imPic_name, imLabel_name);
box = [0,0,0,0]; %default if theres no labelimg
v = true;
if ~strcmp(imPic_name, imLabel_name)
fprintf("!!!! Error: zum Picture gibt es kein entsprechendes LabelPicture -> Abbruch");
imPic_name
imLabel_name
else
% LabelRegion aus Image ausschneiden
bw = imLabel;
s = regionprops(bw, 'BoundingBox');
box = cat(1, s.BoundingBox); % structure to matrix
box = round(box);
% falls mehrere Marker vorhanden sind, ignorieren wir den Datensatz
% das dürfte für das Training Region detection besser sein.
if (height(box) > 1)
v = false;
end
box = box(1,:);
if (numel(box) ~= 4)
fprintf("Boxkoordinaten nicht ok: %s %s\n", imPic_name, imLabel_name)
box
v = false
end
end
a = num2cell(box, 2);
%check for boxes which are somewhat wrong
if v
if (box(3) < 8.) ...
|| (box(4) < 8.) ...
|| (abs(box(3) - box(4)) > 2) ...
|| (box(1) + box(3) > 1024) ...
|| (box(2) + box(4) > 768)
fprintf("boxkoordinaten nicht i.o. %s (%d %d %d %d) \n", imLabel_name, box(1),box(2),box(3),box(4));
v = false;
end
end
DataSet(shuffeldIndex,:) = {imPic_INFO.Filename,a, v};
% display one of the training images and box labels.
if (shuffeldIndex == 4)
annotatedImage = insertShape(imPic,'Rectangle',box);
figure
imshow(annotatedImage)
end
end
%Die Daten sind teilweise nicht in Ordnung, am einfachsten ist natürlich
%die Einträge zu löschen, die nicht gut sind.
fprintf("Groundtruth hat %d eintraege vor der Bereinigung \n ", height(DataSet) )
toDelete = DataSet.valid == false;
DataSet(toDelete,:) = [];
DataSet.valid=[];
fprintf("Groundtruth hat %d eintraege nach der Bereinigung \n", height(DataSet) )
save(outFile, 'DataSet' );

@ -0,0 +1,43 @@
function [ ] = func_setupData( dataDir, zippedDataFile, grDataFile )
% script func_setupData:
% - entpackt die trainingsdaten,
% - räumt ein bisschen auf, bzw. liefert Hinweise zum aufräumen
% - erstellt grounddata
% - (alles nur, falls es das nicht schon gibt)
if not(exist(dataDir , 'dir'))
% unzip data
if (not(exist(zippedDataFile , 'file')))
fprintf("Data file is missing please copy %s to script folder !", zippedDataFile);
return;
end
fprintf("unzipping Data");
unzip (zippedDataFile, dataDir)
%rename files correctly (there are two wrong):
fprintf("fix faulty falenames\n");
movefile (append(dataDir, '/Labels_1024_768/60GBS/60GBS_Gruppe05_SS21_Nr49.png'), append(dataDir, '/Labels_1024_768/60GBS/60GBS_Gruppe05_SS21_49.png'));
movefile (append(dataDir, '/Labels_1024_768/60GBS/60GBS_Gruppe05_SS21_Nr50.png'), append(dataDir, '/Labels_1024_768/60GBS/60GBS_Gruppe05_SS21_50.png'));
fprintf("Labeldata is incomplete\n");
fprintf("please compare data in keinGBS and delete what's to much manually\n");
fprintf("otherwise grounddatageneration will fail\n");
frpintf("then restart script \n");
return;
end
% generate Grounddata from Pictures
if (not(exist(grDataFile , 'file')))
dataStorePicturePath = append(pwd,'/', dataDir,'/Pictures_1024_768/');
dataStoreLabelPath = append(pwd,'/', dataDir, '/Labels_1024_768/');
% Die Tabelle wird in einer Funktion erstellt und gespeichert
% dabei werden Datensätze, wo die Label nicht passen entfernt.
func_groundTruthFromLabelPic(dataStorePicturePath, dataStoreLabelPath, grDataFile);
end

@ -0,0 +1,43 @@
%helperSanitizeBoxes Sanitize box data.
% This example helper is used to clean up invalid bounding box data. Boxes
% with values <= 0 are removed and fractional values are rounded to
% integers.
%
% If none of the boxes are valid, this function passes the data through to
% enable downstream processing to issue proper errors.
% Copyright 2020 The Mathworks, Inc.
function boxes = helperSanitizeBoxes(boxes, imageSize)
persistent hasInvalidBoxes
valid = all(boxes > 0, 2);
if any(valid)
if ~all(valid) && isempty(hasInvalidBoxes)
% Issue one-time warning about removing invalid boxes.
hasInvalidBoxes = true;
warning('Removing ground truth bouding box data with values <= 0.')
end
boxes = boxes(valid,:);
boxes = roundFractionalBoxes(boxes, imageSize);
end
end
function boxes = roundFractionalBoxes(boxes, imageSize)
% If fractional data is present, issue one-time warning and round data and
% clip to image size.
persistent hasIssuedWarning
allPixelCoordinates = isequal(floor(boxes), boxes);
if ~allPixelCoordinates
if isempty(hasIssuedWarning)
hasIssuedWarning = true;
warning('Rounding ground truth bounding box data to integer values.')
end
boxes = round(boxes);
boxes(:,1:2) = max(boxes(:,1:2), 1);
boxes(:,3:4) = min(boxes(:,3:4), imageSize([2 1]));
end
end

Binary file not shown.

Binary file not shown.

@ -0,0 +1,12 @@
function data = preprocessData(data,targetSize)
% Resize image and bounding boxes to targetSize.
sz = size(data{1},[1 2]);
scale = targetSize(1:2)./sz;
data{1} = imresize(data{1},targetSize(1:2));
% Sanitize box data, if needed.
data{2} = helperSanitizeBoxes(data{2}, sz);
% Resize boxes.
data{2} = bboxresize(data{2},scale);
end

Binary file not shown.

@ -0,0 +1,66 @@
% Testscript um ein Bild aus den Daten durch die Netze laufen zu lassen
close all;
clear;
%die netze mit besserer Erkennung _2
RCCN_NET = 'netDetectorResNet50_2.mat';
inputSize = [224 224 3];
% first we need the data...
dataDir = 'Picturedata'; % Destination-Folder for provided (img) Data
zippedDataFile = 'PicturesResizedLabelsResizedSignsCutted.zip'; %Data provided by TA
grDataFile = 'signDatasetGroundTruth.mat';
func_setupData(dataDir, zippedDataFile, grDataFile);
%load data
grdata = load(grDataFile);
traficSignDataset = grdata.DataSet;
%Random Index
%shuffledIndices = randperm(height(traficSignDataset));
%testindx = shuffledIndices(1)
testindx = 7
% Bild einlesen
imgname = traficSignDataset.imageFilename{testindx}
I = imresize(imread(imgname),inputSize(1:2));
%RCCN-Detector laden
pretrained = load(RCCN_NET);
detector = pretrained.detector;
[bboxes,scores] = detect(detector,I);
sfigTitle = ""
bdetected = height(bboxes) > 0;
if bdetected
I = insertObjectAnnotation(I,'rectangle',bboxes,scores);
sfigTitle = "Detected";
else
sfigTitle = "Not Detected";
end
figure;
imshow(I);
annotation('textbox', [0.5, 0.2, 0.1, 0.1], 'String', sfigTitle)
%ggf. bild zuschneiden
if bdetected
icrop = imcrop(I , bboxes);
figure;
imshow(icrop);
%todo durch zweites Netz schicken
%todo achtung, evtl. muss das originalbild nochmal genommen werden
%und die Boxwerte passend umgerechnet
end
Loading…
Cancel
Save