我目前正在加载C中的位图文件。我是C的新手,我遇到了一个问题:我有一个文件指针,读取无符号字符到rgb像素的结构,(它叫做rgb但它按b,g,r和填充的顺序读取 - 这是位图格式文件的默认值)。我的文件是12x12像素,当它到达第9行时,它只在每个组件中放置值'204',就像图像是白色的(即所有组件= 255)。此前的所有组件均等于255。 编辑:我将枚举更改为图像状态返回的三个定义值(未加载,蓝色,不是蓝色)。 EDIT2 :我编辑了代码,但现在im等于0xffffffff且无法访问。 这是代码:
int CalaculateBlueness()
{
bih bih;
bfh bfh;
int counterblue = 0;
hsv hsv;
FILE *filePtr = fopen("C:\\Users\\mishe\\Desktop\\white.bmp", "rb");
//if the file doesn't exist in memory
if (filePtr == NULL)
{
return IMAGE_NOT_LOADED;
}
//read the bitmap file header
fread(&bfh, sizeof(bfh), 1, filePtr);
//verify that this is a bmp file by check bitmap id
if (bfh.bitmap_type[0] != 'B' || bfh.bitmap_type[1] != 'M')
{
fclose(filePtr);
return IMAGE_NOT_LOADED;
}
fclose(filePtr);
//ensure that the filePtr will point at the start of the image info header
filePtr = fopen("C:\\Users\\mishe\\Desktop\\white.bmp", "rb");
fseek(filePtr, 14, SEEK_CUR);
//read the bitmap info header
fread(&bih, sizeof(bih), 1, filePtr);
if (bih.bit_count!=24)
{
return ERROR_BPP;
}
//point the pointer file to the start of the raw data
//fseek(filePtr, bfh.file_size, SEEK_SET);
int size = bih.height * WIDTHBYTES(bih.width * 32);
unsigned char *im = calloc(1, size);
//put the raw bitmap pixel data in strcut rgb array
fread(&im, sizeof(size), 1, filePtr);
//convert each pixel to it's hue value and check if in the range of blue
for (size_t i = 0; i < bih.height; i++)
{
for (size_t j = 0; j < bih.width; j++)
{
hsv =rgbpixel_hue(im);
if (hsv.h>190 && hsv.h<250)
{
counterblue++;
}
fseek(im, 3, SEEK_CUR);
}
}
//check if more than 80% of the image is blue and return the defined state according to the result
if (counterblue > BLUE_THRESHOLD*(bih.height*bih.width))
{
return BLUE;
}
return NOT_BLUE;
}
答案 0 :(得分:2)
读取位图始终是一件困难的事情。
有一些要点需要考虑。
fread(&im[i][j].res, sizeof(unsigned char), 1, filePtr);
使用此行,您可以从文件中读取RGBQUAD
的保留字节。但是,该成员不在文件中。文件中的图像数据包含扫描线。见下文。
读取位图文件标题后,再次打开文件。但是,你没有关闭它。这可能是成功的,或者因为文件已经打开而失败。但是你不要贬低fopen
的返回值。无论如何,没有必要这样做,因为在读完BFH后,filepointer位于BITMAPINFOHEADER;你可以读它。你需要读它,否则你不会知道位图的尺寸。
来自MSDN文档:
建立的位图文件格式由BITMAPFILEHEADER结构和BITMAPINFOHEADER [...]结构组成。 RGBQUAD结构数组(也称为颜色表)遵循位图信息头结构。颜色表之后是颜色表中的第二个索引数组(实际的位图数据)。
对于24位/像素位图,没有颜色表。
所以序列现在是:
//read the bitmap file header
fread(&bfh, sizeof(bfh), 1, filePtr);
//read the bitmap info header
fread(&bih, sizeof(bih), 1, filePtr);
int bpp= bih.biBitCount;
if (bpp != 24) return 0; // error: must be 24 bpp/ 3 bytes per pixel
现在我们必须计算存储图像所需的内存量。图像由 width 行 width 像素组成。这些行称为扫描线。
由于某种原因,扫描线在4字节边界上进行了对齐。这意味着扫描线的最后字节可能未被使用。因此,从文件中读取位图数据的内存量是图像的高度,是图像扫描线数量的乘以:
// WIDTHBYTES takes # of bits in a scanline and rounds up to nearest word.
#define WIDTHBYTES(bits) (((bits) + 31) / 32 * 4)
int size= bih.biHeight * WIDTHBYTES(bih.biWidth*32));
unsigned char *im= malloc(size);
最后,您可以阅读数据。如果有一个颜色表,你应该用搜索跳过它,但由于没有颜色表,你现在可以读取数据:
fread(im, size, 1, filePtr);
现在,为了解决像素问题,您不能使用由图像宽度和高度控制的简单二维表示法......由于扫描线。您可以使用以下内容:
int scanlineSize= WIDTHBYTES(bih.biWidth*bih.biBitCount);
unsigned char *p, *scanline= im;
for (int i=0; i<bih.biHeight; i++)
{
p= scanline;
for (int j=0; j<bih.biWidth; j++)
{
g= *p++;
b= *p++;
r= *p++;
}
scanline += scanlineSize;
}
为了解决3字节像素(x,y)
,请使用:im[y*scanlineSize + x*3]
..除了我相信扫描线是反转的,因此像素位于im[(bih.biHeight-y)*scanlinesize + x*3]
。
答案 1 :(得分:0)
再次打开文件之前关闭filePtr
fclose(filePtr);
filePtr = fopen("C:\\Users\\mishe\\Desktop\\white.bmp", "rb");
和原始数据的偏移量是bfh.offset
//point the pointer file to the start of the raw data
fseek(filePtr, bfh.offset, SEEK_SET);