opencv:边缘检测之kirsch算子

边缘检测的方法有主要有两种:
一种是基于模板匹配的,简单来说即用多个方向的检测模板与图像进行卷积,然后取邻域像素点的最大值。这种方法简单方便,容易理解,容易得到平滑的边缘,但是由于采用非常有限方向的模板(一般是8个方向,但是由于对称性可以减少为4个),因此不能检测出所有的边缘方向。
一种是基于求图像梯度的方法,一阶二阶的梯度算子,如sobel、prewitt、Robert等一阶算子和拉普拉斯算子。检测的灵敏度高,精度定位准确,但同时容易受到噪声点的影响。
kirsch算子属于模板匹配算子,采用八个模板来处理图像的检测图像的边缘,运算量比较大。
8个3x3模板如下:


通过矩阵变换发现经过kirsch算子得到的像素值直接的关系,事实上需要直接由邻域像素点计算得到的只有p0,,因此可以大大减少计算量。

//kirsch算子滤波
void kirsch(const IplImage* src, CvMat* dst)
{
                 if (src->nChannels != 1 && dst->type != 1)
                {
                                cvError(CV_BadNumChannels, "kirsch", "The channels of image must be 1" , __FILE__, __LINE__);
                                 return;
                }
                 if (src->width != dst->width || src->height != dst->height)
                {
                                cvError(CV_StsUnmatchedSizes, "kirsch", "The sizes of input/output must be same" , __FILE__, __LINE__);
                                 return;
                }
                 //保存当前像素的八个模板滤波的结果
                 vector<double > r(8);
                 vector<double > p(8);
                CvMat* temp = cvCreateMat(src->height + 2, src->width + 2, CV_64FC1);
                CvMat* src_copy = cvCreateMat(src->height, src->width, CV_64FC1);
                cvConvertScale(src, src_copy);
                cvCopyMakeBorder(src_copy, temp, cvPoint(1, 1), IPL_BORDER_REPLICATE);
                 for (int y = 1; y != temp->rows - 1; ++y)
                {
                                 for (int x = 1; x != temp->cols - 1; ++x)
                                {
                                                 //8个邻域像素值
                                                p[0] = CV_MAT_ELEM(*temp, double , y - 1, x - 1);
                                                p[1] = CV_MAT_ELEM(*temp, double , y - 1, x);
                                                p[2] = CV_MAT_ELEM(*temp, double , y - 1, x + 1);
                                                p[3] = CV_MAT_ELEM(*temp, double , y, x + 1);
                                                p[4] = CV_MAT_ELEM(*temp, double , y + 1, x + 1);
                                                p[5] = CV_MAT_ELEM(*temp, double , y + 1, x);
                                                p[6] = CV_MAT_ELEM(*temp, double , y + 1, x - 1);
                                                p[7] = CV_MAT_ELEM(*temp, double , y, x - 1);
                                                r[0] = 0.625*(p[0] + p[1] + p[2]) - 0.375*(p[3] + p[4] + p[5] + p[6] + p[7]);
                                                r[1] = r[0] + p[7] - p[2];
                                                r[2] = r[1] + p[6] - p[1];
                                                r[3] = r[2] + p[5] - p[0];
                                                r[4] = r[3] + p[4] - p[7];
                                                r[5] = r[4] + p[3] - p[6];
                                                r[6] = r[5] + p[2] - p[5];
                                                r[7] = r[6] + p[1] - p[4];
                                                 //排序
                                                std::sort(r.begin(), r.end());
                                                 //if (r[1] != 0)
                                                 //{
                                                 //             cout<<"r1 != 0"<<endl;
                                                 //}
                                                *(( double*)CV_MAT_ELEM_PTR(*dst, y - 1, x - 1)) = 8*r[7];
                                }
                }
                cvReleaseMat(&src_copy);
                cvReleaseMat(&src_copy);
}

由lena得到的边缘图像:



  • 2
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值