【数字图像处理】VC++实现分段线性拉伸

  • Post author:
  • Post category:其他




1.算法原理

分段线性拉伸算法是图像灰度变换中常用的算法,在商业图像编辑软件Photoshop中也有相应的功能。分段线性拉伸主要是利用图像对比度,突显图像细节。设输入图像为F(x),输出图像为G(x),分段区间为[start , end]映射区间为[sout, eout]。分段线性拉伸示意图如下:

在这里插入图片描述

图为分段线性拉伸示意图,从图中可以明显得到,分段线性拉伸算法需要明确4个参数Start、End、Sout以及Eout。当这四个参数均已知时,根据两点确定直线法,计算出直线L1、L2和L3的参数,分别为(K1、C1=0)、(K2、C2)和(K2、C2)。那么分段线性拉伸算法的公式如下:

在这里插入图片描述

对于参数分段区间[start, end]以及映射区间[sout, eout], 有人工设定、基于直方图设定等办法,下面实现核心算法。



2.算法实现

由于分段线性拉伸也是图像灰度变换的一种,代码如下所示:

//分段线性拉伸
//fStart :分段区间起点
//fEnd : 分段区间终点
//fSout :映射区间起点
//fEout :映射区间终点
void dividedLinearStrength(BYTE *SrcImage, BYTE *DstImage, int nWidth, int nHeight, float fStart, float fEnd, float fSout, float fEout)
{
	//计算直线L1参数
	float fk1 = fSout / fStart;
	//L2
	float fk2 = (fEout - fSout)/(fEnd - fStart);
	float fc2 = fSout - fk2 * fStart;
	//L3
	float fk3 = (255.0f - fEout)/(255.0f - fEnd);
	float fc3 = 255.0f - fk3*255.0f;

	//建立查询表
	vector<unsigned char> loolupTabel(256);
	for (int m=0;m<256;m++)
	{
		if (m<fStart)
		{
			loolupTabel[m]=(m*fk1);
		}
		else if (m>fEnd)
		{
			loolupTabel[m] = (m*fk3 + fc3);
		}
		else
		{
			loolupTabel[m] = (m*fk2+fc2);
		}
	}
	//灰度映射
	for (int i=0;i<nWidth*nHeight;i++)
	{
		DstImage[i]=loolupTabel[SrcImage[i]];
	}
}

结果如下:

在这里插入图片描述

3.基于直方图的分段线性拉伸

基于直方图的分段线性拉伸算法主要改进在于,通过从直方图自动地计算出分段区间和映射区间四个参数。本质上,直方图是对图像像素进行排序的一个过程。根据分段线性拉伸的原理,对图像像素进行升序排序后,去高灰度等级NH个点对应的最小灰度作为fEnd,取低灰度等级NL个点对应的最大灰度等级作为fStart,fSout=fStart * Sigma, fEout=fEnd *(1+sigma),sigma<1。具体代码实现步骤为:

(1).统计直方图;

(2).计算分段区间和映射区间。为使参数与图像尺寸无关,使用比例的方法限定NH和NL。设图像尺寸MXN,高灰度等级个数比例为fH、低灰度等级个数比例为fL。

代码如下所示:

//基于直方图的分段线性拉伸
//fH:高灰度等级比例
//fL:低灰度等级比例
//fSigma:拉伸系数
void dlsBaseHistogram(BYTE *SrcImage, int bit,BYTE *DstImage, int nWidth, int nHeight, float fH, float fL, float fSigma)
{
	//统计直方图
	vector<int> histogram(256);
	if (bit=8)
	{
		LONG i;
		LONG j;
		LONG lLineBytes = (nWidth*bit/8+3)/4*4;
		int m_imgSize = nWidth*nHeight;
		//初始化直方图矩阵
		for (int k=0;k<256;k++)
		{
			histogram[k]=0;
		}
		//统计灰度
		for (i=0;i<nWidth;i++)
		{
			for (j=0;j<lLineBytes;j++)
			{
				histogram[SrcImage[lLineBytes*i+j]]++;
			}
		}
	}

	//计算分段区间
	int nNH = nWidth*nHeight*fH;
	int nNL = nWidth*nHeight*fL;
	int nAcc=0;
	float fStart =0 ,fEnd = 0;

	for (int m=255;m>=0;m--)
	{
		nAcc += histogram[m];
		if (nAcc>nNH)
		{
			fEnd = m;
			break;
		}
	}

	nAcc=0;
	for (int m=0;m<histogram.size();m++)
	{
		nAcc += histogram[m];
		if (nAcc>nNL)
		{
			fStart = m;
			break;
		}
	}

	//计算映射区间
	float fSout = fStart*fSigma;
	float fEout = fEnd * (fSigma + 1.0f);
	fEout = fEout >255.0f ? 254 : fEout;

	//分段线性拉伸
	dividedLinearStrength(SrcImage,DstImage,nWidth,nHeight,fStart,fEnd,fSout,fEout);
}

结果如下:

在这里插入图片描述

在本例中参数fH=0.2、fL=0.5、fSigma=0.5。



版权声明:本文为weixin_42415138原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。