Enkoder i dekoder BMP do nowego pliku graficznego

0

Cześć,
Na zaliczenie przedmiotu na studiach mam wykonać projekt polegający na stworzenie enkodera i dekodera formatu graficznego BMP do nowego pliku graficzne. Obraz ma być przekształcony 256-stopniowej skali szarości oraz kompresowany za pomocą RLE.
Wykonałem dekoder i enkoder zgodnie ze specyfikacją, niestety wszelkie próby zmiany obrazu kolorowego w skalę szarości nie powiodły się.
Bardzo proszę o pomoc/sugestie co robię nie tak.
Zamieszczam kod enkoder.

#include <stdio.h>           //obsluga plikow
#include <windows.h>
#include <iostream>
#define BITMAP_ID 0x4D42    //format BMP
#define PSM_ID 0x5053       //format BMP

using namespace std;

typedef struct PSMFILEHEADER
{
    short ident;
    int roz_pliku;
    int off_kolor;
    int off_piksel;
} PSMFILEHEADER;

typedef struct PSMINFOHEADER
{
    int roz_nag;
    int szerokosc;
    int wysokosc;
    int kompresja;
    int rozdz_poz;
    int rozdz_pion;
    int kolor;
    int predykator;
} PSMINFOHEADER;



static unsigned char *LoadBmp(char *filename, BITMAPINFOHEADER *bitmapInfoHeader)
{
    FILE                *filePtr;                // wskaznik pliku
    BITMAPFILEHEADER    bitmapFileHeader;        // naglowek pliku
    unsigned char       *bitmapImage;            // bufor obrazu
    int                 imageIdx = 0;            // licznik bajtow obrazu
    unsigned char       tempRGB;                 // zmienna zamiany skladowych

    // otwiera plik w trybie "read binary"
    filePtr = fopen(filename, "rb");
    if (filePtr == NULL)
        return NULL;

    // wczytuje naglowek pliku BMP
    fread(&bitmapFileHeader, sizeof(BITMAPFILEHEADER), 1, filePtr);

    // wczytuje naglowek obrazu zapisanego w pliku
    fread(bitmapInfoHeader, sizeof(BITMAPINFOHEADER), 1, filePtr);


    // sprawdza czy jest to plik BMP
    if (bitmapFileHeader.bfType != BITMAP_ID)
    {
        fclose(filePtr);
        cout<<"Bledny plik BMP!"<<endl;
        return NULL;
    }
    else
    {
        cout<<"Poprawny plik BMP!"<<endl;
    }

    if (bitmapInfoHeader->biCompression != BI_RGB)
    {
        fclose(filePtr);
        cout<<"Obraz skapresowany!"<<endl;
        return NULL;
    }
    else
    {
        cout<<"Brak kompresji!"<<endl;
    }

    /*if (bitmapInfoHeader->biBitCount != 8)
    {
        fclose(filePtr);
        cout<<"To nie jest obraz 8bit!"<<endl;
        return NULL;
    }
    else
    {
        cout<<"Obraz 8bit!"<<endl;
    }*/

    // ustawia wskaznik pliku na poczatku danych opisujacych obraz
    fseek(filePtr, bitmapFileHeader.bfOffBits, SEEK_SET);

    // przydziela pamiec na bufor obrazu
    bitmapImage = (unsigned char*)malloc(bitmapInfoHeader->biSizeImage);

    // sprawdza, czy pamiec zostala przydzielona
    if (!bitmapImage)
    {
        free(bitmapImage);
        fclose(filePtr);
        cout<<"Pamiec nie przydzielona!"<<endl;
        return NULL;
    }
    else
    {
        cout<<"Pamiec przydzielona!"<<endl;
    }

    // wczytuje dane obrazu
    fread(bitmapImage, 1, bitmapInfoHeader->biSizeImage, filePtr);

    // sprawdza czy operacja powiodla sie
    if (bitmapImage == NULL)
    {
        fclose(filePtr);
        cout<<"Nie wczytano obrazu!"<<endl;
        return NULL;
    }
    else
    {
            cout<<"Wczytano obraz!"<<endl<<endl;
    }

    // zamienia skladowe R i B
    for (imageIdx = 0; imageIdx < (int)bitmapInfoHeader->biSizeImage; imageIdx+=3)
    {
        tempRGB = bitmapImage[imageIdx];
        bitmapImage[imageIdx] = bitmapImage[imageIdx + 2];
        bitmapImage[imageIdx + 2] = tempRGB;
    }

    // zamyka plik i zwraca wskaznik bufora zawierajacego obraz
    fclose(filePtr);
    return bitmapImage;
}

static int WritePSM(char *filename, int width, int height, unsigned char *imageData)
{
    FILE             *filePtr;            // wskaznik pliku
    BITMAPFILEHEADER bitmapFileHeader;    // naglowek pliku BMP
    BITMAPINFOHEADER bitmapInfoHeader;    // naglowek obrazu BMP
    PSMFILEHEADER    PSMFileHeader;       // naglowek pliku PSM
    PSMINFOHEADER    PSMInfoHeader;       // naglowek obrazu PSM
    RGBQUAD          quad;
    int              tryb, imageIdx;      // tryb barwy, indeks obrazu
    unsigned char    tempRGB;             // zmienna zamiany skladowych
    unsigned int    skala_szar;
    // otwiera plik do zapisu w trybie "writing binary"
    filePtr = fopen(filename, "wb");
    if (!filePtr)
        return 0;

    // definiuje naglowek pliku
    PSMFileHeader.roz_pliku = sizeof(PSMFILEHEADER);
    PSMFileHeader.ident = PSM_ID;
    PSMFileHeader.off_kolor = width*abs(height)*3;
    PSMFileHeader.off_piksel = sizeof(PSMFILEHEADER) + sizeof(PSMINFOHEADER);

    // definiuje naglowek PSM
    PSMInfoHeader.roz_nag = sizeof(PSMINFOHEADER);
    PSMInfoHeader.szerokosc = width;
    PSMInfoHeader.wysokosc = height;
    PSMInfoHeader.kompresja = BI_RGB;
    PSMInfoHeader.rozdz_poz = bitmapInfoHeader.biXPelsPerMeter;
    PSMInfoHeader.rozdz_pion = -bitmapInfoHeader.biYPelsPerMeter;
    cout<<"Wybierz czy obraz ma byc kolorowy czy w skali szarosci: "<<endl<<endl;
    cout<<"Obraz kolorowy - 1                   Skala szarosci - 0"<<endl;
    cin>>tryb;
    cout<<endl;
    PSMInfoHeader.kolor=tryb;
    cout<<"Obraz: "<<PSMInfoHeader.kolor<<endl;
    int predykator;



    // zapisuje naglowek pliku PSM
    fwrite(&PSMFileHeader, 1, sizeof(PSMFILEHEADER), filePtr);

    // zapisuje naglowek PSM
    fwrite(&PSMInfoHeader, 1, sizeof(PSMINFOHEADER), filePtr);

    if(tryb==1) //obraz kolorowy
    {
    fwrite(imageData, 1, PSMFileHeader.off_kolor, filePtr);
    }
    else // obraz w skali szarosci
    {

       for (imageIdx = 0; imageIdx < (int)bitmapInfoHeader.biSizeImage; imageIdx++)
        {
            tempRGB = (int)(0.229*imageData[imageIdx]+0.587*imageData[imageIdx+1]+0.114*imageData[imageIdx+2]);
            imageData[imageIdx]=tempRGB;
        }
    fwrite(imageData, 1, PSMFileHeader.off_kolor, filePtr);

    }

    // zamyka plik
    fclose(filePtr);
    cout<<endl;
    cout<<"Kodowanie wykonano poprawnie!"<<endl;
    cout<<"Utworzono plik: "<<endl;
    cout<<"Rozmiar pliku: "<<PSMFileHeader.off_kolor<<endl;
    cout<<"Szerokosc obrazu: "<<PSMInfoHeader.szerokosc<<endl;
    cout<<"Wysokosc obrazu: "<<PSMInfoHeader.wysokosc<<endl;
    cout<<"Rozdzielczosc pozioma: "<<PSMInfoHeader.rozdz_poz<<endl;
    cout<<"Rozdzielczosc pionowa: "<<PSMInfoHeader.rozdz_pion<<endl;
    cout<<"Bit/pixel: "<<bitmapInfoHeader.biBitCount<<endl;
    cout<<"Paleta kolorow: "<<bitmapInfoHeader.biClrUsed<<endl;
    cout<<"Obraz: ";
        if(PSMInfoHeader.kolor==1)
            cout<<"Kolorowy"<<endl;
        else
            cout<<"Skala Szarosci"<<endl;

    cout<<"Kompresja: "<<PSMInfoHeader.kompresja<<endl;

    return 1;
}


int main()
{
    // wczytywanie obrazu w formacie BMP
	char *filename = "./obraz.bmp";
	BITMAPINFOHEADER myBitmapInfoHeader;
	unsigned char *bitmapImage;
	bitmapImage = LoadBmp(filename, &myBitmapInfoHeader);

    // zapis obrazu w formacie PSM
	char* filename2 = "./obraz.psm";
	int result, width, height;
	width = (int) myBitmapInfoHeader.biWidth;
	height = (int) myBitmapInfoHeader.biHeight;

	result = WritePSM(filename2, width, height, bitmapImage);

}
 

Pozdrawiam,
Meniu

0
                skala_szar[i][j] = quad.rgbRed;
                skala_szar[i][j] = quad.rgbGreen;
                skala_szar[i][j] = quad.rgbBlue;

Em, co to ma robić?

Poza tym podziel ten kod sensownie na klasy i nie mieszaj działania z operacjami I/O (tak jak we WritePSM).

0

To była ostatnia z prób przekazania bitów RGB do tablicy pikseli ale nie wyszło.

0

Coś tutaj mi nie pasuje:
(int)(0.229*imageData[imageIdx]+0.587*imageData[imageIdx+1]+0.114*imageData[imageIdx+2])/255

Weźmy jakieś przykładowe dane RGB(200, 200, 200):
(0.229*200 + 0.587*200 + 0.114*200) / 255 = 0.72, a potem to 0.72 jeszcze rzutujesz na inta, nie ma prawa wypalić.

1

Wzór na skalę szarości jaki udało mi się ustalić to:
Y= 0,299 * R + 0,587 * G + 0,114 * B

To dzielenie przez 255 jest nie potrzebne.

0

I jak po poprawie?

0

Program kompiluje się ale podczas wykonywania programu i wyborem opcji skala szarości - 0 wyskakuje błąd.

0

Em, w ogóle to jak Ty to liczysz?
Nie powinieneś w pętli przeskakiwać co trzy?

0

Nie wiem. Sugerowałem się kodem c++ zamieszczonym na stronie:
http://www.algorytm.org/przetwarzanie-obrazow/skala-szarosci/skala-szarosci-1-c.html

0

To zrób tak:
Wywal cały ten kod i napisz sam, bez korzystania z poradników, tak abyś rozumiał każdą linijkę.
Bo to co robisz w tej pętli nie ma sensu - nie liczysz średniej ważonej dla każdego z pikseli, a każdego ze składników po kolei, przez co wychodzi jakieś byle co.

1 użytkowników online, w tym zalogowanych: 0, gości: 1