[英]Converting 1-bit bmp file to array in C/C++
我希望將一個可變高度/寬度的1位bmp文件轉換為一個值為0或1的簡單二維數組。我沒有任何代碼和大多數庫中的圖像編輯經驗。發現涉及比我需要更高的比特深度。 對此有任何幫助都會很棒。
這是讀取單色.bmp文件的代碼
(見DMB的回答下面一個小的修復奇數大小.bmps)
#include <stdio.h>
#include <string.h>
#include <malloc.h>
unsigned char *read_bmp(char *fname,int* _w, int* _h)
{
unsigned char head[54];
FILE *f = fopen(fname,"rb");
// BMP header is 54 bytes
fread(head, 1, 54, f);
int w = head[18] + ( ((int)head[19]) << 8) + ( ((int)head[20]) << 16) + ( ((int)head[21]) << 24);
int h = head[22] + ( ((int)head[23]) << 8) + ( ((int)head[24]) << 16) + ( ((int)head[25]) << 24);
// lines are aligned on 4-byte boundary
int lineSize = (w / 8 + (w / 8) % 4);
int fileSize = lineSize * h;
unsigned char *img = malloc(w * h), *data = malloc(fileSize);
// skip the header
fseek(f,54,SEEK_SET);
// skip palette - two rgb quads, 8 bytes
fseek(f, 8, SEEK_CUR);
// read data
fread(data,1,fileSize,f);
// decode bits
int i, j, k, rev_j;
for(j = 0, rev_j = h - 1; j < h ; j++, rev_j--) {
for(i = 0 ; i < w / 8; i++) {
int fpos = j * lineSize + i, pos = rev_j * w + i * 8;
for(k = 0 ; k < 8 ; k++)
img[pos + (7 - k)] = (data[fpos] >> k ) & 1;
}
}
free(data);
*_w = w; *_h = h;
return img;
}
int main()
{
int w, h, i, j;
unsigned char* img = read_bmp("test1.bmp", &w, &h);
for(j = 0 ; j < h ; j++)
{
for(i = 0 ; i < w ; i++)
printf("%c ", img[j * w + i] ? '0' : '1' );
printf("\n");
}
return 0;
}
它是普通的C,所以沒有指針轉換 - 在C ++中使用它時要小心。
最大的問題是.bmp文件中的行是4字節對齊的,這對於單比特圖像很重要。 因此我們將線尺寸計算為“width / 8 +(width / 8)%4”。 每個字節包含8個像素,而不是一個,因此我們使用基於k的循環。
我希望其他代碼是顯而易見的 - 很多人都被告知.bmp標題和pallete數據(我們跳過的8個字節)。
預期產量:
0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0
0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0
0 0 0 0 0 0 1 1 1 1 0 0 1 1 0 0
0 0 0 0 0 0 1 1 1 1 0 0 0 0 0 0
0 0 0 0 0 0 1 1 1 1 0 0 0 0 0 0
0 0 0 1 0 0 1 1 1 1 0 0 0 0 0 0
0 0 0 0 0 0 1 1 1 1 0 0 0 0 0 0
0 0 0 0 0 0 1 1 1 1 0 0 0 0 0 0
0 0 0 0 0 0 1 1 1 1 0 0 0 0 0 0
0 0 0 0 0 0 1 1 1 1 0 0 1 0 0 0
0 0 0 0 0 0 1 1 1 1 0 0 0 0 0 0
0 0 0 0 0 1 1 1 1 1 0 0 0 0 0 0
0 0 0 0 0 1 1 1 1 1 0 0 0 0 1 0
0 0 0 0 0 1 1 1 1 1 0 0 0 0 0 0
0 0 0 1 0 1 1 1 1 1 0 0 0 0 0 0
0 0 0 0 0 1 1 1 1 1 0 0 0 0 0 0
我在20x20測試圖像上嘗試了Viktor Lapyov的解決方案:
但是使用他的代碼,我得到了這個輸出(稍微重新格式化,但你可以看到問題):
最后4個像素未被讀取。 問題出在這里。 (忽略行中的最后一個部分字節。)
// decode bits
int i, j, k, rev_j;
for(j = 0, rev_j = h - 1; j < h ; j++, rev_j--) {
for(i = 0 ; i < w / 8; i++) {
int fpos = j * lineSize + i, pos = rev_j * w + i * 8;
for(k = 0 ; k < 8 ; k++)
img[pos + (7 - k)] = (data[fpos] >> k ) & 1;
}
}
我重寫了內部循環,如下所示:
// decode bits
int i, byte_ctr, j, rev_j;
for(j = 0, rev_j = h - 1; j < h ; j++, rev_j--) {
for( i = 0; i < w; i++) {
byte_ctr = i / 8;
unsigned char data_byte = data[j * lineSize + byte_ctr];
int pos = rev_j * w + i;
unsigned char mask = 0x80 >> i % 8;
img[pos] = (data_byte & mask ) ? 1 : 0;
}
}
一切都很好:
以下c代碼適用於任何大小的單色位圖。 我假設你的位圖在緩沖區中,高度和寬度從文件初始化。 所以
// allocate mem for global buffer
if (!(img = malloc(h * w)) )
return(0);
int i = 0, k, j, scanline;
// calc the scanline. Monochrome images are
// padded with 0 at every line end. This
// makes them divisible by 4.
scanline = ( w + (w % 8) ) >> 3;
// account for the paddings
if (scanline % 4)
scanline += (4 - scanline % 4);
// loop and set the img values
for (i = 0, k = h - 1; i < h; i++)
for (j = 0; j < w; j++) {
img[j+i*w] = (buffer[(j>>3)+k*scanline])
& (0x80 >> (j % 8));
}
希望這可以幫助。 將它轉換為2D現在是一個微不足道的事情:但如果你迷失在這里是將1D數組轉換為2D的數學假設r&c是行和列,w是寬度然后:。 c + r * w = r,c
如果你有進一步的評論打擊我,我出去了!
讓我們想一下a1x7單色位圖,即這是一個7像素寬的直線位圖。 將此圖像存儲在Windows操作系統上; 由於7不能被4整除,因此它將在其中填充額外的3個字節。
因此BITMAPINFOHEADER結構的biSizeImage將顯示總共4個字節。 盡管如此,biHeight和biWidth成員將正確地指出真正的位圖尺寸。
上面的代碼將失敗,因為7/8 = 0(通過與所有c編譯器一樣四舍五入)。 因此循環“i”將不會執行,因此將“k”。
這意味着向量“img”現在包含與“數據”中包含的像素不對應的垃圾值,即結果不正確。
如果它不滿足基本情況,那么通過歸納推理,那么對於一般情況來說它很可能不會有很多好處。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.