utorok, 17 marec 2015 10:40 Written by 2704 times
Rate this item
(2 votes)

C++ - kombinácia bitmapových obrázkov + pootočenie bitmapového obrázku

Vytvoril som malú formulárovú aplikáciu - malý príklad, ako skombinovať dve bitmapy do jednej v nastavenom percentuálnom pomere odtieňov + pootočenie bitmapy o nastavený uhol. Využívam Runtime objekty napísané v C#. Syntax v C++ je trochu odlišná v tomto prípade, ako sú C++ programátori zvyknutý písať pri využívaní MFC (Microsoft fundation classes) knižnice napísanej v C++. Ttreba si tu zvyknúť napr. na drobné detaily typu namiesto operátora "new" sa musí použiť nový operátor "gcnew" pri vytváraní objektov napísaných v C#.

Podmienky:
- predpokladám u programátora základné znalosti z C++ a objektového programovania
- nastavenie projektu v sekcii "Bitmaps Property pages":
    - Use of MFC: Use Standard Windows Libraries
    - Character set: Use Unicode Character Set
    - Common Language Runtime support: Pure MSIL Common Language Runtime Support (/clr:pure)
    - Whole Program optimalization: No whole Program optimalization

Projekt som nazval "Bitmaps", namespace takisto "Bitmaps". Hlavný obsah zdrojového kódu je uložený v súbore Form1.h.
V prílohe sú dva súbory Bitmaps.cpp a Form1.h a dva testovacie obrázky na ukážku motorhead1.bmp a motorhead2.bmp.

Form


Na formulári sú vložené 4 objekty Picturebox. Picturebox1 a Picturebox2 slúžia ako zdroj pre obrázok po skombinovaní bitmáp do jednej a vložení nového bitmapového obrázku do objektu Picturebox3. Po štarte aplikácie si nakopírujte obrázky do adresára, kde sa nachádza výsledný spustiteľný súbor Bitmaps.exe a môžete skúšať. Nahrajte pomocou tlačidla "Load picture 1" prvý obrázok, pomocou tlačidla "Load picture 2" druhý, nastavte percentuálny odtieň druhého obrázku v prvom pomocou objektu "trackBar1" a  stlačte tlačidlo "Combine pictures". Výsledok je vidno ihneď. Pootočenie obrázku "Picturebox2" je možné tlačidlom "Rotate picture". Nastavte uhol pootočenia a stlačte tlačidlo. Obrázok z objektu "Picturebox2" bude pootočený a zobrazený v objekte "Picturebox4".

Malé vysvetlenie k programu.
Kombinácia obrázkov spočíva v prečítaní RGB čísla farby každého jedného bodu "pixelu" oboch bitmáp, rozložení farby na R,G a B zložky a vypočítaní z nich nového RGB čísla farby z nových zložiek RGB. Rovnica výpočtu je jednoduchá a zo zrdrojového kódu zrejmá. Ide o rozdelenie pomeru pôvodných RGB zložiek podľa nastaveného pomeru odtieňu od jednej farby k druhej. Pomery sú sčítané a súčet nových pomerov zložky tvorí novú zložku. Nové čislo farby sa potom vypočíta zo všetkých nových RGB zložiek.

Rotácia obrázku spočíva v prečítaní RGB čísla farby bodu, vypočítaní novej súradnice bodu pootočenú o zadaný uhol v objekte "numericUpDown1" a nastavení tohto čísla farby RGB do nového bodu. Rovnice pootočenia sú vidno v zdrojom kóde takisto a trochu si nimi pripomenieme matematiku zo strednej školy.:)

Kód v CPP - mixBitmaps:

 

private: System::Drawing::Bitmap^ MixBitmaps(System::Drawing::Bitmap^ bitmap1, 
												 System::Drawing::Bitmap^ bitmap2, 
												 int steps,
												 int stepno)
			 {
				//typedef unsigned char * buffer;

				int h = bitmap1->Height < bitmap2->Height ? bitmap1->Height : bitmap2->Height;
				int w = bitmap1->Width < bitmap2->Width ? bitmap1->Width : bitmap2->Width;

				// Check if h or w are nonzero ...
				if (h == 0 && w == 0)
			    {
					throw std::invalid_argument("Bitmaps must be loaded!");
	            }

				this->progressBar1->Value = 0;				

				System::Drawing::Bitmap^ result = gcnew Bitmap(w, h, System::Drawing::Imaging::PixelFormat::Format24bppRgb);
				System::Drawing::Color color, color1, color2;
				int R, G, B;
				double s1 = (double) (steps - stepno) / (double) steps;
				double s2 = (double) stepno / (double) steps;

				for (int y = 0; y < h; y++)
				{
					for (int x = 0; x < w; x++)
					{
						color1 = bitmap1->GetPixel(x, y);
						color2 = bitmap2->GetPixel(x, y);

						R = color1.R * s1 + color2.R * s2;
						G = color1.G * s1 + color2.G * s2;
						B = color1.B * s1 + color2.B * s2;

						color = System::Drawing::Color::FromArgb(R, G, B);
						
						result->SetPixel(x, y, color);		
					}										
					this->progressBar1->Value = Math::Floor ((double) y * (100 / (double) h));
					this->progressBar1->Refresh();
				}
				this->progressBar1->Value = 0;

				return result;
			 }

 

 

Kód v CPP - rotateBitmap:

 

private: System::Drawing::Bitmap^ RotateBitmap(System::Drawing::Bitmap^ src_bitmap, int angle_deg)
			 {
				int h = src_bitmap->Height;
				int w = src_bitmap->Width;

				// Check if h or w are nonzero ...
				if (h == 0 && w == 0)
			    {
					throw std::invalid_argument("Bitmap must be loaded!");
	            }

				this->progressBar1->Value = 0;				

				System::Drawing::Bitmap^ result = gcnew Bitmap(w, h, System::Drawing::Imaging::PixelFormat::Format24bppRgb);
				System::Drawing::Color color;
				double angle_rad = 2 * Math::PI * (double) angle_deg / 360;
				double cosin_angle = Math::Cos(angle_rad);
				double sin_angle = Math::Sin(angle_rad);
				double cx = (double) w / 2.0; 
				double cy = (double) h / 2.0; 
				int nx, ny;
				double deltaX, deltaY;

				for (int y = 0; y < h; y++)
				{
					for (int x = 0; x < w; x++)
					{
						deltaX = (double) x - cx;
						deltaY = (double) y - cy;

						nx = Math::Floor(deltaX * cosin_angle + deltaY * sin_angle + cx);
						ny = Math::Floor(deltaY * cosin_angle - deltaX * sin_angle + cy);

						if (nx >= 0 && nx < w && ny >= 0 && ny < h)
						{
							color = src_bitmap->GetPixel(x, y);
							result->SetPixel(nx, ny, color);		
						}
					}										
					this->progressBar1->Value = Math::Floor ((double) y * (100 / (double) h));
					this->progressBar1->Refresh();
				}
				this->progressBar1->Value = 0;

				return result;
			 }

 

 

Príjemnú zábavu.

S pozdravom

 

Last modified on štvrtok, 19 marec 2015 10:31
Alojz Benďák

Autor je administrátor webu a venuje sa programovaniu takmer 23 rokov.

  • prvý kontakt s počítačmi na strednej škole - PMD 1,2,3, PP06, Atari, Sinclair (programovanie v jazyku: strojový kód, basic a pascal):  2 roky
  • na VŠ - jazyky Turbo pascal a Turbo C: 1rok
  • programovanie databázového ekonomického širokoškálneho software v Delphi a C++ Borland (databázy Paradox): 8 rokov v Codex s.r.o. Nitra
  • programovanie webových aplikácií na databázach MySQL a MS SQL server: 1 roky na živnosť (firmy: Hermes Nitra, Schindler v Bratislave)
  • pracoval ako DBA v Homecredit Brno a vo VÚB Bratislava ako vyvojár + optimalizácie v SQL a PL/SQL na Oracle 11g (firma Accenture)
  • programoval programy pre súkromné firmy pre HW na skenovanie povrchov nádrží pre skladovanie tekutých palív (pristroj Leica)
  • momentálne pracuje ako DBA pod Oracle 11g a ako vyvojár vnútropodnikových databázových aplikacií v PHP, SQL, C++, C# a interface v PL/SQL: 11 rokov
  • ďalej programuje s HTML, CSS, Ajax, Javascript, VBA, MS visual C++ a C# malé podporné aplikácie
  • certifikát SQL expert for Oracle 11g   
  • spolupracuje a aktívne učí pre počítačové firmy: Lapis, IVIT v Nitre