PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : [VB .NET] Farbwert einer Grafik auslesen


Dj-Atzy
2006-01-26, 15:06:04
Hallo,

Ich möchte ein programm schreiben, dass mir den durchschnitts Farbwert einer Jpeg-Datei, die in einer Picture box ist, anzeigt.
Das ganze soll mit VB .NET realisiert werden und da funktioniert der VB 6 Befehl Point(x,y) leider nicht.

Habt ihr ne ahnung wie das geht???

ScottManDeath
2006-01-26, 15:27:09
Bitmap bmp = the_pix_box.Image as Bitmap;

bmp.GetPixel(x,y) ....

Dj-Atzy
2006-01-26, 15:45:56
üäh? kapier ich jetzt nicht sry.

Kannst du das vll. erklären?

weil so:

Bitmap bmp = PictureBox1.Image as Bitmap

bmp.GetPixel(x, y)


will das ganze nicht.

ScottManDeath
2006-01-26, 16:43:50
Naja, Du wandelst castest das Image der Picturebox in den Typ Bitmap um. Wenn das klappt, kannst du dir mit GetPixel die Pixel auslesen. Alternativ musst Du ein eigenes Bitmap Objekt erstellen und die Daten aus dem Image der Picturebox reinkopieren und dann GetPixeln.

Syntax fürs castet kenn ich nicht in VB.NET, musst Du mal nachsehen.

MeLLe
2006-01-26, 21:56:01
So ähnlich :)

Genau hab ich grad auch net zur Hand, aber im Grunde sollte es so

.
.
.
Dim mybmp As Bitmap = PictureBox1.Image.Clone
Dim mygfx As Graphics = mybmp.CreateGraphics()
Dim x,y
Dim sumcol As Double
Dim mycol As Color

For x = 1 To g.Width
For y = 1 To g.Height
mycol = g.getPixel(x,y)
mycol = mybmp.getPixel(x,y)
sumcol = (mycol.R + mycol.G + mycol.B)/3.0
Next
Next

MessageBox.Show("Ergebnis: " & sumcol/(x*y))
.
.
.

klappen (können) ;)


Edit:
Hab grad bemerkt: schon das Bitmap kann ja ge-getPixel-t werden. Nicht erst das Graphics-Objekt. Hört hört :)

Dj-Atzy
2006-01-27, 07:31:36
Also:
Dim mybmp As Bitmap = PictureBox1.Image.Clone
Dim x, y
Dim sumcol As Double
Dim mycol As Color

x = 1
y = 1

For x = 1 To PictureBox1.Size.Width - 1
For y = 1 To PictureBox1.Height - 1
mycol = mybmp.GetPixel(x, y)
'sumcol = (mycol.R + mycol.G + mycol.B) / 3.0
Next
Next

'Label1.Text = ("Ergebnis: " & sumcol / (x * y))
Label1.Text = mycol.R
Label2.Text = mycol.G
Label3.Text = mycol.B

funktioniert das ganz. aber nur sehr sehr langsam. pro bild ca. 15??? sec

Edit: Achja, wie kann ich des machen, dass er z.b nur jedes 2 Pixel nimmt? das würde das ganze vermutlich beschleunigen und ich braucht den wert eh nich sonderlich genau. nur relative grob. also -+10 abweichung wären schon drin.

ScottManDeath
2006-01-27, 10:59:00
Also:
Edit: Achja, wie kann ich des machen, dass er z.b nur jedes 2 Pixel nimmt? das würde das ganze vermutlich beschleunigen und ich braucht den wert eh nich sonderlich genau. nur relative grob. also -+10 abweichung wären schon drin.

Indem Du bei den For Schleifen um 2 inkrementierst?

Dj-Atzy
2006-01-27, 13:13:53
geht wie? sry bin noch relativer anfänger. gerade bei schleifen.

Edit: Habs schon

Aber wie kann ich jetzt ermitteln welche farbe am häufigsten vorkommt?

ScottManDeath
2006-01-27, 14:40:53
Indem Du Dir eine Dictionary<Color,int> (müsste in System.Collections.Generic sein) zum Zählen der Pixelfarben nimmst .

Falls das Dictionary nicht direkt mit Color umgeheb kann, kannst Du ein Dictionary<int,int> nehmen und mit Color.ToArgb und Color.FromArgb zwischen Color und Integer konvertieren.

Sieht in Pseudocode in etwa so aus:

Dictionary<Color,int> map;

for each pixel
map[the_color_of_the_pixel] = 1 + map[the_color_of_the_pixel];



Danach läufst Du alle Elemente des Dictionaries durch und stellst das Maximum fest.

For Each kvp As KeyValuePair(Of Color, Integer) In myDictionary
// finde maximum
Next kvp

Dj-Atzy
2006-01-27, 14:52:17
bekomm ich dann einen Hex wert oder etwas in der art?

Ich wollte eigentlich nur ne ausgabe wie " blau, grün, gelb, rot, orange"

mehr nicht.

ScottManDeath
2006-01-27, 16:29:24
Ja, Du bekommst einen Integer. Du könnest Color.ToKnownColor nehmen um Deine Farbe der nächsten benannten anzupassen und dann davon .Name nehmen.

Das Problem dabei ist, das es nur für wenige Farben vordefinierte Namen gibt.

Alternativ kannst Du auch z.B. einem Button Deine Farbe zuweisen, so dass das Userlein das gleich sieht ;)

MeLLe
2006-01-28, 13:48:36
Also:
Dim mybmp As Bitmap = PictureBox1.Image.Clone
Dim x, y
Dim sumcol As Double
Dim mycol As Color

x = 1
y = 1

For x = 1 To PictureBox1.Size.Width - 1
For y = 1 To PictureBox1.Height - 1
mycol = mybmp.GetPixel(x, y)
'sumcol = (mycol.R + mycol.G + mycol.B) / 3.0
Next
Next

'Label1.Text = ("Ergebnis: " & sumcol / (x * y))
Label1.Text = mycol.R
Label2.Text = mycol.G
Label3.Text = mycol.B

funktioniert das ganz. aber nur sehr sehr langsam. pro bild ca. 15??? sec
Es klappt wirklich? Cool :)
Langsam ists sicher, weil du ja gaaanz oft getPixeln musst. Aber anders gehts halt kaum. Du könntest maximal nen eigenen Thread für stricken, damit die UI reaktionsfähig bleibt und der User nicht denk, die App ist in die heiligen Jagdgründe entschwunden.

Kleine Bemerkung noch: deine obige Variante gibt dir nur das RBG-Tripel des letzten Pixels deines Bildes aus. Das geht natürlich auch ohne verschachtelte For-Schleifen mit einem einizigen Aufruf ...
Aber ich vermute mal das ist nicht so gewollt ;)

Dj-Atzy
2006-01-28, 20:49:05
:eek: Neeeeeeeiiiiin hab mich schon gewundert.

weißt du vll. wie mans richtig macht?

Xmas
2006-01-29, 00:27:33
weißt du vll. wie mans richtig macht?
Wie wäre es damit, die Summe auch wirklich aufzuaddieren statt zu überschreiben? ;)

GetPixel ist laaaangsam. Schneller gehts, wenn man mit Bitmap.LockBits und System.Runtime.InteropServices.Marshal.Copy die Bilddaten in ein int-Array kopiert und dieses verarbeitet, allerdings weiß ich nicht ob das in VB.net auch geht.

In C# siehts jedenfalls so ähnlich aus:
Bitmap bmp = (Bitmap)Image.FromFile(ofd.FileName);

int[] texture = new int[bmp.Width * bmp.Height];
BitmapData bd = bmp.LockBits(
new Rectangle(0, 0, bmp.Width, bmp.Height),
ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);

IntPtr srcPtr = bd.Scan0;
for(int i = 0; i < bmp.Height; ++i)
{
Marshal.Copy(srcPtr, texture, i * bmp.Width, bmp.Width);
srcPtr = (IntPtr)((int)srcPtr + bd.Stride);
}
bmp.UnlockBits(bd);

ScottManDeath
2006-01-29, 10:42:06
Cool, ich nehme an, dass das auch schreibend geht? Dann kann ich den Output meines Tracers fixer speichern :)

Demirug
2006-01-29, 11:07:03
Cool, ich nehme an, dass das auch schreibend geht? Dann kann ich den Output meines Tracers fixer speichern :)

Natürlich geht das auch schreibend. Du kannst aber auch einen Speicherblock den den selbst angelegt hast an ein Image binden.

MeLLe
2006-02-02, 10:35:05
Cool :)
Wieder was gelernt!