Android OpenCV(二十五):Laplacian算子边缘检测

948 阅读2分钟

Laplacian 算子

Laplacian算子具有各方向同性的特点,能够对任意方向的边缘进行提取,具有无方向性的优点,因此使用Laplacian算子提取边缘不需要分别检测X方向的边缘和Y方向的边缘,只需要一次边缘检测即可。Laplacian算子是一种二阶导数算子,对噪声比较敏感,因此常需要配合高斯滤波一起使用。

如果邻域系统是4邻域,Laplacian 算子的模板为:

(010141010)\begin{pmatrix} 0 & 1 & 0\\ 1 & -4 & 1 \\0 & 1 & 0\end{pmatrix}

如果邻域系统是8邻域,Laplacian 算子的模板为:

(111181111)\begin{pmatrix} 1 & 1 & 1\\ 1 & -8& 1 \\1 & 1 & 1\end{pmatrix}

API

public static void Laplacian(Mat src, Mat dst, int ddepth, int ksize, double scale, double delta, int borderType)
  • 参数一:src,输入图像。
  • 参数二:dst,输出图像,与输入图像具有相同的尺寸和通道数。
  • 参数三:ddepth,输出图像的数据类型(深度),根据输入图像的数据类型不同拥有不同的取值范围。当赋值为-1时,输出图像的数据类型自动选择。
  • 参数四:ksize,滤波器的大小,必须为正奇数。
  • 参数五:scale,对导数计算结果进行缩放的缩放因子,默认系数为1,不进行缩放
  • 参数六:delta,偏值,在计算结果中加上偏值。
  • 参数七:borderType,像素外推法选择标志。默认参数为BORDER_DEFAULT,表示不包含边界值倒序填充。

函数的前两个参数分别为输入图像和输出图像,第三个参数为输出图像的数据类型,这里需要注意由于提取边缘信息时有可能会出现负数,因此不要使用CV_8U数据类型的输出图像,否则会使得图像边缘提取不准确。函数第四个参数是滤波器尺寸的大小,必须是正奇数,当该参数的值大于1时,该函数通过Sobel算子计算出图像X方向和Y方向的二阶导数,将两个方向的导数求和得到Laplacian算子。

操作

/**
 * Laplacian算子-边缘检测
 *
 * @author yidong
 * @date 2020-05-18
 */
class LaplacianEdgeDetectionActivity : AppCompatActivity() {


    private lateinit var mBinding: ActivityEdgeDetectionBinding
    private lateinit var mRgb: Mat

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        mBinding = DataBindingUtil.setContentView(this, R.layout.activity_edge_detection)
        val bgr = Utils.loadResource(this, R.drawable.lena)
        mRgb = Mat()
        Imgproc.cvtColor(bgr, mRgb, Imgproc.COLOR_BGR2RGB)
        showMat(mBinding.ivLena, mRgb)
    }

    override fun onCreateOptionsMenu(menu: Menu?): Boolean {
        menuInflater.inflate(R.menu.menu_laplacian, menu)
        return true
    }

    override fun onOptionsItemSelected(item: MenuItem): Boolean {
        when (item.itemId) {
            R.id.without_blur_edge_detection -> {
                edgeDetection()
            }
            R.id.with_blur_edge_detection -> {
                edgeDetectionAfterBlur()
            }
        }
        return true
    }

    private fun showMat(view: ImageView, source: Mat) {
        val bitmap = Bitmap.createBitmap(source.width(), source.height(), Bitmap.Config.ARGB_8888)
        bitmap.density = 360
        Utils.matToBitmap(source, bitmap)
        view.setImageBitmap(bitmap)
    }

    private fun edgeDetection() {
        title = "Laplacian边缘检测"
        val result = Mat()
        Imgproc.Laplacian(mRgb, result, CvType.CV_16S, 3, 1.0, 0.0)
        Core.convertScaleAbs(result, result)
        showMat(mBinding.ivResult, result)
    }

    private fun edgeDetectionAfterBlur() {
        title = "高斯滤波后Laplacian边缘检测"
        val resultG = Mat()
        val result = Mat()
        Imgproc.GaussianBlur(mRgb, resultG, Size(3.0, 3.0), 5.0, 0.0)
        Imgproc.Laplacian(resultG, result, CvType.CV_16S, 3, 1.0, 0.0)
        Core.convertScaleAbs(result, result)
        showMat(mBinding.ivResult, result)
    }
}

效果

直接Laplacian边缘检测 高斯滤波后Laplacian边缘检测

源码

github.com/onlyloveyd/…