首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> 關於C語言

C 語言實現 BMP 彩色圖片轉二值圖像:文件格式解析、灰度化與閾值分割全流程

     編輯:關於C語言

C 語言實現 BMP 彩色圖片轉二值圖像:文件格式解析、灰度化與閾值分割全流程

BMP 是最簡單的位圖格式,無壓縮、結構固定,適合學習圖像處理基礎。本文從文件頭結構、內存對齊、灰度加權公式、全局閾值二值化、行填充處理五個維度,給出完整可編譯運行的 C 實現代碼。

一、BMP 文件結構

// 1. 文件頭 (14 字節)
#pragma pack(1)
typedef struct {
    unsigned char bfType[2];     // "BM"
    unsigned int  bfSize;        // 文件大小
    unsigned short bfReserved1;  // 0
    unsigned short bfReserved2;  // 0
    unsigned int  bfOffBits;     // 數據偏移
} BITMAPFILEHEADER;
#pragma pack()

// 2. 信息頭 (40 字節, BITMAPINFOHEADER)
#pragma pack(1)
typedef struct {
    unsigned int  biSize;          // 40
    int           biWidth;         // 寬(像素)
    int           biHeight;        // 高(像素),負值為正序
    unsigned short biPlanes;       // 1
    unsigned short biBitCount;     // 位深:1/4/8/16/24/32
    unsigned int  biCompression;   // 0=BI_RGB 無壓縮
    unsigned int  biSizeImage;     // 圖像數據大小
    int           biXPelsPerMeter; // 水平分辨率
    int           biYPelsPerMeter; // 垂直分辨率
    unsigned int  biClrUsed;       // 調色板顏色數
    unsigned int  biClrImportant;  // 重要顏色數
} BITMAPINFOHEADER;
#pragma pack()

// 3. 調色板 (僅索引色圖像)
typedef struct {
    unsigned char rgbBlue, rgbGreen, rgbRed, rgbReserved;
} RGBQUAD;

二、關鍵對齊規則

  1. 結構體對齊:#pragma pack(1) 強制 1 字節對齊,確保讀取文件頭字節偏移正確。
  2. 行數據 4 字節對齊:每行像素字節數 = ((width * bitCount/8) + 3) / 4 * 4。不足補 0。讀寫必須處理填充字節。

三、彩色轉灰度:加權平均法

人眼對綠最敏感,標準公式:Gray = 0.299*R + 0.587*G + 0.114*B。BMP 存儲順序為 BGR,代碼中對應調整。

四、灰度轉二值:全局固定閾值

閾值 T=190(經驗值),gray >= T → 1(白),else 0(黑)。進階方法:Otsu 自適應閾值、自適應局部閾值。

五、完整轉換代碼

int main() {
    FILE *fpSrc = fopen("1.bmp", "rb"), *fpDst = fopen("2.bmp", "wb");
    BITMAPFILEHEADER fh; BITMAPINFOHEADER fi; RGBQUAD rg[2];

    fread(&fh, sizeof(fh), 1, fpSrc);
    fread(&fi, sizeof(fi), 1, fpSrc);

    // 修改頭信息為 8 位索引色(二值)
    fi.biBitCount = 8;
    fi.biSizeImage = ((fi.biWidth + 3) / 4 * 4) * abs(fi.biHeight);
    fi.biClrUsed = 2; fi.biClrImportant = 0;
    fh.bfOffBits = sizeof(fh) + sizeof(fi) + 2*sizeof(RGBQUAD);
    fh.bfSize = fh.bfOffBits + fi.biSizeImage;

    // 調色板:索引 0=黑,1=白
    rg[0] = (RGBQUAD){0,0,0,0}; rg[1] = (RGBQUAD){255,255,255,0};

    fwrite(&fh, sizeof(fh), 1, fpDst);
    fwrite(&fi, sizeof(fi), 1, fpDst);
    fwrite(rg, sizeof(rg), 1, fpDst);

    // 行緩衝區
    int srcRowBytes = ((fi.biWidth * 3 + 3) / 4 * 4);
    int dstRowBytes = ((fi.biWidth + 3) / 4 * 4);
    unsigned char *srcRow = malloc(srcRowBytes);
    unsigned char *dstRow = malloc(dstRowBytes);

    for (int y = 0; y < abs(fi.biHeight); y++) {
        fread(srcRow, srcRowBytes, 1, fpSrc);
        for (int x = 0, k = 0; x < fi.biWidth; x++, k += 3) {
            int gray = (int)(0.114*srcRow[k] + 0.587*srcRow[k+1] + 0.299*srcRow[k+2]);
            dstRow[x] = (gray >= 190) ? 1 : 0;
        }
        fwrite(dstRow, dstRowBytes, 1, fpDst);
    }

    free(srcRow); free(dstRow);
    fclose(fpSrc); fclose(fpDst);
    printf("轉換成功!\n");
    return 0;
}

六、運行效果

原圖: 轉換後二值圖:

七、擴展方向

  • 支持 RLE 壓縮 BMP(biCompression=1/2)。
  • 實現 Otsu 自動閾值:計算直方圖最大類間方差。
  • 輸出 1 位深(每字節 8 像素)進一步壓縮存儲。
  • 集成 stb_image.h 支持 PNG/JPG 輸入。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved