理想情况下,边缘检测应该仅产生位于边缘上的像素的集合.实际上,由于噪声,不均匀照明引起的边缘间断,以及其他引入灰度值虚假的不连续的影响,这些像素并不能完全描述边缘特性. 因此,一般在边缘检测后面会紧跟连接算法,将边缘像素组合成有意义的边缘或区域边界.
局部处理是连接边缘点最简单的方法之一,是在每个点(x,y)处的一个小邻域内分析像素的特点,根据特定的准则,将所有的相似点连接起来,以形成根据特定准则满足相同特性像素的一条边缘
用于确定边缘像素相似性的两个主要的性质:
(1)梯度向量的强度
(2)梯度向量的方向
(x,y)表示一个像素点 (s,t)表示以(x,y)为中心的所有的邻域点
如果(s,t)既满足幅度准则又满足角度准则,那么我们将(s,t)连接到(x,y),在图像的每个像素点重复这一操作,当邻域的中心从一个点到另一个点时必须将已连接的点记录下来,简单的记录过程就是将每组被连接的像素分配不同的灰度值
根据以上原理得出步骤一:
1 计算图像x y方向的梯度 g_x,g_y
2 根据梯度矩阵计算幅度矩阵和角度矩阵 Mag angle
3 根据幅度准则和方向准则将图像赋予不同的灰度值
#include <iostream>
#include <opencv2/opencv.hpp>
#include<vector>
//
void CalMag(cv::Mat &src1,cv::Mat &src2,cv::Mat &dst1,cv::Mat &dst2){
for(int i=0;i<src1.rows;i++){
for(int j=0;j<src1.cols;j++){
float gx=src1.at<float>(i,j);
float gy=src2.at<float>(i,j);
dst1.at<float>(i,j)=std::sqrt(std::pow(gx,2)+std::pow(gy,2));
dst2.at<float>(i,j)=std::atan2(gy,gx);
}
}
}
void connect(cv::Mat &src1,cv::Mat &src2,cv::Mat &dst){
for(int i=1;i<src1.rows-1;i++){
for(int j=1;j<src1.cols-1;j++){
float magx=src1.at<float>(i,j);
float anglex=src2.at<float>(i,j);
for(int m=i-1;m<=i+1;m++){
for(int n=j-1;n<=j+1;n++){
float magy=src1.at<float>(m,n);
float angley=src2.at<float>(m,n);
if(m!=i&&n!=j) {
if (std::abs(magx - magy) <= 30 && std::abs(anglex - angley) <= 5) {
int dd = (int) (magx / (1.4));//原因是最大