Android OpenCV基础(四、边缘检测)

一、概述

  在OpenGL图片处理中介绍过OpenGL实现边缘检测的方法,本章介绍OpenCV实现边缘检测的方法,这些方法都位于imgproc模块。

二、Sobel算子

  Sobel算子的原理是:边缘可以通过定位梯度值大于邻域的相素的方法找到(或者推广到大于一个阀值)。Sobel算子是一个离散微分算子 (discrete differentiation operator),它用来计算图像灰度函数的近似梯度。

  Sobel算子结合了高斯平滑和微分求导。当内核大小为 3 时, Sobel内核可能产生比较明显的误差(毕竟,Sobel算子只是求取了导数的近似值)。为解决这一问题,OpenCV提供了Scharr()函数,但该函数仅作用于大小为3的内核。该函数的运算与Sobel函数一样快,但结果却更加精确。

  Soble的调用方式如下:

extern "C"
JNIEXPORT jobject JNICALL
Java_com_bc_sample_OpenCVSample_sobel(JNIEnv *env,
                                      jclass thiz, jobject bitmap) {
    cv::Mat rgbMat;
    bitmapToMat(env, bitmap, rgbMat);
    Mat grad, src_gray;
    /// 使用高斯滤波消除噪声
    GaussianBlur(rgbMat, rgbMat, Size(3, 3), 0, 0, BORDER_DEFAULT);
    /// 转换为灰度图
    cvtColor(rgbMat, src_gray, CV_RGBA2GRAY);
    /// 创建 grad_x 和 grad_y 矩阵
    Mat grad_x, grad_y;
    Mat abs_grad_x, abs_grad_y;
    int scale = 1;
    int delta = 0;
    int ddepth = CV_16S;
    /// 求 X方向梯度
    //Scharr( src_gray, grad_x, ddepth, 1, 0, scale, delta, BORDER_DEFAULT );
    Sobel(src_gray, grad_x, ddepth, 1, 0, 3, scale, delta, BORDER_DEFAULT);
    convertScaleAbs(grad_x, abs_grad_x);
    /// 求Y方向梯度
    //Scharr( src_gray, grad_y, ddepth, 0, 1, scale, delta, BORDER_DEFAULT );
    Sobel(src_gray, grad_y, ddepth, 0, 1, 3, scale, delta, BORDER_DEFAULT);
    convertScaleAbs(grad_y, abs_grad_y);
    /// 合并梯度(近似)
    addWeighted(abs_grad_x, 0.5, abs_grad_y, 0.5, 0, grad);
    jobject resultBitmap = createBitmap(env, grad.cols, grad.rows, "ARGB_8888");
    matToBitmap(env, grad, resultBitmap);
    return resultBitmap;
}

  运行后结果如下所示:
image.png

三、Laplace算子

  Laplace算子的原理是:边缘点的二阶导数为0。所以我们也可以用这个特点来作为检测图像边缘的方法。Laplace算子的调用方式如下:

extern "C"
JNIEXPORT jobject JNICALL
Java_com_bc_sample_OpenCVSample_laplace(JNIEnv *env,
                                        jclass thiz, jobject bitmap) {
    cv::Mat rgbMat, src_gray, dst;
    bitmapToMat(env, bitmap, rgbMat);
    int kernel_size = 3;
    int scale = 1;
    int delta = 0;
    int ddepth = CV_16S;
    /// 使用高斯滤波消除噪声
    GaussianBlur(rgbMat, rgbMat, Size(3, 3), 0, 0, BORDER_DEFAULT);
    /// 转换为灰度图
    cvtColor(rgbMat, src_gray, CV_RGB2GRAY);
    /// 使用Laplace函数
    Mat abs_dst;
    Laplacian(src_gray, dst, ddepth, kernel_size, scale, delta, BORDER_DEFAULT);
    convertScaleAbs(dst, abs_dst);
    jobject resultBitmap = createBitmap(env, abs_dst.cols, abs_dst.rows, "ARGB_8888");
    matToBitmap(env, abs_dst, resultBitmap);
    return resultBitmap;
}

  运行后结果如下所示:
image.png

四、Canny算法

  Canny边缘检测算法是John F. Canny 于1986年开发出来的一个多级边缘检测算法,也被很多人认为是边缘检测的最优算法。Canny算法的主要步骤是消除噪声、计算梯度幅值和方向、非极大值抑制、滞后阈值。Canny算法的调用步骤如下:

extern "C"
JNIEXPORT jobject JNICALL
Java_com_bc_sample_OpenCVSample_canny(JNIEnv *env,
                                      jclass thiz, jobject bitmap) {
    cv::Mat src, src_gray, dst, detected_edges;
    bitmapToMat(env, bitmap, src);
    /// 转换为灰度图
    cvtColor(src, src_gray, CV_RGB2GRAY);
    /// 使用高斯滤波消除噪声
    GaussianBlur(src, src, Size(3, 3), 0, 0, BORDER_DEFAULT);
    int edgeThresh = 1;
    int lowThreshold;
    int ratio = 3;
    int kernel_size = 3;
    /// 使用 3x3内核降噪
    blur(src_gray, detected_edges, Size(3, 3));
    /// 运行Canny算子
    Canny(detected_edges, detected_edges, lowThreshold, lowThreshold * ratio, kernel_size);
    /// 使用Canny算子输出边缘作为掩码显示原图像
    dst = Scalar::all(0);
    src.copyTo(dst, detected_edges);
    jobject resultBitmap = createBitmap(env, dst.cols, dst.rows, "ARGB_8888");
    matToBitmap(env, dst, resultBitmap);
    return resultBitmap;
}

  运行后结果如下所示:
image.png

五、输出轮廓

  Opencv的findContours也是一个比较常用的方法,这个方法可以把图片的轮廓输出到一个vector中。常用来和以上边缘检测算法配合使用来得到一个比较理想的轮廓结果。

extern "C"
std::vector<std::vector<Point>> opencv_sample_findContours(JNIEnv *env,
                                      jclass thiz, jobject bitmap) {
    cv::Mat src;
    bitmapToMat(env, bitmap, src);
    std::vector<std::vector<Point>> contours;
    std::vector<Vec4i> hierarchy;
    /// 寻找轮廓,或者也可以在canny算法后的mat上使用寻找轮廓来获得比较理想的结果
    findContours(src, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, Point(0, 0) );
    return contours;
}

The End

欢迎关注我,一起解锁更多技能:BC的掘金主页~💐 BC的CSDN主页~💐💐
请添加图片描述

OpenCV官网:https://opencv.org/releases/

OpenCV github:https://github.com/opencv/opencv/tree/master

OpenCV2.3.2相关文档:https://www.w3cschool.cn/opencv/

BC的OpenCV专栏:https://juejin.cn/column/7082319523646291976

LearnOpenCV学习资料

OpenCV 4.5.5官方文档

OpenCV 2.3.2官方文档

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值