指针文件在读取原始位图数据的中间随机改变值

时间:2017-12-12 08:23:05

标签: c file bitmap

我目前正在加载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;

}

2 个答案:

答案 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);