opencv图像处理学习(三十六)——角点检测

图像像素区域的兴趣点区域对于目标检测、目标跟踪有很重要的意义。当兴趣点周围存在方形区域时,最易形成角点。对于兴趣点检测。角点反映的是图像中局部最大值或最小值的孤立点,可理解为区域邻域的小方块,存在于不同方形的主边缘处。窗口向任意方向的移动都会导致图像灰度的明显变化,形成的点集称为角点。

1.moravec角点

moravec角点常用于立体匹配,其原理是通过滑动窗口像素变化来实现角点检测,首先计算窗口像素的兴趣值,即以当前像素为中心像素点,取一个正方形w \times w,计算其0°、45°、90°及135°四个方向灰度差的平方和,取其中的最小值作为该兴趣像素点的兴趣值。其公式如下:

E(u,v)=\sum_{x,y}^{}w(x,y)[f(x+u,y+v)-f(x,y)]^{2}

moravec角点检测器对每一个兴趣中心点进行滑窗遍历,计算其相关8-邻域方向的特征关系,像素点值位置变化可取(u,v)={(-1.-1),(-1,0),(-1,1),(0,-1),(0,1),(1,-1),(1,0),(1,-1)}。moravec角点检测于其它同类型角点检测相比存在两个缺点:

(1)非均匀性响应:窗口特性决定了在进行角点检测时,很容易受到邻近特性的影响,一般在实验操作前,先进行平滑操作。moravec角点检测算子对斜边缘的响应很强,这是因为只考虑了每隔45°的方向变化,而没有在全部方向上进行考虑。

(2)噪声响应。由于窗口函数是一个二值函数,不管像素点离中心点的距离时多少,均赋于一样的权重,致使其对应的噪声也有很强的响应。moravec角点检测对噪声十分敏感,一般在进行角点检测前,先对图像兴趣区域采用较大的窗口或先进行平滑操作。

#include <opencv2\opencv.hpp>
using namespace cv;

cv::Mat MoravecCorners(cv::Mat srcImage,int ksize,int threshold)
{
    cv::Mat resMorMat = srcImage.clone();
    int r = ksize / 2;
    const int nRows = srcImage.rows;
    const int nCols = srcImage.cols;
    int nCount = 0;
    CvPoint *pPoint = new CvPoint [nRows * nCols];
    
    for(int i =r;i < srcImage.rows-r;i++)
    {
        for(int j =r;j<srcImage.cols-r;j++)
        {
            int wV1,wV2,wV3,wV4;
            wV1 = wV2 = wV3 = wV4 = 0;
            //计算水平方向窗口内的兴趣值
            for(int k = -r;k<r;k++)
            {
                wV1 += (srcImage.at<uchar>(i,j+k)-         
                srcImage.at<uchar>(i,j+K+1))*(srcImage.at<uchar>(i,j+k)-    
                srcImage.at<uchar>(i,j+k+1))
            }
            //计算垂直方向窗口内的兴趣值
            for(int k =-r;k<r;k++)
            {
                wV2 += (srcImage.at<uchar>(i+k,j)-srcImage.at<uchar>(i+k+1,j))*
                (srcImage.at<uchar>(i+k,j)-srcImage.at<uchar>(i+k+1,j+k+1));
            }  
            //计算45°方向窗口内的兴趣值
            for(int k =-r;k<r;k++)
            {
                wV3 += (srcImage.at<uchar>(i+k,j+k)-srcImage.at<uchar>(i+k+1,j+k+1))*
                (srcImage.at<uchar>(i+k,j+k)-srcImage.at<uchar>(i+k+1,j+k+1));
            }
            //计算135°方向窗口内的兴趣值
            for(int k = -r;k<r;k++)
            {
                wV4 += (srcImage.at<uchar>(i+k,j+k)-srcImage.at<uchar>(i+k+1,j-k-1))*
                (srcImage.at<uchar>(i+k,j-k)-srcImage.at<uchar>(i+k+1,j-k-1));
            }

            int value = min(min(wV1,wV2),min(mV3,mV4));
            
            if(value > threshold)
            {
                pPoint[nConut] = cvPoint(j,i);
                nConut++;
            }
        
        }
    }
 
 for(int i = 0; i < nCount;i++)
  {
      circle(resMorMat,pPoint[i],5,Scalar(255,0,0));
  }

    return resMorMat;
}

2.harris角点

harris角点在maravec角点的基础上进行了改进,对比于moravec角点连续平方求和,它引入了局部变化因子,利用高斯权重函数特性进行角点检测。对于图像f(x,y),任取窗口块W,进行平移\Delta x\Delta y,考虑到局部特性变化,计算图像平移后窗口变化值之差的平方和S如下:

S_{w}=\sum_{(i,j)\epsilon w}(f(i,j)-f(i-\Delta i,j-\Delta j))^{2}

考虑到响应特性,角点不会受到光圈参数的影响,对于S_{w}(\Delta i,\Delta j)中的高斯响应部分,利用泰勒展开,对于平移后的图像,可变换成下式:

f(i,j)-f(i-\Delta i,j-\Delta j)\approx f(i,j)+\begin{bmatrix} \frac{\partial f(i,j)}{\partial i} & \frac{\partial f(i,j)}{\partial j} \end{bmatrix}\begin{bmatrix} \Delta i\\ \Delta j \end{bmatrix}

将上式中f(i,j)-f(i-\Delta i,j-\Delta j)的近似值代入到S_{w}(i,j)中可得到:

S_{w}(i,j)=\sum_{i\epsilon w}\sum_{j\epsilon w}(f(i,j)-f(i,j)-\begin{bmatrix} \frac{\partial f(i,j)}{\partial i} & \frac{\partial f(i,j)}{\partial i} \end{bmatrix}\begin{bmatrix} \Delta i\\ \Delta j \end{bmatrix})^{2}

最后进行矩阵变换,可得到:

S_{w}(i,j)=\begin{bmatrix} \Delta i &\Delta j \end{bmatrix}\begin{bmatrix} a &b \\ c & d \end{bmatrix}\begin{bmatrix} \Delta i\\\Delta j \end{bmatrix}

其中,a=f_{x}^{2},b=c=f_{x}\cdot f_{y},d=f_{y}^{2} ,对于局部微小移动量[u,v],窗口移动导致的图像灰度变化,时矩阵变换中实对称矩阵M。

S_{w}(i,j)=\begin{bmatrix} u &v \end{bmatrix}M\begin{bmatrix} u\\ v \end{bmatrix}

其中M为2x2矩阵,由图像导数可得参数对应于a、b、c及d。对于局部结构矩阵M代表的邻域,将实对称矩阵对角化处理后,对应项可以理解为旋转因子,经过对角化处理后,根据两个正交方向的变化分量计算其相应的特征值\lambda _{1}\lambda _{2}。如果两个特征值均较大且数值相当,则图像窗口在所有方向上的移动都将产生明显的灰度变化,可判断其将形成角点。如果仅有一个特征值较高且远大于另一特征值,则可以得到相应边缘,其它情况下可以得到稳定区域。基于上述特征值特性。harris角点理论提出了相应的角点响应函数。如下式所示:

C(i,j)=det(M)-k(trace(M))^{2}

其中k为常量因子,通常情况取值为0.04~0.06,对图像窗口内数据进行求和加权,实际上可以更好地刻画窗口中心特性。Harris角点在时间复杂度上更高于moravec角点,其对噪声页十分敏感,也存在非均匀响应。harris角点检测器检测率高,且可以得到重复响应。其实现步骤如下:

(1)利用水平于垂直差分算子对图像进行卷积操作,计算得到相应地f_{x},f_{y},根据实对称矩阵M的组成,计算对应矩阵元素的值。

(2)利用高斯函数对矩阵M进行平滑操作,得到新的M矩阵,步骤1和步骤2可以改变顺序。

(3)对每一个像素和给定的邻域窗口,计算局部特征结果矩阵M的特征值和相应函数C(i,j)=det(M)-k(trace(M))^{2}

(4)选取响应函数C的阈值,根据非极大值抑制原理,同时满足阈值及某邻域内的局部极大值为候选角点。

void CornerHarris(const Mat& srcImage,Mat& result,int blockSize,int ksize,double k)
{
    Mat src;
    srcImage.copyTo(src);
    result.create(src.size(),CV_32F);
    int depth = src.depth();
    //检测掩膜尺寸
    double scale = (double)(1<<((ksize>0?ksize:3)-1))*blockSize;
    if(depth == CV_8U)
    {
        scale *= 255.;
    }
    scale = 1./scale;
    //sobel滤波
    Mat dx,dy;
    Sobel(src,dx,CV_32F,1,0,kSize,scale,0);
    Sobel(src,dy,CV_32F,0,1,kSize,scale,0);
    cv::Mat cov(size,CV_32FC3);
    int i,j;
    for(i =0;i<size.height;i++)
    {
        float *covData = (float*)(cov.data+i*cov.step);
        const float *dxData = (const float*)(dx.data + i*dx.step);
        const float *dyData = (const float*)(dy.data + i*dy.step);

        for(j=0;j<size.width;j++)
        {
            float dx_ = dxData[j];
            float dy_ = dyData[j];
            covData[3*j] = dx_*dx_;
            covData[3*j + 1] = dx_*dy_;
            covData[3*j + 2] = dy_*dy_;
         }
    }

    boxFilter(cov,cov.cov.depth(),Size(blockSize,blockSize),Point(-1,-1),false);
    if(cov.isContinuous()&&result.isContinuous())
    {
        size.width *= size.height;
        size.height = 1;
    }

    else
    {
        size = result.size();
    }

    for(i=0;i<size.height;i++)
    {
        float *resultData = (float*)(result.data + i*result.step);
        const float *covData = (const float*)(cov.data+i*cov.step);
        for(j=0;j<size.width;j++)
        {
            float a = covData[3*j];
            float b = covData[3*j+1];
            float c = covData[3*j+2];
            resultData[j] = a*c - b*b - k*(a+c)*(a+c);
        }
    }
}

3.Shi-Tomasi角点

harris算法中角点响应函数的定义为:C(i,j)=det(M)-k(trace(M))^{2}=\lambda _{1}\lambda _{2}-k(\lambda _{1}+\lambda _{2})^{2},而Shi-Tomasi角点检测则选取了不同的角点响应函数:C(i,j)=min(\lambda _{1},\lambda _{2}).

Shi-Tomasi角点检测划分相关一对一匹配对,依据图像的角点特征、图像灰度和位置信息,采用最大互相关函数进行相似度计算,最终实现角点检测。

Opencv中利用函数goodFeaturesToTrack实现该算法,函数原型如下:

void goodFeaturesToTrack(InputArray image,OutputArray corners,int maxCorners,double qualityLevel,double minDistance,InputArray mask = noArray(),int blockSize = 3,bool useHarrisDetecector=false,double k =0.04)

参数image为输入单通道图像,corners为检测到的角点输出矩阵,maxCorners表示检测到的角点输出的最大数目,如果检测到的角点数目大于该值,则选取更强的角点输出;qualityLevel表示可允许接受的角点最差质量,该参数使用时将该数值乘以最佳角点的质量数值来删除角点;minDistance表示返回角点间的最小的欧式距离,用于限定近邻像素被检测出角点的可能性,mask为可选参数为兴趣区域,若输入图像非空,它将被限定到检测到角点区域;blocksize表示像素邻域中计算协方差矩阵窗口的尺寸;useHarrisDetector应用harris检测来确定;k为经验常数。

 

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在Python和OpenCV中实现直线检测,可以使用Hough变换来检测直线。Hough变换是一种常用的图像处理方法,可用于检测直线、圆等几何形状。 以下是一个简单的示例代码,使用Hough变换来检测直线并计算交点: ```python import cv2 import numpy as np # 读取图像 img = cv2.imread('test.jpg') gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # 边缘检测 edges = cv2.Canny(gray, 50, 150, apertureSize=3) # Hough变换检测直线 lines = cv2.HoughLines(edges, 1, np.pi/180, 200) # 计算交点 points = [] for i in range(len(lines)): for j in range(i+1, len(lines)): rho1, theta1 = lines[i][0] rho2, theta2 = lines[j][0] if abs(theta1 - theta2) < np.pi/4: continue a = np.array([[np.cos(theta1), np.sin(theta1)], [np.cos(theta2), np.sin(theta2)]]) b = np.array([rho1, rho2]) x0, y0 = np.linalg.solve(a, b) points.append((int(x0), int(y0))) # 绘制直线和交点 for line in lines: rho, theta = line[0] a = np.cos(theta) b = np.sin(theta) x0 = a*rho y0 = b*rho x1 = int(x0 + 1000*(-b)) y1 = int(y0 + 1000*(a)) x2 = int(x0 - 1000*(-b)) y2 = int(y0 - 1000*(a)) cv2.line(img, (x1,y1), (x2,y2), (0,0,255), 2) for point in points: cv2.circle(img, point, 5, (0,255,0), -1) # 显示图像 cv2.imshow('image', img) cv2.waitKey(0) cv2.destroyAllWindows() ``` 在代码中,首先读取图像并进行灰度转换和边缘检测。然后使用Hough变换检测直线,并计算交点。最后绘制直线和交点,并显示图像。 需要注意的是,在计算交点时,需要将两条直线的极坐标表示转换为直角坐标表示,并使用线性方程组求解。 希望这个例子能够帮助到你实现直线检测并计算交点。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值