Java OpenCV Laplacian算子

Laplacian算子说明

普拉斯算子是最简单的各向同性微分算子,具有旋转不变性。一个二维图像函数 的拉普拉斯变换是各向同性的二阶导数,定义为:
在这里插入图片描述
在一个二维函数f(x,y)中,x,y两个方向的二阶差分分别为,
在这里插入图片描述
在这里插入图片描述
为了更适合于数字图像处理,将该方程表示为离散形式:
在这里插入图片描述
写成filter mask的形式如下,
在这里插入图片描述
       注意该(a)的mask的特点,mask在上下左右四个90度的方向上结果相同,也就是说在90度方向上无方向性。为了让该mask在45度的方向上也具有该性质,对该filter mask进行扩展定义为(b)。
       将Laplace算子写成filter mask后,其操作大同小异于其他的空间滤波操作。将filter mask在原图上逐行移动,然后mask中数值与其重合的像素相乘后求和,赋给与mask中心重合的像素,对图像的第一,和最后的行和列无法做上述操作的像素赋值零,就得到了拉普拉斯操作结果。

OpenCV Laplacian函数说明

函数介绍

Imgproc.Laplacian(Mar src, Mat dst, int ddepth, int ksize, double scale, double delta, int borderType);
src :图片
dst :目标图
ddepth :目标图像的深度。因为输入图像一般为CV_8U,为了避免数据溢出,输出图像深度应该设置为CV_16S
ksize : 内核尺寸
scale : 计算Laplacian的时候可选的比例因子,默认为1。具体说明在下面讲述
delta : 额外加的数值,就是在卷积过程中该数值会添加到每个像素上。具体说明在下面讲述
borderType : 边界填充方式。默认BORDER_DEFAULT。边界填充说明

OpenCV Laplacian源码

下面的代码选自Opencv2.4.9源码文件opencv\sources\modules\imgproc\src文件夹下的deriv.cpp文件,该cpp文件中的Laplacian(…)函数源码,下面只显示了ksize=1or3的情况,

void cv::Laplacian( InputArray _src, OutputArray _dst, int ddepth, int ksize,
                    double scale, double delta, int borderType )
{
    Mat src = _src.getMat();
    if (ddepth < 0)
        ddepth = src.depth();
    _dst.create( src.size(), CV_MAKETYPE(ddepth, src.channels()) );
    Mat dst = _dst.getMat();

    if( ksize == 1 || ksize == 3 )
    {
        float K[2][9] =
        {{0, 1, 0, 1, -4, 1, 0, 1, 0},
         {2, 0, 2, 0, -8, 0, 2, 0, 2}};
        Mat kernel(3, 3, CV_32F, K[ksize == 3]);
        if( scale != 1 )
            kernel *= scale;
        filter2D( src, dst, ddepth, kernel, Point(-1,-1), delta, borderType );
    }else
    {
	    //ksize等于其他值的情况
    }
}

函数效果

代码

	public static void main(String[] args) {
	
        //读入图片
        Mat src = Imgcodecs.imread("G:\\opencvPhoto\\photo\\timg.jpg");
        //Laplacian算子对噪音敏感,事先去噪
        Imgproc.GaussianBlur(src, src, new Size(3, 3), 0);
        //灰度化
        Imgproc.cvtColor(src, src, Imgproc.COLOR_BGR2GRAY);
		Mat dst = new Mat();
        Imgproc.Laplacian(src, dst, CvType.CV_16S, 3, 1, 0, Core.BORDER_DEFAULT);
        Imgcodecs.imwrite("G:\\opencvPhoto\\result\\dst.jpg", dst);

    }

原图
在这里插入图片描述
效果
在这里插入图片描述

运行原理

  1. 以OpenCV的Laplacian内核大小为3时的内核为例
  2. filter2D函数说明
	public static void main(String[] args) {

        //读入图片
        Mat src = Imgcodecs.imread("G:\\opencvPhoto\\photo\\picture2.jpg");
        //Laplacian算子对噪音敏感,事先去噪
        Imgproc.GaussianBlur(src, src, new Size(3, 3), 0);
        //灰度化
        Imgproc.cvtColor(src, src, Imgproc.COLOR_BGR2GRAY);
		//OpenCV自带的Laplacian函数
        Mat temp = new Mat();
        Imgproc.Laplacian(src, temp, CvType.CV_16S, 3, 1, 0, Core.BORDER_DEFAULT);
  
		//手动实现
        //内核
        Mat kernel = new Mat(new Size(3,3), CvType.CV_32F, new Scalar(255));
        kernel.put(0, 0, 2); kernel.put(0, 1, 0); kernel.put(0, 2, 2);
        kernel.put(1, 0, 0); kernel.put(1, 1, -8); kernel.put(1, 2, 0);
        kernel.put(2, 0, 2); kernel.put(2, 1, 0); kernel.put(2, 2, 2);

        Mat dst = new Mat();
        Imgproc.filter2D(src, dst, CvType.CV_16S, kernel, new Point(-1, -1), 0, Core.BORDER_DEFAULT);
		
		//验证图片是否相同
        boolean flag = true;
        for (int row = 0; row < dst.rows(); row++) {
            for (int col = 0; col < dst.cols(); col++) {
                if (temp.get(row, col)[0] != dst.get(row, col)[0]) {
                    flag = false;
                    break;
                }
            }
            if (!flag) {
                break;
            }
        }
        System.out.println(flag);

    }

结果输出
在这里插入图片描述

OpenCV Laplacian 参数说明

scale

	public static void main(String[] args) {
		//图片
        Mat src = new Mat(new Size(3, 3), CvType.CV_8UC1);
        src.put(0, 0, 1); src.put(0, 1, 2); src.put(0, 2, 3);
        src.put(1, 0, 4); src.put(1, 1, 5); src.put(1, 2, 6);
        src.put(2, 0, 7); src.put(2, 1, 8); src.put(2, 2, 9);

        Mat dst1 = new Mat();
        Imgproc.Laplacian(src, dst1, CvType.CV_16S, 1, 1, 0, Core.BORDER_DEFAULT);
        System.out.println("------------------scale=1---------------------");
        for (int row = 0; row < dst1.rows(); row++) {
            for (int col = 0; col < dst1.cols(); col++) {
                System.out.print(dst1.get(row, col)[0] + "   ");
            }
            System.out.println();
        }

        Mat dst2 = new Mat();
        Imgproc.Laplacian(src, dst2, CvType.CV_16S, 1, 2, 0, Core.BORDER_DEFAULT);
        System.out.println("------------------scale=2---------------------");
        for (int row = 0; row < dst2.rows(); row++) {
            for (int col = 0; col < dst2.cols(); col++) {
                System.out.print(dst2.get(row, col)[0] + "   ");
            }
            System.out.println();
        }

        Mat dst3 = new Mat();
        Imgproc.Laplacian(src, dst3, CvType.CV_16S, 1, 3, 0, Core.BORDER_DEFAULT);
        System.out.println("------------------scale=3---------------------");
        for (int row = 0; row < dst3.rows(); row++) {
            for (int col = 0; col < dst3.cols(); col++) {
                System.out.print(dst3.get(row, col)[0] + "   ");
            }
            System.out.println();
        }

    }

结果输出

------------------scale=1---------------------
8.0   6.0   4.0   
2.0   0.0   -2.0   
-4.0   -6.0   -8.0   
------------------scale=2---------------------
16.0   12.0   8.0   
4.0   0.0   -4.0   
-8.0   -12.0   -16.0   
------------------scale=3---------------------
24.0   18.0   12.0   
6.0   0.0   -6.0   
-12.0   -18.0   -24.0  

结论:scale为目标图片在计算后得出的结果上再翻scale倍

delta

	public static void main(String[] args) {
		//图片
        Mat src = new Mat(new Size(3, 3), CvType.CV_8UC1);
        src.put(0, 0, 1); src.put(0, 1, 2); src.put(0, 2, 3);
        src.put(1, 0, 4); src.put(1, 1, 5); src.put(1, 2, 6);
        src.put(2, 0, 7); src.put(2, 1, 8); src.put(2, 2, 9);

        Mat dst1 = new Mat();
        Imgproc.Laplacian(src, dst1, CvType.CV_16S, 1, 1, 0, Core.BORDER_DEFAULT);
        System.out.println("------------------delta=0---------------------");
        for (int row = 0; row < dst1.rows(); row++) {
            for (int col = 0; col < dst1.cols(); col++) {
                System.out.print(dst1.get(row, col)[0] + "   ");
            }
            System.out.println();
        }

        Mat dst2 = new Mat();
        Imgproc.Laplacian(src, dst2, CvType.CV_16S, 1, 1, 0, Core.BORDER_DEFAULT);
        System.out.println("------------------delta=1---------------------");
        for (int row = 0; row < dst2.rows(); row++) {
            for (int col = 0; col < dst2.cols(); col++) {
                System.out.print(dst2.get(row, col)[0] + "   ");
            }
            System.out.println();
        }

        Mat dst3 = new Mat();
        Imgproc.Laplacian(src, dst3, CvType.CV_16S, 1, 1, 2, Core.BORDER_DEFAULT);
        System.out.println("------------------delta=2---------------------");
        for (int row = 0; row < dst3.rows(); row++) {
            for (int col = 0; col < dst3.cols(); col++) {
                System.out.print(dst3.get(row, col)[0] + "   ");
            }
            System.out.println();
        }

    }

结果输出

------------------delta=0---------------------
8.0   6.0   4.0   
2.0   0.0   -2.0   
-4.0   -6.0   -8.0   
------------------delta=1---------------------
9.0   7.0   5.0   
3.0   1.0   -1.0   
-3.0   -5.0   -7.0   
------------------delta=2---------------------
10.0   8.0   6.0   
4.0   2.0   0.0   
-2.0   -4.0   -6.0    

结论:delta为目标图片在计算后得出的结果上再加delta

scale和delta综合验证

	public static void main(String[] args) {
		//图片
        Mat src = new Mat(new Size(3, 3), CvType.CV_8UC1);
        src.put(0, 0, 1); src.put(0, 1, 2); src.put(0, 2, 3);
        src.put(1, 0, 4); src.put(1, 1, 5); src.put(1, 2, 6);
        src.put(2, 0, 7); src.put(2, 1, 8); src.put(2, 2, 9);

        //OpenCV自带的Laplacian函数
        Mat dst1 = new Mat();
        Imgproc.Laplacian(src, dst1, CvType.CV_16S, 1, 1, 0, Core.BORDER_DEFAULT);

        System.out.println("------------------scale=1,delta=0---------------------");
        for (int row = 0; row < dst1.rows(); row++) {
            for (int col = 0; col < dst1.cols(); col++) {
                System.out.print(dst1.get(row, col)[0] + "   ");
            }
            System.out.println();
        }

        Mat dst2 = new Mat();
        Imgproc.Laplacian(src, dst2, CvType.CV_16S, 1, 2, 3, Core.BORDER_DEFAULT);
        System.out.println("------------------scale=2,delta=3---------------------");
        for (int row = 0; row < dst2.rows(); row++) {
            for (int col = 0; col < dst2.cols(); col++) {
                System.out.print(dst2.get(row, col)[0] + "   ");
            }
            System.out.println();
        }
    }

结果输出

------------------scale=1,delta=0---------------------
8.0   6.0   4.0   
2.0   0.0   -2.0   
-4.0   -6.0   -8.0   
------------------scale=2,delta=3---------------------
19.0   15.0   11.0   
7.0   3.0   -1.0   
-5.0   -9.0   -13.0 

过程说明

8*2+3    6*2+3     4*2+3 
2*2+3    0*2+3    -2*2+3
-4*2+3   -6*2+3   -8*2+3

参考链接

https://www.cnblogs.com/polly333/p/7269843.html
https://blog.csdn.net/u010551600/article/details/80357267

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值