Files
Info2-Pr-NeuroNetz/Startcode/imageInput.c
T
Manuel GlockandClaude Opus 5.5 4d6a86f293 Pflichtaufgaben fertig: Matrix-Fixes, Bilder einlesen, NN-Testdatei
- matrix.c: multiply summiert in MatrixType statt int (Nachkommastellen
  gingen verloren), clearMatrix gibt Speicher frei, Indexpruefung pro
  Zeile/Spalte, NULL-Pruefungen in add/multiply
- imageInput.c: fseek-Spruenge entfernt, Dateikopf pruefen, Lesefehler
  behandeln, clearSeries implementiert
- neuralNetworkTests.c: prepareNeuralNetworkFile implementiert
- neuralNetwork.c: clearModel gibt das Layer-Array frei (Speicherleck)
- Zusaetzliche Unittests fuer Matrix und Bildeinlesen
- Testartefakte und Testprogramme in .gitignore, testFile.info2 entfernt

Alle 33 Tests gruen, keine Warnungen, 87.37 % Genauigkeit (wie Referenz).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-13 12:19:07 +01:00

149 lines
4.2 KiB
C

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "imageInput.h"
#define BUFFER_SIZE 100
#define FILE_HEADER_STRING "__info2_image_file_format__"
// Liest den Identifikationstag am Dateianfang und vergleicht ihn mit FILE_HEADER_STRING
static int checkFileHeader(FILE *file)
{
int isValid = 0;
size_t fileHeaderLen = strlen(FILE_HEADER_STRING);
char buffer[BUFFER_SIZE] = {0};
if(fileHeaderLen > BUFFER_SIZE-1)
fileHeaderLen = BUFFER_SIZE-1;
if(fread(buffer, sizeof(char), fileHeaderLen, file) == fileHeaderLen)
isValid = strcmp(buffer, FILE_HEADER_STRING) == 0;
return isValid;
}
// Liest den naechsten unsigned short (Anzahl, Breite bzw. Hoehe); 0 im Fehlerfall.
// Kein fseek noetig: fread setzt den Dateizeiger automatisch hinter die gelesenen Bytes.
static unsigned short readUnsignedShort(FILE *file)
{
unsigned short value = 0;
if(fread(&value, sizeof(unsigned short), 1, file) != 1)
value = 0;
return value;
}
static unsigned short readNumberOfImages(FILE *file)
{
return readUnsignedShort(file);
}
static unsigned short readImageWidth(FILE *file)
{
return readUnsignedShort(file);
}
static unsigned short readImageHeight(FILE *file)
{
return readUnsignedShort(file);
}
// Liest die Pixel eines Bildes in einen neuen Puffer; NULL bei Speicher- oder Lesefehler
static GrayScalePixelType *readImage(FILE *file, unsigned short imageWidth, unsigned short imageHeight)
{
size_t numberOfPixels = (size_t)imageWidth * imageHeight;
GrayScalePixelType *image = (GrayScalePixelType *)malloc(numberOfPixels * sizeof(GrayScalePixelType));
if(image != NULL && fread(image, sizeof(GrayScalePixelType), numberOfPixels, file) != numberOfPixels)
{
free(image);
image = NULL;
}
return image;
}
// Liest das Label, das direkt auf die Pixel eines Bildes folgt; 0 bei Erfolg, sonst -1
static int readLabel(FILE *file, unsigned char *label)
{
return fread(label, sizeof(unsigned char), 1, file) == 1 ? 0 : -1;
}
// Legt eine leere Serie fuer numberOfImages Bilder an (Bildpuffer werden spaeter von readImage geliefert)
static GrayScaleImageSeries *createSeries(unsigned short numberOfImages)
{
GrayScaleImageSeries *series = (GrayScaleImageSeries *)calloc(1, sizeof(GrayScaleImageSeries));
if(series != NULL)
{
// calloc: alle Bildpuffer starten als NULL, damit clearSeries jederzeit gefahrlos aufraeumen kann
series->images = (GrayScaleImage *)calloc(numberOfImages, sizeof(GrayScaleImage));
series->labels = (unsigned char *)calloc(numberOfImages, sizeof(unsigned char));
if(series->images == NULL || series->labels == NULL)
{
clearSeries(series);
series = NULL;
}
else
series->count = numberOfImages;
}
return series;
}
GrayScaleImageSeries *readImages(const char *path)
{
GrayScaleImageSeries *series = NULL;
FILE *file = fopen(path, "rb");
if(file != NULL)
{
if(checkFileHeader(file))
{
unsigned short numberOfImages = readNumberOfImages(file);
unsigned short imageWidth = readImageWidth(file);
unsigned short imageHeight = readImageHeight(file);
if(numberOfImages > 0 && imageWidth > 0 && imageHeight > 0)
series = createSeries(numberOfImages);
for(unsigned int i = 0; series != NULL && i < series->count; i++)
{
series->images[i].width = imageWidth;
series->images[i].height = imageHeight;
series->images[i].buffer = readImage(file, imageWidth, imageHeight);
if(series->images[i].buffer == NULL || readLabel(file, &series->labels[i]) != 0)
{
clearSeries(series);
series = NULL;
}
}
}
fclose(file);
}
return series;
}
void clearSeries(GrayScaleImageSeries *series)
{
if(series != NULL)
{
if(series->images != NULL)
{
for(unsigned int i = 0; i < series->count; i++)
{
free(series->images[i].buffer);
}
}
free(series->images);
free(series->labels);
free(series);
}
}