本程序支持24位真彩色图像和灰度图像,暂时不支持8位灰度图像,在源代码上进行修改可以支持8位。
数字图像处理的全部函数我写在一个文件里了,这里仅列举这个功能所需要的东西。
如果单独使用以下函数,在此程序中首先应定义一个全局指针变量IMG,方便调用。
FILE* IMG;
//此函数为内联函数,在其他的函数中使用,用于读取BMP文件标头并跳过BMP前54字节直接读取像素内容,此函数运作完成之后必须主动关闭文件(fclose(IMG);),*****切记此行,防止出错****** IMG指针是一个全局变量,所以关闭时只要固定关闭IMG即可
_inline uint8_t IMG_BMP_FILEINFOGET(const char* ORI_IMG)
{
IMG = fopen(ORI_IMG, "rb");
if (IMG == NULL)
{
return -1;
}
fread(&fileType, 1, sizeof(unsigned short), IMG);
if (fileType == 0x4d42)
{
fread(&BITMAPFILEHEADER, 1, sizeof(tBITMAPFILEHEADER), IMG);
fread(&BITMAPINFOHEADER, 1, sizeof(tBITMAPINFOHEADER), IMG);
return 0;
}
else
{
fclose(IMG);
return -2;
}
}
/**********
/* ORI_IMG是原来图像的PATH,NEW_IMG是新图像的PATH
/* 此函数用于实现24位真彩色图像的RGB域的直方图均衡化变换
**********/
uint8_t IMG_ColorIMG_HistoEquala(const char* ORI_IMG, const char* NEW_IMG)
{
FILE* IMGH;//用于指向新图像的指针
uint32_t ProDist_R[256] = {};//三通道各自的像素概率
uint32_t ProDist_G[256] = {};
uint32_t ProDist_B[256] = {};
double Prosk_R[256],Prosk_G[256], Prosk_B[256];//三通道各自的概率
uint32_t Trosk_R[256], Trosk_G[256], Trosk_B[256];//均衡化后的变换参数
uint32_t countt = 0;
double check = 0;
int IS_SUCESS = IMG_BMP_FILEINFOGET(ORI_IMG);
if (!IS_SUCESS)
{
//拿到分布直方表数值ProDist
rgbPerPixel* hs = (rgbPerPixel*)malloc(sizeof(rgbPerPixel));
for (long i = BITMAPINFOHEADER.biHeight * BITMAPINFOHEADER.biWidth; i > 0; i--)
{
fread(hs, 1, sizeof(rgbPerPixel), IMG);
ProDist_R[(hs->r)]++;
ProDist_G[(hs->g)]++;
ProDist_B[(hs->b)]++;
countt++;
}
free(hs);
fclose(IMG);
}
else
{
printf("错误*******查询手册*****错误码:%d", IS_SUCESS);
return IS_SUCESS;
}
//开始计算必要参数 灰度域以及色域概率Prosk
for (long i = 0; i < 256; i++)
{
//printf("灰度域 %d 概率 = %lf\r\n", i, (double)ProDist_R[i] / ((double)BITMAPINFOHEADER.biHeight * (double)BITMAPINFOHEADER.biWidth));
check += (double)ProDist_R[i] / ((double)BITMAPINFOHEADER.biHeight * (double)BITMAPINFOHEADER.biWidth);
Prosk_R[i] = check;
}
check = 0;
for (long i = 0; i < 256; i++)
{
//printf("灰度域 %d 概率 = %lf\r\n", i, (double)ProDist_G[i] / ((double)BITMAPINFOHEADER.biHeight * (double)BITMAPINFOHEADER.biWidth));
check += (double)ProDist_G[i] / ((double)BITMAPINFOHEADER.biHeight * (double)BITMAPINFOHEADER.biWidth);
Prosk_G[i] = check;
}
check = 0;
for (long i = 0; i < 256; i++)
{
//printf("灰度域 %d 概率 = %lf\r\n", i, (double)ProDist_B[i] / ((double)BITMAPINFOHEADER.biHeight * (double)BITMAPINFOHEADER.biWidth));
check += (double)ProDist_B[i] / ((double)BITMAPINFOHEADER.biHeight * (double)BITMAPINFOHEADER.biWidth);
Prosk_B[i] = check;
}
printf("%d", (int)(check * 100));
if (!((((int)(check * 100)) == 100) || ((int)(check * 100) == 99)))
{
IS_SUCESS = -7;
printf("\r\n\t\t****错误*****程序数值溢出:查看手册**错误码%d*********\t\r\n", IS_SUCESS);
}
else
{
printf("数据验证成功!****\r\n");
}
printf("count:%d\r\n total:%d\r\ncheck:%lf\r\n", countt, (BITMAPINFOHEADER.biHeight * BITMAPINFOHEADER.biWidth), check);
printf("------操作成功--------\r\n");
//利用Prosk,求得其均衡化变换函数Trosk
for (long i = 0; i < 256; i++)
{
Trosk_R[i] = (uint32_t)(Prosk_R[i] * 255);
Trosk_G[i] = (uint32_t)(Prosk_G[i] * 255);
Trosk_B[i] = (uint32_t)(Prosk_B[i] * 255);
printf("当前彩色梯度%d R域近似域:%d\tG域近似域:%d\tB域近似域:%d\r\n",i, Trosk_R[i], Trosk_G[i], Trosk_B[i]);
//printf("当前灰度域概率%d\t灰度NK %d SK = %lf\t 近似灰度域:%d\r\n", ProDist_B[i], i, Prosk_B[i], Trosk_B[i]);
}
//得到最终的变换函数 Trosk[] 接着写新的图像
IS_SUCESS = IMG_BMP_FILEINFOGET((const char*)ORI_IMG);
if (!IS_SUCESS)
{
printf("-------------BMP文件读取成功-----------\r\n");
rgbPerPixel* hs = (rgbPerPixel*)malloc(sizeof(rgbPerPixel));
rgbPerPixel* hpsn = (rgbPerPixel*)malloc(sizeof(rgbPerPixel));
if ((IMGH = fopen((const char*)NEW_IMG, "wb")) == NULL)
{
IS_SUCESS = -2;
printf("程序出错,文件建立失败,错误码:%d\r\n", IS_SUCESS);
return IS_SUCESS;
}
fwrite(&fileType, 2, 1, IMGH);
fwrite(&BITMAPFILEHEADER, 1, sizeof(BITMAPFILEHEADER), IMGH);
fwrite(&BITMAPINFOHEADER, 1, sizeof(BITMAPINFOHEADER), IMGH);
for (long i = BITMAPINFOHEADER.biHeight * BITMAPINFOHEADER.biWidth; i > 0; i--)
{
fread(hs, 1, sizeof(rgbPerPixel), IMG);
(hpsn->r) = Trosk_R[(hs->r)];
(hpsn->g) = Trosk_G[(hs->g)];
(hpsn->b) = Trosk_B[(hs->b)];
fwrite(hpsn, 1, sizeof(rgbPerPixel), IMGH);
}
free(hs);
free(hpsn);
fclose(IMG);
fclose(IMGH);
printf("\t图像处理完成,保存于IMG source文件夹下,请自行查看\r\n");
IS_SUCESS = 1;
return 0;
}
else
{
IS_SUCESS = -1;
printf("错误*****请查询手册****错误码%d\r\n", IS_SUCESS);
return IS_SUCESS;
}
}
过程有三步:
(1)获取原图像的在RGB域(R\G\B)分别的直方图。
(2)通过直方图分别计算R\G\B各自像素的概率。
(3)计算变换函数T
(4)逐像素填充变换,生成新图像。
P.S.
由于时间紧张,只是草草实现了功能,能够暂时支持作业的完成(QAQ),所以代码未作优化和进一步修改,还请见谅。
至于unsigned short fileType; tBITMAPFILEHEADER BITMAPFILEHEADER; tBITMAPINFOHEADER BITMAPINFOHEADER;
在我上一篇博客里有定义,是文件标头,不知道可以参照,或者进一步查阅百度。
附图片:
处理后:
拍摄的照片效果会更好一点,这里仅作为展示。