Archief - Images in C++

Het archief is een bevroren moment uit een vorige versie van dit forum, met andere regels en andere bazen. Deze posts weerspiegelen op geen enkele manier onze huidige ideeën, waarden of wereldbeelden en zijn op sommige plaatsen gecensureerd wegens ontoelaatbaar. Veel zijn in een andere tijdsgeest gemaakt, al dan niet ironisch - zoals in het ironische subforum Off-Topic - en zouden op dit moment niet meer gepost (mogen) worden. Toch bieden we dit archief nog graag aan als informatiedatabank en naslagwerk. Lees er hier meer over of start een gesprek met anderen.

Ovidius

Legacy Member
Beste forumleden,

Ik wil namelijk een programmaatje maken in c++ ( windows form application).
Daar zit een menubalk in, waarmee naar een afbeelding kan gebrowsed worden.
Vervolgens wordt deze weergegeven in een picturebox.
Tot zover gaat dit prima.
De volgende stap is om het negatief van deze afbeelding te berekenen in weer te geven in die picturebox, maar dit mij niet na wat zoekwerk op internet.

private: System::Void openImageToolStripMenuItem_Click(System::Object^ sender, System::EventArgs^ e)
{
OpenFileDialog^ dlg = gcnew OpenFileDialog();
dlg->Filter = "Image Files(*.PNG;*.JPG;*.JPEG;*.BMP;*.GIF)|*.PNG;*.JPG;*.JPEG;*.BMP;*.GIF";
if(dlg->ShowDialog() == Windows::Forms::DialogResult::OK)
{
ImageBox->Image = Image::FromFile(dlg->FileName); //Image is naam afbeelding
ImageBox->Top = 0;
ImageBox->Left = 0;
ImageBox->Height = ImageBox->Image->Height; //Hoogte imagebox(picturebox) = hoogte afbeelding
ImageBox->Width = ImageBox->Image->Width; //Breedte imagebox(picturebox) = breedt afbeelding

}
}

Hier zit het probleem:

private: System::Void negatiefToolStripMenuItem_Click(System::Object^ sender, System::EventArgs^ e)
{
int x;
int y;
for ( x = 0; x < Width - 1; x += 1)
{
for ( y = 0; y < Height - 1; y+=1)
{
Color KleurOrigineel = Image->GetPixel(x,y); //Color is ingebouwde functie
Color KleurNegatief;
//Argb -> 32 bit kleurenafbeelding
//KleurOrigineel.A -> Doorzichtigheid laten we ongewijzigd
KleurNegatief = Color::FromArgb(KleurOrigineel.A, 255 - KleurOrigineel.R, 255 - KleurOrigineel.G, 255 - KleurOrigineel.B);

Image->SetPixel(x,y,KleurNegatief);
}
}

ImageBox->Image;
}

Ik krijg onder andere error's over GetPixel() en SetPixel().


Hulp is welkom



Groeten Ovidius

Tyfius

Legacy Member
Kan je eens wat meer informatie geven over de exacte foutmeldingen die je krijgt? En indien mogelijk een klein sample applicatie maken die we kunnen testen.

Tyfius

Legacy Member
Base type Image heeft dus geen -> overload, wil zeggen dat ge daar geen functie op kunt oproepen, mss eens Image::GetPixel() proberen, op dezelfde manier als ge uw OpenFile doet.

Ik zie dat uw solution niet al te groot is, kunde die anders ff doorsturen?

Tyfius

Legacy Member
Alles, ZIP heel uw solution folder en zet dat online, dan trek ik mijn plan wel. Als het na 17u30 is gaat ge wel moeten wachten tot ik thuis ben. :)

Die links helpen ook niet echt, ze behandelen andere API's en zijn voor jou niet van toepassing.

NeverwinterX

Legacy Member
Misschien ben ik stekeblind maar System:: Drawing:: Image heeft toch gewoon geen GetPixel methode?

Ik denk dat je een BitMap moet gebruiken daarvoor.

Ovidius

Legacy Member
Inderdaad :), de code die ik heb overgenomen van internet heeft onder public ook:

System:: Drawing::Bitmap ^InvertImage(System:: Drawing::Bitmap ^Image)

maar ik weet niet hoe je dit kunt krijgen. :confused:
Ik doe namelijk dubbelklik op he menulistitem "negatief" (een soort knop eigenlijk),
en hierna moet de afbeelding aangepast worden. Dus die code heb ik daar ondergetypt.
Zo moet het toch zeker om te verwijzen naar dat gewenst menu-item, alleen die bitmap ( wat is dit eigenlijk ?) ontbreekt.


Groeten

Tyfius

Legacy Member
Ok, thuis, ik zal er mij is aan zetten.
De beste manier is trouwens ne color matrix gebruiken, Get/SetPixel is namelijk niet de snelste en meest vriendelijke API.

Ovidius

Legacy Member
Ok, bedankt, hoe efficiënter hoe beter, dat is waar.

Maar het is ook de bedoeling om kennis te maken met deze procedure/code.
Vb in matlab doe ik dit met 5 regels code door gebruik te maken van de ingebouwde functies van de ImageProcessing Toolbox. Dat werkt allemaal snel maar van de achterliggende procedure ( " beeldverwerking") krijg je eigenlijk niks te zien.
Maar in c++ is dit sowieso langer veronderstel ik

Tyfius

Legacy Member
Voila:

Code:
// Ik heb bovenaan wel nog de namespace System::Drawing::Imaging moeten toevoegen.

private: System::Void negatiefToolStripMenuItem_Click(System::Object^  sender, System::EventArgs^  e) 
 {
	 // Het handigste werken we met een Bitmap. We maken eerst een kopie van de originele afbeelding
	 // en vervolgens maken we een nieuwe afbeelding aan die als de negatieve afbeelding zal
	 // ingevuld worden.
	 Bitmap^ original = static_cast<Bitmap^>(ImageBox->Image);
	 Bitmap^ bitmap = gcnew Bitmap(ImageBox->Image->Width, ImageBox->Image->Height);

	 // Maak het object aan dat de uiteindelijke afbeelding zal tekenen.
	 Graphics^ g = Graphics::FromImage(bitmap);

	 // This is the tricky part. We gebruiken een color matrix om de kleuren te inverteren.
	 ColorMatrix^ colorMatrix = gcnew ColorMatrix();
	 colorMatrix->Matrix00 = -1.0f;
	 colorMatrix->Matrix11 = -1.0f;
	 colorMatrix->Matrix22 = -1.0f;
	 colorMatrix->Matrix33 = 1.0f;
	 colorMatrix->Matrix44 = 1.0f;

	 // Wanneer alleen bovenstaande waarden gebruikt worden zal dit op Windows 7 resulteren in een volledig
	 // zwarte afbeelding. Geen idee waarom. Op Windows XP werkt voorgaande. Om overal een negatief van de
	 // afbeelding te krijgen moeten we nog een aantal extra waarden op 1 zetten.
	 colorMatrix->Matrix40 = 1.0f;
	 colorMatrix->Matrix41 = 1.0f;
	 colorMatrix->Matrix42 = 1.0f;

	 // Object die de image attributes bevat.
	 ImageAttributes^ attributes = gcnew ImageAttributes();
	 attributes->SetColorMatrix(colorMatrix);

	 // En hier gaan we dan de uiteindelijke afbeelding tekenen.
	 g->DrawImage(
		 original,
		 Rectangle(0, 0, original->Width, original->Height),
		 0,
		 0, 
		 original->Width, 
		 original->Height, 
		 GraphicsUnit::Pixel, 
		 attributes);

	 // Memory cleanup.
	 delete g;

	 // We converteren tot slot de bitmap afbeelding terug naar de afbeelding die in de ImageBox steekt.
	 ImageBox->Image = static_cast<Image^>(bitmap);				 
 }

Ovidius

Legacy Member
Tyfius, erg bedankt, je bent echt een genie :applause:

Negatief beeld werkt mooi, en door nog eens te klikken is origineel terug.
Alleen heb ik nog wat vragen over de code:
- Wat is dat juist, zo een colormatrix( groen, blauw en rood ?)
- Matrix00,Matrix11,Matrix22,Matrix33,Matrix44 wat is dit juist en waarom zoveel.
Even opgezocht, 5 rijen en 5 kolommen met elementen in de kleuren matrix.( hmmm)
(indien het er 3 waren kan ik nog wel de link leggen naar de basiskleuren).


Groeten

Tyfius

Legacy Member
Meer informatie over de ColorMatrix kan je altijd terug vinden op de MSDN pagina en detail over wat het eigenlijk doet hier.

Eigenlijk ziet onze matrix er als volgt uit:
Code:
-1  0  0  0  0
 0 -1  0  0  0
 0  0 -1  0  0
 0  0  0  1  0
 1  1  1  0  1
Ik kon ook deze als een array van floats samenstellen en die dan aan de constructor meegeven, maar het lijk mij duidelijker de individuele properties te setten. (Matrix00 komt overeen met de -1 links boven enzoverder.)

NeverwinterX

Legacy Member
Tyfius zei:
Meer informatie over de ColorMatrix kan je altijd terug vinden op de MSDN pagina en detail over wat het eigenlijk doet hier.

Eigenlijk ziet onze matrix er als volgt uit:
Code:
-1  0  0  0  0
 0 -1  0  0  0
 0  0 -1  0  0
 0  0  0  1  0
 1  1  1  0  1
Ik kon ook deze als een array van floats samenstellen en die dan aan de constructor meegeven, maar het lijk mij duidelijker de individuele properties te setten. (Matrix00 komt overeen met de -1 links boven enzoverder.)

Eigenlijk is het toch vreemd dat dat werkt? Dat vermenigvuldigt de rgb waarden met -1 (en telt er 1 bij op, maar laat ik dat negeren hier).
Van 150r 20g 30b maak je -150r -20g -30b, wat ongedefinieerd is in rgb space. Vandaar misschien het verschil tussen windows 7 en windows xp: die handelt zo'n uitzonderingsgeval misschien anders af? Misschien dat onder windows xp men dat gewoon optelt bij 255 zodat het inderdaad toevallig uitkomt als de inverse kleur, maar handelt men het onder windows 7 anders af. Of ben ik mis?

Tyfius

Legacy Member
Ik heb de code geconverteerd uit een C# helper library die wij op het werk gebruiken. De code zelf heb ik ooit is op het internet gevonden, maar dat is alweer jaren geleden. Een exact correcte uitleg kan ik dus niet geven.

Ovidius

Legacy Member
De colormatrixmethode is inderdaad zeer snel ( gebruik ik voor een negatief beeld te vormen).
Maar voor een grijswaarde is deze volgens mij niet bruikbaar, dan heb je buiten die omvormingsmatrix de originele kleurwaarden nodig van iedere pixel zodat (rood = groen) = blauw. Hiervoor is Setpixel/Getpixel handig, alleen duurt dit enkele seconden langer.

Tyfius

Legacy Member
Grijswaarden gaat ook met een ColorMatrix hoor.

Vermenigvuldig dan de RGB waarden met 0.5 in plaats van -1.
Code:
.5  0  0  0  0
 0 .5  0  0  0
 0  0 .5  0  0
 0  0  0  1  0
 0  0  0  0  1

Met een ColorMatrix kan je alle mogelijke conversies doen. Als je daarop zoekt vindt je 101 voorbeelden.

Ovidius

Legacy Member
Stel dat de originele kleuren zo zijn: [ red green blue alpha w( altijd 1 blijkbaar) ]
dan gaat [ 0,5 0,7 0,9 1,0 1,0] ---> u colormatrix --> [ 0,25 0,35 0,45 1,0 1,0] zijn.
Dit is toch niet de definitie van een grijswaarde afbeelding als ik me niet vergis.
Hiervoor dienen alle kleuren de tint van blauw te krijgen (vb) in een grijstint.
Dus [ 0,9 0,9 0,9 1,0 1,0], deze gelijke waarde geeft dan de gewenste grijze kleur. :unsure:

Jij gaat de (ongekende) originele kleuren halveren.


Groeten

Tyfius

Legacy Member
Correct, ik was het een en het ander vergeten. Je moet nog transformaties op de niveaus toepassen.

Code:
.5 .5 .5  0  0
.5 .5 .5  0  0
.5 .5 .5  0  0
 0  0  0  1  0
 0  0  0  0  1
Het archief is een bevroren moment uit een vorige versie van dit forum, met andere regels en andere bazen. Deze posts weerspiegelen op geen enkele manier onze huidige ideeën, waarden of wereldbeelden en zijn op sommige plaatsen gecensureerd wegens ontoelaatbaar. Veel zijn in een andere tijdsgeest gemaakt, al dan niet ironisch - zoals in het ironische subforum Off-Topic - en zouden op dit moment niet meer gepost (mogen) worden. Toch bieden we dit archief nog graag aan als informatiedatabank en naslagwerk. Lees er hier meer over of start een gesprek met anderen.
Terug
Bovenaan