AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Programmierung allgemein Multimedia Delphi Farbe von Bildschirminhalt ermitteln ?
Thema durchsuchen
Ansicht
Themen-Optionen

Farbe von Bildschirminhalt ermitteln ?

Ein Thema von Blamaster · begonnen am 2. Jul 2009 · letzter Beitrag vom 19. Jul 2009
Antwort Antwort
Seite 1 von 4  1 23     Letzte »    
Blamaster

Registriert seit: 20. Jul 2007
230 Beiträge
 
#1

Farbe von Bildschirminhalt ermitteln ?

  Alt 2. Jul 2009, 00:18
Hi,

ich habe beriets rausgefunden wie man die Farbe eines bestimmten Pixel auf dem Bildschirm ermitteln kann.

Ich bin gerade dabei ein Art Ambilight zu programmieren, welches mir die überweigende Farbe in einem bestimmten Bereich des Bildschirms ausgeben soll.

Meine Fragen dazu ist nun wie kann man am besten eine Berechnung der überweigenden Farbe realisieren ?

Um es nochmal ein wenig vorstellbarer zu umschreiben. Ich nehme mal eine Fläche von 500x500px in der Bildschirmmitte die darin enthaltenen Pixel sollen nun ausgewertet werden und die am häufigsten vorkommende Farbe soll ausgegeben werden. Dabei reicht allerdings nicht die Aussage Rot, Grün, Blau, usw. überwiegt, sondern es sollte schon ein genauer Farbwert sein.

Ich hoffe mir kann da jemand auf die Sprünge helfen.

mfg Yannic
  Mit Zitat antworten Zitat
Benutzerbild von Aphton
Aphton

Registriert seit: 31. Mai 2009
1.198 Beiträge
 
Turbo Delphi für Win32
 
#2

Re: Farbe von Bildschirminhalt ermitteln ?

  Alt 2. Jul 2009, 02:10
Ich würd immer für jeden Pixel, welcher noch nicht in einer (def.) Liste existiert, einen neuen Eintrag erstellen und für jeden Pixel, der schon besteht, würde ich den Counter des Eintrages erhöhen

Programmiertechnisch würde das so aussehen:

Delphi-Quellcode:
PPixelCounter = ^TPixelCounter;
TPixelCounter = record
  Pixel: TColor;
  Count: Cardinal;
  Prev, Next: PPixelCounter;
end;

TPixelContainer = class
public
  property List: PPixelCounter Read FList Write SetList;
  procedure Add( Pixel: TColor );
  function GetLastItem(): PPixelContainer;
  function SearchPixel( Pixel: TColor ): PPixelContainer;
end;

// Add erweitert die doppelt verkettete Liste um ein neues Element;
// SearchPixel geht die ganze Liste durch und schaut, ob Pixel enthalten ist und liefert die Adresse des Eintrages zurück
Konkrete Vorgehensweise:
Code:
1. Bildpunkt vom Display/Desktop ermitteln
2. Per SearchPixel prüfen, ob der Pixel schon vorhanden ist (NIL?)
3. Falls es vorhanden ist, dann den Rückgabewert von SearchPixel dereferenzieren und dessen Count Wert um 1 erhöhen
4. Ansonsten einen neuen Eintrag erstellen
So ausführlich hab ich noch niemandem geholfen
Hoffe ich konnt dir helfen

MfG
das Erkennen beginnt, wenn der Erkennende vom zu Erkennenden Abstand nimmt
MfG
  Mit Zitat antworten Zitat
Medium

Registriert seit: 23. Jan 2008
3.686 Beiträge
 
Delphi 2007 Enterprise
 
#3

Re: Farbe von Bildschirminhalt ermitteln ?

  Alt 2. Jul 2009, 04:03
Ein naiver Ansatz wäre es, einfach die Durchschnittsfarbe für den Bereich zu ermitteln. Etwas geschickter würde das evtl. noch, wenn man die Pixel die näher zum Rand liegen dabei stärker gewichtet. Was aber eine recht gute Näherung sein dürfte, stützt sich auf Aphtons Idee, welche letztlich ein sog. Histogramm beschreibt - in dem Fall eines über die ganzen Farben. Wenn man von diesem dann noch die obersten ~10% mittelt, dürfte das recht gut werden.

Histogramme sind in der Grafikverarbeitung recht üblich, meist aber für R, G und B separat. Dabei ist dann die Verwaltung der Datenstruktur weit einfacher und schneller, falls das o.g. Methode ausschließt. Ein Array[0..2, 0..255] of Cardinal, 1. Dimension 0-2 für RGB, und 2. Dimension für den Wert den die Farbanteile je annehmen können.
Mal Pseudocode wie man so ein Histogramm aufbaut:
Delphi-Quellcode:
for y := 0 to Bild.Height-1 do
begin
  for x := 0 to Bild.Width-1 do
  begin
    inc(Array[0, Bild.Pixel[x, y].R]);
    inc(Array[1, Bild.Pixel[x, y].G]);
    inc(Array[2, Bild.Pixel[x, y].B]);
  end;
end;
Der Wert von z.B. "Array[1, 128]" gibt dann also an, wie viele Pixel den Grünanteil 128 haben. Aus diesen 3 Listen kann man nun wieder die obersten 10% mitteln, und daraus eine Farbe zusammensetzen.


Eine weitere Variante wäre es das ganze von RGB nach HSV zu konvertieren. Dann nimmt man sich nur die Hue-Werte, für die Saturation und Value einen Mindestwert überschreiten, da diese dann die meiste Farbigkeit und Leuchtkraft beitragen. Aus diesen ermittelten Hue-Werten erstellt man wiederum ein Histogramm, uuuuund mittelt einen Teil am oberen Ende.
Hierbei erhält man allerdings nur eine Farbe, keine Indikation für die Helligkeit. Diese würde ich dann aus den Randpixeln gemittelt herleiten, um einen guten Anschluss an den Bildrand zu bekommen.


Ich habe selbst noch keine der Dinge getestet, und es ist vermutlich sinnvoll alles Mögliche in diese Richtung mal auszuprogrammieren und zu begutachten, da hier ja das subjektive Empfinden den größten Faktor bei der Beurteilung der Güte stellt - und das ist ja bekanntlich nicht immer mit rechnerisch sinnvollen Verfahren gleichzusetzen
Auch spielt eine große Rolle ob die Anzeige vom Bild und dem Ambilight durch das selbe Medium (yeah) geschieht oder nicht. Wenn du z.B. um deinen Monitor verteilte RGB-LEDs ansteuerst, kann es durchaus nötig sein die Farben (bzw. die Farbkanäle) noch weiter zu verarbeiten um einen guten und ähnlichen Farbeindruck herzustellen. (Anhebung von Blau z.B., was bei LEDs meist eine geringere Leuchtkraft hat als Rot und Grün.)

Interessante Sache! Ich fühle mich fast schon genötigt mal was ähnliches in Angriff zu nehmen
"When one person suffers from a delusion, it is called insanity. When a million people suffer from a delusion, it is called religion." (Richard Dawkins)
  Mit Zitat antworten Zitat
Blamaster

Registriert seit: 20. Jul 2007
230 Beiträge
 
#4

Re: Farbe von Bildschirminhalt ermitteln ?

  Alt 2. Jul 2009, 12:34
Hi,

Danke schonmal für die Hilfe.

Ich glaube die Methode von Aphton iost zu resourcen fressend. Ein "scan" sollte ca. alle 25ms erfolgen können.

@ Medium

das sieht ganz interessant aus. Allerdings habe ich da gerade ein Verständnisproblem.

inc(Array[0, Bild.Pixel[x, y].R]);

was wir denn da inkrementiert ?

mfg Yannic

Ah ich glaube jetzt versteh ich es doch. Array[0, Bild.Pixel[x, y].R], Bild.Pixel[x, y].R gibt den Farbwert des aktuellen Pixels (0 - 255) an. Wenn der Wert nun mal angenommen 122 ist wird der Arraysatz Array[0, 122] um 1 richtig ?
  Mit Zitat antworten Zitat
Blamaster

Registriert seit: 20. Jul 2007
230 Beiträge
 
#5

Re: Farbe von Bildschirminhalt ermitteln ?

  Alt 2. Jul 2009, 14:44
Hi,

ich habe gerade mal testweise etwas zusammengeschustert.

Delphi-Quellcode:
procedure TForm1.Button3Click(Sender: TObject);
var
  Color: TColor;
  x, y, i, high_r, high_g, high_b, end_r, end_g, end_b: integer;
  ColorArray: array[0..2, 0..255] of cardinal;
begin

  for y := 200 to 210 do
  begin
    for x := 200 to 210 do
    begin
      Color := GetDesktopColor(x, y);
      inc(ColorArray[0, GetRValue(Color)]);
      inc(ColorArray[1, GetGValue(Color)]);
      inc(ColorArray[2, GetBValue(Color)]);
    end;
  end;

  for i := 0 to 255 do
  begin
    if ColorArray[0, i] > high_r then
    begin
      high_r := ColorArray[0, i];
      end_r := i;
    end;
    if ColorArray[1, i] > high_g then
    begin
      high_g := ColorArray[1, i];
      end_g := i;
    end;
    if ColorArray[2, i] > high_b then
    begin
      high_b := ColorArray[2, i];
      end_b := i;
    end;
  end;

  ShowMessage(IntToStr(end_r));
  ShowMessage(IntToStr(end_g));
  ShowMessage(IntToStr(end_b));

  JvPanel2.Color := RGB(end_r, end_g, end_b);
end;
Da kommen dann bei den 3 ShowMessage flasche Werte raus. Beispiel Hintergrund vom Desktop komplett rot gestellt. Nun kommen bei GetDesktopColor(x, y); auch das richtige raus, wenn ich mir die Farbe anzeigen lasse 255,0,0. Wenn das Programm nun allerdings zu

ShowMessage(IntToStr(end_r));
ShowMessage(IntToStr(end_g));
ShowMessage(IntToStr(end_b));

kommt, dann bekomme ich da bei Rot 251,213,253. Habe ich da etwas übersehen ?

mfg Yannic
  Mit Zitat antworten Zitat
Benutzerbild von turboPASCAL
turboPASCAL

Registriert seit: 8. Mai 2005
Ort: Sondershausen
4.274 Beiträge
 
Delphi 6 Personal
 
#6

Re: Farbe von Bildschirminhalt ermitteln ?

  Alt 2. Jul 2009, 15:27
Oder so was ?

Delphi-Quellcode:
function TForm1.GetBitmapAmbiColor(inBmp: TBitmap): TColor;
type
  TRGBArray = array [Word] of TRGBTRIPLE;
  pRGBArray= ^TRGBArray;
var
  x, y: integer;
  LineScan: pRGBArray;
  AmbiCol: record
    aB, aG, aR: int64;
  end;
  counts: cardinal;
begin
  if inBmp.PixelFormat <> pf24Bit then
    inBmp.PixelFormat := pf24Bit;

  AmbiCol.aR := 0;
  AmbiCol.aG := 0;
  AmbiCol.aB := 0;

  counts := 0;

  for y := 0 to inBmp.Height-1 do // Farbe im Drurchschnitt per Bitmap
  begin
    LineScan := inBmp.Scanline[y];
    for x := 0 to inBmp.Width-1 do
    begin
      inc(AmbiCol.aR, LineScan[x*3].rgbtRed);
      inc(AmbiCol.aG, LineScan[x*3+1].rgbtGreen);
      inc(AmbiCol.aB, LineScan[x*3+2].rgbtBlue);

      inc(counts);
    end;
  end;

  AmbiCol.aR := AmbiCol.aR div counts;
  AmbiCol.aG := AmbiCol.aG div counts;
  AmbiCol.aB := AmbiCol.aB div counts;

  Result := RGB(AmbiCol.aR , AmbiCol.aG , AmbiCol.aB );
end;
Matti
Meine Software-Projekte - Homepage - Grüße vom Rüsselmops -Mops Mopser
  Mit Zitat antworten Zitat
Medium

Registriert seit: 23. Jan 2008
3.686 Beiträge
 
Delphi 2007 Enterprise
 
#7

Re: Farbe von Bildschirminhalt ermitteln ?

  Alt 2. Jul 2009, 15:30
Jub, du musst high_*, end_* und das Array natürlich alle mit 0 initialisieren. So stehen da zunächst einmal zufälige Werte von Anfang an drin - sind ja lokale Variablen.

Edit: Redbox, aber trotzdem. Antwort bezieht sich auf den vorletzten Beitrag.
"When one person suffers from a delusion, it is called insanity. When a million people suffer from a delusion, it is called religion." (Richard Dawkins)
  Mit Zitat antworten Zitat
Reinhard Kern

Registriert seit: 22. Okt 2006
772 Beiträge
 
#8

Re: Farbe von Bildschirminhalt ermitteln ?

  Alt 2. Jul 2009, 15:52
Zitat von Aphton:
Ich würd immer für jeden Pixel, welcher noch nicht in einer (def.) Liste existiert, einen neuen Eintrag erstellen und für jeden Pixel, der schon besteht, würde ich den Counter des Eintrages erhöhen
...
Hallo,

falsch ist das nicht - aber ich weise mal drauf hin, dass heutige Bildschirme i.a. 16 Mio Farben darstellen. Und auch wenn er 500 x 500 Pixel betrachtet, ist es bei einem realen Foto immer noch gut möglich, 100000 verschiedene Farben zu finden. M.a.W. du brauchst 100000 Counter.

Man könnte ja eine Toleranz definieren und so die Zahl verringern, aber der Fragesteller wollte ausdrücklich eine exakte Farbe, wofür auch immer - ich halte das eher für abwegig, denn bei der Fotografie eines Waldes ist die beherrschende Farbe nach intuitivem Verständnis grün, aber in seinem Sinn können es hunderte oder tausende verschiedene Grüns sein.

Gruss Reinhard
  Mit Zitat antworten Zitat
Blamaster

Registriert seit: 20. Jul 2007
230 Beiträge
 
#9

Re: Farbe von Bildschirminhalt ermitteln ?

  Alt 2. Jul 2009, 16:04
Hi,

dann habe ich mich etwas unklar ausgedrückt

Es muss natürlich nicht eine exakte Farbe sein, es reicht natürlich ein Näherungswert ich meine damit eher das z.B. Orange nicht als Rot gewertet werden soll, oder Lila als Blau

mfg Yannic
  Mit Zitat antworten Zitat
Blamaster

Registriert seit: 20. Jul 2007
230 Beiträge
 
#10

Re: Farbe von Bildschirminhalt ermitteln ?

  Alt 2. Jul 2009, 17:22
Hi,

der Code funktioniert jetzt soweit. Allerdings ist das ganze wie vermutet etwas langsam gerade bei großen scan bereichen.

Deswegen hatte ich mal weitergesucht und bin recht oft auf eine G32 oder Graphic 32 unit gestoßen, die wohl funktionen beinhalten soll mit denen das ganze sehr schnell und einfach geht.

Kennt jemand die Unit bzw. weiß mit welcher Funktion es schnell gehen soll ?

Mein aktueller Stand ist folgender:

Delphi-Quellcode:
procedure TForm1.Timer3Timer(Sender: TObject);
var
  Color: TColor;
  Screenshot: TBitmap32;
  x, y, i, high_r, high_g, high_b, end_r, end_g, end_b: integer;
  ColorArray: array[0..2, 0..255] of cardinal;
begin
  high_r := 0;
  high_g := 0;
  high_b := 0;
  end_r := 0;
  end_g := 0;
  end_b := 0;

  for i := 0 to 255 do
  begin
    ColorArray[0, i] := 0;
    ColorArray[1, i] := 0;
    ColorArray[2, i] := 0;
  end;

  Screenshot := TBitmap32.Create;
  FormularScreenShot(Screenshot, GetDesktopWindow);

  for y := 700 to 1000 do
  begin
    for x := 200 to 500 do
    begin
      Color := Screenshot.Pixel[x, y];
      inc(ColorArray[0, GetRValue(Color)]);
      inc(ColorArray[1, GetGValue(Color)]);
      inc(ColorArray[2, GetBValue(Color)]);
    end;
  end;

  for i := 0 to 255 do
  begin
    if ColorArray[0, i] > high_r then
    begin
      high_r := ColorArray[0, i];
      end_r := i;
    end;
    if ColorArray[1, i] > high_g then
    begin
      high_g := ColorArray[1, i];
      end_g := i;
    end;
    if ColorArray[2, i] > high_b then
    begin
      high_b := ColorArray[2, i];
      end_b := i;
    end;
  end;
  Screenshot.Free;
  JvPanel2.Color := RGB(end_r, end_g, end_b);
end;
Ich speichere jetzt erstmal das Dektopbild in ein Bitmap um dann später daraus die Farben zu lesen.

Mit dem Code oben indem ich nun versucht habe die G32 zu verwenden, gibt es probleme mit der Farbausgabe (farbe stimmt nicht blau anstelle von rot) und schneller als die alte Methode ist das auch nicht.

Wenn man im obigen die Screenshot: TBitmap32; wieder gegen TBitmap tauscht stimmt die angezeigte Farbe auch wieder, allerdings auch bei einer zu langsamen Geschwindigkeit.

Jemand eine Idee wie ich mit der G32 schneller zum laufen bekomme ?

mfg Yannic

Edit1. Das Farbproblem habe ich gerade gelöst hatte nicht bedacht das ich TColor32 erstmal wieder in TColor zurückwandeln muss.
  Mit Zitat antworten Zitat
Antwort Antwort
Seite 1 von 4  1 23     Letzte »    


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 21:18 Uhr.
Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz