精华内容
下载资源
问答
  • 为了改进Zernike矩边缘检测方法对非直线边缘检测精度低的弱点,提出了一种改进的基于Zernike矩方法和Sigmoid拟合法的边缘检测方法。用Zernike矩边缘检测方法检测边缘,然后用Sigmoid拟合方法检测边缘,根据边缘类型...
  • Zernike矩边缘检测(附源码)

    千次阅读 热门讨论 2016-01-30 10:25:08
    由于Zernike矩是一种积分算子,因此对噪声不敏感,这一优良特性在图像处理中极其难得。下面我们将介绍Zernike矩边缘检测中的应用。利用Zernike矩进行边缘检测最早由Ghosal等人[4]提出。

    这一篇博文将讨论Zernike矩在边缘检测中的应用,关于Zernike矩的基本概念,可以参看Zernike矩之图像重建(附源码


    源码下载

    参考:

    [4] Ghosal S, Mehrotra R. Orthogonal moment operators for subpixel edge detection[J]. Pattern recognition,
    1993, 26(2): 295-306.


    展开全文
  • 本程序使用Zernike矩来进行边缘像素检测,并添加了一个例子,欢迎需要亚像素边缘检测的同学讨论。
  • 本文详细介绍了zernike矩边缘检测的原理,并提出一种自动搜索阈值的方法,简单可行。希望对大家有帮助。
  • 基于Zernike矩的亚像素边缘检测
  • 基于Zernike矩的亚像素边缘检测算法,田春苗,钟志,针对传统算子定位精度较低、检测出的边缘较粗的缺点,本文提出了基于Zernike矩的亚像素边缘检测算子,并推导出 的模板系数。该算法�
  • 基于Arimoto熵和Zernike矩的图像亚像素边缘检测
  • 为了克服传统的Zernike法在边缘检测过程中,由于人工手动选取阈值而带来的低效率、高误判等不足,将原算法与Otsu法相结合,提出了一种边缘检测的快速算法。利用传统的Zernike法计算出图像的阶跃灰度矩阵,再将该矩阵...
  • 根据别人发表的论文,研究如何实现亚像素边缘检测代码编写

    参考文献:


    首先文献中介绍了什么Zernike矩,涉及到一些计算过程,

    首先看源文件描述:



    表2有一个问题:即m/n应改为n/m。

    我发现我有强烈的名词识别障碍症,所以此处再列一下各个变量的对应名字:

    :Zernike n 阶多项式;Zernike正交复函数多项式

    :(正交)实值多项式

    计算当,时的Zernike正交复函数多项式,(演示一下表2中的结果是怎么计算来的)

    1,首先计算正交实值多项式,把n,m代入根据公式(2)求解


    计算出,此处把换成了r,即表1中所示的结果

    2,把计算出的代入公式(1)中:

    先要明确在极坐标中(就是我们常见的,)则,

    Zernike矩边缘检测原理

    1,还是由表1可知,当时,只有才存在,因此才存在
    所以才有
    2,文献中公式(7)的推导:由已知条件:


    代入公式(6)即可推出公式(7)

    3,至于为什么因为虚部是奇函数所以推导出公式(8),就不懂了
    4,后面的是求公式,感觉公式(11)有错误,因为时间不够就先不分析了
    5,不懂公式(20)是怎么解的
    (数学功底好弱啊……)
    *公式编辑小工具:http://blog.csdn.net/qq_20823641/article/details/51692509
    此篇文章中附有更详细的代码,部分图片可以运行出结果,我想做实验的遥感图像则不可以运行出结果
    http://blog.csdn.net/u010839382/article/details/50610459
    展开全文
  • OpenCV实现基于Zernike矩的亚像素边缘检测

    万次阅读 多人点赞 2017-04-09 17:17:16
    在做物体检测时,由于...从而得到亚像素级别的边缘点的坐标(也就是float类型的坐标),一般来说,现有的技术可以做到2细分、4细分,甚至很牛的能做到更高,通过亚像素边缘检测技术的使用,可以节约成本,提高识别精

        在做物体检测时,由于成本和应用场合的限制,不能够一味地增加相机的分辨率,或者已经用了分辨率很高的相机,但是视野范围很大,仍然无法实现很高的精度,这时就要考虑亚像素技术,亚像素技术就是在两个像素点之间进行进一步的细分,从而得到亚像素级别的边缘点的坐标(也就是float类型的坐标),一般来说,现有的技术可以做到2细分、4细分,甚至很牛的能做到更高,通过亚像素边缘检测技术的使用,可以节约成本,提高识别精度。

        常见的亚像素技术包括灰度矩、Hu矩、空间矩、Zernike矩等,通过查阅多篇论文,综合比较精度、时间和实现难度,选择Zernike矩作为项目中的亚像素边缘检测算法。基于Zernike矩的边缘检测原理,下一篇文章详细再总结一下,这里大体把步骤说一下,并使用OpenCV实现。

        大体步骤就是,首先确定使用的模板大小,然后根据Zernike矩的公式求出各个模板系数,例如我选择的是7*7模板(模板越大精度越高,但是运算时间越长),要计算M00,M11R,M11I,M20,M31R,M31I,M40七个Zernike模板。第二步是对待检测图像进行预处理,包括滤波二值化等,也可以在进行一次Canny边缘检测。第三步是将预处理的图像跟7个Zernike矩模板分别进行卷积,得到7个Zernike矩。第四步是把上一步的矩乘上角度校正系数(这是因为利用Zernike的旋转不变性,Zernike模型把边缘都简化成了x=n的直线,这里要调整回来)。第五步是计算距离参数l和灰度差参数k,根据k和l判断该点是否为边缘点。以下是基于OpenCV的实现。

    #include <math.h>
    #include <opencv2/opencv.hpp>
    
    using namespace std;
    using namespace cv;
    
    const double PI = 3.14159265358979323846;
    const int g_N = 7;
    
    Mat M00 = (Mat_<double>(7, 7) <<
    	0, 0.0287, 0.0686, 0.0807, 0.0686, 0.0287, 0,
    	0.0287, 0.0815, 0.0816, 0.0816, 0.0816, 0.0815, 0.0287,
    	0.0686, 0.0816, 0.0816, 0.0816, 0.0816, 0.0816, 0.0686,
    	0.0807, 0.0816, 0.0816, 0.0816, 0.0816, 0.0816, 0.0807,
    	0.0686, 0.0816, 0.0816, 0.0816, 0.0816, 0.0816, 0.0686,
    	0.0287, 0.0815, 0.0816, 0.0816, 0.0816, 0.0815, 0.0287,
    	0, 0.0287, 0.0686, 0.0807, 0.0686, 0.0287, 0);
    
    Mat M11R = (Mat_<double>(7, 7) <<
    	0, -0.015, -0.019, 0, 0.019, 0.015, 0,
    	-0.0224, -0.0466, -0.0233, 0, 0.0233, 0.0466, 0.0224,
    	-0.0573, -0.0466, -0.0233, 0, 0.0233, 0.0466, 0.0573,
    	-0.069, -0.0466, -0.0233, 0, 0.0233, 0.0466, 0.069,
    	-0.0573, -0.0466, -0.0233, 0, 0.0233, 0.0466, 0.0573,
    	-0.0224, -0.0466, -0.0233, 0, 0.0233, 0.0466, 0.0224,
    	0, -0.015, -0.019, 0, 0.019, 0.015, 0);
    
    Mat M11I = (Mat_<double>(7, 7) <<
    	0, -0.0224, -0.0573, -0.069, -0.0573, -0.0224, 0,
    	-0.015, -0.0466, -0.0466, -0.0466, -0.0466, -0.0466, -0.015,
    	-0.019, -0.0233, -0.0233, -0.0233, -0.0233, -0.0233, -0.019,
    	0, 0, 0, 0, 0, 0, 0,
    	0.019, 0.0233, 0.0233, 0.0233, 0.0233, 0.0233, 0.019,
    	0.015, 0.0466, 0.0466, 0.0466, 0.0466, 0.0466, 0.015,
    	0, 0.0224, 0.0573, 0.069, 0.0573, 0.0224, 0);
    
    Mat M20 = (Mat_<double>(7, 7) <<
    	0, 0.0225, 0.0394, 0.0396, 0.0394, 0.0225, 0,
    	0.0225, 0.0271, -0.0128, -0.0261, -0.0128, 0.0271, 0.0225,
    	0.0394, -0.0128, -0.0528, -0.0661, -0.0528, -0.0128, 0.0394,
    	0.0396, -0.0261, -0.0661, -0.0794, -0.0661, -0.0261, 0.0396,
    	0.0394, -0.0128, -0.0528, -0.0661, -0.0528, -0.0128, 0.0394,
    	0.0225, 0.0271, -0.0128, -0.0261, -0.0128, 0.0271, 0.0225,
    	0, 0.0225, 0.0394, 0.0396, 0.0394, 0.0225, 0);
    
    Mat M31R = (Mat_<double>(7, 7) <<
    	0, -0.0103, -0.0073, 0, 0.0073, 0.0103, 0,
    	-0.0153, -0.0018, 0.0162, 0, -0.0162, 0.0018, 0.0153,
    	-0.0223, 0.0324, 0.0333, 0, -0.0333, -0.0324, 0.0223,
    	-0.0190, 0.0438, 0.0390, 0, -0.0390, -0.0438, 0.0190,
    	-0.0223, 0.0324, 0.0333, 0, -0.0333, -0.0324, 0.0223,
    	-0.0153, -0.0018, 0.0162, 0, -0.0162, 0.0018, 0.0153,
    	0, -0.0103, -0.0073, 0, 0.0073, 0.0103, 0);
    
    Mat M31I = (Mat_<double>(7, 7) <<
    	0, -0.0153, -0.0223, -0.019, -0.0223, -0.0153, 0,
    	-0.0103, -0.0018, 0.0324, 0.0438, 0.0324, -0.0018, -0.0103,
    	-0.0073, 0.0162, 0.0333, 0.039, 0.0333, 0.0162, -0.0073,
    	0, 0, 0, 0, 0, 0, 0,
    	0.0073, -0.0162, -0.0333, -0.039, -0.0333, -0.0162, 0.0073,
    	0.0103, 0.0018, -0.0324, -0.0438, -0.0324, 0.0018, 0.0103,
    	0, 0.0153, 0.0223, 0.0190, 0.0223, 0.0153, 0);
    
    Mat M40 = (Mat_<double>(7, 7) <<
    	0, 0.013, 0.0056, -0.0018, 0.0056, 0.013, 0,
    	0.0130, -0.0186, -0.0323, -0.0239, -0.0323, -0.0186, 0.0130,
    	0.0056, -0.0323, 0.0125, 0.0406, 0.0125, -0.0323, 0.0056,
    	-0.0018, -0.0239, 0.0406, 0.0751, 0.0406, -0.0239, -0.0018,
    	0.0056, -0.0323, 0.0125, 0.0406, 0.0125, -0.0323, 0.0056,
    	0.0130, -0.0186, -0.0323, -0.0239, -0.0323, -0.0186, 0.0130,
    	0, 0.013, 0.0056, -0.0018, 0.0056, 0.013, 0);
    
    
    
    int main()
    {
    
    	Mat OriginalImage = imread("original.png", 0);
    	Mat SubImage = OriginalImage;
    
    	Mat NewSmoothImage;
    	medianBlur(OriginalImage, NewSmoothImage, 13);
    
    	Mat NewAdaThresImage;
    	adaptiveThreshold(NewSmoothImage, NewAdaThresImage, 255, ADAPTIVE_THRESH_GAUSSIAN_C, THRESH_BINARY_INV, 7, 4);
    
    	vector<Point2d> SubEdgePoints;
    
    	Mat ZerImageM00;
    	filter2D(NewAdaThresImage, ZerImageM00, CV_64F, M00, Point(-1, -1), 0, BORDER_DEFAULT);
    	//filter2D( cannyImage, zerImageM00, CV_64F, M00, Point(-1,-1), 0, BORDER_DEFAULT);
    
    	Mat ZerImageM11R;
    	filter2D(NewAdaThresImage, ZerImageM11R, CV_64F, M11R, Point(-1, -1), 0, BORDER_DEFAULT);
    	//filter2D( cannyImage, zerImageM11R, CV_64F, M11R, Point(-1, -1), 0, BORDER_DEFAULT);
    
    	Mat ZerImageM11I;
    	filter2D(NewAdaThresImage, ZerImageM11I, CV_64F, M11I, Point(-1, -1), 0, BORDER_DEFAULT);
    	//filter2D( cannyImage, zerImageM11I, CV_64F, M11I, Point(-1, -1), 0, BORDER_DEFAULT);
    
    	Mat ZerImageM20;
    	filter2D(NewAdaThresImage, ZerImageM20, CV_64F, M20, Point(-1, -1), 0, BORDER_DEFAULT);
    	//filter2D( cannyImage, zerImageM20, CV_64F, M20, Point(-1, -1), 0, BORDER_DEFAULT);
    
    	Mat ZerImageM31R;
    	filter2D(NewAdaThresImage, ZerImageM31R, CV_64F, M31R, Point(-1, -1), 0, BORDER_DEFAULT);
    	//filter2D(cannyImage, zerImageM31R, CV_64F, M31R, Point(-1, -1), 0, BORDER_DEFAULT);
    
    	Mat ZerImageM31I;
    	filter2D(NewAdaThresImage, ZerImageM31I, CV_64F, M31I, Point(-1, -1), 0, BORDER_DEFAULT);
    	//filter2D(cannyImage, zerImageM31I, CV_64F, M31I, Point(-1, -1), 0, BORDER_DEFAULT);
    
    	Mat ZerImageM40;
    	filter2D(NewAdaThresImage, ZerImageM40, CV_64F, M40, Point(-1, -1), 0, BORDER_DEFAULT);
    	//filter2D(cannyImage, zerImageM40, CV_64F, M40, Point(-1, -1), 0, BORDER_DEFAULT);
    
    
    
    	int row_number = NewAdaThresImage.rows;
    	int col_number = NewAdaThresImage.cols;
    	//使用7个的7*7的Zernike模板(其本质是个矩阵)M00、M11R、M11I、M20、M31R、M31I、M40,分别与图像进行卷积,得到每个像素点的七个Zernike矩Z00、Z11R、Z11I、Z20、Z31R、Z31I、Z40
    	//对于每个点,根据它的七个Zernike矩,求得距离参数l和灰度差参数k,当l和k都满足设定的条件时,则判读该点为边缘点,并进一步利用上述7个Zernike矩求出该点的亚像素级坐标
    	//如果l或k不满足设定的条件,则该点不是边缘点,转到下一个点求解距离参数l和灰度差参数k
    	for (int i = 0; i < row_number; i++)
    	{
    		for (int j = 0; j <col_number; j++)
    		{
    			if (ZerImageM00.at<double>(i, j) == 0)
    			{
    				continue;
    			}
    
    			//compute theta
    			//vector<vector<double> > theta2(0);
    			double theta_temporary = atan2(ZerImageM31I.at<double>(i, j), ZerImageM31R.at<double>(i, j));
    			//theta2[i].push_back(thetaTem);
    
    			//compute Z11'/Z31'
    			double rotated_z11 = 0.0;
    			rotated_z11 = sin(theta_temporary)*(ZerImageM11I.at<double>(i, j)) + cos(theta_temporary)*(ZerImageM11R.at<double>(i, j));
    			double rotated_z31 = 0.0;
    			rotated_z31 = sin(theta_temporary)*(ZerImageM31I.at<double>(i, j)) + cos(theta_temporary)*(ZerImageM31R.at<double>(i, j));
    
    			//compute l
    			double l_method1 = sqrt((5 * ZerImageM40.at<double>(i, j) + 3 * ZerImageM20.at<double>(i, j)) / (8 * ZerImageM20.at<double>(i, j)));
    			double l_method2 = sqrt((5 * rotated_z31 + rotated_z11) / (6 * rotated_z11));
    			double l = (l_method1 + l_method2) / 2;
    			//compute k/h
    			double k, h;
    		
    			k = 3 * rotated_z11 / 2 / pow((1 - l_method2*l_method2), 1.5);
    			h = (ZerImageM00.at<double>(i, j) - k*PI / 2 + k*asin(l_method2) + k*l_method2*sqrt(1 - l_method2*l_method2)) / PI;
    
    			//judge the edge
    			double k_value = 20.0;
    		
    			double l_value = sqrt(2) / g_N;
    		
    			double absl = abs(l_method2 - l_method1);
    			if (k >= k_value && absl <= l_value)
    			{
    				Point2d point_temporary;
    				point_temporary.x = j + g_N*l*cos(theta_temporary) / 2;
    				point_temporary.y = i + g_N*l*sin(theta_temporary) / 2;
    				SubEdgePoints.push_back(point_temporary);
    			}
    			else
    			{
    				continue;
    			}
    		}
    	}
    	//显示所检测到的亚像素边缘
    	for (size_t i = 0; i < SubEdgePoints.size(); i++)
    	{
    	    Point center_forshow(cvRound(SubEdgePoints[i].x), cvRound(SubEdgePoints[i].y));
    		circle(OriginalImage, center_forshow, 1, Scalar(0, 97, 255), 1, 8, 0);
    	}
    	imshow("亚像素边缘", OriginalImage);
    	
    	waitKey(0);
    	return 0;
    }
    


    ---------------------------------------7.28更新分割线-------------------------------------------------

    1.因为留言要源代码的朋友比较多,所以我把上面的代码补完整了,新的代码能够实现基本的过程,但是针对不同的应用,肯定不是最优的效果,可能需要根据不同的应用场合进行调整;

    2.评论里提到的双层轮廓,我能想到的是因为对线进行边缘检测操作,因为线的两侧相当于都是前景和背景的边缘,所以两侧各会有一层边缘,不管是Canny(事实上不少Zernike论文都建议先用canny再用Zernike)还是二值化,只要送入Zernike的是线而不是区域,就会有双层轮廓,其他的原因我暂时还没想到,欢迎大家赐教;

    3.双层轮廓并不一定是坏事,比如做圆检测,最后是要用这些边缘点来拟合圆,那么两层轮廓拟合出来的圆放大了说应该是处于两层轮廓中间,这样的结果其实更符合实际情况,但是如果不是规则轮廓,可能会对边缘点的表达和拟合有些问题;


    展开全文
  • 利用正交来进行亚像素边缘检测的算法,首先通过计算图像3个不同阶次的Zernike正交,把理想阶跃灰度模型的4个参数映射到3个Zernike正交中;然后计算边缘所在直线的参数,确定边缘的亚像素级坐标。
  • 提出了一种基于Zernike矩改进的亚像素边缘提取的工件缺陷检测算法。 对图像进行小波分解,并对分解的各频段信息分别利用不同算法进行预处理,重构图像后可以有效地滤除图像噪声,增强目标信息;利用改进的Zernike矩亚...
  • 基于亚像素的边缘检测定位,具有实用价值的参考论文,详细描述了zernike矩的特点及应用
  • 本文提取了一种新型的亚像素边缘检测和中心定位方法,先用Canny算子提取像素边缘,再用Zernike矩进行亚像素边缘定位,最后用最小二乘椭圆拟合进行中心定位。
  • Zernik亚像素边缘检测

    热门讨论 2020-10-30 18:26:43
    在网上看到有人写的Zernike矩亚像素边缘检测,发现存在很大的问题,赌气自己写了一个版本,力求精简,没有做过多优化。模板采用(7,7),借用Opencv的数据结构。如有问题欢迎指出。 关于Zernike矩求亚像素的原理,...

    Zernik矩亚像素边缘检测

    在网上看到有人写的Zernike矩亚像素边缘检测,发现存在很大的问题,赌气自己写了一个版本,力求精简,没有做过多优化。模板采用(7,7),借用Opencv的数据结构。如有问题欢迎指出。
    关于Zernike矩求亚像素的原理,可以百度,有很多资源,下面是本人参考的文献:
    Zernike矩亚像素原理
    下面直接上代码:

    #include <string>
    #include <opencv2/opencv.hpp>
    #include <vector>
    using namespace cv;
    using namespace std;
    
    
    
    const double PI = 3.14159265358979323846;
    const int g_N = 7;
    const int h_N = 3;
    Mat M00 = (Mat_<float>(7, 7) <<
    	0, 0.0287, 0.0686, 0.0807, 0.0686, 0.0287, 0,
    	0.0287, 0.0815, 0.0816, 0.0816, 0.0816, 0.0815, 0.0287,
    	0.0686, 0.0816, 0.0816, 0.0816, 0.0816, 0.0816, 0.0686,
    	0.0807, 0.0816, 0.0816, 0.0816, 0.0816, 0.0816, 0.0807,
    	0.0686, 0.0816, 0.0816, 0.0816, 0.0816, 0.0816, 0.0686,
    	0.0287, 0.0815, 0.0816, 0.0816, 0.0816, 0.0815, 0.0287,
    	0, 0.0287, 0.0686, 0.0807, 0.0686, 0.0287, 0);
    
    Mat M11R = (Mat_<float>(7, 7) <<
    	0, -0.015, -0.019, 0, 0.019, 0.015, 0,
    	-0.0224, -0.0466, -0.0233, 0, 0.0233, 0.0466, 0.0224,
    	-0.0573, -0.0466, -0.0233, 0, 0.0233, 0.0466, 0.0573,
    	-0.069, -0.0466, -0.0233, 0, 0.0233, 0.0466, 0.069,
    	-0.0573, -0.0466, -0.0233, 0, 0.0233, 0.0466, 0.0573,
    	-0.0224, -0.0466, -0.0233, 0, 0.0233, 0.0466, 0.0224,
    	0, -0.015, -0.019, 0, 0.019, 0.015, 0);
    
    Mat M11I = (Mat_<float>(7, 7) <<
    	0, -0.0224, -0.0573, -0.069, -0.0573, -0.0224, 0,
    	-0.015, -0.0466, -0.0466, -0.0466, -0.0466, -0.0466, -0.015,
    	-0.019, -0.0233, -0.0233, -0.0233, -0.0233, -0.0233, -0.019,
    	0, 0, 0, 0, 0, 0, 0,
    	0.019, 0.0233, 0.0233, 0.0233, 0.0233, 0.0233, 0.019,
    	0.015, 0.0466, 0.0466, 0.0466, 0.0466, 0.0466, 0.015,
    	0, 0.0224, 0.0573, 0.069, 0.0573, 0.0224, 0);
    
    Mat M20 = (Mat_<float>(7, 7) <<
    	0, 0.0225, 0.0394, 0.0396, 0.0394, 0.0225, 0,
    	0.0225, 0.0271, -0.0128, -0.0261, -0.0128, 0.0271, 0.0225,
    	0.0394, -0.0128, -0.0528, -0.0661, -0.0528, -0.0128, 0.0394,
    	0.0396, -0.0261, -0.0661, -0.0794, -0.0661, -0.0261, 0.0396,
    	0.0394, -0.0128, -0.0528, -0.0661, -0.0528, -0.0128, 0.0394,
    	0.0225, 0.0271, -0.0128, -0.0261, -0.0128, 0.0271, 0.0225,
    	0, 0.0225, 0.0394, 0.0396, 0.0394, 0.0225, 0);
    
    Mat M31R = (Mat_<float>(7, 7) <<
    	0, -0.0103, -0.0073, 0, 0.0073, 0.0103, 0,
    	-0.0153, -0.0018, 0.0162, 0, -0.0162, 0.0018, 0.0153,
    	-0.0223, 0.0324, 0.0333, 0, -0.0333, -0.0324, 0.0223,
    	-0.0190, 0.0438, 0.0390, 0, -0.0390, -0.0438, 0.0190,
    	-0.0223, 0.0324, 0.0333, 0, -0.0333, -0.0324, 0.0223,
    	-0.0153, -0.0018, 0.0162, 0, -0.0162, 0.0018, 0.0153,
    	0, -0.0103, -0.0073, 0, 0.0073, 0.0103, 0);
    
    Mat M31I = (Mat_<float>(7, 7) <<
    	0, -0.0153, -0.0223, -0.019, -0.0223, -0.0153, 0,
    	-0.0103, -0.0018, 0.0324, 0.0438, 0.0324, -0.0018, -0.0103,
    	-0.0073, 0.0162, 0.0333, 0.039, 0.0333, 0.0162, -0.0073,
    	0, 0, 0, 0, 0, 0, 0,
    	0.0073, -0.0162, -0.0333, -0.039, -0.0333, -0.0162, 0.0073,
    	0.0103, 0.0018, -0.0324, -0.0438, -0.0324, 0.0018, 0.0103,
    	0, 0.0153, 0.0223, 0.0190, 0.0223, 0.0153, 0);
    
    Mat M40 = (Mat_<float>(7, 7) <<
    	0, 0.013, 0.0056, -0.0018, 0.0056, 0.013, 0,
    	0.0130, -0.0186, -0.0323, -0.0239, -0.0323, -0.0186, 0.0130,
    	0.0056, -0.0323, 0.0125, 0.0406, 0.0125, -0.0323, 0.0056,
    	-0.0018, -0.0239, 0.0406, 0.0751, 0.0406, -0.0239, -0.0018,
    	0.0056, -0.0323, 0.0125, 0.0406, 0.0125, -0.0323, 0.0056,
    	0.0130, -0.0186, -0.0323, -0.0239, -0.0323, -0.0186, 0.0130,
    	0, 0.013, 0.0056, -0.0018, 0.0056, 0.013, 0);
    
    
    int main()
    {
    	cv::Mat gray_img, med_img, canny_img, border_img, border_edge;
    	string image_path = "lena.jpg";
    	gray_img = cv::imread(image_path, 0);                                                         //以灰度图形式读取
    	cv::medianBlur(gray_img, med_img, 5);                                                         //中值滤波,不是必须,只为消除部分椒盐噪声
    	cv::Canny(med_img, canny_img, 80, 120);                                                       //canny边缘检测,进行初定位,获取初始边缘
    	//由于图像用到的模板为7*7的,所以先对图像进行边缘扩展
    	copyMakeBorder(med_img, border_img, h_N, h_N, h_N, h_N, cv::BORDER_REPLICATE);
    	copyMakeBorder(canny_img, border_edge, h_N, h_N, h_N, h_N, cv::BORDER_REPLICATE);
    	float Z00 = 0, Z11_I = 0, Z11_R = 0, Z20 = 0, Z31_I = 0, Z31_R = 0, Z40 = 0;                 //不同模板的卷积值
    	cv::Mat roi_img;
    	float theta1, theta3,Zz11, Zz31, Zz20, Zz40, l, r, t;
    	float x, y;
    	vector<cv::Point2f> sub_pixel_edge;
    	//对初始边缘进行亚像素边缘求取
    	for (int i = h_N; i < border_img.rows - h_N; i++)
    	{
    		for (int j = h_N; j < border_img.cols - h_N; j++)
    		{
    			if (border_edge.at<uchar>(i, j) == 255)
    			{	
    				//卷积
    				border_img(cv::Rect(j - h_N, i - h_N, g_N, g_N)).convertTo(roi_img, CV_32FC1);
    				Z00 = roi_img.dot(M00);
    				Z11_I = roi_img.dot(M11I);
    				Z11_R = roi_img.dot(M11R);
    				Z20 = roi_img.dot(M20);
    				/*Z31_I = roi_img.dot(M31I);
    				Z31_R = roi_img.dot(M31R);
    				Z40 = roi_img.dot(M40);	*/
    				theta1 = atan(Z11_I / Z11_R);                                                       //旋转角度计算          
    				Zz11 = Z11_R * cos(theta1) + Z11_I * sin(theta1);                                   //各阶Zernike矩旋转后结果
    
    				l = Z20 / Zz11;                                                                     //边缘距离圆心的距离
    				r = 1.5 * Zz11 / sqrt(pow(1 - pow(l, 2), 3));                                       //阶跃幅度
    				t = (Z00 - r * PI / 2 + r * asin(l) + r * l * sqrt(1 - pow(l, 2))) / PI;            //背景灰度值计算
    
    				//计算亚像素位置
    				x = j + g_N / 2.0 * l * cos(theta1) - h_N;                                          //根据公式计算即可,因扩充了边缘需要减去                
    				y = i + g_N / 2.0 * l * sin(theta1) - h_N;
    				cv::Point2f sub_pixel_point(x, y);
    				sub_pixel_edge.push_back(sub_pixel_point);                                          //存储亚像素边缘位置
    			}			
    		}
    	}
    
    	cv::Mat draw_image;
    	cv::cvtColor(canny_img, draw_image, cv::COLOR_GRAY2RGB);
    	//绘制亚像素边缘图
    	for (int i = 0; i < sub_pixel_edge.size(); i++)
    	{
    		circle(draw_image, sub_pixel_edge[i], 0, Scalar(255, 0, 255), 1, 0, 0);
    	}
    	imshow("sub pixel edge", draw_image);
    	cv::waitKey();
    	return 0;
    }
    

    原图如下:
    Canny结果如下
    在这里插入图片描述
    亚像素结果如下:
    在这里插入图片描述
    图中白色为Canny的像素位置,红色为亚像素的位置。因为图像像素只能画出整像素位置,所以仅供显示,看一下效果。若要准确对比相对位置,可以把亚像素坐标存储起来,用matlab画出来进行对比。

    展开全文
  • 介绍了Zernike 及基于Zernike 的图像亚像素边缘检测 原理, 针对Ghosal 提出的基于Zernike 的亚像素图像边缘检测算法 检测出的图像存在边缘较粗及边缘亚像素定位精度低等不足, 提出了一 种改进算法. 推导了七乘...
  • 与基于 Zernike 的亚像素级算法、基于小波变换与 Zernike 结合的亚像素级算法、基于 Roberts 算子与 Zernike 结合的亚像素级算法相比,本文提出的基于 Franklin 的亚像素级图像边缘检测算法速度更快,...
  • Zerrnike.py

    2020-03-14 12:06:16
    论坛Zernike矩边缘检测多基于matlab,通过Python语言编zernike矩边缘检测,希望可以帮助到初学者,测试图为512*512 Lena图。
  • 执行快速准确的亚像素边缘检测,基于改进的zernike矩方法,有需要的可以下载~~
  • 一种改进的正交 Fourier-Mellin 亚像素边缘检测算法 [C......本文提出一种新的亚像素精度的边缘检测算法 . 该方法给出了一种可修正的贝塞尔点扩...一种亚像素边缘检测方法_IT/计算机_专业资料。提出一种新的亚像素...
  • 亚像素边缘检测技术是采用图像处理软件算法来提高检测精度的有效途径, 文中对法、拟合法和插值法等常用的亚像素边缘检测算法的原理、优点和不足进行了分析 ,提出了Sigmoid函数拟合的亚像素边缘定位算法....

空空如也

空空如也

1 2
收藏数 40
精华内容 16
关键字:

zernike矩边缘检测