opencv:边缘检测之kirsch算子

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

opencv:边缘检测之kirsch算子_第1张图片

opencv:边缘检测之kirsch算子_第2张图片

通过矩阵变换发现经过kirsch算子得到的像素值直接的关系,事实上需要直接由邻域像素点计算得到的只有p0,,因此可以大大减少计算量。
opencv:边缘检测之kirsch算子_第3张图片

//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 r(8);
                 vector 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"<

由lena得到的边缘图像:

opencv:边缘检测之kirsch算子_第4张图片

你可能感兴趣的:(opencv,C++)