android openCV 应用 (五)图像边缘检测

目录

一、边缘检测原理

二、索贝尔算子(普鲁伊特算子)

三、Scharr算子

四、拉普拉斯算子

五、Canny 算法边缘检测

六、边缘检测算法比较

一、边缘检测原理

边缘检测是图像处理中的一个重要步骤,它旨在识别图像中的边缘特征。边缘通常表现为灰度值的不连续或剧烈变化,这些变化可以通过微分运算来检测。边缘检测的基本思想是利用微分运算(如一阶微分和二阶微分)来捕捉图像灰度值的变化,从而识别出边缘。

边缘类型:

  • Step edge(阶跃边缘):灰度突然变化
  • Ramp edge(斜坡边缘):灰度逐渐变化
  • Roof edge(屋顶边缘):灰度先增后减
  • Line edge(线边缘):宽度为1像素或窄条边缘

二、索贝尔算子(普鲁伊特算子)

Sobel算子是一种常用的边缘检测算子,它通过计算图像在水平方向和垂直方向的梯度来检测边缘。Sobel算子的实现步骤如下:

  • 步骤1‌:对图像进行高斯模糊处理,以减少噪声对边缘检测的影响。
  • 步骤2‌:将图像转换为灰度图像,因为边缘检测通常在灰度图像上进行。
  • 步骤3‌:使用Sobel算子计算图像在X方向和Y方向的梯度。
  • 步骤4‌:将梯度值转换为绝对值,并进行归一化处理。
  • 步骤5‌:合并X方向和Y方向的梯度,得到边缘图像。

以下是一个使用Sobel算子进行边缘检测的示例代码:

// 转换为灰度图像
Mat grayMat = new Mat();
Imgproc.cvtColor(imgMat, grayMat, Imgproc.COLOR_RGB2GRAY);

// 创建用于存储结果的Mat
Mat sobelX = new Mat();
Mat sobelY = new Mat();
Mat sobelEdges = new Mat();

// 使用Sobel算子计算图像的X和Y方向的梯度
Imgproc.Sobel(grayMat, sobelX, CvType.CV_16S, 1, 0, 3);
Imgproc.Sobel(grayMat, sobelY, CvType.CV_16S, 0, 1, 3);

// 合并X和Y方向的梯度,得到边缘图
Core.addWeighted(sobelX, 0.5, sobelY, 0.5, 0, sobelEdges);

// 将Mat转为Bitmap显示
Bitmap resultBitmap = Bitmap.createBitmap(sobelEdges.cols(), sobelEdges.rows(), Bitmap.Config.ARGB_8888);
Utils.matToBitmap(sobelEdges, resultBitmap);

// 显示处理后的图像
imageView.setImageBitmap(resultBitmap);

三、Scharr算子

Scharr算子是Sobel算子的一种改进,旨在提供更精确的边缘检测结果,特别是在处理图像中的细节和高频部分时。Scharr算子通过计算图像在水平和垂直方向上的一阶导数来定位边缘,它使用两个3x3的卷积核,一个用于水平方向,另一个用于垂直方向,这两个核被设计为对图像的变化更为敏感,从而能够更准确地检测出边缘。。Scharr算子的实现步骤如下:

  • 步骤1‌:对图像进行必要的预处理,如高斯模糊。
  • 步骤2‌:将图像转换为灰度图像。
  • 步骤3‌:使用Scharr算子计算图像在X方向和Y方向的梯度。
  • 步骤4‌:将导数值转换为绝对值,并进行归一化处理。
  • 步骤5‌:得到边缘图像。

以下是一个使用Scharr算子进行边缘检测的示例代码(省略了部分预处理步骤,假设已转换为灰度图像):

import org.opencv.android.OpenCVLoader;
import org.opencv.core.Core;
import org.opencv.core.CvType;
import org.opencv.core.Mat;
import org.opencv.core.Scalar;
import org.opencv.imgcodecs.Imgcodecs;
import org.opencv.imgproc.Imgproc;

public class ScharrEdgeDetection {

    static {
        if (!OpenCVLoader.initDebug()) {
            // Handle initialization error
        }
    }

    public static void main(String[] args) {
        // 读取图像
        Mat src = Imgcodecs.imread("image.jpg", Imgcodecs.IMREAD_GRAYSCALE);
        if (src.empty()) {
            System.out.println("Could not open or find the image!");
            return;
        }

        // 计算x方向的梯度
        Mat gradX = new Mat();
        Imgproc.Scharr(src, gradX, CvType.CV_16S, 1, 0);
        Core.convertScaleAbs(gradX, gradX);

        // 计算y方向的梯度
        Mat gradY = new Mat();
        Imgproc.Scharr(src, gradY, CvType.CV_16S, 0, 1);
        Core.convertScaleAbs(gradY, gradY);

        // 合并梯度
        Mat gradXY = new Mat();
        Core.addWeighted(gradX, 0.5, gradY, 0.5, 0, gradXY);

        // 保存结果
        Imgcodecs.imwrite("scharr_edge_detection.jpg", gradXY);

        System.out.println("Edge detection completed and result saved!");
    }
}

四、拉普拉斯算子

Laplacian算子是一个二阶导数算子,用于检测图像中的边缘。与Sobel算子不同,Laplacian算子通过计算图像灰度值变化的二阶导数来捕捉边缘。Laplacian算子的实现步骤如下:

  • 步骤1‌:对图像进行必要的预处理,如高斯模糊。
  • 步骤2‌:将图像转换为灰度图像。
  • 步骤3‌:使用Laplacian算子计算图像的二阶导数。
  • 步骤4‌:合并梯度,通过对两个方向的梯度图像进行加权求和来实现。
  • 步骤5‌:得到边缘图像。

以下是一个使用Laplacian算子进行边缘检测的示例代码(省略了部分预处理步骤,假设已转换为灰度图像):

// 使用Laplacian算子计算边缘
Mat laplacian = new Mat();
Imgproc.Laplacian(grayMat, laplacian, CvType.CV_16S, 3);

// 将导数值转换为绝对值,并进行归一化处理
Mat laplacianAbs = new Mat();
Core.convertScaleAbs(laplacian, laplacianAbs);

// 将Mat转为Bitmap显示
Bitmap resultBitmap = Bitmap.createBitmap(laplacianAbs.cols(), laplacianAbs.rows(), Bitmap.Config.ARGB_8888);
Utils.matToBitmap(laplacianAbs, resultBitmap);

// 显示处理后的图像
imageView.setImageBitmap(resultBitmap);

五、Canny 算法边缘检测

Canny算子是图像处理中最常用的边缘检测算法之一,它以高检测率和低误报率著称。

  • 最经典、鲁棒性强的边缘检测算法;
  • 使用梯度、非极大值抑制与双阈值连接判断边缘;
  • 更适用于自然图像。

Canny算子的实现步骤如下:

  • 步骤1‌:对图像进行高斯模糊处理。(去噪声,使曲线平滑)
  • 步骤2‌:计算图像的梯度幅值和方向。(用 Sobel 或 Prewitt 算子)
  • 步骤3‌:应用非极大值抑制,保留梯度方向上的局部最大值。
  • 步骤4‌:使用双阈值处理,得到强边缘和弱边缘。
    • 高于高阈值:强边缘
    • 低于低阈值:非边缘
    • 介于之间:连通强边缘则保留
  • 步骤5‌:通过滞后阈值化,连接强边缘和与强边缘相连的弱边缘,得到最终边缘图像。

以下是一个使用Canny算子进行边缘检测的示例代码:

// 应用高斯模糊减少噪声
Imgproc.GaussianBlur(grayMat, grayMat, new Size(5, 5), 1.5, 1.5);

// 使用Canny算子进行边缘检测
Mat edges = new Mat();
Imgproc.Canny(grayMat, edges, 100, 200);

// 将Mat转为Bitmap显示
Bitmap resultBitmap = Bitmap.createBitmap(edges.cols(), edges.rows(), Bitmap.Config.ARGB_8888);
Utils.matToBitmap(edges, resultBitmap);

// 显示处理后的图像
imageView.setImageBitmap(resultBitmap);

六、边缘检测算法比较

算法抗噪声能力精度是否方向敏感速度适用场景
Sobel一般较快简单图像边缘提取
Prewitt实时图像边缘提取
Roberts极快图像边缘估算
Laplacian较慢图像细节高的场景
Canny通用图像识别

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值