图像处理(九)边缘检测(一)

边缘检测就是找到图像中边缘像素点的过程,从而生成一副边缘图。一般来说边缘检测分为3步:

(1)       基于各种原理和方法找到潜在的边缘点;

(2)       选取阈值,生成二值边缘图;

(3)       有些算法还要进行边缘细化、连接等后续处理

边缘是图像中灰度值不连续的结果,这种不连续性常可以利用求导数的方法方便的检测到,一般常用已接到数和二阶导数来检测边缘。图像中目标的边缘可通过求取她们的导数来确定。导数可用微分算子来计算,而数字图像中求取导数是利用差分近似微分来进行的。在一阶导数方法中,对图像中两个正交方向分别求偏导数,然后对这两个偏导数取不同的范数做为边缘强度,即可得到边缘图像。在这里,我们最常用的以2为模的范数形式,即对这两个偏导数去平方和,再开平方。在实际计算中,求偏导数常常采用的是小区域模进行卷积来近似计算的一阶导数模板算子最常用的方法有Roberts算子法,Prewitt算子法和Sobel算子法。

在这仅介绍一阶导数模板算子,以下是Roberts、Prewitt、Sobel三种算子的模板

Roberts算子

                    

Prewitt算子

                   

Sobel算子

   

具体算法实现(代码中有形态学边缘检测部分,下篇博文再讲)

/// <summary>
    /// 边缘检测
    /// </summary>
    /// <param name="srcBmp">原始图像</param>
    /// <param name="edgeDetectors">边缘检测算子</param>
    /// <param name="dstBmp">目标图像</param>
    /// <param name="mask">模板</param>
    /// <param name="T">阈值,当算子为拉普拉斯时有用</param>
    /// <returns>处理成功 true 失败 false</returns>
    public static bool Edge(Bitmap srcBmp, EdgeDetectors edgeDetectors, out Bitmap dstBmp, int[] mask = null,int T=0) {
        if (srcBmp == null) {
            dstBmp = null;
            return false;
        }
        int[] template = new int[25];
        if (mask != null) { template = mask; }
        Bitmap tempSrcBmp = new Bitmap(srcBmp);//为形态学边缘检测所用
        dstBmp = new Bitmap(srcBmp);
        BitmapData bmpDataSrc = srcBmp.LockBits(new Rectangle(0, 0, srcBmp.Width, srcBmp.Height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
        BitmapData bmpDataDst = dstBmp.LockBits(new Rectangle(0, 0, dstBmp.Width, dstBmp.Height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
        //double[] laplacianArray = new double[bmpDataSrc.Stride * bmpDataSrc.Height];//存储拉普拉斯算子中间结果 
        unsafe {
            byte* ptrSrc = (byte*)bmpDataSrc.Scan0;
            byte* ptrDst = (byte*)bmpDataDst.Scan0;
            double gradX, gradY, grad;
            switch (edgeDetectors) {
                case EdgeDetectors.Roberts://Roberts算子
                    for (int i = 0; i < srcBmp.Height; i++) {
                        for (int j = 0; j < srcBmp.Width; j++) {
                            gradX = ptrSrc[i * bmpDataSrc.Stride + j * 3] - ptrSrc[(i + 1) % srcBmp.Height * bmpDataSrc.Stride + (j + 1) % srcBmp.Width * 3];
                            gradY = ptrSrc[i * bmpDataSrc.Stride + (j + 1) % srcBmp.Width * 3] - ptrSrc[(i + 1) % srcBmp.Height * bmpDataSrc.Stride + j * 3];
                            grad = Math.Sqrt(gradX * gradX + gradY * gradY);
                            grad = grad > 255 ? 255 : grad;
                            ptrDst[i * bmpDataDst.Stride + j * 3] = ptrDst[i * bmpDataDst.Stride + j * 3 + 1] = ptrDst[i * bmpDataDst.Stride + j * 3 + 2] = (byte)grad;
                        }
                    }
                    break;
                case EdgeDetectors.Prewitt://prewitt算子
                    for (int i = 0; i < srcBmp.Height; i++) {
                        for (int j = 0; j < srcBmp.Width; j++) {
                            gradX = ptrSrc[Math.Abs(i - 1) % srcBmp.Height * bmpDataSrc.Stride + (j + 1) % srcBmp.Width * 3] +
                                    ptrSrc[i * bmpDataSrc.Stride + (j + 1) % srcBmp.Width * 3] +
                                    ptrSrc[(i + 1) % srcBmp.Height * bmpDataSrc.Stride + (j + 1) % srcBmp.Width * 3] -
                                    ptrSrc[Math.Abs(i - 1) % srcBmp.Height * bmpDataSrc.Stride + Math.Abs(j - 1) % srcBmp.Width * 3] -
                                    ptrSrc[i * bmpDataSrc.Stride + Math.Abs(j - 1) % srcBmp.Width * 3] -
                                    ptrSrc[(i + 1) % srcBmp.Height * bmpDataSrc.Stride + Math.Abs(j - 1) % srcBmp.Width * 3];
                            gradY = ptrSrc[Math.Abs(i - 1) % srcBmp.Height * bmpDataSrc.Stride + Math.Abs(j - 1) % srcBmp.Width * 3] +
                                    ptrSrc[Math.Abs(i - 1) % srcBmp.Height * bmpDataSrc.Stride + j * 3] +
                                    ptrSrc[Math.Abs(i - 1) % srcBmp.Height * bmpDataSrc.Stride + (j + 1) % srcBmp.Width * 3] -
                                    ptrSrc[(i + 1) % srcBmp.Height * bmpDataSrc.Stride + Math.Abs(j - 1) % srcBmp.Width * 3] -
                                    ptrSrc[(i + 1) % srcBmp.Height * bmpDataSrc.Stride + j * 3] -
                                    ptrSrc[(i + 1) % srcBmp.Height * bmpDataSrc.Stride + (j + 1) % srcBmp.Width * 3];
                            grad = Math.Sqrt(gradX * gradX + gradY * gradY);
                            grad = grad > 255 ? 255 : grad;
                            ptrDst[i * bmpDataDst.Stride + j * 3] = ptrDst[i * bmpDataDst.Stride + j * 3 + 1] = ptrDst[i * bmpDataDst.Stride + j * 3 + 2] = (byte)grad;
                        }
                    }
                    break;
                case EdgeDetectors.Sobel://solbel算子
                    for (int i = 0; i < srcBmp.Height; i++) {
                        for (int j = 0; j < srcBmp.Width; j++) {
                            gradX = ptrSrc[Math.Abs(i - 1) % srcBmp.Height * bmpDataSrc.Stride + (j + 1) % srcBmp.Width * 3] +
                                    2 * ptrSrc[i * bmpDataSrc.Stride + (j + 1) % srcBmp.Width * 3] +
                                    ptrSrc[(i + 1) % srcBmp.Height * bmpDataSrc.Stride + (j + 1) % srcBmp.Width * 3] -
                                    ptrSrc[Math.Abs(i - 1) % srcBmp.Height * bmpDataSrc.Stride + Math.Abs(j - 1) % srcBmp.Width * 3] -
                                    2 * ptrSrc[i * bmpDataSrc.Stride + Math.Abs(j - 1) % srcBmp.Width * 3] -
                                    ptrSrc[(i + 1) % srcBmp.Height * bmpDataSrc.Stride + Math.Abs(j - 1) % srcBmp.Width * 3];
                            gradY = ptrSrc[Math.Abs(i - 1) % srcBmp.Height * bmpDataSrc.Stride + Math.Abs(j - 1) % srcBmp.Width * 3] +
                                    2 * ptrSrc[Math.Abs(i - 1) % srcBmp.Height * bmpDataSrc.Stride + j * 3] +
                                    ptrSrc[Math.Abs(i - 1) % srcBmp.Height * bmpDataSrc.Stride + (j + 1) % srcBmp.Width * 3] -
                                    ptrSrc[(i + 1) % srcBmp.Height * bmpDataSrc.Stride + Math.Abs(j - 1) % srcBmp.Width * 3] -
                                    2 * ptrSrc[(i + 1) % srcBmp.Height * bmpDataSrc.Stride + j * 3] -
                                    ptrSrc[(i + 1) % srcBmp.Height * bmpDataSrc.Stride + (j + 1) % srcBmp.Width * 3];
                            grad = Math.Sqrt(gradX * gradX + gradY * gradY);
                            grad = grad > 255 ? 255 : grad;
                            ptrDst[i * bmpDataDst.Stride + j * 3] = ptrDst[i * bmpDataDst.Stride + j * 3 + 1] = ptrDst[i * bmpDataDst.Stride + j * 3 + 2] = (byte)grad;
                        }
                    }
                    break;
                case EdgeDetectors.Morphology://形态学边缘检测
                    Bitmap erodeBmp = null, expBmp = null;
                    ImageFormats f = GetImageFormat(tempSrcBmp);
                    Erode(tempSrcBmp, ScanStruction.Custom, f, out erodeBmp, mask);
                    Expansion(tempSrcBmp, ScanStruction.Custom, f, out expBmp, mask);
                    BitmapData erodeBmpData = erodeBmp.LockBits(new Rectangle(0, 0, erodeBmp.Width, erodeBmp.Height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
                    BitmapData expBmpData = expBmp.LockBits(new Rectangle(0, 0, expBmp.Width, expBmp.Height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
                    unsafe {
                        int tempB, tempG, tempR;
                        byte* ptrErode = (byte*)erodeBmpData.Scan0;
                        byte* ptrExp = (byte*)expBmpData.Scan0;
                        for (int i = 0; i < expBmp.Height; i++) {
                            for (int j = 0; j < expBmp.Width; j++) {
                                tempB = (ptrExp[i * expBmpData.Stride + j * 3] - ptrErode[i * expBmpData.Stride + j * 3])/2;
                                tempG = (ptrExp[i * expBmpData.Stride + j * 3+1] - ptrErode[i * expBmpData.Stride + j * 3+1])/2;
                                tempR = (ptrExp[i * expBmpData.Stride + j * 3+2] - ptrErode[i * expBmpData.Stride + j * 3+2])/2;
                                tempB = tempB < 0 ? 0 : tempB;
                                tempG = tempG < 0 ? 0 : tempG;
                                tempR = tempR < 0 ? 0 : tempR;
                                ptrDst[i * bmpDataDst.Stride + j * 3] = (byte)tempB;
                                ptrDst[i * bmpDataDst.Stride + j * 3+1] = (byte)tempG;
                                ptrDst[i * bmpDataDst.Stride + j * 3+2] = (byte)tempR;
                            }
                        }
                    }
                    break;
                default:
                    break;
            }
        }
        srcBmp.UnlockBits(bmpDataSrc);
        dstBmp.UnlockBits(bmpDataDst);

        return true;
    }
处理结果



  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值