• Najnowsze pytania
  • Bez odpowiedzi
  • Zadaj pytanie
  • Kategorie
  • Tagi
  • Zdobyte punkty
  • Ekipa ninja
  • IRC
  • FAQ
  • Regulamin
  • Książki warte uwagi

C++ problem z bitmapą

Object Storage Arubacloud
0 głosów
661 wizyt
pytanie zadane 3 stycznia 2017 w C i C++ przez ciastek2808 Początkujący (490 p.)

Witam, mam problem z pewnym zadaniem z bitmapą. Mianowicie mam pokolorować za pomocą programu w C++ obraz, który początkowo jest w odcieniach szarości za pomocą tablicy przejść która wygląda tak: 

gdzie n-odcień szarości, a r,g,b to składowe koloru. 

Kod który napisałam wygląda tak: 

#include <iostream>
#include <fstream>

using namespace std;

struct BITMAPFILEHEADER
{
   int bfType;
   int bfSize;
   int bfReserved1;
   int bfReserved2;
   int bfOffBits;
};

struct BITMAPINFOHEADER
{
   int biSize;
   int biWidth;
   int biHeight;
   int biPlanes;
   int biBitCount;
   int biCompression;
   int biSizeImage;
   int biXpelsPerMeter;
   int biYpelsPerMeter;
   int biCrlUses;
   int biCrlImportant;
};

struct kolor
{
   unsigned char R;
   unsigned char G;
   unsigned char B;
};

void odczytaj_naglowek(fstream &obraz,BITMAPFILEHEADER &ob)
{

    obraz.read(reinterpret_cast<char*>(&ob.bfType), 2);
    obraz.read(reinterpret_cast<char*>(&ob.bfSize), 4);
    obraz.read(reinterpret_cast<char*>(&ob.bfReserved1), 2);
    obraz.read(reinterpret_cast<char*>(&ob.bfReserved2), 2);
    obraz.read(reinterpret_cast<char*>(&ob.bfOffBits), 4);

}

int odczytaj_naglowek_obrazu(fstream &obraz,BITMAPINFOHEADER &ob)
{

    obraz.read(reinterpret_cast<char*>(&ob.biSize), 4);
    obraz.read(reinterpret_cast<char*>(&ob.biWidth ), 4);
    obraz.read(reinterpret_cast<char*>(&ob.biHeight), 4);
    obraz.read(reinterpret_cast<char*>(&ob.biPlanes), 2);
    obraz.read(reinterpret_cast<char*>(&ob.biBitCount), 2);
    obraz.read(reinterpret_cast<char*>(&ob.biCompression), 4);
    obraz.read(reinterpret_cast<char*>(&ob.biSizeImage), 4);
    obraz.read(reinterpret_cast<char*>(&ob.biXpelsPerMeter), 4);
    obraz.read(reinterpret_cast<char*>(&ob.biYpelsPerMeter), 4);
    obraz.read(reinterpret_cast<char*>(&ob.biCrlUses), 4);
    obraz.read(reinterpret_cast<char*>(&ob.biCrlImportant), 4);

    return obraz.tellg();
}

int policz(int n)
{
    if(n==0) return 0;

    else return policz(n-1)+3;
}

void odczytaj_obraz(fstream &obraz,unsigned char tab[], BITMAPINFOHEADER ob)
{

    for(int i=0; i<ob.biSizeImage/3; i++)
    {
        obraz.read(reinterpret_cast<char*>(&tab[i]),3);
    }

    obraz.clear();

}
void koloruj(unsigned char tab[], kolor tab_k[], BITMAPINFOHEADER ob)
{
    for(int i=0; i<ob.biSizeImage/3; i++)
    {

        int k=tab[i];

        if(k==0)
        {
            tab_k[i].R=0;
            tab_k[i].G=0;
            tab_k[i].B=0;

        }

        if(k>0 && k<86)
        {
            tab_k[i].R=policz(k);
            tab_k[i].G=0;
            tab_k[i].B=0;
        }

        if(k==86)
        {
            tab_k[i].R=255;
            tab_k[i].G=0;
            tab_k[i].B=0;
        }

        if(k>86 && k<171)
        {
            tab_k[i].R=255;
            tab_k[i].G=policz(k);
            tab_k[i].B=0;
        }

        if(k==171)
        {
            tab_k[i].R=255;
            tab_k[i].G=255;
            tab_k[i].B=0;
        }

        if(k>171 && k<256)
        {
            tab_k[i].R=255;
            tab_k[i].G=255;
            tab_k[i].B=policz(k);
        }
    }
}

void skopuj_obraz(fstream &obraz_src,fstream &obraz_des,kolor tab[], BITMAPINFOHEADER ob, BITMAPFILEHEADER ob1)
{
    obraz_src.seekg(0);
    obraz_des.seekg(0);

    int k;


    for(int i=0; i<ob1.bfOffBits; i++)
    {
        obraz_src.read(reinterpret_cast<char*>(&k),1);
        obraz_des.write(reinterpret_cast<char*>(&k),1);
    }

    for(int i=0; i<ob.biSizeImage/3; i++)
    {
        obraz_des.put(tab[i].B);
        obraz_des.put(tab[i].G);
        obraz_des.put(tab[i].R);
    }

}

int main()
{
    fstream obraz;
    BITMAPFILEHEADER FileInfo;
    BITMAPINFOHEADER PictureInfo;

    obraz.open("sonar_aktywny_szary.bmp", ios::in | ios::binary);
    if(!obraz)
    {
        cout<<"Nie mozna otworzyc pliku!"<<endl;
        return 0;
    }

    odczytaj_naglowek(obraz,FileInfo);
    odczytaj_naglowek_obrazu(obraz,PictureInfo);



    unsigned char *pixmap;
    pixmap=new unsigned char[PictureInfo.biSizeImage/3];

    kolor *kolormap;
    kolormap=new kolor [PictureInfo.biSizeImage/3];

    odczytaj_obraz(obraz,pixmap, PictureInfo);
    koloruj(pixmap, kolormap, PictureInfo);

    fstream obraz_des;

    obraz_des.open("sonar_aktywny_kolorowy.bmp", ios::out | ios::binary);
    if(!obraz_des)
    {
        cout<<"Nie mozna otworzyc pliku!"<<endl;
        return 0;
    }


    skopuj_obraz(obraz,obraz_des,kolormap,PictureInfo,FileInfo);


    obraz.close();
    obraz_des.close();


    return 0;
}

I nie wiem co z nim jest nie tak :( . Owszem koloruje obrazek, ale nie tak jak powinien. Kolory są na obrazie ułożone w paski i prawie ich nie widać. Wie ktoś co może być źle? Bardzo proszę o pomoc

1 odpowiedź

0 głosów
odpowiedź 3 stycznia 2017 przez Szykem2 Nałogowiec (29,510 p.)
wybrane 6 stycznia 2017 przez ciastek2808
 
Najlepsza
Błąd jest w funkcji policz. Zauważ, że nie uwzględniasz dla jakiego koloru liczysz, przez co nie wiesz, w którym miejscu skończyć. Przykład:

W danym pikselu mamy wartość szarego równą 91, czyli zgodnie z tabelką wartość kanałów to (255, 15, 0). Problem jest z wyliczeniem wartości 15 dla kanału zielonego. Jak powinno się ją liczyć: wiemy że mamy kanał zielony czyli wzór rekurencyjny obowiązuje od wartości 87. Czyli mamy g(91) = g(90) + 3 = g(89) + 3 + 3 = g(88) + 3 + 3 + 3 = g(87) + 3 + 3 + 3 + 3 = g(86) + 3 + 3 + 3 + 3 = 0 + 3 + 3 + 3 +3 + 3 =15. Twoja wersja funkcji nie przerywa liczenia rekurencyjnego i sumuje aż do g(0) czyli 273, a to już przekracza wartość maksymalną i mamy zachowanie niezdefiniowane.

Jak naprawić: przekaż parametr do funkcji, który będzie mówił kiedy przestać liczyć(char - 'r', 'g', 'b', albo najprościej wartość graniczną).

Dodatkowy komentarz: Sugeruję nazywać zmienne/obiekty/funkcje/metody po angielsku, oraz nazwy klas camel case'm (tj. MojaKlasa) jak masz całą nazwę dużymi literami sugerujesz że jest to zmienna/obiekt stały. I jeszcze jedno te if'y można zamienić na switcha ale to ewentualnie przy optymalizacji działania kodu albo temu żeby trochę ładniej wyglądało.
komentarz 4 stycznia 2017 przez ciastek2808 Początkujący (490 p.)
Dzięki za odpowiedź, usunęłam ten błąd ale obrazek dalej wygląda jakby był szarawy. A co do zastąpienia ifów switchem to jak do switcha dać przedział?
komentarz 5 stycznia 2017 przez Szykem2 Nałogowiec (29,510 p.)

Wybacz, tak to jest jak się skacze między językami. W C++ zgodnie ze standardem switch musi przyjmować wartość stałą ale z tego co mi wiadomo to niektóre kompilatory przyjmują składnie z zakresami. Sprawdziłem tylko g++ 4.8.4

switch (15) {
    case 1 ... 10:
        std::cout << "1";
        break;
    case 11 ... 20:
        std::cout << "2";
        break;
    }
    std::cout << std::endl;

Kompiluje się i daje wynik 2 czyli działa, ale to nie jest zawarte w stnadardzie i kompilator nie musi zapewniać switcha z zakresami

komentarz 6 stycznia 2017 przez ciastek2808 Początkujący (490 p.)
Pierwszy raz słyszę o switchu z przedziałami, ale zostanę przy ifach bo muszę się trzymać standardu bo to zadanie na uczelnię, chociaż fajnie wiedzieć, że coś takiego jest możliwe. Znalazłam też inny błąd, nie wzięłam pod uwagę zerowych bajtów w wierszach obrazu, które dopełniają liczbę bajtów do wielokrotności 4, teraz wszystko działa, także dzięki za pomoc :)

Podobne pytania

+1 głos
1 odpowiedź 645 wizyt
pytanie zadane 6 grudnia 2020 w C i C++ przez KumberTwo Dyskutant (8,270 p.)
0 głosów
1 odpowiedź 709 wizyt
pytanie zadane 3 lutego 2019 w C i C++ przez Padoski Użytkownik (990 p.)
0 głosów
1 odpowiedź 1,561 wizyt
pytanie zadane 22 grudnia 2016 w C i C++ przez JAcKNT Nowicjusz (120 p.)

92,555 zapytań

141,403 odpowiedzi

319,559 komentarzy

61,942 pasjonatów

Motyw:

Akcja Pajacyk

Pajacyk od wielu lat dożywia dzieci. Pomóż klikając w zielony brzuszek na stronie. Dziękujemy! ♡

Oto polecana książka warta uwagi.
Pełną listę książek znajdziesz tutaj.

Akademia Sekuraka

Kolejna edycja największej imprezy hakerskiej w Polsce, czyli Mega Sekurak Hacking Party odbędzie się już 20 maja 2024r. Z tej okazji mamy dla Was kod: pasjamshp - jeżeli wpiszecie go w koszyku, to wówczas otrzymacie 40% zniżki na bilet w wersji standard!

Więcej informacji na temat imprezy znajdziecie tutaj. Dziękujemy ekipie Sekuraka za taką fajną zniżkę dla wszystkich Pasjonatów!

Akademia Sekuraka

Niedawno wystartował dodruk tej świetnej, rozchwytywanej książki (około 940 stron). Mamy dla Was kod: pasja (wpiszcie go w koszyku), dzięki któremu otrzymujemy 10% zniżki - dziękujemy zaprzyjaźnionej ekipie Sekuraka za taki bonus dla Pasjonatów! Książka to pierwszy tom z serii o ITsec, który łagodnie wprowadzi w świat bezpieczeństwa IT każdą osobę - warto, polecamy!

...