1. 程式人生 > >BMP的圖像處理

BMP的圖像處理

off 紅色 類型 compress 技術 位圖 gets 圖像處理 lib

近期碰到了一個問題將圖片縮放:

進行了整理發現位圖一些主要的結構能夠進行整理,得出下面圖表:

技術分享

進行圖片縮放的時候會進行一些處理(最臨近差值法):

詳細的代碼例如以下:

#include <stdio.h>
#include <string.h>
#include <math.h>
#include <windows.h>
#include <stdlib.h>

LONG        IWidth;      //原圖像的寬
LONG        IHeight;     //原圖像的高
LONG        biBitCount;    //每像素位數
LONG       INewWidth;   //新圖像的寬
LONG       INewHeight;  //新圖像的高
LONG       ILineByte;  //原圖像數據每行的字節數
LONG       INewLineByte;   //新圖像數據每行的字節數
float    zoomnumber=1;    //初始放大倍數賦值為1
unsigned char *pIBuf;   //原圖像像素指針
unsigned char *pINewBuf;//新圖像像素指針


int ReadBmp(const char* bmpName)//以二進制方式讀入指定的圖像文件
{
    FILE *fp=fopen(bmpName,"rb");
    if(fp==0)
    { 
        printf("打開文件失敗\n");
        return 0;
    }

    fseek(fp,sizeof(BITMAPFILEHEADER),0);//跳過位圖文件頭
    BITMAPINFOHEADER head;//定義位圖信息頭結構體變量。存放在變量head中
    fread(&head,sizeof(BITMAPINFOHEADER),1,fp);//獲取圖像的高、寬和每像素所占的位數,接收地址head。單個元素大小文件頭大小。元素個數1個,輸入流fp
    IWidth = head.biWidth;
    IHeight = head.biHeight;
    biBitCount = head.biBitCount;
    ILineByte = (IWidth *biBitCount/8+3)/4*4;//計算原圖像每行字節數,/4*4以保證是4的倍數
    pIBuf = new unsigned char [ILineByte *IHeight];//定義一個矩陣用以存放原圖像像素信息。pIBuf指向首地址
    fread(pIBuf,1,ILineByte *IHeight,fp);//獲取源文件像素信息。接收地址pIBuf,單個元素大小1字節,元素個數每行字節數*行數,輸入流fp
    return 1;//成功返回1
}

int SaveBmp(const char* bmpName,unsigned char *imgBuf,int width,int height,int biBitCount)//圖像存儲
{
    if(!imgBuf)//假設沒有像素數據傳入,則函數返回
    return 0;
    INewLineByte = (width * biBitCount/8+3)/4*4;//計算新圖像每行字節數。/4*4以保證是4的倍數
    FILE *fp = fopen(bmpName,"wb");//以二進制方式寫文件
    if(fp == 0) 
        return 0;
    BITMAPFILEHEADER fileHead;//申請位圖文件頭結構變量,填寫文件頭信息
    fileHead.bfType= 0x4d42;//bmp類型
    fileHead.bfSize = sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER)+ INewLineByte *height;//位圖文件大小
    fileHead.bfReserved1 = 0;//保留字
    fileHead.bfReserved2 = 0;//保留字
    fileHead.bfOffBits = 54;//文件頭到實際的位圖數據的偏移字節數。前三個部分字節數之和
    fwrite(&fileHead,sizeof(BITMAPFILEHEADER),1,fp);//將新圖像數據寫入文件,獲取數據地址fileHead,單個元素大小文件頭大小,元素個數1個,輸入流fp
    BITMAPINFOHEADER head;//定義位圖信息頭結構變量,存放在變量head中
    head.biBitCount = biBitCount;//24位
    head.biClrImportant = 0;//位圖顯示過程中重要的顏色數,覺得全部的顏色都是重要的
    head.biClrUsed = 0;//位圖實際用到的顏色數為2的biBitCount次冪
    head.biCompression = 0;//位圖壓縮類型
    head.biHeight = height;//新圖像高
    head.biPlanes =1;//目標設備的級別
    head.biSize = 40;//本結構體長度
    head.biSizeImage = ILineByte *height;//實際的位圖數據占用的字節數
    head.biWidth = width;//新圖像寬
    head.biXPelsPerMeter = 0;//指定目標設備的水平分辨率
    head.biYPelsPerMeter = 0;//指定目標設備的垂直分辨率
    fwrite(&head,sizeof(BITMAPINFOHEADER),1,fp);//寫入信息頭
    fwrite(imgBuf,height * INewLineByte,1,fp);//寫入像素數據
    fclose(fp);//關閉文件
    return 1;
}

int Zoom(const char* readPath )//圖像縮放
{
    char address[50];
    ReadBmp(readPath);//讀取圖像
    INewWidth = (int) ((IWidth * zoomnumber) +0.5);//新圖像的寬度。此處加0.5是因為強制轉換時不四舍五入,而是直接截去小數部分
    INewHeight = (int) (IHeight * zoomnumber +0.5);//新圖像的高帶。此處加0.5是因為強制轉換時不四舍五入,而是直接截去小數部分
    ILineByte =(IWidth*biBitCount/8+3)/4*4;//原圖像每行字節數
    INewLineByte = (INewWidth * biBitCount/8+3)/4*4;//新圖像每行字節數
    pINewBuf = new unsigned char [INewLineByte * INewHeight];//定義一個矩陣用以存放新圖像像素信息,pIBuf指向首地址

    LONG i;       //循環變量(像素在新圖像中的坐標)
    LONG j;
    LONG k;       //色彩選擇,k=0時為藍色,k=1時為綠色,k=2時為紅色
    LONG i0;      //像素在原圖像中的坐標
    LONG j0;


    if(biBitCount == 24)
    {
        for(i = 0;i < INewHeight;i++)
        {
            for(j = 0; j < INewWidth;j++)
                for(k=0;k<3;k++)  
                {
                    i0 = (int)(i/zoomnumber+0.5); 
                    j0 = (int)(j/zoomnumber+0.5);
                    if((j0 >= 0) && (j0 < IWidth) && (i0 >=0)&& (i0 <IHeight))
                    {
                        *(pINewBuf+i*INewLineByte+j*3+k) = *(pIBuf+i0*ILineByte+j0*3+k);//最鄰近插值
                    }
                    else
                    {
                        *(pINewBuf+i*INewLineByte+j*3+k)=255;
                    }
                }
        }
    }
    printf("輸入bmp圖像縮放後需保存的路徑名稱和後綴:");
    gets(address); 
    SaveBmp(address,pINewBuf,INewWidth,INewHeight,biBitCount);//調用SaveBmp函數保存圖像
    delete []pINewBuf;//清除指針
    return 1;
}

void main()
{
    char filepath[256];     
    printf("請輸入bmp圖片路徑,名稱和後綴:(如E:\1.bmp)");
    scanf("%s",filepath); 
    ReadBmp(filepath);//調用ReadBmp函數
    printf("請輸入所要縮放的倍數(小於1為縮小,大於1為放大):");
    scanf("%f",&zoomnumber);getchar(); 
    Zoom(filepath);  	
}

驗證下面圖片效果還能夠。



BMP的圖像處理