Pixeldaten aus bitmap auslesen

OP #7866577
Lesenswert?

Hallo, ich möchte gerne in C die PixelDaten aus einer Bitmap auslesen. Hier habe ich aber anscheinend noch Probleme mit der Position der Daten.

1
Read file DREIECK.BMP
2
FileHeader.file_type (BM). 
3
FileHeader.file_size (0). 
4
FileHeader.offset_data (2621440). 
5
FileHeader.size (40). 
6
FileHeader.width (64). 
7
FileHeader.height (64). 
8
FileHeader.planes (1). 
9
FileHeader.bit_count (24). 
10
FileHeader.compression (0). 
11
FileHeader.size_image (12288). 
12
FileHeader.x_pixels_per_meter(0). 
13
FileHeader.y_pixels_per_meter (0). 
14
FileHeader.colors_used (0). 
15
FileHeader.colors_important (0). 
16
DATA_OFFSET 54
17
DATA_OFFSET read 2621440
18
data parsed

Ich habe gedacht, dass zum schluss das ein oder andere mal wenigstens eine ausgabe kommt. Aber wie man sieht kommt da ncihts. auch wenn ich für das offset i fseek die 2621440 nehme, bekomme ich kein printf.

Angehängte Dateien:
Gast #7866582
Lesenswert?

Hallo Chandler,

du möchtest den Header der BMP-Datei in Structs abbilden. Das geht schief, da der Compiler ein sogenanntes Alignment anwenden darf. Es werden also ggf. Füllbytes in die Struktur eingefügt. AFAIK kann der Compiler sogar die Reihenfolge der Elemente ändern (sie stehen dann anders im Speicher als in der Struktur-Deklaration). Leider kenne ich die (Compiler-) Einstellungen bzw. pragmas nicht, um das Alignment zu umgehen. Das werden andere hier jedoch sicher bald ergänzen. WIMRE ist es allerdings besser, die Strukt-Elemente einzeln zu füllen.

Dast Du die Datei mal im Hex-Editor angeschaut? Dann siehst Du schnell, ob der Header Deinen Erwartungen entspricht und wie die Daten dann in der Struktur abgelegt werden.

ciao

Marci

OP #7866603
Lesenswert?

Marci W. schrieb:

Dast Du die Datei mal im Hex-Editor angeschaut? Dann siehst Du schnell, ob der Header Deinen Erwartungen entspricht und wie die Daten dann in der Struktur abgelegt werden.

Das war ein guter tipp. Habe es "jetzt" gemacht und gesehen, dass es nicht wirklich passt. file_type = "BM" und einige andere Werte (im infoHeader) wurde mir immer valide ausgegeben. Bin daher ausgegangen, dass es überallpasst. aber Anscheinend passt es doch nicht überall.

1
fread(&bmpData_s.fileHeader_s.file_type, sizeof(bmpData_s.fileHeader_s.file_type), 1, imageFile);
2
fread(&bmpData_s.fileHeader_s.file_size, sizeof(bmpData_s.fileHeader_s.file_size), 1, imageFile);
3
fread(&bmpData_s.fileHeader_s.reserved1, sizeof(bmpData_s.fileHeader_s.reserved1), 1, imageFile);
4
fread(&bmpData_s.fileHeader_s.reserved2, sizeof(bmpData_s.fileHeader_s.reserved2), 1, imageFile);
5
fread(&bmpData_s.fileHeader_s.offset_data, sizeof(bmpData_s.fileHeader_s.offset_data), 1, imageFile);

damit bekomme ich die Ausgabe

1
Read file DREIECK.BMP
2
FileHeader.file_type (BM). 
3
FileHeader.file_size (12342). 
4
FileHeader.offset_data (54).

sieht auf jedenfall schon einmal anders aus.

Gast #7866946
Lesenswert?

Harald K. schrieb:

In erster Linie ist es mühsamer.

Das stimmt allerdings! Man muss jedoch aufpassen, da bei der Verwendung von "packed" je nach Prozessorarchitektur ein Pointer Misalignment auftreten kann. So gesehen ist der TO mit den einzelnen reads auf der sicheren Seite und plattformunabhängig (OK, es könnte noch Probleme wg. Endianess etc. geben) ;-)

ciao

Marci

OP #7867106
Lesenswert?

Hallo, ganz möchte es doch noch nicht so hinhauen. beim Auslesen der Daten kommt doch noch irgendwas durcheinander.

Damit ich mich einfacher tue, habe ich ein neues Bild erstellt (2x3 Pixel)

Zum schluss möchte ich mir dann mit printf das bild in der Console nachstellen

1
    uint8_t colorData_au8[3] = {0};
2
    for(uint8_t x=0; x<2-1; x++)
3
    {
4
        for(uint8_t y=0; y<3-1; y++)
5
        {
6
            fread(&colorData_au8, sizeof(colorData_au8), 1, imageFile);
7
            bmpData_s.colorData_sa[x][y].red = colorData_au8[2];
8
            bmpData_s.colorData_sa[x][y].green = colorData_au8[1];
9
            bmpData_s.colorData_sa[x][y].blue = colorData_au8[0];
10
        }
11
    }
12

13
    for(uint8_t x=0; x<3-1; x++)
14
    {
15
        for(uint8_t y=0; y<2-1; y++)
16
        {
17
            if ((bmpData_s.colorData_sa[x][y].red > bmpData_s.colorData_sa[x][y].green) && (bmpData_s.colorData_sa[x][y].red > bmpData_s.colorData_sa[x][y].blue))
18
            {
19
                printf("R ");
20
            }
21
            else if ((bmpData_s.colorData_sa[x][y].green > bmpData_s.colorData_sa[x][y].red) && (bmpData_s.colorData_sa[x][y].green > bmpData_s.colorData_sa[x][y].blue))
22
            {
23
                printf("G ");
24
            }
25
            else if ((bmpData_s.colorData_sa[x][y].blue > bmpData_s.colorData_sa[x][y].red) && (bmpData_s.colorData_sa[x][y].blue > bmpData_s.colorData_sa[x][y].green))
26
            {
27
                printf("B ");
28
            }
29
            else if ((bmpData_s.colorData_sa[x][y].blue == 0) && (bmpData_s.colorData_sa[x][y].red == 0) && (bmpData_s.colorData_sa[x][y].green == 0))
30
            {
31
                printf("p ");
32
            }
33
            else
34
            {
35
                printf(". ");
36
            }
37
        }
38
        printf("\n");
39
    }

Die Ausgabe ist allerdings

1
G 
2
p

also das G würde ich verstehen. Das ist unten links. p wäre schräg davon. auch wird mir nur ein Wert ausgegeben, obwohl die for-schleife eigentlich über alles drüber gehen sollte.

Angehängte Dateien:
OP #7867120
Lesenswert?

Rolf M. schrieb:

Wozu soll denn das -1 sein? Ist es gewollt, dass die äußere Schleife nur einmal durchläuft und die innere zweimal?

nein, das war ein Fehler

1
for(uint8_t x=0; x<3; x++)
2
{
3
    for(uint8_t y=0; y<2; y++)
4
    {
5
        fread(&colorData_au8, sizeof(colorData_au8), 1, imageFile);
6
        bmpData_s.colorData_sa[x][y].red = colorData_au8[2];
7
        bmpData_s.colorData_sa[x][y].green = colorData_au8[1];
8
        bmpData_s.colorData_sa[x][y].blue = colorData_au8[0];
9
        printf("r: %u    g: %u    b: %u\n", colorData_au8[2], colorData_au8[1], colorData_au8[0]);                                                                         
10
    }
11
    printf("\n");
12
}

damit lasse ich mir jeden pixel ausgeben.

1
r: 34    g: 177    b: 76
2
r: 237    g: 28    b: 36
3

4
r: 76    g: 0    b: 0
5
r: 0    g: 34    b: 177
6

7
r: 0    g: 0    b: 0
8
r: 85    g: 91    b: 0

die ersten zwei Pixel passen (habe die Farbwerte mit GIMP überprüft) Aber ab dann passt es irgendwie gar nicht mehr.

OP #7867135
Lesenswert?

Habe mir das Bild noch einmal im Hexeditor angesehen. Es scheint so zu sein, dass drei Bytes Farbe kommen (reihenfolge Blau, Grün, Rot), dann noch einmal drei Bytes Farbe (reihenfolge Blau, Grün, Rot) und dann zwei Bytes 0x00 da sind.

Compression = 0 (BI_RGB): Bilddaten sind unkomprimiert, bedeutet "Jede Bildzeile ist durch rechtsseitiges Auffüllen mit Nullen auf ein ganzzahliges Vielfaches von 4 Bytes ausgerichtet." (Wikipedia)

Heißt, da ich 6 Bytes Farbdaten habe (2 pixel x 3Bytes/Pixel), bleiben 2 Bytes übrig um auf 8 Bytes (vielfaches von 4 Bytes) zu kommen.

1
for(uint8_t x=0; x<3; x++)
2
{
3
    for(uint8_t y=0; y<2; y++)
4
    {
5
        fread(&colorData_au8, sizeof(colorData_au8), 1, imageFile);
6
        bmpData_s.colorData_sa[x][y].red = colorData_au8[2];
7
        bmpData_s.colorData_sa[x][y].green = colorData_au8[1];
8
        bmpData_s.colorData_sa[x][y].blue = colorData_au8[0];
9
        printf("r: %u    g: %u    b: %u\n", colorData_au8[2], colorData_au8[1], colorData_au8[0]);                                                                         
10
    }
11
    fseek(imageFile, 2, SEEK_CUR);
12
    printf("\n");
13
}

Das erklärt meine Falschen Zahlwerte.

Muss ich dann jetzt mal weiterschauen, wie ich das machen kann, wenn ich die größe des Bildes nicht genau weiß.

#7868091
Lesenswert?

Der Threadstarter hat mit keinem Wort verraten, /worauf/ sein Programm laufen soll. Die #includes in seinem Sourcefile lassen so etwas wie Linux vermuten, jedenfalls nicht den Betrieb auf einem µC.

Also könnte man auch eine der zig bestehenden Libraries verwenden, um Bilddateien zu lesen, die würden auch die vielen Möglichkeiten unterschiedlichster BMP-Formate erschlagen. Denn BMP ist letztlich nur ein Containerformat, da kann alles mögliche drinstecken.

Und mit so einer Library wie z.B. https://libgd.github.io/ kann man dann auch gleich ganz andere Dateiformate verarbeiten.

Wenn das ganze aber eine Übung im Selbstverarbeiten komplexer Dateiformate sein soll: Header lesen und interpretieren. Dazu die Dokumentation genau ansehen.

https://learn.microsoft.com/en-us/windows/win32/gdi/bitmaps

(Firma: 1984now) #7869204
Lesenswert?

Chandler B. schrieb:

Muss ich dann jetzt mal weiterschauen, wie ich das machen kann, wenn ich die größe des Bildes nicht genau weiß.

Witzig. Genau dafür, dass man das halt sicher weiß, gibt's ja den Header. Der beschreibt, wie die Nutzdaten des Bildes zu interpretieren sind.

Übrigens: biCompression == BI_RGB kennt auch noch ziemlich viele Unterformate. Du hast nur eins davon (RGB24) implementiert. Das ist zwar recht verbreitet, aber es gibt auch andere, die sehr weit verbreitet sind. Sehr häufig wird z.B. RGB32 benutzt, weil es einen Alpha-Kanal besitzt. Auch recht häufig anzutreffen sind Monochrom- (AKA: "Schwarzweiß"-) Bitmaps.

Und nicht zuletzt: auch eins der "alten" indizierten Formate ist noch weit verbreitet: die Variante mit 8Bit-Palettenindizes. Das wird sowohl für Graustufenbilder als auch für (relativ) platzsparende farbige Icons verwendet.

Dazu kommen noch die (allerdings sehr viel seltener verwendeten) Formate mit Bitmasken und wie z.B. RGB565, RGB555, ARGB1555 und RGB332 mit 16 bzw. 8 Bit pro Pixel. Wenn überhaupt heute noch relevant, dann am ehesten im Bereich µC-Programmierung von einem Windows-PC aus.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren