#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define N1 1000 // maximale Bildhöhe
#define N2 1000 // maximale Bildbreite
typedef unsigned char Pixel; // Datentyp Pixel
typedef struct pgm_bild Pgm_Bild; // Datentyp pgmBild
struct pgm_bild {
char magic[10]; // Bildtyp
int nx; // Zeilenzahl
int ny; // Spaltenzahl
int graumax; // max. Grauwert
Pixel bild[N1][N2]; // Bildmatrix
};
//Prototypen
void invertieren ( Pgm_Bild *bild1, Pgm_Bild *bild2 );
void glaetten ( Pgm_Bild *bild1, Pgm_Bild *bild2 );
void schwellwert ( Pgm_Bild *bild1, Pgm_Bild *bild2, Pixel schwellwert );
void kantenbildung ( Pgm_Bild *bild1, Pgm_Bild *bild2 );
int bild_lesen ( char *dateiname, Pgm_Bild *bild1 );
int bild_schreiben ( char *dateiname, Pgm_Bild *bild1 );
#define ASSERT(expr) if(!expr) { fprintf(stderr, "ASSERTION failed: %s\nfile: %s\nline: %d\n", #expr, __FILE__, __LINE__); exit(1); }
const char *error = 0;
/**
* Einlesen einer Bilddatei im PGM Format
* param char *dateiname Name der Eingabedatei
* param Pgm_Bild *bild Rückgabe Struktur des Eingabebildes
* return int Status
* 0: In Ordnung, 1: Fehler beim öffnen, 2: Fehler beim Lesen
*/
int bild_lesen ( char *dateiname, Pgm_Bild *bild )
{
FILE *infile; // Eingabedatei
char zeile[3][10]; // Zwischenspeicher für Header
int i,x,y; // Schleifenzähler
int color; // Zwischenspeicher für Farbwerte
infile = fopen(dateiname, "r");
if( !infile ) {
error = "Kann Datei nicht finden/oeffnen.";
return 1;
}
for( i=0; i<3 && !feof(infile); i++) {
fgets( zeile[i], 9, infile );
}
if( i < 3 ) {
error = "Datei ist keine korrekte PGM Datei.";
return 2;
}
sscanf( zeile[0], "%s\n", bild->magic );
bild->graumax = atoi( zeile[2] );
if( bild->graumax < 0 || bild->graumax > 255) {
error = "Maximaler Grauwert muss zwischen 0 und 255 liegen.";
return 2;
}
if( sscanf( zeile[1], "%d %d", &bild->nx, &bild->ny) != 2 ) {
error = "Datei ist keine korrekte PGM Datei.\n";
return 2;
}
if( bild->nx < 0 || bild->ny < 0 || bild->nx > N2 || bild->ny > N1 ) {
error = "Bild zu gross oder zu klein";
return 2;
}
for( y=0; y < bild->ny && !feof(infile); y++) {
for( x = 0; x < bild->nx && !feof(infile) ; ) {
if( fscanf( infile, "%d", &color ) != 1) // ignoriere alle nicht-Ziffern
continue;
if( color < 0 || color > bild->graumax ) // ignoriere alle falschen Farbwerte
continue;
bild->bild[y][x++] = (Pixel) color;
}
}
if( y != bild->ny || x != bild->nx ) {
error = "Datei wurde nicht komplett geladen.";
return 2;
}
fclose( infile );
return 0;
}
/**
* Schreiben der Bilddaten in eine Datei
*param char *dateiname Name der Ausgabedatei
*param Pgm_Bild *bild Struktur des Ausgabebildes
*return int Status
*0: In Ordnung, 1: Fehler beim öffnen, 2: Fehler beim Schreiben
*/
int bild_schreiben ( char *dateiname, Pgm_Bild *bild )
{
FILE *outfile; // Dateihandle
int x, y; // Schleifenzähler
outfile = fopen( dateiname, "w");
if( !outfile ) {
error = "Kann Datei nicht erstellen.";
return 1;
}
fprintf( outfile, "%s\n", bild->magic);
fprintf( outfile, "%d %d\n", bild->nx, bild->ny);
fprintf( outfile, "%d\n", bild->graumax);
for( y=0; y < bild->ny; y++) {
for( x=0; x < bild->nx; x++) {
fprintf(outfile, "%4d", bild->bild[y][x]);
if( (x*y+1) % 16 )
fprintf(outfile, "\n");
}
}
if( y != bild->ny || x != bild->nx) {
error = "Datei wurde nicht komplett gespeichert.";
return 2;
}
return 0;
}
//Invertierung
void invertieren ( Pgm_Bild *bild1, Pgm_Bild *bild2 )
{
int x, y; // Schleifenzähler
ASSERT( bild1->nx == bild2->nx && bild1->ny == bild2->ny );
for( y=0; y < bild2->ny; y++) {
for( x=0; x < bild2->nx; x++) {
bild2->bild[y][x] = bild1->graumax - bild1->bild[y][x];
}
}
}
void glaetten ( Pgm_Bild *bild1, Pgm_Bild *bild2 )
{
int x, y;
ASSERT( bild1->nx == bild2->nx && bild1->ny == bild2->ny);
// Randpixel kopieren
for( x = 0; x < bild2->nx; x++) {
bild2->bild[0][x] = bild1->bild[0][x];
bild2->bild[bild2->ny-1][x] = bild1->bild[bild2->ny-1][x];
}
for( y = 0; y < bild2->ny; y++) {
bild2->bild[y][0] = bild1->bild[y][0];
bild2->bild[y][bild2->nx-1] = bild1->bild[y][bild2->nx-1];
}
// Innere Pixel setzen
for( y=1; y < (bild2->ny-1); y++) {
for( x=1; x < (bild2->nx-1); x++) {
bild2->bild[y][x] = (bild1->bild[y][x] // Mitte
+bild1->bild[y][x-1] // links daneben
+bild1->bild[y][x+1] // rechts daneben
+bild1->bild[y-1][x-1] // links drüber
+bild1->bild[y-1][x] // genau drüber
+bild1->bild[y-1][x+1] // rechts drüber
+bild1->bild[y+1][x-1] // links drunter
+bild1->bild[y+1][x] // genau drunter
+bild1->bild[y+1][x+1] // rechts drunter
) / 9;
}
}
}
void schwellwert ( Pgm_Bild *bild1, Pgm_Bild *bild2, Pixel schwellwert )
{
int x, y; // Schleifenzähler
ASSERT( bild1->nx == bild2->nx && bild1->ny == bild2->ny);
for( y = 0; y < bild2->ny; y++) {
for( x=0; x < bild2->nx; x++) {
bild2->bild[y][x] = bild1->bild[y][x] < schwellwert ? 0 : bild1->graumax;
}
}
}
void kantenbildung ( Pgm_Bild *bild1, Pgm_Bild *bild2 )
{
int x, y;
ASSERT( bild1->nx == bild2->nx && bild1->ny == bild2->ny);
// Randpixel kopieren
for( x = 0; x < bild2->nx; x++) {
bild2->bild[0][x] = bild1->bild[0][x];
bild2->bild[bild2->ny-1][x] = bild1->bild[bild2->ny-1][x];
}
for( y = 0; y < bild2->ny; y++) {
bild2->bild[y][0] = bild1->bild[y][0];
bild2->bild[y][bild2->nx-1] = bild1->bild[y][bild2->nx-1];
}
// Innere Pixel setzen
for( y=1; y < (bild2->ny-1); y++) {
for( x=1; x < (bild2->nx-1); x++) {
bild2->bild[y][x] = abs(
(4*bild1->bild[y][x] // Mitte
-bild1->bild[y][x-1] // links daneben
-bild1->bild[y][x+1] // rechts daneben
-bild1->bild[y-1][x] // genau drüber
-bild1->bild[y+1][x] // genau drunter
) / 9);
}
}
}
// Bild Details ausgeben
void details( Pgm_Bild *bild) {
printf("Typ: %s\n", bild->magic);
printf("NX: %d\n", bild->nx);
printf("NY: %d\n", bild->ny);
printf("Max: %d\n", bild->graumax);
}
int main(int argc, char *argv[])
{
Pgm_Bild bild1, bild2; // Ein- und Ausgabebildstruktur
char auswahl; // Benutzereingabe
int rc; // Returncode
rc = bild_lesen( "dreifach.pgm", &bild1);
if( rc != 0 ) {
fprintf(stderr, "FEHLER: %s\n", error);
return( rc );
}
// Ausgabebild initialisieren
bild2.graumax = bild1.graumax;
strcpy( bild2.magic, bild1.magic);
bild2.nx = bild1.nx;
bild2.ny = bild1.ny;
auswahl = 0;
while( !auswahl) {
printf("\nBitte waehlen:\n");
printf(" g Glaettung\n");
printf(" i Invertierung\n");
printf(" k Kantenbildung\n");
printf(" s Schwellwert\n");
printf("Auswahl:");
auswahl = getchar();
switch( auswahl ) {
case 'g': // Glättung
glaetten( &bild1, &bild2);
break;
case 'i': // Invertierung
invertieren( &bild1, &bild2);
break;
case 'k': // Kantenerkennung
kantenbildung( &bild1, &bild2);
break;
case 's': // Schwellwert
schwellwert ( &bild1, &bild2, 150);
break;
default:
printf("\n");
auswahl = 0;
}
}
rc = bild_schreiben( "dreifach.out.pgm", &bild2);
if( rc != 0 ) {
fprintf(stderr, "FEHLER: %s\n", error);
return( rc );
}
puts("ENTER druecken");
fflush( stdin );
getchar();
return 0;
}