diff --git a/.idea/editor.xml b/.idea/editor.xml
new file mode 100644
index 0000000..45a9ffc
--- /dev/null
+++ b/.idea/editor.xml
@@ -0,0 +1,341 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/workspace.xml b/.idea/workspace.xml
new file mode 100644
index 0000000..5533b38
--- /dev/null
+++ b/.idea/workspace.xml
@@ -0,0 +1,128 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {
+ "associatedIndex": 5
+}
+
+
+
+
+
+ {
+ "keyToString": {
+ "RunOnceActivity.RadMigrateCodeStyle": "true",
+ "RunOnceActivity.ShowReadmeOnStart": "true",
+ "RunOnceActivity.cidr.known.project.marker": "true",
+ "RunOnceActivity.git.unshallow": "true",
+ "RunOnceActivity.readMode.enableVisualFormatting": "true",
+ "cf.first.check.clang-format": "false",
+ "cidr.known.project.marker": "true",
+ "git-widget-placeholder": "main",
+ "last_opened_file_path": "C:/Users/Silvana/NeuronalesNetz",
+ "node.js.detected.package.eslint": "true",
+ "node.js.detected.package.tslint": "true",
+ "node.js.selected.package.eslint": "(autodetect)",
+ "node.js.selected.package.tslint": "(autodetect)",
+ "nodejs_package_manager_path": "npm",
+ "vue.rearranger.settings.migration": "true"
+ }
+}
+
+
+
+
+ 1762940933833
+
+
+ 1762940933833
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ file://$PROJECT_DIR$/imageInput.c
+
+
+
+
+
+
\ No newline at end of file
diff --git a/imageInput.c b/imageInput.c
index bb30de1..f987e39 100644
--- a/imageInput.c
+++ b/imageInput.c
@@ -6,17 +6,209 @@
#define BUFFER_SIZE 100
#define FILE_HEADER_STRING "__info2_image_file_format__"
-// TODO Implementieren Sie geeignete Hilfsfunktionen für das Lesen der Bildserie aus einer Datei
-// TODO Vervollständigen Sie die Funktion readImages unter Benutzung Ihrer Hilfsfunktionen
+/*
+ * Diese Hilfsfunktionen kümmern sich um:
+ * - Das Öffnen der Datei und Überprüfen des Dateinamens
+ * - Das Überprüfen des Headers, um sicherzustellen, dass es sich um die richtige Datei handelt
+ * - Das Einlesen der Metadaten (Anzahl der Bilder, Bildbreite und -höhe)
+ * -> Die Hilfsfunktionen garantieren, dass die Datei gültig ist, bevor mit dem Einlesen der Bilddaten fortgefahren wird.
+ */
+
+
+static FILE *openImageFile(const char *path) // Checks if the given filename pointer is valid (not NULL).
+{
+ if (path == NULL)
+ {
+ return NULL;
+ }
+
+ return fopen(path, "rb"); //opening document in binear
+}
+
+static int readAndCheckHeader(FILE *file) // gets the length of the header text
+{
+ size_t headerLength = strlen(FILE_HEADER_STRING);
+ char buffer[BUFFER_SIZE];
+
+ if (headerLength + 1 > BUFFER_SIZE) //checks if buffer is big enough for header size
+ {
+ return 0;
+ }
+
+ if (fread(buffer, 1, headerLength, file) != headerLength) // Checks if reading the expected number of header bytes from the file succeeded
+ {
+ return 0;
+ }
+
+ buffer[headerLength] = '\0'; // add string terminator so the header becomes a valid C-string
+
+ if (strcmp(buffer, FILE_HEADER_STRING) != 0) // checks if the expected header matches the header read from the file
+ {
+ return 0;
+ }
+
+ return 1; /* Header ok */
+}
+
+
+static int readImageMetaData(FILE *file, // reads the metadata (count, width, height) from the file and stores them in the provided pointers
+ unsigned short *count,
+ unsigned short *width,
+ unsigned short *height)
+{
+ if (fread(count, sizeof(unsigned short), 1, file) != 1) // read the number of images from the file
+ {
+ return 0;
+ }
+ if (fread(width, sizeof(unsigned short), 1, file) != 1) // reads the image width
+ {
+ return 0;
+ }
+ if (fread(height, sizeof(unsigned short), 1, file) != 1) //reads the image height
+ {
+ return 0;
+ }
+
+ if (*count == 0 || *width == 0 || *height == 0) // check for invalid metadata (count, width or height cannot be zero)
+ {
+ return 0;
+ }
+
+ return 1;
+}
+
+
+/*
+ Hauptfunktion
+*/
GrayScaleImageSeries *readImages(const char *path)
{
- GrayScaleImageSeries *series = NULL;
-
+ // 1. Open the file
+ FILE *file = openImageFile(path);
+ if (file == NULL)
+ {
+ return NULL;
+ }
+
+ // 2. Check the header
+ if (!readAndCheckHeader(file))
+ {
+ fclose(file);
+ return NULL;
+ }
+
+ // 3. Read image metadata
+ unsigned short count = 0;
+ unsigned short width = 0;
+ unsigned short height = 0;
+
+ if (!readImageMetaData(file, &count, &width, &height))
+ {
+ fclose(file);
+ return NULL;
+ }
+
+ // 4. Allocate memory for image series
+ GrayScaleImageSeries *series = (GrayScaleImageSeries *)malloc(sizeof(GrayScaleImageSeries)); // Allocate memory for the image series, images, and labels. Return NULL if allocation fails.
+ if (series == NULL)
+ {
+ fclose(file);
+ return NULL;
+ }
+
+ series->count = count;
+ series->images = (GrayScaleImage *)calloc(count, sizeof(GrayScaleImage));
+ series->labels = (unsigned char *)malloc(count * sizeof(unsigned char));
+
+ if (series->images == NULL || series->labels == NULL)
+ {
+ free(series->images);
+ free(series->labels);
+ free(series);
+ fclose(file);
+ return NULL;
+ }
+
+ // 5. Read the images and labels
+ for (unsigned int i = 0; i < count; i++)
+ {
+ GrayScaleImage *image = &series->images[i];
+
+ image->width = (unsigned int)width;
+ image->height = (unsigned int)height;
+
+ size_t numPixels = (size_t)width * (size_t)height;
+
+ image->buffer = (GrayScalePixelType *)malloc(numPixels * sizeof(GrayScalePixelType));
+ if (image->buffer == NULL)
+ {
+ for (unsigned int j = 0; j < i; j++)
+ {
+ free(series->images[j].buffer);
+ }
+ free(series->images);
+ free(series->labels);
+ free(series);
+ fclose(file);
+ return NULL;
+ }
+
+ if (fread(image->buffer, sizeof(GrayScalePixelType), numPixels, file) != numPixels) // Check if the correct number of pixel values (width * height) were read for the image
+ {
+ for (unsigned int j = 0; j <= i; j++)
+ {
+ free(series->images[j].buffer);
+ }
+ free(series->images);
+ free(series->labels);
+ free(series);
+ fclose(file);
+ return NULL;
+ }
+
+ if (fread(&series->labels[i], sizeof(unsigned char), 1, file) != 1) // Check if the label for the image was successfully read (1 byte)
+ {
+ for (unsigned int j = 0; j <= i; j++)
+ {
+ free(series->images[j].buffer);
+ }
+ free(series->images);
+ free(series->labels);
+ free(series);
+ fclose(file);
+ return NULL;
+ }
+ }
+
+ fclose(file);
return series;
}
// TODO Vervollständigen Sie die Funktion clearSeries, welche eine Bildserie vollständig aus dem Speicher freigibt
void clearSeries(GrayScaleImageSeries *series)
{
-}
\ No newline at end of file
+ if (series == NULL)
+ {
+ return;
+ }
+
+ if (series->images != NULL)
+ {
+ for (unsigned int i = 0; i < series->count; i++)
+ {
+ free(series->images[i].buffer);
+ series->images[i].buffer = NULL;
+ }
+ free(series->images);
+ series->images = NULL;
+ }
+
+ if (series->labels != NULL)
+ {
+ free(series->labels);
+ series->labels = NULL;
+ }
+
+ free(series);
+}
diff --git a/matrix.c b/matrix.c
index ad00628..9b27187 100644
--- a/matrix.c
+++ b/matrix.c
@@ -6,30 +6,148 @@
Matrix createMatrix(unsigned int rows, unsigned int cols)
{
-
+ if(rows && cols){
+ Matrix matrix;
+ matrix.rows = rows;
+ matrix.cols = cols;
+ matrix.buffer = malloc(rows * cols * sizeof(MatrixType));
+
+ matrix.buffer = malloc(rows * cols * sizeof(MatrixType));
+ if (!matrix.buffer) {
+ matrix.rows = 0;
+ matrix.cols = 0;
+ return matrix; // malloc ist fehlgeschlagen
+ }
+
+
+ for (int i = 0; i < (rows * cols); i++)
+ matrix.buffer[i] = 0;
+
+ return matrix;
+ }
+ Matrix matrix;
+ matrix.rows = 0;
+ matrix.cols = 0;
+ matrix.buffer = 0;
+ return matrix;
}
+
void clearMatrix(Matrix *matrix)
{
-
+ free(matrix->buffer);
+ matrix->buffer = NULL;
+ matrix->rows = 0;
+ matrix->cols = 0;
}
void setMatrixAt(MatrixType value, Matrix matrix, unsigned int rowIdx, unsigned int colIdx)
{
-
+ matrix.buffer[rowIdx * matrix.cols + colIdx] = value;
}
MatrixType getMatrixAt(const Matrix matrix, unsigned int rowIdx, unsigned int colIdx)
{
-
+ if(rowIdx >= matrix.rows || colIdx >= matrix.cols){
+ return UNDEFINED_MATRIX_VALUE;
+ }
+ return matrix.buffer[rowIdx * matrix.cols + colIdx];
}
Matrix add(const Matrix matrix1, const Matrix matrix2)
{
-
+ int rows1 = rows(matrix1);
+ int rows2 = rows(matrix2);
+ int cols1 = cols(matrix1);
+ int cols2 = cols(matrix2);
+ if((cols1 == 1 || cols2 == 1) && rows1 == rows2) //Broadcasting
+ {
+ if(cols1 == 1) //Wenn die erste Matrix der Vektor ist
+ {
+ return broadcasting(matrix1, matrix2);
+ }
+ else
+ {
+ return broadcasting(matrix2, matrix1);
+ }
+ }
+ else if(rows1 == rows2 && cols1 == cols2) //Addition nur moeglich, wenn beide Matrizen gleiche ANzahl an Zeilen und Spalten haben
+ {
+ Matrix addition = createMatrix(rows1, cols2); //Matrix erstellt, in die die addierten Werte geschrieben werden
+ MatrixType wert1;
+ MatrixType wert2;
+ for(int i = 0; i < rows1; i++){ //soll fuer jedes Element durchlaufen, sodass alle Werte von beiden Matrizen aufaddiert werden.
+ for(int j = 0; j < cols1; j++){
+ wert1 = getMatrixAt(matrix1, i, j);
+ wert2 = getMatrixAt(matrix2, i, j);
+ MatrixType addierterWert = wert1 + wert2;
+ setMatrixAt(addierterWert, addition, i, j);
+ }
+ }
+ return addition;
+ }
+ else{
+ return createMatrix(0,0);
+ }
}
+Matrix broadcasting(const Matrix vektor, const Matrix matrix)
+ {
+ int rowsM = rows(matrix);
+ int colsM = cols(matrix);
+ Matrix result = createMatrix(rowsM, colsM);
+ MatrixType wert;
+ MatrixType koordinate;
+ for(int i = 0; i < rowsM; i++)
+ {
+ for(int j = 0; j < colsM; j++){
+ wert = getMatrixAt(matrix, i, j);
+ koordinate = getMatrixAt(vektor, i, 0);
+ setMatrixAt((koordinate + wert), result, i, j);
+ }
+ }
+ return result;
+ }
+
Matrix multiply(const Matrix matrix1, const Matrix matrix2)
{
-
+ int rows1 = rows(matrix1);
+ int cols1 = cols(matrix1);
+ int rows2 = rows(matrix2);
+ int cols2 = cols(matrix2);
+ if(cols1 == rows2) //Bedingung fuer Multiplikation: Spalten der ersten Matrix gleich Zeilen 2. Matrix
+ {
+ Matrix result = createMatrix(rows1, cols2);
+ MatrixType wert1;
+ MatrixType wert2;
+ MatrixType mul;
+ MatrixType add = 0;
+ for(int i = 0; i < rows1; i++)
+ {
+ for(int k = 0; k < cols2; k++)
+ {
+ for(int j = 0; j < cols1; j++)
+ {
+ wert1 = getMatrixAt(matrix1, i, j);
+ wert2 = getMatrixAt(matrix2, j, k);
+ mul = wert1 * wert2;
+ add += mul;
+ }
+ setMatrixAt(add, result, i, k);
+ add = 0;
+ }
+ }
+ return result;
+ }
+ return createMatrix(0,0);
+}
+
+int rows(const Matrix matrix)
+{
+ return matrix.rows;
+}
+
+int cols(const Matrix matrix)
+{
+ return matrix.cols;
}
\ No newline at end of file
diff --git a/matrix.h b/matrix.h
index cc640d1..dfe05c9 100644
--- a/matrix.h
+++ b/matrix.h
@@ -6,6 +6,11 @@
typedef float MatrixType;
// TODO Matrixtyp definieren
+typedef struct{
+ unsigned int rows;
+ unsigned int cols;
+ MatrixType *buffer; //Data wird in einem eindimensionalen Array gespeichert (Spalten und Reihen liegen ja im Speicher hintereinannder)
+} Matrix;
Matrix createMatrix(unsigned int rows, unsigned int cols);
@@ -13,7 +18,10 @@ void clearMatrix(Matrix *matrix);
void setMatrixAt(MatrixType value, Matrix matrix, unsigned int rowIdx, unsigned int colIdx);
MatrixType getMatrixAt(const Matrix matrix, unsigned int rowIdx, unsigned int colIdx);
Matrix add(const Matrix matrix1, const Matrix matrix2);
+Matrix broadcasting(const Matrix matrix1, const Matrix matrix2);
Matrix multiply(const Matrix matrix1, const Matrix matrix2);
+int rows(const Matrix matrix);
+int cols(const Matrix matrix);
#endif
diff --git a/neuralNetwork.c b/neuralNetwork.c
index bd8f164..5bec5b4 100644
--- a/neuralNetwork.c
+++ b/neuralNetwork.c
@@ -170,7 +170,7 @@ NeuralNetwork loadModel(const char *path)
static Matrix imageBatchToMatrixOfImageVectors(const GrayScaleImage images[], unsigned int count)
{
- Matrix matrix = {NULL, 0, 0};
+ Matrix matrix = {0,0, NULL};
if(count > 0 && images != NULL)
{
diff --git a/neuralNetwork.h b/neuralNetwork.h
index 7f06607..78a6102 100644
--- a/neuralNetwork.h
+++ b/neuralNetwork.h
@@ -1,6 +1,8 @@
#ifndef NEURALNETWORK_H
#define NEURALNETWORK_H
+#define FILE_HEADER_STRING "__info2_neural_network_file_format__"
+
#include "imageInput.h"
#include "matrix.h"
diff --git a/neuralNetworkTests.c b/neuralNetworkTests.c
index 21ab370..f87cee9 100644
--- a/neuralNetworkTests.c
+++ b/neuralNetworkTests.c
@@ -6,11 +6,44 @@
#include "neuralNetwork.h"
+//Testdatei schreiben
static void prepareNeuralNetworkFile(const char *path, const NeuralNetwork nn)
{
- // TODO
+// Datei öffnen
+FILE *file = fopen(path, "wb");
+if (file == NULL)
+return;
+
+// Header schreiben
+const char *fileTag = "__info2_neural_network_file_format__";
+fwrite(fileTag, 1, strlen(fileTag), file);
+
+// input Dimension schreiben
+int inputDim = nn.layers[0].weights.cols;
+fwrite(&inputDim, sizeof(int), 1, file);
+
+// für weiter Layer nur output Dimension schreiben
+for (unsigned int i = 0; i < nn.numberOfLayers; i++)
+{
+ int outputDim = nn.layers[i].weights.rows;
+ fwrite(&outputDim, sizeof(int), 1, file);
+
+ int weightCount = nn.layers[i].weights.rows * nn.layers[i].weights.cols;
+ fwrite(nn.layers[i].weights.buffer, sizeof(MatrixType), weightCount, file);
+
+ int biasesCount = nn.layers[i].biases.rows * nn.layers[i].biases.cols;
+ fwrite(nn.layers[i].biases.buffer, sizeof(MatrixType), biasesCount, file);
}
+// Ende: loadModel liest 0 ein
+int fileEnd = 0;
+fwrite(&fileEnd, sizeof(int), 1, file);
+
+// Datei schließen
+fclose(file);
+}
+
+
void test_loadModelReturnsCorrectNumberOfLayers(void)
{
const char *path = "some__nn_test_file.info2";