Laden...

kopieren bzw initialisieren von Bitmaps ändert Bittiefe

Erstellt von ghostwhisperer32 vor 13 Jahren Letzter Beitrag vor 13 Jahren 4.235 Views
G
ghostwhisperer32 Themenstarter:in
5 Beiträge seit 2010
vor 13 Jahren
kopieren bzw initialisieren von Bitmaps ändert Bittiefe

Hallo !
Warum bekomme ich kein 8bppindexed - Bitmap wenn ich ein Bitmap GENAU DIESEN Typs kopiere ? Das kopierte Bild hat immer 32bitArgb.

zb konstruktor

bmp2 = new bitmap(bmp1)

oder eigene kopierfunktion

bmp2 = copybitmap(bmp1) ..... {return new bitmap(source)}

egal was ich mache, nie ist die kopie mit dem original identisch und ich bekomme in der Anzeige bunte Bilder statt grauwertbildern! ausserdem bekomme ich dadurch falsche Berechnungen, wenn ich zB gradienten berechnen will.

Der Grauwert bleibt nur dann grau, wenn ich einfach sage bmp1 = bmp2. Aber da übergebe ich ja nur die Referenz, was dazu führt, dass zB das Richtungsbild statt dem Gradientenbetrag angezeigt wird, da ich den Inhalt letztlich in der Reihenfolge überschreibe.

HELP !!

Torsten

5.657 Beiträge seit 2006
vor 13 Jahren

Der Bitmap-Konstruktor erwartet ein Image-Objekt, kein Bitmap-Objekt. Deshalb weiß er auch nicht, welches Bitformat verwendet wird, weil die Image-Klasse das nicht unterstützt. Nehme ich jedenfalls an. Hast du evtl. mal Bitmap.Clone() probiert? Oder evtl.: Bitmap.Clone(Rectangle, PixelFormat)?

Weeks of programming can save you hours of planning

G
ghostwhisperer32 Themenstarter:in
5 Beiträge seit 2010
vor 13 Jahren
Grauwert durch mischen ?

Funzt bisher auch nicht, kA warum.
Die Zuweisung bzw das Kopieren generiert immer 32bppArgb.
Ich hab mir jetzt damit beholfen, dass ich bmpdata extrahiert und gelockt hab.
Gleichzeitig habe ich dasselbe mit einem 32bppArgb-Bmp gemacht.
Jetzt hab ich pixel für pixel den Wert per pointer vom original ausgelesen, den pointer auf das neue bild entsprechent mit +4 iteriert und die
Kanäle des 32bit bildes (ptr+0, +1,+2,+3) mit dem Wert des originalpointers belegt. Dh natürlich nicht A aber rgb.

Nur eins ist hier irgendwie falsch. Wie muss ich A belegen? Wenn ich 255 sage kriege ich ein halbtransparentes blaustichiges Bild, mit 0 ein hlbtrsp gelbstichiges Bild aber kein solides Grauwert-Bild (immerhin keinen Regenbogen mehr)..... Oder habe ich an den pointern was falsch ? Hier der Code:

protected Bitmap CopyBitmap(Bitmap source)
        {
            Bitmap expbitmap = new Bitmap(source.Width, source.Height, System.Drawing.Imaging.PixelFormat.Format32bppArgb);

            unsafe
            {
                Rectangle lockedRect = new Rectangle(0, 0, source.Width, source.Height);
                BitmapData orgData = source.LockBits(lockedRect, ImageLockMode.ReadOnly,
                source.PixelFormat);
                BitmapData expData = expbitmap.LockBits(lockedRect, ImageLockMode.WriteOnly, expbitmap.PixelFormat);
                int offset1 = orgData.Stride - orgData.Width;  // ist zGlück 0 !!
                int offset2 = expData.Stride - expData.Width*4; // ist zGlück 0 !!
                byte* ptrorg = (byte*)orgData.Scan0.ToPointer();
                byte* ptrexp = (byte*)expData.Scan0.ToPointer();
                //indexierung zeilenweise im Bild -> 
                for (int dy = 0; dy < orgData.Height; dy++)
                {
                    for (int dx = 0; dx < orgData.Width; dx++, ptrorg += 1, ptrexp+=4)
                    {
                         *(ptrexp + 0) = 255; //A
                         *(ptrexp + 1) = *(ptrorg ); //R
                         *(ptrexp + 2) = *(ptrorg ); //G
                         *(ptrexp + 3) = *(ptrorg ); //B

                    }
                    ptrorg += offset1;
                    ptrexp += offset2;

                }
                source.UnlockBits(orgData);
                expbitmap.UnlockBits(expData);
            }
                // Unlock the locked bits
                
            return (expbitmap);
        }

Gibts vielleicht einen besseren Weg 3 Grauwert-Bilder zu einem Farbbild zu mischen ?? bzw in diesem Fall 3 Kanäle konstant zu belegen um Grauwerte zu bekommen ??

THANKS

Der Bitmap-Konstruktor erwartet ein Image-Objekt, kein Bitmap-Objekt. Deshalb weiß er auch nicht, welches Bitformat verwendet wird, weil die Image-Klasse das nicht unterstützt. Nehme ich jedenfalls an. Hast du evtl. mal Bitmap.Clone() probiert? Oder evtl.: Bitmap.Clone(Rectangle, PixelFormat)?

5.657 Beiträge seit 2006
vor 13 Jahren

Funzt bisher auch nicht, kA warum.
Die Zuweisung bzw das Kopieren generiert immer 32bppArgb.

Auch wenn du der Clone-Methode das Original-PixelFormat übergibst?

Übrigens bitte unbedingt den Code in Code-Tags schreiben, der ist echt unlesbar 😃

Weeks of programming can save you hours of planning

S
248 Beiträge seit 2008
vor 13 Jahren

Hallo,

ich habe mal die Methode Clone wie von MrSparkle genannt versucht, und diese funktionierte bei mir ohne Probleme (8bppindexed).


public static Bitmap Clone(Bitmap bitmap)
{
    if (bitmap == null)
        throw new ArgumentNullException("bitmap");
    Rectangle rect = new Rectangle(0, 0, bitmap.Width, bitmap.Height);
    return bitmap.Clone(rect, bitmap.PixelFormat);
}

Sollte diese trotzdem nicht funktionieren, kannst du die Daten auch manuell klonen:


public static Bitmap Clone2(Bitmap bitmap)
{
    if (bitmap == null)
        throw new ArgumentNullException("bitmap");

    Bitmap clone;
    Rectangle rect = new Rectangle(0, 0, bitmap.Width, bitmap.Height);
    BitmapData bmpData = bitmap.LockBits(rect, ImageLockMode.ReadOnly, bitmap.PixelFormat);
    try
    {
        clone = new Bitmap(bmpData.Width, bmpData.Height, bmpData.Stride, bmpData.PixelFormat, bmpData.Scan0);
    }
    finally
    {
        bitmap.UnlockBits(bmpData);
    }
    clone.Palette = bitmap.Palette;
    return clone;
}

Ich hoffe das hilft dir weiter zum Thema klonen.

Warum das manuelle Kopieren von dir nicht funktioniert liegt am Layout der Farbstruct. Diese ist nicht ARGB sondern BGRA (siehe RGBQUAD):


typedef struct tagRGBQUAD { 
  BYTE rgbBlue;
  BYTE rgbGreen;
  BYTE rgbRed;
  BYTE rgbReserved;
} RGBQUAD;

Grüße

spooky

G
ghostwhisperer32 Themenstarter:in
5 Beiträge seit 2010
vor 13 Jahren

Hallo !
Ich denke ich weiss jetzt woran es liegt, dass sowohl new Bitmap als auch Clone das Pixelformat verwirft und fehlinterpretiert.
Das originalbild (geladen) wird richtig kopiert. Es wird zwar auch zu 32 bit umgemodelt, bleibt aber grau in grau.

Alle anderen Bilder die ich anzeigen möchte sind jedoch selbst BERECHNET.
zuerst extrahier ich die Daten in ein 2d-double-array, dann berechne ich zB den symmetrischen gradienten g=(p(x+1)-p(x-1))/2 ebenfalls als 2d-double.

Abschließend reskalier ich die ergebnisse auf 0..255 und mach byte draus und schreib das ergebnis in eine bitmapdata für das ergebnisbild gradientbmp im 8bppindexed format.

Und hier liegt wohl der Hase im Pfeffer: Die Daten SIND richtig skaliert haben aber keinen Bezug mehr zur Farb-Palette wie zb bei einem geladenen 8bit-Bild ?? Warum ist das so? Ich meine warum heisst das Format "indexed" wenn es trotzdem einen Bezug zu einer Farbpalette braucht? Und wie ich sagte, die Daten sind skaliert. Oder gibt es 2 Einträge pro Position ? Den Grauwert UND eine Palettenfarbe als enumeratedtype ? Muss ich an der Stelle eine eigene Farbpalette generieren und den Bezug künstlich wiederherstellen?

MFG Torsten

49.485 Beiträge seit 2005
vor 13 Jahren

Hallo ghostwhisperer32,

Ich meine warum heisst das Format "indexed" wenn es trotzdem einen Bezug zu einer Farbpalette braucht?

indexed bedeutet doch gerade, dass als Bitmapdaten nicht direkt die Farbwerte verwendet werden, sondern eben Indexwerte in eine Farbpalette.

Oder gibt es 2 Einträge pro Position ? Den Grauwert UND eine Palettenfarbe als enumeratedtype ?

Nein, ein Index bezieht sich immer genau auf einen bestimmten Eintrag in der Farbpalette. Der Wert des Index repräsentiert keinen Grauwert. Für welche Farbe ein Index steht, ergibt sich nur durch einen Blick an die durch den Index bestimmte Position in der Farbpalette.

Muss ich an der Stelle eine eigene Farbpalette generieren und den Bezug künstlich wiederherstellen?

Wenn du in einem Indexed-Format alle Farben nach einer bestimmten Formel ändern willst, musst du nur die Farben in der Farbpalette neu berechnen. Die Indexwerte kannst und musst du alle unverändert lassen.

herbivore

G
ghostwhisperer32 Themenstarter:in
5 Beiträge seit 2010
vor 13 Jahren
pferdsch

Danke nochmal !!

Jetzt gehts ohne mein "vonHandkopieren". Ich hatte zwar die Bitmaps mit dem richtigen Format 8bppindexed angelegt, aber dabei wurden die Paletten-Strukturen NICHT angepasst. Also fehlte noch ein picnew.palette = picorg.palette.
Wenn ich jetzt zB gradientenbetrag {1000...0,1} auf {255..0} abbilde kann ich dies per pointer in die bitmapdata eintragen. Der Rest ergibt sich von selbst.

Ich hatte immer gedacht wo 8bit dransteht ist auch 8bit drin...
Dabei ist in Windowsforms offensichtlich IMMER 32 bit und nur die Grösse der Palette definiert 8,16,32 bit usw gemäß Anzahl der Einträge und welcher Farbe das entspricht.

Also vielen Dank !!

Wenn du in einem Indexed-Format alle Farben nach einer bestimmten Formel ändern willst, musst du nur die Farben in der Farbpalette neu berechnen. Die Indexwerte kannst und musst du alle unverändert lassen.

49.485 Beiträge seit 2005
vor 13 Jahren

Hallo ghostwhisperer32,

auch bei Indexed-Formaten muss ja irgendwo mal angegeben werden, welche en Wert R, G und B (und evtl. noch A) haben. Dafür braucht man 24/32bit. Und das steht natürlich als Wert in der Palette. Was bei Indexed-Formaten als Bittiefe angegeben wird, bezieht sich auf die Größe der Indexwerte. Insofern ist ist da bei 8bit auch tatsächlich 8bit drin, sprich jedes Pixel in der Bitmap wird dann durch 8bit repräsentiert. Und es sind entsprechend nur 256 unterschiedliche Farben möglich. Welche 256 Farben das genau sind, bestimmt die Palette.

herbivore

G
ghostwhisperer32 Themenstarter:in
5 Beiträge seit 2010
vor 13 Jahren
interne repräsentation

Schon klar jetzt. Ich meinte aber was anderes..
Ein Bild dass mit 8Bit abgespeichert wird hat WIRKLICH nur 8 Bit.
Das Windowsinterne Standard-Format hat hier immer jedoch 32 bit unabhängig von der Anzahl der Farben in EINER Palette.
Anders gesagt: 8bpp und 32argb haben beide dieselbe substruktur, thats all.

OK Danke nochmal und schönes Wochenend !!

49.485 Beiträge seit 2005
vor 13 Jahren

Hallo ghostwhisperer32,

8bpp und 32argb haben beide dieselbe substruktur

nö, das wird z.B. in NET 1.1: Bitmap, Graphics, Handle: Problem mit 8-bit-Pixel deutlich. Bei 8bpp wird immer nur ein Byte per Pixel geschrieben und nicht vier wie bei 32bpp.

herbivore