| Autor |
Beitrag |
Andreas Pfau
      
Beiträge: 997
|
Verfasst: Fr 28.02.03 21:26
Hallo,
ich arbeite grade an einem Icon-Editor. Da ist natürlich wichtig, dass ich die Palette optimieren kann, also z.B. auf 8-Bit reduzieren. Wie ich die Farben auslese und eine Palette draus mache ist mir klar.
Aber... jetzt habe ich einen Array voller Farben... wie entscheide ich, welche Farben ich rausschmeiße? Oder sollte ich besser Farben mischen? Wenn ja, welche mit welcher? Ich hätte schon ein paar Ideen... z.b. Umwandenl in HSB (wie?), dann nach Farbton sortieren, und von jedem Farbton eine rauschmeißen, bis es nur noch 256 sind... aber wie machen das professionelle Anwendungen? Wenn ich in PhotoImpact auf 8-Bit klicke, habe ich in Sekundenbruchteilen 'ne tolle Palette. Kann mir jemand das erklären? Ich brauche keinen Code, nur 'n Schema, wie so was geht.
|
|
Andreas Pfau 
      
Beiträge: 997
|
Verfasst: Sa 01.03.03 21:30
Keiner weiß es? Also, ich habe rumprobiert... Ich habe die Häufigkeit der Farben gezählt und nur die 256 häufigsten verwendet... bringt aber nix, z.b. bei großen, einfarbigen Hintergründen.
Was ich suche, wäre 'ne Formel, um die "Varianz" zweier Farben zu berechnen (z.B. Farbe1 unterscheidet sich von Farbe2 um 375). Wie erreiche ich das? Also, mit verlässlichen Ergebnissen, so dass sich Fabrn mit gleichem Farbton weniger unterscheiden als verschiedene... Also, dass sich Hellblau on Dunkelblau kaum unterscheidet, aber stark von Hellrot... Da bräuchte ich HSL... oder? Wer hat Ideen?
|
|
FriFra
      
Beiträge: 557
Win XP Prof, Win XP Home,Win Server 2003,Win 98SE,Win 2000,Win NT4,Win 3.11,Suse Linux 7.3 Prof,Suse Linux 8.0 Prof
D2k5 Prof, D7 Prof, D5 Standard, D3 Prof, K3 Prof
|
Verfasst: So 16.03.03 18:41
 Wenn Du schon irgendwo eine Lösung gefunden hast wäre es schön, wenn Du diese hier posten würdest...
 Ich suche auch nach so einer Funktion...
|
|
Andreas Pfau 
      
Beiträge: 997
|
Verfasst: So 16.03.03 20:11
Na ja, unter www.efg2.com gibt's so was, irgendwo. Quadtree Quantization nennt sich das. Funzt, nur hätte ich gerne einen Code, den ich auch verstehe. Und es gibt keine Erklärung dazu.
_________________ Life is a bad adventure, but the graphic is really good!
|
|
Eternail
      
Beiträge: 18
|
Verfasst: Do 24.04.03 16:04
| Andreas Pfau hat folgendes geschrieben: | | Wie ich die Farben auslese und eine Palette draus mache ist mir klar. |
Genau danach suche ich. Kannst du eventuell den posten, wie man aus bekannten Farben eine Palette für ein TBitMap erstellt?
|
|
Andreas Pfau 
      
Beiträge: 997
|
Verfasst: Do 24.04.03 16:28
Ach, so. Also, Farben auslesen mache ich so, dass ich Pixel für Pixel auslese, und den Wert in eine Liste schreibe, sofern der Wert nicht schon vorhanden ist. Ich denke, das bedarf keinem Code. Ist zwar eine Slow-Motion-Lösung, aber ich weiß nicht, wie sonst.
Gut, dann aus deiner Lsite eine Palette machen. Erstmal weise deinem Bitmap ein Pixelformat zu, klar, oder? Dann Die Palette erstellen:
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37:
| procedure Make8BitPalette(Bitmap: TBitmap; Palette: Array Of TColor); const NumColors = 256; var I: Integer; H: HPalette; P: PLogPalette; begin Bitmap.PixelFormat := pf8Bit;
GetMem(P, SizeOf(TLogPalette) + (SizeOf(TPaletteEntry) * (NumColors - 1)));
P.palVersion := $300; // Ist immer $300 !!! P.palNumEntries := NumColors;
For I := 0 To NumColors - 1 Do begin If (Max(Palette) <= I) Then begin // Farben aus Liste extrahieren P.palPalEntry[I].peRed := Palette[I] And $FF; P.palPalEntry[I].peGreen := Palette[I] And $FF00 Shr 8; P.palPalEntry[I].peBlue := Palette[I] And $FF0000 Shr 16; end Else begin // Wenn Palette zu klein, Schwarz nehmen P.palPalEntry[I].peRed := 0; P.palPalEntry[I].peGreen := 0; P.palPalEntry[I].peBlue := 0; end; // Ist normalerweise 0 P.palPalEntry[I].peFlags := 0; end;
H := CreatePalette(P^); If H <> 0 Then Bitmap.Palette := H;
FreeMem(P); end; |
Ich denke, das erklärt sich von selbst.
_________________ Life is a bad adventure, but the graphic is really good!
|
|
Eternail
      
Beiträge: 18
|
Verfasst: Do 24.04.03 18:36
Auch wenn mir so Sachen mit GetMem eigentlich eher suspekt sind - es funktioniert. Ich musste nur das "max" gegen ein "high" vertauschen.
Allerdings kann ich, wenn ich die Palette auf acht Bit beschränke auch nur noch acht-Bit-Farben verwenden. Gibt es eine Möglichkeit (ausser mit gif) ZB nur die Farben $00 bis $FF (also die ganzen Rottöne zu verwenden)?
Danke soweit erstmal,
Michael Nagel 
|
|
Andreas Pfau 
      
Beiträge: 997
|
Verfasst: Do 24.04.03 18:58
1) WAS??? WAS??? Max() gegen Min()? Erklär mir Bitte, warum? Das kann in hunterdttausendmillionenmilliarden Jahren nicht sein!
2) Nun, dan musst du nur die Farbzuweisung ändern, und so eine rote Palette erstellen:
Quelltext 1: 2: 3: 4: 5: 6:
| For I := 0 To NumColors - 1 Do begin P.palPalEntry[I].peRed := I; P.palPalEntry[I].peGreen := 0; P.palPalEntry[I].peBlue := 0; P.palPalEntry[I].peFlags := 0; end; |
NumColors MUSS jetzt "256" sein, sonst fataler Error. Es gibt keine mir bekannte Möglichkeit, das zu umgehen.
Übrigens: Ich weiß nicht, ob du es weißt, aber du kannst ruhig einem farbigen Bitmap eine monochrome Palette zuweisen... Windows nimmt automaitsch dien nächstgelegene Farbe.
GetMem() könnte man umgehen... Aber dann bräuchte man für jedes Pixelformat eine andere Struktur... Mach es doch so, es funzt, der Speicher wird freigegeben, kein Problem. Don't touch a running system, heißt es doch 
_________________ Life is a bad adventure, but the graphic is really good!
|
|
Eternail
      
Beiträge: 18
|
Verfasst: Do 24.04.03 19:40
| Andreas Pfau hat folgendes geschrieben: | 1) WAS??? WAS??? Max() gegen Min()? Erklär mir Bitte, warum? Das kann in hunterdttausendmillionenmilliarden Jahren nicht sein! |
Kennst du "lesen"?  Ich habe geschrieben (hoffentlich!) "gegen HIGH()". Weil "max() geht nicht bei dynamischen arrays!"!
| Andreas Pfau hat folgendes geschrieben: | 2) Nun, dan musst du nur die Farbzuweisung ändern, und so eine rote Palette erstellen:
Quelltext 1: 2: 3: 4: 5: 6:
| For I := 0 To NumColors - 1 Do begin P.palPalEntry[I].peRed := I; P.palPalEntry[I].peGreen := 0; P.palPalEntry[I].peBlue := 0; P.palPalEntry[I].peFlags := 0; end; |
NumColors MUSS jetzt "256" sein, sonst fataler Error. Es gibt keine mir bekannte Möglichkeit, das zu umgehen.
Übrigens: Ich weiß nicht, ob du es weißt, aber du kannst ruhig einem farbigen Bitmap eine monochrome Palette zuweisen... Windows nimmt automaitsch dien nächstgelegene Farbe. |
Irgendwas klappt da nicht. Wenn ich es so mache, wie gesagt, bekomm ich immer noch die breiten Farbbalken, den entstehen, wenn zu wenig Farben zur VErfügung stehen. Sogar wenn ich alles auf := 0 stelle kommen noch die Balken, anstatt, dass alles schwarz wird. irgendwo ist da noch ein Fehler...
| Andreas Pfau hat folgendes geschrieben: | GetMem() könnte man umgehen... Aber dann bräuchte man für jedes Pixelformat eine andere Struktur... Mach es doch so, es funzt, der Speicher wird freigegeben, kein Problem. Don't touch a running system, heißt es doch  |
Wegen mir...
|
|
Andreas Pfau 
      
Beiträge: 997
|
Verfasst: Do 24.04.03 19:53
 tiefe Schande über main Haupt... es muss High() heißen.
Lesen... davon habe ich mal im TV gesehen, das ist doch so eine Süßspeise, oder?
OK, dann zu deinem Problem: Probier als Flag stat "0" die Werte "PC_NOCOLLAPSE" und/oder "PC_RESERVED". Es kann nämlich sein, dass Windows keine passende Farbe findet, und einfahc eneue Indizes erstellt. Und, ähem, Pixelformat muss pf8Bit sein, aber ich denke, das muss ich nicht sagen.
_________________ Life is a bad adventure, but the graphic is really good!
|
|
Eternail
      
Beiträge: 18
|
Verfasst: Do 24.04.03 21:24
Kann nicht sein, dass Windows die passende Farbe nicht findet, weil...
...weil die BitMap nur aus den Farben aufgebaut wird, die ich später auch zum Farbpalette erstellen nutze. Ist doch Sinn der Sache. Ich will die Größe von der BitMap dritteln, indem ich die ganzen grün/blau-Informationen verwerfe, die ich eh nicht brauche. Deshalb will ich eine Colormap, wo nur die roten Farben drin sind, aus denen ich zuvor mein Bild erstellt habe...
PS: ...d.h. ich brauche 24bit Farben, damit ich 8bit "Rots" habe. Aber ich brauche nur 8bit verschienden Farben, weil blau und grün eh immer null sind. Geht das überhaupt mit BitMaps? Muss ja, sonst wäre die ganze Farbtabellen-Geschichte unsinnig.
|
|
Andreas Pfau 
      
Beiträge: 997
|
Verfasst: Do 24.04.03 21:51
Lass' mich zusammenfassen: Du hast Bilddaten, bei denen G und B immer 0 sind, nur R ist unterschiedlich. Dazu sind Bitmaps da.
ERklär mir mal, wie sich das äußert, wie sieht dein Bitmap aus? Evtl liegt der Fehler wo andres: Du hast vollfarben konvertierst sie zu 8Bit, und machst die Geschichte Rot... Versuch es so: Erstelle eine 2. Bitmap, mach da ein erote Palette, und kopiere dein Bitmap in das 2.Bitmap (das rote), nicht mit Assign() sondern über's Canvas. Wenn das nicht funzt, weiß ich auch net... aber informier mich drüber!
_________________ Life is a bad adventure, but the graphic is really good!
|
|
Andreas Pfau 
      
Beiträge: 997
|
Verfasst: Sa 26.04.03 15:10
Also, nochmal zu deinem Problem. Ich habe es jetzt selber ausprobiert. Ich ahbe mir eine bitmap erstellt, die NUR aus rottönen enthält, d.h. ALLE Grün- und Blauwerte sind 0. Diese Btimap hat 24Bit. Ich habe die Bitmap in Image1 geladen und folgenden Code angewendet:
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34:
| procedure MakeRedPalette8(Bitmap: TBitmap); var I: Integer; H: HPalette; P: PLogPalette; begin Bitmap.PixelFormat := pf8Bit;
GetMem(P, SizeOf(TLogPalette) + (SizeOf(TPaletteEntry) * 255));
P.palVersion := $300; P.palNumEntries := 256;
For I := 0 To 255 Do begin P.palPalEntry[I].peRed := I; P.palPalEntry[I].peGreen := 0; P.palPalEntry[I].peBlue := 0; P.palPalEntry[I].peFlags := 0; end;
H := CreatePalette(P^); If H <> 0 Then Bitmap.Palette := H;
FreeMem(P); end;
procedure TMain.Button6Click(Sender: TObject); begin Image2.Picture.Bitmap.Width := Image1.Picture.Bitmap.Width; Image2.Picture.Bitmap.Height := Image1.Picture.Bitmap.Height; MakeRedPalette8(Image2.Picture.Bitmap); Image2.Picture.Bitmap.Canvas.Draw(0, 0, Image1.Picture.Bitmap); end; |
Jetzt habe ich in Image2 GENAU das geliche Bitmap, nur dass es halt nur aus 8Bit besteht. Zeig mir mal deinen Code, und ich helfe dir bei der Fehelrsuche! Oder hat sich's schon erledigt?
_________________ Life is a bad adventure, but the graphic is really good!
|
|
Eternail
      
Beiträge: 18
|
Verfasst: Sa 26.04.03 16:46
Das Problem hat sich noch nicht geklärt, aber ich werde erst nach dem Wochenende dazu kommen, mich nochmal ausführlich zu melden.
|
|
Eternail
      
Beiträge: 18
|
Verfasst: So 27.04.03 21:49
Ist früher was gewoeden, als ich gedacht habe. Und besser als ich gedacht habe. Es klappt auf einmal. Hier mein Code (noch ohne Fehlerkorrektur):
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54: 55: 56: 57: 58: 59: 60: 61: 62: 63: 64:
| procedure TForm1.Image1Click(Sender: TObject); var BM: TBitMap; myCol: array of TColor; i,j: word; begin if Tag = 0 then begin //BitMap erstellen BM := TBitMap.Create; BM.Width := 256; BM.Height := 256; Image1.Height := 256; Image1.Width := 256;
//Die 256 Farbwerte für die Palette festlegen - (von schwarz nach grün) SetLength(myCol, 256); for i := 0 to 255 do myCol[i] := i shl 8;
//Das Bild einfärben - Farbverlauf schwarz nach grün for i := 0 to 255 do for j := 0 to 255 do BM.Canvas.Pixels[i,j] := myCol[i];
//Das Bild übernehmen Image1.Picture.Bitmap := BM; BM.Free; end
else begin //Die Palette des Bildes nur auf die verwendeten Grüntöne beschränken //falls es funktioniert, ändert sich nichts Image1.Picture.Bitmap.PixelFormat := pf24bit; Image1.Picture.Bitmap.Palette := Get8BitPalette(myCol); end;
Tag := not Tag; end;
function TForm1.Get8BitPalette(farben: array of TColor): HPalette; var i: Integer; P: PLogPalette; begin GetMem(P, SizeOf(TLogPalette) + (SizeOf(TPaletteEntry) * 255));
P.palVersion := $300; P.palNumEntries := 256;
for i := 0 to 255 do begin //Farben aus Liste extrahieren P.palPalEntry[i].peRed := (farben[i] and $0000FF) ; P.palPalEntry[i].peGreen := (farben[i] and $00FF00) shr 8; P.palPalEntry[i].peBlue := (farben[i] and $FF0000) shr 16; P.palPalEntry[I].peFlags := 0; end;
Result := CreatePalette(P^);
FreeMem(P); end; |
vielen Dank nochmal,
Michael
|
|
|