Rekommenderade övningsuppgifter

Syfte

Syftet med denna laboration är att du skall:

Introduktion

Din uppgift är att skriva ett program som kan läsa in en bild från en fil i 24-bitars okomprimerat BMP-format (dvs en Windows-bitmapp) och sedan antingen justera ljusstyrkan för bilden, eller konvertera den till gråskala. Därefter ska bilden sparas till fil igen.

Ändra ljusstyrka
  1. Läsa in en bild från en fil.
  2. Justera ljusstyrkan för R-, G- och B-kanalerna oberoende av varandra. (Mer information om vad som menas med R/G/B-kanaler finns nedan.) Användaren anger tre tal som anger hur mycket varje färgvärde ska skalas. Talen 0.5 1.2 0 anger exempelvis halverad ljusstyrka för röda färger och 20% ökning för gröna färger, medan den blå färgkomponenten helt ska tas bort.
  3. Spara den ändrade bilden till en fil.
  4. Avsluta programmet
Konvertera till gråskala
  1. Läsa in en bild från en fil.
  2. Konvertera bilden till gråskala.
  3. Spara den ändrade bilden till en fil.
  4. Avsluta programmet

Att tolka BMP-filer är lite besvärligt (även om det är ett av de enklare bildformaten), särskilt som vi inte diskuterat filhantering ännu. Därför får du färdig kod för att läsa in en bild respektive spara en bild. Koden består av filerna bm.h, bm.c. Du måste separatkompilera C-filen, dvs du får inte bara klistra in den i filen där din main-funktion ligger. Koden i de ovannämnda filerna är knappast föredömlig, utan dess syfte är snarare att ge er en realistiskt bild av hur färdig kod kan se ut.

Datastruktur för bilden

Denna typ av bilder är uppdelade i tre komponenter (kanaler): en för rött, en för grönt och en för blått. Dessa bilder överlagras sedan ovanpå varandra för att ge den färdiga bilden. Varje komponent kan ses som ett array av array, där elementen är heltal mellan 0 och 255 som anger ljusstyrkan för respektive färg. Anta att du har en bild som är tre punkter hög och tre punkter bred. Den är helt röd, bortsett från punkten i mitten som är svagt blå. Komponenterna kan då se ut så här:

 
  Röd:             Grön:          Blå: 
  255 255 255      0   0   0      0   0   0 
  255   0 255      0   0   0      0  30   0 
  255 255 255      0   0   0      0   0   0 

I detta program representeras en bild som en tvådimensionell array av pixel-structar där varje pixel struct innehåller de tre färgkomponenterna i varsin unsigned char. Eftersom en char kan representera alla tal mellan 0 och 255 behöver vi inte använda int, och eftersom alla tal betraktas som positiva används unsigned char.

typedef struct {
    unsigned char red;
    unsigned char green;
    unsigned char blue;
} pixel;

typedef struct {
    pixel array[MAXROWS][MAXCOLUMNS];
    int rows, columns;
} image;

image-structen svarar mot själva bilden, den innehåller förutom en tvådimensionell array med pixlar, rows som är antalet rader i bilden och columns som är antal kolumner (dvs storleken på den inlästa bilden). Structen pixel innehåller värdet för färgerna vid en viss pixel (punkt) i bilden.

Om bildrutinerna

Du behöver två funktioner från den kod du fått:
bmp_read (läser in en bild till minnet)
bmp_write (skriver en bild som är lagrad i minnet till en fil).
Prototyperna ser ut på följande sätt:

image bmp_read(char fname[]);
int bmp_write(char fname[], image picture);

Dessa två funktioner läser, respektive skriver en BMP-bild antingen från en fil till minnet, eller från minnet till en fil.
fname är namnet på den fil som ska hanteras.
picture svarar mot bilden.
bmp_write returnerar 1 om det gick bra, och 0 något ej fungerade, medans bmp_read ger tillbaka en bild med rows och columns satt till -1 om något går fel vid inläsningen.

Algoritmer

Ändra ljusstyrka

Ändringen av ljusstyrkan går till så att ljusstyrkan för respektive färgkomponent skalas i varje pixel. Har en pixel ljusstyrkan (25 255 50) och de skall skalas med (0 1.2 0.5) för R, G respektive B, blir resultatet (0 255 25) för den pixeln.

Gråskala

Hos en bild i gråskala är ljusstyrkan hos de tre färgkomponenterna lika stora, t.ex. (128 128 128).

Att konvertera en bild till gråskala görs enklast bäst genom att räkna ut gråskalevärde = (76 * R / 255) + (150 * G / 255) + (29 * B / 255) och sätta färgernas värde till detta beräknade värde. Så om pixeln hade värdet (5, 230, 70) blir gråskalevärdet (144, 144, 144).

Exempel på användning av bildrutinerna

Följande kodsnutt läser in bilden "image1.bmp", halverar ljusstyrkan för den röda komponenten och skriver data till bilden "image2.bmp":

#include "bm.h" 
#include <stdio.h>
#include <stdlib.h>
 
int main(void) { 
    image picture;
    int r, k;

    picture=bmp_read("image1.bmp");
    if (picture.columns == -1) {
        printf("Error: could not perform bmp_read.\n");
        exit(1);
    }

    for (r = 0; r < picture.rows; r++)
        for (k = 0; k < picture.columns; k++) {
            picture.array[r][k].red /= 2;
        }

    if(!bmp_write("image2.bmp", picture)) {
        fprintf(stderr, "Error: Could not perform bmp_write.\n");
        exit(1);
    }
    return 0;
}

Exempel på användning av programmet

Menyn visas när användaren startar programmet och följer sedan stegen "läsa fil", "modifiera fil", "spara fil", "avsluta" enligt ovan, utan att visa menyn flera gånger. Det första filnamnet är en länk till en bild ni kan använda för att testa ert program (endast i specifikation, ditt eget program ska inte ha några länkar). Om du klickar på dem visan hur bilden ser ut. Ni måste ta hand om validering av indata. Det är tillåtet avbryta programkörningen om felaktiga indata ges, men bara om vettiga felmeddelanden ges till användaren.

Exempel på att ändra ljusstyrka:

 
  MENY 
  1 Ändra ljusstyrka
  2 Konvertera till gråskala
  3 Avsluta utan åtgärd

  Välj ett alternativ: 1 
      Ange filnamn: rgb.bmp 
      
      Ange faktorer (R G B): 1.3 0.8 0.2 
      
      Ange filnamn: rgb2.bmp  
    
      Allt gick bra, programmet avslutas.

Exempel på att konvertera till gråskala:

 
  MENY 
  1 Ändra ljusstyrka
  2 Konvertera till gråskala
  3 Avsluta utan åtgärd

  Välj ett alternativ: 2 
      Ange filnamn att läsa från: testbild.bmp 
      
      Konvertering utförd. 
      
      Ange filnamn att skriva till: testbild2.bmp  
    
      Allt gick bra, programmet avslutas.

Några saker att tänka på

Tips på arbetsgång för er som har svårt att komma igång med uppgiften:

  1. Börja skriv ett enkelt program som läser in en bild mha bmp_read och sedan sparar denna bild till en ny fil (mha bmp_write). En bra utgångspunkt är exempelprogrammet i uppgiften (testa så att det fungerar).
  2. Skriv en funktion för att givet en pixel-struct (som tas in som parameter) beräkna den pixelns gråskalevärde. Funktionen kan tex returner en ny pixel med detta värde för alla 3 färgkomponenter. Testa så att den fungerar genom att skicka in en pixel och se så att du får tillbaka en pixel med korrekta värden.
  3. Skriv en funktion som tar in hur hur ljusstyrkan ska förändras för en pixels 3 olika färgkomponenter (en parameter per färg) samt en pixel och ger tillbaka en ny pixel med färgvärdena ändrade.
  4. Skriv en funktion som givet en bild skapar en ny bild som innehåller pixlarna i första bilden konverterade till gråskala (använder sig lämpligtvis av funktionen från punkt 2 ovan). och returnerar den nya bilden
  5. Testa att det funkar genom att läsa in en bild. Konvertera den till gråskala samt skriva den till en fil (och kontrollera så att den ser ok ut)
  6. Skriv en funktion som givet en bild och hur ljusstyrkan för denna ska ändras skapar en ny bild som innehåller pixlarna i första bilden med ljusstyrkan konverterad (använder sig lämpligtvis av funktionen från punkt 3 ovan) och returnerar den nya bilden
  7. Skriv en meny där man kan välja vad som ska göras (gråskalekonverteringen eller ljusstyrkeförändringen) och där man får möjlighet att välja filnamn och för ljusstyrkeändringen ange vilka värden bilden ska konverteras med.

Inlämning

Väl kommenterad källkod ska vara inlämnad via det webbaserade inlämningssystemet som ni hittar här senast 15/10 kl. 13.00. Skriv ert namn och användarnamn som en kommentar i filen.
Uppgiften ska lösas enskilt.