#include #include #include #include "imageInput.h" #define BUFFER_SIZE 100 #define FILE_HEADER_STRING "__info2_image_file_format__" #define HEADER_LEN (sizeof(FILE_HEADER_STRING) - 1) //-1, um \0 Character rauszufiltern // TODO Implementieren Sie geeignete Hilfsfunktionen für das Lesen der Bildserie aus einer Datei static int checkDimensions(unsigned int width, unsigned int height){ int ok = 0; if(width > 0 && height > 0) return ok = 1; else return ok = 0; } static int checkHeader(const GrayScalePixelType *buffer){ int ok = 0; char header[HEADER_LEN + 1]; //Array mit Platz für Header Länge + \0 Character -> String // Jeder Byte in String kopieren for(int i = 0; i < HEADER_LEN; i++){ header[i] = buffer[i]; } header[HEADER_LEN] = '\0'; // Nullterminator am Ende anhängen if(strcmp(header, FILE_HEADER_STRING) == 0) // wenn beide identische sind gibt cmp 0 zurück return ok = 1; else return ok = 0; } static FILE *openImageFile(const char *path) { return fopen(path, "rb"); } static int ReadCheckHeader(FILE *fp, GrayScalePixelType *header) { if(fread(header, sizeof(GrayScalePixelType), HEADER_LEN, fp) != HEADER_LEN) { return 0; } return 1; } static int readMetaData(FILE *fp, unsigned int *numImages, unsigned int *width, unsigned int *height) { if(fread(numImages, sizeof(unsigned int), 1, fp) != 1 || fread(width, sizeof(unsigned int), 1, fp) != 1 || fread(height, sizeof(unsigned int), 1, fp)!= 1) { return 0; } return 1; } static GrayScaleImageSeries *allocateSeriesStruct(void) { GrayScaleImageSeries *series = malloc(sizeof(GrayScaleImageSeries)); return series; } static int AllocateCheckImageAndLabels(GrayScaleImageSeries *series, unsigned int numImages) { series->count = numImages; //Speicher für die Pointer an sich belegen series->images = malloc(numImages * sizeof(GrayScaleImage)); //Speicher für alle Bild-Strukturen, nicht aber für die Pixel selbst (denn image ist nochmal ein Array selbst) series->labels = malloc(numImages * sizeof(unsigned char)); //Speicher für alle Labels //Prüfen, ob Speicher für die Arrays reserviert werden konnte, wenn nicht -> Freigabe if(series->images == NULL || series->labels == NULL){ free(series->images); //wenn trotzdem was reingeschrieben wurde, dann freigeben free(series->labels); free(series); return 0; } return 1; } static int AllocateCheckPixelData(GrayScaleImageSeries *series, unsigned int numImages, unsigned int width, unsigned int height) { for(unsigned int i = 0; i < numImages; i++){ series -> images[i].buffer = malloc(width * height); //Speicher für Pixeldaten selbst if(series->images[i].buffer == NULL){ for(unsigned int j = 0; j < i; j++){ free(series->images[j].buffer); //wenn Speicher nicht reserviert werden konnte, dann zuerst das Array mit Pixeldaten freigeben } free(series->images); //anschließend auch die Speicher für Bildstrukturen und Label-Arrays freigeben, weil zuvor für diese schon Speicher reserviert wurde free(series->labels); free(series); return 0; } } return 1; } static int ReadImagesAndLabels(FILE *fp, GrayScaleImageSeries *series, unsigned int numImages, unsigned int width, unsigned int height) { for(int i = 0; i < numImages; i++) { //Breite und Höhe werden gesetzt (GrayScaleImage) series -> images[i].width = width; series -> images[i].height = height; //Pixeldaten einlesen und Prüfen ob alle essentiellen Pixel eingelesen wurden if(fread(series -> images[i].buffer, 1, width * height, fp) != (width * height)) { clearSeries(series); return 0; } //Jedes Bild hat ein Label, was direkt danach eingelesen wird und auf Größe geprüft wird if(fread(&series -> labels[i], 1, 1, fp) != 1){ clearSeries(series); return 0; } } return 1; } // TODO Vervollständigen Sie die Funktion readImages unter Benutzung Ihrer Hilfsfunktionen GrayScaleImageSeries *readImages(const char *path) { GrayScaleImageSeries *series = NULL; //Datei im Binärmodus öffnen FILE *fp = openImageFile(path); if(!fp) return NULL; //Buffer zum Einlesen des Headers GrayScalePixelType header[HEADER_LEN]; //Prüfen, ob genau die HEADER_LEN Bytes eingelesen werden if(!ReadCheckHeader(fp, header)){ fclose(fp); return NULL; } //Prüfen, ob es sich um den korrekten Header handelt mit Hilfsfunktion if(!checkHeader(header)){ fclose(fp); return NULL; } //Anzahl der Bilder, Breite und Höhe einlesen unsigned int numImages, width, height; //muss man das als Zeiger initialisieren????????? if(!readMetaData(fp, &numImages, &width, &height)){ fclose(fp); return NULL; } //Prüfen, ob gültige Länge oder Breite if(!checkDimensions(width, height)){ fclose(fp); return NULL; } //Speicher für die gesamte Bildserie reservieren (aber nur für die Struktur) series = allocateSeriesStruct(); if(!series) { fclose(fp); return NULL; //Fehler bei Speicherreservierung } if(!AllocateCheckImageAndLabels(series, numImages)){ fclose(fp); return NULL; } //Speicher für die Pixeldaten selbst reserviern und Prüfen, ob er reserviert werden konnte if(!AllocateCheckPixelData(series, numImages, width, height)){ fclose(fp); return NULL; } if(!ReadImagesAndLabels(fp, series, numImages, width, height)){ fclose(fp); return NULL; } return series; } // TODO Vervollständigen Sie die Funktion clearSeries, welche eine Bildserie vollständig aus dem Speicher freigibt void clearSeries(GrayScaleImageSeries *series) { }