Frage:
Wie man ein Bitmap-Bild auf Arduino liest
Seawish
2016-01-21 13:35:15 UTC
view on stackexchange narkive permalink

Ich möchte eine Bitmap in ein binäres Array konvertieren. Mein Bitmap-Bild ist ein monochromatisches 1bpp-Bild mit 272 * 208 Pixel. Ich bin verwirrt, wenn die Breite meines Bildes 16 statt 272 beträgt und die Höhe korrigiert wird. Und wenn ich den Bitmap-Header überspringe, um Bitmap-Informationen zu erhalten, wird in meiner Textdatei eine Zeichenfolge mit einer bedeutungslosen Zahl angezeigt.

  #include <SPI.h> # include <SD.h> # include <TFT.h>File bmpImage; File textFile; void setup () {Serial.begin (9600); while (! Serial) {;} Serial.print ("Initializing SD card ..."); if (! SD.begin (53)) {Serial.println ("Initialisierung fehlgeschlagen!"); return;} Serial.println ("Initialisierung abgeschlossen."); int height = 0; int width = 0; // OpenbmpImage = SD.open ("Circle.bmp", FILE_READ); textFile = SD.open ("test. txt ", FILE_WRITE); bmpImage.seek (0x12); // Breite in Pixel = 16width = bmpImage.read (); bmpImage.seek (0x16); // Höhe in Pixel = 208height = bmpImage.read (); Serial. println (width); Serial.println (height); int imageSize = height * width; bmpImage.seek (0x36); // Bitmap-Header für (int i = 0; i < height; i ++) {for (int j = 0; j < width; j ++) {textFile.write (bmpImage.read ()); textFile.write (""); } textFile.write ("\ n");} bmpImage.close (); textFile.close (); Serial.println ("done write");} void loop () {// nach dem Setup passiert nichts}  
Drei antworten:
Mikael Patel
2016-01-21 15:41:56 UTC
view on stackexchange narkive permalink

Das war eine sehr rohe Methode, um eine BMP -Datei zu lesen. Es gibt viele Annahmen, die zu Fehlern führen können.

  1. Die Datei ist eine BMP-Datei. Die Headersignatur wird nicht überprüft.
  2. Es wird angenommen, dass der Bildversatz direkt hinter dem Dateikopf liegt. Es wird nicht gelesen.
  3. Die Bildbreite beträgt weniger als 256. Es wird nur das niedrigste Byte der 32-Bit-Bildbreite gelesen. Bei 272> 256 beträgt das niedrige Byte 16.
  4. Die Bildhöhe beträgt weniger als 256. Es wird nur das niedrigste Byte der 32-Bit-Bildhöhe gelesen.
  5. ol>

    Es ist eine kleine Bitmap, aber das Lesen dauert sehr lange, wenn jeweils ein Byte gelesen wird. Es gibt Methoden zur Verbesserung der Leistung, aber das ist eine Antwort auf eine andere Frage.

    Eine robustere Methode zum Lesen der BMP-Header- und Bildinformationen besteht darin, sie als Struktur zu definieren und zu lesen.

      struct bmp_file_header_t {uint16_t Signatur; uint32_t file_size; uint16_t reserviert [2]; uint32_t image_offset;}; struct bmp_image_header_t {uint32_t header_size; uint32_t image_width; uint32_t image_height; uint16_t color_planes; uint16_t bits_per_pixel; uint32_t compress_method; uint32_t image_size; uint32_t horizontal_resolution; uint32_t vertikale_auflösung; uint32_t colours_in_palette; uint32_t important_colors;}; bmpImage = SD.open ("Circle.bmp", FILE_READ); ... // Datei lesen headerbmp_file_header_t fileHeader; bmpImage.read (&fileHeader, sizeof (fileHeader)); ... // Lesen Sie das Bild headerbmp_image_header_t imageHeader; bmpImage.read (&imageHeader, sizeof (imageHeader)); ... // Überprüfen Sie die Bildgröße und das Format ... // Suchen Sie die pixelsbmpImage.seek (fileHeader.image_offset);  

    Die Datei- und Bildinformationen werden in Little-Endian gespeichert, sodass sie auf einem AVR einwandfrei funktionieren.

frarugi87
2016-01-21 15:42:06 UTC
view on stackexchange narkive permalink

Zunächst empfehle ich Ihnen, die vollständige Spezifikation des BMP-Dateikopfs zu lesen (z. B. auf Wikipedia).

Beachten Sie insbesondere, dass

  1. Sie können eine Farbtabelle (Palette) haben: Folglich kann die Startadresse der Bitmap-Daten nicht 0x36 sein.
  2. Die Pixel werden nicht pro Byte gespeichert, sondern können gepackt werden (siehe ) Pixelspeicher)
  3. Es gibt verschiedene Arten von Headern
  4. Breite und Höhe sind 4-Byte-Ganzzahlen, daher ist Ihre Breite in Ordnung (272 = 256 + 16)
  5. ol>

    Dies bedeutet, wenn Ihre Bitmap einen Standard- BITMAPINFOHEADER -Header hat, und wenn Ihre Bitmap einen 24-Bit-Standard hat Bei der Codierung (16 Millionen Farben) können Sie Folgendes tun:

      int32_t readNbytesInt (Datei * p_file, int position, byte nBytes) {if ( nBytes > 4) return 0; p_file->seek (Position); int32_t weight = 1; int32_t result = 0; für (; nBytes; nBytes--) {Ergebnis + = Gewicht * p_file->read (); Gewicht << = 8; } Ergebnis zurückgeben;} void setup () {Serial.begin (9600); while (! Serial); Serial.print ("SD-Karte initialisieren ..."); if (! SD.begin (53)) {Serial.println ("Initialisierung fehlgeschlagen!"); während (1); // <- so solltest du die Ausführung blockieren, nicht mit Rückgaben} Serial.println ("Initialisierung abgeschlossen."); // Datei öffnen bmpImage = SD.open ("Circle.bmp", FILE_READ); Datei textFile = SD.open ("test.txt", FILE_WRITE); int32_t dataStartingOffset = readNbytesInt (&bmpImage, 0x0A, 4); // Ändere ihre Typen in int32_t (4byte) int32_t width = readNbytesInt (&bmpImage, 0x12, 4); int32_t height = readNbytesInt (&bmpImage, 0x16, 4); Serial.println (Breite); Serial.println (Höhe); int16_t pixelsize = readNbytesInt (&bmpImage, 0x1C, 2); if (Pixelgröße! = 24) {Serial.println ("Bild ist nicht 24 bpp"); während (1);
    } bmpImage.seek (dataStartingOffset); // Bitmap-Header überspringen // 24bpp bedeutet, dass Sie drei Bytes pro Pixel haben, normalerweise B G R Byte R, G, B; für (int32_t i = 0; i <-Höhe; i ++) {für (int32_t j = 0; j <-Breite; j ++) {B = bmpImage.read (); G = bmpImage.read (); R = bmpImage.read (); textFile.print ("R"); textFile.print (R); textFile.print ("G"); textFile.print (G); textFile.print ("B"); textFile.print (B); textFile.print (""); } textFile.print ("\ n"); } bmpImage.close (); textFile.close (); Serial.println ("done write");}  

    Die Textausgabe sollte eine Datei mit einem Array von Zeichenfolgen wie R10G100B25 sein, wobei R das ist rote Komponente des Pixels, G ist die grüne Komponente und B die blaue.

    Dies ist jetzt nur mit dem 24bpp-Format kompatibel. Wenn Sie weitere Formate unterstützen möchten, müssen Sie die Spezifikationen lesen und codieren.

    Lassen Sie mich wissen, ob dies für Sie funktioniert

SoreDakeNoKoto
2016-01-21 20:02:18 UTC
view on stackexchange narkive permalink

Oder Sie können Ihren alten Code mit einigen Anpassungen beibehalten, wenn Sie nur Ihr Bild lesen möchten, ohne sich um zu viele Überprüfungen zu kümmern.

Ändern Sie den Typ von imageSize in unsigned long .

Die Höhe und Breite sind 4-Byte-Felder, sodass ein einzelnes read () sie nicht schneidet. Sie müssen die Höhe und Breite als long oder int32_t deklarieren und dann bei jedem Offset 4 Bytes lesen, während Sie die Bytes mithilfe der Bitverschiebung zu einer Zahl zusammensetzen und sich daran erinnern Es ist Little Endian. So etwas:

  long width | = bmpImage.read (); width | = (long) (bmpImage.read ()) << 8; width | = (long) (bmpImage.read ()) << 16; width | = (long) (bmpImage.read ()) << 24;  

Wiederholen Sie diesen Vorgang, um die Höhe zu ermitteln, aber verwenden Sie abs ( ) , um den absoluten Wert zu erhalten, da dieser normalerweise negativ ist. Sie können auch nach einer Farbtabelle suchen. Normalerweise ist das ColorDepth-Feld ein guter Indikator (Offset 28). Wenn es weniger als 16 ist, sollten Sie eine Farbtabelle erwarten. Wenn Sie dies jedoch bereits wissen, können Sie es überspringen und zum Startversatz gelangen, normalerweise 0x36. Ihr aktueller Code berücksichtigt die Auffüllung nicht (obwohl Ihr Bild keine Auffüllung hat) und verwendet auch nicht das tatsächliche Bild Breite in Bytes. Um diese Breite zu erhalten, wird unter der Annahme, dass der BMP RGB888 24 Bit pro Pixel verwendet:

  width = ((width * 24) + 31) / 32; width * = 4;   vor>

Damit können Sie jetzt jede Zeile lesen, obwohl sie normalerweise von unten nach oben angeordnet ist. Sie schreiben jedoch nicht richtig in die Datei. Sie sollten textfile.print () und nicht write () verwenden. Ersteres schreibt den Dezimalwert jedes Bytes in Ihre Datei, während letzteres das exakte nicht codierte Byte in die Textdatei schreibt, was zu viel Kauderwelsch führen würde, wenn Sie versuchen, den Inhalt der Datei anzuzeigen, z. B. auf dem Editor. da der Bereich der druckbaren Zeichen (unter Standard-ASCII-Codierung) zwischen 32 und 127 liegt und Ihr Bild wahrscheinlich viele Bytes außerhalb dieses Bereichs hat.



Diese Fragen und Antworten wurden automatisch aus der englischen Sprache übersetzt.Der ursprüngliche Inhalt ist auf stackexchange verfügbar. Wir danken ihm für die cc by-sa 3.0-Lizenz, unter der er vertrieben wird.
Loading...