我正在开发一个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个最受欢迎的值,它可以很好地工作,但是在这里它并不像我希望的那样工作,因为像素值没有被正确读取。
答案 0 :(得分:2)
处理位图时需要跳过此填充。我建议更换这个周期:
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个字节。如果它具有不同的颜色深度,则需要相应地修改代码。