Laden...

Bitwise Bitmap Compare: Negativer Stride...

Erstellt von KainPlan vor 14 Jahren Letzter Beitrag vor 14 Jahren 2.457 Views
K
KainPlan Themenstarter:in
133 Beiträge seit 2009
vor 14 Jahren
Bitwise Bitmap Compare: Negativer Stride...

Ich hab mich hier an einem bitweisen vergleich zweier Images versucht. Mein Problem ist nur das die Strides beider Bilder negativ sind (deswegen auch Math.Abs()). Wenn man versucht den Speicher zu kopieren erhält man beim zweiten Schritt eine Zugriffsverletzung. Nun komm ich nicht weiter, ich hab keine Ahnung woher die Zugriffsverletzung kommt.



        public static bool SameAs(this Image g, Image img)
        {
            #region VALUE_COMPARE

            #if VALUE_COMPARE
                if (g.Width != img.Width || g.Height != img.Height)
                    return false;
                if (g.HorizontalResolution != img.HorizontalResolution)
                    return false;
                if (g.VerticalResolution != img.VerticalResolution)
                    return false;
                if (g.PixelFormat != img.PixelFormat)
                    return false;
                if (g.Palette.Flags != img.Palette.Flags)
                    return false;
                if (g.Flags != img.Flags)
                    return false;
            #endif

            #endregion

            #region BIT_COMPARE

            #if BIT_COMPARE
                // Bit compare
                Bitmap one = g as Bitmap;
                Bitmap two = img as Bitmap;

                BitmapData d0 = one.LockBits(new Rectangle(0, 0, one.Width, one.Height), ImageLockMode.WriteOnly, one.PixelFormat);
                BitmapData d1 = two.LockBits(new Rectangle(0, 0, two.Width, two.Height), ImageLockMode.WriteOnly, two.PixelFormat);

                int s0 = Math.Abs(d0.Stride);
                int s1 = Math.Abs(d1.Stride);

                /* I think this cannot happen if VALUE_COMPARE is defined. */
                bool retval = false;
                if (s0 != s1)
                    goto finalize;

                if (d0.Stride != d1.Stride)
                    goto finalize;

                IntPtr scan0 = d0.Scan0;
                IntPtr scan1 = d1.Scan0;

                for (int i = 0; i < one.Height; i++)
                {
                    byte[] b0 = new byte[s0];
                    byte[] b1 = new byte[s0];

                    Marshal.Copy(scan0, b0, i * s0, s0);
                    Marshal.Copy(scan1, b1, i * s0, s0);

                    for (int j = 0; j < s0; j++)
                    {
                        if (b0[j] != b1[j])
                        {
                            goto finalize;
                        }
                    }
                }

                retval = true;

                finalize:
                one.UnlockBits(d0);
                two.UnlockBits(d1);

                return retval;
            #else
                return true;      
            #endif

            #endregion
        }

1.361 Beiträge seit 2007
vor 14 Jahren

Hi,

wenn Stride negativ ist, dann ist Stride negativ. Das bedeutet, dass die nächste Zeile im Speicher davor liegt. Deshalb bekommst du auch, wenn du stride manuell wieder auf positiv setzt und im Speicher dahinter ließt, eine Zugriffsverletzung.

//Edit:
Also einfach das Math.Abs wegnehmen und der Code sollte funktionieren (hab ihn darüberhinaus aber nicht weiter geprüft)

beste Grüße
zommi

K
KainPlan Themenstarter:in
133 Beiträge seit 2009
vor 14 Jahren

  byte[] b0 = new byte[s0];

Man kann kein Array mit einer negativen Zahl initialisieren.


  Marshal.Copy(scan0, b0, i * s0, s0);

Der memcpy ersatz nimmt auch keine negative Zahl an...

49.485 Beiträge seit 2005
vor 14 Jahren

Hallo KainPlan,

ImageLockMode.WriteOnly

hm, du willst doch lesen, oder?

herbivore

1.361 Beiträge seit 2007
vor 14 Jahren

Hi,

Ich gehe im folgenden, davon aus, dass du die Bilder "inhaltsgleich" vergleich willst.
sonst könntest du ja einfach die Speicherbereiche byte-weise durchgehen und vergleichen, ohne dich dabei überhaupt zu interessieren, dass es sich dabei um Bilder handelt.
1.Verwende kein Goto. Lieber einen try-catch-finally block und wirf intern ne Exception. 1.Die Strides von zwei Bilder können sehr wohl unterschiedlich sein. Also streiche

if (s0 != s1)

sowie

if (d0.Stride != d1.Stride)

1.Die Anzahl an sinnvollen Bytes pro Zeile ist nicht (immer) gleich dem Math.Abs(Stride). Korrekt wäre

bytesPerLine = width * bitDepth / 8

(falls bitDepth durch 8 teilbar ist, sonst müsste, bevor du durch 8 teilst, erst noch aufgerundet werden auf das nächste vielfache) 1.Die Byte-Arrays erzeugst du dann mit

new byte [bytesPerLine];

1.Kopiert wird mit

Marshal.Copy(scan0 + i*d0.Stride, b0, 0, bytesPerLine);

beste Grüße
zommi

K
KainPlan Themenstarter:in
133 Beiträge seit 2009
vor 14 Jahren

Die Strides von zwei Bilder können sehr wohl unterschiedlich sein. Also streiche

if (s0 != s1)  

sowie

if (d0.Stride != d1.Stride)  

Aber wieso sollt ich das streichen? Wenn die werte sich unterscheiden hab ich ja 2 verschiedene Bitmaps, warum sollt ich da dann weiter prüfen?

1.361 Beiträge seit 2007
vor 14 Jahren

Bloß weil intern im Speicherlayout im einen Bild die Pixel anders angeordnet sind, sind es doch trotzdem die selben Pixel-Werte, sprich das selbe dargestellte Bild.

beste Grüße
zommi

K
KainPlan Themenstarter:in
133 Beiträge seit 2009
vor 14 Jahren

Achso! Jetzt hab ich's verstanden. -.- klappt nun! Danke.