在Android上玩转Opencv 系列:11.基础知识 边缘检测

226 阅读4分钟

在 Android 中使用 OpenCV 进行边缘检测,通常涉及一些经典的图像处理算法,如 Canny 边缘检测Sobel 算子Laplacian 算子等。OpenCV 提供了多种函数来实现这些算法。下面我将逐步介绍这些函数的使用和应用场景。

1. Canny 边缘检测

Canny 边缘检测是图像处理中最常用的边缘检测算法之一,它的主要优点是能够准确检测出图像的边缘,并且具有较强的噪声抑制能力。

Canny 函数用法

Imgproc.Canny(Mat image, Mat edges, double threshold1, double threshold2);

image: 输入图像,通常是灰度图像。

edges: 输出图像,包含边缘的二值图像。

threshold1: 较低的阈值,用于边缘检测的梯度值。

threshold2: 较高的阈值,用于边缘检测的梯度值。

Canny 算法通过两个阈值来处理图像的边缘。第一个阈值用于强边缘的连接,第二个阈值用于弱边缘的连接。只有当梯度大于高阈值时,才认为是强边缘;梯度值介于低和高阈值之间时,认为是弱边缘,最终只有强边缘或者与强边缘相连的弱边缘才会被保留。

示例代码:Canny 边缘检测

import org.opencv.core.CvType;
import org.opencv.core.Mat;
import org.opencv.core.Size;
import org.opencv.imgproc.Imgproc;
import org.opencv.android.Utils;
import android.graphics.Bitmap;

public class MainActivity extends AppCompatActivity {

    static {
        System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // 获取图片
        Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.sample_image);

        // 将Bitmap转换为Mat
        Mat imgMat = new Mat();
        Utils.bitmapToMat(bitmap, imgMat);

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

        // 创建一个空的Mat来存储边缘图
        Mat edges = new Mat();

        // 使用Canny边缘检测
        Imgproc.GaussianBlur(grayMat, grayMat, new Size(5, 5), 1.5, 1.5);  // 高斯模糊,减少噪声
        Imgproc.Canny(grayMat, edges, 100, 200);  // 设置阈值为100和200

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

        // 显示处理后的图像
        ImageView imageView = findViewById(R.id.imageView);
        imageView.setImageBitmap(resultBitmap);
    }
}

2. Sobel 算子

Sobel 算子是一种常用的边缘检测算子,它通过计算图像在水平方向和垂直方向的梯度,来检测图像的边缘。Sobel 算子可以增强图像中的边缘信息,并且可以通过调整核的大小来控制检测的灵敏度。

Sobel 函数用法

Imgproc.Sobel(Mat image, Mat dest, int ddepth, int dx, int dy, int ksize, double scale, double delta, int borderType);

image: 输入图像。

dest: 输出图像,包含边缘检测的结果。

ddepth: 输出图像的深度,通常为 CvType.CV_8U 或 CvType.CV_16S。

dx: x方向的导数阶数,通常为 1 或 0。

dy: y方向的导数阶数,通常为 1 或 0。

ksize: Sobel 算子的大小(通常为 3、5 或 7)。

scale: 结果缩放因子。

delta: 可选的加值。

borderType: 边界的填充方法。

示例代码: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);

3. Laplacian 算子

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

Laplacian 函数用法

Imgproc.Laplacian(Mat image, Mat dest, int ddepth, int ksize, double scale, double delta, int borderType);

image: 输入图像。

dest: 输出图像,包含检测到的边缘。

ddepth: 输出图像的深度。

ksize: 卷积核的大小,通常为 1、3、5 或 7。

scale: 结果缩放因子。

delta: 可选的加值。

borderType: 边界的填充方法。

示例代码:Laplacian 边缘检测

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

// 创建Mat来存储结果
Mat laplacianEdges = new Mat();

// 使用Laplacian算子计算边缘
Imgproc.Laplacian(grayMat, laplacianEdges, CvType.CV_16S, 3, 1, 0, Core.BORDER_DEFAULT);

// 转换为8位图像
Mat absLaplacian = new Mat();
Core.convertScaleAbs(laplacianEdges, absLaplacian);

// 将结果转换为Bitmap
Bitmap resultBitmap = Bitmap.createBitmap(absLaplacian.cols(), absLaplacian.rows(), Bitmap.Config.ARGB_8888);
Utils.matToBitmap(absLaplacian, resultBitmap);

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

4. 边缘检测常见注意事项

  1. 图像预处理:在进行边缘检测之前,通常需要对图像进行预处理,如灰度化高斯模糊等。这样可以减少噪声对边缘检测结果的干扰。

  2. 阈值调整:边缘检测算法(如 Canny)的阈值设置非常重要。较高的阈值会导致检测到的边缘较少,而较低的阈值可能会导致图像中的噪声也被误认为边缘。

  3. 性能优化:图像处理可能会对性能产生较大影响,尤其是在较大的图像上。可以使用 OpenCV 的优化方法(如使用 GPU 加速)来提高性能。

总结

在 Android 中使用 OpenCV 进行边缘检测时,我们可以选择不同的算法(如 Canny、Sobel、Laplacian)根据需求进行边缘提取。每种算法都有自己的优缺点,通常需要根据具体的应用场景来选择合适的算法。通过合适的图像预处理和参数调节,可以获得精确的边缘检测效果。