generated from freudenreichan/info2Praktikum-NeuronalesNetz
217 lines
5.4 KiB
C
217 lines
5.4 KiB
C
#include <stdio.h>
|
||
#include <stdlib.h>
|
||
#include <string.h>
|
||
#include "imageInput.h"
|
||
|
||
// Größe eines temporären Puffers
|
||
#define BUFFER_SIZE 100
|
||
|
||
// Fester Header-String, der am Anfang jeder gültigen Bilddatei stehen muss
|
||
#define FILE_HEADER_STRING "__info2_image_file_format__"
|
||
|
||
/*
|
||
* Prüft den Dateiheader und liest Bildanzahl, Breite und Höhe aus.
|
||
* Gibt 1 (true) zurück, wenn alles gültig ist, sonst 0 (false).
|
||
*/
|
||
static int checkheader(FILE *path, unsigned short *count, unsigned short *width, unsigned short *height)
|
||
{
|
||
unsigned int headerlen = strlen(FILE_HEADER_STRING);
|
||
unsigned char header[64];
|
||
|
||
// Prüfen, ob der Header-String in den Puffer passt
|
||
if (headerlen >= sizeof(header))
|
||
{
|
||
return 0;
|
||
}
|
||
|
||
// Header aus Datei lesen – muss exakt gleich lang sein
|
||
if (fread(header, 1, headerlen, path) != headerlen)
|
||
{
|
||
return 0;
|
||
}
|
||
|
||
// Header vergleichen – Datei muss mit FILE_HEADER_STRING beginnen
|
||
if (strncmp((char *)header, FILE_HEADER_STRING, headerlen) != 0)
|
||
{
|
||
return 0;
|
||
}
|
||
|
||
// Danach folgen in der Datei: count, width, height (je 2 Bytes)
|
||
if (fread(count, sizeof(unsigned short), 1, path) != 1)
|
||
return 0;
|
||
|
||
if (fread(width, sizeof(unsigned short), 1, path) != 1)
|
||
return 0;
|
||
|
||
if (fread(height, sizeof(unsigned short), 1, path) != 1)
|
||
return 0;
|
||
|
||
return 1;
|
||
}
|
||
|
||
/*
|
||
* Reserviert Speicher für eine Serie von Graustufenbildern.
|
||
* Legt:
|
||
* - Hauptstruktur
|
||
* - Array von Bildern
|
||
* - Array von Labels
|
||
* - Für jedes Bild einen Pixelpuffer
|
||
* an.
|
||
*/
|
||
static GrayScaleImageSeries *allocateSeries(unsigned short count, unsigned short width, unsigned short height)
|
||
{
|
||
// Platz für die Gesamtstruktur anfordern
|
||
GrayScaleImageSeries *series = malloc(sizeof(GrayScaleImageSeries));
|
||
if (series == NULL)
|
||
{
|
||
return NULL;
|
||
}
|
||
|
||
series->count = count;
|
||
|
||
// Arrays für Bilder und Labels anlegen
|
||
series->images = calloc(count, sizeof(GrayScaleImage));
|
||
series->labels = calloc(count, sizeof(unsigned char));
|
||
|
||
if (series->images == NULL || series->labels == NULL)
|
||
{
|
||
return NULL;
|
||
}
|
||
|
||
// Jedem Bild Höhe, Breite und einen eigenen Pixelpuffer zuweisen
|
||
for (unsigned int i = 0; i < count; i++)
|
||
{
|
||
series->images[i].height = height;
|
||
series->images[i].width = width;
|
||
|
||
// Für jedes Bild einen Puffer anlegen: width * height Pixel
|
||
series->images[i].buffer = calloc(height * width, sizeof(GrayScalePixelType));
|
||
|
||
if (series->images[i].buffer == NULL)
|
||
{
|
||
// Falls ein Puffer fehlschlägt → alles bisherige wieder freigeben
|
||
clearSeries(series);
|
||
return NULL;
|
||
}
|
||
}
|
||
|
||
return series;
|
||
}
|
||
|
||
/*
|
||
* Liest die Pixeldaten und Labels aller Bilder aus der Datei.
|
||
* Reihenfolge in der Datei je Bild:
|
||
* 1. Pixelwerte (width*height Stück)
|
||
* 2. 1 Byte Label
|
||
*/
|
||
static int loadImageData(FILE *file, GrayScaleImageSeries *series, unsigned short count, unsigned short width, unsigned short height)
|
||
{
|
||
for (unsigned int i = 0; i < count; i++)
|
||
{
|
||
size_t pixelCount = width * height;
|
||
|
||
// Pixeldaten in den Bildpuffer schreiben
|
||
if (fread(series->images[i].buffer, sizeof(GrayScalePixelType), pixelCount, file) != pixelCount)
|
||
{
|
||
return 0;
|
||
}
|
||
|
||
// Label lesen (1 Byte)
|
||
if (fread(&series->labels[i], sizeof(unsigned char), 1, file) != 1)
|
||
{
|
||
return 0;
|
||
}
|
||
}
|
||
|
||
return 1;
|
||
}
|
||
|
||
// Schliesst eine Datei, sofern sie geöffnet ist
|
||
static void closefile(FILE *file)
|
||
{
|
||
if (file != NULL)
|
||
{
|
||
fclose(file);
|
||
}
|
||
}
|
||
|
||
/*
|
||
* Hauptfunktion zum Einlesen der Bilddaten:
|
||
* 1. Datei öffnen
|
||
* 2. Header + Metadaten lesen
|
||
* 3. Speicher anlegen
|
||
* 4. Pixeldaten + Labels laden
|
||
* 5. Datei schließen
|
||
* 6. Zeiger auf fertige Daten zurückgeben
|
||
*/
|
||
GrayScaleImageSeries *readImages(const char *path)
|
||
{
|
||
unsigned short count, width, height;
|
||
GrayScaleImageSeries *series = NULL;
|
||
|
||
// Datei im binären Modus öffnen
|
||
FILE *file = fopen(path, "rb");
|
||
if (file == NULL)
|
||
{
|
||
return NULL;
|
||
}
|
||
|
||
// Header überprüfen und Metadaten lesen
|
||
if (!checkheader(file, &count, &width, &height))
|
||
{
|
||
closefile(file);
|
||
return NULL;
|
||
}
|
||
|
||
// Speicher für Serie anlegen
|
||
series = allocateSeries(count, width, height);
|
||
if (series == NULL)
|
||
{
|
||
closefile(file);
|
||
return NULL;
|
||
}
|
||
|
||
// Bilddaten laden
|
||
if (!loadImageData(file, series, count, width, height))
|
||
{
|
||
clearSeries(series);
|
||
closefile(file);
|
||
return NULL;
|
||
}
|
||
|
||
// Datei schließen und fertige Struktur zurückgeben
|
||
closefile(file);
|
||
|
||
return series;
|
||
}
|
||
|
||
/*
|
||
* Gibt den gesamten reservierten Speicher der Bildserie wieder frei.
|
||
* Dazu:
|
||
* - alle Pixelpuffer
|
||
* - Bilderarray
|
||
* - Labelsarray
|
||
* - Hauptstruktur
|
||
*/
|
||
void clearSeries(GrayScaleImageSeries *series)
|
||
{
|
||
if (series != NULL)
|
||
{
|
||
// Erst alle Bildpuffer freigeben
|
||
for (unsigned int i = 0; i < series->count; i++)
|
||
{
|
||
free(series->images[i].buffer);
|
||
}
|
||
|
||
// Danach Arrays freigeben
|
||
free(series->images);
|
||
free(series->labels);
|
||
|
||
// Am Ende die Struktur selbst
|
||
free(series);
|
||
}
|
||
|
||
// count, width, height müssen nicht auf 0 gesetzt werden,
|
||
// da sie bei einer Neu-Allokation sowieso überschrieben werden.
|
||
}
|