收入囊中
在上个步骤中,产生了梯度幅值, (upper and lower):
如果一个像素点的梯度值大于upper,则是边界
如果一个像素点的梯度值小于lower,则不是边界
如果介于两者之间,仅当这个点和边界点连通才会被认为是边界点
根据高阈值得到一个边缘图像,这样一个图像含有很少的假边缘,但是由于阈值较高,产生的图像边缘可能不闭合,为解决这样一个问题采用了另外一个低阈值。在高阈值图像中把边缘链接成轮廓,当到达轮廓的端点时,该算法会在断点的8邻域点中寻找满足低阈值的点,再根据此点收集新的边缘,直到整个图像边缘闭合。
Canny推荐upper:lower 的比例为 2:1 或者 3:1.
小提示:因为,所以最高阀值不是255而是360!还有处于[lower,upper]的点检测是否是边界肯定要放在最后一步,也就是[0,lower),(upper,360]的点都处理完再处理,这样才能判连通!
|
#include "opencv2/imgproc/imgproc.hpp" #include "opencv2/highgui/highgui.hpp" #include <iostream> using namespace cv; /// Global variables Mat src, src_gray; Mat dst, detected_edges; int lowThreshold; int const max_lowThreshold = 100; int ratio = 3; int kernel_size = 3; const char* window_name = "Edge Map"; static void CannyThreshold(int, void*) { blur( src_gray, detected_edges, Size(3,3) ); Canny( detected_edges, detected_edges, lowThreshold, lowThreshold*ratio, kernel_size ); dst = Scalar::all(0); //detected_edges是mask,只有detected_edges被置上(边缘),才会从原始彩色图像copy到dot中,所以展示的是彩色边缘 src.copyTo( dst, detected_edges); imshow( window_name, dst ); } int main( int, char** argv ) { src = imread( argv[1] ); dst.create( src.size(), src.type() ); cvtColor( src, src_gray, CV_BGR2GRAY ); namedWindow( window_name, CV_WINDOW_AUTOSIZE ); createTrackbar( "Min Threshold:", window_name, &lowThreshold, max_lowThreshold, CannyThreshold ); CannyThreshold(0, 0); waitKey(0); return 0; }
public int[][] CannyEdgeDetect(int[][] oldmat)
{
int[][] tempI = gaussFilter(oldmat);
//////////////////?¨—??…“‘”√≤a?¨μ?o?≤???/////////////////////////
///// P[i,j]=(S[i,j+1]-S[i,j]+S[i+1,j+1]-S[i+1,j])/2 /////
///// Q[i,j]=(S[i,j]-S[i+1,j]+S[i,j+1]-S[i+1,j+1])/2 /////
/////////////////////////////////////////////////////////////////
float[][] P = new float[height][width]; //x?ú?′μo ?
float[][] Q = new float[height][width]; //y?ú?′μo ?
int[][] M = new int[height][width]; //????∑?÷μ
float[][] Theta = new float[height][width]; //????∑Ω?ú
//o?à?x,y∑Ω?úμ??′μo ?
for(int i=0; i<(width-1); i++)
{
for(int j=0; j<(height-1); j++)
{
P[j][i] = (float)(tempI[j][Math.min(i+1, width-1)] - tempI[j][i] + tempI[Math.min(j+1, height-1)][Math.min(i+1, width-1)] - tempI[Math.min(j+1, height-1)][i])/2;
Q[j][i] = (float)(tempI[j][i] - tempI[Math.min(j+1, height-1)][i] + tempI[j][Math.min(i+1, width-1)] - tempI[Math.min(j+1, height-1)][Math.min(i+1, width-1)])/2;
}
}
//o?à?????∑?÷μ∫?????μ?∑Ω?ú
for(int i=0; i<width; i++)
{
for(int j=0; j<height; j++)
{
M[j][i] = (int)(Math.sqrt(P[j][i]*P[j][i] + Q[j][i]*Q[j][i])+0.5);
//System.out.println(M[j][i]);
Theta[j][i] = (float) (Math.atan2(Q[j][i], P[j][i]) * 57.3);
if(Theta[j][i] < 0)
Theta[j][i] += 360; //Ω′’?∏?Ω?????aaμΩ0~360∑???
}
}
int[][] N = new int[height][width]; //∑?o′¥?÷μ“÷÷?Ω·π?
int g1=0, g2=0, g3=0, g4=0; //”√”?Ωˉ––≤?÷죨μ√μΩ—??òà?μ??ˉ±í÷μ
double dTmp1=0.0, dTmp2=0.0; //±£¥ê?Ω∏?—??òà?μ?≤?÷μμ√μΩμ?a“?? ???
double dWeight=0.0; //≤?÷μμ??®÷?
//±?Ωá≥? oa?
for(int i=0; i<width; i++)
{
N[0][i] = 0;
N[height-1][i] = 0;
}
for(int j=0; j<height; j++)
{
N[j][0] = 0;
N[j][width-1] = 0;
}
//Ωˉ––?÷≤??ó¥?÷μ—∞’“
for(int i=1; i<(width-1); i++)
{
for(int j=1; j<(height-1); j++)
{
if(M[j][i] == 0)
N[j][i] = 0; //?áπ?μ±?∞????∑?÷μ??0£¨‘ú≤a ??÷≤??ó¥??‘∏√μ?∏≥??0
else
{
//////// ???≈–?? ù”???÷÷?è??£¨?a∫?∏????è??≤?÷μ///////
////////////////////μ?“a÷÷?è??///////////////////////
///////// g1 g2 /////////////
///////// C /////////////
///////// g3 g4 /////////////
/////////////////////////////////////////////////////
if( ((Theta[j][i]>=90)&&(Theta[j][i]<135)) ||
((Theta[j][i]>=270)&&(Theta[j][i]<315)))
{
//////∏???–±? ∫?à?∏?÷–o‰÷μΩˉ––≤?÷μ??Ω?
g1 = M[j-1][i-1];
g2 = M[j-1][i];
g3 = M[j+1][i];
g4 = M[j+1][i+1];
dWeight = Math.abs(P[j][i])/Math.abs(Q[j][i]); //∑¥’??–
dTmp1 = g1*dWeight+g2*(1-dWeight);
dTmp2 = g4*dWeight+g3*(1-dWeight);
}
////////////////////μ???÷÷?è??///////////////////////
///////// g1 /////////////
///////// g2 C g3 /////////////
///////// g4 /////////////
/////////////////////////////////////////////////////
else if( ((Theta[j][i]>=135)&&(Theta[j][i]<180)) ||
((Theta[j][i]>=315)&&(Theta[j][i]<360)))
{
g1 = M[j-1][i-1];
g2 = M[j][i-1];
g3 = M[j][i+1];
g4 = M[j+1][i+1];
dWeight = Math.abs(Q[j][i])/Math.abs(P[j][i]); //’??–
dTmp1 = g2*dWeight+g1*(1-dWeight);
dTmp2 = g4*dWeight+g3*(1-dWeight);
}
////////////////////μ???÷÷?è??///////////////////////
///////// g1 g2 /////////////
///////// C /////////////
///////// g4 g3 /////////////
/////////////////////////////////////////////////////
else if( ((Theta[j][i]>=45)&&(Theta[j][i]<90)) ||
((Theta[j][i]>=225)&&(Theta[j][i]<270)))
{
g1 = M[j-1][i];
g2 = M[j-1][i+1];
g3 = M[j+1][i];
g4 = M[j+1][i-1];
dWeight = Math.abs(P[j][i])/Math.abs(Q[j][i]); //∑¥’??–
dTmp1 = g2*dWeight+g1*(1-dWeight);
dTmp2 = g3*dWeight+g4*(1-dWeight);
}
////////////////////μ?à?÷÷?è??///////////////////////
///////// g1 /////////////
///////// g4 C g2 /////////////
///////// g3 /////////////
/////////////////////////////////////////////////////
else if( ((Theta[j][i]>=0)&&(Theta[j][i]<45)) ||
((Theta[j][i]>=180)&&(Theta[j][i]<225)))
{
g1 = M[j-1][i+1];
g2 = M[j][i+1];
g3 = M[j+1][i-1];
g4 = M[j][i-1];
dWeight = Math.abs(Q[j][i])/Math.abs(P[j][i]); //’??–
dTmp1 = g1*dWeight+g2*(1-dWeight);
dTmp2 = g3*dWeight+g4*(1-dWeight);
}
}
//////////Ωˉ––?÷≤??ó¥?÷μ≈–??£¨≤¢–¥??o?≤?Ω·π?////////////////
if((M[j][i]>=dTmp1) && (M[j][i]>=dTmp2))
N[j][i] = 128;
else
N[j][i] = 0;
//System.out.println(N[j][i]);
}
}
//à′∑?÷μo?≤? μ?÷
int []nHist = new int[1024];
int nEdgeNum; //?…??±?Ωá ?
int nMaxMag = 0; //?ó¥????? ?
int nHighCount;
//?≥o?÷±∑Ω?o
for(int i=0;i<1024;i++)
nHist[i] = 0;
for(int i=0; i<width; i++)
{
for(int j=0; j<height; j++)
{
if(N[j][i]==128)
nHist[M[j][i]]++;
}
}
//aò?°?ó¥?????∑?÷μo∞?±‘?±?‘μμ?∏? ?
nEdgeNum = nHist[0];
nMaxMag = 0; //aò?°?ó¥?μ?????÷μ
for(int i=1; i<1024; i++) //?≥o??≠π?°∞∑??ó¥?÷μ“÷÷?°±∫?”–??…??òà?
{
if(nHist[i] != 0) //??????0μ?μ? ?≤a?…????±?Ωáμ?μ?
{
nMaxMag = i;
}
nEdgeNum += nHist[i]; //?≠π?non-maximum suppression∫?”–??…??òà?
}
//o?à??Ω∏?∑?÷μ
float dRatHigh = 0.79f;
float dThrHigh;
float dThrLow;
float dRatLow = 0.5f;
nHighCount = (int)(dRatHigh * nEdgeNum + 0.5);
int k = 1;
nEdgeNum = nHist[1];
while((k<(nMaxMag-1)) && (nEdgeNum < nHighCount))
{
k++;
nEdgeNum += nHist[k];
}
dThrHigh = k; //∏??–÷μ
dThrLow = (int)((dThrHigh) * dRatLow + 0.5); //μ??–÷μ
System.out.println("high = " + dThrHigh + "low = " + dThrLow);
//dThrHigh = 10;
//dThrLow = 5;
//Ωˉ––±?‘μo?≤?
int cx = width;
int cy = height;
for(int i=0; i<width; i++)
{
for(int j=0; j<height; j++)
{
if((N[j][i]==128) && (M[j][i] >= dThrHigh))
{
N[j][i] = 255;
TraceEdge(j, i, (int)(dThrLow+0.5), N, M);
}
}
}
//Ω′aπ√a”–…?÷√??±?Ωáμ?μ?…?÷√??∑?±?Ωáμ?
for(int i=0; i<width; i++)
{
for(int j=0; j<height; j++)
{
if(N[j][i] != 255)
{
N[j][i] = 0 ; // …?÷√??∑?±?Ωáμ?
}
N[j][i] = N[j][i] + (N[j][i] << 8) + (N[j][i] << 16);
}
}
return N;
}
/*
* cancy ∏®÷˙∫? ?
*/
private void TraceEdge(int y, int x, int nThrLow, int[][] pResult, int[][] pMag)
{
//?‘8??”ú?òà?Ωˉ––≤è—?
int[] xNum = {1,1,0,-1,-1,-1,0,1};
int[] yNum = {0,1,1,1,0,-1,-1,-1};
int yy,xx,k;
for(k=0;k<8;k++)
{
yy = y+yNum[k];
xx = x+xNum[k];
if(pResult[yy][xx]==128 && pMag[yy][xx]>=nThrLow )
{
//∏√μ?…???±?Ωáμ?
pResult[yy][xx] = 255;
//“‘∏√μ???÷––?‘?Ωˉ––∏˙??
TraceEdge(yy,xx,nThrLow,pResult,pMag);
}
}
}
OpenCV2马拉松第17圈——边缘检测(Canny边缘检测),布布扣,bubuko.com
OpenCV2马拉松第17圈——边缘检测(Canny边缘检测)
原文地址:http://blog.csdn.net/abcd1992719g/article/details/25612389