C++实现bmp格式图像直方图均衡化及对比度受限的自适应直方图均衡化(CLAHE)

       关于直方图均衡化以及自适应直方图均衡化(CLAHE)的理论可以去查阅相关博客或者课本,这里只是分享对bmp格式的图片的直方图均衡化处理以及自适应直方图均衡化(CLAHE)处理的代码。

     准备工作:首先你得有图像的像素信息,图像的宽度和高度等等。

     代码中用到的变量以及定义预先说明下:

     int m_nWidth:图像的宽度

     int m_nHeight:图像的高度

     int m_nDibWidth:四字节对齐后的宽度,比如m_nWidth = 511,m_nDibWidth = 512。

     BYTE *m_pImage:原图像数据信息,其大小为m_nDibWidth*m_nHeight

     BYTE *m_pImage2:处理后的图像数据信息

下面贴直方图均衡化的代码:

int i, j,k;
	BYTE* p, *p2;
	int t,N = m_nWidth*m_nHeight;
	double hist[256] = {0};
	for (i = 0; i < m_nHeight; i++) {
		for (j = 0; j < m_nWidth; j++) {
			p = m_pImage + i*m_nDibWidth + j;
			hist[*p] = hist[*p] + 1.0/N;//计算直方图,归一化的直方图,类似概率密度
		}
	}
	double cum[256] = { 0 };
	cum[0] = hist[0];
	for (k = 1; k < 256; k++) {
		cum[k] = cum[k - 1] + hist[k];//计算累加
	}
	for (i = 0; i < m_nHeight; i++) {
		for (j = 0; j < m_nWidth; j++) {
			p = m_pImage + i*m_nDibWidth + j;
			p2 = m_pImage2 + i*m_nDibWidth + j;
			*p2 = (BYTE)(cum[*p] * 255);
		}
	}

 

 

下面贴自适应直方图均衡化(CLAHE)的代码:

// TODO: 在此添加控件通知处理程序代码
	int block = 8;
	//将图像均匀分成等矩形大小,8行8列64个块是常用的选择  
	int width_block = m_nWidth / block;
	int height_block = m_nHeight / block;
	
	//存储各个直方图 
	int **tmp = NULL;
	tmp = (int **)malloc(sizeof(int*)*block*block);       //arr在这里可以看出成数组,数组的每个成员都是指向int类型的指针,这样每个指针指向的代表一行,共row行   
	for (int i = 0; i<block*block; i++)            //为每行申请空间
	{
		tmp[i] = (int*)malloc(sizeof(int)* 256);       //每一行有col列
	}
	//存储累积函数  
	float **C = NULL;
	C = (float **)malloc(sizeof(float*)*block*block);       //arr在这里可以看出成数组,数组的每个成员都是指向int类型的指针,这样每个指针指向的代表一行,共row行   
	for (int i = 0; i<block*block; i++)            //为每行申请空间
	{
		C[i] = (float*)malloc(sizeof(float) * 256);       //每一行有col列
	}
	//初始化为0
	for (int i = 0; i < block*block; i++) {
		for (int j = 0; j < 256; j++) {
			C[i][j] = 0;
			tmp[i][j] = 0;
		}
	}

	//计算累积函数  
	for (int i = 0; i < block; i++)
	{
		for (int j = 0; j < block; j++)
		{
			int start_x = i * width_block;
			int end_x = start_x + width_block;
			int start_y = j * height_block;
			int end_y = start_y + height_block;
			int num = i + block*j;
			int total = width_block * height_block;
			for (int ii = start_x; ii < end_x; ii++)
			{
				for (int jj = start_y; jj < end_y; jj++)
				{
					int index = (int)(*(m_pImage + jj * m_nDibWidth + ii));
					tmp[num][index]++;
				}
			}


			//裁剪操作  
			int average = width_block * height_block / 255;
			int LIMIT = 4 * average;
			int steal = 0;
			for (int k = 0; k < 256; k++)
			{
				if (tmp[num][k] > LIMIT) {
					steal += tmp[num][k] - LIMIT;
					tmp[num][k] = LIMIT;
				}

			}

			int bonus = steal / 256;
			//hand out the steals averagely  
			for (int k = 0; k < 256; k++)
			{
				tmp[num][k] += bonus;
			}

			//计算累积分布直方图  
			for (int k = 0; k < 256; k++)
			{
				if (k == 0)
					C[num][k] = 1.0f * tmp[num][k] / total;
				else
					C[num][k] = C[num][k - 1] + 1.0f * tmp[num][k] / total;
			}

		}
	}

//	int[][] new_mat = new int[height][width];
	//计算变换后的像素值  
	//根据像素点的位置,选择不同的计算方法  
	for (int i = 0; i < m_nWidth; i++)
	{
		for (int j = 0; j < m_nHeight; j++)
		{
			//four coners  
			if (i <= width_block / 2 && j <= height_block / 2)
			{
				int num = 0;
				*(m_pImage2 + j*m_nDibWidth + i) = C[num][((int)(*(m_pImage + j*m_nDibWidth + i)))] * 255;
				
			}
			else if (i <= width_block / 2 && j >= ((block - 1)*height_block + height_block / 2)) {
				int num = block*(block - 1);
				*(m_pImage2 + j*m_nDibWidth + i) = C[num][((int)(*(m_pImage + j*m_nDibWidth + i)))] * 255;
				
			}
			else if (i >= ((block - 1)*width_block + width_block / 2) && j <= height_block / 2) {
				int num = block - 1;
				*(m_pImage2 + j*m_nDibWidth + i) = C[num][((int)(*(m_pImage + j*m_nDibWidth + i)))] * 255;
				
			}
			else if (i >= ((block - 1)*width_block + width_block / 2) && j >= ((block - 1)*height_block + height_block / 2)) {
				int num = block*block - 1;
				*(m_pImage2 + j*m_nDibWidth + i) = C[num][((int)(*(m_pImage + j*m_nDibWidth + i)))] * 255;
				
			}

			//four edges except coners  
			else if (i <= width_block / 2)
			{
				//线性插值  
				int num_i = 0;
				int num_j = (j - height_block / 2) / height_block;
				int num1 = num_j*block + num_i;
				int num2 = num1 + block;
				float p = (j - (num_j*height_block + height_block / 2)) / (1.0f*height_block);
				float q = 1 - p;
				*(m_pImage2 + j*m_nDibWidth + i) = ( q*C[num1][((int)(*(m_pImage + j*m_nDibWidth + i)))] + p*C[num2][((int)(*(m_pImage + j*m_nDibWidth + i)))] )*255;
				
			}
			else if (i >= ((block - 1)*width_block + width_block / 2)) {
				//线性插值  
				int num_i = block - 1;
				int num_j = (j - height_block / 2) / height_block;
				int num1 = num_j*block + num_i;
				int num2 = num1 + block;
				float p = (j - (num_j*height_block + height_block / 2)) / (1.0f*height_block);
				float q = 1 - p;
				*(m_pImage2 + j*m_nDibWidth + i) = (q*C[num1][((int)(*(m_pImage + j*m_nDibWidth + i)))] + p*C[num2][((int)(*(m_pImage + j*m_nDibWidth + i)))]) * 255;
				
			}
			else if (j <= height_block / 2) {
				//线性插值  
				int num_i = (i - width_block / 2) / width_block;
				int num_j = 0;
				int num1 = num_j*block + num_i;
				int num2 = num1 + 1;
				float p = (i - (num_i*width_block + width_block / 2)) / (1.0f*width_block);
				float q = 1 - p;
				*(m_pImage2 + j*m_nDibWidth + i) = (q*C[num1][((int)(*(m_pImage + j*m_nDibWidth + i)))] + p*C[num2][((int)(*(m_pImage + j*m_nDibWidth + i)))]) * 255;
				
			}
			else if (j >= ((block - 1)*height_block + height_block / 2)) {
				//线性插值  
				int num_i = (i - width_block / 2) / width_block;
				int num_j = block - 1;
				int num1 = num_j*block + num_i;
				int num2 = num1 + 1;
				float p = (i - (num_i*width_block + width_block / 2)) / (1.0f*width_block);
				float q = 1 - p;
				*(m_pImage2 + j*m_nDibWidth + i) = (q*C[num1][((int)(*(m_pImage + j*m_nDibWidth + i)))] + p*C[num2][((int)(*(m_pImage + j*m_nDibWidth + i)))]) * 255;
				
			}

			//inner area  
			else {
				int num_i = (i - width_block / 2) / width_block;
				int num_j = (j - height_block / 2) / height_block;
				int num1 = num_j*block + num_i;
				int num2 = num1 + 1;
				int num3 = num1 + block;
				int num4 = num2 + block;
				float u = (i - (num_i*width_block + width_block / 2)) / (1.0f*width_block);
				float v = (j - (num_j*height_block + height_block / 2)) / (1.0f*height_block);
				*(m_pImage2 + j * m_nDibWidth + i) = (int)((u*v*C[num4][((int)(*(m_pImage + j*m_nDibWidth + i)))] +
					(1 - v)*(1 - u)*C[num1][((int)(*(m_pImage + j*m_nDibWidth + i)))] +
					u*(1 - v)*C[num2][((int)(*(m_pImage + j*m_nDibWidth + i)))] +
					v*(1 - u)*C[num3][((int)(*(m_pImage + j*m_nDibWidth + i)))]) * 255);

			}
			*(m_pImage2 + j*m_nDibWidth + i) = *(m_pImage2 + j*m_nDibWidth + i) + (*(m_pImage2 + j*m_nDibWidth + i) << 8) + (*(m_pImage2 + j*m_nDibWidth + i) << 16);
		}
	}

只能说:灰度图片的效果对比度是提升了,但其色彩的不丰富性导致看起来可能不咋地。

              所以彩色图片的效果会更好些。

 

  • 3
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

GallagherZ

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值