Forum: Mikrocontroller und Digitale Elektronik Bitmap-header-code


von leluno (Gast)


Lesenswert?

ich möchte den ov7670-output als Bitmap speichern. Der Sensor liefert 
16bit-Pixel. Kennt jemand Programmcode zur Generierung der 54 Bytes 
Bitmap-header?

von Dirk K. (dekoepi)


Lesenswert?

Du musst die Ausgabedaten noch umrechnen und den Header nach dieser 
Struktur schreiben:
http://de.wikipedia.org/wiki/Windows_Bitmap#Dateikopf

Nimm' beispielsweise 24 Bit Bitmap. Dazu musst du das packed-Format halt 
"strecken", bei 565-RGB eben
Pixel1[0]=AusgabeByte1>>3;
Pixel1[1]=((0b00000111 & Ausgabebyte1)<<3) | (Ausgabebyte2>>5);
Pixel1[2]=(0b00011111 & Ausgabebyte2);

Solltest du die YUV-Ausgabe verwenden, musst du sogar richtig rechnen 
lassen.

Edit: Grade gesehen, Bitmap kann auch 16Bit, dachte zunächst, das geht 
nur mit komprimierten Daten. Also einfach 16-Bit-RGB speichern, und 
alles sollte passen.

: Bearbeitet durch User
von c-hater (Gast)


Lesenswert?

leluno schrieb:

> ich möchte den ov7670-output als Bitmap speichern. Der Sensor liefert
> 16bit-Pixel. Kennt jemand Programmcode zur Generierung der 54 Bytes
> Bitmap-header?

1)
Ein Bitmapheader hat keine konstante Länge, da er offene Arrays enthält 
(bzw. zumindest enthalten kann).

2)
Ein Bitmapheader enthält Daten, die das Bild beschreiben. 
Dementsprechend kann es keinen universellen Code geben, um ihn zu 
schreiben. So ein Code könnte nur eine Funktion sein, dem man die 
entsprechenden Informationen als Parameter übergeben müßte, damit er sie 
dann in die Struktur schreibt. Da kann man dann die Informationen auch 
gleich selber in die Struktur schreiben. Insbesondere, wenn man sowieso 
nur den Header für ein bestimmtes feststehendes Bildformat schreiben 
will, dann kann man ihn nämlich komplett zur Entwurfszeit 
vordefinieren/vorberechnen und der Laufzeitcode macht nichts anderes 
mehr, als den Blob in eine Datei zu schreiben. Das "Vorberechnen" hält 
sich dabei übrigens sehr in Grenzen, es gibt nur maximal drei berechnete 
Felder im Header.

3)
"16Bit-Pixel" ist nicht exakt genug, denn es gibt etliche verschiedene 
Spielarten von 16Bit-Pixeln. RGB555, RGB565 und diverse YUV-Formate. Der 
Header muß zum Inhalt passen, sonst sieht das Ergebnis etwas bis sehr 
komisch aus.

Kurzfassung: du wirst nicht drumrumkommen, deine Faulheit zu überwinden 
und dich selber mit der Struktur zu beschäftigen.

von Maxx (Gast)


Lesenswert?

leluno schrieb:
> ich möchte den ov7670-output als Bitmap speichern. Der Sensor
> liefert
> 16bit-Pixel. Kennt jemand Programmcode zur Generierung der 54 Bytes
> Bitmap-header?

Wenn du immer konstante Einstellungen hast und selbst über alle Details 
bestimmen kannst ist der einfachste und praktikabelste weg dir ein BMP 
dieser Größe und dieses Formats am PC zu erstellen und den Header daraus 
auszuschneiden und als Template zu verwenden.

Du brauchst ja keine eierlegende Wollmilchsau.

von leluno (Gast)


Lesenswert?

danke für die Antworten

c-hater schrieb:
> Das "Vorberechnen" hält
> sich dabei übrigens sehr in Grenzen, es gibt nur maximal drei berechnete
> Felder im Header.

genau dafür hätte ich gern den code

> Kurzfassung: du wirst nicht drumrumkommen, deine Faulheit zu überwinden
> und dich selber mit der Struktur zu beschäftigen.

Programmieren ist nun mal auch das Zusammensuchen von brauchbaren 
Code-Schnipseln.  Das Gebiet ist für einen interessierten Laien viel zu 
komplex, um alles selbst zu machen.

Maxx schrieb:
> Template

Das habe ich natürlich schon versucht. Scheiterte zunächst daran, dass 
das Kopieren im unteren Ascii-Bereich nicht so ganz einfach ist.

Es gibt hier eine Seite, in der es einigermaßen nachvollziehbar ist:
http://blog.csdn.net/pathuang68/article/details/4219681
Unklar ist mir der Aufbau des RGBQUAD-arrays. Da ist wohl definiert, was 
das Programm mit den 5-6-5-Pixeln machen muss. Mann könnte 
wahrscheinlich auch z.b. 5-5-6-Bitmaps machen.

Dirk K. schrieb:
> Dirk K.
Wie geht es denn bei dir voran? Ich habe inzwischen Dateien mit 
16bit-Pixeln auf der sd-karte, die ich leider noch nicht lesen und 
überprüfen kann. Wenn das geklappt hat, ist der nächste Schritt, das 
Bildformat auf 300k Pixel hochzusetzen.

von Dirk K. (dekoepi)


Lesenswert?

Habe gestern Abend mal ein SD-Card-Modul ausgekramt, das MicroSD-Modell 
ist zu sehr auf Arduino (5V) angepasst. Hadere noch immer mit DMA. 
Könnte aber via Polling einfach mal mit einer SD-lib was wegschreiben 
und gucken, ob die Daten überhaupt sinnvoll sind.

Mit dem Wiki-Link oben kann man sich einen Header doch ganz schnell 
selber tackern? Einige Felder musst du ohnehin anpassen, andere als 
konstant annehmen.

Sonst nimm halt das hier ;) 
http://forum.arduino.cc/index.php?topic=159557.msg1507008#msg1507008

von Karl H. (kbuchegg)


Lesenswert?

leluno schrieb:

> Programmieren ist nun mal auch das Zusammensuchen von brauchbaren
> Code-Schnipseln.  Das Gebiet ist für einen interessierten Laien viel zu
> komplex, um alles selbst zu machen.

Was ist zu komplex?

Das Ausrechnen, aus wievielen Pixel eine Bitmap besteht die zb 320 mal 
240 Pixel gross ist? Und wenn 1 Pixel aus 2 Byte besteht (wegen 16 Bit), 
wieviele Bytes das dann sind?

Das ist Stoff der 3. Klasse Grundschule. Wenn dir das zu komplex ist, 
dann solltest du dir ein anderes Hobby suchen.

Das einzige, was rudimentär einer irgendwie gearteten Definition von 
'komplex' entsprechen könnte, das ist, dass die Bytelänge einer Zeile in 
einer BMP immer ein Vielfaches von 4 ist. Und das wirst du ja wohl noch 
alleine hinkriegen, dass wenn ich zu dir 23 sage, du als Antwort 24 
gibst, weil 4 die nächst größere Zahl zu 23 ist, die auch durch 4 
teilbar ist.

Aber komplizierter als das wird es nicht, wenn es darum geht die 
einzelnen Felder in einem BMP Bitmap Header auszufüllen. Man muss 
natürlich wissen, welche Bedeutung die einzelnen Felder in dieser 
Struktur haben. Aber dazu gibt es ja Doku bis zum Abwinken.

: Bearbeitet durch User
von leluno (Gast)


Lesenswert?

Karl Heinz schrieb:
> Was ist zu komplex?

danke für den Hinweis.

Komplex ist das Gesamtprojekt. Ich habe nicht den Anspruch, z.B. das 
Fat-System selbst zu entwickeln. Ich verwende den foolproof-code von 
Chan -war immer noch schwierig genug. Ich habe mir meine Lcd-lib nicht 
komplett anhand des Datenblatts selbst geschrieben, sondern habe auf 
Codebeispielen aufgebaut. Die Initialisierung des ov7670 habe ich 
selbstverständlich nicht selbst gemacht sondern verwende hierfür 
Beispielcode von avrman.

Mein Ethernetteil stammt von Ulrich Radig.

Alles irgendwo abgeschrieben. Respekt vor Grundschülern, die anscheinend 
heute schon in der dritten Klasse solchen Code selbst entwickeln können. 
War zu meiner Zeit noch nicht so.

Natürlich bin ich in der Lage, den Bmp-header selbst zu entwickeln. Das 
dauert aber mindestens zwei Stunden - vielleicht auch wesentlich länger. 
Das beabsichtigte Gesamtsystem ist komplex. Wenn ich da zwei Stunden 
Entwicklungszeit dadurch einspare, dass ich den von Dirk aufgezeigten 
arduino-code benutze, dann mach ich das. Ich habe wirklich nicht den 
Anspruch jeden Teil des Gesamtcodes bis ins kleinste Detail selbst zu 
entwickeln.

Die einzelnen Codeschnipsel sinnvoll zusammenzusetzen ist zumindest für 
meine Verhältnisse anspruchsvoll genug.

von Karl H. (kbuchegg)


Lesenswert?

leluno schrieb:

> Alles irgendwo abgeschrieben. Respekt vor Grundschülern, die anscheinend
> heute schon in der dritten Klasse solchen Code selbst entwickeln können.

Davon habe ich nicht geschrieben.
Deine Frage dreht sich um die Member eines Bitmap Headers. Und deine 
Aussage war, den auszufüllen wäre so wahnsinnig komplex.

> Natürlich bin ich in der Lage, den Bmp-header selbst zu entwickeln. Das
> dauert aber mindestens zwei Stunden - vielleicht auch wesentlich länger.

Wahnsinn.
Mitlerweile sind fast 12 Stunden seit deiner Frage ins Land gezogen. Ich 
würde mal sagen - mit den 2 Stunden wärst du besser bedient gewesen.
Zumal es keine 2 Stunden dauert, für die überschaubare Anzahl an Membern 
in dieser Datenstruktur Belegungen zu finden. Da bewegen wir uns selbst 
bei jemandem, der das noch nie gemacht hat, eher bei 20 Minuten. Hat das 
jemand schon mal gemacht, dann sind das eher 2 Minuten.

Du willst es einfach nur nicht machen. Lass uns doch der Wahrheit ins 
Auge sehen und nicht dauern fadenscheinige Ausreden dafür finden.

> Das beabsichtigte Gesamtsystem ist komplex.

Deine Frage geht um Bitmap Header.
Punkt.

Bleib beim Thema.

von leluno (Gast)


Lesenswert?

Karl Heinz schrieb:
> Du willst es einfach nur nicht machen.

...und das völlig zu recht. Das Problem ist RGB565. Das Umrechnen auf 
24bit -während des Schreibvorgangs - scheidet wegen dem damit 
verbundenen Performanceverlust aus. 16bit-Bitmaps sind eher 
ungebräuchlich. Es wird eine Farbtabelle benötigt. Die Informationen zum 
Aufbau und zur Einbindung dieser Farbtabelle muss man sich mühsam 
zusammensuchen. Wenn du das in weniger als 2 Stunden schaffst, bist du 
wirklich gut.

von Karl H. (kbuchegg)


Lesenswert?

leluno schrieb:

> ...und das völlig zu recht. Das Problem ist RGB565. Das Umrechnen auf
> 24bit -während des Schreibvorgangs - scheidet wegen dem damit
> verbundenen Performanceverlust aus. 16bit-Bitmaps sind eher
> ungebräuchlich.

Immerhin hast du wenigstens mitlerweile bei Wikipedia den Headeraufbau 
nachgelesen. :-)

> Es wird eine Farbtabelle benötigt.

Nö.


'ungebräuchlich' heißt in diesem Zusammenhan, dass du wohl eher selten 
ein Malprogramm findest, welches 16 Bit Bilder speichern kann.
Aber öffnen und anzeigen können sie das alle. So wie jedes andere 
Programm, welches BMP einlesen kann.


> Die Informationen zum
> Aufbau und zur Einbindung dieser Farbtabelle muss man sich mühsam
> zusammensuchen. Wenn du das in weniger als 2 Stunden schaffst, bist du
> wirklich gut.

Lass es gut sein.
Das was du hier rumlametierst hab ich schon zur Genüge gemacht. Vor 20 
Jahren das erste mal, als man von so etwas wie einem Internet oder 
Online-Foren nur träumen konnte. Also erzähl mir da besser nicht, wie 
lange was dauert.

: Bearbeitet durch User
von c-hater (Gast)


Lesenswert?

leluno schrieb:

> Das Problem ist RGB565.

Nein.

> 16bit-Bitmaps sind eher
> ungebräuchlich.

HEUTE ja. Anfang bis Mitte der 90er des letzten Jahrhunderts sah das 
noch ganz anders aus. Und übrigens: Informationen dazu gab es damals im 
I-Net tatsächlich auch schon und es gibt sie heute auch noch. Es ist 
heute sogar viel einfacher, sie zu finden, denn heute gibt es Google. 
Man muß die Suchmaschine nur kompetent benutzen können.

> Es wird eine Farbtabelle benötigt.

Nein. RGB565 ist ganz im Gegenteil sogar eines der ganz wenigen 
Bitmap-Formate, was nicht nur keine Farbtabelle zwingend braucht, 
sondern obendrein auch keine der normalerweise möglichen optionale 
Farbtabelle haben darf.

Du hast die Deklaration des Headers immer noch nicht verstanden. Da gibt 
es eine Union...

> Die Informationen zum
> Aufbau und zur Einbindung dieser Farbtabelle muss man sich mühsam
> zusammensuchen.

Also ich würde die Farbtabellensache innert 2 Sekunden wiederfinden, 
obwohl ich mich das letzte Mal vor ca. 20 Jahren aktiv damit beschäftigt 
habe.
Allerdings weiß ich schon vorab, daß es sinnlos ist, sie in diesem 
Zusammenhang zu suchen, denn hier sind Farb*MASKEN* gefragt. Der andere 
Zweig der Uniondeklaration...

Und woher weiß man das? Weil man die verschissene Dokumentation zu 
bmih.biCompression tatsächlich gelesen hat und weiß, was die Konstante 
BI_BITFIELDS an dieser Stelle bedeutet...

von leluno (Gast)


Lesenswert?

Problem war wirklich nur die Suche nach dem Headeraufbau. Das 
Programmieren geht dann tatsächlich in 20 Minuten.

If we are dealing with 16-bit or 32-bit images, then the Color Table 
contains a set of bit masks used to define which bits in the pixel data 
to associate with each color. Note that the original Version 3 BMP 
format did not support these image types. Instead, these were an 
extension of the format developed for WindowsNT. For both the 16-bit and 
the 32-bit variants, the color masks are 32-bits long with the green 
mask being first and the blue mask being last. In both cases the bit 
masks start with the most significant bits, meaning that for the 16-bit 
images the least significant two bytes are zero. The format requires 
that the bits in each mask be contiguous and that the masks be 
non-overlapping. The most common bit masks for 16-bit images are RGB555 
and RGB565 while the most common bitmasks for 32-bit images are RGB888 
and RGB101010.

If we are dealing with a 24-bit image, then there is no Color Table 
present.

1
 void f_write_Bmpheader(u16 px,u16 py) {
2
//nur RGB565 + no padding: px%4==0
3
4
5
uint8_t  bmpFileHeader[14] = {'B','M', 0,0,0,0, 0,0, 0,0, 54+16,0,0,0};
6
uint8_t  bmpInfoHeader[40] = {40,0,0,0, 0,0,0,0, 0,0,0,0, 1,0, 16,0,3,0};
7
uint8_t  bmpcolorTable[16] = {0xf8,0,0,0,0xf8,0,0,0,0xf8,0,0,0,0x00,0,0,0};
8
9
10
11
  //bmpInfoHeader[16]=3;//compression bitfields
12
 // u32 rowSize = 4 * ((3*px + 3)/4);     
13
  u32 fileSize = 54 + 16 + py*px;
14
  
15
//u8  pad = rowSize-3*px;         //Number of zeros needed;
16
  
17
  bmpFileHeader[ 2] = (uint8_t)(fileSize      );
18
  bmpFileHeader[ 3] = (uint8_t)(fileSize >>  8);
19
  bmpFileHeader[ 4] = (uint8_t)(fileSize >> 16);
20
  bmpFileHeader[ 5] = (uint8_t)(fileSize >> 24);
21
22
  bmpInfoHeader[ 4] = (uint8_t)(       px      );
23
  bmpInfoHeader[ 5] = (uint8_t)(       px >>  8);
24
  bmpInfoHeader[ 6] = (uint8_t)(       px >> 16);
25
  bmpInfoHeader[ 7] = (uint8_t)(       px >> 24);
26
  bmpInfoHeader[ 8] = (uint8_t)(       py      );
27
  bmpInfoHeader[ 9] = (uint8_t)(       py >>  8);
28
  bmpInfoHeader[10] = (uint8_t)(       py >> 16);
29
  bmpInfoHeader[11] = (uint8_t)(       py >> 24);
30
31
   f_write(&Fil, bmpFileHeader, 14, &bw);  
32
  f_write(&Fil, bmpInfoHeader, 40, &bw);  
33
  f_write(&Fil, bmpcolorTable, 16, &bw);  
34
}

von leluno (Gast)


Lesenswert?

leluno schrieb:
> 0xf8

das 2. muss 0xfc sein

von W.S. (Gast)


Lesenswert?

Karl Heinz schrieb:
> Lass es gut sein.

Ach Karlheinz, da rackerst du dich redlich ab und kriegst als Antwort 
"Programmieren ist nun mal auch das Zusammensuchen von brauchbaren
Code-Schnipseln."

Bei sowas wird mir schlecht.

an den TO:
Ich habe ja gar nix dagegen, wenn jemand sich passable Algorithmen in 
Form von Codeschnipseln zulegt. Sowas macht sicherlich jeder.
ABER: Daraus besteht eben nicht das Programmieren. Laß dir das gesagt 
sein. Lerne logisches und analytisches Denken, wende es auf 
digitalelektronische Probleme an und entwickle daraus Lösungsstrategien 
- daraus besteht Programmieren.

W.S.

von Grundschüler (Gast)


Lesenswert?

W.S. schrieb:
> Bei sowas wird mir schlecht.

Dem ist nur zuzustimmen. Der vom TO vorgestellte code funktioniert nicht 
einmal. Richtig muss es lauten:
1
 void f_write_Bmpheader(int16_t px,int16_t py) {
2
//nur RGB565 + no padding: px%4==0
3
4
py=py*(-1);
5
uint8_t  bmpFileHeader[14] = {'B','M', 0,0,0,0, 0,0, 0,0, 54+12,0,0,0};
6
uint8_t  bmpInfoHeader[40] = {40,0,0,0, 0,0,0,0, 0,0,0,0, 1,0, 16,0,3,0,0,0,0,128,1};
7
uint8_t  bmpcolorTable[12] = {0,0xf8,0,0,224,7,0,0,31,0,0,0};
8
9
10
  //bmpInfoHeader[16]=3;//compression bitfields
11
 // u32 rowSize = 4 * ((3*px + 3)/4);     
12
  u32 fileSize = 54 +12 +  py*px*2;
13
  
14
//u8  pad = rowSize-3*px;         //Number of zeros needed;
15
  
16
  bmpFileHeader[ 2] = (uint8_t)(fileSize      );
17
  bmpFileHeader[ 3] = (uint8_t)(fileSize >>  8);
18
  bmpFileHeader[ 4] = (uint8_t)(fileSize >> 16);
19
  bmpFileHeader[ 5] = (uint8_t)(fileSize >> 24);
20
21
  bmpInfoHeader[ 4] = (uint8_t)(       px      );
22
  bmpInfoHeader[ 5] = (uint8_t)(       px >>  8);
23
  bmpInfoHeader[ 6] = (uint8_t)(       px >> 16);
24
  bmpInfoHeader[ 7] = (uint8_t)(       px >> 24);
25
  bmpInfoHeader[ 8] = (uint8_t)(       py      );
26
  bmpInfoHeader[ 9] = (uint8_t)(       py >>  8);
27
  bmpInfoHeader[10] = (uint8_t)(       py >> 16);
28
  bmpInfoHeader[11] = (uint8_t)(       py >> 24);
29
30
UINT bw;
31
   f_write(&Fil, bmpFileHeader, 14, &bw);  
32
  f_write(&Fil, bmpInfoHeader, 40, &bw);  
33
  f_write(&Fil, bmpcolorTable, 12, &bw);  
34
}

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.