C ++ - 位图的10种最流行的颜色

时间:2016-06-10 12:38:01

标签: c++ bitmap

我正在开发一个C ++项目 - 应该找到位图的高度,宽度和10种最流行的颜色。找到高度和宽度不是问题,我已经在几分钟内完成了,但我发现这些颜色存在严重问题。

这是我的代码:

#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");
}

这一行:

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

应该为adresPixeli写一个像素地址。它位于第10个字节,所以在此之前我只是转到文件的第10个字节:

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

在这里,我想将值读入名为mapaPixeli的数组中,该数组具有足够的内存(宽度*高度)。

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;
        }

问题是:它没有正确读取值:(我不知道为什么,我找不到错误。也许你们中的一些人能帮助我。有一个条件 - 如果它是24位(在我的情况下是1个像素是24位),它只会读取像素,检查它。

之后有一个我自己的算法,可以在一个数组中找到10个最受欢迎的值,它可以很好地工作,但是在这里它并不像我希望的那样工作,因为像素值没有被正确读取。

1 个答案:

答案 0 :(得分:2)

我想你忘记了位图图片中每一行末尾的填充,如下图所示: enter image description here

处理位图时需要跳过此填充。我建议更换这个周期:

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

有两个嵌套循环并在处理每一行之前在文件中搜索:

    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;
        }
    }

在循环之前,您计算填充并将其放入变量:

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

然后在每行之前将文件流指针移动到每行的开头:

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

此代码假定有问题的BMP文件每像素有3个字节。如果它具有不同的颜色深度,则需要相应地修改代码。