(1)直方图伸展以及直方图均衡化
观察某些图像的释放图可以很容易看到,整个可用的强度值范围并没有被完全利用,特别是图像中比较亮的强度值。这里,通过伸展直方图来生成一个对比度更高的图像。
然后,利用EMgucv的自带函数进行直方图均衡化,值得注意的是,函数库里面的直方图均衡命令是针对灰度值而言的,那么,在处理彩色图像的时候,要么将其转换为灰度图像,要么针对BGR三个通道的直方图分别进行均衡,然后将三幅单通道图像合并得到最后的彩色均衡化图像,也是本节的方案。
//基于查找表的直方图伸展,图像增强
private void button39_Click(object sender, EventArgs e)
{
if (chapter4Img.IsEmpty)
return;
var dhData = getDenseHistogramDataOfImage(chapter4Img);//默认直方图256Bins,像素值方位[0.255]
RangeF[] minValueAndMaxVlue = new RangeF[3];
float minValue = 0.01f;//忽略数量少于minValue的箱子,定义数值范围0-1
if (minValue < 0)
minValue = 0;
else if (minValue > 1)
minValue = 1;
minValue = chapter4Img.Rows * chapter4Img.Cols * minValue;//计算得到最小箱子
for(int i=0;i<dhData.Length;i++)
{
if(dhData[i]==null)
{
minValueAndMaxVlue[i].Max = minValueAndMaxVlue[i].Min = -1f;//及不存在这个通道的数据
continue;
}
minValueAndMaxVlue[i].Min = 0f;
for (;minValueAndMaxVlue[i].Min < dhData[i].GetBinValues().Length; minValueAndMaxVlue[i].Min+=1)
{
if (dhData[i].GetBinValues()[(int)minValueAndMaxVlue[i].Min] > minValue)
break;
}
minValueAndMaxVlue[i].Max = dhData[i].GetBinValues().Length - 1;
for(;minValueAndMaxVlue[i].Max>=0;minValueAndMaxVlue[i].Max-=1)
{
if (dhData[i].GetBinValues()[(int)minValueAndMaxVlue[i].Max] > minValue)
break;
}
}
var lut = new Image<Bgr, byte>(256, 1);
List<byte[]> arrayData = new List<byte[]>();
arrayData.Add(new byte[256]);
arrayData.Add(new byte[256]);
arrayData.Add(new byte[256]);
if (chapter4Img.NumberOfChannels==1)
{
for(int i=0;i<256;i++)
{
if (i < minValueAndMaxVlue[0].Min)
arrayData[0][i] = 0;
else if (i > minValueAndMaxVlue[0].Max)
arrayData[0][i] = 255;
else
arrayData[0][i] = (byte)Math.Round(255.0 * (i - minValueAndMaxVlue[0].Min) / (minValueAndMaxVlue[0].Max - minValueAndMaxVlue[0].Min));
}
}
else//对每个通道进行计算,得到范围
{
for(int index=0;index<3;index++)
{
arrayData[index] = new byte[256];
for (int i = 0; i < 256; i++)
{
if (i < minValueAndMaxVlue[index].Min)
arrayData[index][i] = 0;
else if (i > minValueAndMaxVlue[0].Max)
arrayData[index][i] = 255;
else
arrayData[index][i] = (byte)Math.Round(255.0 * (i - minValueAndMaxVlue[index].Min) / (minValueAndMaxVlue[index].Max - minValueAndMaxVlue[0].Min));
}
}
}
for(int i=0;i<256;i++)
{
for(int j=0;j<3;j++)
{
lut.Data[0, i, j] = arrayData[j][i];
}
}
Mat resultImg = new Mat();
if(chapter4Img.NumberOfChannels==1)
{
CvInvoke.LUT(chapter4Img, lut.Split()[0].Mat, resultImg);
}
else
{
CvInvoke.LUT(chapter4Img, lut.Split()[0].Mat, resultImg);
}
CvInvoke.NamedWindow("Based on One Channel (Blue)", NamedWindowType.Normal);
CvInvoke.Imshow("Based on One Channel (Blue)", resultImg);
//对所有的通道取同样的minValueAndMaxValue范围计算
arrayData.Add(new byte[256]);//再加一个数组
int newMinValue = Math.Min((int)Math.Min(minValueAndMaxVlue[0].Min, minValueAndMaxVlue[1].Min), (int)minValueAndMaxVlue[2].Min);
int newMaxValue= Math.Max((int)Math.Max(minValueAndMaxVlue[0].Max, minValueAndMaxVlue[1].Max), (int)minValueAndMaxVlue[2].Max);
for(int i=0;i<256;i++)
{
if (i < newMinValue)
arrayData[3][i] = 0;
else if (i > newMaxValue)
arrayData[3][i] = 255;
else
arrayData[3][i] = (byte)((255.0*(i - newMinValue) / (newMaxValue - newMinValue)));
}
var newLut = new Mat(1, 256, DepthType.Cv8U, 1);
newLut.SetTo(arrayData[3]);
if(chapter4Img.NumberOfChannels==3)
{
CvInvoke.LUT(chapter4Img, newLut, resultImg);
CvInvoke.NamedWindow("Based on BGR three Channels", NamedWindowType.KeepRatio);
CvInvoke.Ims