BMP图像直方图均衡化算法程序(C语言、RGB域)

本程序支持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;
在我上一篇博客里有定义,是文件标头,不知道可以参照,或者进一步查阅百度。

附图片:
原图片
处理后:
处理后的图片示例
拍摄的照片效果会更好一点,这里仅作为展示。

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,我可以为您提供一些关于BMP图像直方图均衡算法的基本思路和C语言实现。 直方图均衡是一种图像增强技术,它可以使图像的对比度增强,提高图像的质量。直方图均衡的基本思路是将图像的像素值进行重新分配,使得图像的灰度级分布更加均匀。 下面是一种基于C语言实现的BMP图像直方图均衡算法的伪代码: 1. 读取BMP图像的像素矩阵 2. 统计图像像素矩阵的灰度级直方图 3. 计算直方图均衡映射表 4. 对原始像素矩阵进行直方图均衡 5. 将均衡后的像素矩阵写回BMP图像 下面是一份可以实现直方图均衡的C语言代码: ```c #include <stdio.h> #include <stdlib.h> #include <string.h> #pragma pack(1) //按字节对齐 typedef struct BMPFileHeader { char bfType[2]; int bfSize; short bfReserved1; short bfReserved2; int bfOffBits; } BMPFileHeader; typedef struct BMPInfoHeader { int biSize; int biWidth; int biHeight; short biPlanes; short biBitCount; int biCompression; int biSizeImage; int biXPelsPerMeter; int biYPelsPerMeter; int biClrUsed; int biClrImportant; } BMPInfoHeader; typedef struct RGB { unsigned char blue; unsigned char green; unsigned char red; } RGB; int main() { FILE* fp; BMPFileHeader bmpFileHeader; BMPInfoHeader bmpInfoHeader; RGB* image; RGB* image2; unsigned char* grayImage; unsigned char* grayImage2; int* hist; int* eqHist; int* map; int width, height, size, size2, i, j, k, max; char filename[100]; // 读取图像文件 printf("Enter the filename of the BMP image: "); scanf("%s", filename); fp = fopen(filename, "rb"); if (!fp) { printf("Error: Failed to open the file.\n"); return -1; } // 读取文件头 fread(&bmpFileHeader, sizeof(BMPFileHeader), 1, fp); if (bmpFileHeader.bfType[0] != 'B' || bmpFileHeader.bfType[1] != 'M') { printf("Error: Not a BMP file.\n"); return -1; } // 读取信息头 fread(&bmpInfoHeader, sizeof(BMPInfoHeader), 1, fp); if (bmpInfoHeader.biBitCount != 24) { printf("Error: Not a 24-bit BMP file.\n"); return -1; } // 计算图像大小 width = bmpInfoHeader.biWidth; height = bmpInfoHeader.biHeight; size = width * height; size2 = sizeof(unsigned char) * size; // 读取像素数据 image = (RGB*)malloc(sizeof(RGB) * size); fread(image, sizeof(RGB), size, fp); // 将RGB图像转换为灰度图像 grayImage = (unsigned char*)malloc(size2); for (i = 0; i < size; i++) { grayImage[i] = (unsigned char)(0.299 * image[i].red + 0.587 * image[i].green + 0.114 * image[i].blue); } // 计算灰度级直方图 hist = (int*)malloc(sizeof(int) * 256); memset(hist, 0, sizeof(int) * 256); for (i = 0; i < size; i++) { hist[grayImage[i]]++; } // 计算直方图均衡映射表 eqHist = (int*)malloc(sizeof(int) * 256); map = (int*)malloc(sizeof(int) * 256); max = size / 256; for (i = 0; i < 256; i++) { eqHist[i] = 0; for (j = 0; j <= i; j++) { eqHist[i] += hist[j]; } map[i] = (int)(eqHist[i] * 255.0 / size + 0.5); if (eqHist[i] > max) { eqHist[i] = max; } } // 对灰度图像进行直方图均衡 grayImage2 = (unsigned char*)malloc(size2); for (i = 0; i < size; i++) { grayImage2[i] = (unsigned char)map[grayImage[i]]; } // 将灰度图像转换为RGB图像 image2 = (RGB*)malloc(sizeof(RGB) * size); for (i = 0; i < size; i++) { image2[i].red = grayImage2[i]; image2[i].green = grayImage2[i]; image2[i].blue = grayImage2[i]; } // 写回图像文件 fseek(fp, sizeof(BMPFileHeader) + sizeof(BMPInfoHeader), SEEK_SET); fwrite(image2, sizeof(RGB), size, fp); fclose(fp); free(image); free(image2); free(grayImage); free(grayImage2); free(hist); free(eqHist); free(map); printf("Done.\n"); return 0; } ``` 这份代码可以读取一个BMP图像文件,将其转换为灰度图像,进行直方图均衡,然后将均衡后的图像写回文件中。注意,这份代码只支持24位的BMP图像文件。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值