在进行边沿检测前先对当前图像做相关操作,m_Bitmap是当前图像
Rectangle rect = new Rectangle(0, 0, m_Bitmap.Width, m_Bitmap.Height);
BitmapData bmpData = m_Bitmap.LockBits(rect, System.Drawing.Imaging.ImageLockMode.ReadWrite, m_Bitmap.PixelFormat);
IntPtr ptr = bmpData.Scan0;
int bytes = m_Bitmap.Width * m_Bitmap.Height*3 ;
byte[] grayValues = new byte[bytes];
System.Runtime.InteropServices.Marshal.Copy(ptr, grayValues, 0, bytes);
设置相关变量
//得到阈值
byte[] thresh = new byte[2];
thresh[0] = Convert.ToByte(60);//根据实际需求改动
thresh[1] = Convert.ToByte(25);//根据实际需求改动
//得到均方差
double sigema = 1.5;//根据实际需求改动
double[] tempArray;
double[] tempImage = new double[bytes];
double[] grad = new double[bytes];
byte[] aLable = new byte[bytes];
double[] edgeMap = new double[bytes];
double gradX, gradY, angle;
高斯模板半径
//高斯模板半径=3sigema
int rad = Convert.ToInt16(Math.Ceiling(3 * sigema));
for (int i = 0; i < bytes; i++)
{
tempImage[i] = Convert.ToDouble(grayValues[i]);
}
//调用高斯平滑处理方法,在最下面会把该方法给出来
gaussSmooth(tempImage, out tempArray, sigema);
//sobel一阶偏导求梯度幅值和方向
for (int i = 0; i < m_Bitmap.Height; i++)
{
for (int j = 0; j < m_Bitmap.Width; j++)
{
//水平方向梯度
gradX = tempArray[((Math.Abs(i - 1)) % m_Bitmap.Height) * m_Bitmap.Width + ((j + 1) % m_Bitmap.Width)] + 2 * tempArray[i * m_Bitmap.Width + ((j + 1) % m_Bitmap.Width)] + tempArray[((i + 1) % m_Bitmap.Height) * m_Bitmap.Width + ((j + 1) % m_Bitmap.Width)] - tempArray[((Math.Abs(i - 1)) % m_Bitmap.Height) * m_Bitmap.Width + ((Math.Abs(j - 1)) % m_Bitmap.Width)] - 2 * tempArray[i * m_Bitmap.Width + ((Math.Abs(j - 1)) % m_Bitmap.Width)] - tempArray[((i + 1) % m_Bitmap.Height) * m_Bitmap.Width + ((Math.Abs(j - 1)) % m_Bitmap.Width)];
//垂直方向梯度
gradY = tempArray[((Math.Abs(i - 1)) % m_Bitmap.Height) * m_Bitmap.Width + ((Math.Abs(j - 1)) % m_Bitmap.Width)] + 2 * tempArray[((Math.Abs(i - 1)) % m_Bitmap.Height) * m_Bitmap.Width + j] + tempArray[((Math.Abs(i - 1)) % m_Bitmap.Height) * m_Bitmap.Width + ((j + 1) % m_Bitmap.Width)] - tempArray[((i + 1) % m_Bitmap.Height) * m_Bitmap.Width + ((Math.Abs(j - 1)) % m_Bitmap.Width)] - 2 * tempArray[((i + 1) % m_Bitmap.Height) * m_Bitmap.Width + j]- tempArray[((i + 1) % m_Bitmap.Height) * m_Bitmap.Width+ ((j + 1) % m_Bitmap.Width)];
//梯度和
grad[i * m_Bitmap.Width + j] = Math.Sqrt(gradX * gradX + gradY * gradY);
//梯度方向(弧度)
angle = Math.Atan2(gradY, gradX);
//四个方向量化
if ((angle >= -1.178097 && angle <= 1.178097) || angle >= 2.748894 || angle < -2.748894)
{
aLable[i * m_Bitmap.Width + j] = 0;
}
else if ((angle >= 0.392699 && angle < 1.178097) || (angle >= -2.748894 && angle < -1.963495))
{
aLable[i * m_Bitmap.Width + j] = 1;
}
else if ((angle >= -1.178097 && angle < -0.392699) || (angle >= 1.963495 && angle < 2.748894))
{
aLable[i * m_Bitmap.Width + j] = 2;
}
else
{
aLable[i * m_Bitmap.Width + j] = 3;
}
}
}
//双阈值算法
Array.Clear(grayValues, 0, bytes);
for (int i = 0; i < m_Bitmap.Height ; i++)
{
for (int j = 0; j < m_Bitmap.Width; j++)
{
if (edgeMap[i * m_Bitmap.Width + j]> thresh[0])
{
grayValues[i * m_Bitmap.Width + j] = 255;
//调用边缘的跟踪方法
traceEdge(i, j, edgeMap, ref grayValues, thresh[1]);
}
}
}
解锁m_Bitmap并在picturebox显示出来
System.Runtime.InteropServices.Marshal.Copy(grayValues, 0, ptr, bytes);
m_Bitmap.UnlockBits(bmpData);
Invalidate();
pictureBox1.Image = m_Bitmap;
在这个程序中涉及到两个方法
一个是高斯平滑处理方法:
//高斯平滑处理方法
//inputImage 输入图像
// outputImage 输出图像
//sigema 均方差
private void gaussSmooth(double[]inputImage,out double[] outputImage,double sigema)
{
//方差
double std2 = 2 * sigema * sigema;
//半径=3sigema
int radius = Convert.ToInt16(Math.Ceiling(3 * sigema));
int filterWidth = 2 * radius + 1;
double[] filter = new double[filterWidth];
outputImage = new double[inputImage.Length];
//限定输入的情况为方阵的情况下得到的图像的宽度和高度
int length = Convert.ToInt16(Math.Sqrt(inputImage.Length));
double[] tempImage = new double[inputImage.Length];
double sum = 0;
//产生一维高斯函数
for (int i = 0; i < filterWidth; i++)
{
int xx = (i - radius) * (i - radius);
filter[i] = Math.Exp(-xx / std2);
sum += filter[i];
}
//归一化
for (int i = 0; i < filterWidth; i++)
{
filter[i] = filter[i] / sum;
}
//水平方向滤波
for (int i = 0; i < length; i++)
{
for (int j = 0; j < length; j++)
{
double temp = 0;
for (int k = -radius; k <= radius; k++)
{
//循环拓展
int rem = (Math.Abs(j + k) % length);
//计算卷积和
temp += inputImage[i * length + rem] * filter[k + radius];
}
tempImage[i + length + j] = temp;
}
}
//垂直方向滤波
for (int j = 0; j < length; j++)
{
for (int i = 0; i < length; i++)
{
double temp = 0;
for (int k = -radius ; k <=radius; k++)
{
//循环拓展
int rem = (Math.Abs(i + k) )% length;
//计算卷积和
temp += tempImage[rem * length + j] * filter[k + radius];
}
outputImage[i * length + j] = temp;
}
}
}
另一个是边缘点跟踪方法:
//边缘点跟踪方法
//边缘跟踪,递归算法
//k:图像纵坐标
//l:图像横坐标
//inputImage 梯度图像
//outputImage 输出边缘图像
//thrLow:低阈值
private void traceEdge(int k,int l,double[]inputImage,ref byte[]outputImage,byte thrLow)
{
//8领域
int[] kOffset = new int[] { 1, 1, 0, -1, -1, -1, 0, 1 };
int[] lOffset = new int[] { 0, 1, 1, -1, 1, 0, -1, -1 };
int kk, ll;
for (int p = 0; p < 8; p++)
{
kk = k + kOffset[p];
//循环拓展
kk = Math.Abs(kk) % m_Bitmap.Height;
ll = l + lOffset[p];
//循环拓展
ll = Math.Abs(ll) % m_Bitmap.Width;
if (outputImage[ll * m_Bitmap.Width + kk] != 255)
{
if (inputImage[ll * m_Bitmap.Width + kk] > thrLow)
{
outputImage[ll * m_Bitmap.Width + kk] = 255;
//递归调用
traceEdge(ll, kk, inputImage, ref outputImage, thrLow);
}
}
}
}