2011-03-19 76 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,允許攻擊者控制程序,其中不少是遠程利用。)