From dcdcefe4cc4b296d861033623d8533c98daf4d34 Mon Sep 17 00:00:00 2001 From: Max Perschke Date: Sat, 7 Nov 2026 15:26:38 +0100 Subject: [PATCH] ImageInput und ImageInputTests implementiert --- Startcode/imageInput.c | 95 +++++++++++++++++++- Startcode/imageInputTests.c | 174 ++++++++++++++++++------------------ 2 files changed, 178 insertions(+), 91 deletions(-) diff --git a/Startcode/imageInput.c b/Startcode/imageInput.c index bb30de1..b23f752 100644 --- a/Startcode/imageInput.c +++ b/Startcode/imageInput.c @@ -8,15 +8,104 @@ // TODO Implementieren Sie geeignete Hilfsfunktionen für das Lesen der Bildserie aus einer Datei +/* Liest den Dateitag sowie Anzahl und Abmessungen der Bilder. */ +static int readFileHeader(FILE *file, unsigned short *count, unsigned short *width, unsigned short *height) +{ + char tag[sizeof(FILE_HEADER_STRING) - 1]; + + return fread(tag, sizeof(tag), 1, file) == 1 && + memcmp(tag, FILE_HEADER_STRING, sizeof(tag)) == 0 && + fread(count, sizeof(*count), 1, file) == 1 && + fread(width, sizeof(*width), 1, file) == 1 && + fread(height, sizeof(*height), 1, file) == 1 && + *count > 0 && *width > 0 && *height > 0; +} + +/* Liest die Pixel und das unmittelbar folgende Label eines Bildes. */ +static int readImage(FILE *file, GrayScaleImage *image, unsigned char *label, size_t pixelCount) +{ + image->buffer = (GrayScalePixelType *)malloc(pixelCount); + if (image->buffer == NULL || fread(image->buffer, sizeof(*image->buffer), pixelCount, file) != pixelCount || + fread(label, sizeof(*label), 1, file) != 1) + { + free(image->buffer); + image->buffer = NULL; + return 0; + } + return 1; +} + +/* Gibt auch bereits teilweise geladene Serien und deren Pixelpuffer frei. */ +static void freeImages(GrayScaleImageSeries *series) +{ + if (series == NULL) + return; + 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); +} // TODO Vervollständigen Sie die Funktion readImages unter Benutzung Ihrer Hilfsfunktionen GrayScaleImageSeries *readImages(const char *path) { GrayScaleImageSeries *series = NULL; - + unsigned short count, width, height; + size_t pixelCount; + FILE *file; + + if (path == NULL || (file = fopen(path, "rb")) == NULL) + return 0; + + /* Zuerst den Header validieren, bevor Speicher reserviert wird */ + if (!readFileHeader(file, &count, &width, &height)) + { + fclose(file); + freeImages(series); + return 0; + } + + pixelCount = (size_t)width * height; + series = (GrayScaleImageSeries *)calloc(1, sizeof(*series)); + if (series == NULL) + { + + fclose(file); + freeImages(series); + return 0; + } + + series->count = count; + series->images = (GrayScaleImage *)calloc(count, sizeof(*series->images)); + series->labels = (unsigned char *)malloc(count * sizeof(*series->labels)); + if (series->images == NULL || series->labels == NULL) + { + fclose(file); + freeImages(series); + return 0; + } + + /* Ein Datensatz besteht jeweils aus Pixeln, gefolgt von einem Labelbyte. */ + for (unsigned int i = 0; i < count; ++i) + { + series->images[i].width = width; + series->images[i].height = height; + if (!readImage(file, &series->images[i], &series->labels[i], pixelCount)) + { + fclose(file); + freeImages(series); + return 0; + } + } + + 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 + freeImages(series); +} diff --git a/Startcode/imageInputTests.c b/Startcode/imageInputTests.c index 03240ab..2f8b0ab 100644 --- a/Startcode/imageInputTests.c +++ b/Startcode/imageInputTests.c @@ -6,102 +6,96 @@ #include "imageInput.h" -static void prepareImageFile(const char *path, unsigned short int width, unsigned short int height, unsigned int short numberOfImages, unsigned char label) +static void writeHeader(FILE *file, unsigned short count, unsigned short width, unsigned short height) { - FILE *file = fopen(path, "wb"); - - if(file != NULL) - { - const char *fileTag = "__info2_image_file_format__"; - GrayScalePixelType *zeroBuffer = (GrayScalePixelType *)calloc(numberOfImages * width * height, sizeof(GrayScalePixelType)); - - if(zeroBuffer != NULL) - { - fwrite(fileTag, sizeof(fileTag[0]), strlen(fileTag), file); - fwrite(&numberOfImages, sizeof(numberOfImages), 1, file); - fwrite(&width, sizeof(width), 1, file); - fwrite(&height, sizeof(height), 1, file); - - for(int i = 0; i < numberOfImages; i++) - { - fwrite(zeroBuffer, sizeof(GrayScalePixelType), width * height, file); - fwrite(&label, sizeof(unsigned char), 1, file); - } - - free(zeroBuffer); - } - - fclose(file); - } + const char *tag = "__info2_image_file_format__"; + fwrite(tag, 1, strlen(tag), file); + fwrite(&count, sizeof(count), 1, file); + fwrite(&width, sizeof(width), 1, file); + fwrite(&height, sizeof(height), 1, file); } +static void prepareImageFile(const char *path, unsigned short width, unsigned short height, + unsigned short count, unsigned char label) +{ + FILE *file = fopen(path, "wb"); + if (file == NULL) return; + + writeHeader(file, count, width, height); + size_t pixelCount = (size_t)width * height; + GrayScalePixelType *pixels = (GrayScalePixelType *)calloc(pixelCount, sizeof(*pixels)); + if (pixels != NULL) + { + for (unsigned int i = 0; i < count; ++i) + { + fwrite(pixels, sizeof(*pixels), pixelCount, file); + fwrite(&label, sizeof(label), 1, file); + } + free(pixels); + } + fclose(file); +} void test_readImagesReturnsCorrectNumberOfImages(void) { - GrayScaleImageSeries *series = NULL; - const unsigned short expectedNumberOfImages = 2; const char *path = "testFile.info2"; - prepareImageFile(path, 8, 8, expectedNumberOfImages, 1); - series = readImages(path); + const unsigned short expectedCount = 2; + prepareImageFile(path, 8, 8, expectedCount, 1); + GrayScaleImageSeries *series = readImages(path); TEST_ASSERT_NOT_NULL(series); - TEST_ASSERT_EQUAL_UINT16(expectedNumberOfImages, series->count); + TEST_ASSERT_EQUAL_UINT16(expectedCount, series->count); clearSeries(series); remove(path); } -void test_readImagesReturnsCorrectImageWidth(void) +void test_readImagesReturnsCorrectImageDimensions(void) { - GrayScaleImageSeries *series = NULL; - const unsigned short expectedWidth = 10; const char *path = "testFile.info2"; - prepareImageFile(path, expectedWidth, 8, 2, 1); - series = readImages(path); + prepareImageFile(path, 10, 9, 2, 1); + GrayScaleImageSeries *series = readImages(path); TEST_ASSERT_NOT_NULL(series); - TEST_ASSERT_NOT_NULL(series->images); - TEST_ASSERT_EQUAL_UINT16(2, series->count); - TEST_ASSERT_EQUAL_UINT16(expectedWidth, series->images[0].width); - TEST_ASSERT_EQUAL_UINT16(expectedWidth, series->images[1].width); - clearSeries(series); - remove(path); -} - -void test_readImagesReturnsCorrectImageHeight(void) -{ - GrayScaleImageSeries *series = NULL; - const unsigned short expectedHeight = 10; - const char *path = "testFile.info2"; - prepareImageFile(path, 8, expectedHeight, 2, 1); - series = readImages(path); - TEST_ASSERT_NOT_NULL(series); - TEST_ASSERT_NOT_NULL(series->images); - TEST_ASSERT_EQUAL_UINT16(2, series->count); - TEST_ASSERT_EQUAL_UINT16(expectedHeight, series->images[0].height); - TEST_ASSERT_EQUAL_UINT16(expectedHeight, series->images[1].height); + TEST_ASSERT_EQUAL_UINT16(10, series->images[0].width); + TEST_ASSERT_EQUAL_UINT16(10, series->images[1].width); + TEST_ASSERT_EQUAL_UINT16(9, series->images[0].height); + TEST_ASSERT_EQUAL_UINT16(9, series->images[1].height); clearSeries(series); remove(path); } void test_readImagesReturnsCorrectLabels(void) { - const unsigned char expectedLabel = 15; - - GrayScaleImageSeries *series = NULL; const char *path = "testFile.info2"; - prepareImageFile(path, 8, 8, 2, expectedLabel); - series = readImages(path); + prepareImageFile(path, 8, 8, 2, 15); + GrayScaleImageSeries *series = readImages(path); TEST_ASSERT_NOT_NULL(series); - TEST_ASSERT_NOT_NULL(series->labels); - TEST_ASSERT_EQUAL_UINT16(2, series->count); - for (int i = 0; i < 2; i++) { - TEST_ASSERT_EQUAL_UINT8(expectedLabel, series->labels[i]); - } + TEST_ASSERT_EQUAL_UINT8(15, series->labels[0]); + TEST_ASSERT_EQUAL_UINT8(15, series->labels[1]); clearSeries(series); remove(path); } -void test_readImagesReturnsNullOnNotExistingPath(void) +void test_readImagesReturnsPixelData(void) { - const char *path = "testFile.txt"; + const char *path = "testFile.info2"; + const unsigned char pixels[] = { 0, 17, 128, 255 }; + const unsigned char label = 7; + FILE *file = fopen(path, "wb"); + TEST_ASSERT_NOT_NULL(file); + writeHeader(file, 1, 2, 2); + fwrite(pixels, sizeof(pixels), 1, file); + fwrite(&label, sizeof(label), 1, file); + fclose(file); + + GrayScaleImageSeries *series = readImages(path); + TEST_ASSERT_NOT_NULL(series); + TEST_ASSERT_EQUAL_UINT8_ARRAY(pixels, series->images[0].buffer, sizeof(pixels)); + clearSeries(series); + remove(path); +} + +void test_readImagesReturnsNullOnMissingPath(void) +{ + const char *path = "missingTestFile.info2"; remove(path); TEST_ASSERT_NULL(readImages(path)); } @@ -109,35 +103,39 @@ void test_readImagesReturnsNullOnNotExistingPath(void) void test_readImagesFailsOnWrongFileTag(void) { const char *path = "testFile.info2"; - FILE *file = fopen(path, "w"); - if(file != NULL) - { - fprintf(file, "some_tag "); - fclose(file); - TEST_ASSERT_NULL(readImages(path)); - } + FILE *file = fopen(path, "wb"); + TEST_ASSERT_NOT_NULL(file); + fputs("wrong tag", file); + fclose(file); + TEST_ASSERT_NULL(readImages(path)); remove(path); } -void setUp(void) { - // Falls notwendig, kann hier Vorbereitungsarbeit gemacht werden +void test_readImagesFailsOnTruncatedImage(void) +{ + const char *path = "testFile.info2"; + const unsigned char partialPixels[] = { 1, 2 }; + FILE *file = fopen(path, "wb"); + TEST_ASSERT_NOT_NULL(file); + writeHeader(file, 1, 2, 2); + fwrite(partialPixels, sizeof(partialPixels), 1, file); + fclose(file); + TEST_ASSERT_NULL(readImages(path)); + remove(path); } -void tearDown(void) { - // Hier kann Bereinigungsarbeit nach jedem Test durchgeführt werden -} +void setUp(void) {} +void tearDown(void) {} -int main() +int main(void) { UNITY_BEGIN(); - - printf("\n============================\nImage input tests\n============================\n"); RUN_TEST(test_readImagesReturnsCorrectNumberOfImages); - RUN_TEST(test_readImagesReturnsCorrectImageWidth); - RUN_TEST(test_readImagesReturnsCorrectImageHeight); + RUN_TEST(test_readImagesReturnsCorrectImageDimensions); RUN_TEST(test_readImagesReturnsCorrectLabels); - RUN_TEST(test_readImagesReturnsNullOnNotExistingPath); + RUN_TEST(test_readImagesReturnsPixelData); + RUN_TEST(test_readImagesReturnsNullOnMissingPath); RUN_TEST(test_readImagesFailsOnWrongFileTag); - + RUN_TEST(test_readImagesFailsOnTruncatedImage); return UNITY_END(); -} \ No newline at end of file +}