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

BMP Problem w zrozumieniu

VPS Starter Arubacloud
0 głosów
410 wizyt
pytanie zadane 2 lutego 2019 w C i C++ przez Padoski Użytkownik (990 p.)
edycja 2 lutego 2019 przez Padoski

Hejka, znalazłem kod dotyczący bitmap i srednio go rozumiem. Kod wyglada nastepująco:

 

#include<iostream>
#include<fstream>
#include<windows.h>

using namespace std;

void przetworzBMP(ifstream &s)
{
	BITMAPFILEHEADER bmpFile;
	BITMAPINFOHEADER bmpInfo;

	if (s.is_open())
	{
		//pobranie naglowka zajmuje 14 bajtow i 40 bajtow

		s.read((char*)&bmpFile, 14);
		s.read((char*)&bmpInfo, 40);

		//wydobycie informacji o rozmiarze pliku

		int szerokosc = bmpInfo.biWidth;
		int wysokosc = bmpInfo.biHeight;

		//dlugosc kazdego wiersza musi byc podzelna przez 4 - wiersz dopelniany jest zerami :-)
		int dopelnienie = 4 - (3 * szerokosc) % 4;
		cout << "szer=" << szerokosc << endl;
		cout << "dop=" << dopelnienie << endl;

		int iloscDanych = bmpFile.bfSize - 14 - 40;


		//rezerwuje miejsce na zawartosc mapy bitow
		unsigned char* dane = new unsigned char[iloscDanych];

		//wczytanie danych

		s.read((char*)dane, iloscDanych);
		s.close();

		//utworzenie nowego pliku ze zmienionym kolorem
		ofstream nowy("klon.bmp");

		//kopiowani naglowków
		nowy.write((char*)&bmpFile, 14);
		nowy.write((char*)&bmpInfo, 40);

		//transformacja bitow

		unsigned char* wsk = dane;

		for (int i = 0; i < wysokosc; i++)
		{

			for (int j = 0; j < szerokosc; j++)
			{
				if (*wsk == 0 && *(wsk + 1) == 0 && *(wsk + 2) == 0)
				{

					*wsk = (byte)255;
					*(wsk + 1) = (byte)0;
					*(wsk + 2) = (byte)100;
				}
				wsk += 3;
			}
			wsk += dopelnienie;
		}

		nowy.write((char*)dane, iloscDanych);
		nowy.close();

		delete[] dane;


	}
}

int main()
{
	ifstream bmp("examp.bmp");
	przetworzBMP(bmp);

	system("PAUSE");
}

I moje pytania są następujące: Czym jest nagłowek? Dlaczego dlugosc wiersza musi być podzielna przez 4 ? Co to znaczy kopiowanie nagłowków? I rowniez nie rozumiem zbytnio transformacji bitów.

unsigned char* wsk = dane;

		for (int i = 0; i < wysokosc; i++)
		{

			for (int j = 0; j < szerokosc; j++)
			{
				if (*wsk == 0 && *(wsk + 1) == 0 && *(wsk + 2) == 0)
				{

					*wsk = (byte)255;
					*(wsk + 1) = (byte)0;
					*(wsk + 2) = (byte)100;
				}
				wsk += 3;
			}
			wsk += dopelnienie;
		}

Czy mogłby ktoś w stanie jakos postarać się mi to wytlumaczyć, albo przesłac linka do jakiegoś źródła z którego bym mogl sie o tym dowiedziec ? (lecz narazie nie znam podstaw i wgl jak takie cos zachodzi) będę bardzo wdzieczny :)))

W najblizszym czasie chciałbym umiec wykonac takie zadanie:

Napisz program, któryw pliku bmppodzieli obraz na n*m części(dzieląc wysokość nanrównychczęści i szerokość na m równych części), w obrębie każdej części kolor pikseli zamieńwartościami średnimi w obrębie danej częsci

komentarz 2 lutego 2019 przez j23 Mędrzec (195,220 p.)
edycja 2 lutego 2019 przez j23

int dopelnienie = 4 - (3 * szerokosc) % 4;

To jest źle. Dopełnienie dla szerokości (w bajtach) podzielnych przez 4 powinno być 0, a według tego wzoru będzie 4.


Bezpieczniej będzie tak czytać:

//wczytanie danych
scanlineSize = ((bmpInfo.biWidth * bmpInfo.biBitCount + 31) / 32) * 4;
iloscDanych = scanlineSize * bmpInfo.biHeight;

unsigned char* dane = new unsigned char[iloscDanych];

s.seekg(bmpFile.bfOffBits);
s.read((char*)dane, iloscDanych);

 

1 odpowiedź

+2 głosów
odpowiedź 2 lutego 2019 przez criss Mędrzec (172,590 p.)

Czym jest nagłowek?

Każdy format ma swój nagłówek/header. Np. kilka bajtów które zawsze są na początku danego formatu, aby programy ładujące np. taki obrazek BMP mogły szybko zwerfyikować czy to faktycznie jest format BMP. W przypadku obrazów na pewno też rozmiar obrazu w pikselach, ilość kanałow i layout (RG/RGB/RGBA/BGRA....), ilość bitów na kanał, format zapisu pixela itd... Zobacz sobie na wikipedii z czego się składa header BMP.

Dlaczego dlugosc wiersza musi być podzielna przez 4 ?

Nie wiem, możliwe, że specyfikacja BMP tego wymaga.

 Co to znaczy kopiowanie nagłowków?

Dokładnie to. Nagłówek jest czytany z wejściowego pliku i przepisywany do drugiego pliku. 

Z tego co widze, autor pewnie zakłada RGB 8bitów na kanał i dla każdego piksela jeśli jest czarny (warunek *wsk == 0 && *(wsk + 1) == 0 && *(wsk + 2) == 0), to podmienia go na RGB {255,0,100}.

1
komentarz 2 lutego 2019 przez Arkadiusz Sikorski Pasjonat (20,160 p.)

Dlaczego dlugosc wiersza musi być podzielna przez 4 ?

O ile pamiętam, to zaszłość historyczna spowodowana wymogiem wyrównania pamięci.

Więcej opisane jest tutaj:

The reason you read/write data in/out from RAM and the CPU 4-bytes at a time, is because this is the current _native word length_ of the processor-- 32 bits. aka "unsigned long".

Czytanie 4 bajtów na raz jest po prostu szybsze i bardziej naturalne dla procesora. Czy raczej "było", bo obecnie procesory operują na dłuższych słowach. 

Odpowiedzią na to pytanie jest chyba po prostu "kiedyś był taki wymóg spowodowany działaniem sprzętu, teraz tak jest, żeby była zgodność z formatem, który powstał wcześniej".

komentarz 3 lutego 2019 przez Padoski Użytkownik (990 p.)

@Criss,
 Dzięki, wielkie mam jeszcze pytanie (warunek *wsk == 0 && *(wsk + 1) == 0 && *(wsk + 2) == 0), to podmienia go na RGB {255,0,100}.  Rozumiem ze wsk wskazuje na dane. Czym są te dane? Dlaczego stworzone są az trzy warunki( mam namysli wsk, wsk+1 wsk+2)? Czym jest wsk+1, wsk+2 wsk+3.

Chcę się przymierzyć do zrobienia tego zadania. Lecz nw w jaki sposob mogłbym wskazac na dany pixel i odczytać jego RGB, by pozniej wyliczyc srednią. Również nie wiem w jaki sposób mogłbym podzielić na n*m części. Jak narysować cokolowiek na danym pixelu ?

Napisz program, któryw pliku bmppodzieli obraz na n*m części(dzieląc wysokość nanrównychczęści i szerokość na m równych części), w obrębie każdej części kolor pikseli zamieńwartościami średnimi w obrębie danej częsci 

Z góry bardzo dziekuje i pozdrawiam

komentarz 3 lutego 2019 przez criss Mędrzec (172,590 p.)

wsk na początku wskazuje na początek bloku pikseli. Każdy pixel składa się z 3 składowych: R, G, B z których każda jest pojedynczym bajtem reprezentującym liczbę bez znaku w przedziale 0..255. Zatem pixel na pozycji x,y moze byc wskazany przez wsk+3*(y*W+x) gdzie W to szerokosc obrazu (rozmiar w osi X) w pikselach.

Teraz jesli

unsigned char* px = wsk+3*(y*W+x);

wskazuje na pixel na pozycji x,y, to px+0 wskazuje na R tego piksela, px+1 wskazuje na G, a px+2 wskazuje na B.

To powinno ci wystarczyć do zrobienia zadania.

Podobne pytania

0 głosów
1 odpowiedź 380 wizyt
pytanie zadane 16 stycznia 2020 w C i C++ przez Igor Użytkownik (740 p.)
0 głosów
1 odpowiedź 1,113 wizyt
pytanie zadane 10 stycznia 2018 w C i C++ przez marcin_kub Obywatel (1,420 p.)
0 głosów
0 odpowiedzi 358 wizyt
pytanie zadane 28 marca 2021 w Mikrokontrolery przez francus11 Gaduła (3,250 p.)

93,031 zapytań

141,995 odpowiedzi

321,300 komentarzy

62,379 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

Wprowadzenie do ITsec, tom 2

Można już zamawiać tom 2 książki "Wprowadzenie do bezpieczeństwa IT" - będzie to około 650 stron wiedzy o ITsec (17 rozdziałów, 14 autorów, kolorowy druk).

Planowana premiera: 30.09.2024, zaś planowana wysyłka nastąpi w drugim tygodniu października 2024.

Warto preorderować, tym bardziej, iż mamy dla Was kod: pasja (użyjcie go w koszyku), dzięki któremu uzyskamy dodatkowe 15% zniżki! Dziękujemy zaprzyjaźnionej ekipie Sekuraka za kod dla naszej Społeczności!

...