六、直方图均衡化
直方图均衡化又称直方图修平,是一种很重要的非线性点运算。使用该方法可以加强图像的局部对比度,尤其是当图像的有用数据的对比度相当接近的时候。通过这种方法,亮度可以更好的在直方图上分布。直方图均衡化的基本思想是把原始图像的直方图变换为均匀分布的形式。这样增加了灰度值的动态范围,从而达到增强图像整体对比度的效果。
计算步骤
1)计算图像f(x,y)的各灰度级中像素出现的概率p(i)。
2) 计算p的累计概率函数c(i),c即为图像的累计归一化直方图
3)将c(i)缩放至0~255范围内
Rectangle rect = new Rectangle(0, 0, curBitmap.Width, curBitmap.Height);
System.Drawing.Imaging.BitmapData bmpData = curBitmap.LockBits(rect, System.Drawing.Imaging.ImageLockMode.ReadWrite, curBitmap.PixelFormat);
IntPtr ptr = bmpData.Scan0;
int bytes = curBitmap.Width * curBitmap.Height;
byte[] grayValues = new byte[bytes];
System.Runtime.InteropServices.Marshal.Copy(ptr, grayValues, 0, bytes);
byte temp;
int[] tempArray = new int[256];
int[] countPixel = new int[256];
byte[] pixelMap = new byte[256];
//计算各级灰度的像素个数
for (int i = 0; i < bytes; i++)
{
//灰度级
temp = grayValues[i];
//计数加1
countPixel[temp]++;
}
//计算各级灰度累计分布函数
for (int i = 0; i < 256; i++)
{
if(i!=0)
{
tempArray[i] = tempArray[i - 1] + countPixel[i];
}
else
{
tempArray[i] = countPixel[i];
}
pixelMap[i] = (byte)(255.0 * tempArray[i] / bytes + 0.5);
}
for (int i=0; i<bytes; i++)
{
temp = grayValues[i];
grayValues[i] = pixelMap[temp];
}
System.Runtime.InteropServices.Marshal.Copy(grayValues, 0, ptr, bytes);
curBitmap.UnlockBits(bmpData);
pictureBox1.Image = curBitmap;
左图为原图,右图为均衡后的图
七、直方图匹配
直方图匹配,又称直方图规定化,即变换原图的直方图为规定的某种形式的直方图,即将某幅影像或某一区域的直方图匹配到另一幅影像上。使两幅影像的色调保持一致而进行的图像增强方法。直方图匹配本质上是让两幅图像的累积直方图尽量相似,累积直方图相似了,直方图也就相似了。
目的:将图片B的直方图匹配到图片A上
步骤1:首先获取图片B的累计分布函数数组
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
namespace point_operation
{
public partial class shapingForm : Form
{
public shapingForm()
{
InitializeComponent();
shapingPixel = new int[256];
cumHist = new double[256];
}
private void open_Click(object sender, EventArgs e)
{
OpenFileDialog opnDlg = new OpenFileDialog();
opnDlg.Filter = "所有图像文件 | *.bmp; *.pcx; *.png; *.jpg; *.gif;" +
"*.tif; *.ico; *.dxf; *.cgm; *.cdr; *.wmf; *.eps; *.emf|" +
"位图( *.bmp; *.jpg; *.png;...) | *.bmp; *.pcx; *.png; *.jpg; *.gif; *.tif; *.ico|" +
"矢量图( *.wmf; *.eps; *.emf;...) | *.dxf; *.cgm; *.cdr; *.wmf; *.eps; *.emf";
opnDlg.Title = "打开图像文件";
opnDlg.ShowHelp = true;
if (opnDlg.ShowDialog() == DialogResult.OK)
{
shapingFileName = opnDlg.FileName;
try
{
shapingBitmap = (Bitmap)Image.FromFile(shapingFileName);
}
catch (Exception exp)
{
MessageBox.Show(exp.Message);
}
Rectangle rect = new Rectangle(0, 0, shapingBitmap.Width, shapingBitmap.Height);
System.Drawing.Imaging.BitmapData bmpData = shapingBitmap.LockBits(rect, System.Drawing.Imaging.ImageLockMode.ReadWrite, shapingBitmap.PixelFormat);
IntPtr ptr = bmpData.Scan0;
shapingSize = shapingBitmap.Width * shapingBitmap.Height;
byte[] grayValues = new byte[shapingSize];
System.Runtime.InteropServices.Marshal.Copy(ptr, grayValues, 0, shapingSize);
byte temp = 0;
maxPixel = 0;
Array.Clear(shapingPixel,0,256);
for (int i = 0; i < shapingSize; i++)
{
temp = grayValues[i];
shapingPixel[temp]++;
if (shapingPixel[temp] > maxPixel)
{
maxPixel = shapingPixel[temp];
}
}
System.Runtime.InteropServices.Marshal.Copy(grayValues, 0, ptr, shapingSize);
shapingBitmap.UnlockBits(bmpData);
}
Invalidate();
}
private void startShaping_Click(object sender, EventArgs e)
{
this.DialogResult = DialogResult.OK;
}
private void close_Click(object sender, EventArgs e)
{
this.Close();
}
private void shapingForm_Paint(object sender, PaintEventArgs e)
{
if (shapingBitmap != null)
{
Pen curPen = new Pen(Brushes.Black, 1);
Graphics g = e.Graphics;
g.DrawLine(curPen, 50, 240, 320, 240);
g.DrawLine(curPen, 50, 240, 50, 30);
g.DrawLine(curPen, 100, 240, 100, 242);
g.DrawLine(curPen, 150, 240, 150, 242);
g.DrawLine(curPen, 200, 240, 200, 242);
g.DrawLine(curPen, 250, 240, 250, 242);
g.DrawLine(curPen, 300, 240, 300, 242);
g.DrawString("0", new Font("New Timer", 8), Brushes.Black, new PointF(46, 242));
g.DrawString("50", new Font("New Timer", 8), Brushes.Black, new PointF(92, 242));
g.DrawString("100", new Font("New Timer", 8), Brushes.Black, new PointF(139, 242));
g.DrawString("150", new Font("New Timer", 8), Brushes.Black, new PointF(189, 242));
g.DrawString("200", new Font("New Timer", 8), Brushes.Black, new PointF(239, 242));
g.DrawString("250", new Font("New Timer", 8), Brushes.Black, new PointF(289, 242));
g.DrawLine(curPen, 48, 40, 50, 40);
g.DrawString("0", new Font("New Timer", 8), Brushes.Black, new PointF(34, 234));
g.DrawString(maxPixel.ToString(), new Font("New Timer", 8), Brushes.Black, new PointF(18, 34));
double temp = 0;
int[] tempArray = new int[256];
for (int i = 0; i < 256; i++)
{
temp = 200 * (double)shapingPixel[i] / (double)maxPixel;
g.DrawLine(curPen, 50 + i, 240, 50 + i, 240 - (int)temp);
if (i != 0)
{
tempArray[i] = tempArray[i - 1] + shapingPixel[i];
}
else
{
tempArray[0] = shapingPixel[0];
}
cumHist[i] = (double)tempArray[i] / (double)shapingSize;
}
curPen.Dispose();
}
}
public double[] ApplicationP
{
get
{
return cumHist;
}
}
}
}
步骤2: 映射
private void shaping_Click(object sender, EventArgs e)
{
if (curBitmap != null)
{
shapingForm sForm = new shapingForm();
if (sForm.ShowDialog() == DialogResult.OK)
{
Rectangle rect = new Rectangle(0, 0, curBitmap.Width, curBitmap.Height);
System.Drawing.Imaging.BitmapData bmpData = curBitmap.LockBits(rect, System.Drawing.Imaging.ImageLockMode.ReadWrite, curBitmap.PixelFormat);
IntPtr ptr = bmpData.Scan0;
int bytes = curBitmap.Width * curBitmap.Height;
byte[] grayValues = new byte[bytes];
System.Runtime.InteropServices.Marshal.Copy(ptr, grayValues, 0, bytes);
byte temp = 0;
double[] PPixel = new double[256];
double[] QPixel = new double[256];
int[] qPixel = new int[256];
int[] tempArray = new int[256];
for (int i = 0; i < grayValues.Length; i++)
{
temp = grayValues[i];
qPixel[temp]++;
}
for (int i = 0; i < 256; i++)
{
if (i != 0)
{
tempArray[i] = tempArray[i - 1] + qPixel[i];
}
else
{
tempArray[0] = qPixel[0];
}
QPixel[i] = (double)tempArray[i] / (double)bytes;
}
PPixel = sForm.ApplicationP;
double diffA, diffB;
byte k = 0;
byte[] mapPixel = new byte[256];
//进行直方图匹配
for (int i = 0; i < 256; i++)
{
diffB = 1;
for (int j = k; j < 256; j++)
{
//找到两个累计分布函数中最相似的位置
diffA = Math.Abs(QPixel[i] - PPixel[j]);
if (diffA - diffB < 1.0E-08)
{
//记录下差值
diffB = diffA;
k = (byte)j;
}
else
{
//找到位置记录下来,并退出内层循环
k = (byte)(j - 1);
break;
}
}
//达到最大灰度级,退出外层循环
if (k == 255)
{
for (int l = i; l < 256; l++)
{
mapPixel[l] = k;
}
break;
}
//得到映射关系
mapPixel[i] = k;
}
//进行灰度映射
for (int i = 0; i < bytes; i++)
{
temp = grayValues[i];
grayValues[i] = mapPixel[temp];
}
System.Runtime.InteropServices.Marshal.Copy(grayValues, 0, ptr, bytes);
curBitmap.UnlockBits(bmpData);
}
Invalidate();
}
}