我是靠谱客的博主 寒冷鸡翅,最近开发中收集的这篇文章主要介绍使用C++实现彩色图像直方图均衡化的三种方法引言先导知识算法实现,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

引言

本文主要介绍如何实现彩色图像的直方图均衡化,达到图像增强效果的三种方法:

1. 对RGB三个通道图像分别进行直方图均衡化,然后再合并三个通道;

2. 提取RGB三个通道图像,计算其平均直方图结果,然后再进行均衡化;

3. RGB空间转为HSI空间图像,对I(亮度,Intensity)通道进行直方图均衡化,再转为RGB图像。

第一种方法不推荐,会破坏色彩结构;根据情况选择第2,3种方法。

 

先导知识

直方图

首先必须了解灰度直方图是什么东西。直方图就是统计一个图像各灰度级值0~255有多少各像素点。

 

单通道均衡化

在实现之前先了解单通道图像(灰度图)直方图均衡化和其过程。

上述过程就是求出一个原像素点到均衡化的像素点的一个映射函数 f(x)。利用该映射函数就可以循环扫描图像的每一个像素x,然后得到f(x)替代原来的像素值x,达到均衡化的结果。

在实际均衡化过程中,核心步骤如下:
1. 传入单通道图像和该的灰度直方图。
2. 遍历灰度直方图,对值 I 从 0~255 累计求和,对累计求和,对和结果除以图像的素数,然后乘以 L-1得到函数结果 得到函数结果 f(xi )。
3. 将每一个灰度值 i累积求和的结果 累积求和的结果 f(xi )存储在一个大小为 256 的 int 数组中,存储的位置为 i;
4. 遍历输入图像每一个素,记点值为 x,修改其像素值使等于 f(x)。
5. 均衡化结束。

 

算法实现

单通道均衡化

主要步骤如下,EqualizedResult就是均衡化的映射函数,下一步骤就是将像素点值作为映射函数的输入,将输出结果替代原来的像素值。


// 功能:对灰度直方图进行均衡化
// 输入:单通道CImg对象, 灰度图对象
// 输出:均衡化结果
CImg<unsigned int> HistogramEqualization::HistogramEqualizationMethod
(CImg<unsigned int> InputImage,CImg<unsigned int>  Histogram)
{
	int L = 256; //灰度级
	int NumOfPixels = (InputImage)._width * (InputImage)._height;

	double CumulativeDistributionFunction[256] = { 0 }; // 灰度直方图的累积分布
	double EqualizedResult[256] = { 0 };               //  均衡化结果映射函数
	/*直方图就对应于概率密度函数pdf,
	而概率分布函数cdf就是直方图的累积和,
	即概率密度函数的积分
	积分*(L(=255)-1)*/
	
	/*均衡化关键步骤*/
	int count = 0;
	cimg_forX(Histogram, x) {
		count += Histogram[x];  // 累计求和
		CumulativeDistributionFunction[x] = 1.0 * count / NumOfPixels;  //计算概率
		EqualizedResult[x] = round(CumulativeDistributionFunction[x] * (L - 1)); // 计算概率密度,round四舍五入
	}

	/*输出均衡化结果*/
	CImg<unsigned int> OutputImage((InputImage)._width, (InputImage)._height, 1, 1, 0);
	cimg_forXY(OutputImage, x, y) // calculate histogram equalization result
		OutputImage(x, y, 0) = EqualizedResult[(InputImage)(x, y)];
	return OutputImage;
}

 

独立RGB通道均衡化


/*功能: 分别对彩色图的三个通道分开求解均衡化结果,然后合并*/
/*输入: 均衡化图像文件名*/
/*输出: 彩色图均衡化结果*/
CImg<unsigned int> HistogramEqualization::Hist_Equal_ColorImage_OneColorChannel(string ImageFileName)
{
	CImg<unsigned int> ColorImage;
	ColorImage.load_bmp(ImageFileName.c_str());
	CImg<unsigned int> R_Channel = HistogramEqualizationMethod(ColorImage.get_channel(0),
		GetHistogram(ColorImage.get_channel(0)));
	CImg<unsigned int> G_Channel = HistogramEqualizationMethod(ColorImage.get_channel(1),
		GetHistogram(ColorImage.get_channel(1)));
	CImg<unsigned int> B_Channel = HistogramEqualizationMethod(ColorImage.get_channel(2), 
		GetHistogram(ColorImage.get_channel(2)));

	CImg<unsigned int> EqualizedImage = ColorImage;
	cimg_forXY(ColorImage, x, y) {
		EqualizedImage(x, y, 0) = R_Channel(x, y, 0);
		EqualizedImage(x, y, 1) = G_Channel(x, y, 0);
		EqualizedImage(x, y, 2) = B_Channel(x, y, 0);
	}
	if (show) EqualizedImage.display("通道独立均衡化结果");
	char FileName[100] = {};
	sprintf_s(FileName, "%d_OneChannels_equalize_%s", number++, ImageFileName.c_str());
	EqualizedImage.save(FileName);
	return EqualizedImage;
}

 

三通道直方图平均后均衡化


/*传入三个通道图像计算平均亮度直方图*/
CImg<unsigned int> HistogramEqualization::GetAverageHistogram
(CImg<unsigned int> img1, CImg<unsigned int> img2, CImg<unsigned int> img3)
{
	CImg<unsigned int> histogram(256, 1, 1, 1, 0);
	cimg_forXY(img1, x, y) {
		++histogram[(int)img1(x, y)];
		++histogram[(int)img2(x, y)];
		++histogram[(int)img3(x, y)];
	}
	cimg_forX(histogram, pos) histogram(pos) /= 3;
	return histogram;
}


// 功能:对彩色图进行直方图均衡化,先求三个通道的平均直方图
// 输入: 彩色图文件名
// 输出: 均衡化结果
CImg<unsigned int> HistogramEqualization::Hist_Equal_ColorImage_ThreeColorChannels(string ImageFileName)
{
	CImg<unsigned int> ColorImage;
	ColorImage.load_bmp(ImageFileName.c_str());
	CImg<unsigned int> R_Channel = ColorImage.get_channel(0);
	CImg<unsigned int> G_Channel = ColorImage.get_channel(1);
	CImg<unsigned int> B_Channel = ColorImage.get_channel(2);
	CImg<unsigned int> AverageHistogram = GetAverageHistogram(R_Channel, G_Channel, B_Channel);

	double CumulativeDistributionFunction[256] = { 0 }; // 灰度直方图的累积分布
	double EqualizedResult[256] = { 0 };          // 均衡化结果图
	int count = 0;
	int L = 256;
	int NumOfPixels = ColorImage._height * ColorImage._width;
	cimg_forX(AverageHistogram, pos) {
		count += AverageHistogram[pos];
		CumulativeDistributionFunction[pos] = 1.0 * count / NumOfPixels;
		EqualizedResult[pos] = round(CumulativeDistributionFunction[pos] * (L - 1));
	}
	CImg<unsigned int> EqualizedImage = ColorImage;
	cimg_forXY(EqualizedImage, x, y) {
		EqualizedImage(x, y, 0) = EqualizedResult[R_Channel(x, y)];
		EqualizedImage(x, y, 1) = EqualizedResult[G_Channel(x, y)];
		EqualizedImage(x, y, 2) = EqualizedResult[B_Channel(x, y)];
	}
	if (show) EqualizedImage.display("三通道直方图平均后进行均衡化的结果");
	char FileName[100] = {};
	sprintf_s(FileName, "%d_Threechannels_equalize_%s", number++, ImageFileName.c_str());
	EqualizedImage.save(FileName);
	return EqualizedImage;
}

 

HSI空间下均衡化

这个略复杂。。

RGB转HSI空间公式:

HSI转RGB空间公式:

 


/*功能:在HSI空间下进行均衡化,然后再转回RGB空间*/
CImg<double> HistogramEqualization::Hist_Equal_ColorImage_HSISpace(string ImageFileName)
{
	CImg<unsigned int> ColorImage;
	ColorImage.load(ImageFileName.c_str());
	// 获取RGB通道图像,并归一化
	CImg<double> R_Channel = ColorImage.get_channel(0)* 1.0 / 255.0;
	CImg<double> G_Channel = ColorImage.get_channel(1) * 1.0 / 255.0;
	CImg<double> B_Channel = ColorImage.get_channel(2) * 1.0 / 255.0;
	
	int w = ColorImage._width;
	int h = ColorImage._height;

	// HSI 
	CImg<double> Hue(w, h, 1, 1, 0);
	CImg<double> Saturation(w, h, 1, 1, 0);
	CImg<double> Intensity(w, h, 1, 1, 0);

	// for calculate Hue
	CImg<double> theta(w, h, 1, 1, 0);
	cimg_forXY(Hue, x, y) {
		double numerator = R_Channel(x, y, 0) - G_Channel(x, y, 0) + R_Channel(x, y, 0) - B_Channel(x, y, 0);
		double denominator = 2.0 * sqrt((R_Channel(x, y, 0) - G_Channel(x, y, 0)) * (R_Channel(x, y, 0) - G_Channel(x, y, 0))
			+ (R_Channel(x, y, 0) - B_Channel(x, y, 0))*(G_Channel(x, y, 0) - B_Channel(x, y, 0)));
		theta(x, y, 0) =  acos(numerator / denominator);
	}

	cimg_forXY(Hue, x, y) {
		if (G_Channel(x, y, 0) >= B_Channel(x, y, 0)) {
			Hue(x, y, 0) = theta(x, y, 0);
		}
		else {
			Hue(x, y, 0) = 2 * cimg::PI - theta(x, y, 0);
		}
	}

	// calculate saturation and intensity
	cimg_forXY(Intensity, x, y) { 
		double deno = (R_Channel(x, y, 0) + G_Channel(x, y, 0) + B_Channel(x, y, 0));
		if (deno == 0) deno = 1e-12f;  // 取极小,近似0
		Saturation(x, y, 0) = 1.0 - 3.0 * cimg::min(R_Channel(x, y, 0), B_Channel(x, y, 0), G_Channel(x, y, 0))
			/ deno;
		Intensity(x, y, 0) = 1.0 * (R_Channel(x, y, 0) + G_Channel(x, y, 0) + B_Channel(x, y, 0)) / 3.0;
		if (Saturation(x, y, 0) == 0) Hue(x, y, 0) = 0;  // 黑色
	}
	CImg<unsigned int> tmp_Intensity(w, h, 1, 1, 0);  // 亮度图像 0~255
	cimg_forXY(tmp_Intensity, x, y) {
		tmp_Intensity(x, y, 0) = floor(Intensity(x, y, 0) * 255);
	}
	
	CImg<unsigned int> I_Histogram = GetHistogram(tmp_Intensity); // 亮度直方图,由于rgb通道值/255,需要扩大255
	tmp_Intensity = HistogramEqualizationMethod(tmp_Intensity, I_Histogram); // 亮度直方图均衡化
	cimg_forXY(Intensity, x, y) {
		Intensity(x, y, 0) = tmp_Intensity(x, y, 0) * 1.0 / 255.0;
	}

	CImg<double> EqualizedImage(w, h, 1, 3, 0);

	cimg_forXY(Intensity, x, y) {
		if (Hue(x, y, 0) < 2 * cimg::PI / 3 && Hue(x, y, 0) >= 0) { //RG sector
			EqualizedImage(x, y, 2) = Intensity(x, y, 0) * (1 - Saturation(x,y,0));
			EqualizedImage(x, y, 0) = Intensity(x, y, 0) *(1 + Saturation(x, y, 0) * cos(Hue(x, y, 0)) / cos(cimg::PI / 3 - Hue(x,y,0)));
			EqualizedImage(x, y, 1) = 3 * Intensity(x, y, 0) - (EqualizedImage(x,y,2) + EqualizedImage(x, y, 0));
		}
		else if (Hue(x, y, 0) < 4 * cimg::PI / 3 && Hue(x, y, 0) >= 2 * cimg::PI / 3) { //GB sector
			EqualizedImage(x, y, 0) = Intensity(x, y, 0) * (1 - Saturation(x, y, 0));
			EqualizedImage(x, y, 1) = Intensity(x, y, 0) *(1 + Saturation(x, y, 0) * cos(Hue(x, y, 0) - 2*cimg::PI/3) / cos(cimg::PI - Hue(x, y, 0)));
			EqualizedImage(x, y, 2) = 3 * Intensity(x, y, 0) - (EqualizedImage(x, y, 1) + EqualizedImage(x, y, 0));
		}
		else if (Hue(x, y, 0) <= 2 * cimg::PI  && Hue(x, y, 0) >= 4 * cimg::PI / 3) { // BR sector
			EqualizedImage(x, y, 1) = Intensity(x, y, 0) * (1 - Saturation(x, y, 0));
			EqualizedImage(x, y, 2) = Intensity(x, y, 0) *(1 + Saturation(x, y, 0) * cos(Hue(x, y, 0) - 4 * cimg::PI / 3) / cos(5 * cimg::PI / 3 - Hue(x, y, 0)));
			EqualizedImage(x, y, 0) = 3 * Intensity(x, y, 0) - (EqualizedImage(x, y, 1) + EqualizedImage(x, y, 2));
		}
	}
	
	CImg<unsigned int> resultImage(w, h, 1, 3, 0);
	cimg_forXY(EqualizedImage, x, y) {
		resultImage(x, y, 0) = 255 * min(max(EqualizedImage(x, y, 0), 0.0), 1.0);
		resultImage(x, y, 1) = 255 * min(max(EqualizedImage(x, y, 1), 0.0), 1.0);
		resultImage(x, y, 2) = 255 * min(max(EqualizedImage(x, y, 2), 0.0), 1.0);
	}
	//resultImage = resultImage.normalize(0, 255);
	if (show) resultImage.display("HSI空间下均衡化的结果");
	char FileName[100] = {};
	//sprintf_s(FileName, "%d_HSI_equalize_%s", number++, ImageFileName.c_str());
	//resultImage.save(FileName);
	return resultImage;
}

 

 

最后

以上就是寒冷鸡翅为你收集整理的使用C++实现彩色图像直方图均衡化的三种方法引言先导知识算法实现的全部内容,希望文章能够帮你解决使用C++实现彩色图像直方图均衡化的三种方法引言先导知识算法实现所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(35)

评论列表共有 0 条评论

立即
投稿
返回
顶部