Asg 1: Color to greyscale image conversion


Implement a basic color-to-greyscale image converter. A popular approach is to use the luminosity method, where each greyscale pixel is computed as a weighted average of the three R, G, B color pixels, i.e., 0.21 R + 0.72 G + 0.07 B (see this page for an example, and a couple of alternatives).

Suggestions (e.g., for C implementation)

  1. Create two modules, ppm.c and pgm.c, each implementation file with its own header.
  2. The ppm image module should take care of converting the color image to a greyscale image.
  3. The main.c code driver tests the modules by:
    1. calling ppm_read(...) to read in the PPM image
    2. calling ppm_togrey(...) to convert the PPM image
    3. calling pgm_write(...) to output the PGM image
    4. calling ppm_free(...) to free PPM image memory
    5. calling pgm_free(...) to free PGM image memory

Further Suggestions

  1. The bulk of the code for this project sits in the I/O functions for reading and writing PPM and PGM image files.
  2. You should develop this project incrementally where you first write code for the PGM image, test it by reading and writing (e.g., copying) a PGM image—if you can copy an image without distorting it in any way, your I/O routines are working.
  3. After you have the PGM image code working, you basically just copy it to ppm.c and use three (1D) arrays for the R, G, B channels.
  4. The tricky part of this project is proper use of header files.
  5. Here is a working pgm.h header:
    #ifndef PGM_H
    #define PGM_H
    typedef struct {
            char            *name;  // filename
            int             cols;   // width
            int             rows;   // height
            int             maxc;   // max color (usually 255)
            char            *magic; // magic number (expect 'P5')
            float           *gpix;  // grey pixels, stored as 1D array
    } PGM;
    PGM     *pgm_alloc(int r, int c);
    void     pgm_free(PGM **img);
    PGM     *pgm_read(const char *file);
    int      pgm_write(PGM *img, const char *file);
  6. Here is a working ppm.h header:
    #ifndef PPM_H
    #define PPM_H
    typedef struct {
            char            *name;  // filename
            int             cols;   // width
            int             rows;   // height
            int             maxc;   // max color (usually 255)
            char            *magic; // magic number (expect 'P5')
            float           *rpix;  // red pixels, stored as 1D array
            float           *gpix;  // green pixels, stored as 1D array
            float           *bpix;  // blue pixels, stored as 1D array
    } PPM;
    PPM     *ppm_alloc(int r, int c);
    void     ppm_free(PPM **img);
    PPM     *ppm_read(const char *file);
    int      ppm_write(PPM *img, const char *file);

Example Program Input

(right-click to Save As mandrill.ppm)

Example Program Output


  1. If you call your source code file main.c here is a Makefile that you can use to try to compile the project:
    CC = gcc
    INCLUDE = -I.
    CFLAGS = -g
    LDFLAGS = -L. -L/usr/lib
    LDLIBS = -lc -lm
    	$(CC) $(INCLUDE) $(CFLAGS) -c -o $@ $<
    all: main
    main: pgm.o ppm.o main.o main.c
    	$(CC) -o $@ $@.o pgm.o ppm.o $(LDFLAGS) $(LDLIBS)
    main.o: main.c
    	rm -f *.o
    	rm -rf main
    Note that each line underneath the targets is indented by a tab, not just spaces, this is important!

Turn in

Turn in all of your code, in one tar.gz archive of your asg##/ directory, including:
  1. A README file containing
    1. Course id--section no
    2. Name
    3. Brief solution description (e.g., program design, description of algorithm, etc., however appropriate).
    4. Lessons learned, identified interesting features of your program
    5. Any special usage instructions
  2. Makefile
  3. source code (.h headers and .c source)
  4. object code (do a make clean before tar)

How to hand in

See handin notes

Grading scheme