2016-06-10 7 views
0

Ich arbeite an einem C++ - Projekt - es soll Höhe, Breite und 10 beliebtesten Farben einer Bitmap finden. Das Finden von Höhe und Breite ist kein Problem, ich habe es innerhalb von Minuten gemacht, aber ich habe ernsthafte Probleme mit der Suche nach diesen Farben.C++ - 10 beliebtesten Farben einer Bitmap

Hier ist mein Code:

#include <iostream> 
#include <fstream> 
#include <vector> 


using namespace std; 

void main(int argc, char *argv[]) 
{ 
    ifstream plik; 
    plik.open(argv[1]); 

    if (plik.good()) 
    { 
     cout << "Bitmapa zaladowana poprawnie." << endl; 


     // Idziemy do 10 bajtu w pliku - tam jest zapisany numer bajtu pod ktorym zaczynaja sie informacje o pixelach 
     plik.seekg(10, ios::beg); 
     int adresPixeli = 0; 
     plik.read((char*)&adresPixeli, sizeof(int)); 

     // Idziemy na 18 bajt w pliku (pod nim jest zapisana szerokosc, a od 22 jest wysokosc) 
     plik.seekg(18, ios::beg); 
     int szerokosc, wysokosc; 

     // Zapisujemy szerokosc do zmiennej szerokosc (w pixelach) 
     plik.read((char*)&szerokosc, sizeof(int)); 

     plik.read((char*)&wysokosc, sizeof(int)); 

     cout << "Szerokosc obrazu to: " << szerokosc << endl; 
     cout << "Wysokosc obrazu to: " << wysokosc << endl; 

     // Przejscie na 28 bajt w pliku, pod nim jest zapisana informacja o tym ile bitow ma kazdy pixel 
     plik.seekg(28, ios::beg); 
     int iloscBitow = 0; 
     // Read number of bytes used per pixel 
     plik.read((char*)&iloscBitow, sizeof(short int)); 



     // Jesli mamy wysokosc i szerokosc to mozemy stworzyc tablice ktora bedzie przechowywac wartosci kolorow pixeli 
     // Rozmiar tablicy musi byc rowny szerokosc * wysokosc, a jeden pixel ma 3 bajty informacji 
     // RGB - red green blue, czyli informacje o kolorach (po 1 bajcie na red, green i blue) 

     // Alokacja pamieci dla tablicy ktora bedzie przechowywac wartosci bitow. 
     int *mapaPixeli = new int [szerokosc * wysokosc]; 

     // Przejście do bajtu pod ktorym zaczynaja sie pixele 
     plik.seekg(adresPixeli, ios::beg); 

     // Zmienna do ktorej bedziemy wczytywac wartosc pixela (kolor - RGB, zapisany szesnastkowo np. 0xFFFFFF to kolor bialy, a 
     // 0x000000 to kolor czarny 
     // pozniej policzymy najczesciej wystepujace kolory i je wypiszemy 
     int wartoscPixela; 
     for (int i = 0; i < szerokosc * wysokosc; i++) 
     { 
      wartoscPixela = 0; 
      // Wczytujemy 3 bajty - bo na tylu zapisane sa informacje odnosnie 1 pixela, do zmiennej wartoscPixela 
      plik.read((char*)&wartoscPixela, 3); 
      // Zapisujemy wartosc w tablicy pixeli 
      if (iloscBitow == 24) 
      mapaPixeli[i] = wartoscPixela; 
     } 

     for (int i = 0; i < 100; i++) 
      cout << hex << mapaPixeli[i] << " "; 


     // Szukanie 10 najpopularniejszych kolorow 

     int max_count = 0; 
     int wynik; 
     // Przechowuje te elementy ktore juz zostaly policzone 
     vector<int> wartosciUnikalne; 
     // Sprawdza, czy element jest juz w wektorze wartosciUnikalne 
     bool czyJest = find(wartosciUnikalne.begin(), wartosciUnikalne.end(), 1) != wartosciUnikalne.end(); 
     // Sprawdza czy wypisano juz 10 kolorow 
     int ileKolorow = 0; 

     cout << "Kody szesnastkowe 10 najpopularniejszych kolorow w bitmapie: to" << endl; 

     // Bedziemy wyliczac wystepowania 10 najczesciej powtarzajaych sie elementow 
     for (int ilosc = 0; ilosc < 10; ilosc++) 
     { 
      int max_count = 0; 

      for (int i = 0; i < szerokosc*wysokosc; i++) 
      { 
       // Sprawdza czy element jest w wartosciUnikalne 
       czyJest = find(wartosciUnikalne.begin(), wartosciUnikalne.end(), mapaPixeli[i]) != wartosciUnikalne.end(); 
       int count = 1; 
       // Jesli nie ma elementu w wartosciUnikalne - liczy jego wystapienia 
       if (czyJest == false) 
       { 
        for (int j = i + 1; j<szerokosc*wysokosc; j++) 
        if (mapaPixeli[i] == mapaPixeli[j]) 
         count++; 
        if (count>max_count) 
         max_count = count; 
       } 
      } 

      for (int i = 0; i < szerokosc*wysokosc; i++) 
      { 
       int count = 1; 
       czyJest = find(wartosciUnikalne.begin(), wartosciUnikalne.end(), mapaPixeli[i]) != wartosciUnikalne.end(); 

       // Sprawdza czy jest element w wartosci unikalne, jesli nie ma - szuka aktualnie sprawdzanego elementu o najwiekszej 
       // ilosci wystapien i wypisuje go 
       if (czyJest == false) 
       { 
        for (int j = i + 1; j < szerokosc*wysokosc; j++) 
        if (mapaPixeli[i] == mapaPixeli[j]) 
         count++; 

        if (count == max_count && ileKolorow <=10) 
        { 
         ileKolorow++; 
         wynik = mapaPixeli[i]; 
         cout << hex << wynik << endl; 

         //cout << count << " " << max_count << endl; 
         wartosciUnikalne.push_back(wynik); 
        } 
       } 
      } 
     } 
    } 

    else 
     cout << "Nie udalo sie wczytac bitmapy." << endl; 

    system("PAUSE"); 
} 

Diese Zeile:

plik.read((char*)&adresPixeli, sizeof(int)); 

Soll ja eine Adresse von Pixeln adresPixeli schreiben. Es ist am 10. Byte, so vor, dass ich gehen nur bis zum 10. Byte der Datei hier:

plik.seekg(10, ios::beg); 

Und hier habe ich die Werte in ein Array lesen möchten genannt mapaPixeli, die genügend Speicher (Breite * Höhe) hat.

for (int i = 0; i < szerokosc * wysokosc; i++) 
     { 
      wartoscPixela = 0; 
      // Wczytujemy 3 bajty - bo na tylu zapisane sa informacje odnosnie 1 pixela, do zmiennej wartoscPixela 
      plik.read((char*)&wartoscPixela, 3); 
      // Zapisujemy wartosc w tablicy pixeli 
      if (iloscBitow == 24) 
      mapaPixeli[i] = wartoscPixela; 
     } 

Das Problem ist:.. Es Werte nicht richtig lesen :(Ich weiß nicht, warum, und ich kann einen Fehler nicht gefunden Vielleicht werden einige von euch der Lage sein, mir dort zu helfen Auch gibt es eine Bedingung - es liest nur Pixel, wenn es 24 Bits ist (1 Pixel ist 24 Bits in meinem Fall), überprüfte es

Dann danach gibt es meinen eigenen Algorithmus, um 10 populärste Werte in einem Array zu finden, das funktioniert perfekt, aber hier funktioniert es nicht so, wie ich es gerne hätte, weil Pixelwerte nicht richtig gelesen werden

+4

Ich glaube, Sie unterschätzen die Komplexität des BMP-Dateiformats https://en.wikipedia.org/wiki/BMP_file_format. Können Sie eine externe Bibliothek verwenden, um auf die Pixel zuzugreifen? –

+0

Nein Ich kann keine externe Bibliothek verwenden. Das ist das Problem: Ja, ich habe diese Seite im Wiki schon einmal gelesen. Ich weiß, es ist ziemlich komplex, aber ich muss es irgendwie tun. – MindRoller

+1

Sie werden verloren gehen, wenn Sie Code hetzen, ohne ein wenig darüber nachzudenken. Erstellen Sie eine geeignete Klasse, lesen Sie den Dateikopf mit der entsprechenden Struktur, speichern Sie Informationen in Elementvariablen, teilen Sie Ihren Code in separate logische Einheiten (verschiedene Funktionen) usw. Wie Alessandro Teruzzi sagte, ist das nicht so einfach. – Boiethios

Antwort

2

Ich glaube, du hast die Auffüllung am Ende jeder Zeile in der Bitmap vergessen wie auf diesem Bild gezeigt: enter image description here

Sie müssen diese Auffüllung bei der Verarbeitung der Bitmap überspringen. Ich schlage vor, ersetzen Sie diesen Zyklus:

for (int i = 0; i < szerokosc * wysokosc; i++) { 
    ... 
} 

mit zwei verschachtelten Zyklen und sucht in der Datei vor jeder Zeile Verarbeitung:

int wartoscPixela; 
    int bytesPerPixel = 3; 
    int padding = szerokosc * bytesPerPixel % 4 == 0 ? 0 : 4 - szerokosc * bytesPerPixel % 4; 
    for (int i = 0; i < szerokosc; i++) 
    { 
     plik.seekg(adresPixeli + (szerokosc*bytesPerPixel+padding)*i, ios::beg); 
     for (int j = 0; j < wysokosc; j++) 
     { 
      wartoscPixela = 0; 
      // Wczytujemy 3 bajty - bo na tylu zapisane sa informacje odnosnie 1 pixela, do zmiennej wartoscPixela 
      plik.read((char*)&wartoscPixela, 3); 
      // Zapisujemy wartosc w tablicy pixeli 
      if (iloscBitow == 24) 
       mapaPixeli[i*szerokosc+j] = wartoscPixela; 
     } 
    } 

Vor den Zyklen Sie die Polsterung berechnen und sie in eine Variable setzen:

int padding = szerokosc * bytesPerPixel % 4 == 0 ? 0 : 4 - szerokosc * bytesPerPixel % 4; 

Dann vor jeder Zeile bewegen Sie die Datei-Stream-Zeiger auf den Anfang jeder Zeile:

plik.seekg(adresPixeli + (szerokosc*bytesPerPixel+padding)*i, ios::beg); 

Bei diesem Code wird davon ausgegangen, dass die betreffende BMP-Datei 3 Byte pro Pixel aufweist. Wenn es eine andere Farbtiefe hat, müssen Sie Ihren Code entsprechend ändern.

+0

Das ist ein guter Punkt, +1, versucht, Programm funktioniert besser, aber immer noch nicht richtig:/ – MindRoller

+0

Nun, es ist wirklich seltsam, weil es funktionieren sollte ... ehh verdammt, es berechnet die erste Farbe richtig (Bitmap hat 2 Farben) aber zweite ist nicht korrekt, es sagt 6363 statt 006363. – MindRoller

+0

Okay, ich habe alles korrigiert und es funktioniert jetzt! Danke @Reilly :) Beste Antwort ist hier! – MindRoller