我們都知道梯度很好求,只需要將[-1,1] 與圖像分別在x 方向和y方向卷積,即可求得兩個方向上的梯度。不過在求梯度方向時,還是有些麻煩,因為梯度方向會指向360°的任何一個方向,所以直接用atan(dy/dx)函數,通常會得到正負PI/2范圍內的值,因此,在本文中將根據dy、dx的正負,求取任一象限內的梯度方向。x、y以及四個象限如下圖所示:

在本文中編制了兩個函數一個是獲取梯度方向函數
Mat getGradientDirect(Mat&img_dy,Mat&img_dx)
一個是將梯度方向等分為8個方向:0、PI/4、PI/2、PI、5PI/4、3PI/2、7PI/4.。函數名為:
void octantDirect(Mat&theta)
下面是兩個函數的代碼:
Mat getGradientDirect(Mat&img_dy,Mat&img_dx)
{
int rows=img_dx.rows,cols=img_dy.cols;
Mat theta(rows,cols,img_dx.type(),Scalar::all(0));
for(int i=0;i<rows;i++)
{
for(int j=0;j<cols;j++)
{
Vec3f dx=img_dx.at<Vec3f>(i,j);
Vec3f dy=img_dy.at<Vec3f>(i,j);
for(int k=0;k<theta.channels();k++)
{
if(dx[k]>0&&dy[k]==0)//X正向
theta.at<Vec3f>(i,j)[k]=0;
if(dx[k]>0&&dy[k]>0)//第1象限
theta.at<Vec3f>(i,j)[k]=atan(dy[k]/dx[k]);
if(dx[k]==0&&dy[k]>0)//Y正向
theta.at<Vec3f>(i,j)[k]=PI/2;
if(dx[k]<0&&dy[k]>0)//第2象限
theta.at<Vec3f>(i,j)[k]=atan(dy[k]/dx[k])+PI;
if(dx[k]<0&&dy[k]==0)//X負向
theta.at<Vec3f>(i,j)[k]=PI;
if(dx[k]<0&&dy[k]<0)//第3象限
theta.at<Vec3f>(i,j)[k]=atan(dy[k]/dx[k])+PI;
if(dx[k]==0&&dy[k]<0)//Y負向
theta.at<Vec3f>(i,j)[k]=PI*1.5;
if(dx[k]>0&&dy[k]<0)//第4象限
theta.at<Vec3f>(i,j)[k]=atan(dy[k]/dx[k])+2*PI;
if(dx[k]==0&&dy[k]==0)// dy/dx=0/0
theta.at<Vec3f>(i,j)[k]=0;
}
}
}
return theta;
}
八分儀代碼:
void octantDirect(Mat&theta)
{
int rows=theta.rows,cols=theta.cols;
for(int i=0;i<rows;i++)
{
for(int j=0;j<cols;j++)
{
auto p=theta.at<Vec3f>(i,j);
// auto pr=theta.data+i*theta.step[0]+j*theta.step[1];
for(int k=0;k<theta.channels();k++)
{
if((0.125*PI>p[k]&&p[k]>=0) ||
( PI*2>p[k]&&p[k]>=PI*1.875))
theta.at<Vec3f>(i,j)[k]=0;
if(0.375*PI>p[k]&&p[k]>=0.125*PI)
theta.at<Vec3f>(i,j)[k]=1;
if(0.625*PI>p[k]&&p[k]>=0.375*PI)
theta.at<Vec3f>(i,j)[k]=2;
if(0.875*PI>p[k]&&p[k]>=0.625*PI)
theta.at<Vec3f>(i,j)[k]=3;
if(1.125*PI>p[k]&&p[k]>=0.875*PI)
theta.at<Vec3f>(i,j)[k]=4;
if(1.375*PI>p[k]&&p[k]>=1.125*PI)
theta.at<Vec3f>(i,j)[k]=5;
if(1.625*PI>p[k]&&p[k]>=1.375*PI)
theta.at<Vec3f>(i,j)[k]=6;
if(1.875*PI>p[k]&&p[k]>=1.625*PI)
theta.at<Vec3f>(i,j)[k]=7;
}
}
}
}
