首页 > 代码库 > BMP的图像处理

BMP的图像处理

近期碰到了一个问题将图片缩放:

进行了整理发现位图一些主要的结构能够进行整理,得出下面图表:

技术分享

进行图片缩放的时候会进行一些处理(最临近差值法):

详细的代码例如以下:

#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的图像处理