实验四—bmp文件


目录

实验目的

实验内容

BMP文件的读写

注意以下几点:

请编程实现:

实验要求

注意事项

实验效果图(仅供参考)

实验目的

1.掌握BMP文件的读写方法;

2.掌握数组的使用方法;

3.数组的遍历和数组元素的操作;

4.动态分配一维和二维数组

实验内容

后面的实验需要从图片中读入数据,进行处理。我们使用格式比较简单的BMP图像文件。我们先仔细学习一下BMP文件格式的定义和容易出错的地方,下面是关于BMP文件的说明。

BMP文件的读写

熟悉BMP文件的文件格式,练习文件的读写操作。

BMP文件格式是Windows操作系统推荐和支持的标准图像文件格式,是一种将内存或显示器的图像数据不经过压缩而直接按位存盘的文件格式,故称位图(bitmap),其扩展名为BMP。BMP图像通常有4个部分组成:文件头、信息头、颜色表、数据。

第一部分为位图文件头BITMAPFILEHEADER。位图文件头结构长度固定为14个字节,包含文件的类型、大小、位图文件保留字、位图数据距文件头的偏移量。其中WORD为无符号16位整数(unsigned short,2字节),DWORD为无符号32位整数(unsigned long,4字节)。这两个都是为了代码的简洁做的typedef定义。具体结构体定义如下: 

//位图文件头
typedef struct tagBITMAPFILEHEADER {
	WORD     bfType;  //位图文件的类型,必须为0x4d42 即BM两个字符的ASCII码,
                      //注意这里的little endian存储方式,’B’(42)在低位,‘M’(4d)在高位,
                      //因此第一个字节是’B’,第二个字节是’M’。
	DWORD    bfSize;  //位图文件的大小,以字节为单位 包括该14字节    
	WORD     bfReserved1; //位图文件保留字,暂时不用,一般为0         
	WORD     bfReserved2; //位图文件保留字,暂时不用,一般为0         
    DWORD    bfOffBits; //位图数据距文件头的偏移量,以字节为单位,即前三部分和
} BITMAPFILEHEADER;

第二部分为位图信息头BITMAPINFOHEADER,该结构固定为40个字节,用于说明位图的尺寸、宽高、像素、分辨率、颜色表等信息。具体结构定义如下:

//位图信息头
typedef struct tagBITMAPINFOHEADER {
	DWORD    biSize;            //本结构所占用字节数 40字节
 	LONG     biWidth;           //位图的宽度,以像素为单位
	LONG     biHeight;          //位图的高度,以像素为单位
	WORD     biPlanes;          //目标设备的级别,必须为1
	WORD     biBitCount;        //每个像素所需的位数,必须是1(双色)、
	                              //4(16色)、8(256色)或24(真彩色)之一
	DWORD    biCompression;     //位图压缩类型,必须是 0(BI_RGB不压缩)、
	                              //1(BI_RLE8压缩类型)
//2(BI_RLE压缩类型)之一
	DWORD    biSizeImage;       //位图的大小,以字节为单位
	LONG     biXPelsPerMeter;   //位图水平分辨率,每米像素数
	LONG     biYPelsPerMeter;   //位图垂直分辨率,每米像素数
	DWORD    biClrUsed;         //位图实际使用的颜色表中的颜色数
	DWORD    biClrImportant;    //位图显示过程中重要的颜色数 
} BITMAPINFOHEADER;

第三部分为颜色表或调色板(Palette)。有些位图需要调色板,有些位图如真彩色图(biBitCount=24)不需要调色板,它们的BITMAPINFOHEADER后面直接是位图数据。调色板实际是一个数组,共有biClrUsed个元素(如果该值为零,则有2的biBitCount次幂个元素)。数组中每个元素的类型是一个RGBQUAD结构,占4字节。定义如下:

//位图颜色表
typedef struct tagRGBQUAD
{
    BYTE       rgbBlue;		      //蓝色的亮度(值范围为0~255)
    BYTE       rgbGreen;		      //绿色的亮度(值范围为0~255)
    BYTE       rgbRed;			      //红色的亮度(值范围为0~255)
    BYTE       rgbReserved;	      //保留,必须为0
} RGBQUAD;

第四部分就是实际的图像数据。对于真彩色图(24位位图 biBitCount=24),图像数据就是实际的RGB值;对于用到调色板的位图,图像数据就是该像素颜色在调色板中的索引值。下面对2色、16色、256色和真彩色位图分别介绍:

(1)2色位图:当biBitCount=1时,用1位就可以表示该像素的颜色(0表示黑,1表示白),所以8个像素占1个字节;

(2)16色位图:当biBitCount=4时,用4为可以表示一个像素的颜色,所以2个像素占1个字节;

(3)256色位图:当biBitCount=8时,用1个字节表示1个像素,1个像素占1个字节;

(4)真彩色图:当biBitCount=24时,此时用3个字节表示1个像素,其中RGB各占1字节,由于没有颜色表,位图信息头后面是位图数据。

注意以下几点:

由于Windows规定一个扫描所占的字节数必须是4的倍数(即以long为单位),不足的以0填充。因此,图像每一行的数据最后有可能出现补0。同时注意下面公式,计算只含位图数据的大小:

biSizeImage=(((bi.biWidth*bi.biBitCount)+31)/32*4)*bi.Height

上述公式可以用来验证BMP文件补零的问题。最外层括号计算的是每行的字节数,包括了补的零。在读取文件时可以通过信息头进行查看验证。

BMP图片格式的数据是从下到上、从左到右读。即文件中最先读到的图像是最下面一行的左边第一个元素,即从左下角开始存储(0,0)点,从左下角到右上角存储数据。另外,如果是真彩色图像,即biBitCount=24,每个像素的3通道像素值的存储顺序,不是RGB,而是BGR。

使用C++读取BMP图片,可以自定义上述结构体,包含BMP位图的位图文件头结构、位图信息头结构、位图颜色表3个结构。Windows API在其库文件wingdi.h中系统定义了BMP图像的结构BITMAPFILEHEADER、BITMAPINFOHEADER。我们自己写的标准C/C++代码自己定义这些结构体即可。

如果你自定义这些结构体,你可能会掉进BITMAPFILEHEADER的坑里。用sizeof算一下这个结构体所占的字节数,你会发现结果不是14,而是16,这是由与上面第1条类似的为了效率而默认的4字节对齐原因产生的。请自行搜索“内存对齐Memory Alignment”问题学习。解决办法有3种:1)不使用自定义的结构体,在MFC下可直接使用系统库自带的结构体;2)更改对齐规则;3)不整体读该结构体,而是把该结构体内部的各个元素分别单独读取。网上有很多资料提供解决这个问题的办法:

C++读写BMP文件头部时的字节对齐问题_xiaosuanzaowb的博客-CSDN博客

bmp图像的字节对齐问题_soundzyt的博客-CSDN博客

BMP文件格式及读写 - oshixiaoxiliu - 博客园

下面这段示例代码展示了读取一幅24位彩色BMP文件的总行数一半的数据,然后保存成另外一个BMP图像文件。这里读取的图像每行像素的字节数正好是4的整数倍,所以没有处理补零的情况,仅供实验时参考。

#include <cstdio>
#include <cstdlib>

// 针对该结构体的字节对齐问题调整对齐策略
#pragma pack(push,1)
struct BMPFILEHEADER
{
    unsigned short bfType;
    unsigned int   bfSize;
    unsigned short bfReserved1;
    unsigned short bfReserved2;
    unsigned int   bfOffBits;
};
#pragma pack(pop)

struct BITMAPINFOHEADER
{
    unsigned long    biSize;            //本结构所占用字节数 40字节
    long             biWidth;           //位图的宽度,以像素为单位
    long             biHeight;          //位图的高度,以像素为单位
    unsigned short   biPlanes;          //目标设备的级别,必须为1
    unsigned short   biBitCount;        //每个像素所需的位数,必须是1(双色)、
                                        //4(16色)、8(256色)或24(真彩色)之一
    unsigned long    biCompression;     //位图压缩类型,必须是 0(BI_RGB不压缩)、
                                        //1(BI_RLE8压缩类型)
                                        //2(BI_RLE压缩类型)之一
    unsigned long    biSizeImage;       //位图的大小,以字节为单位
    long             biXPelsPerMeter;   //位图水平分辨率,每米像素数
    long             biYPelsPerMeter;   //位图垂直分辨率,每米像素数
    unsigned long    biClrUsed;         //位图实际使用的颜色表中的颜色数
    unsigned long    biClrImportant;    //位图显示过程中重要的颜色数 
};


int main()
{    
    FILE* fp = NULL;  // C标准库的文件指针
    fopen_s(&fp, "Fruits.bmp", "rb"); // 二进制读取方式打开文件

    BMPFILEHEADER bmpfileheader;  // 文件头
    BITMAPINFOHEADER bitmapinfoheader;  // 信息头
    // 读取文件头
    fread(&bmpfileheader, sizeof(bmpfileheader), 1, fp);
    // 读取信息头
    fread(&bitmapinfoheader, sizeof(bitmapinfoheader), 1, fp);

    // 计算总的像素个数
    int num_pix = bitmapinfoheader.biHeight * bitmapinfoheader.biWidth;

    // 动态分配一维数组存储像素数据,注意3通道,每个像素3个字节
    unsigned char* data = (unsigned char *)malloc(num_pix / 2 * 3);
    // 读取像素数据,只读了一半的行数
    fread(data, num_pix / 2 * 3, 1, fp);

    // 更新信息头里的行数和数据总字节数
    bitmapinfoheader.biHeight /= 2;
    bitmapinfoheader.biSizeImage /= 2;

    FILE* fp2 = NULL; // 保存文件的文件指针
    fopen_s(&fp2, "Fruits2.bmp", "wb"); // 二进制写入方式打开文件
    // 写入文件头
    fwrite(&bmpfileheader, sizeof(bmpfileheader), 1, fp2);
    // 写入信息头
    fwrite(&bitmapinfoheader, sizeof(bitmapinfoheader), 1, fp2);
    // 写入数据
    fwrite(data, num_pix / 2 * 3, 1, fp2);
    // 关闭写入的文件
    fclose(fp2);

    // 释放动态分配的内存
    free(data);
    // 关闭读取的文件
    fclose(fp);

    return 0;
}

实验提供的图像是24位真彩色图像,即biBitCount=24,每个像素有3个值(RGB三个通道)来表示,因此没有颜色表那部分数据。为简单起见,我们接下来的实验是要把图像读入二维数组后再做其他处理,因此要把这个三维的数据(行、列、通道)转换为二维数据(只有行、列)。因此,实验要求在读取BMP文件的时候,把每个像素的三个像素值转换成一个值,一个简单的做法是取RGB三个通道的平均数。

本次实验读入一幅图像,比如“Fruits.bmp”。将图像数据读入到内存中动态分配的二维数组中。图像的大小是height行,width列像素,每个像素占3个字节,类型是unsigned char的整数(即在区间[0,255]内)。在读取的时候把每个像素的3个通道的值求平均,存入二维数组对应的位置。按照下面的任务处理完后,再写入一幅新的BMP文件。注意,因为在读取的时候计算3通道的平均值,丢失了颜色信息,我们是无法再还原成彩色图像了,因此在把结果保存成BMP图像文件的时候,需要把二维数组的每一个值赋值到新图像的3个通道,结果图像虽然内部有RGB三个通道的数据,但是由于都是同一个值,因此图像没有颜色,称为灰度图。

请编程实现:

读取给定的BMP图像。通过读取文件信息头里的biSizeImage的值,验证BMP每行像素所占字节数是否补0达到4的整数倍。

动态分配二维数组a,将图像数据“降维”后读入a中。这里的“降维”指的是把3通道的彩色图像读取到单通道的二维数组中。

将数组a的元素上下翻转。即第一行变为最后一行。即实现函数FlipImageUpDown。

将变换后的数组a写入一幅新的BMP图像文件。如果以上步骤正确,新的图像是原图翻转后的图像。

将数组a的元素左右翻转。即第一列变为最后一列。即实现函数FlipImageLeftRight。

将变换后的数组a写入一幅新的BMP图像文件。如果以上步骤正确,会显示翻转后的图像。

将图像缩小为原来尺寸的一半,存入动态分配内存的二维数组b。一个简单的做法是将a中的属于奇数行和奇数列的元素读取写入到b中。操作完成后,将b写回硬盘一个新的BMP文件中。

void ReadBMP(const char *filename, unsigned char **d, 文件头, 信息头)
{
// 当读入的图像是"Fruits_480x511.jpg"时,这个图像每行字节数不是4的整数倍,文件里每行都有补零
// 你的这个函数应该能够正确处理这种情况
}

void WriteBMP(const char *filename, unsigned char **d, 文件头, 信息头)
{// 同样需要注意你的函数应该能够处理需要补零的情况
}

void FlipImageUpDown(unsigned char **d, int rows, int cols) { }

void FlipImageLeftRight(unsigned char **d, int rows, int cols)  { }

void ResizeImage(/*相关的形参*/) { }

int main(int argc, char* argv[])
{
// 调用你写的读取BMP图像的函数,读取数据到二维数组
// write your code here

// 上下翻转图像
// 调用FlipImageUpDown
// 将反转后的数组的数据写入一幅新的图像文件

// 左右翻转图像
// 调用FlipImageLeftRight
// 将反转后的数组的数据写入一幅新的图像文件

// 将原图缩小为原尺寸的一半,结果存入新的动态二维数组中 

// 将缩小操作后的结果数组的数据写入一幅新的图像文件
    
    
return 0;
}

实验要求

完成上述代码,并能显示正确的结果图像。

注意事项

图像的基本组成单元用“像素”表示,例如如果图像的大小是480*511像素,表示图像的高度(行数)为480像素,宽度(列数)为511像素,;

本实例中给的图像都是3通道(24位)的彩色图像。读取的时候要将其处理为灰度图像。

二级指针作为函数参数时,应在函数声明时指明其行、列数,否则函数内部无法得知数组的维度;

动态分配的数组,使用完后要及时释放,防止内存的泄漏。

实验效果图(仅供参考)

读入原图像到二维数组后,再保存为另一幅图像。由于丢失了颜色信息,变成了灰度图。

   2.图像上下翻转

   3.图像左右翻转

4.图像尺寸缩小为原来的一半 

源码——

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<Windows.h>
#include<cstdio>
#include<cstdlib>
using namespace std;
unsigned char **  ReadBMP(const char* filename, BITMAPFILEHEADER *filehead , BITMAPINFOHEADER *infohead)
{//读取已知文件中的信息存入到二级指针**d中
    unsigned char** d;
    FILE* fp = fopen(filename, "rb");
    if (!fp)
    {
        printf("文件打开错误");
        exit(0);
    }
    long width, height;
    fread(filehead, sizeof(BITMAPFILEHEADER), 1, fp);//读取文件头
    fread(infohead, sizeof(BITMAPINFOHEADER), 1, fp);//读取信息头
    height = infohead->biHeight ;//读取像素高度
    width = infohead->biWidth;//读取像素宽度
    // 当读入的图像是"Fruits_480x511.jpg"时,这个图像每行字节数不是4的整数倍,文件里每行都有补零
    // 你的这个函数应该能够正确处理这种情况
    //补0
    if (height % 4 != 0)
    {
        height = (height * (infohead->biBitCount) / 8 + 3) / 4 * 4;
        height = height / 3;
    }
    if (width % 4 != 0)
    {
        width = (width* (infohead->biWidth)/ 8 + 3) / 4 * 4;
        width = width / 3;
    }
    //动态开辟内存空间,二维数组
    d = new unsigned char* [height];
    int i, j;
    unsigned char a, b, c;//像素点信息
    for (i = 0; i < height; i++)
    {
        d[i] = new unsigned char[width];
    }
    for (i = 0; i < height; i++)
    {
        for (j = 0; j < width; j++)
        {
            fread(&a, sizeof(unsigned char), 1, fp);
            fread(&b, sizeof(unsigned char), 1, fp);
            fread(&c, sizeof(unsigned char), 1, fp);
            d[i][j] = (a + b + c) / 3;
        }
    }
    fclose(fp);
    return d;
}
void WriteBMP(char *filename,BITMAPFILEHEADER filehead, BITMAPINFOHEADER infohead, unsigned char** p)
{
 
    FILE* fp= fopen(filename, "wb");
    if (fp == NULL)
    {
        printf("文件打开失败");
        exit(0);
    }
    fwrite(&filehead, sizeof(BITMAPFILEHEADER), 1, fp);
    fwrite(&infohead, sizeof(BITMAPINFOHEADER), 1, fp);
    // fwrite(img, sizeof(RGB), size, pfout);
    int height, weight;
    height = infohead.biHeight;
    weight = infohead.biWidth;
    int i, j, k;
    for (i = 0; i < height; i++)
    {
        for (j = 0; j < weight; j++)
        {
            for (k = 0; k < 3; k++)
                fwrite(&p[i][j], sizeof(unsigned char), 1, fp);
        }
    }
    fclose(fp);
    /* for (i = 0; i < height; i++)//释放空间
         delete[] p[i];
     delete p;*/
}
void FlipImageUpDown(unsigned char** d, int rows, int cols) 
{ 
 
    int i, j;
    unsigned char **d1=new unsigned char *[rows];
    for (i = 0; i < rows; i++)
    {
        d1[i] = new unsigned char[cols];
    }
    for (i = 0; i < rows; i++)
    {
        for (j = 0; j < cols; j++)
        {
            d1[i][j] = d[i][j];
        }
    }
    for (i = 0; i < rows; i++)
    {
        for (j = 0; j < cols; j++)
        {
            d[i][j] = d1[rows - i - 1][j];
        }
    }//释放动态分配的
    for (i = 0; i < rows; i++)
    {
        delete[]d1[i];
    }
    delete []d1;
}
 
void FlipImageLeftRight(unsigned char** d, int rows, int cols)
{
    int i, j;
    unsigned char** d1 = new unsigned char* [rows];
    for (i = 0; i < rows; i++)
    {
        d1[i] = new unsigned char[cols];
    }
    for (i = 0; i < rows; i++)
    {
        for (j = 0; j < cols; j++)
        {
            d1[i][j] = d[i][j];
        }
    }
    for (i = 0; i < rows; i++)
    {
        for (j = 0; j < cols; j++)
        {
            d[i][j] = d1[i][cols-j-1];
        }
    }//释放动态分配
    for (i = 0; i < rows; i++)
    {
        delete[]d1[i];
    }
    delete []d1;
}
void ResizeImage(unsigned char** d, int rows, int cols)
{
    unsigned char **d1 = new unsigned char* [rows / 2];
    int i, j;
    for (i = 0; i < rows / 2; i++)
    {
        d1[i] = new unsigned char[cols / 2];
    }
   for (i = 0; 2 * i < rows; i++)
    {
        for (j = 0; 2 * j < cols; j++)
        {
            d1[i][j] = d[i*2][j*2];
        }
    }
    for (i = 0; i < rows / 2; i++)
    {
        for (j = 0; j < cols / 2; j++)
        {
            d[i][j] = d1[i][j];
        }
    }
}
void WriteBMP2(char* filename, BITMAPFILEHEADER filehead, BITMAPINFOHEADER infohead, unsigned char** p)
{
 
    FILE* fp = fopen(filename, "wb");
    if (fp == NULL)
    {
        printf("文件打开失败");
        exit(0);
    }  
    infohead.biHeight /= 2;//长宽各变成1/2
    infohead.biWidth /= 2;
    fwrite(&filehead, sizeof(BITMAPFILEHEADER), 1, fp);
    fwrite(&infohead, sizeof(BITMAPINFOHEADER), 1, fp);
    // fwrite(img, sizeof(RGB), size, pfout);
    int height, weight;
    height = infohead.biHeight;
    weight = infohead.biWidth;
    int i, j, k;
    for (i = 0; i < height; i++)
    {
        for (j = 0; j < weight; j++)
        {                
            for (k = 0; k < 3; k++)
            fwrite(&p[i][j], sizeof(unsigned char), 1,fp);
        }
    }
    fclose(fp);
    /* for (i = 0; i < height; i++)//释放空间
         delete[] p[i];
     delete p;*/
}
int main(int argc, char* argv[])
{
    // 调用你写的读取BMP图像的函数,读取数据到二维数组
    // write your code here
    BITMAPFILEHEADER filehead;//文件头
    BITMAPINFOHEADER infohead;//信息头
    char filename[100];//文件名
    cout << "请输入你想要操作的文件名"<<endl;
    cin >> filename;
    char filename2[100];
    cout << "1:上下翻转"<<endl;
    cout << "2:左右翻转" << endl;
    cout << "3:缩小图片为2分之一" << endl;
    cout << "请输入你想要的操作" << endl;
    int e;
    cin >> e;
    unsigned char **a= ReadBMP(filename, &filehead, &infohead);//定义存储信息的数组指针
   //ReadBMP(filename,a, &filehead, &infohead);//读取图片中的信息存入到二维数组a中
    long height = infohead.biHeight;
    long  width = infohead.biWidth;
    long i, j;
    switch (e)
    {
    case 0:
        cin >> filename2;
        WriteBMP( filename2,filehead, infohead,a);
        cout << "灰度化图片保存完整存入:" << filename2 ;
        break;
    case 1:
        FlipImageUpDown(a, height, width);
        cin >> filename2;
        WriteBMP(filename2, filehead, infohead, a);
        cout << "上下翻转的灰度化图片完整存入::" << filename2 ;
        break;
    case 2:
        FlipImageLeftRight(a, height, width);
        cin >> filename2;
        WriteBMP(filename2, filehead, infohead, a);
        cout << "左右翻转的灰度化图片完整存入::" << filename2;
        break;
    case 3:
        ResizeImage(a, height, width);
        cin >> filename2;
        WriteBMP2(filename2, filehead, infohead, a);
        cout << "缩小为1/2灰度化图片完整存入::" << filename2;
        break;
    default :
        cout << "退出" << endl;
        break;
    }
    return 0;
}

  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
我明白了,这是一道编程题,你想让我帮你编写一个可以将24位真彩色BMP文件转换为灰色图像,最后存储为8位伪彩色BMP文件的Python程序,对吧? 好的,先说一下步骤,我们可以将24位真彩色BMP文件的RGB值转换为灰度值,再将灰度值转换为8位伪彩色数值,最后输出8位伪彩色BMP文件,这个过程可以使用面向对象的方式来实现。 以下是代码示例: ```python class BMPConverter: def __init__(self, filepath): self.filepath = filepath def read_file(self): with open(self.filepath, 'rb') as file: # 读取文件头部,19-22位为位图数据偏移量 file.seek(18) self.img_offset = int.from_bytes(file.read(4), byteorder='little') # 读取位图宽度和高度,18-21位为宽度,22-25位为高度 file.seek(18) self.width = int.from_bytes(file.read(4), byteorder='little') self.height = int.from_bytes(file.read(4), byteorder='little') # 读取位图数据 file.seek(self.img_offset) self.data = file.read() def to_gray(self): # 将RGB值转换为灰度值 gray_data = bytearray() for i in range(self.width * self.height): b = self.data[i * 3] g = self.data[i * 3 + 1] r = self.data[i * 3 + 2] gray_value = int(0.3 * r + 0.59 * g + 0.11 * b) gray_data.append(gray_value) self.data = gray_data def to_pseudocolor(self): # 将灰度值转换为8位伪彩色数值 pseudo_data = bytearray() for i in range(self.width * self.height): gray_value = self.data[i] pseudo_value = int(gray_value / 16) # 每个伪彩色值跨度为16 pseudo_data.append(pseudo_value) self.data = pseudo_data def write_file(self, outpath): # 输出8位伪彩色BMP文件 with open(outpath, 'wb') as file: # 写入文件头部 file.write(b'BM') file.write((14 + 40 + self.width * self.height).to_bytes(4, byteorder='little')) file.write(b'\x00\x00') file.write(b'\x00\x00') file.write((14 + 40).to_bytes(4, byteorder='little')) # 写入信息头 file.write(b'\x28\x00\x00\x00') # BITMAPINFOHEADER file.write(self.width.to_bytes(4, byteorder='little')) file.write(self.height.to_bytes(4, byteorder='little')) file.write(b'\x01\x00') # 1个平面 file.write(b'\x08\x00') # 8位伪彩色 file.write(b'\x00\x00\x00\x00') # 不压缩 file.write((self.width * self.height).to_bytes(4, byteorder='little')) file.write(b'\x00\x00\x00\x00') file.write(b'\x00\x00\x00\x00') file.write(b'\x00\x00\x00\x00') file.write(b'\x00\x00\x00\x00') # 写入调色板 for i in range(256): file.write(bytes([i, i, i, 0])) # 写入位图数据 file.write(self.data) # 测试 if __name__ == '__main__': converter = BMPConverter(r'D:\多媒体技术\3\实验三素材\实验三素材\24位真彩色BMP\robert.bmp') converter.read_file() converter.to_gray() converter.to_pseudocolor() converter.write_file('output.bmp') ``` 这段程序会读取文件,将RGB值转换为灰度值,再将灰度值转换为8位伪彩色数值,最后输出8位伪彩色BMP文件,你可以根据需要修改代码中的输入输出路径。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值