Android使用Sobel算法边缘检测

效果图:

从左往右分别为原图、灰度图、进行边缘检测后的图

    

 

先说说Sobel边缘检测算法:

Sobel算子是计算机视觉领域的一种重要处理方法。主要用于获得数字图像的一阶梯度,常见的应用和物理意义是边缘检测。在技术上,它是一个离散的一阶差分算子,用来计算图像亮度函数的一阶梯度之近似值。在图像的任何一点使用此算子,将会产生该点对应的梯度矢量或是其法矢量。

 

该算子包含两组3x3的矩阵,分别为横向及纵向,将之与图像作平面卷积,即可分别得出横向及纵向的亮度差分近似值。如果以A代表原始图像,Gx及Gy分别代表经横向及纵向边缘检测的图像,其卷积因子和公式如下:

 

Sobel的卷积因子:


公式:


图像的每一个像素的横向及纵向梯度近似值可用以下的公式结合,来计算梯度的大小:





具体计算如下:



getPixel()方法是获取bitmap图象x, y位置的像素

可以看到上面我用到了Math.sqrt(2)这是对2进行开方是因为我用了sobel的另一种形式

 

Sobel算子另一种形式是各向同性Sobel(IsotropicSobel)算子,也有两个,一个是检测水平边缘的,另一个是检测垂直边缘的。各向同性Sobel算子和普通Sobel算子相比,它的位置加权系数更为准确,在检测不同方向的边沿时梯度的幅度一致。将Sobel算子矩阵中的所有2改为根号2,就能得到各向同性Sobel的矩阵。

 

 

知道了sobel算子的算法,接下来就开始实现:

Sobel.java部分代码:

@Override
    public void detection(Bitmap originalBitmap) {

        //原图
        this.originalBitmap = originalBitmap;

        //将原图灰度化
        this.temp = BitmapUtil.toGrayscale(this.originalBitmap);
        //图片的宽高
        int w = temp.getWidth();
        int h = temp.getHeight();

        //存放灰度图个像素点的数值
        mmap = new int[w * h];
        //存放计算后各对应点的数值
        tmap = new double[w * h];

        //获取灰度图各像素点的数值,并赋给mmap数组
        temp.getPixels(mmap, 0, temp.getWidth(), 0, 0, temp.getWidth(),
                temp.getHeight());

        //保存数值最大的数
        max = -999;
        //进行计算
        for (int i = 0; i < w; i++) {
            for (int j = 0; j < h; j++) {
                //计算横向数值
                double gx = GX(i, j, temp);
                //计算纵向数值
                double gy = GY(i, j, temp);
                //进行开方处理
                tmap[j * w + i] = Math.sqrt(gx * gx + gy * gy);
                //保存最大值
                if (max < tmap[j * w + i]) {
                    max = tmap[j * w + i];
                }
            }
        }

}


/**
     *
     * 根据设定的阙值获取处理后的图片
     *
     * @param a
     * @param b
     * @param c
     *
     */
    public void getBitmap(double a, double b, double c){

        //如果阙值为0,返回灰度图
        if(a == 0 && b == 0 && c == 0){
            iMain.setBitmap(temp);
            return ;
        }

        int w = temp.getWidth();
        int h = temp.getHeight();
        //存放处理后的图象各像素点的数组
        int[] cmap = new int[w * h];

        //筛选计算
        for (int i = 0; i < w; i++) {
            for (int j = 0; j < h; j++) {
                if (tmap[j * w + i] > max * a) {
                    //如果大于阙值max*a,则保存灰度图该点的像素
                    cmap[j * w + i] = mmap[j * w + i];
                } else if (tmap[j * w + i] > max * b) {
                    //否则如果大于阙值max*b,则保存灰度图该点的像素+50,(变淡)
                    cmap[j * w + i] = getColor(mmap[j * w + i], 50);
                } else if (tmap[j * w + i] > max * c) {
                    //否则如果大于阙值max*c,则保存灰度图该点的像素+80,(变得更淡)
                    cmap[j * w + i] = getColor(mmap[j * w + i], 80);
                } else {
                    //否则该点为白色
                    cmap[j * w + i] = Color.WHITE;
                }
            }
        }

        //将筛选出来的结果生成bitmap
        Bitmap bm =  Bitmap.createBitmap(cmap, temp.getWidth(), temp.getHeight(),
                Bitmap.Config.ARGB_8888);

        iMain.setBitmap(bm);
    }

可以看到这里我用了三个阙值,原来的算法是只用了一个阙值,但是我自己测试后,发现一个阙值处理出来的图片边缘还是不够平滑,所以写多两个阙值

 

颜色处理方法:

/**
     * 处理颜色
     * @param color
     * @param value value为负数时颜色加深,为正数时颜色变淡
     * @return
     */
    private int getColor(int color, int value) {

        int cr, cg, cb;

        cr = (color & 0x00ff0000) >> 16;
        cg = (color & 0x0000ff00) >> 8;
        cb = color & 0x000000ff;

        cr += value;
        cg += value;
        cb += value;

        if(cr > 255){
            cr = 255;
        }
        if(cg > 255){
            cg = 255;
        }
        if(cb > 255){
            cb = 255;
        }

        if(cr < 0){
            cr = 0;
        }
        if(cg < 0){
            cg = 0;
        }
        if(cb < 0){
            cb = 0;
        }

        return Color.argb(255, cr, cg, cb);
    }


由于代码较多,这里就一一展示了,具体可以看看我的代码:

Github地址: https://github.com/smileysx/EdgeDetection

 

这里几次用到了两个for循环,一张图片两个for循环,处理时间可想而知。

所以我在里面处理图片的时候开启了一个子线程去处理。

 

后面会说下用RenderScript处理图象,能更快处理图象。

 

 

效果图:

     

    


代码地址:

Github地址: https://github.com/smileysx/EdgeDetection


参考文章:

1. Android自动手绘,圆你儿时画家梦!

2.Sobel边缘检测算法




  • 13
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值