2011-03-19 75 views
3

我试图从24位BMP文件中获取RGB值。我使用的图像是一个很小的图像,全部是红色的,所以所有的像素BGR配置应该是B:0 G:0 R:255。我这样做:从位图中读取BGR颜色C

int main(int argc, char **argv) 
{ 
    principal(); 
    return 0; 
} 

typedef struct { 
    unsigned char blue; 
    unsigned char green; 
    unsigned char red; 
} rgb; 

typedef struct { 
    int ancho, alto; 
    rgb *pixeles[MAX_COORD][MAX_COORD]; 
} tBitmapData; 

void principal() 
{ 

    FILE *fichero; 
    tBitmapData *bmpdata = (tBitmapData *) malloc(sizeof(tBitmapData)); 
    rgb *pixel; 
    int i, j, num_bytes; 
    unsigned char *buffer_imag; 
    char nombre[] = "imagen.bmp"; 
    fichero = fopen(nombre, "r"); 
    if (fichero == NULL) 
      puts("No encontrado\n"); 
    else { 
      fseek(fichero, 18, SEEK_SET); 
      fread(&(bmpdata->ancho), sizeof((bmpdata->ancho)), 4, fichero); 
      printf("Ancho: %d\n", bmpdata->ancho); 
      fseek(fichero, 22, SEEK_SET); 
      fread(&(bmpdata->alto), sizeof((bmpdata->alto)), 4, fichero); 
      printf("Alto: %d\n", bmpdata->alto); 
    } 

    num_bytes = (bmpdata->alto * bmpdata->ancho * 3); 
    fseek(fichero, 54, SEEK_SET); 
    for (j = 0; j < bmpdata->alto; j++) { 
      printf("R G B Fila %d\n", j + 1); 
      for (i = 0; i < bmpdata->ancho; i++) { 
        pixel = 
         (rgb *) malloc(sizeof(rgb) * bmpdata->alto * 
             bmpdata->ancho * 3); 
        fread(pixel, 1, sizeof(rgb), fichero); 
        printf("Pixel %d: B: %3d G: %d R: %d \n", i + 1, 
          pixel->blue, pixel->green, pixel->red); 
      } 
    } 
    fclose(fichero); 
} 

的问题是,当我打印出来,第一个像素都很好,B:0 G:0 R:255,但随后他们开始改变B:0 G:255 R:0,然后B:255 G:0 R:0。如果宽度是10像素,则每10个像素发生一次更改。

+1

这可能不是你的问题的原因,但你意识到你分配*三次*必要的内存来保存*整个图像*,*每像素*,并泄漏所有它?如果你要单独为每个像素“fread”,你可以使用在堆栈上分配的'rgb'结构。 – zwol 2011-03-19 00:36:44

+1

此外,如果您可以上传显示问题的图像文件,我们可以在其中找到某个位置,这将会很有帮助。 – zwol 2011-03-19 00:37:37

+0

简单的解释是位图的像素格式是32bpp。你不检查它,这是一个错误。你也忽略了跨步,对24bpp格式致命。不要自己编写这些代码,知道如何以任意格式读取图像文件的库很多。 – 2011-03-19 01:01:48

回答

5

BMP file format中,每行像素数据可以被填充以便四舍五入为4个字节的倍数。

如果您有10个24位像素,即30个字节,然后是2个字节的填充。您的代码不会跳过填充。

2

我觉得你fread(3)电话是错误的:

 fread(&(bmpdata->ancho), sizeof((bmpdata->ancho)), 4, fichero); 

这要求阅读4*sizeof((bmpdata->ancho))字节为int。我假设sizeof((bmpdata->ancho))返回4,所以我认为你正在用这两个调用在无关的内存上涂写。将4更改为1 - 您只能读取一个项目。

您从不使用num_bytes;删除它。未使用的代码使得思考使用的代码更加困难。 :)

你分配三倍多的内存,您需要:

   pixel = 
        (rgb *) malloc(sizeof(rgb) * bmpdata->alto * 
            bmpdata->ancho * 3); 

3看起来是想在你的rgb结构考虑每个红,绿,蓝,但sizeof(rgb)已经知道结构的正确尺寸。 (这可能是4字节,为便于32位CPU对齐,或者它可能是12字节,再次用于对齐(每个char本身4字节边界),或者甚至可能是字节,它们确实享有64位系统与8字节边界对齐数据的工作)

而最后一件事,我注意到:

   fread(pixel, 1, sizeof(rgb), fichero); 

因为C编译器允许插入孔进入的结构,你不能假设磁盘上的格式匹配您的内存结构定义。您需要使用GNU C extension __packed__属性,或者需要从为使用bmp格式设计的使用库或结构中读取数据。如果这对你来说是一个有趣的项目,那么一定要尝试__packed__路线:如果它工作正常,如果它不起作用,希望你可以了解为什么不行,并重新编写代码以手动加载结构的每个元素。如果您只是想获得可以正确解析位图的内容,那么您可能需要尝试查找一些预先编写的库,这些库已经可以正确解析图像。

(是的,这是非常重要获得图像解析正确; CVE has a list of malformed image exploits,允许攻击者控制程序,其中不少是远程利用。)