全彩转灰度公式和灰度转伪彩色对应关系均可在代码里找到,有详细注释
#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;
}