2009-09-30 9 views
11

Ich lese Bits aus einer monochromen Bitmap. Ich speichere alle 16 Bits in einer short in umgekehrter Reihenfolge. Wenn das Bit in der Bitmap schwarz ist, speichert ein 1. Wenn weiß, speichern Sie einen 0.Verschieben des Vorzeichen-Bits in .NET

ZB: für Bitmap: BBBW BBBW BBBW wwww
meine kurz ist: 0000 0111 0111 0111

Der erste Weg ich habe versucht, dies zu tun war:

short m; 
// ... 
Color c = bmp.GetPixel(j, i); 
if (c.R == Color.Black) 
    m |= short.MinValue; 
m >>= 1; 
// ... 

nach einer Zuordnung und Verschiebung, bekam ich den erwarteten -32768 (1000 0000 0000 0000).
Nach dem zweiten Mal habe ich -16384 (1100 0000 0000 0000).

Ich habe meinen Code auf ushort geändert und die if Zeile zu s |= (ushort)Math.Pow(2, 15); geändert und jetzt funktioniert es.

Meine Frage ist: Warum wird das Zeichen Bit in .NET nicht verschieben? Gibt es eine Möglichkeit, das Vorzeichenbit zu verschieben?

+0

Um es effizient zu halten, können Sie einfach m ‚ushort‘ anstelle von ‚kurz‘, oder starten Sie aus dem Bit ganz rechts und links verschieben machen (nur mit Math.Pow zu vermeiden). – Groo

Antwort

27

In C# Verschiebungen sind arithmetische Verschiebungen (im Gegensatz zu logischen Verschiebungen). In einer rechten arithmetischen Verschiebung, das Vorzeichenbit auf der linken Seite verschoben, so dass das Vorzeichen der Zahl erhalten bleibt. Ein Recht Verschiebung ist äquivalent von 2 bis Dividieren:

alt text

Wenn Sie eine logische Verschiebung (keine Vorzeichenerweiterung) wollen, Verwendung Zahlen ohne Vorzeichen:

alt text

+0

Beachten Sie, dass "unsigned numbers" nicht für die gesamte Methode verwendet werden muss, wenn sie aus einem anderen Grund nicht passt . 'm = (kurz) ((ushort) >> 1)' würde der Compiler die 'shr.un' für unsigned shift ohne irgendwelche Cast-Operationen ausgeben; Die Umwandlungen, die in der C# existieren, sind nicht in der CIL vorhanden, sie wissen nur, dass Sie sie zu diesem Zeitpunkt nicht signiert behandeln wollen. –

3

Recht Verschiebung unterzeichnet ganze Zahlen in C# mit dem linken Bits mit dem Vorzeichenbit füllen. Effektiv ist das Ergebnis des Rechts, das eine Ganzzahl mit Vorzeichen um ein einzelnes Bit verschiebt, gleich der Division durch 2.

Sie können diese Art von Rechtsverschiebung auch an anderen Stellen finden. Zum Beispiel liefert die x86-Assembly zwei verschiedene Anweisungen, sar (die die linken Bits mit Vorzeichenbit füllt) und shr (die linke Bits mit Null füllt).

Wenn Sie dieses Verhalten nicht in C# möchten, müssen Sie unsignierte Typen beim Verschieben verwenden.

1

Die kurze Antwort auf Ihre Frage, wie Sie herausgefunden haben, ist die Verwendung von unsigned Integer, um das Vorzeichen Bit zu vermeiden, und das ist alles in Ordnung. Jedoch sind die folgenden betrachten

Optimierungshinweis

Unter der Annahme, dass man eine Menge solcher Umwandlungen zu tun haben (in der Regel gibt es eine Menge von Pixeln in einer Bitmap), sollte eine Reihe von 256 Byte prüfen, mit das würde direkt die umgekehrte Version des Bitmusters (oder was auch immer die Umwandlung sein mag) für ein komplettes Byte bereitstellen. Dann erhalten Sie durch direkte Indizierung dieses Arrays mit dem hohen oder niedrigen Byte-Wert des 16-Bit-Wortes die Ergebnisse für alle 8 Bits. In einigen Fällen, in denen die Zeit/Leistung sehr begrenzt ist (und Platz ist verfügbar ...), können Sie sogar eine Array-Größe von 64k verwenden, die jeweils ein ganzes Wort verarbeitet.

in Ihrem Beispiel angegeben die Umwandlung gegeben, können Sie die vorausberechneten Werte Array so etwas wie sein haben würde:

byte[] mirror = { 
     0x00, 0x80, 0x40, 0xC0, 0x20, 0xA0, 0x60, 0xE0, 0x10, 0x90, 0x50, 0xD0, 0x30, 0xB0, 0x70, 0xF0, 
     0x08, 0x88, 0x48, 0xC8, 0x28, 0xA8, 0x68, 0xE8, 0x18, 0x98, 0x58, 0xD8, 0x38, 0xB8, 0x78, 0xF8, 
     0x04, 0x84, 0x44, 0xC4, 0x24, 0xA4, 0x64, 0xE4, 0x14, 0x94, 0x54, 0xD4, 0x34, 0xB4, 0x78, 0xF8, 
     // etc.. 
     0x0F, 0x8F, 0x4F, 0xCF, 0x2F, 0xAF, 0x6F, 0xEF, 0x1F, 0x9F, 0x5F, 0xDF, 0x3F, 0xBF, 0x7F, 0xFF 
    }; 
+0

Ich konvertiere das Bild, das auf einem Gerät angezeigt wird, das es benötigt, in umgekehrten 16-Bit-Segmenten wie folgt: bitmap = 0,1,2, ..., 62,63. device = 15..0, 31..16, 47..32, 63..48 – Dinah

4

http://msdn.microsoft.com/en-us/library/k2ay192e.aspx

„Der >> Operator verschiebt die Bits von expression1 rechts durch die Anzahl der in expression2 angegebenen Bits.Das Vorzeichenbit von ausdruck1 wird verwendet, um die Ziffern von links zu füllen.Ziffern, die nach rechts verschoben sind, werden verworfen.Der Datentyp von Ausdruck1 bestimmt den Datentyp, der von diesem Operator zurückgegebenwird."

2

pro http://www.blackwasp.co.uk/CSharpShiftOperators.aspx

... unterzeichnet ganzen Zahlen die höchste Bit zu bestimmen, verwenden, wenn der Wert einer Variablen positiv oder negativ ist, und dass die verbleibenden Bits verwenden Zweierkomplementnotation für negative Werte Die höchste Bit würde normalerweise als das Überlaufbit für eine Schiebe-Links-Operation betrachtet werden. Um dies zu berücksichtigen, versteht C#, dass dieses Bit nicht für signierte Datentypen angepasst werden sollte und dass negative Zahlen entsprechend verschoben werden sollten. Das Verschieben funktioniert sowohl für negative als auch für positive Werte.

int value = -240; 
int halved = value >> 1;  // Result = -120 
Verwandte Themen