先看原图,canny图,和canny局部放大图(看来需要改进的地方很多啊!):
以下是我canny算子的完整代码,虽然他能运行,可能没有想象的那么好,没有的请你补充完整,可以随意改进,直到你想要的完美结果。(比如,增加高斯平滑,不用行吗?比如,增加sobel,不用行吗?,比如,这个算法太费时间,如何高效运行?)
以前用繁体中文注释,代码中有乱码,请见谅,不是日文版!哈哈!(从c++翻译过来)
private void CannySideGrandiant(ref byte[] m_image0, int w, int h, ref byte[,] m_N) { int[,] m_P = new int[h, w]; int[,] m_Q = new int[h, w]; int[,] m_M = new int[h, w]; double[,] m_Theta = new double[h, w]; // unsafe { for (int j = 0; j < h; j++) for (int i = 0; i < w; i++) { int n0 = j * w + i; m_N[j, i] = m_image0[n0];///初始化输出图像? } } for (int i = 0; i < (h - 1); i++) { for (int j = 0; j < (w - 1); j++) { int n0 = (i * w + j);
//m_P[i, j] = Math.Abs(m_image0[n0] - m_image0[n0 + 1]); //m_Q[i, j] = Math.Abs(m_image0[n0] - m_image0[n0 + w]); m_P[i, j] = m_image0[n0] - m_image0[n0 + 1];//x方向梯度图像 m_Q[i, j] = m_image0[n0] - m_image0[n0 + w];//y方向梯度图像 //try //{ // m_P[i, j] = m_image0[n0 - 1] + m_image0[n0 + 1] - 2 * m_image0[n0]; // m_Q[i, j] = m_image0[n0 - w] + m_image0[n0 + w] - 2 * m_image0[n0]; //} //catch (Exception ex) //{ } } }
for (int i = 0; i < h - 1; i++) { for (int j = 0; j < w - 1; j++) { // m_M[i, j] = m_P[i, j] + m_Q[i, j]; m_M[i, j] = Math.Abs(m_P[i, j]) + Math.Abs(m_Q[i, j]);//梯度图像 m_M[i, j] = m_M[i, j] > 255 ? 255 : m_M[i, j];
//m_Theta[i, j] = Math.Atan(m_Q[i, j] / (m_P[i, j] * 1.0)) * 57.3; //if (m_Theta[i, j] < 0) // m_Theta[i, j] += 360; m_Theta[i, j] = jiaoduAndxiangxian(m_P[i, j], m_Q[i, j]) * 57.3;//梯度角图像 }//角度和象限函数,前面博文经常看到,去找找看? }
for (int i = 0; i < w; i++) { m_N[0, i] = 0; m_N[h - 1, i] = 0;//边界置零 } for (int j = 0; j < h; j++) { m_N[j, 0] = 0; m_N[j, w - 1] = 0;//边界置零 }
int g1 = 0, g2 = 0, g3 = 0, g4 = 0; double dTmp1 = 0.0, dTmp2 = 0.0; double dWeight = 0.0;
for (int i = 1; i < (w - 1); i++) { for (int j = 1; j < (h - 1); j++) { //辫0獶娩翴 if (m_M[j, i] == 0) { m_N[j, i] = 0; } else {
材/// / g1 g2 / / C / / g4 g3 / / if (((m_Theta[j, i] >= 90) && (m_Theta[j, i] < 135)) || ((m_Theta[j, i] >= 270) && (m_Theta[j, i] < 315))) {//寻找梯度方向上的亚像素点
g1 = m_M[j - 1, i - 1]; g2 = m_M[j - 1, i]; g4 = m_M[j + 1, i]; g3 = m_M[j + 1, i + 1]; dWeight = Math.Abs(m_P[j, i] / (m_Q[j, i] * 1.0)); dTmp1 = g1 * dWeight + g2 * (1 - dWeight); dTmp2 = g3 * dWeight + g4 * (1 - dWeight); } 材/// / g1 / / g4 C g2 / / g3 / / else if (((m_Theta[j, i] >= 0) && (m_Theta[j, i] < 45)) || ((m_Theta[j, i] >= 180) && (m_Theta[j, i] < 225)))//寻找梯度方向上的亚像素点 { //int nPointIdx = i+j*w; g3 = m_M[j + 1, i - 1]; g2 = m_M[j, i + 1]; g1 = m_M[j - 1, i + 1]; g4 = m_M[j, i - 1]; dWeight = Math.Abs(m_Q[j, i] / (m_P[j, i] * 1.0)); //
dTmp1 = g1 * dWeight + g2 * (1 - dWeight); dTmp2 = g3 * dWeight + g4 * (1 - dWeight);
} 材/// / g2 g1 / / C / / g3 g4 / /// else if (((m_Theta[j, i] >= 45) && (m_Theta[j, i] < 90)) || ((m_Theta[j, i] >= 225) && (m_Theta[j, i] < 270)))//寻找梯度方向上的亚像素点 { //int nPointIdx = i+j*w; g2 = m_M[j - 1, i]; g1 = m_M[j - 1, i + 1]; g4 = m_M[j + 1, i]; g3 = m_M[j + 1, i - 1]; dWeight = Math.Abs(m_P[j, i] / (m_Q[j, i] * 1.0)); //はタち
dTmp1 = g1 * dWeight + g2 * (1 - dWeight); dTmp2 = g3 * dWeight + g4 * (1 - dWeight); } 材/// / g3 / / g4 C g2 / / g1 / / else if (((m_Theta[j, i] >= 135) && (m_Theta[j, i] < 180)) || ((m_Theta[j, i] >= 315) && (m_Theta[j, i] < 360)))//寻找梯度方向上的亚像素点 { //int nPointIdx = i+j*w; g1 = m_M[j + 1, i + 1]; g2 = m_M[j, i + 1]; g3 = m_M[j - 1, i - 1]; g4 = m_M[j, i - 1]; dWeight = Math.Abs(m_Q[j, i] / (m_P[j, i] * 1.0)); //タち dTmp1 = g1 * dWeight + g2 * (1 - dWeight); dTmp2 = g3 * dWeight + g4 * (1 - dWeight); }
}
if ((m_M[j, i] >= dTmp1) && (m_M[j, i] >= dTmp2)) { m_N[j, i] = 128; //极大值不抑制 置128 } else { m_N[j, i] =0; //非极大值抑制置0
} } } //N is 0 or 128 gray bitmap //蔼耬砞﹚ int[] nHist = new int[361]; int nEdgeNum; int nMaxMag = 0; int nHighCount;
for (int i = 0; i < h; i++) { for (int j = 0; j < w; j++) { if (m_N[i, j] == 128) nHist[m_M[i, j]]++;//直方图统计 } }
nEdgeNum = nHist[0]; nMaxMag = 0; for (int i = 1; i < 361; i++) { if (nHist[i] != 0) { nMaxMag = i; } nEdgeNum += nHist[i]; }
//double dRatHigh = m_twoThres; ノㄓ絋﹚蔼耬 double dRatHigh = 0.9; ノㄓ絋﹚蔼耬 double dThrHigh; int dThrLow; double dRatLow = 0.5; nHighCount = (int)(dRatHigh * nEdgeNum + 0.5); int jj = 1; nEdgeNum = nHist[1]; while ((jj < (nMaxMag - 1)) && (nEdgeNum < nHighCount)) { jj++; nEdgeNum += nHist[jj]; } dThrHigh = jj;//根据直方图统计结果,计算高门槛值 dThrLow = (int)((dThrHigh) * dRatLow + 0.5);//根据直方图统计结果,计算低门槛值
for (int i = 0; i < h; i++) { for (int j = 0; j < w; j++) { if ((m_N[i, j] == 128) && (m_M[i, j] >= dThrHigh)) { m_N[i, j] = 255;
TraceEdge(i, j, dThrLow, ref m_N, ref m_M); //染色算法,强边缘和弱边缘连接 } } } for (int i = 0; i < h; i++) { for (int j = 0; j < w; j++) { if (m_N[i, j] != 255) { m_N[i, j] = 0;//最后返回图像,使用0和255,增强图像对比度
} } }
}