Projektaufbau – Entrauschungs-KI
Aufbau
Dieses Projekt implementiert ein Denoising Convolutional Neural Network (DnCNN) in MATLAB unter Verwendung von Residual Learning. Es dient dazu, Bildrauschen aus digitalen Bildern zu entfernen. Im Gegensatz zu klassischen Ansätzen lernt das Netz hierbei das Rauschen selbst (Residual) und subtrahiert es vom Eingangsbild.
Technische Voraussetzungen
MATLAB mit folgenden Toolboxen:
- Deep Learning Toolbox
- Image Processing Toolbox
- Computer Vision Toolbox
- Parallel Computing Toolbox
Training (DnCnnTrain.m)
Trainiert das neuronale Netz mit Bildern aus dem Ordner ./ImagesForTraining. Dieser Ordner enthält die Trainingsdaten, zusammengestellt aus den Datensätzen BSDS500 und DIV2K.
Funktionsweise
Das Skript prüft, ob Patches existieren, und bietet via Dialog an, neue zu erstellen.
- Daten-Verarbeitung
- Quellen: Bilder werden aus
./ImagesForTraining(und Unterordnern) geladen. - Patch-Extraktion: Bilder werden in 50x50 Pixel große Ausschnitte zerlegt (Stride: 30px, Overlap: 20px).
- Filterung: Nur RGB-Bilder, die größer als die Patches sind, werden verarbeitet.
- Speicherung: Patches werden physisch im Ordner
./PatchesCreatedByThisScriptInOrderToProperlyTrainTheAIabgelegt.
- Quellen: Bilder werden aus
- Datensatz-Split: Die erstellten Patches werden im Verhältnis 90:10 in Trainings- und Validierungsdaten unterteilt (
trainSplit = 0.9) - Noise-Augmentation: Während des Trainings wird dynamisch Rauschen mittels einer Helper-Funktion (
addNoise) hinzugefügt. - Architektur: Ein 15-Layer tiefes CNN mit Residual Learning.
- Optimiser: Verwendet ADAM mit dynamischer Anpassung der Lernrate (Piecewise Drop).
- Training-Modi: Über einen Dialog kann gewählt werden zwischen:
- Train new AI: Startet mit einer Lernrate von
1e-3. - Train old AI: Lädt trainierte AI und setzt das Training mit einer feineren Lernrate von
1e-4fort.
- Speicherung: Das beste Ergebnis (gemessen am Validation-Loss) wird gespeichert. Das finale Netz wird unter
.KIs/Neue_KI.matabgelegt.
Code-Auszug
% --- Grundkonfiguration & Parameter ---
pathToImages = './ImagesForTraining';
patchDirectory = './PatchesCreatedByThisScriptInOrderToProperlyTrainTheAI';
patchSize = 50; % Patch-Größe: 50x50 Pixel
stride = 30; % Versatz (Stride)
trainSplit = 0.9; % 90% Training, 10% Validierung
maxPatchesPerImage = 600; % Max. 600 Patches pro Bild
networkDepth = 15; % Tiefe des Netzwerks
% --- (Code-Abschnitt zur Patch-Erstellung hier ausgeblendet) ---
% ... Bilder werden geladen, geprüft und in Patches zerlegt ...
% --- Datensatz vorbereiten ---
% Lädt alle Patches und konvertiert sie zu Double
allPatches = imageDatastore(patchDirectory, 'ReadFcn', @(f)im2double(imread(f)));
% Zufällige Aufteilung (Split)
numFiles = numel(allPatches.Files);
idx = randperm(numFiles);
trainFiles = allPatches.Files(idx(1:round(trainSplit * numFiles)));
valFiles = allPatches.Files(idx(round(trainSplit * numFiles) + 1:end));
% Datastores mit dynamischem Rauschen (addNoise Funktion) erstellen
dsTrain = transform(imageDatastore(trainFiles), @(x)addNoise(x, true));
dsVal = transform(imageDatastore(valFiles), @(x)addNoise(x, true));
% --- Netzwerk-Architektur & Modus ---
% Abfrage: Neue KI trainieren oder alte fortsetzen?
if strcmp(trainNewOrOldAI, 'Neue KI trainieren')
initialLRate = 1e-3;
% 1. Eingabe-Block (Start)
layers = [
imageInputLayer([patchSize patchSize 3], "Normalization", "none")
convolution2dLayer(3, 64, 'Padding', 'same')
batchNormalizationLayer
reluLayer
];
% 2. Mittlere Layer (Schleife für Tiefe)
for i = 2:(networkDepth-1)
layers = [
layers
convolution2dLayer(3, 64, 'Padding', 'same')
batchNormalizationLayer
reluLayer
];
end
% 3. Ausgabe-Block (Ende)
layers = [
layers
convolution2dLayer(3, 3, "Padding","same")
batchNormalizationLayer
regressionLayer
];
lGraph = layerGraph(layers);
else
% Alte KI laden
loadNet = load('./KIs/Alte_KI.mat');
lGraph = layerGraph(loadNet.net);
initialLRate = 1e-4; % Feinere Lernrate
end
% --- Training Starten ---
options = trainingOptions("adam", ...
'MaxEpochs', 50, ...
'MiniBatchSize', 128, ...
'InitialLearnRate', initialLRate, ...
'LearnRateSchedule', 'piecewise', ...
'LearnRateDropFactor', 0.3, ...
'LearnRateDropPeriod', 12, ...
'ValidationData', dsVal, ...
'OutputNetwork', 'best-validation-loss', ...
'Plots', 'training-progress');
net = trainNetwork(dsTrain, lGraph, options);
save('.KIs/Neue_AI.mat', 'net');
Evaluierung (DnCnnEval.m)
Wendet das trainierte Modell auf neue Bilder im Ordner ./Testbilder an.
Funktionsweise
- Preprocessing: Lädt Bilder und konvertiert Graustufenbilder künstlich in 3-Kanal-Bilder (RGB), um die Kompatibilität mit dem Netz zu gewährleisten.
- Rauschen: Falls das Bild als "sauber" markiert ist, fügt das Skript automatisch Gaußsches Rauschen hinzu.
- Visualisierung: Erstellt eine "Input vs. Output"-Collage.
Code-Auszug
% Modell laden
if ~exist('net', 'var')
data = load("Path/AI_InitialLearnRate_1e-3.mat");
net = data.net;
end
% Rauschen hinzufügen (falls nötig)
if ~isImageNoisy
imgDouble = imnoise(imgDouble, "gaussian", 0, 0.03);
end
% Entrauschen
imgRestored = denoiseImages(net, imgDouble, 50, 50/2, true);
% Collage erstellen (Input | Separator | Output)
separatorWidth = 20;
separator = ones(h, separatorWidth, 3);
collage = [imgDouble, separator, imgRestored];
% Beschriftung einfügen
textLabels = {'Input', 'Output'};
positions = [10, 10; (w + separatorWidth + 10), 10];
collage = insertText(collage, positions, textLabels, ...
'FontSize', max(20, round(h/25)), ...
'BoxColor', 'white', ...
'BoxOpacity', 0.7);
imwrite(collage, saveName);
Rausch-Generator Tool (DnCNNNoise.m)
Ein Hilfsskript, um einen kompletten Ordner von Bildern permanent zu verrauschen, falls Testdaten benötigt werden.
Funktionsweise & Code
Nutzt eine grafische Oberfläche (GUI) zur Ordnerauswahl und die Image Processing Toolbox (imnoise), um mathematisch exaktes Rauschen hinzuzufügen.
% User Interface für Auswahl
noiseChoice = questdlg('Which noise for ALL images?', 'Noise Type', ...
'Salt & Pepper', 'Gaussian', 'Speckle', 'Gaussian');
% Rauschen anwenden
switch noiseChoice
case 'Salt & Pepper'
% Fügt "Salz und Pfeffer"-Rauschen hinzu (Dichte: 0.05)
imgNoisy = imnoise(img, 'salt & pepper', 0.05);
case 'Gaussian'
% Fügt Gaußsches Rauschen hinzu (Mittelwert 0, Varianz 0.01)
imgNoisy = imnoise(img, 'gaussian', 0, 0.01);
case 'Speckle'
% Fügt multiplikatives Rauschen hinzu (Varianz 0.04)
imgNoisy = imnoise(img, 'speckle', 0.04);
end
Quellen
- P. Arbeláez, M. Maire, C. Fowlkes and J. Malik, "Contour Detection and Hierarchical Image Segmentation," in IEEE Transactions on Pattern Analysis and Machine Intelligence, vol. 33, no. 5, pp. 898-916, May 2011, doi: 10.1109/TPAMI.2010.161. keywords: {Image segmentation;Pixel;Detectors;Image edge detection;Humans;Histograms;Benchmark testing;Contour detection;image segmentation;computer vision.}
- R. Timofte, S. Gu, J. Wu, L. Van Gool, L. Zhang, M.-H. Yang, M. Haris et al., "NTIRE 2018 Challenge on Single Image Super-Resolution: Methods and Results," in The IEEE Conference on Computer Vision and Pattern Recognition (CVPR) Workshops, June 2018.