Integer in Binärzahl umwandeln ?



  • Hallo zusammen...

    Ich habe ein kleines Problem, dessen Lösung sicher ganz einfach ist, aber ich bekomme es nicht hin 😮

    Es soll eine 16-Bit Raw-Datei gelesen werden. Wenn ich die Datei einlese bekomme ich pro Pixel aber 2 Integerwerte (zwischen 0 und 255).
    (Da kann ich leider nix dran Ändern, da die Dateien so angelegt sind. Lieber wäre mir natürlich ein Integer von 0 - 65535)

    Um an mein 16-Bit-Signal zu kommen müsste ich jetzt, glaube ich zumindest, die Integer in Binärzahlen umrechnen und diese "aneinandersetzen".
    Die so erhaltene doppelt so lange Binärzahl würde ich dann wieder umrechnen wollen in einen 16-Bit Integer.

    Gibt es dafür eine möglichst elegante Lösung?

    Mein bisheriger Ansatz liefert leider nur zwei Zeichenketten von 1 und 0. Diese müssten dann aneinander gesetzt werden und wieder zu einem Integer gemacht werden. Ziemliches gefrimel und funktioniert noch nicht so ganz 🙄

    Hoffe, ihr könnt mir nen Tipp geben, wie ich das besser hin bekommen kann...

    Danke schonmal! 🙂



  • // Per Bit-Verknüpfung:
    unsigned char a = 0xA5;
    unsigned char b = 0x28;
    unsigned short c = static_cast<unsigned short>(a)<<16 | b;
    
    // Per union:
    union CharConnector
    {
        struct
        {
            unsigned char a;
            unsigned char b;
        };
        unsigned short c;
    };
    
    CharConnector v;
    v.a = 0xA5;
    v.b = 0x89;
    std::cout << v.c << std::endl;
    

    🙂



  • Vielen Dank erstmal!
    Das hat doch schonmal wunderbar funktioniert.

    Leider funktioniert das ganze mit der Raw-Datei nicht so ganz, wie ich es mir vorgestellt hab 😞
    Um die Daten mit Origin vernünftig auswerten zu können möchte ich die Grauwerte in eine ASCII-Datei schreiben. Ich erhalte zwar ein 640x480 Pixel Grauwertbild, aber das sieht nicht aus, wie es aussehen sollte 🙄 (http://www.bildercache.de/anzeige/20081126-224407-208.jpg)

    Ein Ähnliches Bild erhalte ich aber auch, wenn ich ungeraden Pixel binär auf die geraden addiere. Daran kanns also nicht liegen...
    Kennt sich vllt. einer mit solchen Problemen aus?

    Hier mal mein Programm:

    #include <fstream>
    #include <iostream>
    #include <stdio.h>
    using namespace std;
    
    union CharConnector
    {
        struct
        {
            unsigned char a;
            unsigned char b;
        };
        unsigned short c;
    };
    
    int main(int argc, char *argv[])
    {
    	fstream Datei1, Output;
    	unsigned char zelle=0;
    	int temp=0;
    	unsigned char a=0x01, b=0x01;
    	unsigned short bin = static_cast<unsigned short>(a)<<16 | b; 
    	CharConnector v;
    
    	Datei1.open("02.raw", ios::in);
    	Output.open("out.txt", ios::out);
    
    	for (int i=0 ; i<614400 ; i++)		//640*2*480=614400 
    	{
    
    			Datei1 >> zelle;			// bei allen ungeraden Pixeln soll der Wert binär auf den des vorhergehenden addiert werden
    			if (i%2!=0) 
    			{
    				v.a = temp;
    				v.b = zelle; 
    				bin = v.c;
    				Output << bin << "\t";				
    			}
    
    			if (i%1280==0) Output << endl;  // Zeilenumbruch nach 640 Pixeln
    			temp = zelle;
    
    	}
    
    	Datei1.close();
    
    	return 0;
    }
    

    Vielleicht seht ihr ja auch schnell nen Fehler 😕

    PS: Ich weiß 100%, dass keine Header-Infos in der Datei gespeichert sind. Daran kanns also auch n icht liegen...



  • Hoi!

    Also, zwei Dinge:

    int temp=0;
    
    // ...
    
    v.a = temp;
    

    Erstere Zeile ist die einzige Zuweisung an temp. Wenn du allerdings zwei unsigned char Werte aus der Datei ließt und diese "verknüpfen" möchtest, dann solltest du temp zu irgendeinem Zeitpunkt auch einen solchen Wert zuweisen.

    2. Ich glaube du weiß nicht genau was du eigentlich machst. Das ist schlecht, vor allem, wenn du Algorithmen für sauber definierte, binäre Dateiformate schreiben möchtest. Zunächsteinmal solltest du dir darüber klar werden was du überhaupt hast und was du möchtest. Ich kenne das Dateiformat mit dem du arbeitest nicht, aber nach dem was ich von dir gehört habe, stehen in dem Dateiformat zwei zueinandergehörende 8-Bit Werte (char bzw unsigned char) hintereinander, welche du auslesen möchtest und dann als 16-Bit Wert (short bzw unsigned short) speichern möchtest.

    Zunächsteinmal solltest du dir darüber im klaren sein, dass du binäre Zahlen einfach "hintereinander" hängen kannst. Dazu solltest du wissen, dass der Computer zahlen immer binär speichert, es lassen sich also alle binären Operationen auf deine anscheinend Dezimal gespeicherten Werte anwenden. Unter C++ haben diese Operationen die Operanden <<, >> (Bit-Verschiebung), |, &, ^ (Bit-Verknüpfungen).
    Wenn du nun also zwei 8-Bit Werte aus einer Datei ließt und den ersten in der Variablen ersterChar und den zweiten in der Varaiblen zweiterChar speicherst, dann kann du die einfach über Bitoperationen verknüpfen und sie in neuerShort speichern. Siehe dazu folgenden Quelltext

    neuerShort = ersterChar << 8; // wir verschieben ersterChar um 8 Bits nach links
    neuerShort = neuerShort | zweiterChar; // Bitweise oder verknüpfung mit zweiterChar, um die 8 leeren Bits, die durch die verschiebnung entstanden sind mit den Bits aus zweiterChar zu füllen
    

    Badestrand's Vorschlag nutzt nun einen C++ Sprachmechanismus um das Verschieben der Bytes unnötig zu machen. Ein Union ist eine Struktur, die es ermöglicht mit verschiedenen "Masken" auf den selben Speicherbereich zuzugreifen.
    Du schreibst also Werte nach a und b und kannst dann auf c zugreifen und erhälst das selbe Ergebnis als hättest du die eingelesenen Werte so verschoeben wie ich es oben beschrieben habe.

    Vorsicht sei allerdings geboten: ich meine, dass je nach Architektur, nämlich Big- bzw Little Endian sich die Reihenfolge der High- und Lowbytes umkehrt und darum geschriebener Quelltext in diesem Zusammenhang nicht einwandfrei portabel ist. Das gilt vor allem für die Union Variante. Ich glaube, bin mir allerdings nicht ganz sicher, dass erstere Variante unabhängig von der "Endianess" funktionieren sollte.

    Grüße,
    Daniel



  • Hallo ip!

    Wenn du sagst, dass ich nicht genau weiß, was ich eigentlich mache, hast du gar nicht mal so unrecht 🙄
    Ich beschäftige mich noch nicht lange mit C++ und auch nur immer mal wieder schubweise. Ich benötige es jetzt aber "leider" öfter um gewisse Probleme zu lösen. Ich muss aber zugeben, dass mich mit der Zeit auch ein gewisser Ehrgeiz gepackt hat, dass alles hin zu bekommen 🙂

    Wie ein Computer so im groben Funktioniert (Binäre Darstellung usw.) ist mir aber durchaus klar. Das Problem ist es wohl eher, dass ich noch immer nicht so das Gefühl dafür habe, was und wie man was mit C++ machen kann. Diese Bitoperatoren waren mir zB neu 😮 (Obwohl ich schon einige Tutorials und nen kleines Buch zu C++ gelesen habe)

    Wenn du nun also zwei 8-Bit Werte aus einer Datei ließt und den ersten in der Variablen ersterChar und den zweiten in der Varaiblen zweiterChar speicherst, dann kann du die einfach über Bitoperationen verknüpfen und sie in neuerShort speichern.

    Ich werde im Laufe des Vormittags die von dir Vorgeschlagene Variante ausprobieren. Aber irgendwie habe ich wenig Hoffnung, da Badestrand Methode ja mit Testzahlen auch super funktioniert hat (hatte mir nen kleines Prog geschrieben, welches dann die Zahlen so zusammengesetzt hat).

    Deshalb habe ich ja "gehofft", dass ihr in meinem Programm irgend einen groben Denkfehler findet.
    Hab "temp" jetzt mal als "unsigned char" definiert, ändert aber nix. Werd dann auf dem Weg zur Uni nochmal drüber nachdenken. Wenn inzwischen jemand eine Idee hat, nur her damit 🙂



  • Ich hatte mich geirrt was den Fehler in deinem Quelltext anging - du weißt temp Später noch den Wert aus zelle zu, das hatte ich vorher übersehen.

    Wie aber bereits gesagt, kann es gut sein, dass du ein Problem mit der Reihenfolge der Bytes in der Datei hast. Zur Verdeutlichung:

    Wenn du einen Short (16 bit) in einem Speicher ablegst, hast du dazu im Prinzip zwei Möglichkeiten, entweder "nach oben" oder "nach unten" liegend. Folgendes Bild verdeutlicht dies

    Dezimal 5 als 16 Bit in Big Endian
    
    Adresse   0x000001    0x000002 
    Byteorder High Byte   Low Byte
    Binär     0000 0000   0000 0101
    
    bzw
    
    Dezimal 5 als 16 Bit in Little Endian
    
    Adresse   0x0000001  0x000002
    Byteorder Low Byte   High Byte
    Binär     0000 0101  0000 0000
    

    Erstere Variante nennt man Big Endian und letztere Little Endian. Die x86 Rechnerarchitektur benutzt das Little Endian Format.
    Die Frage ist nun in welcher Reihenfolge die Daten in der Datei abgespeichert sind. Sollten sie dort im Big Endian Format abgelegt sein muss eine konvertierung erfolgen. Das geschieht einfach indem du die Zuweisungen an v.a und v.b vertauschst und somit der Reihenfolge der Bytes im Speicher vertauschst.

    Grüße,
    Daniel

    PS: Was hindert dich eigentlich daran einfach direkt 2 Byte aus der Datei zu lesen und diese in einem unsigned short zu speichern?


Anmelden zum Antworten