C语言实现BMP图片全彩转灰度,灰度转伪彩

C语言实现BMP图片全彩转灰度,灰度转伪彩

  • 代码
  • 测试结果

代码

全彩转灰度公式和灰度转伪彩色对应关系均可在代码里找到,有详细注释

#include
#include
#include

#pragma pack(1)
typedef struct tagBITMAPFILEHEADER
{
    unsigned short bfType;//文件格式
    unsigned long bfSize;//文件大小
    unsigned short bfReserved1;//保留
    unsigned short bfReserved2;
    unsigned long bfOffBits; //DIB数据在文件中的偏移量
}fileHeader;
#pragma pack()
/*
位图数据信息结构
*/
#pragma pack(1)
typedef struct tagBITMAPINFOHEADER
{
    unsigned long biSize;//该结构的大小
    long biWidth;//文件宽度
    long biHeight;//文件高度
    unsigned short biPlanes;//平面数
    unsigned short biBitCount;//颜色位数
    unsigned long biCompression;//压缩类型
    unsigned long biSizeImage;//DIB数据区大小
    long biXPixPerMeter;
    long biYPixPerMeter;
    unsigned long biClrUsed;//多少颜色索引表
    unsigned long biClrImporant;//多少重要颜色
}fileInfo;
#pragma pack()
/*
调色板结构
*/
#pragma pack(1)
typedef struct tagRGBQUAD
{
    unsigned char rgbBlue; //蓝色分量亮度
    unsigned char rgbGreen;//绿色分量亮度
    unsigned char rgbRed;//红色分量亮度
    unsigned char rgbReserved;
}rgbq;
#pragma pack()

//其他数据  
typedef struct OtherData  
{  
    unsigned char extradata;  
    struct OtherData *next;  

}OtherData;

int colorToGray(FILE* fp1,FILE* fp2)
{
    fileHeader * fh;
    fileInfo * fi;
    fh = (fileHeader *)malloc(sizeof(fileHeader));
    fi = (fileInfo *)malloc(sizeof(fileInfo));

    //读取位图头结构和信息头
    fread(fh, sizeof(fileHeader), 1, fp1);
    fread(fi, sizeof(fileInfo), 1, fp1);

    //修改信息头
    fi->biBitCount = 8;
    //fi->biSizeImage = ((fi->biWidth * 3 + 3) / 4) * 4 * fi->biHeight;
    fi->biSizeImage = fi->biHeight*fi->biWidth;
    //修改文件头
    fh->bfOffBits = sizeof(fileHeader) + sizeof(fileInfo) + 256 * sizeof(rgbq);
    fh->bfSize = fh->bfOffBits + fi->biSizeImage;

    //创建调色板
    int i,j,k=0;
    rgbq *fq = (rgbq *)malloc(256 * sizeof(rgbq));
    for (i = 0; i<256; i++)
    {
        fq[i].rgbBlue = fq[i].rgbGreen = fq[i].rgbRed = i;
    }
    //写入文件头、信息头、调色板
    fwrite(fh, sizeof(fileHeader), 1, fp2);
    fwrite(fi, sizeof(fileInfo), 1, fp2);
    fwrite(fq, sizeof(rgbq), 256, fp2);

    //将位图信息转为灰度
    //存储bmp一行的像素点
    unsigned char ImgData[3000][3];
    //将灰度图像存到一维数组中
    unsigned char ImgData2[3000];


    //公式 
    for (i = 0; i<fi->biHeight; i++)
    {
        for (j = 0; j<(fi->biWidth + 3) / 4 * 4; j++)
        {
            for (k = 0; k<3; k++)
            fread(&ImgData[j][k], 1, 1, fp1);
        }
        for (j = 0; j<(fi->biWidth + 3) / 4 * 4; j++)
        {
            ImgData2[j] = int((float)ImgData[j][0] * 0.114 +
                (float)ImgData[j][1] * 0.587 +
                (float)ImgData[j][2] * 0.299);
        }
        //将灰度图信息写入
        fwrite(ImgData2, j, 1, fp2);
    }

    free(fh);
    free(fi);
    free(fq);
    fclose(fp1);
    fclose(fp2);
    return 1;
}

int grayToColor(FILE* fp1,FILE* fp2)  
{   
    unsigned char * * ImgData;//二维数组 
    unsigned int j, k,i;  
    fileHeader fh;  
    fileInfo fi;  
    rgbq *IpRGBQuad;           
    OtherData  *Otherdata, *temp,*SavePreCursor;  


    /*图像的读取顺序是从下到上,从左到右*/  

    IpRGBQuad = (rgbq *)malloc(256*sizeof(rgbq));//灰度图为8位的调色板数据为256个结构,1024个字节  
    Otherdata = (OtherData*)malloc(sizeof(OtherData));  
    SavePreCursor = Otherdata;//保存当前指针游标,目的就是保存链表头结点  
    Otherdata->extradata = NULL;  
    Otherdata->next = NULL;  

    //拥有1024个调色板数据   
    fread(&fh, sizeof(fileHeader), 1, fp1);  

    if (fh.bfType == 0x4D42)  
    {
        //读取位图信息头 
        fread(&fi, sizeof(fileInfo), 1, fp1);  
        //读取调色板数据   
        fread(IpRGBQuad, sizeof(rgbq), 256, fp1); 
        fi.biBitCount = 24;
        fi.biSizeImage = fi.biHeight*fi.biWidth;
        fh.bfOffBits = sizeof(fileHeader)+sizeof(fileInfo)+256*sizeof(rgbq);
        fh.bfSize = fh.bfOffBits + fi.biSizeImage;
        fwrite(&fh, sizeof(fileHeader), 1, fp2);
        fwrite(&fi, sizeof(fileInfo), 1, fp2);
        fwrite(IpRGBQuad, sizeof(rgbq), 256, fp2);

        //读取像素数据  

        fi.biHeight++;  
        fi.biWidth += 2;  
        ImgData = new unsigned char *[fi.biHeight];  

        for (j = 0; j < fi.biHeight; j++)  
        {  
            ImgData[j] = new unsigned char [fi.biWidth];//定义像素数组ImgData[InfoHeader.biHeight][InfoHeader.biWidth]  
        }  

        for ( j = 0; j < fi.biHeight; j++)  
        {  

            for ( k = 0; k < fi.biWidth; k++)  
            {  
                fread(&ImgData[j][k], sizeof(unsigned char), 1, fp1);
                //fwrite(&ImgData[j][k], sizeof(unsigned char), 1, fp2);
            }  
        }  

    unsigned char ImgData2[3000][3];//伪彩色数据     

    for (i = 0; i<fi.biHeight; i++)
    {
        for (j = 0; j<fi.biWidth; j++)
        {
            //蓝色
            if(ImgData[i][j] >=0 && ImgData[i][j]<=31)
            {
                ImgData2[j][2] = 0;
                ImgData2[j][1] = 0;
                ImgData2[j][0] = 255;
            }
            //绿色
            if(ImgData[i][j] >=32 && ImgData[i][j]<=63)
            {
                ImgData2[j][2] = 0;
                ImgData2[j][1] = 255;
                ImgData2[j][0] = 0;
            }
            //淡蓝色
            if(ImgData[i][j] >=64 && ImgData[i][j]<=95)
            {
                ImgData2[j][2] = 173;
                ImgData2[j][1] = 216;
                ImgData2[j][0] = 230;
            }
            //紫色
            if(ImgData[i][j] >=96 && ImgData[i][j]<=127)
            {
                ImgData2[j][2] = 155;
                ImgData2[j][1] = 48;
                ImgData2[j][0] = 255;
            }
            //红色
            if(ImgData[i][j] >=128 && ImgData[i][j]<=159)
            {
                ImgData2[j][2] = 255;
                ImgData2[j][1] = 0;
                ImgData2[j][0] = 0;
            }
            //橙色
            if(ImgData[i][j] >=160 && ImgData[i][j]<=191)
            {
                ImgData2[j][2] = 255;
                ImgData2[j][1] = 165;
                ImgData2[j][0] = 0;
            }
            //黄色
            if(ImgData[i][j] >=192 && ImgData[i][j]<=223)
            {
                ImgData2[j][2] = 255;
                ImgData2[j][1] = 255;
                ImgData2[j][0] = 0;
            }
            //淡黄色
            if(ImgData[i][j] >=224 && ImgData[i][j]<=255)
            {
                ImgData2[j][2] = 255;
                ImgData2[j][1] = 255;
                ImgData2[j][0] = 254;
            }
        }
        fwrite(ImgData2, sizeof(unsigned char)*3, j, fp2);
    }


        //读取其他数据  

        temp = (OtherData*)malloc(sizeof(OtherData));  
        while (!feof(fp1))  
        {  
            temp = (OtherData*)malloc(sizeof(OtherData));  

            fread(&temp->extradata, sizeof(unsigned char), 1, fp1);  
            fwrite(&temp->extradata, sizeof(unsigned char), 1, fp2);  
            Otherdata->next = temp;  
            Otherdata = Otherdata->next;  
        }  
        Otherdata->next = NULL;//置末尾为空,判断条件  
        Otherdata = SavePreCursor;//使Otherdata重新指向头部  
    }  


    fclose(fp1);  
    fclose(fp2);   
    return 1;  
}
int main(){
    int colorToGray(FILE* fp1,FILE* fp2);
    int grayToColor(FILE* fp1,FILE* fp2);
    int n;
    char inPath[100],outPath[100];
    printf("功能:\n");
    printf("1 : 彩色转灰色\n");
    printf("2 : 灰色转伪彩色\n");
    printf("输入功能编号:\n");
    scanf("%d",&n);
    printf("输入源文件绝对地址(含文件名):\n");
    scanf("%s",inPath);
    printf("输入目标文件绝对地址(含文件名):\n");
    scanf("%s",outPath);


    FILE *fp1 = fopen(inPath, "rb+");
    if (fp1 == NULL)
    {
        printf("打开文件fp1失败");
        return 0;
    }
    FILE *fp2 = fopen(outPath, "wb");
    if (fp1 == NULL)
    {
        printf("打开文件fp2失败");
        return 0;
    }

    switch(n)
    {
        case 1:
        {
            if(colorToGray(fp1,fp2) == 1)
            {
                printf("success\n");
            }
            break;
        };
        case 2:
        {
            if(grayToColor(fp1,fp2) == 1)
            {
                printf("success\n");
            }
            break;
        }
        default: break;
    }
}


简单接口函数:


// 图像数据
typedef struct _uv_image
{
    uv_uint8      *data;            //  图像数据
    uv_image_type type;             //  图像格式
    uv_int32      step;             //  每行步长
    uv_int32      height;           //  图像高度
    uv_int32      width;            //  图像宽度
}uv_image;                          //  64bit:8 + 4 + 4 + 4 + 4 = 24 byte;   32bit:4 + 4 + 4 + 4 + 4 = 20 byte

// 图像类型
typedef enum _uv_image_type
{
    uv_image_type_gray = 0,         //  灰度图
    uv_image_type_bgr  = 1,         //  彩色图,以bgr形式排列
    uv_image_type_rgb  = 2,         //  彩色图,以rgb形式排列
    uv_image_type_hsv  = 3,         //  hsv格式图像
}uv_image_type;


#define IMAGE_ALIGN_BYTE        64
#define GET_ALIGN_LENGTH(length, align_byte)    (((length) + ((align_byte) - 1)) & ~((align_byte) - 1))     //  计算数据对齐,一般align_byte取2的幂次

#ifdef __cplusplus
    #define MALLOC_PTR(dev_ptr, type, num)      ((dev_ptr) = static_cast<type*>(malloc(static_cast<uv_uint32>(num) * sizeof(type))))
#else
    #define MALLOC_PTR(dev_ptr, type, num)      ((dev_ptr) = (type*)malloc(((uv_uint32)num) * sizeof(type)))
#endif

/*
* 文件: uv_tool_defect.h
* 作者-日期: 2022-08-18
* 函数介绍:灰度图转彩图
* 输入参数:const uv_image *src_img,
* 输出参数:uv_image *dst_img uv_image::data不需要提前分配,,后续会由output指针自动释放
* 返回值  :
*/
kn_status uv_tool_image2bgr(const uv_image *src_img,uv_image *dst_img)
{
    kn_status nStatu = kn_status_ok;
    if(KN_NULL == src_img || KN_NULL == dst_img)
    {
        KN_DBG("KN_NULL == src_img || KN_NULL == dst_img");
        return kn_status_data_null;
    }


    dst_img->type = uv_image_type_bgr;//
    dst_img->height = src_img->height;
    dst_img->width = src_img->width;
    dst_img->step = GET_ALIGN_LENGTH((dst_img)->width*3, IMAGE_ALIGN_BYTE);

    MALLOC_PTR(dst_img->data,uv_uint8,2 * dst_img->height*dst_img->step);
    memset(dst_img->data,0,sizeof(uv_uint8) * dst_img->height*dst_img->step);

    uv_uint8 *pd = dst_img->data;
    const uv_int32 offset = dst_img->step - (dst_img->width*3);
    uv_uint8 *src_pd = src_img->data;
    const uv_int32 src_offset = src_img->step - (src_img->width);


    //伪彩色数据
    uv_uint32 k = 0;
    uv_uint32 n = 0;
    for(k = 0; k < src_img->height; k++,pd += offset,src_pd += src_offset)
    {
        for(n = 0; n < src_img->width; n++,pd += 3, src_pd++)
        {
            //蓝色
            if((*src_pd) >=0 && (*src_pd) <=31)
            {
                *(pd + 2)= 0;
                *(pd + 1) = 0;
                *(pd + 0) = 0;
            }
            //绿色
            if((*src_pd) >=32 && (*src_pd)<=63)
            {
                *(pd + 2) = 0;
                *(pd + 1) = 255;
                *(pd + 0) = 0;
            }
            //淡蓝色
            if((*src_pd) >=64 && (*src_pd)<=95)
            {
                *(pd + 2) = 173;
                *(pd + 1) = 216;
                *(pd + 0) = 230;
            }
            //紫色
            if((*src_pd) >=96 && (*src_pd)<=127)
            {
                *(pd + 2) = 155;
                *(pd + 1) = 48;
                *(pd + 0) = 255;
            }
            //红色
            if((*src_pd) >=128 && (*src_pd)<=159)
            {
                *(pd + 2) = 255;
                *(pd + 1) = 0;
                *(pd + 0) = 0;
            }
            //橙色
            if((*src_pd) >=160 && (*src_pd)<=191)
            {
                *(pd + 2) = 255;
                *(pd + 1) = 165;
                *(pd + 0) = 0;
            }
            //黄色
            if((*src_pd) >=192 && (*src_pd)<=223)
            {
                *(pd + 2) = 255;
                *(pd + 1) = 255;
                *(pd + 0) = 0;
            }
            //淡黄色
            if((*src_pd) >=224 && (*src_pd)<=255)
            {
                *(pd + 2) = 255;
                *(pd + 1) = 255;
                *(pd + 0) = 254;
            }
        }
    }

    return nStatu;
}

测试结果

C语言实现BMP图片全彩转灰度,灰度转伪彩_第1张图片
C语言实现BMP图片全彩转灰度,灰度转伪彩_第2张图片
C语言实现BMP图片全彩转灰度,灰度转伪彩_第3张图片

你可能感兴趣的:(Linux,c/c++,c语言,开发语言)