sky__fall
poor coder
采纳率100%
2015-07-04 12:45 阅读 2.6k
已采纳

用C语言将bmp 8位灰度图的灰度值缩小16倍,调色板中数值由255行变成16行调

40

用C语言将bmp 8位灰度图的灰度值缩小16倍,由0-255变成0-16,调色板中数值由255行变成16行,同时调色板rgbBlue rgbRed rgbGreen数值范围由0-255变成0-1。我用c语言实现后,为什么图片不再是灰度图,有了其他颜色???

```#pragma once
#ifndef BMP_H_INCLUDED
#define BMP_H_INCLUDED
#include
#include
#include
#include
#include
#include
typedef unsigned short WORD;//2字节
typedef unsigned long DWORD;//4字节
typedef long LONG;
typedef unsigned char BYTE;
#define pi 3.1415926535

/* 位图文件头结构 14字节 */
typedef struct tagBITMAPFILEHEADER
{ // bmfh
WORD bfType;//位图文件类型,必须为BMP(0-1字节)
DWORD bfSize;//位图文件大小,以字节为单位(2-5字节)
WORD bfReserved1;//位图文件保留字,必须为0(6-7字节)
WORD bfReserved2;//位图文件保留字,必须为0(8-9字节)
DWORD bfOffBits;//位图数据的起始位置,以相对于位图文件头的偏移量表示(10-13字节)
}BITMAPFILEHEADER;

/* 位图信息头结构 40字节 */
typedef struct tagBITMAPINFOHEADER
{ // bmih
DWORD biSize; // 本结构占得字节数(14-17字节),结构长度 40B
LONG biWidth;//位图的宽度,以像素为单位(18-21字节)
LONG biHeight;//位图的高度,以像素为单位(22-25字节)
WORD biPlanes;//颜色面板值必须为1(26-27字节)
WORD biBitCount;// 表示颜色要用到的位数,颜色位值可以是1(双色),(28-29字节)
//4(16色),8(256色),16(64K色,高彩色),24(16M,真彩色),32(4096M增强型真彩色)中的一个
DWORD biCompression;// 压缩格式,必须是0(不压缩)(30-33字节)
//1(BI_RLE8压缩类型)或2(BI_RLE4压缩类型)或3(Bitfields,位域存放)
DWORD biSizeImage;// 位图的大小,位图占用字节数=biWidth(4的整倍数)*biHeight
LONG biXPelsPerMeter;// 水平分辨率,每米像素数(38-41字节)
LONG biYPelsPerMeter;// 垂直分辨率,每米像素数(42-45字节)
DWORD biClrUsed;// 位图实际使用的颜色表中的颜色数,(46-49字节)
DWORD biClrImportant;// 位图显示过程中重要的颜色数(50-53字节)
}BITMAPINFOHEADER;

/* 调色板 4字节 */
//颜色表中RGBQUAD结构数据的个数由biBitCount来确定
//颜色表中RGBQUAD结构数据的个数有biBitCount来确定:
// 当biBitCount=1,4,8时,分别有2,16,256个表项;????????????
// 当biBitCount=24时,没有颜色表项
typedef struct tagRGBQUAD
{ // rgbq
double rgbBlue;//蓝色的亮度(值得范围0-255)
double rgbGreen;//绿色的亮度
double rgbRed;//红色的亮度
double rgbReserved;//保留,必须为0
}RGBQUAD;

//位图数据
//位图数据记录了位图的每一个像素值,记录顺序是在扫描行内是从左到右,
//扫描行之间是从下到上。位图的一个像素值所占的字节数:
/* 当biBitCount=1时,8个像素占1个字节;
  当biBitCount=4时,2个像素占1个字节;
  当biBitCount=8时,1个像素占1个字节;
  当biBitCount=24时,1个像素占3个字节;*/
//Windows规定一个扫描行所占的字节数必须是4的倍数(即以long为单位),不足的以0填充,
/* 定义图像信息 */
typedef struct tagBITMAPINFO
{
BITMAPINFOHEADER bmiHeader;//位图信息头
RGBQUAD bmiColors[1];//颜色表
}BITMAPINFO;

/* 定义位图图像 /
typedef struct _Bitmap
{
BITMAPFILEHEADER bmfh;
BITMAPINFOHEADER bmih;
int width;
int height;
int bitCount; // 8 或者24
int imageSize; // 图像数据大小(imageSize=height*widthStep)字节
BYTE
imageData; //排列的图像数据,指向存储空间第一个单元的
int widthStep; //排列的图像行大小,不够4的整数倍的就补0
}Bitmap;

/**

  • 位图创建函数 创建一个Bitmap结构,并为图像数据分配空间 *
  • 使用方法:
  • Bitmap bmp=(Bitmap)malloc(sizeof(Bitmap));
  • ret=CreateBitmap(bmp,50,50,3);
    

    /
    int CreateBitmap(Bitmap
    bmp, int width, int height, int bitCount)
    {
    bmp->width = width;
    bmp->height = height;
    bmp->bmih.biWidth = width;
    bmp->bmih.biHeight = height;

    bmp->widthStep = (int)((width*bitCount + 31) / 32) * 4; //可是为什么这样计算????????????
    //eg:5*5的灰度图像,bitcount=8,则计算出来,widthstep=8,一行的像素个数不够4的倍数的补0
    bmp->imageSize = bmp->height*bmp->widthStep*sizeof(BYTE);//计算排列的图像大小sizeof(BYTE)=1

    if (bitCount == 8)
    {
    bmp->bitCount = 8;
    bmp->bmfh.bfType = 0x4d42; //注意是4d42 这个地方折磨我一下午啊
    bmp->bmfh.bfReserved1 = 0;
    bmp->bmfh.bfReserved2 = 0;
    bmp->bmih.biBitCount = 8;
    bmp->bmih.biSize = 40;
    bmp->bmih.biPlanes = 1;
    bmp->bmfh.bfSize = 54 + 256 * 4 + height*bmp->widthStep;
    bmp->bmfh.bfOffBits = 1078;
    bmp->bmih.biBitCount = 8;
    bmp->bmih.biCompression = 0;
    bmp->bmih.biSizeImage = bmp->imageSize;
    bmp->bmih.biClrUsed = 0;
    bmp->bmih.biClrImportant = 0;
    bmp->bmih.biXPelsPerMeter = 0;
    bmp->bmih.biYPelsPerMeter = 0;
    }
    else if (bitCount == 24)
    {
    bmp->bitCount = 24;
    bmp->bmfh.bfType = 0x4d42;
    bmp->bmih.biBitCount = 24;
    bmp->bmfh.bfReserved1 = 0;
    bmp->bmfh.bfReserved2 = 0;
    bmp->bmih.biSize = 40;
    bmp->bmih.biPlanes = 1;
    bmp->bmfh.bfSize = 54 + height*bmp->widthStep;
    bmp->bmfh.bfOffBits = 54;
    bmp->bmih.biBitCount = 24;
    bmp->bmih.biSizeImage = bmp->imageSize;
    bmp->bmih.biClrUsed = 0;
    bmp->bmih.biCompression = 0;
    bmp->bmih.biClrImportant = 0;
    bmp->bmih.biXPelsPerMeter = 0;
    bmp->bmih.biYPelsPerMeter = 0;
    }
    else
    {
    printf("Error(CreateBitmap): only supported 8 or 24 bits bitmap.\n");
    return -1;
    }

    bmp->imageData = (BYTE*)malloc(bmp->imageSize); //分配数据空间
    if (!(bmp->imageData))
    {
    printf("Error(CreateBitmap): can not allocate bitmap memory.\n");
    return -1;
    }
    return 0;
    }

/**

  • 位图指针释放函数 释放位图数据空间 *
  • 使用方法:
  • ReleaseBitmap(bmp); / void ReleaseBitmap(Bitmap bmp) { free(bmp->imageData); bmp->imageData = NULL; free(bmp); bmp = NULL; }

/**

  • 路径检查函数:是否为BMP文件,是否可读
  • 正确返回0,错误返回-1 *
  • 使用方法
  •     ret=CheckPath(path);
    

    */
    int CheckPath(char *path)
    {
    FILE *fd;
    int len = strlen(path) / sizeof(char);
    char ext[3];
    //check whether the path include the characters "bmp" at end
    strncpy(ext, &path[len - 3], 3);
    if (!(ext[0] == 'b' && ext[1] == 'm' && ext[2] == 'p')) {
    printf("Error(CheckPath): the extension of the file is not bmp.\n");
    return -1;
    }

    //check whether the file can be read or not
    fd = fopen(path, "r");
    if (!fd)
    {
    printf("Error(CheckPath): can not open the file.\n");
    return -1;
    }
    fclose(fd);

    return 0;
    }

void ShowImage(char * filepath)
{
char cmd[266];
strcpy(cmd, "start ");
strcat(cmd, filepath);
printf("%s\n", cmd);
system(cmd);
}
/**

  • 从文件中读取位图函数
  • 正确返回0,错误返回-1 *
  • 使用方法:
  • bmp=(Bitmap*)malloc(sizeof(Bitmap));
  • ret=ReadBitmap(path, bmp);
    

    /
    int ReadBitmap(char
    path, Bitmap* bmp)
    {
    int ret;
    FILE *fd;

    //检查路径是否可读
    ret = CheckPath(path);
    if (ret == -1)
    {
    printf("Error(ReadRGBBitmap): the path of the image is invalid.\n");
    return -1;
    }

    ShowImage(path);
    //打开文件
    fd = fopen(path, "rb");
    if (fd == 0)
    {
    printf("Error(ReadRGBBitmap): can not open the image.\n");
    return -1;
    }
    //读取文件信息头14字节
    fread(&(bmp->bmfh.bfType), sizeof(WORD), 1, fd);
    fread(&(bmp->bmfh.bfSize), sizeof(DWORD), 1, fd);
    fread(&(bmp->bmfh.bfReserved1), sizeof(WORD), 1, fd);
    fread(&(bmp->bmfh.bfReserved2), sizeof(WORD), 1, fd);
    fread(&(bmp->bmfh.bfOffBits), sizeof(DWORD), 1, fd);

    //读取位图信息头40字节
    fread(&(bmp->bmih.biSize), sizeof(DWORD), 1, fd);
    fread(&(bmp->bmih.biWidth), sizeof(DWORD), 1, fd);
    fread(&(bmp->bmih.biHeight), sizeof(DWORD), 1, fd);
    fread(&(bmp->bmih.biPlanes), sizeof(WORD), 1, fd);
    fread(&(bmp->bmih.biBitCount), sizeof(WORD), 1, fd);
    fread(&(bmp->bmih.biCompression), sizeof(DWORD), 1, fd);
    fread(&(bmp->bmih.biSizeImage), sizeof(DWORD), 1, fd);
    fread(&(bmp->bmih.biXPelsPerMeter), sizeof(DWORD), 1, fd);
    fread(&(bmp->bmih.biYPelsPerMeter), sizeof(DWORD), 1, fd);
    fread(&(bmp->bmih.biClrUsed), sizeof(DWORD), 1, fd);
    fread(&(bmp->bmih.biClrImportant), sizeof(DWORD), 1, fd);

    //创建位图结构
    ret = CreateBitmap(bmp, bmp->bmih.biWidth, bmp->bmih.biHeight, bmp->bmih.biBitCount);
    if (ret == -1)
    {
    printf("Error(CreateBitmap): can not CreateBitmap.\n");
    return -1;
    }
    //读取图像数据
    //由于4字节对齐格式
    fseek(fd, bmp->bmfh.bfOffBits, SEEK_SET); //定位到图像数据区
    ret = fread(bmp->imageData, bmp->imageSize, 1, fd);
    if (ret == 0)
    {
    if (feof(fd)) //if the file pointer point to the end of the file
    {
    }
    if (ferror(fd)) //if error happened while read the pixel data
    {
    printf("Error(ReadBitmap): can not read the pixel data.\n");
    fclose(fd);
    return -1;
    }
    }
    //关闭文件
    fclose(fd);
    return 0;
    }

/**

  • 保存位图到文件中去
  • 正确返回0,错误返回-1 *
  • 使用方法:
  • bmp=(Bitmap*)malloc(sizeof(Bitmap));
  • ret=SaveBitmap(path, bmp);
    

    /
    int SaveBitmap(char
    path, Bitmap* bmp, RGBQUAD *map = 0)
    {
    int ret = 0;
    FILE *fd;

    //检查路径是否正确
    int len = strlen(path) / sizeof(char);
    char ext[3];
    //check whether the path include the characters "bmp" at end
    strncpy(ext, &path[len - 3], 3);
    if (!(ext[0] == 'b' && ext[1] == 'm' && ext[2] == 'p'))
    {
    printf("Error(SaveBitmap): the extension of the file is not bmp.\n");
    return -1;
    }

    //打开文件
    fd = fopen(path, "wb");
    if (fd == 0)
    {
    printf("Error(SaveBitmap): can not open the image.\n");
    return -1;
    }

    //保存文件信息头 14字节
    fwrite(&(bmp->bmfh.bfType), sizeof(WORD), 1, fd);
    fwrite(&(bmp->bmfh.bfSize), sizeof(DWORD), 1, fd);
    fwrite(&(bmp->bmfh.bfReserved1), sizeof(WORD), 1, fd);
    fwrite(&(bmp->bmfh.bfReserved2), sizeof(WORD), 1, fd);
    fwrite(&(bmp->bmfh.bfOffBits), sizeof(DWORD), 1, fd);

    //保存位图信息头 40字节
    fwrite(&(bmp->bmih.biSize), sizeof(DWORD), 1, fd);
    fwrite(&(bmp->bmih.biWidth), sizeof(DWORD), 1, fd);
    fwrite(&(bmp->bmih.biHeight), sizeof(DWORD), 1, fd);
    fwrite(&(bmp->bmih.biPlanes), sizeof(WORD), 1, fd);
    fwrite(&(bmp->bmih.biBitCount), sizeof(WORD), 1, fd);
    fwrite(&(bmp->bmih.biCompression), sizeof(DWORD), 1, fd);
    fwrite(&(bmp->bmih.biSizeImage), sizeof(DWORD), 1, fd);
    fwrite(&(bmp->bmih.biXPelsPerMeter), sizeof(DWORD), 1, fd);
    fwrite(&(bmp->bmih.biYPelsPerMeter), sizeof(DWORD), 1, fd);
    fwrite(&(bmp->bmih.biClrUsed), sizeof(DWORD), 1, fd);
    fwrite(&(bmp->bmih.biClrImportant), sizeof(DWORD), 1, fd);

    //保存颜色表
    if (bmp->bmih.biBitCount == 8)
    {
    ret = fwrite(map, sizeof(RGBQUAD) , 256, fd);
    }
    if (ret == -1)
    {
    printf("Error(SaveBitmap): can not save Color Palette.\n");
    return -1;
    }

    //保存图像数据
    ret = fwrite(bmp->imageData, bmp->imageSize, 1, fd);
    if (ret != 1)
    {
    printf("Error(SaveBitmap): can not save the pixel data.\n");
    return -1;
    }

    //关闭文件
    fclose(fd);
    return 0;
    }

int gray2ind(Bitmap* src, RGBQUAD map, Bitmap dst)
{

int r ,m;
CreateBitmap(dst, src->width, src->height, 8);


//灰度数据缩放
for (int i = 0; i<dst->height; i++)
{
    for (int j = 0; j<dst->width; j++)
    {
        r = *(src->imageData + src->widthStep*(src->height - 1 - i) + j);
        m = r / 16;

        *(dst->imageData + dst->widthStep*(dst->height - 1 - i) + j) = m;


    }
}
for (int i = 0; i<16; ++i)    //调色板转换为0-1的小数
{
double gray = 0;

    gray = i*0.0667;
    (map + i)->rgbBlue = gray;
    (map + i)->rgbRed = gray;
    (map + i)->rgbGreen = gray;
    (map + i)->rgbReserved = 0;

}

return 0;

}

#endif // BMP_H_INCLUDED



  • 点赞
  • 写回答
  • 关注问题
  • 收藏
  • 复制链接分享

3条回答 默认 最新

  • 已采纳
    sky__fall poor coder 2015-07-04 12:59

    问题是,调色板 r g b三值相等啊,还有怎么会变三通道呢

    点赞 评论 复制链接分享
  • Evankaka Evankaka 2015-07-04 12:47

    是不是图片变成三通道的了。

    点赞 评论 复制链接分享
  • wangyaninglm shiter 2015-07-04 13:20

    可能是你把数据缩小后,合并移位了,可以把值打印出来看看,或者单步调试下看看

    点赞 评论 复制链接分享

相关推荐